aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@penguin.transmeta.com>2002-04-03 01:03:45 -0800
committerLinus Torvalds <torvalds@penguin.transmeta.com>2002-04-03 01:03:45 -0800
commit5e4b50795ee8c7659a1181cea4c98712e02ea63e (patch)
treeb4e0f1a19c549bc54e93f4ada5c3b0a0953e58cb
parent893d709002e952c54cce2e140854207a5f7fdcca (diff)
parent6a1a68c8febfc71c895a05a10afe6812b7c77584 (diff)
downloadhistory-5e4b50795ee8c7659a1181cea4c98712e02ea63e.tar.gz
Merge bk://linuxusb.bkbits.net/linus-2.5v2.5.8-pre1
into penguin.transmeta.com:/home/penguin/torvalds/repositories/kernel/linux
-rw-r--r--CREDITS8
-rw-r--r--Documentation/00-INDEX38
-rwxr-xr-xDocumentation/BK-usage/bksend36
-rwxr-xr-xDocumentation/BK-usage/bz64wrap41
-rwxr-xr-xDocumentation/BK-usage/cset-to-linus2
-rwxr-xr-xDocumentation/BK-usage/csets-to-patches2
-rwxr-xr-xDocumentation/BK-usage/unbz64wrap25
-rw-r--r--Documentation/Changes8
-rw-r--r--Documentation/DMA-mapping.txt6
-rw-r--r--Documentation/DocBook/Makefile8
-rw-r--r--Documentation/DocBook/kernel-api.tmpl4
-rw-r--r--Documentation/DocBook/via-audio.tmpl6
-rw-r--r--Documentation/SubmittingDrivers2
-rw-r--r--Documentation/filesystems/Locking15
-rw-r--r--Documentation/kernel-parameters.txt4
-rw-r--r--Documentation/networking/dl2k.txt6
-rw-r--r--Documentation/networking/ip-sysctl.txt24
-rw-r--r--Documentation/networking/ppp_generic.txt432
-rw-r--r--Documentation/sonypi.txt3
-rw-r--r--Documentation/sound/oss/AudioExcelDSP162
-rw-r--r--Documentation/usb/se401.txt2
-rw-r--r--Documentation/video4linux/Zoran6
-rw-r--r--Documentation/video4linux/bttv/README.freeze4
-rw-r--r--Documentation/video4linux/w9966.txt40
-rw-r--r--Documentation/watchdog-api.txt390
-rw-r--r--MAINTAINERS2
-rw-r--r--Makefile8
-rw-r--r--Rules.make4
-rw-r--r--arch/alpha/kernel/alpha_ksyms.c1
-rw-r--r--arch/alpha/kernel/setup.c6
-rw-r--r--arch/arm/kernel/armksyms.c2
-rw-r--r--arch/arm/mach-arc/dma.c2
-rw-r--r--arch/cris/drivers/ethernet.c6
-rw-r--r--arch/cris/drivers/gpio.c2
-rw-r--r--arch/cris/drivers/ide.c14
-rw-r--r--arch/cris/kernel/ksyms.c2
-rw-r--r--arch/i386/Config.help33
-rw-r--r--arch/i386/boot/setup.S2
-rw-r--r--arch/i386/config.in29
-rw-r--r--arch/i386/defconfig9
-rw-r--r--arch/i386/kernel/Makefile3
-rw-r--r--arch/i386/kernel/apic.c5
-rw-r--r--arch/i386/kernel/bluesmoke.c224
-rw-r--r--arch/i386/kernel/bootflag.c253
-rw-r--r--arch/i386/kernel/cpuid.c1
-rw-r--r--arch/i386/kernel/dmi_scan.c83
-rw-r--r--arch/i386/kernel/i386_ksyms.c1
-rw-r--r--arch/i386/kernel/microcode.c105
-rw-r--r--arch/i386/kernel/mpparse.c5
-rw-r--r--arch/i386/kernel/mtrr.c1
-rw-r--r--arch/i386/kernel/nmi.c129
-rw-r--r--arch/i386/kernel/pci-dma.c2
-rw-r--r--arch/i386/kernel/pci-irq.c39
-rw-r--r--arch/i386/kernel/pci-pc.c3
-rw-r--r--arch/i386/kernel/setup.c102
-rw-r--r--arch/i386/kernel/traps.c15
-rw-r--r--arch/i386/mm/ioremap.c2
-rw-r--r--arch/ia64/kernel/ia64_ksyms.c1
-rw-r--r--arch/m68k/atari/config.c6
-rw-r--r--arch/m68k/kernel/m68k_ksyms.c1
-rw-r--r--arch/m68k/mac/baboon.c2
-rw-r--r--arch/mips/kernel/mips_ksyms.c3
-rw-r--r--arch/mips/kernel/signal.c2
-rw-r--r--arch/mips/kernel/smp.c2
-rw-r--r--arch/mips/sni/pci.c2
-rw-r--r--arch/mips64/kernel/mips64_ksyms.c3
-rw-r--r--arch/mips64/math-emu/cp1emu.c2
-rw-r--r--arch/parisc/kernel/parisc_ksyms.c1
-rw-r--r--arch/ppc/4xx_io/stb_kb.c2
-rw-r--r--arch/ppc/iSeries/iSeries_irq.c2
-rw-r--r--arch/ppc/kernel/ppc_ksyms.c1
-rw-r--r--arch/ppc/math-emu/op-4.h2
-rw-r--r--arch/s390/kernel/s390_ksyms.c2
-rw-r--r--arch/s390x/kernel/s390_ksyms.c2
-rw-r--r--arch/sh/kernel/sh_ksyms.c3
-rw-r--r--arch/sparc/kernel/ioport.c2
-rw-r--r--arch/sparc/kernel/irq.c2
-rw-r--r--arch/sparc/kernel/pcic.c2
-rw-r--r--arch/sparc/kernel/process.c8
-rw-r--r--arch/sparc/kernel/ptrace.c18
-rw-r--r--arch/sparc/kernel/setup.c39
-rw-r--r--arch/sparc/kernel/signal.c11
-rw-r--r--arch/sparc/kernel/sparc_ksyms.c1
-rw-r--r--arch/sparc/kernel/sun4d_smp.c2
-rw-r--r--arch/sparc/kernel/time.c2
-rw-r--r--arch/sparc/kernel/traps.c2
-rw-r--r--arch/sparc/mm/iommu.c2
-rw-r--r--arch/sparc/mm/srmmu.c4
-rw-r--r--arch/sparc/mm/sun4c.c2
-rw-r--r--arch/sparc/mm/swift.S8
-rw-r--r--arch/sparc/mm/tsunami.S6
-rw-r--r--arch/sparc64/defconfig11
-rw-r--r--arch/sparc64/kernel/binfmt_elf32.c2
-rw-r--r--arch/sparc64/kernel/ebus.c54
-rw-r--r--arch/sparc64/kernel/head.S9
-rw-r--r--arch/sparc64/kernel/ioctl32.c12
-rw-r--r--arch/sparc64/kernel/irq.c2
-rw-r--r--arch/sparc64/kernel/pci.c58
-rw-r--r--arch/sparc64/kernel/pci_common.c65
-rw-r--r--arch/sparc64/kernel/pci_psycho.c13
-rw-r--r--arch/sparc64/kernel/pci_sabre.c15
-rw-r--r--arch/sparc64/kernel/pci_schizo.c47
-rw-r--r--arch/sparc64/kernel/power.c4
-rw-r--r--arch/sparc64/kernel/ptrace.c17
-rw-r--r--arch/sparc64/kernel/signal.c6
-rw-r--r--arch/sparc64/kernel/signal32.c6
-rw-r--r--arch/sparc64/kernel/smp.c6
-rw-r--r--arch/sparc64/kernel/sparc64_ksyms.c1
-rw-r--r--arch/sparc64/kernel/sys_sparc.c6
-rw-r--r--arch/sparc64/kernel/sys_sunos32.c2
-rw-r--r--arch/sparc64/kernel/time.c4
-rw-r--r--arch/sparc64/kernel/trampoline.S9
-rw-r--r--arch/sparc64/mm/init.c2
-rw-r--r--arch/sparc64/prom/bootstr.c5
-rw-r--r--arch/sparc64/prom/misc.c2
-rw-r--r--arch/sparc64/solaris/misc.c2
-rw-r--r--arch/sparc64/solaris/timod.c2
-rw-r--r--arch/x86_64/kernel/x8664_ksyms.c1
-rw-r--r--drivers/acpi/acpi_tables.c1
-rw-r--r--drivers/atm/eni.c1
-rw-r--r--drivers/block/DAC960.c4
-rw-r--r--drivers/block/blkpg.c4
-rw-r--r--drivers/block/cciss.c1
-rw-r--r--drivers/block/cciss_scsi.c1
-rw-r--r--drivers/block/genhd.c72
-rw-r--r--drivers/block/loop.c9
-rw-r--r--drivers/block/nbd.c2
-rw-r--r--drivers/block/rd.c5
-rw-r--r--drivers/cdrom/cdrom.c1
-rw-r--r--drivers/char/acquirewdt.c22
-rw-r--r--drivers/char/advantechwdt.c40
-rw-r--r--drivers/char/agp/agpgart_be.c119
-rw-r--r--drivers/char/applicom.c2
-rw-r--r--drivers/char/cyclades.c38
-rw-r--r--drivers/char/drm/i810_dma.c2
-rw-r--r--drivers/char/esp.c2
-rw-r--r--drivers/char/eurotechwdt.c47
-rw-r--r--drivers/char/i810-tco.c32
-rw-r--r--drivers/char/ib700wdt.c39
-rw-r--r--drivers/char/ip2/i2lib.c2
-rw-r--r--drivers/char/machzwd.c47
-rw-r--r--drivers/char/mixcomwd.c74
-rw-r--r--drivers/char/mxser.c105
-rw-r--r--drivers/char/raw.c2
-rw-r--r--drivers/char/rocket.c176
-rw-r--r--drivers/char/sbc60xxwdt.c14
-rw-r--r--drivers/char/shwdt.c22
-rw-r--r--drivers/char/softdog.c33
-rw-r--r--drivers/char/sonypi.c140
-rw-r--r--drivers/char/sonypi.h27
-rw-r--r--drivers/char/stallion.c2
-rw-r--r--drivers/char/synclink.c4
-rw-r--r--drivers/char/tpqic02.c10
-rw-r--r--drivers/char/tty_io.c4
-rw-r--r--drivers/char/vme_scc.c14
-rw-r--r--drivers/char/wdt.c39
-rw-r--r--drivers/char/wdt977.c341
-rw-r--r--drivers/char/wdt_pci.c43
-rw-r--r--drivers/fc4/soc.c1
-rw-r--r--drivers/fc4/socal.c1
-rw-r--r--drivers/i2c/i2c-algo-bit.c4
-rw-r--r--drivers/i2c/i2c-dev.c8
-rw-r--r--drivers/i2c/i2c-proc.c4
-rw-r--r--drivers/ide/aec62xx.c38
-rw-r--r--drivers/ide/ali14xx.c4
-rw-r--r--drivers/ide/alim15x3.c32
-rw-r--r--drivers/ide/amd74xx.c22
-rw-r--r--drivers/ide/buddha.c4
-rw-r--r--drivers/ide/cmd640.c6
-rw-r--r--drivers/ide/cmd64x.c72
-rw-r--r--drivers/ide/cs5530.c8
-rw-r--r--drivers/ide/cy82c693.c14
-rw-r--r--drivers/ide/dtc2278.c4
-rw-r--r--drivers/ide/gayle.c4
-rw-r--r--drivers/ide/hpt34x.c27
-rw-r--r--drivers/ide/hpt366.c86
-rw-r--r--drivers/ide/ht6560b.c2
-rw-r--r--drivers/ide/icside.c42
-rw-r--r--drivers/ide/ide-cd.c54
-rw-r--r--drivers/ide/ide-disk.c376
-rw-r--r--drivers/ide/ide-dma.c38
-rw-r--r--drivers/ide/ide-features.c39
-rw-r--r--drivers/ide/ide-floppy.c40
-rw-r--r--drivers/ide/ide-geometry.c1
-rw-r--r--drivers/ide/ide-pci.c110
-rw-r--r--drivers/ide/ide-pmac.c46
-rw-r--r--drivers/ide/ide-pnp.c4
-rw-r--r--drivers/ide/ide-probe.c79
-rw-r--r--drivers/ide/ide-proc.c18
-rw-r--r--drivers/ide/ide-tape.c45
-rw-r--r--drivers/ide/ide-taskfile.c436
-rw-r--r--drivers/ide/ide.c633
-rw-r--r--drivers/ide/it8172.c14
-rw-r--r--drivers/ide/macide.c2
-rw-r--r--drivers/ide/ns87415.c20
-rw-r--r--drivers/ide/opti621.c6
-rw-r--r--drivers/ide/pdc202xx.c60
-rw-r--r--drivers/ide/pdc4030.c54
-rw-r--r--drivers/ide/pdcadma.c6
-rw-r--r--drivers/ide/piix.c22
-rw-r--r--drivers/ide/qd65xx.c22
-rw-r--r--drivers/ide/rz1000.c6
-rw-r--r--drivers/ide/serverworks.c26
-rw-r--r--drivers/ide/sis5513.c24
-rw-r--r--drivers/ide/sl82c105.c16
-rw-r--r--drivers/ide/trm290.c21
-rw-r--r--drivers/ide/umc8672.c4
-rw-r--r--drivers/ide/via82cxxx.c22
-rw-r--r--drivers/ieee1394/dv1394.c1
-rw-r--r--drivers/ieee1394/pcilynx.c3
-rw-r--r--drivers/ieee1394/video1394.c1
-rw-r--r--drivers/isdn/avmb1/capifs.c7
-rw-r--r--drivers/isdn/avmb1/kcapi.c4
-rw-r--r--drivers/isdn/eicon/eicon_mod.c5
-rw-r--r--drivers/isdn/hisax/hisax_fcpcipnp.c1
-rw-r--r--drivers/isdn/hisax/hisax_isac.c1
-rw-r--r--drivers/md/lvm-snap.c37
-rw-r--r--drivers/md/md.c2
-rw-r--r--drivers/media/radio/radio-gemtek-pci.c2
-rw-r--r--drivers/media/video/videodev.c16
-rw-r--r--drivers/mtd/chips/sharp.c2
-rw-r--r--drivers/mtd/devices/blkmtd.c4
-rw-r--r--drivers/mtd/ftl.c16
-rw-r--r--drivers/mtd/mtdblock.c2
-rw-r--r--drivers/mtd/mtdblock_ro.c2
-rw-r--r--drivers/mtd/nand/nand_ecc.c2
-rw-r--r--drivers/mtd/nftlcore.c2
-rw-r--r--drivers/net/3c503.c10
-rw-r--r--drivers/net/3c505.c2
-rw-r--r--drivers/net/8390.h4
-rw-r--r--drivers/net/Config.in3
-rw-r--r--drivers/net/Makefile3
-rw-r--r--drivers/net/Space.c320
-rw-r--r--drivers/net/ac3200.c10
-rw-r--r--drivers/net/acenic.c49
-rw-r--r--drivers/net/acenic.h9
-rw-r--r--drivers/net/aironet4500.h14
-rw-r--r--drivers/net/arcnet/arc-rimi.c2
-rw-r--r--drivers/net/arcnet/com90xx.c2
-rw-r--r--drivers/net/arlan.c14
-rw-r--r--drivers/net/at1700.c2
-rw-r--r--drivers/net/atp.c2
-rw-r--r--drivers/net/daynaport.c26
-rw-r--r--drivers/net/de620.c15
-rw-r--r--drivers/net/dl2k.c135
-rw-r--r--drivers/net/dl2k.h5
-rw-r--r--drivers/net/e100/Makefile2
-rw-r--r--drivers/net/e100/e100.h31
-rw-r--r--drivers/net/e100/e100_config.c99
-rw-r--r--drivers/net/e100/e100_config.h7
-rw-r--r--drivers/net/e100/e100_main.c113
-rw-r--r--drivers/net/e100/e100_test.c467
-rw-r--r--drivers/net/e1000/LICENSE13
-rw-r--r--drivers/net/e1000/Makefile3
-rw-r--r--drivers/net/e1000/e1000.h55
-rw-r--r--drivers/net/e1000/e1000_ethtool.c85
-rw-r--r--drivers/net/e1000/e1000_hw.c3228
-rw-r--r--drivers/net/e1000/e1000_hw.h (renamed from drivers/net/e1000/e1000_mac.h)532
-rw-r--r--drivers/net/e1000/e1000_mac.c1821
-rw-r--r--drivers/net/e1000/e1000_main.c943
-rw-r--r--drivers/net/e1000/e1000_osdep.h13
-rw-r--r--drivers/net/e1000/e1000_param.c154
-rw-r--r--drivers/net/e1000/e1000_phy.c1485
-rw-r--r--drivers/net/e1000/e1000_phy.h422
-rw-r--r--drivers/net/e1000/e1000_proc.c118
-rw-r--r--drivers/net/e2100.c8
-rw-r--r--drivers/net/eepro100.c1
-rw-r--r--drivers/net/epic100.c12
-rw-r--r--drivers/net/es3210.c10
-rw-r--r--drivers/net/hamradio/6pack.c3
-rw-r--r--drivers/net/hamradio/baycom_epp.c6
-rw-r--r--drivers/net/hamradio/baycom_ser_fdx.c8
-rw-r--r--drivers/net/hamradio/dmascc.c1
-rw-r--r--drivers/net/hamradio/mkiss.c2
-rw-r--r--drivers/net/hamradio/scc.c2
-rw-r--r--drivers/net/hamradio/soundmodem/sm.h26
-rw-r--r--drivers/net/hamradio/soundmodem/sm_afsk1200.c8
-rw-r--r--drivers/net/hamradio/soundmodem/sm_afsk2400_7.c8
-rw-r--r--drivers/net/hamradio/soundmodem/sm_afsk2400_8.c8
-rw-r--r--drivers/net/hamradio/soundmodem/sm_afsk2666.c4
-rw-r--r--drivers/net/hamradio/soundmodem/sm_sbc.c4
-rw-r--r--drivers/net/hamradio/soundmodem/sm_wss.c4
-rw-r--r--drivers/net/hamradio/soundmodem/smdma.h18
-rw-r--r--drivers/net/hamradio/yam.c3
-rw-r--r--drivers/net/hp-plus.c4
-rw-r--r--drivers/net/irda/sa1100_ir.c1
-rw-r--r--drivers/net/lance.c2
-rw-r--r--drivers/net/lne390.c10
-rw-r--r--drivers/net/ne3210.c10
-rw-r--r--drivers/net/ns83820.c18
-rw-r--r--drivers/net/pcnet32.c10
-rw-r--r--drivers/net/sb1000.c40
-rw-r--r--drivers/net/sb1250-mac.c2673
-rw-r--r--drivers/net/skfp/skfddi.c2
-rw-r--r--drivers/net/smc-mca.c10
-rw-r--r--drivers/net/smc-ultra.c10
-rw-r--r--drivers/net/smc-ultra32.c6
-rw-r--r--drivers/net/strip.c1
-rw-r--r--drivers/net/sun3_82586.c1206
-rw-r--r--drivers/net/sun3_82586.h318
-rw-r--r--drivers/net/sungem.c468
-rw-r--r--drivers/net/sungem.h5
-rw-r--r--drivers/net/sunhme.c449
-rw-r--r--drivers/net/sunhme.h2
-rw-r--r--drivers/net/tc35815.c1779
-rw-r--r--drivers/net/tg3.c105
-rw-r--r--drivers/net/tg3.h2
-rw-r--r--drivers/net/tokenring/smctr.c4
-rw-r--r--drivers/net/wan/comx-hw-locomx.c4
-rw-r--r--drivers/net/wan/comx-hw-mixcom.c2
-rw-r--r--drivers/net/wan/comx-hw-munich.c32
-rw-r--r--drivers/net/wan/cosa.c7
-rw-r--r--drivers/net/wan/dscc4.c3
-rw-r--r--drivers/net/wan/hd6457x.c1
-rw-r--r--drivers/net/wan/sdla_ppp.c4
-rw-r--r--drivers/net/wd.c14
-rw-r--r--drivers/net/wireless/orinoco_plx.c25
-rw-r--r--drivers/parport/parport_mfc3.c1
-rw-r--r--drivers/pci/pci.c2
-rw-r--r--drivers/pci/pci.ids21
-rw-r--r--drivers/pcmcia/Config.in4
-rw-r--r--drivers/pcmcia/i82092.c4
-rw-r--r--drivers/pnp/pnpbios_core.c223
-rw-r--r--drivers/pnp/pnpbios_proc.c165
-rw-r--r--drivers/s390/block/dasd.c2
-rw-r--r--drivers/s390/block/dasd_int.h8
-rw-r--r--drivers/s390/block/xpram.c2
-rw-r--r--drivers/s390/char/tapeblock.c2
-rw-r--r--drivers/sbus/audio/amd7930.c3
-rw-r--r--drivers/sbus/audio/cs4231.c6
-rw-r--r--drivers/sbus/char/aurora.c2
-rw-r--r--drivers/sbus/char/uctrl.c10
-rw-r--r--drivers/sbus/sbus.c6
-rw-r--r--drivers/scsi/3w-xxxx.c282
-rw-r--r--drivers/scsi/3w-xxxx.h29
-rw-r--r--drivers/scsi/53c7,8xx.c4
-rw-r--r--drivers/scsi/53c7xx.c4
-rw-r--r--drivers/scsi/NCR53C9x.c2
-rw-r--r--drivers/scsi/a2091.c2
-rw-r--r--drivers/scsi/aic7xxx/aic7xxx_linux.c9
-rw-r--r--drivers/scsi/aic7xxx_old.c4
-rw-r--r--drivers/scsi/eata.c2
-rw-r--r--drivers/scsi/fdomain.c2
-rw-r--r--drivers/scsi/ide-scsi.c17
-rw-r--r--drivers/scsi/ppa.c2
-rw-r--r--drivers/scsi/sun3x_esp.c2
-rw-r--r--drivers/scsi/tmscsim.c151
-rw-r--r--drivers/scsi/u14-34f.c4
-rw-r--r--drivers/tc/zs.c2
-rw-r--r--drivers/usb/inode.c6
-rw-r--r--drivers/usb/storage/transport.h2
-rw-r--r--drivers/usb/usbvideo.c13
-rw-r--r--drivers/usb/usbvideo.h2
-rw-r--r--drivers/video/amifb.c32
-rw-r--r--drivers/video/atafb.c66
-rw-r--r--drivers/video/aty/atyfb_base.c26
-rw-r--r--fs/Makefile8
-rw-r--r--fs/adfs/super.c4
-rw-r--r--fs/affs/super.c6
-rw-r--r--fs/autofs/inode.c7
-rw-r--r--fs/autofs4/inode.c4
-rw-r--r--fs/binfmt_elf.c16
-rw-r--r--fs/bio.c5
-rw-r--r--fs/buffer.c24
-rw-r--r--fs/devpts/inode.c9
-rw-r--r--fs/dquot.c14
-rw-r--r--fs/ext2/super.c10
-rw-r--r--fs/ext3/super.c6
-rw-r--r--fs/fat/inode.c6
-rw-r--r--fs/filesystems.c3
-rw-r--r--fs/hfs/super.c17
-rw-r--r--fs/hpfs/super.c6
-rw-r--r--fs/inode.c11
-rw-r--r--fs/intermezzo/super.c6
-rw-r--r--fs/iobuf.c5
-rw-r--r--fs/isofs/inode.c4
-rw-r--r--fs/jbd/journal.c2
-rw-r--r--fs/jfs/jfs_logmgr.c3
-rw-r--r--fs/jfs/jfs_txnmgr.c7
-rw-r--r--fs/jfs/super.c12
-rw-r--r--fs/minix/bitmap.c97
-rw-r--r--fs/minix/dir.c4
-rw-r--r--fs/minix/file.c3
-rw-r--r--fs/minix/inode.c50
-rw-r--r--fs/minix/itree_common.c29
-rw-r--r--fs/minix/itree_v1.c4
-rw-r--r--fs/minix/itree_v2.c4
-rw-r--r--fs/minix/minix.h91
-rw-r--r--fs/minix/namei.c4
-rw-r--r--fs/nfs/nfsroot.c6
-rw-r--r--fs/nls/Config.help9
-rw-r--r--fs/nls/Config.in1
-rw-r--r--fs/nls/nls_cp1250.c365
-rw-r--r--fs/noquot.c15
-rw-r--r--fs/ntfs/fs.c5
-rw-r--r--fs/partitions/Config.help5
-rw-r--r--fs/partitions/Config.in1
-rw-r--r--fs/partitions/Makefile1
-rw-r--r--fs/partitions/check.c4
-rw-r--r--fs/partitions/efi.c828
-rw-r--r--fs/partitions/efi.h133
-rw-r--r--fs/partitions/msdos.c11
-rw-r--r--fs/proc/array.c2
-rw-r--r--fs/proc/inode.c7
-rw-r--r--fs/proc/proc_misc.c23
-rw-r--r--fs/reiserfs/journal.c6
-rw-r--r--fs/reiserfs/super.c8
-rw-r--r--fs/romfs/inode.c57
-rw-r--r--fs/super.c4
-rw-r--r--fs/udf/super.c5
-rw-r--r--fs/ufs/super.c9
-rw-r--r--fs/vfat/namei.c4
-rw-r--r--include/asm-arm/arch-cl7500/system.h2
-rw-r--r--include/asm-arm/arch-sa1100/keyboard.h4
-rw-r--r--include/asm-i386/apic.h1
-rw-r--r--include/asm-i386/apicdef.h12
-rw-r--r--include/asm-i386/checksum.h1
-rw-r--r--include/asm-i386/hw_irq.h1
-rw-r--r--include/asm-i386/io.h92
-rw-r--r--include/asm-i386/irq.h1
-rw-r--r--include/asm-i386/msr.h13
-rw-r--r--include/asm-i386/processor.h5
-rw-r--r--include/asm-i386/rwsem.h2
-rw-r--r--include/asm-i386/string-486.h2
-rw-r--r--include/asm-i386/string.h2
-rw-r--r--include/asm-i386/timex.h7
-rw-r--r--include/asm-m68k/string.h23
-rw-r--r--include/asm-mips/spinlock.h4
-rw-r--r--include/asm-mips64/spinlock.h4
-rw-r--r--include/asm-parisc/pgalloc.h2
-rw-r--r--include/asm-sparc/elf.h2
-rw-r--r--include/asm-sparc/pgtable.h3
-rw-r--r--include/asm-sparc/sbus.h3
-rw-r--r--include/asm-sparc64/pgalloc.h9
-rw-r--r--include/asm-sparc64/processor.h16
-rw-r--r--include/asm-sparc64/sbus.h3
-rw-r--r--include/linux/device.h2
-rw-r--r--include/linux/ethtool.h43
-rw-r--r--include/linux/fs.h1
-rw-r--r--include/linux/hdreg.h113
-rw-r--r--include/linux/ide.h212
-rw-r--r--include/linux/inetdevice.h2
-rw-r--r--include/linux/iobuf.h4
-rw-r--r--include/linux/minix_fs.h62
-rw-r--r--include/linux/minix_fs_i.h15
-rw-r--r--include/linux/minix_fs_sb.h26
-rw-r--r--include/linux/mtd/compatmac.h4
-rw-r--r--include/linux/nbd.h2
-rw-r--r--include/linux/netdevice.h2
-rw-r--r--include/linux/netfilter_ipv4/ip_conntrack.h67
-rw-r--r--include/linux/netfilter_ipv4/ip_conntrack_core.h2
-rw-r--r--include/linux/netfilter_ipv4/ip_conntrack_ftp.h26
-rw-r--r--include/linux/netfilter_ipv4/ip_conntrack_helper.h25
-rw-r--r--include/linux/netfilter_ipv4/ip_conntrack_irc.h16
-rw-r--r--include/linux/netfilter_ipv4/ip_conntrack_protocol.h7
-rw-r--r--include/linux/netfilter_ipv4/ip_nat_helper.h22
-rw-r--r--include/linux/netfilter_ipv4/ip_nat_rule.h17
-rw-r--r--include/linux/pci_ids.h46
-rw-r--r--include/linux/pnpbios.h11
-rw-r--r--include/linux/quota.h1
-rw-r--r--include/linux/raid/md.h2
-rw-r--r--include/linux/rtnetlink.h2
-rw-r--r--include/linux/sched.h1
-rw-r--r--include/linux/securebits.h2
-rw-r--r--include/linux/skbuff.h1
-rw-r--r--include/linux/smb_fs.h1
-rw-r--r--include/linux/sonypi.h23
-rw-r--r--include/linux/spinlock.h2
-rw-r--r--include/linux/string.h2
-rw-r--r--include/linux/sysctl.h6
-rw-r--r--include/linux/udf_fs.h4
-rw-r--r--include/linux/videodev.h8
-rw-r--r--include/net/ndisc.h6
-rw-r--r--include/net/pkt_sched.h4
-rw-r--r--include/net/sock.h2
-rw-r--r--include/net/tcp.h14
-rw-r--r--init/do_mounts.c2
-rw-r--r--ipc/sem.c5
-rw-r--r--ipc/shm.c7
-rw-r--r--kernel/Makefile3
-rw-r--r--kernel/acct.c18
-rw-r--r--kernel/exit.c10
-rw-r--r--kernel/ksyms.c3
-rw-r--r--kernel/sys.c12
-rw-r--r--kernel/sysctl.c8
-rw-r--r--lib/Makefile2
-rw-r--r--lib/rbtree.c3
-rw-r--r--lib/string.c37
-rw-r--r--mm/filemap.c20
-rw-r--r--mm/mempool.c3
-rw-r--r--mm/shmem.c7
-rw-r--r--net/atm/pppoatm.c1
-rw-r--r--net/atm/resources.c144
-rw-r--r--net/ax25/af_ax25.c1
-rw-r--r--net/core/neighbour.c4
-rw-r--r--net/core/skbuff.c2
-rw-r--r--net/core/sock.c1
-rw-r--r--net/econet/af_econet.c2
-rw-r--r--net/ipv4/af_inet.c8
-rw-r--r--net/ipv4/arp.c28
-rw-r--r--net/ipv4/devinet.c5
-rw-r--r--net/ipv4/fib_frontend.c3
-rw-r--r--net/ipv4/fib_semantics.c29
-rw-r--r--net/ipv4/icmp.c8
-rw-r--r--net/ipv4/ip_gre.c5
-rw-r--r--net/ipv4/ip_input.c4
-rw-r--r--net/ipv4/ipip.c6
-rw-r--r--net/ipv4/netfilter/Config.help11
-rw-r--r--net/ipv4/netfilter/Config.in2
-rw-r--r--net/ipv4/netfilter/Makefile13
-rw-r--r--net/ipv4/netfilter/ip_conntrack_core.c372
-rw-r--r--net/ipv4/netfilter/ip_conntrack_ftp.c58
-rw-r--r--net/ipv4/netfilter/ip_conntrack_irc.c106
-rw-r--r--net/ipv4/netfilter/ip_conntrack_proto_generic.c2
-rw-r--r--net/ipv4/netfilter/ip_conntrack_proto_icmp.c2
-rw-r--r--net/ipv4/netfilter/ip_conntrack_proto_tcp.c17
-rw-r--r--net/ipv4/netfilter/ip_conntrack_proto_udp.c2
-rw-r--r--net/ipv4/netfilter/ip_conntrack_standalone.c14
-rw-r--r--net/ipv4/netfilter/ip_fw_compat_masq.c2
-rw-r--r--net/ipv4/netfilter/ip_fw_compat_redir.c2
-rw-r--r--net/ipv4/netfilter/ip_nat_core.c85
-rw-r--r--net/ipv4/netfilter/ip_nat_ftp.c198
-rw-r--r--net/ipv4/netfilter/ip_nat_helper.c221
-rw-r--r--net/ipv4/netfilter/ip_nat_irc.c191
-rw-r--r--net/ipv4/netfilter/ip_nat_proto_tcp.c1
-rw-r--r--net/ipv4/netfilter/ip_nat_proto_unknown.c2
-rw-r--r--net/ipv4/netfilter/ip_nat_rule.c44
-rw-r--r--net/ipv4/netfilter/ip_nat_snmp_basic.c17
-rw-r--r--net/ipv4/netfilter/ip_nat_standalone.c32
-rw-r--r--net/ipv4/netfilter/ip_queue.c2
-rw-r--r--net/ipv4/netfilter/ipt_ULOG.c2
-rw-r--r--net/ipv4/route.c12
-rw-r--r--net/ipv4/sysctl_net_ipv4.c2
-rw-r--r--net/ipv4/tcp.c4
-rw-r--r--net/ipv4/tcp_input.c8
-rw-r--r--net/ipv4/tcp_ipv4.c224
-rw-r--r--net/ipv4/tcp_minisocks.c65
-rw-r--r--net/ipv4/tcp_output.c40
-rw-r--r--net/ipv4/udp.c14
-rw-r--r--net/ipv6/addrconf.c22
-rw-r--r--net/ipv6/ndisc.c54
-rw-r--r--net/ipv6/netfilter/ip6_queue.c2
-rw-r--r--net/ipv6/sit.c6
-rw-r--r--net/ipv6/tcp_ipv6.c77
-rw-r--r--net/ipv6/udp.c5
-rw-r--r--net/khttpd/sockets.c2
-rw-r--r--net/lapb/lapb_iface.c1
-rw-r--r--net/netlink/netlink_dev.c2
-rw-r--r--net/netrom/af_netrom.c3
-rw-r--r--net/netsyms.c1
-rw-r--r--net/packet/af_packet.c2
-rw-r--r--net/rose/af_rose.c1
-rw-r--r--net/sched/sch_prio.c1
-rw-r--r--net/sched/sch_sfq.c15
-rw-r--r--net/sunrpc/stats.c1
-rw-r--r--net/sunrpc/xprt.c2
-rw-r--r--net/x25/af_x25.c1
-rw-r--r--scripts/mkspec12
-rw-r--r--sound/core/rtctimer.c2
-rw-r--r--sound/oss/ac97_codec.c2
-rw-r--r--sound/oss/ad1848.h5
-rw-r--r--sound/oss/cs4232.h6
-rw-r--r--sound/oss/gus.h6
-rw-r--r--sound/oss/mad16.c41
-rw-r--r--sound/oss/mpu401.h6
-rw-r--r--sound/oss/opl3.h6
-rw-r--r--sound/oss/pas2.h6
-rw-r--r--sound/oss/pss.c2
568 files changed, 21357 insertions, 9814 deletions
diff --git a/CREDITS b/CREDITS
index 7ac710701c28c..5bc325becbea5 100644
--- a/CREDITS
+++ b/CREDITS
@@ -2133,7 +2133,7 @@ S: D-37083 Goettingen
S: Germany
N: Thomas Molina
-E: tmolina@home.com
+E: tmolina@cox.net
D: bug fixes, documentation, minor hackery
N: David Mosberger-Tang
@@ -2537,6 +2537,7 @@ S: Germany
N: Thiago Berlitz Rondon
E: maluco@mileniumnet.com.br
+W: http://vivaldi.linuxms.com.br/~maluco
D: Miscellaneous kernel hacker
S: R. Anhanguera, 1487 - Ipiranga
S: 79080-740 - Campo Grande - Mato Grosso do Sul
@@ -3289,9 +3290,10 @@ S: Bellevue, Washington 98007
S: USA
N: Richard Zidlicky
-E: rdzidlic@geocities.com,rdzidlic@cip.informatik.uni-erlangen.de
-W: http://www.geocities.com/SiliconValley/Bay/2602/
+E: rz@linux-m68k.org, rdzidlic@geocities.com
+W: http://www.geocities.com/rdzidlic
D: Q40 port - see arch/m68k/q40/README
+D: various m68k hacks
S: Germany
N: Werner Zimmermann
diff --git a/Documentation/00-INDEX b/Documentation/00-INDEX
index ec202d84110bd..96cd7163b50a6 100644
--- a/Documentation/00-INDEX
+++ b/Documentation/00-INDEX
@@ -12,14 +12,14 @@ Following translations are available on the WWW:
00-INDEX
- this file.
+BK-usage/
+ - directory with info on BitKeeper.
BUG-HUNTING
- brute force method of doing binary search of patches to find bug.
Changes
- list of changes that break older software packages.
CodingStyle
- how the boss likes the C code in the kernel to look.
-Configure.help
- - text file that is used for help when you run "make config"
DMA-mapping.txt
- info for PCI drivers using DMA portably across all platforms.
DocBook/
@@ -34,6 +34,10 @@ README.DAC960
- info on Mylex DAC960/DAC1100 PCI RAID Controller Driver for Linux
README.moxa
- release notes for Moxa mutiport serial card.
+README.nsp_cs.eng
+ - info on WorkBiT NinjaSCSI-3/32Bi driver.
+SAK.txt
+ - info on Secure Attention Keys.
SubmittingDrivers
- procedure to get a new driver source included into the kernel tree.
SubmittingPatches
@@ -44,6 +48,8 @@ arm/
- directory with info about Linux on the ARM architecture.
binfmt_misc.txt
- info on the kernel support for extra binary formats.
+block/
+ - info on the Block I/O (BIO) layer.
cachetlb.txt
- describes the cache/TLB flushing interfaces Linux uses.
cciss.txt
@@ -54,6 +60,8 @@ computone.txt
- info on Computone Intelliport II/Plus Multiport Serial Driver
cpqarray.txt
- info on using Compaq's SMART2 Intelligent Disk Array Controllers.
+cris/
+ - directory with info about Linux on CRIS architecture.
devices.txt
- plain ASCII listing of all the nodes in /dev/ with major minor #'s
digiboard.txt
@@ -62,6 +70,8 @@ digiepca.txt
- info on Digi Intl. {PC,PCI,EISA}Xx and Xem series cards.
dnotify.txt
- info about directory notification in Linux.
+driver-model.txt
+ - info about Linux driver model.
exception.txt
- how Linux v2.2 handles exceptions without verify_area etc.
fb/
@@ -80,12 +90,16 @@ i2c/
- directory with info about the I2C bus/protocol (2 wire, kHz speed)
i386/
- directory with info about Linux on intel 32 bit architecture.
+i810_rng.txt
+ - info on Linux support for random number generator in i8xx chipsets.
ia64/
- directory with info about Linux on intel 64 bit architecture.
ide.txt
- important info for users of ATA devices (IDE/EIDE disks and CD-ROMS)
initrd.txt
- how to use the RAM disk as an initial/temporary root filesystem.
+input/
+ - info on Linux input device support.
ioctl-number.txt
- how to implement and register device/driver ioctl calls.
isapnp.txt
@@ -94,12 +108,6 @@ isdn/
- directory with info on the Linux ISDN support, and supported cards.
java.txt
- info on the in-kernel binary support for Java(tm)
-joystick-api.txt
- - API specification for applications that will be using the joystick.
-joystick-parport.txt
- - info on how to hook joysticks/gamepads to the parallel port.
-joystick.txt
- - info on using joystick devices (and driver) with Linux.
kbuild/
- directory with info about the kernel build process
kernel-doc-nano-HOWTO.txt
@@ -128,6 +136,8 @@ md.txt
- info on boot arguments for the multiple devices driver
memory.txt
- info on typical Linux memory problems.
+mips/
+ - directory with info about Linux on MIPS architecture.
mkdev.cciss
- script to make /dev entries for SMART controllers (see cciss.txt)
mkdev.ida
@@ -161,9 +171,13 @@ pci.txt
pcwd-watchdog.txt
- info and sample code for using with the PC Watchdog reset card.
pm.txt
- - info on Linux power management support
+ - info on Linux power management support.
+power/
+ - directory with info on Linux PCI power management.
powerpc/
- directory with info on using Linux with the PowerPC.
+preempt-locking.txt
+ - info on locking under a preemptive kernel.
ramdisk.txt
- short guide on how to set up and use the RAM disk.
riscom8.txt
@@ -172,6 +186,8 @@ rtc.txt
- notes on how to use the Real Time Clock (aka CMOS clock) driver.
s390/
- directory with info on using Linux on the IBM S390.
+sh/
+ - directory with info on porting Linux to a new architecture.
scsi-generic.txt
- info on the sg driver for generic (non-disk/CD/tape) SCSI devices.
scsi.txt
@@ -186,6 +202,8 @@ smp.tex
- LaTeX document describing implementation of Multiprocessor Linux
smp.txt
- a few more notes on symmetric multi-processing
+sonypi.txt
+ - info on Linux Sony Programmable I/O Device support.
sound/
- directory with info on sound card support
sparc/
@@ -216,6 +234,8 @@ vm/
- directory with info on the Linux vm code.
watchdog.txt
- how to auto-reboot Linux if it has "fallen and can't get up". ;-)
+x86_64/
+ - directory with info on Linux support for AMD x86-64 (Hammer) machines.
xterm-linux.xpm
- XPM image of penguin logo (see logo.txt) sitting on an xterm.
zorro.txt
diff --git a/Documentation/BK-usage/bksend b/Documentation/BK-usage/bksend
new file mode 100755
index 0000000000000..dbeeefa8e241e
--- /dev/null
+++ b/Documentation/BK-usage/bksend
@@ -0,0 +1,36 @@
+#!/bin/sh
+# A script to format BK changeset output in a manner that is easy to read.
+# Andreas Dilger <adilger@turbolabs.com> 13/02/2002
+#
+# Add diffstat output after Changelog <adilger@turbolabs.com> 21/02/2002
+
+PROG=bksend
+
+usage() {
+ echo "usage: $PROG -r<rev>"
+ echo -e "\twhere <rev> is of the form '1.23', '1.23..', '1.23..1.27',"
+ echo -e "\tor '+' to indicate the most recent revision"
+
+ exit 1
+}
+
+case $1 in
+-r) REV=$2; shift ;;
+-r*) REV=`echo $1 | sed 's/^-r//'` ;;
+*) echo "$PROG: no revision given, you probably don't want that";;
+esac
+
+[ -z "$REV" ] && usage
+
+echo "You can import this changeset into BK by piping this whole message to:"
+echo "'| bk receive [path to repository]' or apply the patch as usual."
+
+SEP="\n===================================================================\n\n"
+echo -e $SEP
+bk changes -r$REV
+echo
+bk export -tpatch -du -h -r$REV | diffstat
+echo; echo
+bk export -tpatch -du -h -r$REV
+echo -e $SEP
+bk send -wgzip_uu -r$REV -
diff --git a/Documentation/BK-usage/bz64wrap b/Documentation/BK-usage/bz64wrap
new file mode 100755
index 0000000000000..be780876849f1
--- /dev/null
+++ b/Documentation/BK-usage/bz64wrap
@@ -0,0 +1,41 @@
+#!/bin/sh
+
+# bz64wrap - the sending side of a bzip2 | base64 stream
+# Andreas Dilger <adilger@clusterfs.com> Jan 2002
+
+
+PATH=$PATH:/usr/bin:/usr/local/bin:/usr/freeware/bin
+
+# A program to generate base64 encoding on stdout
+BASE64_ENCODE="uuencode -m /dev/stdout"
+BASE64_BEGIN=
+BASE64_END=
+
+BZIP=NO
+BASE64=NO
+
+# Test if we have the bzip program installed
+bzip2 -c /dev/null > /dev/null 2>&1 && BZIP=YES
+
+# Test if uuencode can handle the -m (MIME) encoding option
+$BASE64_ENCODE < /dev/null > /dev/null 2>&1 && BASE64=YES
+
+if [ $BASE64 = NO ]; then
+ BASE64_ENCODE=mimencode
+ BASE64_BEGIN="begin-base64 644 -"
+ BASE64_END="===="
+
+ $BASE64_ENCODE < /dev/null > /dev/null 2>&1 && BASE64=YES
+fi
+
+if [ $BZIP = NO -o $BASE64 = NO ]; then
+ echo "$0: can't use bz64 encoding: bzip2=$BZIP, $BASE64_ENCODE=$BASE64"
+ exit 1
+fi
+
+# Sadly, mimencode does not appear to have good "begin" and "end" markers
+# like uuencode does, and it is picky about getting the right start/end of
+# the base64 stream, so we handle this internally.
+echo "$BASE64_BEGIN"
+bzip2 -9 | $BASE64_ENCODE
+echo "$BASE64_END"
diff --git a/Documentation/BK-usage/cset-to-linus b/Documentation/BK-usage/cset-to-linus
index ae03b2c791bc1..d28a96f8c6180 100755
--- a/Documentation/BK-usage/cset-to-linus
+++ b/Documentation/BK-usage/cset-to-linus
@@ -1,4 +1,4 @@
-#!/usr/bin/perl5.6.1 -w
+#!/usr/bin/perl -w
use strict;
diff --git a/Documentation/BK-usage/csets-to-patches b/Documentation/BK-usage/csets-to-patches
index 3e135099442c1..e2b81c35883f2 100755
--- a/Documentation/BK-usage/csets-to-patches
+++ b/Documentation/BK-usage/csets-to-patches
@@ -1,4 +1,4 @@
-#!/usr/bin/perl5.6.1 -w
+#!/usr/bin/perl -w
use strict;
diff --git a/Documentation/BK-usage/unbz64wrap b/Documentation/BK-usage/unbz64wrap
new file mode 100755
index 0000000000000..ccef3dd267c72
--- /dev/null
+++ b/Documentation/BK-usage/unbz64wrap
@@ -0,0 +1,25 @@
+#!/bin/sh
+
+# unbz64wrap - the receiving side of a bzip2 | base64 stream
+# Andreas Dilger <adilger@clusterfs.com> Jan 2002
+
+# Sadly, mimencode does not appear to have good "begin" and "end" markers
+# like uuencode does, and it is picky about getting the right start/end of
+# the base64 stream, so we handle this explicitly here.
+
+PATH=$PATH:/usr/bin:/usr/local/bin:/usr/freeware/bin
+
+if mimencode -u < /dev/null > /dev/null 2>&1 ; then
+ SHOW=
+ while read LINE; do
+ case $LINE in
+ begin-base64*) SHOW=YES ;;
+ ====) SHOW= ;;
+ *) [ "$SHOW" ] && echo $LINE ;;
+ esac
+ done | mimencode -u | bunzip2
+ exit $?
+else
+ cat - | uudecode -o /dev/stdout | bunzip2
+ exit $?
+fi
diff --git a/Documentation/Changes b/Documentation/Changes
index 8d7aea65706e8..35bead6192eb0 100644
--- a/Documentation/Changes
+++ b/Documentation/Changes
@@ -55,7 +55,7 @@ o util-linux 2.10o # fdformat --version
o modutils 2.4.2 # insmod -V
o e2fsprogs 1.25 # tune2fs
o jfsutils 1.0.14 # fsck.jfs -V
-o reiserfsprogs 3.x.0j # reiserfsck 2>&1|grep reiserfsprogs
+o reiserfsprogs 3.x.1b # reiserfsck 2>&1|grep reiserfsprogs
o pcmcia-cs 3.1.21 # cardmgr -V
o PPP 2.4.0 # pppd --version
o isdn4k-utils 3.1pre1 # isdnctrl 2>&1|grep version
@@ -107,8 +107,8 @@ assembling the 16-bit boot code, removing the need for as86 to compile
your kernel. This change does, however, mean that you need a recent
release of binutils.
-System utililities
-==================
+System utilities
+================
Architectural changes
---------------------
@@ -320,7 +320,7 @@ o <http://oss.software.ibm.com/jfs>
Reiserfsprogs
-------------
-o <ftp://ftp.namesys.com/pub/reiserfsprogs/reiserfsprogs-3.x.0j.tar.gz>
+o <ftp://ftp.namesys.com/pub/reiserfsprogs/reiserfsprogs-3.x.0b.tar.gz>
LVM toolset
-----------
diff --git a/Documentation/DMA-mapping.txt b/Documentation/DMA-mapping.txt
index 1690b0ed01380..d51adf424b482 100644
--- a/Documentation/DMA-mapping.txt
+++ b/Documentation/DMA-mapping.txt
@@ -759,13 +759,10 @@ to "Closing".
Struct scatterlist must contain, at a minimum, the following
members:
- char *address;
struct page *page;
unsigned int offset;
unsigned int length;
- The "address" member will disappear in 2.5.x
-
This means that your pci_{map,unmap}_sg() and all other
interfaces dealing with scatterlists must be able to cope
properly with page being non NULL.
@@ -775,9 +772,6 @@ to "Closing".
If "address" is NULL, then "page+offset" is being used.
If "page" is NULL, then "address" is being used.
- In 2.5.x, all scatterlists will use "page+offset". But during
- 2.4.x we still have to support the old method.
-
2) More to come...
Closing
diff --git a/Documentation/DocBook/Makefile b/Documentation/DocBook/Makefile
index a564b85dc2605..c8f0c981ecac7 100644
--- a/Documentation/DocBook/Makefile
+++ b/Documentation/DocBook/Makefile
@@ -59,8 +59,8 @@ z8530book.sgml: z8530book.tmpl $(TOPDIR)/drivers/net/wan/z85230.c
$(TOPDIR)/scripts/docgen $(TOPDIR)/drivers/net/wan/z85230.c \
<z8530book.tmpl >z8530book.sgml
-via-audio.sgml: via-audio.tmpl $(TOPDIR)/drivers/sound/via82cxxx_audio.c
- $(TOPDIR)/scripts/docgen $(TOPDIR)/drivers/sound/via82cxxx_audio.c \
+via-audio.sgml: via-audio.tmpl $(TOPDIR)/sound/oss/via82cxxx_audio.c
+ $(TOPDIR)/scripts/docgen $(TOPDIR)/sound/oss/via82cxxx_audio.c \
<via-audio.tmpl >via-audio.sgml
tulip-user.sgml: tulip-user.tmpl
@@ -100,8 +100,8 @@ APISOURCES := $(TOPDIR)/drivers/media/video/videodev.c \
$(TOPDIR)/drivers/hotplug/pci_hotplug_core.c \
$(TOPDIR)/drivers/hotplug/pci_hotplug_util.c \
$(TOPDIR)/drivers/block/ll_rw_blk.c \
- $(TOPDIR)/drivers/sound/sound_core.c \
- $(TOPDIR)/drivers/sound/sound_firmware.c \
+ $(TOPDIR)/sound/sound_core.c \
+ $(TOPDIR)/sound/sound_firmware.c \
$(TOPDIR)/drivers/net/wan/syncppp.c \
$(TOPDIR)/drivers/net/wan/z85230.c \
$(TOPDIR)/drivers/usb/hcd.c \
diff --git a/Documentation/DocBook/kernel-api.tmpl b/Documentation/DocBook/kernel-api.tmpl
index 69bf709460267..8b7088186c0dd 100644
--- a/Documentation/DocBook/kernel-api.tmpl
+++ b/Documentation/DocBook/kernel-api.tmpl
@@ -203,8 +203,8 @@
<chapter id="snddev">
<title>Sound Devices</title>
-!Edrivers/sound/sound_core.c
-!Idrivers/sound/sound_firmware.c
+!Esound/sound_core.c
+!Isound/sound_firmware.c
</chapter>
<chapter id="usb">
diff --git a/Documentation/DocBook/via-audio.tmpl b/Documentation/DocBook/via-audio.tmpl
index f06641a623f78..0471cceb740ea 100644
--- a/Documentation/DocBook/via-audio.tmpl
+++ b/Documentation/DocBook/via-audio.tmpl
@@ -537,7 +537,7 @@ Version 1.1.6
</listitem>
<listitem>
<para>
- Optimize included headers to eliminate headers found in linux/drivers/sound
+ Optimize included headers to eliminate headers found in linux/sound
</para>
</listitem>
</itemizedlist>
@@ -587,7 +587,9 @@ Version 1.1.4
<chapter id="intfunctions">
<title>Internal Functions</title>
-!Idrivers/sound/via82cxxx_audio.c
+!Isound/oss/via82cxxx_audio.c
</chapter>
</book>
+
+
diff --git a/Documentation/SubmittingDrivers b/Documentation/SubmittingDrivers
index 4588d36af9f90..72574d485c240 100644
--- a/Documentation/SubmittingDrivers
+++ b/Documentation/SubmittingDrivers
@@ -3,7 +3,7 @@ Submitting Drivers For The Linux Kernel
This document is intended to explain how to submit device drivers to the
Linux 2.2 and 2.4 kernel trees. Note that if you are interested in video
-card drivers you should probably talk to XFree86 (http://wwww.xfree86.org)
+card drivers you should probably talk to XFree86 (http://www.xfree86.org)
instead.
Also read the Documentation/SubmittingPatches document.
diff --git a/Documentation/filesystems/Locking b/Documentation/filesystems/Locking
index 9d1a96f32e267..08a52c4f97643 100644
--- a/Documentation/filesystems/Locking
+++ b/Documentation/filesystems/Locking
@@ -140,6 +140,10 @@ prototypes:
int (*prepare_write)(struct file *, struct page *, unsigned, unsigned);
int (*commit_write)(struct file *, struct page *, unsigned, unsigned);
int (*bmap)(struct address_space *, long);
+ int (*flushpage) (struct page *, unsigned long);
+ int (*releasepage) (struct page *, int);
+ int (*direct_IO)(int, struct inode *, struct kiobuf *, unsigned long, int);
+
locking rules:
All may block
BKL PageLocked(page)
@@ -149,6 +153,8 @@ sync_page: no maybe
prepare_write: no yes
commit_write: no yes
bmap: yes
+flushpage: no yes
+releasepage: no yes
->prepare_write(), ->commit_write(), ->sync_page() and ->readpage()
may be called from the request handler (/dev/loop).
@@ -161,6 +167,15 @@ well-defined...
filesystems and by the swapper. The latter will eventually go away. All
instances do not actually need the BKL. Please, keep it that way and don't
breed new callers.
+ ->flushpage() is called when the filesystem must attempt to drop
+some or all of the buffers from the page when it is being truncated. It
+returns zero on success. If ->flushpage is zero, the kernel uses
+block_flushpage() instead.
+ ->releasepage() is called when the kernel is about to try to drop the
+buffers from the page in preparation for freeing it. It returns zero to
+indicate that the buffers are (or may be) freeable. If ->releasepage is zero,
+the kernel assumes that the fs has no private interest in the buffers.
+
Note: currently almost all instances of address_space methods are
using BKL for internal serialization and that's one of the worst sources
of contention. Normally they are calling library functions (in fs/buffer.c)
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index b4ed0da89f62f..be8601c616474 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -17,6 +17,7 @@ restrictions referred to are that the relevant option is valid if:
CD Appropriate CD support is enabled.
DEVFS devfs support is enabled.
DRM Direct Rendering Management support is enabled.
+ EFI EFI Partitioning (GPT) is enabled
EIDE EIDE/ATAPI support is enabled.
FB The frame buffer device is enabled.
HW Appropriate hardware is enabled.
@@ -219,6 +220,9 @@ running once the system is up.
gdth= [HW,SCSI]
+ gpt [EFI] Forces disk with valid GPT signature but
+ invalid Protective MBR to be treated as GPT.
+
gscd= [HW,CD]
gus= [HW,SOUND]
diff --git a/Documentation/networking/dl2k.txt b/Documentation/networking/dl2k.txt
index 04b18033bebcf..dbcf694c6a0c1 100644
--- a/Documentation/networking/dl2k.txt
+++ b/Documentation/networking/dl2k.txt
@@ -1,7 +1,7 @@
D-Link DL2000-based Gigabit Ethernet Adapter Installation
for Linux
- Jan 02, 2002
+ Jan 29, 2002
Contents
========
@@ -199,8 +199,8 @@ media=media_type - Specifies the media type the NIC operates at.
6 1000Mbps full duplex.
By default, the NIC operates at autosense.
- Note that only 1000mbps_fd and 1000mbps_hd
- types are available for fiber adapter.
+ 1000mbps_fd and 1000mbps_hd types are only
+ available for fiber adapter.
vlan=[0|1] - Specifies the VLAN ID. If vlan=0, the
Virtual Local Area Network (VLAN) function is
diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt
index e0588af1fd402..2de4d2736fe5e 100644
--- a/Documentation/networking/ip-sysctl.txt
+++ b/Documentation/networking/ip-sysctl.txt
@@ -126,7 +126,13 @@ tcp_max_tw_buckets - INTEGER
if network conditions require more than default value.
tcp_tw_recycle - BOOLEAN
- Enable fast recycling TIME-WAIT sockets. Default value is 1.
+ Enable fast recycling TIME-WAIT sockets. Default value is 0.
+ It should not be changed without advice/request of technical
+ experts.
+
+tcp_tw_reuse - BOOLEAN
+ Allow to reuse TIME-WAIT sockets for new connections when it is
+ safe from protocol viewpoint. Default value is 0.
It should not be changed without advice/request of technical
experts.
@@ -182,10 +188,7 @@ tcp_max_syn_backlog - INTEGER
still did not receive an acknowledgement from connecting client.
Default value is 1024 for systems with more than 128Mb of memory,
and 128 for low memory machines. If server suffers of overload,
- try to increase this number. Warning! If you make it greater
- than 1024, it would be better to change TCP_SYNQ_HSIZE in
- include/net/tcp.h to keep TCP_SYNQ_HSIZE*16<=tcp_max_syn_backlog
- and to recompile kernel.
+ try to increase this number.
tcp_window_scaling - BOOLEAN
Enable window scaling as defined in RFC1323.
@@ -358,6 +361,17 @@ mc_forwarding - BOOLEAN
Do multicast routing. The kernel needs to be compiled with CONFIG_MROUTE
and a multicast routing daemon is required.
+medium_id - INTEGER
+ Integer value used to differentiate the devices by the medium they
+ are attached to. Two devices can have different id values when
+ the broadcast packets are received only on one of them.
+ The default value 0 means that the device is the only interface
+ to its medium, value of -1 means that medium is not known.
+
+ Currently, it is used to change the proxy_arp behavior:
+ the proxy_arp feature is enabled for packets forwarded between
+ two devices attached to different media.
+
proxy_arp - BOOLEAN
Do proxy arp.
diff --git a/Documentation/networking/ppp_generic.txt b/Documentation/networking/ppp_generic.txt
new file mode 100644
index 0000000000000..15b5172fbb986
--- /dev/null
+++ b/Documentation/networking/ppp_generic.txt
@@ -0,0 +1,432 @@
+ PPP Generic Driver and Channel Interface
+ ----------------------------------------
+
+ Paul Mackerras
+ paulus@samba.org
+ 7 Feb 2002
+
+The generic PPP driver in linux-2.4 provides an implementation of the
+functionality which is of use in any PPP implementation, including:
+
+* the network interface unit (ppp0 etc.)
+* the interface to the networking code
+* PPP multilink: splitting datagrams between multiple links, and
+ ordering and combining received fragments
+* the interface to pppd, via a /dev/ppp character device
+* packet compression and decompression
+* TCP/IP header compression and decompression
+* detecting network traffic for demand dialling and for idle timeouts
+* simple packet filtering
+
+For sending and receiving PPP frames, the generic PPP driver calls on
+the services of PPP `channels'. A PPP channel encapsulates a
+mechanism for transporting PPP frames from one machine to another. A
+PPP channel implementation can be arbitrarily complex internally but
+has a very simple interface with the generic PPP code: it merely has
+to be able to send PPP frames, receive PPP frames, and optionally
+handle ioctl requests. Currently there are PPP channel
+implementations for asynchronous serial ports, synchronous serial
+ports, and for PPP over ethernet.
+
+This architecture makes it possible to implement PPP multilink in a
+natural and straightforward way, by allowing more than one channel to
+be linked to each ppp network interface unit. The generic layer is
+responsible for splitting datagrams on transmit and recombining them
+on receive.
+
+
+PPP channel API
+---------------
+
+See include/linux/ppp_channel.h for the declaration of the types and
+functions used to communicate between the generic PPP layer and PPP
+channels.
+
+Each channel has to provide two functions to the generic PPP layer,
+via the ppp_channel.ops pointer:
+
+* start_xmit() is called by the generic layer when it has a frame to
+ send. The channel has the option of rejecting the frame for
+ flow-control reasons. In this case, start_xmit() should return 0
+ and the channel should call the ppp_output_wakeup() function at a
+ later time when it can accept frames again, and the generic layer
+ will then attempt to retransmit the rejected frame(s). If the frame
+ is accepted, the start_xmit() function should return 1.
+
+* ioctl() provides an interface which can be used by a user-space
+ program to control aspects of the channel's behaviour. This
+ procedure will be called when a user-space program does an ioctl
+ system call on an instance of /dev/ppp which is bound to the
+ channel. (Usually it would only be pppd which would do this.)
+
+The generic PPP layer provides seven functions to channels:
+
+* ppp_register_channel() is called when a channel has been created, to
+ notify the PPP generic layer of its presence. For example, setting
+ a serial port to the PPPDISC line discipline causes the ppp_async
+ channel code to call this function.
+
+* ppp_unregister_channel() is called when a channel is to be
+ destroyed. For example, the ppp_async channel code calls this when
+ a hangup is detected on the serial port.
+
+* ppp_output_wakeup() is called by a channel when it has previously
+ rejected a call to its start_xmit function, and can now accept more
+ packets.
+
+* ppp_input() is called by a channel when it has received a complete
+ PPP frame.
+
+* ppp_input_error() is called by a channel when it has detected that a
+ frame has been lost or dropped (for example, because of a FCS (frame
+ check sequence) error).
+
+* ppp_channel_index() returns the channel index assigned by the PPP
+ generic layer to this channel. The channel should provide some way
+ (e.g. an ioctl) to transmit this back to user-space, as user-space
+ will need it to attach an instance of /dev/ppp to this channel.
+
+* ppp_unit_number() returns the unit number of the ppp network
+ interface to which this channel is connected, or -1 if the channel
+ is not connected.
+
+Connecting a channel to the ppp generic layer is initiated from the
+channel code, rather than from the generic layer. The channel is
+expected to have some way for a user-level process to control it
+independently of the ppp generic layer. For example, with the
+ppp_async channel, this is provided by the file descriptor to the
+serial port.
+
+Generally a user-level process will initialize the underlying
+communications medium and prepare it to do PPP. For example, with an
+async tty, this can involve setting the tty speed and modes, issuing
+modem commands, and then going through some sort of dialog with the
+remote system to invoke PPP service there. We refer to this process
+as `discovery'. Then the user-level process tells the medium to
+become a PPP channel and register itself with the generic PPP layer.
+The channel then has to report the channel number assigned to it back
+to the user-level process. From that point, the PPP negotiation code
+in the PPP daemon (pppd) can take over and perform the PPP
+negotiation, accessing the channel through the /dev/ppp interface.
+
+At the interface to the PPP generic layer, PPP frames are stored in
+skbuff structures and start with the two-byte PPP protocol number.
+The frame does *not* include the 0xff `address' byte or the 0x03
+`control' byte that are optionally used in async PPP. Nor is there
+any escaping of control characters, nor are there any FCS or framing
+characters included. That is all the responsibility of the channel
+code, if it is needed for the particular medium. That is, the skbuffs
+presented to the start_xmit() function contain only the 2-byte
+protocol number and the data, and the skbuffs presented to ppp_input()
+must be in the same format.
+
+The channel must provide an instance of a ppp_channel struct to
+represent the channel. The channel is free to use the `private' field
+however it wishes. The channel should initialize the `mtu' and
+`hdrlen' fields before calling ppp_register_channel() and not change
+them until after ppp_unregister_channel() returns. The `mtu' field
+represents the maximum size of the data part of the PPP frames, that
+is, it does not include the 2-byte protocol number.
+
+If the channel needs some headroom in the skbuffs presented to it for
+transmission (i.e., some space free in the skbuff data area before the
+start of the PPP frame), it should set the `hdrlen' field of the
+ppp_channel struct to the amount of headroom required. The generic
+PPP layer will attempt to provide that much headroom but the channel
+should still check if there is sufficient headroom and copy the skbuff
+if there isn't.
+
+On the input side, channels should ideally provide at least 2 bytes of
+headroom in the skbuffs presented to ppp_input(). The generic PPP
+code does not require this but will be more efficient if this is done.
+
+
+Buffering and flow control
+--------------------------
+
+The generic PPP layer has been designed to minimize the amount of data
+that it buffers in the transmit direction. It maintains a queue of
+transmit packets for the PPP unit (network interface device) plus a
+queue of transmit packets for each attached channel. Normally the
+transmit queue for the unit will contain at most one packet; the
+exceptions are when pppd sends packets by writing to /dev/ppp, and
+when the core networking code calls the generic layer's start_xmit()
+function with the queue stopped, i.e. when the generic layer has
+called netif_stop_queue(), which only happens on a transmit timeout.
+The start_xmit function always accepts and queues the packet which it
+is asked to transmit.
+
+Transmit packets are dequeued from the PPP unit transmit queue and
+then subjected to TCP/IP header compression and packet compression
+(Deflate or BSD-Compress compression), as appropriate. After this
+point the packets can no longer be reordered, as the decompression
+algorithms rely on receiving compressed packets in the same order that
+they were generated.
+
+If multilink is not in use, this packet is then passed to the attached
+channel's start_xmit() function. If the channel refuses to take
+the packet, the generic layer saves it for later transmission. The
+generic layer will call the channel's start_xmit() function again
+when the channel calls ppp_output_wakeup() or when the core
+networking code calls the generic layer's start_xmit() function
+again. The generic layer contains no timeout and retransmission
+logic; it relies on the core networking code for that.
+
+If multilink is in use, the generic layer divides the packet into one
+or more fragments and puts a multilink header on each fragment. It
+decides how many fragments to use based on the length of the packet
+and the number of channels which are potentially able to accept a
+fragment at the moment. A channel is potentially able to accept a
+fragment if it doesn't have any fragments currently queued up for it
+to transmit. The channel may still refuse a fragment; in this case
+the fragment is queued up for the channel to transmit later. This
+scheme has the effect that more fragments are given to higher-
+bandwidth channels. It also means that under light load, the generic
+layer will tend to fragment large packets across all the channels,
+thus reducing latency, while under heavy load, packets will tend to be
+transmitted as single fragments, thus reducing the overhead of
+fragmentation.
+
+
+SMP safety
+----------
+
+The PPP generic layer has been designed to be SMP-safe. Locks are
+used around accesses to the internal data structures where necessary
+to ensure their integrity. As part of this, the generic layer
+requires that the channels adhere to certain requirements and in turn
+provides certain guarantees to the channels. Essentially the channels
+are required to provide the appropriate locking on the ppp_channel
+structures that form the basis of the communication between the
+channel and the generic layer. This is because the channel provides
+the storage for the ppp_channel structure, and so the channel is
+required to provide the guarantee that this storage exists and is
+valid at the appropriate times.
+
+The generic layer requires these guarantees from the channel:
+
+* The ppp_channel object must exist from the time that
+ ppp_register_channel() is called until after the call to
+ ppp_unregister_channel() returns.
+
+* No thread may be in a call to any of ppp_input(), ppp_input_error(),
+ ppp_output_wakeup(), ppp_channel_index() or ppp_unit_number() for a
+ channel at the time that ppp_unregister_channel() is called for that
+ channel.
+
+* ppp_register_channel() and ppp_unregister_channel() must be called
+ from process context, not interrupt or softirq/BH context.
+
+* The remaining generic layer functions may be called at softirq/BH
+ level but must not be called from a hardware interrupt handler.
+
+* The generic layer may call the channel start_xmit() function at
+ softirq/BH level but will not call it at interrupt level. Thus the
+ start_xmit() function may not block.
+
+* The generic layer will only call the channel ioctl() function in
+ process context.
+
+The generic layer provides these guarantees to the channels:
+
+* The generic layer will not call the start_xmit() function for a
+ channel while any thread is already executing in that function for
+ that channel.
+
+* The generic layer will not call the ioctl() function for a channel
+ while any thread is already executing in that function for that
+ channel.
+
+* By the time a call to ppp_unregister_channel() returns, no thread
+ will be executing in a call from the generic layer to that channel's
+ start_xmit() or ioctl() function, and the generic layer will not
+ call either of those functions subsequently.
+
+
+Interface to pppd
+-----------------
+
+The PPP generic layer exports a character device interface called
+/dev/ppp. This is used by pppd to control PPP interface units and
+channels. Although there is only one /dev/ppp, each open instance of
+/dev/ppp acts independently and can be attached either to a PPP unit
+or a PPP channel. This is achieved using the file->private_data field
+to point to a separate object for each open instance of /dev/ppp. In
+this way an effect similar to Solaris' clone open is obtained,
+allowing us to control an arbitrary number of PPP interfaces and
+channels without having to fill up /dev with hundreds of device names.
+
+When /dev/ppp is opened, a new instance is created which is initially
+unattached. Using an ioctl call, it can then be attached to an
+existing unit, attached to a newly-created unit, or attached to an
+existing channel. An instance attached to a unit can be used to send
+and receive PPP control frames, using the read() and write() system
+calls, along with poll() if necessary. Similarly, an instance
+attached to a channel can be used to send and receive PPP frames on
+that channel.
+
+In multilink terms, the unit represents the bundle, while the channels
+represent the individual physical links. Thus, a PPP frame sent by a
+write to the unit (i.e., to an instance of /dev/ppp attached to the
+unit) will be subject to bundle-level compression and to fragmentation
+across the individual links (if multilink is in use). In contrast, a
+PPP frame sent by a write to the channel will be sent as-is on that
+channel, without any multilink header.
+
+A channel is not initially attached to any unit. In this state it can
+be used for PPP negotiation but not for the transfer of data packets.
+It can then be connected to a PPP unit with an ioctl call, which
+makes it available to send and receive data packets for that unit.
+
+The ioctl calls which are available on an instance of /dev/ppp depend
+on whether it is unattached, attached to a PPP interface, or attached
+to a PPP channel. The ioctl calls which are available on an
+unattached instance are:
+
+* PPPIOCNEWUNIT creates a new PPP interface and makes this /dev/ppp
+ instance the "owner" of the interface. The argument should point to
+ an int which is the desired unit number if >= 0, or -1 to assign the
+ lowest unused unit number. Being the owner of the interface means
+ that the interface will be shut down if this instance of /dev/ppp is
+ closed.
+
+* PPPIOCATTACH attaches this instance to an existing PPP interface.
+ The argument should point to an int containing the unit number.
+ This does not make this instance the owner of the PPP interface.
+
+* PPPIOCATTCHAN attaches this instance to an existing PPP channel.
+ The argument should point to an int containing the channel number.
+
+The ioctl calls available on an instance of /dev/ppp attached to a
+channel are:
+
+* PPPIOCDETACH detaches the instance from the channel. This ioctl is
+ deprecated since the same effect can be achieved by closing the
+ instance. In order to prevent possible races this ioctl will fail
+ with an EINVAL error if more than one file descriptor refers to this
+ instance (i.e. as a result of dup(), dup2() or fork()).
+
+* PPPIOCCONNECT connects this channel to a PPP interface. The
+ argument should point to an int containing the interface unit
+ number. It will return an EINVAL error if the channel is already
+ connected to an interface, or ENXIO if the requested interface does
+ not exist.
+
+* PPPIOCDISCONN disconnects this channel from the PPP interface that
+ it is connected to. It will return an EINVAL error if the channel
+ is not connected to an interface.
+
+* All other ioctl commands are passed to the channel ioctl() function.
+
+The ioctl calls that are available on an instance that is attached to
+an interface unit are:
+
+* PPPIOCSMRU sets the MRU (maximum receive unit) for the interface.
+ The argument should point to an int containing the new MRU value.
+
+* PPPIOCSFLAGS sets flags which control the operation of the
+ interface. The argument should be a pointer to an int containing
+ the new flags value. The bits in the flags value that can be set
+ are:
+ SC_COMP_TCP enable transmit TCP header compression
+ SC_NO_TCP_CCID disable connection-id compression for
+ TCP header compression
+ SC_REJ_COMP_TCP disable receive TCP header decompression
+ SC_CCP_OPEN Compression Control Protocol (CCP) is
+ open, so inspect CCP packets
+ SC_CCP_UP CCP is up, may (de)compress packets
+ SC_LOOP_TRAFFIC send IP traffic to pppd
+ SC_MULTILINK enable PPP multilink fragmentation on
+ transmitted packets
+ SC_MP_SHORTSEQ expect short multilink sequence
+ numbers on received multilink fragments
+ SC_MP_XSHORTSEQ transmit short multilink sequence nos.
+
+ The values of these flags are defined in <linux/if_ppp.h>. Note
+ that the values of the SC_MULTILINK, SC_MP_SHORTSEQ and
+ SC_MP_XSHORTSEQ bits are ignored if the CONFIG_PPP_MULTILINK option
+ is not selected.
+
+* PPPIOCGFLAGS returns the value of the status/control flags for the
+ interface unit. The argument should point to an int where the ioctl
+ will store the flags value. As well as the values listed above for
+ PPPIOCSFLAGS, the following bits may be set in the returned value:
+ SC_COMP_RUN CCP compressor is running
+ SC_DECOMP_RUN CCP decompressor is running
+ SC_DC_ERROR CCP decompressor detected non-fatal error
+ SC_DC_FERROR CCP decompressor detected fatal error
+
+* PPPIOCSCOMPRESS sets the parameters for packet compression or
+ decompression. The argument should point to a ppp_option_data
+ structure (defined in <linux/if_ppp.h>), which contains a
+ pointer/length pair which should describe a block of memory
+ containing a CCP option specifying a compression method and its
+ parameters. The ppp_option_data struct also contains a `transmit'
+ field. If this is 0, the ioctl will affect the receive path,
+ otherwise the transmit path.
+
+* PPPIOCGUNIT returns, in the int pointed to by the argument, the unit
+ number of this interface unit.
+
+* PPPIOCSDEBUG sets the debug flags for the interface to the value in
+ the int pointed to by the argument. Only the least significant bit
+ is used; if this is 1 the generic layer will print some debug
+ messages during its operation. This is only intended for debugging
+ the generic PPP layer code; it is generally not helpful for working
+ out why a PPP connection is failing.
+
+* PPPIOCGDEBUG returns the debug flags for the interface in the int
+ pointed to by the argument.
+
+* PPPIOCGIDLE returns the time, in seconds, since the last data
+ packets were sent and received. The argument should point to a
+ ppp_idle structure (defined in <linux/ppp_defs.h>). If the
+ CONFIG_PPP_FILTER option is enabled, the set of packets which reset
+ the transmit and receive idle timers is restricted to those which
+ pass the `active' packet filter.
+
+* PPPIOCSMAXCID sets the maximum connection-ID parameter (and thus the
+ number of connection slots) for the TCP header compressor and
+ decompressor. The lower 16 bits of the int pointed to by the
+ argument specify the maximum connection-ID for the compressor. If
+ the upper 16 bits of that int are non-zero, they specify the maximum
+ connection-ID for the decompressor, otherwise the decompressor's
+ maximum connection-ID is set to 15.
+
+* PPPIOCSNPMODE sets the network-protocol mode for a given network
+ protocol. The argument should point to an npioctl struct (defined
+ in <linux/if_ppp.h>). The `protocol' field gives the PPP protocol
+ number for the protocol to be affected, and the `mode' field
+ specifies what to do with packets for that protocol:
+
+ NPMODE_PASS normal operation, transmit and receive packets
+ NPMODE_DROP silently drop packets for this protocol
+ NPMODE_ERROR drop packets and return an error on transmit
+ NPMODE_QUEUE queue up packets for transmit, drop received
+ packets
+
+ At present NPMODE_ERROR and NPMODE_QUEUE have the same effect as
+ NPMODE_DROP.
+
+* PPPIOCGNPMODE returns the network-protocol mode for a given
+ protocol. The argument should point to an npioctl struct with the
+ `protocol' field set to the PPP protocol number for the protocol of
+ interest. On return the `mode' field will be set to the network-
+ protocol mode for that protocol.
+
+* PPPIOCSPASS and PPPIOCSACTIVE set the `pass' and `active' packet
+ filters. These ioctls are only available if the CONFIG_PPP_FILTER
+ option is selected. The argument should point to a sock_fprog
+ structure (defined in <linux/filter.h>) containing the compiled BPF
+ instructions for the filter. Packets are dropped if they fail the
+ `pass' filter; otherwise, if they fail the `active' filter they are
+ passed but they do not reset the transmit or receive idle timer.
+
+* PPPIOCSMRRU enables or disables multilink processing for received
+ packets and sets the multilink MRRU (maximum reconstructed receive
+ unit). The argument should point to an int containing the new MRRU
+ value. If the MRRU value is 0, processing of received multilink
+ fragments is disabled. This ioctl is only available if the
+ CONFIG_PPP_MULTILINK option is selected.
+
+Last modified: 7-feb-2002
diff --git a/Documentation/sonypi.txt b/Documentation/sonypi.txt
index 24d391c6ba11a..4d5a8c6ee5f1a 100644
--- a/Documentation/sonypi.txt
+++ b/Documentation/sonypi.txt
@@ -25,7 +25,8 @@ A simple daemon which translates the jogdial movements into mouse wheel events
can be downloaded at: <http://www.alcove-labs.org/en/software/sonypi/>
This driver supports also some ioctl commands for setting the LCD screen
-brightness (some more commands may be added in the future).
+brightness and querying the batteries charge information (some more
+commands may be added in the future).
This driver can also be used to set the camera controls on Picturebook series
(brightness, contrast etc), and is used by the video4linux driver for the
diff --git a/Documentation/sound/oss/AudioExcelDSP16 b/Documentation/sound/oss/AudioExcelDSP16
index f4ffd9d0c2e13..d6130d959129a 100644
--- a/Documentation/sound/oss/AudioExcelDSP16
+++ b/Documentation/sound/oss/AudioExcelDSP16
@@ -2,7 +2,7 @@ Driver
------
Informations about Audio Excel DSP 16 driver can be found in the source
-file lowlevel/aedsp16.c
+file aedsp16.c
Please, read the head of the source before using it. It contain useful
informations.
diff --git a/Documentation/usb/se401.txt b/Documentation/usb/se401.txt
index 46c9bc57b20b1..7b9d1c960a10f 100644
--- a/Documentation/usb/se401.txt
+++ b/Documentation/usb/se401.txt
@@ -40,7 +40,7 @@ net frequency. Valid options for this option are 0, 50 and 60. (0=disable,
KNOWN PROBLEMS:
The driver works fine with the usb-ohci and uhci host controller drivers,
-the default settings also work with usb-uhci. But sending more then one bulk
+the default settings also work with usb-uhci. But sending more than one bulk
transfer at a time with usb-uhci doesn't work yet.
Users of usb-ohci and uhci can safely enlarge SE401_NUMSBUF in se401.h in
order to increase the throughput (and thus framerate).
diff --git a/Documentation/video4linux/Zoran b/Documentation/video4linux/Zoran
index 67d87ff8ff911..e1dda3e4ab143 100644
--- a/Documentation/video4linux/Zoran
+++ b/Documentation/video4linux/Zoran
@@ -160,9 +160,9 @@ grabbing facilities, you must either
set aside the necessary memory during boot time. There seem to be
several versions of this patch against various kernel versions
floating around in the net, you may obtain one e.g. from:
- http://www.polyware.nl/~middelin/patch/bigphysarea-2.2.1.tar.gz You
- also have to compile your driver AFTER installing that patch in order
- to get it working
+ http://www.polyware.nl/~middelin/hob-v4l.html#bigphysarea
+ You also have to compile your driver AFTER installing that patch in
+ order to get it working
or
diff --git a/Documentation/video4linux/bttv/README.freeze b/Documentation/video4linux/bttv/README.freeze
index 55642faa0d321..968a5c3eb4464 100644
--- a/Documentation/video4linux/bttv/README.freeze
+++ b/Documentation/video4linux/bttv/README.freeze
@@ -46,10 +46,6 @@ Sometimes problems show up with bttv just because of the high load on
the PCI bus. The bt848/878 chips have a few workarounds for known
incompatibilities, see README.quirks.
-Some folks report that increasing the pci latency helps too,
-althrought I'm not sure whenever this really fixes the problems or
-only makes it less likely to happen.
-
Some mainboard have problems to deal correctly with multiple devices
doing DMA at the same time. bttv + ide seems to cause this sometimes,
if this is the case you likely see freezes only with video and hard disk
diff --git a/Documentation/video4linux/w9966.txt b/Documentation/video4linux/w9966.txt
index d132c43019a43..e7ac33a7eb06c 100644
--- a/Documentation/video4linux/w9966.txt
+++ b/Documentation/video4linux/w9966.txt
@@ -1,37 +1,33 @@
+W9966 Camera driver, written by Jakob Kemi (jakob.kemi@telia.com)
-W9966 Camera driver, written by Jakob Kemi (jakob.kemi@post.utfors.se)
+After a lot of work in softice & wdasm, reading .pdf-files and tiresome
+trial-and-error work I've finally got everything to work. I needed vision for a
+robotics project so I borrowed this camera from a friend and started hacking.
+Anyway I've converted my original code from the AVR 8bit RISC C/ASM code into
+a working Linux driver.
-Ok, after a lot of work in softice, wdasm, reading pdf-files
-and trial-and-error work I've finally got everything to work.
-Since I needed some vision for a robotics project I borrowed
-this camera from a friend and started hacking. Anyway I've
-converted my original code from the AVR 8bit RISC C/asm
-into a working linux driver. I would really appreciate _any_
-kind of feedback regarding this driver.
+To get it working simply configure your kernel to support
+parport, ieee1284, video4linux and w9966
-To get it working quickly configure your kernel
-to support parport, ieee1284, video4linux, experimental drivers
-and w9966
-
-If w9966 is statically linked it will perform aggressive probing
-for the camera. If built as a module you'll have more configuration options.
+If w9966 is statically linked it will always perform aggressive probing for
+the camera. If built as a module you'll have more configuration options.
Options:
-modprobe w9966.o pardev=parport0(or whatever) parmode=0 (0=auto, 1=ecp, 2=epp)
-
+ modprobe w9966.o pardev=parport0(or whatever) parmode=0 (0=auto, 1=ecp, 2=epp)
voila!
you can also type 'modinfo -p w9966.o' for option usage
(or checkout w9966.c)
-I've only tested it with custom built testprograms
-(http://hem.fyristorg.com/mogul/w9966.html) and with gqcam.
-(you'll need to tweak the code to qcam a bit to make it work,
-dimensions and such)
+The only thing to keep in mind is that the image format is in Y-U-Y-V format
+where every two pixels take 4 bytes. In SDL (www.libsdl.org) this format
+is called VIDEO_PALETTE_YUV422 (16 bpp).
+
+A minimal test application (with source) is available from:
+ http://hem.fyristorg.com/mogul/w9966.html
The slow framerate is due to missing DMA ECP read support in the
parport drivers. I might add working EPP support later.
Good luck!
-
- /Jakob
+ /Jakob Kemi
diff --git a/Documentation/watchdog-api.txt b/Documentation/watchdog-api.txt
new file mode 100644
index 0000000000000..ce180c34967f6
--- /dev/null
+++ b/Documentation/watchdog-api.txt
@@ -0,0 +1,390 @@
+The Linux Watchdog driver API.
+
+Copyright 2002 Christer Weingel <wingel@nano-system.com>
+
+Some parts of this document are copied verbatim from the sbc60xxwdt
+driver which is (c) Copyright 2000 Jakob Oestergaard <jakob@ostenfeld.dk>
+
+This document describes the state of the Linux 2.4.18 kernel.
+
+Introduction:
+
+A Watchdog Timer (WDT) is a hardware circuit that can reset the
+computer system in case of a software fault. You probably knew that
+already.
+
+Usually a userspace daemon will notify the kernel watchdog driver via the
+/dev/watchdog special device file that userspace is still alive, at
+regular intervals. When such a notification occurs, the driver will
+usually tell the hardware watchdog that everything is in order, and
+that the watchdog should wait for yet another little while to reset
+the system. If userspace fails (RAM error, kernel bug, whatever), the
+notifications cease to occur, and the hardware watchdog will reset the
+system (causing a reboot) after the timeout occurs.
+
+The Linux watchdog API is a rather AD hoc construction and different
+drivers implement different, and sometimes incompatible, parts of it.
+This file is an attempt to document the existing usage and allow
+future driver writers to use it as a reference.
+
+The simplest API:
+
+All drivers support the basic mode of operation, where the watchdog
+activates as soon as /dev/watchdog is opened and will reboot unless
+the watchdog is pinged within a certain time, this time is called the
+timeout or margin. The simplest way to ping the watchdog is to write
+some data to the device. So a very simple watchdog daemon would look
+like this:
+
+int main(int argc, const char *argv[]) {
+ int fd=open("/dev/watchdog",O_WRONLY);
+ if (fd==-1) {
+ perror("watchdog");
+ exit(1);
+ }
+ while(1) {
+ write(fd, "\0", 1);
+ sleep(10);
+ }
+}
+
+A more advanced driver could for example check that a HTTP server is
+still responding before doing the write call to ping the watchdog.
+
+When the device is closed, the watchdog is disabled. This is not
+always such a good idea, since if there is a bug in the watchdog
+daemon and it crashes the system will not reboot. Because of this,
+some of the drivers support the configuration option "Disable watchdog
+shutdown on close", CONFIG_WATCHDOG_NOWAYOUT. If it is set to Y when
+compiling the kernel, there is no way of disabling the watchdog once
+it has been started. So, if the watchdog dameon crashes, the system
+will reboot after the timeout has passed.
+
+Some other drivers will not disable the watchdog, unless a specific
+magic character 'V' has been sent /dev/watchdog just before closing
+the file. If the userspace daemon closes the file without sending
+this special character, the driver will assume that the daemon (and
+userspace in general) died, and will stop pinging the watchdog without
+disabling it first. This will then cause a reboot.
+
+The ioctl API:
+
+All conforming drivers also support an ioctl API.
+
+Pinging the watchdog using an ioctl:
+
+All drivers that have an ioctl interface support at least one ioctl,
+KEEPALIVE. This ioctl does exactly the same thing as a write to the
+watchdog device, so the main loop in the above program could be
+replaced with:
+
+ while (1) {
+ ioctl(fd, WDIOC_KEEPALIVE, 0);
+ sleep(10);
+ }
+
+the argument to the ioctl is ignored.
+
+Setting and getting the timeout:
+
+For some drivers it is possible to modify the watchdog timeout on the
+fly with the SETTIMEOUT ioctl, those drivers have the WDIOF_SETTIMEOUT
+flag set in their option field. The argument is an integer
+representing the timeout in seconds. The driver returns the real
+timeout used in the same variable, and this timeout might differ from
+the requested one due to limitation of the hardware.
+
+ int timeout = 45;
+ ioctl(fd, WDIOC_SETTIMEOUT, &timeout);
+ printf("The timeout was set to %d seconds\n", timeout);
+
+This example might actually print "The timeout was set to 60 seconds"
+if the device has a granularity of minutes for its timeout.
+
+Starting with the Linux 2.4.18 kernel, it is possible to query the
+current timeout using the GETTIMEOUT ioctl.
+
+ ioctl(fd, WDIOC_GETTIMEOUT, &timeout);
+ printf("The timeout was is %d seconds\n", timeout);
+
+Envinronmental monitoring:
+
+All watchdog drivers are required return more information about the system,
+some do temperature, fan and power level monitoring, some can tell you
+the reason for the last reboot of the system. The GETSUPPORT ioctl is
+available to ask what the device can do:
+
+ struct watchdog_info ident;
+ ioctl(fd, WDIOC_GETSUPPORT, &ident);
+
+the fields returned in the ident struct are:
+
+ identity a string identifying the watchdog driver
+ firmware_version the firmware version of the card if available
+ options a flags describing what the device supports
+
+the options field can have the following bits set, and describes what
+kind of information that the GET_STATUS and GET_BOOT_STATUS ioctls can
+return. [FIXME -- Is this correct?]
+
+ WDIOF_OVERHEAT Reset due to CPU overheat
+
+The machine was last rebooted by the watchdog because the thermal limit was
+exceeded
+
+ WDIOF_FANFAULT Fan failed
+
+A system fan monitored by the watchdog card has failed
+
+ WDIOF_EXTERN1 External relay 1
+
+External monitoring relay/source 1 was triggered. Controllers intended for
+real world applications include external monitoring pins that will trigger
+a reset.
+
+ WDIOF_EXTERN2 External relay 2
+
+External monitoring relay/source 2 was triggered
+
+ WDIOF_POWERUNDER Power bad/power fault
+
+The machine is showing an undervoltage status
+
+ WDIOF_CARDRESET Card previously reset the CPU
+
+The last reboot was caused by the watchdog card
+
+ WDIOF_POWEROVER Power over voltage
+
+The machine is showing an overvoltage status. Note that if one level is
+under and one over both bits will be set - this may seem odd but makes
+sense.
+
+ WDIOF_KEEPALIVEPING Keep alive ping reply
+
+The watchdog saw a keepalive ping since it was last queried.
+
+ WDIOF_SETTIMEOUT Can set/get the timeout
+
+
+For those drivers that return any bits set in the option field, the
+GETSTATUS and GETBOOTSTATUS ioctls can be used to ask for the current
+status, and the status at the last reboot, respectively.
+
+ int flags;
+ ioctl(fd, WDIOC_GETSTATUS, &flags);
+
+ or
+
+ ioctl(fd, WDIOC_GETBOOTSTATUS, &flags);
+
+Note that not all devices support these two calls, and some only
+support the GETBOOTSTATUS call.
+
+Some drivers can measure the temperature using the GETTEMP ioctl. The
+returned value is the temperature in degrees farenheit.
+
+ int temperature;
+ ioctl(fd, WDIOC_GETTEMP, &temperature);
+
+Finally the SETOPTIONS ioctl can be used to control some aspects of
+the cards operation; right now the pcwd driver is the only one
+supporting thiss ioctl.
+
+ int options = 0;
+ ioctl(fd, WDIOC_SETOPTIONS, options);
+
+The following options are available:
+
+ WDIOS_DISABLECARD Turn off the watchdog timer
+ WDIOS_ENABLECARD Turn on the watchdog timer
+ WDIOS_TEMPPANIC Kernel panic on temperature trip
+
+[FIXME -- better explanations]
+
+Implementations in the current drivers in the kernel tree:
+
+Here I have tried to summarize what the different drivers support and
+where they do strange things compared to the other drivers.
+
+acquirewdt.c -- Acquire Single Board Computer
+
+ This driver has a hardcoded timeout of 1 minute
+
+ Supports CONFIG_WATCHDOG_NOWAYOUT
+
+ GETSUPPORT returns KEEPALIVEPING. GETSTATUS will return 1 if
+ the device is open, 0 if not. [FIXME -- isn't this rather
+ silly? To be able to use the ioctl, the device must be open
+ and so GETSTATUS will always return 1].
+
+advantechwdt.c -- Advantech Single Board Computer
+
+ Timeout that defaults to 60 seconds, supports SETTIMEOUT.
+
+ Supports CONFIG_WATCHDOG_NOWAYOUT
+
+ GETSUPPORT returns WDIOF_KEEPALIVEPING and WDIOF_SETTIMEOUT.
+ The GETSTATUS call returns if the device is open or not.
+ [FIXME -- silliness again?]
+
+eurotechwdt.c -- Eurotech CPU-1220/1410
+
+ The timeout can be set using the SETTIMEOUT ioctl and defaults
+ to 60 seconds.
+
+ Also has a module parameter "ev", event type which controls
+ what should happen on a timeout, the string "int" or anything
+ else that causes a reboot. [FIXME -- better description]
+
+ Supports CONFIG_WATCHDOG_NOWAYOUT
+
+ GETSUPPORT returns CARDRESET and WDIOF_SETTIMEOUT but
+ GETSTATUS is not supported and GETBOOTSTATUS just returns 0.
+
+i810-tco.c -- Intel 810 chipset
+
+ Also has support for a lot of other i8x0 stuff, but the
+ watchdog is one of the things.
+
+ The timeout is set using the module parameter "i810_margin",
+ which is in steps of 0.6 seconds where 2<i810_margin<64. The
+ driver supports the SETTIMEOUT ioctl.
+
+ Supports CONFIG_WATCHDOG_NOWAYOUT.
+
+ GETSUPPORT returns WDIOF_SETTIMEOUT. The GETSTATUS call
+ returns some kind of timer value which ist not compatible with
+ the other drivers. GETBOOT status returns some kind of
+ hardware specific boot status. [FIXME -- describe this]
+
+ib700wdt.c -- IB700 Single Board Computer
+
+ Default timeout of 30 seconds and the timeout is settable
+ using the SETTIMEOUT ioctl. Note that only a few timeout
+ values are supported.
+
+ Supports CONFIG_WATCHDOG_NOWAYOUT
+
+ GETSUPPORT returns WDIOF_KEEPALIVEPING and WDIOF_SETTIMEOUT.
+ The GETSTATUS call returns if the device is open or not.
+ [FIXME -- silliness again?]
+
+machzwd.c -- MachZ ZF-Logic
+
+ Hardcoded timeout of 10 seconds
+
+ Has a module parameter "action" that controls what happens
+ when the timeout runs out which can be 0 = RESET (default),
+ 1 = SMI, 2 = NMI, 3 = SCI.
+
+ Supports CONFIG_WATCHDOG_NOWAYOUT and the the magic character
+ 'V' close handling.
+
+ GETSUPPORT returns WDIOF_KEEPALIVEPING, and the GETSTATUS call
+ returns if the device is open or not. [FIXME -- silliness
+ again?]
+
+mixcomwd.c -- MixCom Watchdog
+
+ [FIXME -- I'm unable to tell what the timeout is]
+
+ Supports CONFIG_WATCHDOG_NOWAYOUT
+
+ GETSUPPORT returns WDIOF_KEEPALIVEPING, GETSTATUS returns if
+ the device is opened or not [FIXME -- I'm not really sure how
+ this works, there seems to be some magic connected to
+ CONFIG_WATCHDOG_NOWAYOUT]
+
+pcwd.c -- Berkshire PC Watchdog
+
+ Hardcoded timeout of 1.5 seconds
+
+ Supports CONFIG_WATCHDOG_NOWAYOUT
+
+ GETSUPPORT returns WDIOF_OVERHEAT|WDIOF_CARDRESET and both
+ GETSTATUS and GETBOOTSTATUS return something useful.
+
+ The SETOPTIONS call can be used to enable and disable the card
+ and to ask the driver to call panic if the system overheats.
+
+sbc60xxwdt.c -- 60xx Single Board Computer
+
+ Hardcoded timeout of 10 seconds
+
+ Does not support CONFIG_WATCHDOG_NOWAYOUT, but has the magic
+ character 'V' close handling.
+
+ No bits set in GETSUPPORT
+
+scx200.c -- National SCx200 CPUs
+
+ Not in the kernel yet.
+
+ The timeout is set using a module parameter "margin" which
+ defaults to 60 seconds. The timeout can also be set using
+ SETTIMEOUT and read using GETTIMEOUT.
+
+ Supports a module parameter "nowayout" that is initialized
+ with the value of CONFIG_WATCHDOG_NOWAYOUT. Also supports the
+ magic character 'V' handling.
+
+shwdt.c -- SuperH 3/4 processors
+
+ [FIXME -- I'm unable to tell what the timeout is]
+
+ Supports CONFIG_WATCHDOG_NOWAYOUT
+
+ GETSUPPORT returns WDIOF_KEEPALIVEPING, and the GETSTATUS call
+ returns if the device is open or not. [FIXME -- silliness
+ again?]
+
+softdog.c -- Software watchdog
+
+ The timeout is set with the module parameter "soft_margin"
+ which defaults to 60 seconds, the timeout is also settable
+ using the SETTIMEOUT ioctl.
+
+ Supports CONFIG_WATCHDOG_NOWAYOUT
+
+ WDIOF_SETTIMEOUT bit set in GETSUPPORT
+
+w83877f_wdt.c -- W83877F Computer
+
+ Hardcoded timeout of 30 seconds
+
+ Does not support CONFIG_WATCHDOG_NOWAYOUT, but has the magic
+ character 'V' close handling.
+
+ No bits set in GETSUPPORT
+
+wdt.c -- ICS WDT500/501 ISA and
+wdt_pci.c -- ICS WDT500/501 PCI
+
+ Default timeout of 60 seconds. The timeout is also settable
+ using the SETTIMEOUT ioctl.
+
+ Supports CONFIG_WATCHDOG_NOWAYOUT
+
+ GETSUPPORT returns with bits set depending on the actual
+ card. The WDT501 supports a lot of external monitoring, the
+ WDT500 much less.
+
+wdt285.c -- Footbridge watchdog
+
+ The timeout is set with the module parameter "soft_margin"
+ which defaults to 60 seconds. The timeout is also settable
+ using the SETTIMEOUT ioctl.
+
+ Does not support CONFIG_WATCHDOG_NOWAYOUT
+
+ WDIOF_SETTIMEOUT bit set in GETSUPPORT
+
+wdt977.c -- Netwinder W83977AF chip
+
+ Hardcoded timeout of 3 minutes
+
+ Supports CONFIG_WATCHDOG_NOWAYOUT
+
+ Does not support any ioctls at all.
+
diff --git a/MAINTAINERS b/MAINTAINERS
index 5f37f6e92bb9b..5388402bb014f 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1437,8 +1437,6 @@ P: Anton Blanchard
M: anton@samba.org
L: sparclinux@vger.kernel.org
L: ultralinux@vger.kernel.org
-W: http://ultra.linux.cz
-W: http://www.geog.ubc.ca/s_linux.html
S: Maintained
SPECIALIX IO8+ MULTIPORT SERIAL CARD DRIVER
diff --git a/Makefile b/Makefile
index b3aef7bd7c3a8..cc61c4089d33b 100644
--- a/Makefile
+++ b/Makefile
@@ -1,12 +1,12 @@
VERSION = 2
PATCHLEVEL = 5
-SUBLEVEL = 7
-EXTRAVERSION =
+SUBLEVEL = 8
+EXTRAVERSION =-pre1
KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
-KERNELPATH=kernel-$(shell echo $(KERNELRELEASE) | sed -e "s/-//")
+KERNELPATH=kernel-$(shell echo $(KERNELRELEASE) | sed -e "s/-//g")
CONFIG_SHELL := $(shell if [ -x "$$BASH" ]; then echo $$BASH; \
else if [ -x /bin/bash ]; then echo /bin/bash; \
@@ -341,7 +341,7 @@ init/main.o: init/main.c include/config/MARKER
$(CC) $(CFLAGS) $(CFLAGS_KERNEL) $(PROFILING) -DKBUILD_BASENAME=$(subst $(comma),_,$(subst -,_,$(*F))) -c -o $*.o $<
init/do_mounts.o: init/do_mounts.c include/config/MARKER
- $(CC) $(CFLAGS) $(CFLAGS_KERNEL) $(PROFILING) -c -o $*.o $<
+ $(CC) $(CFLAGS) $(CFLAGS_KERNEL) $(PROFILING) -DKBUILD_BASENAME=$(subst $(comma),_,$(subst -,_,$(*F))) -c -o $*.o $<
fs lib mm ipc kernel drivers net sound: dummy
$(MAKE) CFLAGS="$(CFLAGS) $(CFLAGS_KERNEL)" $(subst $@, _dir_$@, $@)
diff --git a/Rules.make b/Rules.make
index 2d3c5faf21a7b..83f31b8b78423 100644
--- a/Rules.make
+++ b/Rules.make
@@ -50,10 +50,10 @@ ALL_SUB_DIRS := $(sort $(subdir-y) $(subdir-m) $(subdir-n) $(subdir-))
#
%.s: %.c
- $(CC) $(CFLAGS) $(EXTRA_CFLAGS) $(CFLAGS_$@) -S $< -o $@
+ $(CC) $(CFLAGS) $(EXTRA_CFLAGS) -DKBUILD_BASENAME=$(subst $(comma),_,$(subst -,_,$(*F))) $(CFLAGS_$@) -S $< -o $@
%.i: %.c
- $(CPP) $(CFLAGS) $(EXTRA_CFLAGS) $(CFLAGS_$@) $< > $@
+ $(CPP) $(CFLAGS) $(EXTRA_CFLAGS) -DKBUILD_BASENAME=$(subst $(comma),_,$(subst -,_,$(*F))) $(CFLAGS_$@) $< > $@
%.o: %.c
$(CC) $(CFLAGS) $(EXTRA_CFLAGS) -DKBUILD_BASENAME=$(subst $(comma),_,$(subst -,_,$(*F))) $(CFLAGS_$@) -c -o $@ $<
diff --git a/arch/alpha/kernel/alpha_ksyms.c b/arch/alpha/kernel/alpha_ksyms.c
index 4cfcab8818cc2..c3e028e648acd 100644
--- a/arch/alpha/kernel/alpha_ksyms.c
+++ b/arch/alpha/kernel/alpha_ksyms.c
@@ -103,7 +103,6 @@ EXPORT_SYMBOL(strncpy);
EXPORT_SYMBOL(strnlen);
EXPORT_SYMBOL(strncat);
EXPORT_SYMBOL(strstr);
-EXPORT_SYMBOL(strtok);
EXPORT_SYMBOL(strpbrk);
EXPORT_SYMBOL(strchr);
EXPORT_SYMBOL(strrchr);
diff --git a/arch/alpha/kernel/setup.c b/arch/alpha/kernel/setup.c
index 58c0ee067475e..42c3bf32e584b 100644
--- a/arch/alpha/kernel/setup.c
+++ b/arch/alpha/kernel/setup.c
@@ -472,6 +472,7 @@ setup_arch(char **cmdline_p)
struct percpu_struct *cpu;
char *type_name, *var_name, *p;
void *kernel_end = _end; /* end of kernel */
+ char *args = command_line;
hwrpb = (struct hwrpb_struct*) __va(INIT_HWRPB->phys_addr);
boot_cpuid = hard_smp_processor_id();
@@ -509,7 +510,8 @@ setup_arch(char **cmdline_p)
/*
* Process command-line arguments.
*/
- for (p = strtok(command_line, " \t"); p ; p = strtok(NULL, " \t")) {
+ while ((p = strsep(&args, " \t")) != NULL) {
+ if (!*p) continue;
if (strncmp(p, "alpha_mv=", 9) == 0) {
vec = get_sysvec_byname(p+9);
continue;
@@ -528,7 +530,7 @@ setup_arch(char **cmdline_p)
}
}
- /* Replace the command line, now that we've killed it with strtok. */
+ /* Replace the command line, now that we've killed it with strsep. */
strcpy(command_line, saved_command_line);
/* If we want SRM console printk echoing early, do it now. */
diff --git a/arch/arm/kernel/armksyms.c b/arch/arm/kernel/armksyms.c
index a84ba04ad73e7..5724dbd48ec56 100644
--- a/arch/arm/kernel/armksyms.c
+++ b/arch/arm/kernel/armksyms.c
@@ -180,7 +180,7 @@ EXPORT_SYMBOL_NOVERS(strchr);
EXPORT_SYMBOL_NOVERS(strlen);
EXPORT_SYMBOL_NOVERS(strnlen);
EXPORT_SYMBOL_NOVERS(strpbrk);
-EXPORT_SYMBOL_NOVERS(strtok);
+EXPORT_SYMBOL_NOVERS(strsep);
EXPORT_SYMBOL_NOVERS(strrchr);
EXPORT_SYMBOL_NOVERS(strstr);
EXPORT_SYMBOL_NOVERS(memset);
diff --git a/arch/arm/mach-arc/dma.c b/arch/arm/mach-arc/dma.c
index 26a4e2447a605..9012117e07a5c 100644
--- a/arch/arm/mach-arc/dma.c
+++ b/arch/arm/mach-arc/dma.c
@@ -100,7 +100,7 @@ static int arc_floppy_cmdend_get_dma_residue(dmach_t channel, dma_t *dma)
/* 10/1/1999 DAG - Presume whether there is an outstanding command? */
extern unsigned int fdc1772_fdc_int_done;
- * Explicit! If the int done is 0 then 1 int to go */
+ /* Explicit! If the int done is 0 then 1 int to go */
return (fdc1772_fdc_int_done==0)?1:0;
}
diff --git a/arch/cris/drivers/ethernet.c b/arch/cris/drivers/ethernet.c
index 47fe0a6e78ffc..a01c0ec04e833 100644
--- a/arch/cris/drivers/ethernet.c
+++ b/arch/cris/drivers/ethernet.c
@@ -996,7 +996,7 @@ e100_rx(struct net_device *dev)
int i;
#endif
- if (!led_active && jiffies > led_next_time) {
+ if (!led_active && time_after(jiffies, led_next_time)) {
/* light the network leds depending on the current speed. */
e100_set_network_leds(NETWORK_ACTIVITY);
@@ -1288,7 +1288,7 @@ e100_hardware_send_packet(char *buf, int length)
{
D(printk("e100 send pack, buf 0x%x len %d\n", buf, length));
- if (!led_active && jiffies > led_next_time) {
+ if (!led_active && time_after(jiffies, led_next_time)) {
/* light the network leds depending on the current speed. */
e100_set_network_leds(NETWORK_ACTIVITY);
@@ -1313,7 +1313,7 @@ e100_hardware_send_packet(char *buf, int length)
static void
e100_clear_network_leds(unsigned long dummy)
{
- if (led_active && jiffies > led_next_time) {
+ if (led_active && jiffies > time_after(jiffies, led_next_time)) {
e100_set_network_leds(NO_NETWORK_ACTIVITY);
/* Set the earliest time we may set the LED */
diff --git a/arch/cris/drivers/gpio.c b/arch/cris/drivers/gpio.c
index c454e5de50465..445dfaa8421ff 100644
--- a/arch/cris/drivers/gpio.c
+++ b/arch/cris/drivers/gpio.c
@@ -217,7 +217,7 @@ static int
gpio_open(struct inode *inode, struct file *filp)
{
struct gpio_private *priv;
- int p = MINOR(inode->i_rdev);
+ int p = minor(inode->i_rdev);
if (p >= NUM_PORTS && p != LEDS)
return -EINVAL;
diff --git a/arch/cris/drivers/ide.c b/arch/cris/drivers/ide.c
index 95fe8ed25c9d5..79a617d3890b4 100644
--- a/arch/cris/drivers/ide.c
+++ b/arch/cris/drivers/ide.c
@@ -271,10 +271,10 @@ init_e100_ide (void)
printk("ide: ETRAX 100LX built-in ATA DMA controller\n");
- /* first fill in some stuff in the ide_hwifs fields */
+ /* first initialize the channel interface data */
for(h = 0; h < MAX_HWIFS; h++) {
- ide_hwif_t *hwif = &ide_hwifs[h];
+ struct ata_channel *hwif = &ide_hwifs[h];
hwif->chipset = ide_etrax100;
hwif->tuneproc = &tune_e100_ide;
hwif->dmaproc = &e100_dmaproc;
@@ -355,7 +355,7 @@ init_e100_ide (void)
printk("ide: waiting %d seconds for drives to regain consciousness\n", CONFIG_ETRAX_IDE_DELAY);
h = jiffies + (CONFIG_ETRAX_IDE_DELAY * HZ);
- while(jiffies < h) ;
+ while(time_before(jiffies, h)) ;
/* reset the dma channels we will use */
@@ -717,7 +717,7 @@ static ide_startstop_t etrax_dma_intr (ide_drive_t *drive)
LED_DISK_READ(0);
LED_DISK_WRITE(0);
- dma_stat = HWIF(drive)->dmaproc(ide_dma_end, drive);
+ dma_stat = drive->channel->dmaproc(ide_dma_end, drive);
stat = GET_STAT(); /* get drive status */
if (OK_STAT(stat,DRIVE_READY,drive->bad_wstat|DRQ_STAT)) {
if (!dma_stat) {
@@ -798,7 +798,7 @@ static int e100_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
* not a diskdrive.
*/
- if (drive->media != ide_disk)
+ if (drive->type != ATA_DISK)
return 0;
dma_begin:
@@ -809,7 +809,7 @@ static int e100_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
WAIT_DMA(ATA_RX_DMA_NBR);
/* set up the Etrax DMA descriptors */
-
+
if(e100_ide_build_dmatable (drive))
return 1;
@@ -902,7 +902,7 @@ static int e100_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
* --- Marcin Dalecki
*/
-void ide_release_dma (ide_hwif_t *hwif)
+void ide_release_dma(struct ata_channel *hwif)
{
/* empty */
}
diff --git a/arch/cris/kernel/ksyms.c b/arch/cris/kernel/ksyms.c
index ef798138fcc38..4d2cbc18c6a83 100644
--- a/arch/cris/kernel/ksyms.c
+++ b/arch/cris/kernel/ksyms.c
@@ -38,9 +38,7 @@ EXPORT_SYMBOL(loops_per_usec);
/* String functions */
EXPORT_SYMBOL(memcmp);
EXPORT_SYMBOL(memmove);
-EXPORT_SYMBOL(strtok);
EXPORT_SYMBOL(strpbrk);
-EXPORT_SYMBOL(simple_strtol);
EXPORT_SYMBOL(strstr);
EXPORT_SYMBOL(strcpy);
EXPORT_SYMBOL(strchr);
diff --git a/arch/i386/Config.help b/arch/i386/Config.help
index dbcd190af96e6..d4f8b78e91abc 100644
--- a/arch/i386/Config.help
+++ b/arch/i386/Config.help
@@ -128,6 +128,12 @@ CONFIG_NOHIGHMEM
If unsure, say "off".
+CONFIG_HIGHPTE
+ The VM uses one page table entry for each page of physical memory.
+ For systems with a lot of RAM, this can be wasteful of precious
+ low memory. Setting this option will put user-space page table
+ entries in high memory.
+
CONFIG_HIGHMEM4G
Select this if you have a 32-bit processor and between 1 and 4
gigabytes of physical RAM.
@@ -797,6 +803,30 @@ CONFIG_APM_REAL_MODE_POWER_OFF
a work-around for a number of buggy BIOSes. Switch this option on if
your computer crashes instead of powering off properly.
+CONFIG_X86_MCE
+ Machine Check Exception support allows the processor to notify the
+ kernel if it detects a problem (e.g. overheating, component failure).
+ The action the kernel takes depends on the severity of the problem,
+ ranging from a warning message on the console, to halting the machine.
+ Your processor must be a Pentium or newer to support this - check the
+ flags in /proc/cpuinfo for mce. Note that some older Pentium systems
+ have a design flaw which leads to false MCE events - hence MCE is
+ disabled on all P5 processors, unless explicitly enabled with "mce"
+ as a boot argument. Similarly, if MCE is built in and creates a
+ problem on some new non-standard machine, you can boot with "nomce"
+ to disable it. MCE support simply ignores non-MCE processors like
+ the 386 and 486, so nearly everyone can say Y here.
+
+CONFIG_X86_MCE_NONFATAL
+ Enabling this feature starts a timer that triggers every 5 seconds which
+ will look at the machine check registers to see if anything happened.
+ Non-fatal problems automatically get corrected (but still logged).
+ Disable this if you don't want to see these messages.
+ Seeing the messages this option prints out may be indicative of dying hardware,
+ or out-of-spec (ie, overclocked) hardware.
+ This option only does something on hardware with Intel P6 style MCE.
+ (Pentium Pro and above, AMD Athlon/Duron)
+
CONFIG_TOSHIBA
This adds a driver to safely access the System Management Mode of
the CPU on Toshiba portables with a genuine Toshiba BIOS. It does
@@ -903,3 +933,6 @@ CONFIG_DEBUG_BUGVERBOSE
of the BUG call as well as the EIP and oops trace. This aids
debugging but costs about 70-100K of memory.
+CONFIG_DEBUG_OBSOLETE
+ Say Y here if you want to reduce the chances of the tree compiling,
+ and are prepared to dig into driver internals to fix compile errors.
diff --git a/arch/i386/boot/setup.S b/arch/i386/boot/setup.S
index 100c19b5a2604..d738905d02920 100644
--- a/arch/i386/boot/setup.S
+++ b/arch/i386/boot/setup.S
@@ -544,7 +544,7 @@ done_apm_bios:
cmpw $0, %cs:realmode_swtch
jz rmodeswtch_normal
- lcall *%cs:realmode_swtch
+ lcall %cs:realmode_swtch
jmp rmodeswtch_end
diff --git a/arch/i386/config.in b/arch/i386/config.in
index b3109591a1d9d..771fa43e2830c 100644
--- a/arch/i386/config.in
+++ b/arch/i386/config.in
@@ -25,6 +25,7 @@ choice 'Processor family' \
Pentium-4 CONFIG_MPENTIUM4 \
K6/K6-II/K6-III CONFIG_MK6 \
Athlon/Duron/K7 CONFIG_MK7 \
+ Elan CONFIG_MELAN \
Crusoe CONFIG_MCRUSOE \
Winchip-C6 CONFIG_MWINCHIPC6 \
Winchip-2 CONFIG_MWINCHIP2 \
@@ -119,6 +120,11 @@ if [ "$CONFIG_MK7" = "y" ]; then
define_bool CONFIG_X86_PGE y
define_bool CONFIG_X86_USE_PPRO_CHECKSUM y
fi
+if [ "$CONFIG_MELAN" = "y" ]; then
+ define_int CONFIG_X86_L1_CACHE_SHIFT 4
+ define_bool CONFIG_X86_USE_STRING_486 y
+ define_bool CONFIG_X86_ALIGNMENT_16 y
+fi
if [ "$CONFIG_MCYRIXIII" = "y" ]; then
define_int CONFIG_X86_L1_CACHE_SHIFT 5
define_bool CONFIG_X86_TSC y
@@ -150,6 +156,10 @@ if [ "$CONFIG_MWINCHIP3D" = "y" ]; then
define_bool CONFIG_X86_USE_PPRO_CHECKSUM y
define_bool CONFIG_X86_OOSTORE y
fi
+
+bool 'Machine Check Exception' CONFIG_X86_MCE
+dep_bool 'Check for non-fatal errors' CONFIG_X86_MCE_NONFATAL $CONFIG_X86_MCE
+
tristate 'Toshiba Laptop support' CONFIG_TOSHIBA
tristate 'Dell laptop support' CONFIG_I8K
@@ -160,25 +170,20 @@ tristate '/dev/cpu/*/cpuid - CPU information support' CONFIG_X86_CPUID
choice 'High Memory Support' \
"off CONFIG_NOHIGHMEM \
4GB CONFIG_HIGHMEM4G \
- 4GB-highpte CONFIG_HIGHMEM4G_HIGHPTE \
- 64GB CONFIG_HIGHMEM64G \
- 64GB-highpte CONFIG_HIGHMEM64G_HIGHPTE" off
-if [ "$CONFIG_HIGHMEM4G" = "y" ]; then
- define_bool CONFIG_HIGHMEM y
+ 64GB CONFIG_HIGHMEM64G" off
+
+if [ "$CONFIG_HIGHMEM4G" = "y" -o "$CONFIG_HIGHMEM64G" = "y" ]; then
+ bool 'Use high memory pte support' CONFIG_HIGHPTE
fi
-if [ "$CONFIG_HIGHMEM4G_HIGHPTE" = "y" ]; then
+
+if [ "$CONFIG_HIGHMEM4G" = "y" ]; then
define_bool CONFIG_HIGHMEM y
- define_bool CONFIG_HIGHPTE y
fi
+
if [ "$CONFIG_HIGHMEM64G" = "y" ]; then
define_bool CONFIG_HIGHMEM y
define_bool CONFIG_X86_PAE y
fi
-if [ "$CONFIG_HIGHMEM64G_HIGHPTE" = "y" ]; then
- define_bool CONFIG_HIGHMEM y
- define_bool CONFIG_HIGHPTE y
- define_bool CONFIG_X86_PAE y
-fi
bool 'Math emulation' CONFIG_MATH_EMULATION
bool 'MTRR (Memory Type Range Register) support' CONFIG_MTRR
diff --git a/arch/i386/defconfig b/arch/i386/defconfig
index 2c7f6ed01ddb5..ce94a6f0b81ae 100644
--- a/arch/i386/defconfig
+++ b/arch/i386/defconfig
@@ -39,6 +39,7 @@ CONFIG_MPENTIUMIII=y
# CONFIG_MPENTIUM4 is not set
# CONFIG_MK6 is not set
# CONFIG_MK7 is not set
+# CONFIG_MELAN is not set
# CONFIG_MCRUSOE is not set
# CONFIG_MWINCHIPC6 is not set
# CONFIG_MWINCHIP2 is not set
@@ -57,6 +58,8 @@ CONFIG_X86_TSC=y
CONFIG_X86_GOOD_APIC=y
CONFIG_X86_PGE=y
CONFIG_X86_USE_PPRO_CHECKSUM=y
+CONFIG_X86_MCE=y
+# CONFIG_X86_MCE_NONFATAL is not set
# CONFIG_TOSHIBA is not set
# CONFIG_I8K is not set
# CONFIG_MICROCODE is not set
@@ -64,9 +67,7 @@ CONFIG_X86_USE_PPRO_CHECKSUM=y
# CONFIG_X86_CPUID is not set
CONFIG_NOHIGHMEM=y
# CONFIG_HIGHMEM4G is not set
-# CONFIG_HIGHMEM4G_HIGHPTE is not set
# CONFIG_HIGHMEM64G is not set
-# CONFIG_HIGHMEM64G_HIGHPTE is not set
# CONFIG_MATH_EMULATION is not set
# CONFIG_MTRR is not set
CONFIG_SMP=y
@@ -103,7 +104,6 @@ CONFIG_CARDBUS=y
# CONFIG_I82092 is not set
# CONFIG_I82365 is not set
# CONFIG_TCIC is not set
-# CONFIG_PCMCIA_SA1100 is not set
#
# PCI Hotplug Support
@@ -268,7 +268,6 @@ CONFIG_BLK_DEV_IDEDMA=y
# CONFIG_BLK_DEV_ALI15X3 is not set
# CONFIG_WDC_ALI15X3 is not set
# CONFIG_BLK_DEV_AMD74XX is not set
-# CONFIG_AMD74XX_OVERRIDE is not set
# CONFIG_BLK_DEV_CMD64X is not set
# CONFIG_BLK_DEV_CY82C693 is not set
# CONFIG_BLK_DEV_CS5530 is not set
@@ -276,7 +275,6 @@ CONFIG_BLK_DEV_IDEDMA=y
# CONFIG_HPT34X_AUTODMA is not set
# CONFIG_BLK_DEV_HPT366 is not set
CONFIG_BLK_DEV_PIIX=y
-CONFIG_PIIX_TUNING=y
# CONFIG_BLK_DEV_NS87415 is not set
# CONFIG_BLK_DEV_OPTI621 is not set
# CONFIG_BLK_DEV_PDC_ADMA is not set
@@ -291,7 +289,6 @@ CONFIG_PIIX_TUNING=y
# CONFIG_IDEDMA_IVB is not set
CONFIG_IDEDMA_AUTO=y
# CONFIG_DMA_NONPCI is not set
-CONFIG_BLK_DEV_IDE_MODES=y
# CONFIG_BLK_DEV_ATARAID is not set
# CONFIG_BLK_DEV_ATARAID_PDC is not set
# CONFIG_BLK_DEV_ATARAID_HPT is not set
diff --git a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile
index 47fda4a75ed18..f23c37411e7c5 100644
--- a/arch/i386/kernel/Makefile
+++ b/arch/i386/kernel/Makefile
@@ -18,7 +18,8 @@ export-objs := mca.o mtrr.o msr.o cpuid.o microcode.o i386_ksyms.o time.o
obj-y := process.o semaphore.o signal.o entry.o traps.o irq.o vm86.o \
ptrace.o i8259.o ioport.o ldt.o setup.o time.o sys_i386.o \
- pci-dma.o i386_ksyms.o i387.o bluesmoke.o dmi_scan.o
+ pci-dma.o i386_ksyms.o i387.o bluesmoke.o dmi_scan.o \
+ bootflag.o
ifdef CONFIG_PCI
diff --git a/arch/i386/kernel/apic.c b/arch/i386/kernel/apic.c
index 5072e08395f70..cb80ad40d1dbd 100644
--- a/arch/i386/kernel/apic.c
+++ b/arch/i386/kernel/apic.c
@@ -90,7 +90,7 @@ void clear_local_APIC(void)
apic_write_around(APIC_LVTPC, APIC_LVT_MASKED);
v = GET_APIC_VERSION(apic_read(APIC_LVR));
if (APIC_INTEGRATED(v)) { /* !82489DX */
- if (maxlvt > 3)
+ if (maxlvt > 3) /* Due to Pentium errata 3AP and 11AP. */
apic_write(APIC_ESR, 0);
apic_read(APIC_ESR);
}
@@ -449,6 +449,7 @@ static struct {
unsigned int apic_lvterr;
unsigned int apic_tmict;
unsigned int apic_tdcr;
+ unsigned int apic_thmr;
} apic_pm_state;
static void apic_pm_suspend(void *data)
@@ -470,6 +471,7 @@ static void apic_pm_suspend(void *data)
apic_pm_state.apic_lvterr = apic_read(APIC_LVTERR);
apic_pm_state.apic_tmict = apic_read(APIC_TMICT);
apic_pm_state.apic_tdcr = apic_read(APIC_TDCR);
+ apic_pm_state.apic_thmr = apic_read(APIC_LVTTHMR);
__save_flags(flags);
__cli();
disable_local_APIC();
@@ -498,6 +500,7 @@ static void apic_pm_resume(void *data)
apic_write(APIC_SPIV, apic_pm_state.apic_spiv);
apic_write(APIC_LVT0, apic_pm_state.apic_lvt0);
apic_write(APIC_LVT1, apic_pm_state.apic_lvt1);
+ apic_write(APIC_LVTTHMR, apic_pm_state.apic_thmr);
apic_write(APIC_LVTPC, apic_pm_state.apic_lvtpc);
apic_write(APIC_LVTT, apic_pm_state.apic_lvtt);
apic_write(APIC_TDCR, apic_pm_state.apic_tdcr);
diff --git a/arch/i386/kernel/bluesmoke.c b/arch/i386/kernel/bluesmoke.c
index 63db0ab54101d..ac636f46937bc 100644
--- a/arch/i386/kernel/bluesmoke.c
+++ b/arch/i386/kernel/bluesmoke.c
@@ -3,16 +3,128 @@
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/sched.h>
+#include <linux/smp.h>
+#include <linux/config.h>
+#include <linux/irq.h>
#include <asm/processor.h>
+#include <asm/system.h>
#include <asm/msr.h>
+#include <asm/apic.h>
+#include <asm/pgtable.h>
+
+#ifdef CONFIG_X86_MCE
static int mce_disabled __initdata = 0;
+static int banks;
+
/*
- * Machine Check Handler For PII/PIII
+ * If we get an MCE, we don't know what state the caches/TLB's are
+ * going to be in, so we throw them all away.
*/
+static void inline flush_all (void)
+{
+ __asm__ __volatile__ ("invd": : );
+ __flush_tlb();
+}
-static int banks;
+/*
+ * P4/Xeon Thermal transition interrupt handler
+ */
+
+static void intel_thermal_interrupt(struct pt_regs *regs)
+{
+#ifdef CONFIG_X86_LOCAL_APIC
+ u32 l, h;
+ unsigned int cpu = smp_processor_id();
+
+ ack_APIC_irq();
+
+ rdmsr(MSR_IA32_THERM_STATUS, l, h);
+ if (l & 1) {
+ printk(KERN_EMERG "CPU#%d: Temperature above threshold\n", cpu);
+ printk(KERN_EMERG "CPU#%d: Running in modulated clock mode\n", cpu);
+ } else {
+ printk(KERN_INFO "CPU#%d: Temperature/speed normal\n", cpu);
+ }
+#endif
+}
+
+static void unexpected_thermal_interrupt(struct pt_regs *regs)
+{
+ printk(KERN_ERR "CPU#%d: Unexpected LVT TMR interrupt!\n", smp_processor_id());
+}
+
+/*
+ * Thermal interrupt handler for this CPU setup
+ */
+
+static void (*vendor_thermal_interrupt)(struct pt_regs *regs) = unexpected_thermal_interrupt;
+
+asmlinkage void smp_thermal_interrupt(struct pt_regs regs)
+{
+ vendor_thermal_interrupt(&regs);
+}
+
+/* P4/Xeon Thermal regulation detect and init */
+
+static void __init intel_init_thermal(struct cpuinfo_x86 *c)
+{
+#ifdef CONFIG_X86_LOCAL_APIC
+ u32 l, h;
+ unsigned int cpu = smp_processor_id();
+
+ /* Thermal monitoring */
+ if (!test_bit(X86_FEATURE_ACPI, &c->x86_capability))
+ return; /* -ENODEV */
+
+ /* Clock modulation */
+ if (!test_bit(X86_FEATURE_ACC, &c->x86_capability))
+ return; /* -ENODEV */
+
+ rdmsr(MSR_IA32_MISC_ENABLE, l, h);
+ /* first check if its enabled already, in which case there might
+ * be some SMM goo which handles it, so we can't even put a handler
+ * since it might be delivered via SMI already -zwanem.
+ */
+
+ if (l & (1<<3)) {
+ printk(KERN_DEBUG "CPU#%d: Thermal monitoring already enabled\n", cpu);
+ } else {
+ wrmsr(MSR_IA32_MISC_ENABLE, l | (1<<3), h);
+ printk(KERN_INFO "CPU#%d: Thermal monitoring enabled\n", cpu);
+ }
+
+ /* check wether a vector already exists */
+ l = apic_read(APIC_LVTTHMR);
+ if (l & 0xff) {
+ printk(KERN_DEBUG "CPU#%d: Thermal LVT already handled\n", cpu);
+ return; /* -EBUSY */
+ }
+
+ wrmsr(MSR_IA32_MISC_ENABLE, l | (1<<3), h);
+ printk(KERN_INFO "CPU#%d: Thermal monitoring enabled\n", cpu);
+
+ /* The temperature transition interrupt handler setup */
+ l = THERMAL_APIC_VECTOR; /* our delivery vector */
+ l |= (APIC_DM_FIXED | APIC_LVT_MASKED); /* we'll mask till we're ready */
+ apic_write_around(APIC_LVTTHMR, l);
+
+ rdmsr(MSR_IA32_THERM_INTERRUPT, l, h);
+ wrmsr(MSR_IA32_THERM_INTERRUPT, l | 0x3 , h);
+
+ /* ok we're good to go... */
+ vendor_thermal_interrupt = intel_thermal_interrupt;
+ l = apic_read(APIC_LVTTHMR);
+ apic_write_around(APIC_LVTTHMR, l & ~APIC_LVT_MASKED);
+
+ return;
+#endif
+}
+
+/*
+ * Machine Check Handler For PII/PIII
+ */
static void intel_machine_check(struct pt_regs * regs, long error_code)
{
@@ -20,7 +132,9 @@ static void intel_machine_check(struct pt_regs * regs, long error_code)
u32 alow, ahigh, high, low;
u32 mcgstl, mcgsth;
int i;
-
+
+ flush_all();
+
rdmsr(MSR_IA32_MCG_STATUS, mcgstl, mcgsth);
if(mcgstl&(1<<0)) /* Recoverable ? */
recover=0;
@@ -41,13 +155,12 @@ static void intel_machine_check(struct pt_regs * regs, long error_code)
if(high&(1<<27))
{
rdmsr(MSR_IA32_MC0_MISC+i*4, alow, ahigh);
- printk("[%08x%08x]", alow, ahigh);
+ printk("[%08x%08x]", ahigh, alow);
}
if(high&(1<<26))
{
rdmsr(MSR_IA32_MC0_ADDR+i*4, alow, ahigh);
- printk(" at %08x%08x",
- ahigh, alow);
+ printk(" at %08x%08x", ahigh, alow);
}
printk("\n");
/* Clear it */
@@ -109,8 +222,55 @@ asmlinkage void do_machine_check(struct pt_regs * regs, long error_code)
machine_check_vector(regs, error_code);
}
+
+#ifdef CONFIG_X86_MCE_NONFATAL
+struct timer_list mce_timer;
+
+static void mce_checkregs (unsigned int cpu)
+{
+ u32 low, high;
+ int i;
+
+ if (cpu!=smp_processor_id())
+ BUG();
+
+ for (i=0; i<banks; i++) {
+ rdmsr(MSR_IA32_MC0_STATUS+i*4, low, high);
+
+ if ((low | high) != 0) {
+ flush_all();
+ printk (KERN_EMERG "MCE: The hardware reports a non fatal, correctable incident occured on CPU %d.\n", smp_processor_id());
+ printk (KERN_EMERG "Bank %d: %08x%08x\n", i, high, low);
+
+ /* Scrub the error so we don't pick it up in 5 seconds time. */
+ wrmsr(MSR_IA32_MC0_STATUS+i*4, 0UL, 0UL);
+
+ /* Serialize */
+ wmb();
+ }
+ }
+
+ /* Refresh the timer. */
+ mce_timer.expires = jiffies + 5 * HZ;
+ add_timer (&mce_timer);
+}
+
+static void mce_timerfunc (unsigned long data)
+{
+ int i;
+
+ for (i=0; i<smp_num_cpus; i++) {
+ if (i == smp_processor_id())
+ mce_checkregs(i);
+ else
+ smp_call_function (mce_checkregs, i, 1, 1);
+ }
+}
+#endif
+
+
/*
- * Set up machine check reporting for Intel processors
+ * Set up machine check reporting for processors with Intel style MCE
*/
static void __init intel_mcheck_init(struct cpuinfo_x86 *c)
@@ -164,19 +324,27 @@ static void __init intel_mcheck_init(struct cpuinfo_x86 *c)
if(done==0)
printk(KERN_INFO "Intel machine check architecture supported.\n");
rdmsr(MSR_IA32_MCG_CAP, l, h);
- if(l&(1<<8))
+ if(l&(1<<8)) /* Control register present ? */
wrmsr(MSR_IA32_MCG_CTL, 0xffffffff, 0xffffffff);
banks = l&0xff;
- for(i=1;i<banks;i++)
- {
- wrmsr(MSR_IA32_MC0_CTL+4*i, 0xffffffff, 0xffffffff);
+
+ /* Don't enable bank 0 on intel P6 cores, it goes bang quickly. */
+ if (c->x86_vendor == X86_VENDOR_INTEL && c->x86 == 6) {
+ for(i=1; i<banks; i++)
+ wrmsr(MSR_IA32_MC0_CTL+4*i, 0xffffffff, 0xffffffff);
+ } else {
+ for(i=0; i<banks; i++)
+ wrmsr(MSR_IA32_MC0_CTL+4*i, 0xffffffff, 0xffffffff);
}
- for(i=0;i<banks;i++)
- {
+
+ for(i=0; i<banks; i++)
wrmsr(MSR_IA32_MC0_STATUS+4*i, 0x0, 0x0);
- }
+
set_in_cr4(X86_CR4_MCE);
printk(KERN_INFO "Intel machine check reporting enabled on CPU#%d.\n", smp_processor_id());
+
+ intel_init_thermal(c);
+
done=1;
}
@@ -206,28 +374,36 @@ static void __init winchip_mcheck_init(struct cpuinfo_x86 *c)
* This has to be run for each processor
*/
-
-
void __init mcheck_init(struct cpuinfo_x86 *c)
{
if(mce_disabled==1)
return;
-
+
switch(c->x86_vendor)
{
case X86_VENDOR_AMD:
- /*
- * AMD K7 machine check is Intel like
- */
- if(c->x86 == 6)
+ /* AMD K7 machine check is Intel like */
+ if(c->x86 == 6) {
intel_mcheck_init(c);
+#ifdef CONFIG_X86_MCE_NONFATAL
+ /* Set the timer to check for non-fatal errors every 5 seconds */
+ init_timer (&mce_timer);
+ mce_timer.expires = jiffies + 5 * HZ;
+ mce_timer.data = 0;
+ mce_timer.function = &mce_timerfunc;
+ add_timer (&mce_timer);
+#endif
+ }
break;
+
case X86_VENDOR_INTEL:
intel_mcheck_init(c);
break;
+
case X86_VENDOR_CENTAUR:
winchip_mcheck_init(c);
break;
+
default:
break;
}
@@ -247,3 +423,9 @@ static int __init mcheck_enable(char *str)
__setup("nomce", mcheck_disable);
__setup("mce", mcheck_enable);
+
+#else
+asmlinkage void do_machine_check(struct pt_regs * regs, long error_code) {}
+asmlinkage void smp_thermal_interrupt(struct pt_regs regs) {}
+void __init mcheck_init(struct cpuinfo_x86 *c) {}
+#endif
diff --git a/arch/i386/kernel/bootflag.c b/arch/i386/kernel/bootflag.c
new file mode 100644
index 0000000000000..ed98c85718a60
--- /dev/null
+++ b/arch/i386/kernel/bootflag.c
@@ -0,0 +1,253 @@
+/*
+ * Implement 'Simple Boot Flag Specification 1.0'
+ *
+ */
+
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <asm/io.h>
+
+#include <linux/mc146818rtc.h>
+
+
+#define SBF_RESERVED (0x78)
+#define SBF_PNPOS (1<<0)
+#define SBF_BOOTING (1<<1)
+#define SBF_DIAG (1<<2)
+#define SBF_PARITY (1<<7)
+
+
+struct sbf_boot
+{
+ u8 sbf_signature[4];
+ u32 sbf_len;
+ u8 sbf_revision __attribute((packed));
+ u8 sbf_csum __attribute((packed));
+ u8 sbf_oemid[6] __attribute((packed));
+ u8 sbf_oemtable[8] __attribute((packed));
+ u8 sbf_revdata[4] __attribute((packed));
+ u8 sbf_creator[4] __attribute((packed));
+ u8 sbf_crearev[4] __attribute((packed));
+ u8 sbf_cmos __attribute((packed));
+ u8 sbf_spare[3] __attribute((packed));
+};
+
+
+static int sbf_port __initdata = -1;
+
+static int __init sbf_struct_valid(unsigned long tptr)
+{
+ u8 *ap;
+ u8 v;
+ unsigned int i;
+ struct sbf_boot sb;
+
+ memcpy_fromio(&sb, tptr, sizeof(sb));
+
+ if(sb.sbf_len != 40 && sb.sbf_len != 39)
+ // 39 on IBM ThinkPad A21m, BIOS version 1.02b (KXET24WW; 2000-12-19).
+ return 0;
+
+ ap = (u8 *)&sb;
+ v= 0;
+
+ for(i=0;i<sb.sbf_len;i++)
+ v+=*ap++;
+
+ if(v)
+ return 0;
+
+ if(memcmp(sb.sbf_signature, "BOOT", 4))
+ return 0;
+
+ if (sb.sbf_len == 39)
+ printk (KERN_WARNING "SBF: ACPI BOOT descriptor is wrong length (%d)\n",
+ sb.sbf_len);
+
+ sbf_port = sb.sbf_cmos; /* Save CMOS port */
+ return 1;
+}
+
+static int __init parity(u8 v)
+{
+ int x = 0;
+ int i;
+
+ for(i=0;i<8;i++)
+ {
+ x^=(v&1);
+ v>>=1;
+ }
+ return x;
+}
+
+static void __init sbf_write(u8 v)
+{
+ unsigned long flags;
+ if(sbf_port != -1)
+ {
+ v &= ~SBF_PARITY;
+ if(!parity(v))
+ v|=SBF_PARITY;
+
+ printk(KERN_INFO "SBF: Setting boot flags 0x%x\n",v);
+
+ spin_lock_irqsave(&rtc_lock, flags);
+ CMOS_WRITE(v, sbf_port);
+ spin_unlock_irqrestore(&rtc_lock, flags);
+ }
+}
+
+static u8 __init sbf_read(void)
+{
+ u8 v;
+ unsigned long flags;
+ if(sbf_port == -1)
+ return 0;
+ spin_lock_irqsave(&rtc_lock, flags);
+ v = CMOS_READ(sbf_port);
+ spin_unlock_irqrestore(&rtc_lock, flags);
+ return v;
+}
+
+static int __init sbf_value_valid(u8 v)
+{
+ if(v&SBF_RESERVED) /* Reserved bits */
+ return 0;
+ if(!parity(v))
+ return 0;
+ return 1;
+}
+
+
+static void __init sbf_bootup(void)
+{
+ u8 v;
+ if(sbf_port == -1)
+ return;
+ v = sbf_read();
+ if(!sbf_value_valid(v))
+ printk(KERN_WARNING "SBF: Simple boot flag value 0x%x read from CMOS RAM was invalid\n",v);
+ v &= ~SBF_RESERVED;
+ v &= ~SBF_BOOTING;
+ v &= ~SBF_DIAG;
+#if defined(CONFIG_ISAPNP)
+ v |= SBF_PNPOS;
+#endif
+ sbf_write(v);
+}
+
+static int __init sbf_init(void)
+{
+ unsigned int i;
+ void *rsdt;
+ u32 rsdtlen = 0;
+ u32 rsdtbase = 0;
+ u8 sum = 0;
+ int n;
+
+ u8 *p;
+
+ for(i=0xE0000; i <= 0xFFFE0; i+=16)
+ {
+ p = phys_to_virt(i);
+
+ if(memcmp(p, "RSD PTR ", 8))
+ continue;
+
+ sum = 0;
+ for(n=0; n<20; n++)
+ sum+=p[n];
+
+ if(sum != 0)
+ continue;
+
+ /* So it says RSD PTR and it checksums... */
+
+ /*
+ * Process the RDSP pointer
+ */
+
+ rsdtbase = *(u32 *)(p+16);
+
+ /*
+ * RSDT length is ACPI 2 only, for ACPI 1 we must map
+ * and remap.
+ */
+
+ if(p[15]>1)
+ rsdtlen = *(u32 *)(p+20);
+ else
+ rsdtlen = 36;
+
+ if(rsdtlen < 36 || rsdtlen > 1024)
+ continue;
+ break;
+ }
+ if(i>0xFFFE0)
+ return 0;
+
+
+ rsdt = ioremap(rsdtbase, rsdtlen);
+ if(rsdt == 0)
+ return 0;
+
+ i = readl(rsdt + 4);
+
+ /*
+ * Remap if needed
+ */
+
+ if(i > rsdtlen)
+ {
+ rsdtlen = i;
+ iounmap(rsdt);
+ rsdt = ioremap(rsdtbase, rsdtlen);
+ if(rsdt == 0)
+ return 0;
+ }
+
+ for(n = 0; n < i; n++)
+ sum += readb(rsdt + n);
+
+ if(sum)
+ {
+ iounmap(rsdt);
+ return 0;
+ }
+
+ /* Ok the RSDT checksums too */
+
+ for(n = 36; n+3 < i; n += 4)
+ {
+ unsigned long rp = readl(rsdt+n);
+ int len = 4096;
+
+ if(rp > 0xFFFFFFFFUL - len)
+ len = 0xFFFFFFFFUL - rp;
+
+ /* Too close to the end!! */
+ if(len < 20)
+ continue;
+ rp = (unsigned long)ioremap(rp, 4096);
+ if(rp == 0)
+ continue;
+ if(sbf_struct_valid(rp))
+ {
+ /* Found the BOOT table and processed it */
+ printk(KERN_INFO "SBF: Simple Boot Flag extension found and enabled.\n");
+ }
+ iounmap((void *)rp);
+ }
+ iounmap(rsdt);
+ sbf_bootup();
+ return 0;
+}
+
+module_init(sbf_init);
diff --git a/arch/i386/kernel/cpuid.c b/arch/i386/kernel/cpuid.c
index 499b2fd70266e..0c2bd6de08b67 100644
--- a/arch/i386/kernel/cpuid.c
+++ b/arch/i386/kernel/cpuid.c
@@ -35,6 +35,7 @@
#include <linux/poll.h>
#include <linux/smp.h>
#include <linux/major.h>
+#include <linux/fs.h>
#include <linux/smp_lock.h>
#include <linux/fs.h>
diff --git a/arch/i386/kernel/dmi_scan.c b/arch/i386/kernel/dmi_scan.c
index 25bc3d7286ee9..21b1edb14689c 100644
--- a/arch/i386/kernel/dmi_scan.c
+++ b/arch/i386/kernel/dmi_scan.c
@@ -295,6 +295,22 @@ static __init int apm_is_horked(struct dmi_blacklist *d)
return 0;
}
+/*
+ * Work around broken HP Pavilion Notebooks which assign USB to
+ * IRQ 9 even though it is actually wired to IRQ 11
+ */
+static __init int fix_broken_hp_bios_irq9(struct dmi_blacklist *d)
+{
+#ifdef CONFIG_PCI
+ extern int broken_hp_bios_irq9;
+ if (broken_hp_bios_irq9 == 0)
+ {
+ broken_hp_bios_irq9 = 1;
+ printk(KERN_INFO "%s detected - fixing broken IRQ routing\n", d->ident);
+ }
+#endif
+ return 0;
+}
/*
* Check for clue free BIOS implementations who use
@@ -438,6 +454,25 @@ static int __init local_apic_kills_bios(struct dmi_blacklist *d)
}
/*
+ * The Microstar 6163-2 (a.k.a Pro) mainboard will hang shortly after
+ * resumes, and also at what appears to be asynchronous APM events,
+ * if the local APIC is enabled.
+ */
+static int __init apm_kills_local_apic(struct dmi_blacklist *d)
+{
+#ifdef CONFIG_X86_LOCAL_APIC
+ extern int dont_enable_local_apic;
+ if (apm_info.bios.version && !dont_enable_local_apic) {
+ dont_enable_local_apic = 1;
+ printk(KERN_WARNING "%s with broken BIOS detected. "
+ "Refusing to enable the local APIC.\n",
+ d->ident);
+ }
+#endif
+ return 0;
+}
+
+/*
* The Intel AL440LX mainboard will hang randomly if the local APIC
* timer is running and the APM BIOS hasn't been disabled.
*/
@@ -483,10 +518,10 @@ static __initdata struct dmi_blacklist dmi_blacklist[]={
} },
#endif
{ broken_ps2_resume, "Dell Latitude C600", { /* Handle problems with APM on the C600 */
- MATCH(DMI_SYS_VENDOR, "Dell"),
+ MATCH(DMI_SYS_VENDOR, "Dell"),
MATCH(DMI_PRODUCT_NAME, "Latitude C600"),
NO_MATCH, NO_MATCH
- } },
+ } },
{ broken_apm_power, "Dell Inspiron 5000e", { /* Handle problems with APM on Inspiron 5000e */
MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
MATCH(DMI_BIOS_VERSION, "A04"),
@@ -512,6 +547,11 @@ static __initdata struct dmi_blacklist dmi_blacklist[]={
MATCH(DMI_PRODUCT_NAME, "PowerEdge 300/"),
NO_MATCH, NO_MATCH
} },
+ { set_bios_reboot, "Dell PowerEdge 2400", { /* Handle problems with rebooting on Dell 300/800's */
+ MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
+ MATCH(DMI_PRODUCT_NAME, "PowerEdge 2400"),
+ NO_MATCH, NO_MATCH
+ } },
{ set_apm_ints, "Dell Inspiron", { /* Allow interrupts during suspend on Dell Inspiron laptops*/
MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
MATCH(DMI_PRODUCT_NAME, "Inspiron 4000"),
@@ -533,12 +573,23 @@ static __initdata struct dmi_blacklist dmi_blacklist[]={
MATCH(DMI_PRODUCT_NAME, "Delhi3"),
NO_MATCH, NO_MATCH,
} },
+ { apm_is_horked, "Fujitsu-Siemens", { /* APM crashes */
+ MATCH(DMI_BIOS_VENDOR, "hoenix/FUJITSU SIEMENS"),
+ MATCH(DMI_BIOS_VERSION, "Version1.01"),
+ NO_MATCH, NO_MATCH,
+ } },
{ apm_is_horked, "Sharp PC-PJ/AX", { /* APM crashes */
MATCH(DMI_SYS_VENDOR, "SHARP"),
MATCH(DMI_PRODUCT_NAME, "PC-PJ/AX"),
MATCH(DMI_BIOS_VENDOR,"SystemSoft"),
MATCH(DMI_BIOS_VERSION,"Version R2.08")
} },
+ { apm_is_horked, "Dell Inspiron 2500", { /* APM crashes */
+ MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
+ MATCH(DMI_PRODUCT_NAME, "Inspiron 2500"),
+ MATCH(DMI_BIOS_VENDOR,"Phoenix Technologies LTD"),
+ MATCH(DMI_BIOS_VERSION,"A11")
+ } },
{ sony_vaio_laptop, "Sony Vaio", { /* This is a Sony Vaio laptop */
MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
MATCH(DMI_PRODUCT_NAME, "PCG-"),
@@ -548,7 +599,7 @@ static __initdata struct dmi_blacklist dmi_blacklist[]={
MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
MATCH(DMI_BIOS_VERSION, "R0206H"),
MATCH(DMI_BIOS_DATE, "08/23/99"), NO_MATCH
- } },
+ } },
{ swab_apm_power_in_minutes, "Sony VAIO", { /* Handle problems with APM on Sony Vaio PCG-N505VX */
MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
@@ -574,6 +625,12 @@ static __initdata struct dmi_blacklist dmi_blacklist[]={
MATCH(DMI_BIOS_DATE, "08/11/00"), NO_MATCH
} },
+ { swab_apm_power_in_minutes, "Sony VAIO", { /* Handle problems with APM on Sony Vaio PCG-Z600LEK(DE) */
+ MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
+ MATCH(DMI_BIOS_VERSION, "R0206Z3"),
+ MATCH(DMI_BIOS_DATE, "12/25/00"), NO_MATCH
+ } },
+
{ swab_apm_power_in_minutes, "Sony VAIO", { /* Handle problems with APM on Sony Vaio PCG-Z505LS */
MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
MATCH(DMI_BIOS_VERSION, "R0203D0"),
@@ -617,6 +674,17 @@ static __initdata struct dmi_blacklist dmi_blacklist[]={
NO_MATCH, NO_MATCH
} },
+ { local_apic_kills_bios, "IBM Thinkpad T20", {
+ MATCH(DMI_BOARD_VENDOR, "IBM"),
+ MATCH(DMI_BOARD_NAME, "264741U"),
+ NO_MATCH, NO_MATCH
+ } },
+
+ { apm_kills_local_apic, "Microstar 6163", {
+ MATCH(DMI_BOARD_VENDOR, "MICRO-STAR INTERNATIONAL CO., LTD"),
+ MATCH(DMI_BOARD_NAME, "MS-6163"),
+ NO_MATCH, NO_MATCH } },
+
{ apm_kills_local_apic_timer, "Intel AL440LX", {
MATCH(DMI_BOARD_VENDOR, "Intel Corporation"),
MATCH(DMI_BOARD_NAME, "AL440LX"),
@@ -678,7 +746,14 @@ static __initdata struct dmi_blacklist dmi_blacklist[]={
NO_MATCH, NO_MATCH
} },
-
+ { fix_broken_hp_bios_irq9, "HP Pavilion N5400 Series Laptop", {
+ MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
+ MATCH(DMI_BIOS_VERSION, "GE.M1.03"),
+ MATCH(DMI_PRODUCT_VERSION, "HP Pavilion Notebook Model GE"),
+ MATCH(DMI_BOARD_VERSION, "OmniBook N32N-736")
+ } },
+
+
/*
* Generic per vendor APM settings
*/
diff --git a/arch/i386/kernel/i386_ksyms.c b/arch/i386/kernel/i386_ksyms.c
index 5e21e7a4629b7..b7e346df7495b 100644
--- a/arch/i386/kernel/i386_ksyms.c
+++ b/arch/i386/kernel/i386_ksyms.c
@@ -93,7 +93,6 @@ EXPORT_SYMBOL_NOVERS(__get_user_1);
EXPORT_SYMBOL_NOVERS(__get_user_2);
EXPORT_SYMBOL_NOVERS(__get_user_4);
-EXPORT_SYMBOL(strtok);
EXPORT_SYMBOL(strpbrk);
EXPORT_SYMBOL(strstr);
diff --git a/arch/i386/kernel/microcode.c b/arch/i386/kernel/microcode.c
index 64fb22f72def2..40da258a929d3 100644
--- a/arch/i386/kernel/microcode.c
+++ b/arch/i386/kernel/microcode.c
@@ -51,6 +51,12 @@
* Bugfix for HT (Hyper-Threading) enabled processors
* whereby processor resources are shared by all logical processors
* in a single CPU package.
+ * 1.10 28 Feb 2002 Asit K Mallick <asit.k.mallick@intel.com> and
+ * Tigran Aivazian <tigran@veritas.com>,
+ * Serialize updates as required on HT processors due to speculative
+ * nature of implementation.
+ * 1.11 22 Mar 2001 Tigran Aivazian <tigran@veritas.com>
+ * Fix the panic when writing zero-length microcode chunk.
*/
#include <linux/init.h>
@@ -60,12 +66,16 @@
#include <linux/vmalloc.h>
#include <linux/miscdevice.h>
#include <linux/devfs_fs_kernel.h>
+#include <linux/spinlock.h>
#include <asm/msr.h>
#include <asm/uaccess.h>
#include <asm/processor.h>
-#define MICROCODE_VERSION "1.09"
+
+static spinlock_t microcode_update_lock = SPIN_LOCK_UNLOCKED;
+
+#define MICROCODE_VERSION "1.11"
MODULE_DESCRIPTION("Intel CPU (IA-32) microcode update driver");
MODULE_AUTHOR("Tigran Aivazian <tigran@veritas.com>");
@@ -195,7 +205,8 @@ static void do_update_one(void *unused)
struct cpuinfo_x86 *c = cpu_data + cpu_num;
struct update_req *req = update_req + cpu_num;
unsigned int pf = 0, val[2], rev, sig;
- int i,found=0;
+ unsigned long flags;
+ int i;
req->err = 1; /* assume update will fail on this cpu */
@@ -216,8 +227,9 @@ static void do_update_one(void *unused)
for (i=0; i<microcode_num; i++)
if (microcode[i].sig == sig && microcode[i].pf == pf &&
microcode[i].ldrver == 1 && microcode[i].hdrver == 1) {
-
- found=1;
+ int sum = 0;
+ struct microcode *m = &microcode[i];
+ unsigned int *sump = (unsigned int *)(m+1);
printf("Microcode\n");
printf(" Header Revision %d\n",microcode[i].hdrver);
@@ -234,54 +246,69 @@ static void do_update_one(void *unused)
printf(" Loader Revision %x\n",microcode[i].ldrver);
printf(" Processor Flags %x\n\n",microcode[i].pf);
+ req->slot = i;
+
+ /* serialize access to update decision */
+ spin_lock_irqsave(&microcode_update_lock, flags);
+
/* trick, to work even if there was no prior update by the BIOS */
wrmsr(MSR_IA32_UCODE_REV, 0, 0);
__asm__ __volatile__ ("cpuid" : : : "ax", "bx", "cx", "dx");
/* get current (on-cpu) revision into rev (ignore val[0]) */
rdmsr(MSR_IA32_UCODE_REV, val[0], rev);
+
if (microcode[i].rev < rev) {
+ spin_unlock_irqrestore(&microcode_update_lock, flags);
printk(KERN_ERR
- "microcode: CPU%d not 'upgrading' to earlier revision"
+ "microcode: CPU%d not 'upgrading' to earlier revision"
+ " %d (current=%d)\n", cpu_num, microcode[i].rev, rev);
+ return;
+ } else if (microcode[i].rev == rev) {
+ /* notify the caller of success on this cpu */
+ req->err = 0;
+ spin_unlock_irqrestore(&microcode_update_lock, flags);
+ printk(KERN_ERR
+ "microcode: CPU%d already at revision"
" %d (current=%d)\n", cpu_num, microcode[i].rev, rev);
- } else {
- int sum = 0;
- struct microcode *m = &microcode[i];
- unsigned int *sump = (unsigned int *)(m+1);
-
- while (--sump >= (unsigned int *)m)
- sum += *sump;
- if (sum != 0) {
- printk(KERN_ERR "microcode: CPU%d aborting, "
- "bad checksum\n", cpu_num);
- break;
- }
-
- /* write microcode via MSR 0x79 */
- wrmsr(MSR_IA32_UCODE_WRITE, (unsigned int)(m->bits), 0);
+ return;
+ }
- /* serialize */
- __asm__ __volatile__ ("cpuid" : : : "ax", "bx", "cx", "dx");
+ /* Verify the checksum */
+ while (--sump >= (unsigned int *)m)
+ sum += *sump;
+ if (sum != 0) {
+ req->err = 1;
+ spin_unlock_irqrestore(&microcode_update_lock, flags);
+ printk(KERN_ERR "microcode: CPU%d aborting, "
+ "bad checksum\n", cpu_num);
+ return;
+ }
+
+ /* write microcode via MSR 0x79 */
+ wrmsr(MSR_IA32_UCODE_WRITE, (unsigned int)(m->bits), 0);
- /* get the current revision from MSR 0x8B */
- rdmsr(MSR_IA32_UCODE_REV, val[0], val[1]);
+ /* serialize */
+ __asm__ __volatile__ ("cpuid" : : : "ax", "bx", "cx", "dx");
- /* notify the caller of success on this cpu */
- req->err = 0;
- req->slot = i;
+ /* get the current revision from MSR 0x8B */
+ rdmsr(MSR_IA32_UCODE_REV, val[0], val[1]);
- printk(KERN_INFO "microcode: CPU%d updated from revision "
- "%d to %d, date=%08x\n",
- cpu_num, rev, val[1], m->date);
- }
- break;
+ /* notify the caller of success on this cpu */
+ req->err = 0;
+ spin_unlock_irqrestore(&microcode_update_lock, flags);
+ printk(KERN_INFO "microcode: CPU%d updated from revision "
+ "%d to %d, date=%08x\n",
+ cpu_num, rev, val[1], microcode[i].date);
+ return;
}
-
- if(!found)
- printk(KERN_ERR "microcode: CPU%d no microcode found! (sig=%x, pflags=%d)\n",
- cpu_num, sig, pf);
+
+ printk(KERN_ERR
+ "microcode: CPU%d no microcode found! (sig=%x, pflags=%d)\n",
+ cpu_num, sig, pf);
}
+
static ssize_t microcode_read(struct file *file, char *buf, size_t len, loff_t *ppos)
{
ssize_t ret = 0;
@@ -305,11 +332,15 @@ static ssize_t microcode_write(struct file *file, const char *buf, size_t len, l
{
ssize_t ret;
- if (len % sizeof(struct microcode) != 0) {
+ if (!len || len % sizeof(struct microcode) != 0) {
printk(KERN_ERR "microcode: can only write in N*%d bytes units\n",
sizeof(struct microcode));
return -EINVAL;
}
+ if ((len >> PAGE_SHIFT) > num_physpages) {
+ printk(KERN_ERR "microcode: too much data (max %d pages)\n", num_physpages);
+ return -EINVAL;
+ }
down_write(&microcode_rwsem);
if (!mc_applied) {
mc_applied = kmalloc(smp_num_cpus*sizeof(struct microcode),
diff --git a/arch/i386/kernel/mpparse.c b/arch/i386/kernel/mpparse.c
index 313f05f6f2bd7..2df0c948a1a26 100644
--- a/arch/i386/kernel/mpparse.c
+++ b/arch/i386/kernel/mpparse.c
@@ -232,6 +232,7 @@ void __init MP_processor_info (struct mpc_config_processor *m)
if (m->mpc_apicid > MAX_APICS) {
printk("Processor #%d INVALID. (Max ID: %d).\n",
m->mpc_apicid, MAX_APICS);
+ --num_processors;
return;
}
ver = m->mpc_apicver;
@@ -816,11 +817,13 @@ void __init find_intel_smp (void)
* trustworthy, simply because the SMP table may have been
* stomped on during early boot. These loaders are buggy and
* should be fixed.
+ *
+ * MP1.4 SPEC states to only scan first 1K of 4K EBDA.
*/
address = *(unsigned short *)phys_to_virt(0x40E);
address <<= 4;
- smp_scan_config(address, 0x1000);
+ smp_scan_config(address, 0x400);
if (smp_found_config)
printk(KERN_WARNING "WARNING: MP table in the EBDA can be UNSAFE, contact linux-smp@vger.kernel.org if you experience SMP problems!\n");
}
diff --git a/arch/i386/kernel/mtrr.c b/arch/i386/kernel/mtrr.c
index d93e7a710a444..2adc9ddf3076a 100644
--- a/arch/i386/kernel/mtrr.c
+++ b/arch/i386/kernel/mtrr.c
@@ -498,7 +498,6 @@ static int have_wrcomb (void)
case MTRR_IF_INTEL:
rdmsr (MTRRcap_MSR, config, dummy);
return (config & (1<<10));
- return 1;
case MTRR_IF_AMD_K6:
case MTRR_IF_CENTAUR_MCR:
case MTRR_IF_CYRIX_ARR:
diff --git a/arch/i386/kernel/nmi.c b/arch/i386/kernel/nmi.c
index f91e5a3bdd619..c0b10d8aaefbf 100644
--- a/arch/i386/kernel/nmi.c
+++ b/arch/i386/kernel/nmi.c
@@ -8,6 +8,7 @@
* Fixes:
* Mikael Pettersson : AMD K7 support for local APIC NMI watchdog.
* Mikael Pettersson : Power Management for local APIC NMI watchdog.
+ * Mikael Pettersson : Pentium 4 support for local APIC NMI watchdog.
*/
#include <linux/config.h>
@@ -43,6 +44,32 @@ extern void show_registers(struct pt_regs *regs);
#define P6_EVENT_CPU_CLOCKS_NOT_HALTED 0x79
#define P6_NMI_EVENT P6_EVENT_CPU_CLOCKS_NOT_HALTED
+#define MSR_P4_MISC_ENABLE 0x1A0
+#define MSR_P4_MISC_ENABLE_PERF_AVAIL (1<<7)
+#define MSR_P4_MISC_ENABLE_PEBS_UNAVAIL (1<<12)
+#define MSR_P4_PERFCTR0 0x300
+#define MSR_P4_CCCR0 0x360
+#define P4_ESCR_EVENT_SELECT(N) ((N)<<25)
+#define P4_ESCR_OS (1<<3)
+#define P4_ESCR_USR (1<<2)
+#define P4_CCCR_OVF_PMI (1<<26)
+#define P4_CCCR_THRESHOLD(N) ((N)<<20)
+#define P4_CCCR_COMPLEMENT (1<<19)
+#define P4_CCCR_COMPARE (1<<18)
+#define P4_CCCR_REQUIRED (3<<16)
+#define P4_CCCR_ESCR_SELECT(N) ((N)<<13)
+#define P4_CCCR_ENABLE (1<<12)
+/* Set up IQ_COUNTER0 to behave like a clock, by having IQ_CCCR0 filter
+ CRU_ESCR0 (with any non-null event selector) through a complemented
+ max threshold. [IA32-Vol3, Section 14.9.9] */
+#define MSR_P4_IQ_COUNTER0 0x30C
+#define MSR_P4_IQ_CCCR0 0x36C
+#define MSR_P4_CRU_ESCR0 0x3B8
+#define P4_NMI_CRU_ESCR0 (P4_ESCR_EVENT_SELECT(0x3F)|P4_ESCR_OS|P4_ESCR_USR)
+#define P4_NMI_IQ_CCCR0 \
+ (P4_CCCR_OVF_PMI|P4_CCCR_THRESHOLD(15)|P4_CCCR_COMPLEMENT| \
+ P4_CCCR_COMPARE|P4_CCCR_REQUIRED|P4_CCCR_ESCR_SELECT(4)|P4_CCCR_ENABLE)
+
int __init check_nmi_watchdog (void)
{
irq_cpustat_t tmp[NR_CPUS];
@@ -84,11 +111,11 @@ static int __init setup_nmi_watchdog(char *str)
/*
* If any other x86 CPU has a local APIC, then
* please test the NMI stuff there and send me the
- * missing bits. Right now Intel P6 and AMD K7 only.
+ * missing bits. Right now Intel P6/P4 and AMD K7 only.
*/
if ((nmi == NMI_LOCAL_APIC) &&
(boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) &&
- (boot_cpu_data.x86 == 6))
+ (boot_cpu_data.x86 == 6 || boot_cpu_data.x86 == 15))
nmi_watchdog = nmi;
if ((nmi == NMI_LOCAL_APIC) &&
(boot_cpu_data.x86_vendor == X86_VENDOR_AMD) &&
@@ -118,7 +145,15 @@ static void disable_apic_nmi_watchdog(void)
wrmsr(MSR_K7_EVNTSEL0, 0, 0);
break;
case X86_VENDOR_INTEL:
- wrmsr(MSR_IA32_EVNTSEL0, 0, 0);
+ switch (boot_cpu_data.x86) {
+ case 6:
+ wrmsr(MSR_P6_EVNTSEL0, 0, 0);
+ break;
+ case 15:
+ wrmsr(MSR_P4_IQ_CCCR0, 0, 0);
+ wrmsr(MSR_P4_CRU_ESCR0, 0, 0);
+ break;
+ }
break;
}
}
@@ -157,17 +192,22 @@ static inline void nmi_pm_init(void) { }
* Original code written by Keith Owens.
*/
+static void __pminit clear_msr_range(unsigned int base, unsigned int n)
+{
+ unsigned int i;
+
+ for(i = 0; i < n; ++i)
+ wrmsr(base+i, 0, 0);
+}
+
static void __pminit setup_k7_watchdog(void)
{
- int i;
unsigned int evntsel;
nmi_perfctr_msr = MSR_K7_PERFCTR0;
- for(i = 0; i < 4; ++i) {
- wrmsr(MSR_K7_EVNTSEL0+i, 0, 0);
- wrmsr(MSR_K7_PERFCTR0+i, 0, 0);
- }
+ clear_msr_range(MSR_K7_EVNTSEL0, 4);
+ clear_msr_range(MSR_K7_PERFCTR0, 4);
evntsel = K7_EVNTSEL_INT
| K7_EVNTSEL_OS
@@ -184,27 +224,54 @@ static void __pminit setup_k7_watchdog(void)
static void __pminit setup_p6_watchdog(void)
{
- int i;
unsigned int evntsel;
- nmi_perfctr_msr = MSR_IA32_PERFCTR0;
+ nmi_perfctr_msr = MSR_P6_PERFCTR0;
- for(i = 0; i < 2; ++i) {
- wrmsr(MSR_IA32_EVNTSEL0+i, 0, 0);
- wrmsr(MSR_IA32_PERFCTR0+i, 0, 0);
- }
+ clear_msr_range(MSR_P6_EVNTSEL0, 2);
+ clear_msr_range(MSR_P6_PERFCTR0, 2);
evntsel = P6_EVNTSEL_INT
| P6_EVNTSEL_OS
| P6_EVNTSEL_USR
| P6_NMI_EVENT;
- wrmsr(MSR_IA32_EVNTSEL0, evntsel, 0);
- Dprintk("setting IA32_PERFCTR0 to %08lx\n", -(cpu_khz/nmi_hz*1000));
- wrmsr(MSR_IA32_PERFCTR0, -(cpu_khz/nmi_hz*1000), 0);
+ wrmsr(MSR_P6_EVNTSEL0, evntsel, 0);
+ Dprintk("setting P6_PERFCTR0 to %08lx\n", -(cpu_khz/nmi_hz*1000));
+ wrmsr(MSR_P6_PERFCTR0, -(cpu_khz/nmi_hz*1000), 0);
apic_write(APIC_LVTPC, APIC_DM_NMI);
evntsel |= P6_EVNTSEL0_ENABLE;
- wrmsr(MSR_IA32_EVNTSEL0, evntsel, 0);
+ wrmsr(MSR_P6_EVNTSEL0, evntsel, 0);
+}
+
+static int __pminit setup_p4_watchdog(void)
+{
+ unsigned int misc_enable, dummy;
+
+ rdmsr(MSR_P4_MISC_ENABLE, misc_enable, dummy);
+ if (!(misc_enable & MSR_P4_MISC_ENABLE_PERF_AVAIL))
+ return 0;
+
+ nmi_perfctr_msr = MSR_P4_IQ_COUNTER0;
+
+ if (!(misc_enable & MSR_P4_MISC_ENABLE_PEBS_UNAVAIL))
+ clear_msr_range(0x3F1, 2);
+ /* MSR 0x3F0 seems to have a default value of 0xFC00, but current
+ docs doesn't fully define it, so leave it alone for now. */
+ clear_msr_range(0x3A0, 31);
+ clear_msr_range(0x3C0, 6);
+ clear_msr_range(0x3C8, 6);
+ clear_msr_range(0x3E0, 2);
+ clear_msr_range(MSR_P4_CCCR0, 18);
+ clear_msr_range(MSR_P4_PERFCTR0, 18);
+
+ wrmsr(MSR_P4_CRU_ESCR0, P4_NMI_CRU_ESCR0, 0);
+ wrmsr(MSR_P4_IQ_CCCR0, P4_NMI_IQ_CCCR0 & ~P4_CCCR_ENABLE, 0);
+ Dprintk("setting P4_IQ_COUNTER0 to 0x%08lx\n", -(cpu_khz/nmi_hz*1000));
+ wrmsr(MSR_P4_IQ_COUNTER0, -(cpu_khz/nmi_hz*1000), -1);
+ apic_write(APIC_LVTPC, APIC_DM_NMI);
+ wrmsr(MSR_P4_IQ_CCCR0, P4_NMI_IQ_CCCR0, 0);
+ return 1;
}
void __pminit setup_apic_nmi_watchdog (void)
@@ -216,9 +283,17 @@ void __pminit setup_apic_nmi_watchdog (void)
setup_k7_watchdog();
break;
case X86_VENDOR_INTEL:
- if (boot_cpu_data.x86 != 6)
+ switch (boot_cpu_data.x86) {
+ case 6:
+ setup_p6_watchdog();
+ break;
+ case 15:
+ if (!setup_p4_watchdog())
+ return;
+ break;
+ default:
return;
- setup_p6_watchdog();
+ }
break;
default:
return;
@@ -296,6 +371,18 @@ void nmi_watchdog_tick (struct pt_regs * regs)
last_irq_sums[cpu] = sum;
alert_counter[cpu] = 0;
}
- if (nmi_perfctr_msr)
+ if (nmi_perfctr_msr) {
+ if (nmi_perfctr_msr == MSR_P4_IQ_COUNTER0) {
+ /*
+ * P4 quirks:
+ * - An overflown perfctr will assert its interrupt
+ * until the OVF flag in its CCCR is cleared.
+ * - LVTPC is masked on interrupt and must be
+ * unmasked by the LVTPC handler.
+ */
+ wrmsr(MSR_P4_IQ_CCCR0, P4_NMI_IQ_CCCR0, 0);
+ apic_write(APIC_LVTPC, APIC_DM_NMI);
+ }
wrmsr(nmi_perfctr_msr, -(cpu_khz/nmi_hz*1000), -1);
+ }
}
diff --git a/arch/i386/kernel/pci-dma.c b/arch/i386/kernel/pci-dma.c
index 18a08ccbac1b4..2031b8583ecad 100644
--- a/arch/i386/kernel/pci-dma.c
+++ b/arch/i386/kernel/pci-dma.c
@@ -19,7 +19,7 @@ void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size,
void *ret;
int gfp = GFP_ATOMIC;
- if (hwdev == NULL || hwdev->dma_mask != 0xffffffff)
+ if (hwdev == NULL || ((u32)hwdev->dma_mask != 0xffffffff))
gfp |= GFP_DMA;
ret = (void *)__get_free_pages(gfp, get_order(size));
diff --git a/arch/i386/kernel/pci-irq.c b/arch/i386/kernel/pci-irq.c
index 15957438cb05b..b4898265dad3b 100644
--- a/arch/i386/kernel/pci-irq.c
+++ b/arch/i386/kernel/pci-irq.c
@@ -23,6 +23,7 @@
#define PIRQ_VERSION 0x0100
int pci_use_acpi_routing = 0;
+int broken_hp_bios_irq9;
static struct irq_routing_table *pirq_table;
@@ -208,6 +209,24 @@ static int pirq_via_set(struct pci_dev *router, struct pci_dev *dev, int pirq, i
}
/*
+ * ITE 8330G pirq rules are nibble-based
+ * FIXME: pirqmap may be { 1, 0, 3, 2 },
+ * 2+3 are both mapped to irq 9 on my system
+ */
+static int pirq_ite_get(struct pci_dev *router, struct pci_dev *dev, int pirq)
+{
+ static unsigned char pirqmap[4] = { 1, 0, 2, 3 };
+ return read_config_nybble(router,0x43, pirqmap[pirq-1]);
+}
+
+static int pirq_ite_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq)
+{
+ static unsigned char pirqmap[4] = { 1, 0, 2, 3 };
+ write_config_nybble(router, 0x43, pirqmap[pirq-1], irq);
+ return 1;
+}
+
+/*
* OPTI: high four bits are nibble pointer..
* I wonder what the low bits do?
*/
@@ -227,12 +246,12 @@ static int pirq_opti_set(struct pci_dev *router, struct pci_dev *dev, int pirq,
*/
static int pirq_cyrix_get(struct pci_dev *router, struct pci_dev *dev, int pirq)
{
- return read_config_nybble(router, 0x5C, pirq-1);
+ return read_config_nybble(router, 0x5C, (pirq-1)^1);
}
static int pirq_cyrix_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq)
{
- write_config_nybble(router, 0x5C, pirq-1, irq);
+ write_config_nybble(router, 0x5C, (pirq-1)^1, irq);
return 1;
}
@@ -445,10 +464,17 @@ static struct irq_router pirq_routers[] = {
{ "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_0, pirq_piix_get, pirq_piix_set },
{ "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371MX, pirq_piix_get, pirq_piix_set },
{ "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443MX_0, pirq_piix_get, pirq_piix_set },
+ { "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_0, pirq_piix_get, pirq_piix_set },
+ { "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AB_0, pirq_piix_get, pirq_piix_set },
{ "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0, pirq_piix_get, pirq_piix_set },
+ { "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_10, pirq_piix_get, pirq_piix_set },
+ { "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_0, pirq_piix_get, pirq_piix_set },
+ { "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_12, pirq_piix_get, pirq_piix_set },
{ "ALI", PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, pirq_ali_get, pirq_ali_set },
+ { "ITE", PCI_VENDOR_ID_ITE, PCI_DEVICE_ID_ITE_IT8330G_0, pirq_ite_get, pirq_ite_set },
+
{ "VIA", PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_0, pirq_via_get, pirq_via_set },
{ "VIA", PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C596, pirq_via_get, pirq_via_set },
{ "VIA", PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686, pirq_via_get, pirq_via_set },
@@ -589,6 +615,15 @@ static int pirq_lookup_irq(struct pci_dev *dev, u8 pin, int assign)
DBG(" -> PIRQ %02x, mask %04x, excl %04x", pirq, mask, pirq_table->exclusive_irqs);
mask &= pcibios_irq_mask;
+ /* Work around broken HP Pavilion Notebooks which assign USB to
+ IRQ 9 even though it is actually wired to IRQ 11 */
+
+ if (broken_hp_bios_irq9 && pirq == 0x59 && dev->irq == 9) {
+ dev->irq = 11;
+ pci_write_config_byte(dev, PCI_INTERRUPT_LINE, 11);
+ r->set(pirq_router_dev, dev, pirq, 11);
+ }
+
/*
* Find the best IRQ to assign: use the one
* reported by the device if possible.
diff --git a/arch/i386/kernel/pci-pc.c b/arch/i386/kernel/pci-pc.c
index 7702a6d0c040f..9f40d4374b71d 100644
--- a/arch/i386/kernel/pci-pc.c
+++ b/arch/i386/kernel/pci-pc.c
@@ -1205,7 +1205,8 @@ static void __init pci_fixup_via_northbridge_bug(struct pci_dev *d)
pci_read_config_byte(d, where, &v);
if (v & 0xe0) {
- printk("Disabling broken memory write queue.\n");
+ printk("Disabling broken memory write queue: [%02x] %02x->%02x\n",
+ where, v, v & 0x1f);
v &= 0x1f; /* clear bits 5, 6, 7 */
pci_write_config_byte(d, where, v);
}
diff --git a/arch/i386/kernel/setup.c b/arch/i386/kernel/setup.c
index d3f11c8b6ac7e..bbeb875aecfb4 100644
--- a/arch/i386/kernel/setup.c
+++ b/arch/i386/kernel/setup.c
@@ -99,6 +99,8 @@
#endif
#include <linux/highmem.h>
#include <linux/bootmem.h>
+#include <linux/pci.h>
+#include <linux/pci_ids.h>
#include <linux/seq_file.h>
#include <linux/console.h>
#include <asm/processor.h>
@@ -127,9 +129,6 @@ unsigned long mmu_cr4_features;
/*
* Bus types ..
*/
-#ifdef CONFIG_EISA
-int EISA_bus;
-#endif
int MCA_bus;
/* for MCA, but anyone else can use it if they want */
@@ -210,6 +209,10 @@ struct resource standard_io_resources[] = {
{ "dma2", 0xc0, 0xdf, IORESOURCE_BUSY },
{ "fpu", 0xf0, 0xff, IORESOURCE_BUSY }
};
+#ifdef CONFIG_MELAN
+standard_io_resources[1] = { "pic1", 0x20, 0x21, IORESOURCE_BUSY };
+standard_io_resources[5] = { "pic2", 0xa0, 0xa1, IORESOURCE_BUSY };
+#endif
#define STANDARD_IO_RESOURCES (sizeof(standard_io_resources)/sizeof(struct resource))
@@ -1240,7 +1243,7 @@ static int __init init_amd(struct cpuinfo_x86 *c)
}
/*
- * Read Cyrix DEVID registers (DIR) to get more detailed info. about the CPU
+ * Read NSC/Cyrix DEVID registers (DIR) to get more detailed info. about the CPU
*/
static void __init do_cyrix_devid(unsigned char *dir0, unsigned char *dir1)
{
@@ -1315,7 +1318,7 @@ extern void calibrate_delay(void) __init;
static void __init check_cx686_slop(struct cpuinfo_x86 *c)
{
unsigned long flags;
-
+
if (Cx86_dir0_msb == 3) {
unsigned char ccr3, ccr5;
@@ -1325,7 +1328,7 @@ static void __init check_cx686_slop(struct cpuinfo_x86 *c)
ccr5 = getCx86(CX86_CCR5);
if (ccr5 & 2)
setCx86(CX86_CCR5, ccr5 & 0xfd); /* reset SLOP */
- setCx86(CX86_CCR3, ccr3); /* disable MAPEN */
+ setCx86(CX86_CCR3, ccr3); /* disable MAPEN */
local_irq_restore(flags);
if (ccr5 & 2) { /* possible wrong calibration done */
@@ -1336,6 +1339,7 @@ static void __init check_cx686_slop(struct cpuinfo_x86 *c)
}
}
+
static void __init init_cyrix(struct cpuinfo_x86 *c)
{
unsigned char dir0, dir0_msn, dir0_lsn, dir1 = 0;
@@ -1402,17 +1406,12 @@ static void __init init_cyrix(struct cpuinfo_x86 *c)
break;
case 4: /* MediaGX/GXm */
- /*
- * Life sometimes gets weiiiiiiiird if we use this
- * on the MediaGX. So we turn it off for now.
- */
-
#ifdef CONFIG_PCI
- /* It isnt really a PCI quirk directly, but the cure is the
+ /* It isn't really a PCI quirk directly, but the cure is the
same. The MediaGX has deep magic SMM stuff that handles the
SB emulation. It thows away the fifo on disable_dma() which
is wrong and ruins the audio.
-
+
Bug2: VSA1 has a wrap bug so that using maximum sized DMA
causes bad things. According to NatSemi VSA2 has another
bug to do with 'hlt'. I've not seen any boards using VSA2
@@ -1427,15 +1426,26 @@ static void __init init_cyrix(struct cpuinfo_x86 *c)
/* GXm supports extended cpuid levels 'ala' AMD */
if (c->cpuid_level == 2) {
+ /* Enable Natsemi MMX extensions */
+ setCx86(CX86_CCR7, getCx86(CX86_CCR7) | 1);
+
get_model_name(c); /* get CPU marketing name */
- clear_bit(X86_FEATURE_TSC, c->x86_capability);
+ /*
+ * The 5510/5520 companion chips have a funky PIT
+ * that breaks the TSC synchronizing, so turn it off
+ */
+ if(pci_find_device(PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5510, NULL) ||
+ pci_find_device(PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5520, NULL))
+ clear_bit(X86_FEATURE_TSC, c->x86_capability);
return;
}
else { /* MediaGX */
Cx86_cb[2] = (dir0_lsn & 1) ? '3' : '4';
p = Cx86_cb+2;
c->x86_model = (dir1 & 0x20) ? 1 : 2;
+#ifndef CONFIG_CS5520
clear_bit(X86_FEATURE_TSC, &c->x86_capability);
+#endif
}
break;
@@ -1453,7 +1463,7 @@ static void __init init_cyrix(struct cpuinfo_x86 *c)
tmp = (!(dir0_lsn & 7) || dir0_lsn & 1) ? 2 : 0;
Cx86_cb[tmp] = cyrix_model_mult2[dir0_lsn & 7];
p = Cx86_cb+tmp;
- if (((dir1 & 0x0f) > 4) || ((dir1 & 0xf0) == 0x20))
+ if (((dir1 & 0x0f) > 4) || ((dir1 & 0xf0) == 0x20))
(c->x86_model)++;
/* Emulate MTRRs using Cyrix's ARRs. */
set_bit(X86_FEATURE_CYRIX_ARR, &c->x86_capability);
@@ -2096,7 +2106,7 @@ static void __init init_intel(struct cpuinfo_x86 *c)
}
if ( l1i || l1d )
printk(KERN_INFO "CPU: L1 I cache: %dK, L1 D cache: %dK\n",
- l1i, l1d);
+ l1i, l1d);
if ( l2 )
printk(KERN_INFO "CPU: L2 cache: %dK\n", l2);
if ( l3 )
@@ -2203,6 +2213,8 @@ void __init get_cpu_vendor(struct cpuinfo_x86 *c)
c->x86_vendor = X86_VENDOR_AMD;
else if (!strcmp(v, "CyrixInstead"))
c->x86_vendor = X86_VENDOR_CYRIX;
+ else if (!strcmp(v, "Geode by NSC"))
+ c->x86_vendor = X86_VENDOR_NSC;
else if (!strcmp(v, "UMC UMC UMC "))
c->x86_vendor = X86_VENDOR_UMC;
else if (!strcmp(v, "CentaurHauls"))
@@ -2528,24 +2540,6 @@ void __init identify_cpu(struct cpuinfo_x86 *c)
* indicate the features this CPU genuinely supports!
*/
switch ( c->x86_vendor ) {
- case X86_VENDOR_UNKNOWN:
- default:
- /* Not much we can do here... */
- /* Check if at least it has cpuid */
- if (c->cpuid_level == -1)
- {
- /* No cpuid. It must be an ancient CPU */
- if (c->x86 == 4)
- strcpy(c->x86_model_id, "486");
- else if (c->x86 == 3)
- strcpy(c->x86_model_id, "386");
- }
- break;
-
- case X86_VENDOR_CYRIX:
- init_cyrix(c);
- break;
-
case X86_VENDOR_AMD:
init_amd(c);
break;
@@ -2554,6 +2548,10 @@ void __init identify_cpu(struct cpuinfo_x86 *c)
init_centaur(c);
break;
+ case X86_VENDOR_CYRIX:
+ init_cyrix(c);
+ break;
+
case X86_VENDOR_INTEL:
init_intel(c);
break;
@@ -2562,13 +2560,32 @@ void __init identify_cpu(struct cpuinfo_x86 *c)
c->x86_cache_size = 256; /* A few had 1 MB... */
break;
- case X86_VENDOR_TRANSMETA:
- init_transmeta(c);
+ case X86_VENDOR_NSC:
+ init_cyrix(c);
break;
case X86_VENDOR_RISE:
init_rise(c);
break;
+
+ case X86_VENDOR_TRANSMETA:
+ init_transmeta(c);
+ break;
+
+ case X86_VENDOR_UNKNOWN:
+ default:
+ /* Not much we can do here... */
+ /* Check if at least it has cpuid */
+ if (c->cpuid_level == -1)
+ {
+ /* No cpuid. It must be an ancient CPU */
+ if (c->x86 == 4)
+ strcpy(c->x86_model_id, "486");
+ else if (c->x86 == 3)
+ strcpy(c->x86_model_id, "386");
+ }
+ break;
+
}
printk(KERN_DEBUG "CPU: After vendor init, caps: %08x %08x %08x %08x\n",
@@ -2646,14 +2663,15 @@ void __init dodgy_tsc(void)
{
get_cpu_vendor(&boot_cpu_data);
- if ( boot_cpu_data.x86_vendor == X86_VENDOR_CYRIX )
+ if (( boot_cpu_data.x86_vendor == X86_VENDOR_CYRIX ) ||
+ ( boot_cpu_data.x86_vendor == X86_VENDOR_NSC ))
init_cyrix(&boot_cpu_data);
}
/* These need to match <asm/processor.h> */
static char *cpu_vendor_names[] __initdata = {
- "Intel", "Cyrix", "AMD", "UMC", "NexGen", "Centaur", "Rise", "Transmeta" };
+ "Intel", "Cyrix", "AMD", "UMC", "NexGen", "Centaur", "Rise", "Transmeta", "NSC" };
void __init print_cpu_info(struct cpuinfo_x86 *c)
@@ -2694,10 +2712,10 @@ static int show_cpuinfo(struct seq_file *m, void *v)
*/
static char *x86_cap_flags[] = {
/* Intel-defined */
- "fpu", "vme", "de", "pse", "tsc", "msr", "pae", "mce",
- "cx8", "apic", NULL, "sep", "mtrr", "pge", "mca", "cmov",
- "pat", "pse36", "pn", "clflush", NULL, "dts", "acpi", "mmx",
- "fxsr", "sse", "sse2", "ss", "ht", "tm", "ia64", NULL,
+ "fpu", "vme", "de", "pse", "tsc", "msr", "pae", "mce",
+ "cx8", "apic", NULL, "sep", "mtrr", "pge", "mca", "cmov",
+ "pat", "pse36", "pn", "clflush", NULL, "dts", "acpi", "mmx",
+ "fxsr", "sse", "sse2", "ss", "ht", "tm", "ia64", NULL,
/* AMD-defined */
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
diff --git a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c
index a5349ba757b3a..ad8aa377c1ef9 100644
--- a/arch/i386/kernel/traps.c
+++ b/arch/i386/kernel/traps.c
@@ -25,6 +25,10 @@
#include <linux/interrupt.h>
#include <linux/highmem.h>
+#ifdef CONFIG_EISA
+#include <linux/ioport.h>
+#endif
+
#ifdef CONFIG_MCA
#include <linux/mca.h>
#include <asm/processor.h>
@@ -951,11 +955,20 @@ cobalt_init(void)
printk("Cobalt APIC enabled: ID reg %lx\n", co_apic_read(CO_APIC_ID));
}
#endif
+
+#ifdef CONFIG_EISA
+int EISA_bus;
+static struct resource eisa_id = { "EISA ID", 0xc80, 0xc83, IORESOURCE_BUSY };
+#endif
+
void __init trap_init(void)
{
#ifdef CONFIG_EISA
- if (isa_readl(0x0FFFD9) == 'E'+('I'<<8)+('S'<<16)+('A'<<24))
+ if (isa_readl(0x0FFFD9) == 'E'+('I'<<8)+('S'<<16)+('A'<<24)) {
EISA_bus = 1;
+ if (request_resource(&ioport_resource, &eisa_id) == -EBUSY)
+ printk ("EISA port was EBUSY :-(\n");
+ }
#endif
#ifdef CONFIG_X86_LOCAL_APIC
diff --git a/arch/i386/mm/ioremap.c b/arch/i386/mm/ioremap.c
index 043accaad82cd..70efe3824a21f 100644
--- a/arch/i386/mm/ioremap.c
+++ b/arch/i386/mm/ioremap.c
@@ -11,6 +11,7 @@
#include <linux/vmalloc.h>
#include <asm/io.h>
#include <asm/pgalloc.h>
+#include <asm/fixmap.h>
static inline void remap_area_pte(pte_t * pte, unsigned long address, unsigned long size,
unsigned long phys_addr, unsigned long flags)
@@ -162,7 +163,6 @@ void iounmap(void *addr)
return vfree((void *) (PAGE_MASK & (unsigned long) addr));
}
-#include <asm/fixmap.h>
void __init *bt_ioremap(unsigned long phys_addr, unsigned long size)
{
unsigned long offset, last_addr;
diff --git a/arch/ia64/kernel/ia64_ksyms.c b/arch/ia64/kernel/ia64_ksyms.c
index fb2a770c7cf42..c2964682dff86 100644
--- a/arch/ia64/kernel/ia64_ksyms.c
+++ b/arch/ia64/kernel/ia64_ksyms.c
@@ -23,7 +23,6 @@ EXPORT_SYMBOL(strncpy);
EXPORT_SYMBOL(strnlen);
EXPORT_SYMBOL(strrchr);
EXPORT_SYMBOL(strstr);
-EXPORT_SYMBOL(strtok);
EXPORT_SYMBOL(strpbrk);
#include <linux/irq.h>
diff --git a/arch/m68k/atari/config.c b/arch/m68k/atari/config.c
index b96532afc891f..54c73f182070c 100644
--- a/arch/m68k/atari/config.c
+++ b/arch/m68k/atari/config.c
@@ -205,14 +205,16 @@ void __init atari_switches_setup( const char *str, unsigned len )
char switches[len+1];
char *p;
int ovsc_shift;
+ char *args = switches;
- /* copy string to local array, strtok works destructively... */
+ /* copy string to local array, strsep works destructively... */
strncpy( switches, str, len );
switches[len] = 0;
atari_switches = 0;
/* parse the options */
- for( p = strtok( switches, "," ); p; p = strtok( NULL, "," ) ) {
+ while ((p = strsep(&args, ",")) != NULL) {
+ if (!*p) continue;
ovsc_shift = 0;
if (strncmp( p, "ov_", 3 ) == 0) {
p += 3;
diff --git a/arch/m68k/kernel/m68k_ksyms.c b/arch/m68k/kernel/m68k_ksyms.c
index 4e980deb2d971..3efad5ad086da 100644
--- a/arch/m68k/kernel/m68k_ksyms.c
+++ b/arch/m68k/kernel/m68k_ksyms.c
@@ -54,7 +54,6 @@ EXPORT_SYMBOL(dump_thread);
EXPORT_SYMBOL(strnlen);
EXPORT_SYMBOL(strrchr);
EXPORT_SYMBOL(strstr);
-EXPORT_SYMBOL(strtok);
EXPORT_SYMBOL(enable_irq);
EXPORT_SYMBOL(disable_irq);
EXPORT_SYMBOL(kernel_thread);
diff --git a/arch/m68k/mac/baboon.c b/arch/m68k/mac/baboon.c
index 9b9bab2bdcbcb..e80793a2b2017 100644
--- a/arch/m68k/mac/baboon.c
+++ b/arch/m68k/mac/baboon.c
@@ -27,7 +27,7 @@ volatile struct baboon *baboon;
void baboon_irq(int, void *, struct pt_regs *);
-extern int macide_ack_intr(ide_hwif_t *);
+extern int macide_ack_intr(struct ata_channel *);
/*
* Baboon initialization.
diff --git a/arch/mips/kernel/mips_ksyms.c b/arch/mips/kernel/mips_ksyms.c
index c232279333932..8433873ff80cc 100644
--- a/arch/mips/kernel/mips_ksyms.c
+++ b/arch/mips/kernel/mips_ksyms.c
@@ -51,7 +51,6 @@ EXPORT_SYMBOL_NOVERS(memcmp);
EXPORT_SYMBOL_NOVERS(memset);
EXPORT_SYMBOL_NOVERS(memcpy);
EXPORT_SYMBOL_NOVERS(memmove);
-EXPORT_SYMBOL(simple_strtol);
EXPORT_SYMBOL_NOVERS(strcat);
EXPORT_SYMBOL_NOVERS(strchr);
EXPORT_SYMBOL_NOVERS(strlen);
@@ -60,7 +59,7 @@ EXPORT_SYMBOL_NOVERS(strncat);
EXPORT_SYMBOL_NOVERS(strnlen);
EXPORT_SYMBOL_NOVERS(strrchr);
EXPORT_SYMBOL_NOVERS(strstr);
-EXPORT_SYMBOL_NOVERS(strtok);
+EXPORT_SYMBOL_NOVERS(strsep);
EXPORT_SYMBOL(_clear_page);
EXPORT_SYMBOL(enable_irq);
diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c
index 5a05734843a0e..b5ad2cc6015a4 100644
--- a/arch/mips/kernel/signal.c
+++ b/arch/mips/kernel/signal.c
@@ -204,7 +204,7 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext *sc)
#define restore_gp_reg(i) do { \
err |= __get_user(reg, &sc->sc_regs[i]); \
regs->regs[i] = reg; \
-} while(0);
+} while(0)
restore_gp_reg( 1); restore_gp_reg( 2); restore_gp_reg( 3);
restore_gp_reg( 4); restore_gp_reg( 5); restore_gp_reg( 6);
restore_gp_reg( 7); restore_gp_reg( 8); restore_gp_reg( 9);
diff --git a/arch/mips/kernel/smp.c b/arch/mips/kernel/smp.c
index a82e0b9b9923a..9ea43d1706006 100644
--- a/arch/mips/kernel/smp.c
+++ b/arch/mips/kernel/smp.c
@@ -156,7 +156,7 @@ void __init smp_boot_cpus(void)
sprintf(p->comm, "%s%d", "Idle", i);
init_tasks[i] = p;
p->processor = i;
- p->cpus_runnable = 1 << i; /* we schedule the first task manually *
+ p->cpus_runnable = 1 << i; /* we schedule the first task manually */
del_from_runqueue(p);
unhash_process(p);
/* Attach to the address space of init_task. */
diff --git a/arch/mips/sni/pci.c b/arch/mips/sni/pci.c
index 00a3d186d7e3c..080324211391e 100644
--- a/arch/mips/sni/pci.c
+++ b/arch/mips/sni/pci.c
@@ -25,7 +25,7 @@ do { \
((dev->bus->number & 0xff) << 0x10) | \
((dev->devfn & 0xff) << 0x08) | \
(where & 0xfc); \
-} while(0);
+} while(0)
#if 0
/* To do: Bring this uptodate ... */
diff --git a/arch/mips64/kernel/mips64_ksyms.c b/arch/mips64/kernel/mips64_ksyms.c
index 91f18e507cb16..da8d6ed1391c7 100644
--- a/arch/mips64/kernel/mips64_ksyms.c
+++ b/arch/mips64/kernel/mips64_ksyms.c
@@ -48,14 +48,13 @@ EXPORT_SYMBOL_NOVERS(memcmp);
EXPORT_SYMBOL_NOVERS(memset);
EXPORT_SYMBOL_NOVERS(memcpy);
EXPORT_SYMBOL_NOVERS(memmove);
-EXPORT_SYMBOL(simple_strtol);
EXPORT_SYMBOL_NOVERS(strcat);
EXPORT_SYMBOL_NOVERS(strchr);
EXPORT_SYMBOL_NOVERS(strlen);
EXPORT_SYMBOL_NOVERS(strncat);
EXPORT_SYMBOL_NOVERS(strnlen);
EXPORT_SYMBOL_NOVERS(strrchr);
-EXPORT_SYMBOL_NOVERS(strtok);
+EXPORT_SYMBOL_NOVERS(strsep);
EXPORT_SYMBOL_NOVERS(strpbrk);
EXPORT_SYMBOL(_clear_page);
diff --git a/arch/mips64/math-emu/cp1emu.c b/arch/mips64/math-emu/cp1emu.c
index 5acd218d218da..dac6494f84b05 100644
--- a/arch/mips64/math-emu/cp1emu.c
+++ b/arch/mips64/math-emu/cp1emu.c
@@ -29,7 +29,7 @@
* Notes:
* 1) the IEEE754 library (-le) performs the actual arithmetic;
* 2) if you know that you won't have an fpu, then you'll get much
- * better performance by compiling with -msoft-float! */
+ * better performance by compiling with -msoft-float!
*
* Nov 7, 2000
* Massive changes to integrate with Linux kernel.
diff --git a/arch/parisc/kernel/parisc_ksyms.c b/arch/parisc/kernel/parisc_ksyms.c
index 2b4dbd74ca948..111a2fb5a4672 100644
--- a/arch/parisc/kernel/parisc_ksyms.c
+++ b/arch/parisc/kernel/parisc_ksyms.c
@@ -20,7 +20,6 @@ EXPORT_SYMBOL(strlen);
EXPORT_SYMBOL(strncat);
EXPORT_SYMBOL(strncmp);
EXPORT_SYMBOL(strncpy);
-EXPORT_SYMBOL(strtok);
#include <linux/pci.h>
EXPORT_SYMBOL(hppa_dma_ops);
diff --git a/arch/ppc/4xx_io/stb_kb.c b/arch/ppc/4xx_io/stb_kb.c
index f723e28029d6d..ccb2cd83420d0 100644
--- a/arch/ppc/4xx_io/stb_kb.c
+++ b/arch/ppc/4xx_io/stb_kb.c
@@ -19,7 +19,7 @@
#include <linux/random.h>
#include <linux/poll.h>
#include <linux/miscdevice.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/kbd_kern.h>
/* the following are borrowed from pc_keyb.c, thanks to those involved! */
diff --git a/arch/ppc/iSeries/iSeries_irq.c b/arch/ppc/iSeries/iSeries_irq.c
index c0760bceb4752..1d8efc93f1603 100644
--- a/arch/ppc/iSeries/iSeries_irq.c
+++ b/arch/ppc/iSeries/iSeries_irq.c
@@ -36,7 +36,7 @@
#include <linux/irq.h>
#include <linux/spinlock.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <asm/iSeries/HvCallPci.h>
#include <asm/iSeries/HvCallXm.h>
diff --git a/arch/ppc/kernel/ppc_ksyms.c b/arch/ppc/kernel/ppc_ksyms.c
index 1f45d577df52c..f2591a7cf0e50 100644
--- a/arch/ppc/kernel/ppc_ksyms.c
+++ b/arch/ppc/kernel/ppc_ksyms.c
@@ -123,7 +123,6 @@ EXPORT_SYMBOL(strncat);
EXPORT_SYMBOL(strchr);
EXPORT_SYMBOL(strrchr);
EXPORT_SYMBOL(strpbrk);
-EXPORT_SYMBOL(strtok);
EXPORT_SYMBOL(strstr);
EXPORT_SYMBOL(strlen);
EXPORT_SYMBOL(strnlen);
diff --git a/arch/ppc/math-emu/op-4.h b/arch/ppc/math-emu/op-4.h
index 3458d78708929..5da9921eab8a4 100644
--- a/arch/ppc/math-emu/op-4.h
+++ b/arch/ppc/math-emu/op-4.h
@@ -279,7 +279,7 @@
X##_f[1] = (rsize <= _FP_W_TYPE_SIZE ? 0 : r >> _FP_W_TYPE_SIZE); \
X##_f[2] = (rsize <= 2*_FP_W_TYPE_SIZE ? 0 : r >> 2*_FP_W_TYPE_SIZE); \
X##_f[3] = (rsize <= 3*_FP_W_TYPE_SIZE ? 0 : r >> 3*_FP_W_TYPE_SIZE); \
- } while (0);
+ } while (0)
#define _FP_FRAC_CONV_4_1(dfs, sfs, D, S) \
do { \
diff --git a/arch/s390/kernel/s390_ksyms.c b/arch/s390/kernel/s390_ksyms.c
index 617db282d5502..e286bdd588b13 100644
--- a/arch/s390/kernel/s390_ksyms.c
+++ b/arch/s390/kernel/s390_ksyms.c
@@ -44,7 +44,7 @@ EXPORT_SYMBOL_NOVERS(strncpy);
EXPORT_SYMBOL_NOVERS(strnlen);
EXPORT_SYMBOL_NOVERS(strrchr);
EXPORT_SYMBOL_NOVERS(strstr);
-EXPORT_SYMBOL_NOVERS(strtok);
+EXPORT_SYMBOL_NOVERS(strsep);
EXPORT_SYMBOL_NOVERS(strpbrk);
/*
diff --git a/arch/s390x/kernel/s390_ksyms.c b/arch/s390x/kernel/s390_ksyms.c
index 5b9415126e796..edfb5f66663bd 100644
--- a/arch/s390x/kernel/s390_ksyms.c
+++ b/arch/s390x/kernel/s390_ksyms.c
@@ -47,7 +47,7 @@ EXPORT_SYMBOL_NOVERS(strncpy);
EXPORT_SYMBOL_NOVERS(strnlen);
EXPORT_SYMBOL_NOVERS(strrchr);
EXPORT_SYMBOL_NOVERS(strstr);
-EXPORT_SYMBOL_NOVERS(strtok);
+EXPORT_SYMBOL_NOVERS(strsep);
EXPORT_SYMBOL_NOVERS(strpbrk);
/*
diff --git a/arch/sh/kernel/sh_ksyms.c b/arch/sh/kernel/sh_ksyms.c
index 40c5936d82f07..6ef33a1274d7f 100644
--- a/arch/sh/kernel/sh_ksyms.c
+++ b/arch/sh/kernel/sh_ksyms.c
@@ -39,9 +39,6 @@ EXPORT_SYMBOL(no_irq_type);
/* Networking helper routines. */
EXPORT_SYMBOL(csum_partial_copy);
-EXPORT_SYMBOL(simple_strtol);
-
-EXPORT_SYMBOL(strtok);
EXPORT_SYMBOL(strpbrk);
EXPORT_SYMBOL(strstr);
EXPORT_SYMBOL(strlen);
diff --git a/arch/sparc/kernel/ioport.c b/arch/sparc/kernel/ioport.c
index 8f4c425334446..e7ff970205b50 100644
--- a/arch/sparc/kernel/ioport.c
+++ b/arch/sparc/kernel/ioport.c
@@ -161,7 +161,7 @@ void sbus_iounmap(unsigned long addr, unsigned long size)
static void *_sparc_alloc_io(unsigned int busno, unsigned long phys,
unsigned long size, char *name)
{
- static int printed_full = 0;
+ static int printed_full;
struct xresource *xres;
struct resource *res;
char *tack;
diff --git a/arch/sparc/kernel/irq.c b/arch/sparc/kernel/irq.c
index 5e3a4008de43d..0235faa1a96c5 100644
--- a/arch/sparc/kernel/irq.c
+++ b/arch/sparc/kernel/irq.c
@@ -91,7 +91,7 @@ void (*init_timers)(void (*)(int, void *,struct pt_regs *)) =
*/
#define MAX_STATIC_ALLOC 4
struct irqaction static_irqaction[MAX_STATIC_ALLOC];
-int static_irq_count = 0;
+int static_irq_count;
struct irqaction *irq_action[NR_IRQS+1] = {
NULL, NULL, NULL, NULL, NULL, NULL , NULL, NULL,
diff --git a/arch/sparc/kernel/pcic.c b/arch/sparc/kernel/pcic.c
index 53c2aaa296e41..5bc6a12f1b43f 100644
--- a/arch/sparc/kernel/pcic.c
+++ b/arch/sparc/kernel/pcic.c
@@ -185,7 +185,7 @@ static struct pcic_sn2list pcic_known_sysnames[] = {
* Only one PCIC per IIep,
* and since we have no SMP IIep, only one per system.
*/
-static int pcic0_up = 0;
+static int pcic0_up;
static struct linux_pcic pcic0;
unsigned int pcic_regs;
diff --git a/arch/sparc/kernel/process.c b/arch/sparc/kernel/process.c
index 6d96f8dac8c18..0afa247266781 100644
--- a/arch/sparc/kernel/process.c
+++ b/arch/sparc/kernel/process.c
@@ -63,9 +63,9 @@ int cpu_idle(void)
for (;;) {
if (ARCH_SUN4C_SUN4) {
static int count = HZ;
- static unsigned long last_jiffies = 0;
- static unsigned long last_faults = 0;
- static unsigned long fps = 0;
+ static unsigned long last_jiffies;
+ static unsigned long last_faults;
+ static unsigned long fps;
unsigned long now;
unsigned long faults;
unsigned long flags;
@@ -83,7 +83,7 @@ int cpu_idle(void)
fps = (fps + (faults - last_faults)) >> 1;
last_faults = faults;
#if 0
- printk("kernel faults / second = %d\n", fps);
+ printk("kernel faults / second = %ld\n", fps);
#endif
if (fps >= SUN4C_FAULT_HIGH) {
sun4c_grow_kernel_ring();
diff --git a/arch/sparc/kernel/ptrace.c b/arch/sparc/kernel/ptrace.c
index 8b85b4f9d6ece..1d30b5c857f69 100644
--- a/arch/sparc/kernel/ptrace.c
+++ b/arch/sparc/kernel/ptrace.c
@@ -278,6 +278,7 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
unsigned long data = regs->u_regs[UREG_I3];
unsigned long addr2 = regs->u_regs[UREG_I4];
struct task_struct *child;
+ int ret;
lock_kernel();
#ifdef DEBUG_PTRACE
@@ -335,20 +336,13 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
pt_succ_return(regs, 0);
goto out_tsk;
}
- if (!(child->ptrace & PT_PTRACED)) {
- pt_error_return(regs, ESRCH);
- goto out_tsk;
- }
- if(child->state != TASK_STOPPED) {
- if(request != PTRACE_KILL) {
- pt_error_return(regs, ESRCH);
- goto out_tsk;
- }
- }
- if(child->p_pptr != current) {
- pt_error_return(regs, ESRCH);
+
+ ret = ptrace_check_attach(child, request == PTRACE_KILL);
+ if (ret < 0) {
+ pt_error_return(regs, -ret);
goto out_tsk;
}
+
switch(request) {
case PTRACE_PEEKTEXT: /* read word at location addr. */
case PTRACE_PEEKDATA: {
diff --git a/arch/sparc/kernel/setup.c b/arch/sparc/kernel/setup.c
index 89fbafcdd47af..09b92306390b1 100644
--- a/arch/sparc/kernel/setup.c
+++ b/arch/sparc/kernel/setup.c
@@ -47,8 +47,6 @@
#include <asm/hardirq.h>
#include <asm/machines.h>
-#undef PROM_DEBUG_CONSOLE
-
struct screen_info screen_info = {
0, 0, /* orig-x, orig-y */
0, /* unused */
@@ -134,6 +132,19 @@ void kernel_enter_debugger(void)
}
}
+static void
+prom_console_write(struct console *con, const char *s, unsigned n)
+{
+ prom_printf("%s", s);
+}
+
+static struct console prom_debug_console = {
+ name: "debug",
+ write: prom_console_write,
+ flags: CON_PRINTBUFFER,
+ index: -1,
+};
+
int obp_system_intr(void)
{
if (boot_flags & BOOTME_KGDB) {
@@ -166,6 +177,10 @@ static void __init process_switch(char c)
prom_printf("boot_flags_init: Halt!\n");
prom_halt();
break;
+ case 'p':
+ /* Use PROM debug console. */
+ register_console(&prom_debug_console);
+ break;
default:
printk("Unknown boot switch (-%c)\n", c);
break;
@@ -280,21 +295,6 @@ struct tt_entry *sparc_ttable;
struct pt_regs fake_swapper_regs;
-#ifdef PROM_DEBUG_CONSOLE
-static void
-prom_console_write(struct console *con, const char *s, unsigned n)
-{
- prom_printf("%s", s);
-}
-
-static struct console prom_console = {
- name: "debug",
- write: prom_console_write,
- flags: CON_PRINTBUFFER,
- index: -1,
-};
-#endif
-
extern void paging_init(void);
void __init setup_arch(char **cmdline_p)
@@ -348,9 +348,6 @@ void __init setup_arch(char **cmdline_p)
printk("UNKNOWN!\n");
break;
};
-#ifdef PROM_DEBUG_CONSOLE
- register_console(&prom_console);
-#endif
#ifdef CONFIG_DUMMY_CONSOLE
conswitchp = &dummy_con;
@@ -381,7 +378,7 @@ void __init setup_arch(char **cmdline_p)
if (!root_flags)
root_mountflags &= ~MS_RDONLY;
ROOT_DEV = to_kdev_t(root_dev);
-#ifdef CONFIG_BLK_DEV_RAM
+#ifdef CONFIG_BLK_DEV_INITRD
rd_image_start = ram_flags & RAMDISK_IMAGE_START_MASK;
rd_prompt = ((ram_flags & RAMDISK_PROMPT_FLAG) != 0);
rd_doload = ((ram_flags & RAMDISK_LOAD_FLAG) != 0);
diff --git a/arch/sparc/kernel/signal.c b/arch/sparc/kernel/signal.c
index 08ad9624d9e62..022883fbbea88 100644
--- a/arch/sparc/kernel/signal.c
+++ b/arch/sparc/kernel/signal.c
@@ -1195,8 +1195,8 @@ asmlinkage int do_signal(sigset_t *oldset, struct pt_regs * regs,
info.si_signo = signr;
info.si_errno = 0;
info.si_code = SI_USER;
- info.si_pid = current->p_pptr->pid;
- info.si_uid = current->p_pptr->uid;
+ info.si_pid = current->parent->pid;
+ info.si_uid = current->parent->uid;
}
/* If the (new) signal is now blocked, requeue it. */
@@ -1245,7 +1245,7 @@ asmlinkage int do_signal(sigset_t *oldset, struct pt_regs * regs,
current->exit_code = signr;
/* notify_parent() is SMP safe */
- if(!(current->p_pptr->sig->action[SIGCHLD-1].sa.sa_flags &
+ if(!(current->parent->sig->action[SIGCHLD-1].sa.sa_flags &
SA_NOCLDSTOP))
notify_parent(current, SIGCHLD);
schedule();
@@ -1280,7 +1280,10 @@ asmlinkage int do_signal(sigset_t *oldset, struct pt_regs * regs,
#endif
/* fall through */
default:
- sig_exit(signr, exit_code, &info);
+ sigaddset(&current->pending.signal, signr);
+ recalc_sigpending(current);
+ current->flags |= PF_SIGNALED;
+ do_exit(exit_code);
/* NOT REACHED */
}
}
diff --git a/arch/sparc/kernel/sparc_ksyms.c b/arch/sparc/kernel/sparc_ksyms.c
index 25b97dda0407e..316fc9696c78b 100644
--- a/arch/sparc/kernel/sparc_ksyms.c
+++ b/arch/sparc/kernel/sparc_ksyms.c
@@ -250,7 +250,6 @@ EXPORT_SYMBOL_NOVERS(strncmp);
EXPORT_SYMBOL(strchr);
EXPORT_SYMBOL(strrchr);
EXPORT_SYMBOL(strpbrk);
-EXPORT_SYMBOL(strtok);
EXPORT_SYMBOL(strstr);
EXPORT_SYMBOL(page_kernel);
diff --git a/arch/sparc/kernel/sun4d_smp.c b/arch/sparc/kernel/sun4d_smp.c
index 46e199a637d3f..4c2dd850c8256 100644
--- a/arch/sparc/kernel/sun4d_smp.c
+++ b/arch/sparc/kernel/sun4d_smp.c
@@ -47,7 +47,7 @@ extern struct task_struct *current_set[NR_CPUS];
extern volatile int smp_processors_ready;
extern unsigned long cpu_present_map;
extern int smp_num_cpus;
-static int smp_highest_cpu = 0;
+static int smp_highest_cpu;
extern int smp_threads_ready;
extern unsigned char mid_xlate[NR_CPUS];
extern volatile unsigned long cpu_callin_map[NR_CPUS];
diff --git a/arch/sparc/kernel/time.c b/arch/sparc/kernel/time.c
index 8e40a700e7999..6e7935ab7c56b 100644
--- a/arch/sparc/kernel/time.c
+++ b/arch/sparc/kernel/time.c
@@ -115,7 +115,7 @@ __volatile__ unsigned int *master_l10_limit;
void timer_interrupt(int irq, void *dev_id, struct pt_regs * regs)
{
/* last time the cmos clock got updated */
- static long last_rtc_update=0;
+ static long last_rtc_update;
#ifndef CONFIG_SMP
if(!user_mode(regs))
diff --git a/arch/sparc/kernel/traps.c b/arch/sparc/kernel/traps.c
index 5c361f9335e4a..2bdaa11e7be58 100644
--- a/arch/sparc/kernel/traps.c
+++ b/arch/sparc/kernel/traps.c
@@ -272,7 +272,7 @@ extern int do_mathemu(struct pt_regs *, struct task_struct *);
void do_fpe_trap(struct pt_regs *regs, unsigned long pc, unsigned long npc,
unsigned long psr)
{
- static int calls = 0;
+ static int calls;
siginfo_t info;
unsigned long fsr;
int ret = 0;
diff --git a/arch/sparc/mm/iommu.c b/arch/sparc/mm/iommu.c
index cfd35dbdc4b59..927a72e765e35 100644
--- a/arch/sparc/mm/iommu.c
+++ b/arch/sparc/mm/iommu.c
@@ -25,7 +25,7 @@ extern int viking_mxcc_present;
BTFIXUPDEF_CALL(void, flush_page_for_dma, unsigned long)
#define flush_page_for_dma(page) BTFIXUP_CALL(flush_page_for_dma)(page)
extern int flush_page_for_dma_global;
-static int viking_flush = 0;
+static int viking_flush;
/* viking.S */
extern void viking_flush_page(unsigned long page);
extern void viking_mxcc_flush_page(unsigned long page);
diff --git a/arch/sparc/mm/srmmu.c b/arch/sparc/mm/srmmu.c
index 6f5fa8cdaa7a2..bd0292118fc09 100644
--- a/arch/sparc/mm/srmmu.c
+++ b/arch/sparc/mm/srmmu.c
@@ -1739,7 +1739,7 @@ static void __init init_tsunami(void)
static void __init poke_viking(void)
{
unsigned long mreg = srmmu_get_mmureg();
- static int smp_catch = 0;
+ static int smp_catch;
if(viking_mxcc_present) {
unsigned long mxcc_control = mxcc_get_creg();
@@ -1963,7 +1963,7 @@ extern unsigned long srmmu_fault;
iaddr = &(insn); \
daddr = &(dest); \
*iaddr = SPARC_BRANCH((unsigned long) daddr, (unsigned long) iaddr); \
- } while(0);
+ } while(0)
static void __init patch_window_trap_handlers(void)
{
diff --git a/arch/sparc/mm/sun4c.c b/arch/sparc/mm/sun4c.c
index f06384045afe8..65836301aede4 100644
--- a/arch/sparc/mm/sun4c.c
+++ b/arch/sparc/mm/sun4c.c
@@ -425,7 +425,7 @@ extern unsigned long vac_hwflush_patch2, vac_hwflush_patch2_on;
daddr = &(dst); \
iaddr = &(src); \
*daddr = *iaddr; \
- } while (0);
+ } while (0)
static void patch_kernel_fault_handler(void)
{
diff --git a/arch/sparc/mm/swift.S b/arch/sparc/mm/swift.S
index b1acc2b38d938..2dcaa5ac1a38d 100644
--- a/arch/sparc/mm/swift.S
+++ b/arch/sparc/mm/swift.S
@@ -53,11 +53,9 @@ swift_flush_cache_all:
.globl swift_flush_cache_mm
swift_flush_cache_mm:
-#ifndef CONFIG_SMP
ld [%o0 + AOFF_mm_context], %g2
cmp %g2, -1
be swift_flush_cache_mm_out
-#endif
WINDOW_FLUSH(%g4, %g5)
rd %psr, %g1
andn %g1, PSR_ET, %g3
@@ -121,11 +119,9 @@ swift_flush_cache_range:
swift_flush_cache_page:
ld [%o0 + 0x0], %o0 /* XXX vma->vm_mm, GROSS XXX */
70:
-#ifndef CONFIG_SMP
ld [%o0 + AOFF_mm_context], %g2
cmp %g2, -1
be swift_flush_cache_page_out
-#endif
WINDOW_FLUSH(%g4, %g5)
rd %psr, %g1
andn %g1, PSR_ET, %g3
@@ -226,11 +222,9 @@ swift_flush_sig_insns:
swift_flush_tlb_range:
ld [%o0 + 0x00], %o0 /* XXX vma->vm_mm GROSS XXX */
swift_flush_tlb_mm:
-#ifndef CONFIG_SMP
ld [%o0 + AOFF_mm_context], %g2
cmp %g2, -1
be swift_flush_tlb_all_out
-#endif
swift_flush_tlb_all:
mov 0x400, %o1
sta %g0, [%o1] ASI_M_FLUSH_PROBE
@@ -244,11 +238,9 @@ swift_flush_tlb_page:
mov SRMMU_CTX_REG, %g1
ld [%o0 + AOFF_mm_context], %o3
andn %o1, (PAGE_SIZE - 1), %o1
-#ifndef CONFIG_SMP
cmp %o3, -1
be swift_flush_tlb_page_out
nop
-#endif
#if 1
mov 0x400, %o1
sta %g0, [%o1] ASI_M_FLUSH_PROBE
diff --git a/arch/sparc/mm/tsunami.S b/arch/sparc/mm/tsunami.S
index 5d490af96f636..5cf689a12ea0b 100644
--- a/arch/sparc/mm/tsunami.S
+++ b/arch/sparc/mm/tsunami.S
@@ -27,10 +27,8 @@ tsunami_flush_cache_range:
ld [%o0 + 0x0], %o0 /* XXX vma->vm_mm, GROSS XXX */
tsunami_flush_cache_mm:
ld [%o0 + AOFF_mm_context], %g2
-#ifndef CONFIG_SMP
cmp %g2, -1
be tsunami_flush_cache_out
-#endif
tsunami_flush_cache_all:
WINDOW_FLUSH(%g4, %g5)
tsunami_flush_page_for_dma:
@@ -50,11 +48,9 @@ tsunami_flush_sig_insns:
tsunami_flush_tlb_range:
ld [%o0 + 0x00], %o0 /* XXX vma->vm_mm GROSS XXX */
tsunami_flush_tlb_mm:
-#ifndef CONFIG_SMP
ld [%o0 + AOFF_mm_context], %g2
cmp %g2, -1
be tsunami_flush_tlb_out
-#endif
tsunami_flush_tlb_all:
mov 0x400, %o1
sta %g0, [%o1] ASI_M_FLUSH_PROBE
@@ -73,10 +69,8 @@ tsunami_flush_tlb_page:
mov SRMMU_CTX_REG, %g1
ld [%o0 + AOFF_mm_context], %o3
andn %o1, (PAGE_SIZE - 1), %o1
-#ifndef CONFIG_SMP
cmp %o3, -1
be tsunami_flush_tlb_page_out
-#endif
lda [%g1] ASI_M_MMUREGS, %g5
sta %o3, [%g1] ASI_M_MMUREGS
sta %g0, [%o1] ASI_M_FLUSH_PROBE
diff --git a/arch/sparc64/defconfig b/arch/sparc64/defconfig
index 98b73d973b4a5..472ab2d1b58f4 100644
--- a/arch/sparc64/defconfig
+++ b/arch/sparc64/defconfig
@@ -248,7 +248,7 @@ CONFIG_NET_CLS_POLICE=y
CONFIG_IDE=y
#
-# IDE, ATA and ATAPI Block devices
+# ATA and ATAPI Block devices
#
CONFIG_BLK_DEV_IDE=y
@@ -283,9 +283,9 @@ CONFIG_BLK_DEV_IDECD=y
# CONFIG_BLK_DEV_ISAPNP is not set
# CONFIG_BLK_DEV_RZ1000 is not set
CONFIG_BLK_DEV_IDEPCI=y
+# CONFIG_BLK_DEV_OFFBOARD is not set
# CONFIG_IDEPCI_SHARE_IRQ is not set
CONFIG_BLK_DEV_IDEDMA_PCI=y
-# CONFIG_BLK_DEV_OFFBOARD is not set
CONFIG_IDEDMA_PCI_AUTO=y
CONFIG_IDEDMA_ONLYDISK=y
CONFIG_BLK_DEV_IDEDMA=y
@@ -296,13 +296,13 @@ CONFIG_BLK_DEV_IDEDMA=y
CONFIG_BLK_DEV_ALI15X3=y
# CONFIG_WDC_ALI15X3 is not set
# CONFIG_BLK_DEV_AMD74XX is not set
-# CONFIG_AMD74XX_OVERRIDE is not set
CONFIG_BLK_DEV_CMD64X=y
# CONFIG_BLK_DEV_CY82C693 is not set
# CONFIG_BLK_DEV_CS5530 is not set
# CONFIG_BLK_DEV_HPT34X is not set
# CONFIG_HPT34X_AUTODMA is not set
# CONFIG_BLK_DEV_HPT366 is not set
+# CONFIG_BLK_DEV_PIIX is not set
CONFIG_BLK_DEV_NS87415=y
# CONFIG_BLK_DEV_OPTI621 is not set
# CONFIG_BLK_DEV_PDC_ADMA is not set
@@ -314,10 +314,9 @@ CONFIG_BLK_DEV_NS87415=y
# CONFIG_BLK_DEV_TRM290 is not set
# CONFIG_BLK_DEV_VIA82CXXX is not set
# CONFIG_IDE_CHIPSETS is not set
-CONFIG_IDEDMA_AUTO=y
# CONFIG_IDEDMA_IVB is not set
+CONFIG_IDEDMA_AUTO=y
# CONFIG_DMA_NONPCI is not set
-CONFIG_BLK_DEV_IDE_MODES=y
# CONFIG_BLK_DEV_ATARAID is not set
# CONFIG_BLK_DEV_ATARAID_PDC is not set
# CONFIG_BLK_DEV_ATARAID_HPT is not set
@@ -789,6 +788,7 @@ CONFIG_USB_OHCI=y
# USB Device Class drivers
#
# CONFIG_USB_AUDIO is not set
+# CONFIG_USB_EMI26 is not set
CONFIG_USB_BLUETOOTH=m
CONFIG_USB_STORAGE=m
# CONFIG_USB_STORAGE_DEBUG is not set
@@ -909,6 +909,7 @@ CONFIG_MAGIC_SYSRQ=y
# CONFIG_DEBUG_SPINLOCK is not set
# CONFIG_DEBUG_BUGVERBOSE is not set
# CONFIG_DEBUG_DCFLUSH is not set
+# CONFIG_STACK_DEBUG is not set
#
# Library routines
diff --git a/arch/sparc64/kernel/binfmt_elf32.c b/arch/sparc64/kernel/binfmt_elf32.c
index 5b742bc444fce..cbe01f5b1271c 100644
--- a/arch/sparc64/kernel/binfmt_elf32.c
+++ b/arch/sparc64/kernel/binfmt_elf32.c
@@ -43,7 +43,7 @@ do { unsigned int *dest = &(__elf_regs[0]); \
dest[34] = (unsigned int) src->tnpc; \
dest[35] = src->y; \
dest[36] = dest[37] = 0; /* XXX */ \
-} while(0);
+} while(0)
typedef struct {
union {
diff --git a/arch/sparc64/kernel/ebus.c b/arch/sparc64/kernel/ebus.c
index 2ccb4030afc38..a01ecbd1fd8db 100644
--- a/arch/sparc64/kernel/ebus.c
+++ b/arch/sparc64/kernel/ebus.c
@@ -275,6 +275,25 @@ probe_interrupts:
printk("]");
}
+static struct pci_dev *find_next_ebus(struct pci_dev *start, int *is_rio_p)
+{
+ struct pci_dev *pdev = start;
+
+ do {
+ pdev = pci_find_device(PCI_VENDOR_ID_SUN, PCI_ANY_ID, pdev);
+ if (pdev &&
+ (pdev->device == PCI_DEVICE_ID_SUN_EBUS ||
+ pdev->device == PCI_DEVICE_ID_SUN_RIO_EBUS))
+ break;
+ } while (pdev != NULL);
+
+ if (pdev && (pdev->device == PCI_DEVICE_ID_SUN_RIO_EBUS))
+ *is_rio_p = 1;
+ else
+ *is_rio_p = 0;
+
+ return pdev;
+}
void __init ebus_init(void)
{
@@ -289,12 +308,7 @@ void __init ebus_init(void)
if (!pci_present())
return;
- is_rio = 0;
- pdev = pci_find_device(PCI_VENDOR_ID_SUN, PCI_DEVICE_ID_SUN_EBUS, 0);
- if (!pdev) {
- pdev = pci_find_device(PCI_VENDOR_ID_SUN, PCI_DEVICE_ID_SUN_RIO_EBUS, 0);
- is_rio = 1;
- }
+ pdev = find_next_ebus(NULL, &is_rio);
if (!pdev) {
printk("ebus: No EBus's found.\n");
return;
@@ -315,16 +329,7 @@ void __init ebus_init(void)
we'd have to tweak with the ebus_chain
in the runtime after initialization. -jj */
if (!prom_getchild (ebusnd)) {
- struct pci_dev *orig_pdev = pdev;
-
- is_rio = 0;
- pdev = pci_find_device(PCI_VENDOR_ID_SUN,
- PCI_DEVICE_ID_SUN_EBUS, orig_pdev);
- if (!pdev) {
- pdev = pci_find_device(PCI_VENDOR_ID_SUN,
- PCI_DEVICE_ID_SUN_RIO_EBUS, orig_pdev);
- is_rio = 1;
- }
+ pdev = find_next_ebus(pdev, &is_rio);
if (!pdev) {
if (ebus == ebus_chain) {
ebus_chain = NULL;
@@ -374,20 +379,9 @@ void __init ebus_init(void)
next_ebus:
printk("\n");
- {
- struct pci_dev *orig_pdev = pdev;
-
- is_rio = 0;
- pdev = pci_find_device(PCI_VENDOR_ID_SUN,
- PCI_DEVICE_ID_SUN_EBUS, orig_pdev);
- if (!pdev) {
- pdev = pci_find_device(PCI_VENDOR_ID_SUN,
- PCI_DEVICE_ID_SUN_RIO_EBUS, orig_pdev);
- is_rio = 1;
- }
- if (!pdev)
- break;
- }
+ pdev = find_next_ebus(pdev, &is_rio);
+ if (!pdev)
+ break;
cookie = pdev->sysdata;
ebusnd = cookie->prom_node;
diff --git a/arch/sparc64/kernel/head.S b/arch/sparc64/kernel/head.S
index d7962d774f045..6ada27709a5aa 100644
--- a/arch/sparc64/kernel/head.S
+++ b/arch/sparc64/kernel/head.S
@@ -565,13 +565,6 @@ setup_tba: /* i0 = is_starfire */
#define KERN_HIGHBITS ((_PAGE_VALID|_PAGE_SZ4MB)^0xfffff80000000000)
#define KERN_LOWBITS (_PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_W)
-#define VPTE_BASE_SPITFIRE 0xfffffffe00000000
-#if 1
-#define VPTE_BASE_CHEETAH VPTE_BASE_SPITFIRE
-#else
-#define VPTE_BASE_CHEETAH 0xffe0000000000000
-#endif
-
mov TSB_REG, %g1
stxa %g0, [%g1] ASI_DMMU
membar #Sync
@@ -602,8 +595,6 @@ setup_tba: /* i0 = is_starfire */
clr %g7
#undef KERN_HIGHBITS
#undef KERN_LOWBITS
-#undef VPTE_BASE_SPITFIRE
-#undef VPTE_BASE_CHEETAH
/* Setup Interrupt globals */
wrpr %o1, (PSTATE_IG|PSTATE_IE), %pstate
diff --git a/arch/sparc64/kernel/ioctl32.c b/arch/sparc64/kernel/ioctl32.c
index f979f3fbb2f5b..d6763aec029b5 100644
--- a/arch/sparc64/kernel/ioctl32.c
+++ b/arch/sparc64/kernel/ioctl32.c
@@ -1061,7 +1061,7 @@ static int fb_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg)
break;
default:
do {
- static int count = 0;
+ static int count;
if (++count <= 20)
printk("%s: Unknown fb ioctl cmd fd(%d) "
"cmd(%08x) arg(%08lx)\n",
@@ -1714,7 +1714,7 @@ static int ppp_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg)
break;
default:
do {
- static int count = 0;
+ static int count;
if (++count <= 20)
printk("ppp_ioctl: Unknown cmd fd(%d) "
"cmd(%08x) arg(%08x)\n",
@@ -1824,7 +1824,7 @@ static int mt_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg)
break;
default:
do {
- static int count = 0;
+ static int count;
if (++count <= 20)
printk("mt_ioctl: Unknown cmd fd(%d) "
"cmd(%08x) arg(%08x)\n",
@@ -1942,7 +1942,7 @@ static int cdrom_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long ar
break;
default:
do {
- static int count = 0;
+ static int count;
if (++count <= 20)
printk("cdrom_ioctl: Unknown cmd fd(%d) "
"cmd(%08x) arg(%08x)\n",
@@ -2029,7 +2029,7 @@ static int loop_status(unsigned int fd, unsigned int cmd, unsigned long arg)
}
break;
default: {
- static int count = 0;
+ static int count;
if (++count <= 20)
printk("%s: Unknown loop ioctl cmd, fd(%d) "
"cmd(%08x) arg(%08lx)\n",
@@ -4882,7 +4882,7 @@ asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
handler = (void *)(long)t->handler;
error = handler(fd, cmd, arg, filp);
} else {
- static int count = 0;
+ static int count;
if (++count <= 20)
printk("sys32_ioctl(%s:%d): Unknown cmd fd(%d) "
"cmd(%08x) arg(%08x)\n",
diff --git a/arch/sparc64/kernel/irq.c b/arch/sparc64/kernel/irq.c
index 59b4f9c2a453a..82bca8d2a8d44 100644
--- a/arch/sparc64/kernel/irq.c
+++ b/arch/sparc64/kernel/irq.c
@@ -82,7 +82,7 @@ unsigned char dma_sync_reg_table_entry = 0;
*/
#define MAX_STATIC_ALLOC 4
static struct irqaction static_irqaction[MAX_STATIC_ALLOC];
-static int static_irq_count = 0;
+static int static_irq_count;
/* This is exported so that fast IRQ handlers can get at it... -DaveM */
struct irqaction *irq_action[NR_IRQS+1] = {
diff --git a/arch/sparc64/kernel/pci.c b/arch/sparc64/kernel/pci.c
index 4507491109569..bca907b6e1861 100644
--- a/arch/sparc64/kernel/pci.c
+++ b/arch/sparc64/kernel/pci.c
@@ -234,33 +234,63 @@ int pci_claim_resource(struct pci_dev *pdev, int resource)
return request_resource(root, res);
}
+/*
+ * Given the PCI bus a device resides on, try to
+ * find an acceptable resource allocation for a
+ * specific device resource..
+ */
+static int pci_assign_bus_resource(const struct pci_bus *bus,
+ struct pci_dev *dev,
+ struct resource *res,
+ unsigned long size,
+ unsigned long min,
+ int resno)
+{
+ unsigned int type_mask;
+ int i;
+
+ type_mask = IORESOURCE_IO | IORESOURCE_MEM;
+ for (i = 0 ; i < 4; i++) {
+ struct resource *r = bus->resource[i];
+ if (!r)
+ continue;
+
+ /* type_mask must match */
+ if ((res->flags ^ r->flags) & type_mask)
+ continue;
+
+ /* Ok, try it out.. */
+ if (allocate_resource(r, res, size, min, -1, size, NULL, NULL) < 0)
+ continue;
+
+ /* PCI config space updated by caller. */
+ return 0;
+ }
+ return -EBUSY;
+}
+
int pci_assign_resource(struct pci_dev *pdev, int resource)
{
struct pcidev_cookie *pcp = pdev->sysdata;
struct pci_pbm_info *pbm = pcp->pbm;
struct resource *res = &pdev->resource[resource];
- struct resource *root;
- unsigned long min, max, size, align;
+ unsigned long min, size;
int err;
- if (res->flags & IORESOURCE_IO) {
- root = &pbm->io_space;
- min = root->start + 0x400UL;
- max = root->end;
- } else {
- root = &pbm->mem_space;
- min = root->start;
- max = min + 0x80000000UL;
- }
+ if (res->flags & IORESOURCE_IO)
+ min = pbm->io_space.start + 0x400UL;
+ else
+ min = pbm->mem_space.start;
+
+ size = res->end - res->start + 1;
- size = res->end - res->start;
- align = size + 1;
+ err = pci_assign_bus_resource(pdev->bus, pdev, res, size, min, resource);
- err = allocate_resource(root, res, size + 1, min, max, align, NULL, NULL);
if (err < 0) {
printk("PCI: Failed to allocate resource %d for %s\n",
resource, pdev->name);
} else {
+ /* Update PCI config space. */
pbm->parent->base_address_update(pdev, resource);
}
diff --git a/arch/sparc64/kernel/pci_common.c b/arch/sparc64/kernel/pci_common.c
index 5b0a721a8d04a..b7ba835da61f7 100644
--- a/arch/sparc64/kernel/pci_common.c
+++ b/arch/sparc64/kernel/pci_common.c
@@ -571,14 +571,12 @@ static int __init pci_intmap_match(struct pci_dev *pdev, unsigned int *interrupt
struct pci_pbm_info *pbm = dev_pcp->pbm;
struct linux_prom_pci_registers *pregs = dev_pcp->prom_regs;
unsigned int hi, mid, lo, irq;
- int i, num_intmap;
-
- if (pbm->num_pbm_intmap == 0)
- return 0;
+ int i, num_intmap, map_slot;
intmap = &pbm->pbm_intmap[0];
intmask = &pbm->pbm_intmask;
num_intmap = pbm->num_pbm_intmap;
+ map_slot = 0;
/* If we are underneath a PCI bridge, use PROM register
* property of the parent bridge which is closest to
@@ -639,11 +637,21 @@ static int __init pci_intmap_match(struct pci_dev *pdev, unsigned int *interrupt
printk("pci_intmap_match: Trying to recover.\n");
return 0;
}
+
+ if (pdev->bus->self != bus_dev)
+ map_slot = 1;
} else {
pregs = bus_pcp->prom_regs;
+ map_slot = 1;
}
}
+ if (map_slot) {
+ *interrupt = ((*interrupt
+ - 1
+ + PCI_SLOT(pdev->devfn)) & 0x3) + 1;
+ }
+
hi = pregs->phys_hi & intmask->phys_hi;
mid = pregs->phys_mid & intmask->phys_mid;
lo = pregs->phys_lo & intmask->phys_lo;
@@ -655,24 +663,33 @@ static int __init pci_intmap_match(struct pci_dev *pdev, unsigned int *interrupt
intmap[i].phys_lo == lo &&
intmap[i].interrupt == irq) {
*interrupt = intmap[i].cinterrupt;
+ printk("PCI-IRQ: Routing bus[%2x] slot[%2x] map[%d] to INO[%02x]\n",
+ pdev->bus->number, PCI_SLOT(pdev->devfn),
+ map_slot, *interrupt);
return 1;
}
}
- /* Print it both to OBP console and kernel one so that if bootup
- * hangs here the user has the information to report.
+ /* We will run this code even if pbm->num_pbm_intmap is zero, just so
+ * we can apply the slot mapping to the PROM interrupt property value.
+ * So do not spit out these warnings in that case.
*/
- prom_printf("pci_intmap_match: bus %02x, devfn %02x: ",
- pdev->bus->number, pdev->devfn);
- prom_printf("IRQ [%08x.%08x.%08x.%08x] not found in interrupt-map\n",
- pregs->phys_hi, pregs->phys_mid, pregs->phys_lo, *interrupt);
- prom_printf("Please email this information to davem@redhat.com\n");
-
- printk("pci_intmap_match: bus %02x, devfn %02x: ",
- pdev->bus->number, pdev->devfn);
- printk("IRQ [%08x.%08x.%08x.%08x] not found in interrupt-map\n",
- pregs->phys_hi, pregs->phys_mid, pregs->phys_lo, *interrupt);
- printk("Please email this information to davem@redhat.com\n");
+ if (num_intmap != 0) {
+ /* Print it both to OBP console and kernel one so that if bootup
+ * hangs here the user has the information to report.
+ */
+ prom_printf("pci_intmap_match: bus %02x, devfn %02x: ",
+ pdev->bus->number, pdev->devfn);
+ prom_printf("IRQ [%08x.%08x.%08x.%08x] not found in interrupt-map\n",
+ pregs->phys_hi, pregs->phys_mid, pregs->phys_lo, *interrupt);
+ prom_printf("Please email this information to davem@redhat.com\n");
+
+ printk("pci_intmap_match: bus %02x, devfn %02x: ",
+ pdev->bus->number, pdev->devfn);
+ printk("IRQ [%08x.%08x.%08x.%08x] not found in interrupt-map\n",
+ pregs->phys_hi, pregs->phys_mid, pregs->phys_lo, *interrupt);
+ printk("Please email this information to davem@redhat.com\n");
+ }
return 0;
}
@@ -720,20 +737,6 @@ static void __init pdev_fixup_irq(struct pci_dev *pdev)
goto have_irq;
}
- /* Firmware gets quad-hme interrupts property totally
- * wrong. It is 4 EBUS+HME devices behind a Digital bridge.
- * For each of the 4 instances the EBUS has interrupt property
- * '1' and the HME has interrupt property '2'. So we have to
- * fix this up.
- */
- if (!strcmp(pcp->prom_name, "SUNW,qfe") ||
- !strcmp(pcp->prom_name, "qfe")) {
- if (PCI_SLOT(pdev->devfn) & ~3)
- BUG();
-
- prom_irq = PCI_SLOT(pdev->devfn) + 1;
- }
-
/* Can we find a matching entry in the interrupt-map? */
if (pci_intmap_match(pdev, &prom_irq)) {
pdev->irq = p->irq_build(pbm, pdev, (portid << 6) | prom_irq);
diff --git a/arch/sparc64/kernel/pci_psycho.c b/arch/sparc64/kernel/pci_psycho.c
index 7276dd43e605e..3d2230a823518 100644
--- a/arch/sparc64/kernel/pci_psycho.c
+++ b/arch/sparc64/kernel/pci_psycho.c
@@ -1101,7 +1101,14 @@ static void __init psycho_base_address_update(struct pci_dev *pdev, int resource
int where, size, is_64bit;
res = &pdev->resource[resource];
- where = PCI_BASE_ADDRESS_0 + (resource * 4);
+ if (resource < 6) {
+ where = PCI_BASE_ADDRESS_0 + (resource * 4);
+ } else if (resource == PCI_ROM_RESOURCE) {
+ where = pdev->rom_base_reg;
+ } else {
+ /* Somebody might have asked allocation of a non-standard resource */
+ return;
+ }
is_64bit = 0;
if (res->flags & IORESOURCE_IO)
@@ -1117,6 +1124,10 @@ static void __init psycho_base_address_update(struct pci_dev *pdev, int resource
pci_read_config_dword(pdev, where, &reg);
reg = ((reg & size) |
(((u32)(res->start - root->start)) & ~size));
+ if (resource == PCI_ROM_RESOURCE) {
+ reg |= PCI_ROM_ADDRESS_ENABLE;
+ res->flags |= PCI_ROM_ADDRESS_ENABLE;
+ }
pci_write_config_dword(pdev, where, reg);
/* This knows that the upper 32-bits of the address
diff --git a/arch/sparc64/kernel/pci_sabre.c b/arch/sparc64/kernel/pci_sabre.c
index 59537914080cb..0de9131492b91 100644
--- a/arch/sparc64/kernel/pci_sabre.c
+++ b/arch/sparc64/kernel/pci_sabre.c
@@ -1067,7 +1067,14 @@ static void __init sabre_base_address_update(struct pci_dev *pdev, int resource)
int where, size, is_64bit;
res = &pdev->resource[resource];
- where = PCI_BASE_ADDRESS_0 + (resource * 4);
+ if (resource < 6) {
+ where = PCI_BASE_ADDRESS_0 + (resource * 4);
+ } else if (resource == PCI_ROM_RESOURCE) {
+ where = pdev->rom_base_reg;
+ } else {
+ /* Somebody might have asked allocation of a non-standard resource */
+ return;
+ }
is_64bit = 0;
if (res->flags & IORESOURCE_IO)
@@ -1083,6 +1090,10 @@ static void __init sabre_base_address_update(struct pci_dev *pdev, int resource)
pci_read_config_dword(pdev, where, &reg);
reg = ((reg & size) |
(((u32)(res->start - base)) & ~size));
+ if (resource == PCI_ROM_RESOURCE) {
+ reg |= PCI_ROM_ADDRESS_ENABLE;
+ res->flags |= PCI_ROM_ADDRESS_ENABLE;
+ }
pci_write_config_dword(pdev, where, reg);
/* This knows that the upper 32-bits of the address
@@ -1148,7 +1159,7 @@ static struct pcidev_cookie *alloc_bridge_cookie(struct pci_pbm_info *pbm)
static void __init sabre_scan_bus(struct pci_controller_info *p)
{
- static int once = 0;
+ static int once;
struct pci_bus *sabre_bus;
struct pci_pbm_info *pbm;
struct pcidev_cookie *cookie;
diff --git a/arch/sparc64/kernel/pci_schizo.c b/arch/sparc64/kernel/pci_schizo.c
index cd604a5e3f8ea..48a81bf414624 100644
--- a/arch/sparc64/kernel/pci_schizo.c
+++ b/arch/sparc64/kernel/pci_schizo.c
@@ -383,7 +383,7 @@ static unsigned int __init schizo_irq_build(struct pci_pbm_info *pbm,
struct ino_bucket *bucket;
unsigned long imap, iclr, pbm_off;
unsigned long imap_off, iclr_off;
- int pil, inofixup = 0;
+ int pil;
if (pbm == &p->pbm_A)
pbm_off = SCHIZO_PBM_A_REGS_OFF;
@@ -406,10 +406,13 @@ static unsigned int __init schizo_irq_build(struct pci_pbm_info *pbm,
iclr = p->controller_regs + pbm_off + iclr_off;
iclr += 4;
- if (ino < 0x18)
- inofixup = ino & 0x03;
-
- bucket = __bucket(build_irq(pil, inofixup, iclr, imap));
+ /* On Schizo, no inofixup occurs. This is because each
+ * INO has it's own IMAP register. On Psycho and Sabre
+ * there is only one IMAP register for each PCI slot even
+ * though four different INOs can be generated by each
+ * PCI slot.
+ */
+ bucket = __bucket(build_irq(pil, 0, iclr, imap));
bucket->flags |= IBF_PCI;
return __irq(bucket);
@@ -1423,7 +1426,14 @@ static void __init schizo_base_address_update(struct pci_dev *pdev, int resource
int where, size, is_64bit;
res = &pdev->resource[resource];
- where = PCI_BASE_ADDRESS_0 + (resource * 4);
+ if (resource < 6) {
+ where = PCI_BASE_ADDRESS_0 + (resource * 4);
+ } else if (resource == PCI_ROM_RESOURCE) {
+ where = pdev->rom_base_reg;
+ } else {
+ /* Somebody might have asked allocation of a non-standard resource */
+ return;
+ }
is_64bit = 0;
if (res->flags & IORESOURCE_IO)
@@ -1439,6 +1449,10 @@ static void __init schizo_base_address_update(struct pci_dev *pdev, int resource
pci_read_config_dword(pdev, where, &reg);
reg = ((reg & size) |
(((u32)(res->start - root->start)) & ~size));
+ if (resource == PCI_ROM_RESOURCE) {
+ reg |= PCI_ROM_ADDRESS_ENABLE;
+ res->flags |= PCI_ROM_ADDRESS_ENABLE;
+ }
pci_write_config_dword(pdev, where, reg);
/* This knows that the upper 32-bits of the address
@@ -1469,24 +1483,12 @@ static void __init schizo_resource_adjust(struct pci_dev *pdev,
#define SCHIZO_PCI_B_IO_MATCH 0x00070UL
#define SCHIZO_PCI_B_IO_MASK 0x00078UL
-/* VAL must be non-zero. */
-static unsigned long strip_to_lowest_bit_set(unsigned long val)
-{
- unsigned long tmp;
-
- tmp = 1UL;
- while (!(tmp & val))
- tmp <<= 1UL;
-
- return tmp;
-}
-
static void schizo_determine_mem_io_space(struct pci_pbm_info *pbm,
int is_pbm_a, unsigned long reg_base)
{
u64 mem_match, mem_mask;
u64 io_match;
- u64 long a, b;
+ u64 a;
if (is_pbm_a) {
mem_match = reg_base + SCHIZO_PCI_A_MEM_MATCH;
@@ -1498,11 +1500,12 @@ static void schizo_determine_mem_io_space(struct pci_pbm_info *pbm,
mem_mask = mem_match + 0x8UL;
a = schizo_read(mem_match) & ~0x8000000000000000UL;
- b = strip_to_lowest_bit_set(schizo_read(mem_mask));
- /* It should be 2GB in size. */
+ /* It should be 2GB in size but the decode is set for the full
+ * 4GB so we have to add the 2G by hand.
+ */
pbm->mem_space.start = a;
- pbm->mem_space.end = a + (b - 1UL);
+ pbm->mem_space.end = a + 0x80000000;
pbm->mem_space.flags = IORESOURCE_MEM;
/* This 32MB area is divided into two pieces. The first
diff --git a/arch/sparc64/kernel/power.c b/arch/sparc64/kernel/power.c
index 320fa2587d767..7f7d05b5b42b9 100644
--- a/arch/sparc64/kernel/power.c
+++ b/arch/sparc64/kernel/power.c
@@ -22,7 +22,7 @@ static unsigned long power_reg = 0UL;
#define POWER_COURTESY_OFF (1 << 1)
static DECLARE_WAIT_QUEUE_HEAD(powerd_wait);
-static int button_pressed = 0;
+static int button_pressed;
static void power_handler(int irq, void *dev_id, struct pt_regs *regs)
{
@@ -81,7 +81,7 @@ void __init power_init(void)
{
struct linux_ebus *ebus;
struct linux_ebus_device *edev;
- static int invoked = 0;
+ static int invoked;
if (invoked)
return;
diff --git a/arch/sparc64/kernel/ptrace.c b/arch/sparc64/kernel/ptrace.c
index 17efd37f997b0..8171a5bac6ef4 100644
--- a/arch/sparc64/kernel/ptrace.c
+++ b/arch/sparc64/kernel/ptrace.c
@@ -122,6 +122,7 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
unsigned long data = regs->u_regs[UREG_I3];
unsigned long addr2 = regs->u_regs[UREG_I4];
struct task_struct *child;
+ int ret;
if (test_thread_flag(TIF_32BIT)) {
addr &= 0xffffffffUL;
@@ -184,18 +185,10 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
pt_succ_return(regs, 0);
goto out_tsk;
}
- if (!(child->ptrace & PT_PTRACED)) {
- pt_error_return(regs, ESRCH);
- goto out_tsk;
- }
- if (child->state != TASK_STOPPED) {
- if (request != PTRACE_KILL) {
- pt_error_return(regs, ESRCH);
- goto out_tsk;
- }
- }
- if (child->p_pptr != current) {
- pt_error_return(regs, ESRCH);
+
+ ret = ptrace_check_attach(child, request == PTRACE_KILL);
+ if (ret < 0) {
+ pt_error_return(regs, -ret);
goto out_tsk;
}
diff --git a/arch/sparc64/kernel/signal.c b/arch/sparc64/kernel/signal.c
index 3500113039c88..0b8fdbcf06611 100644
--- a/arch/sparc64/kernel/signal.c
+++ b/arch/sparc64/kernel/signal.c
@@ -729,8 +729,8 @@ static int do_signal(sigset_t *oldset, struct pt_regs * regs,
info.si_signo = signr;
info.si_errno = 0;
info.si_code = SI_USER;
- info.si_pid = current->p_pptr->pid;
- info.si_uid = current->p_pptr->uid;
+ info.si_pid = current->parent->pid;
+ info.si_uid = current->parent->uid;
}
/* If the (new) signal is now blocked, requeue it. */
@@ -772,7 +772,7 @@ static int do_signal(sigset_t *oldset, struct pt_regs * regs,
struct signal_struct *sig;
current->exit_code = signr;
- sig = current->p_pptr->sig;
+ sig = current->parent->sig;
preempt_disable();
current->state = TASK_STOPPED;
if (sig && !(sig->action[SIGCHLD-1].sa.sa_flags &
diff --git a/arch/sparc64/kernel/signal32.c b/arch/sparc64/kernel/signal32.c
index e983d8fd15ea7..a1985ced682e4 100644
--- a/arch/sparc64/kernel/signal32.c
+++ b/arch/sparc64/kernel/signal32.c
@@ -1403,8 +1403,8 @@ int do_signal32(sigset_t *oldset, struct pt_regs * regs,
info.si_signo = signr;
info.si_errno = 0;
info.si_code = SI_USER;
- info.si_pid = current->p_pptr->pid;
- info.si_uid = current->p_pptr->uid;
+ info.si_pid = current->parent->pid;
+ info.si_uid = current->parent->uid;
}
/* If the (new) signal is now blocked, requeue it. */
@@ -1446,7 +1446,7 @@ int do_signal32(sigset_t *oldset, struct pt_regs * regs,
struct signal_struct *sig;
current->exit_code = signr;
- sig = current->p_pptr->sig;
+ sig = current->parent->sig;
preempt_disable();
current->state = TASK_STOPPED;
if (sig && !(sig->action[SIGCHLD-1].sa.sa_flags &
diff --git a/arch/sparc64/kernel/smp.c b/arch/sparc64/kernel/smp.c
index 24d26dbdda973..65389be5acfb5 100644
--- a/arch/sparc64/kernel/smp.c
+++ b/arch/sparc64/kernel/smp.c
@@ -46,8 +46,8 @@ volatile int __cpu_number_map[NR_CPUS] __attribute__ ((aligned (SMP_CACHE_BYTES
volatile int __cpu_logical_map[NR_CPUS] __attribute__ ((aligned (SMP_CACHE_BYTES)));
/* Please don't make this stuff initdata!!! --DaveM */
-static unsigned char boot_cpu_id = 0;
-static int smp_activated = 0;
+static unsigned char boot_cpu_id;
+static int smp_activated;
/* Kernel spinlock */
spinlock_t kernel_flag __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED;
@@ -898,7 +898,7 @@ extern unsigned long xcall_capture;
static atomic_t smp_capture_depth = ATOMIC_INIT(0);
static atomic_t smp_capture_registry = ATOMIC_INIT(0);
-static unsigned long penguins_are_doing_time = 0;
+static unsigned long penguins_are_doing_time;
void smp_capture(void)
{
diff --git a/arch/sparc64/kernel/sparc64_ksyms.c b/arch/sparc64/kernel/sparc64_ksyms.c
index 250a4e2641d8f..8c675be8e2ff3 100644
--- a/arch/sparc64/kernel/sparc64_ksyms.c
+++ b/arch/sparc64/kernel/sparc64_ksyms.c
@@ -303,7 +303,6 @@ EXPORT_SYMBOL(strcmp);
EXPORT_SYMBOL(strchr);
EXPORT_SYMBOL(strrchr);
EXPORT_SYMBOL(strpbrk);
-EXPORT_SYMBOL(strtok);
EXPORT_SYMBOL(strstr);
#ifdef CONFIG_SOLARIS_EMUL_MODULE
diff --git a/arch/sparc64/kernel/sys_sparc.c b/arch/sparc64/kernel/sys_sparc.c
index 9fb202abd34ab..0c2eef4751a1c 100644
--- a/arch/sparc64/kernel/sys_sparc.c
+++ b/arch/sparc64/kernel/sys_sparc.c
@@ -380,7 +380,7 @@ out:
asmlinkage unsigned long
c_sys_nis_syscall (struct pt_regs *regs)
{
- static int count=0;
+ static int count;
/* Don't make the system unusable, if someone goes stuck */
if (count++ > 5)
@@ -450,7 +450,7 @@ asmlinkage int sys_aplib(void)
asmlinkage int solaris_syscall(struct pt_regs *regs)
{
- static int count = 0;
+ static int count;
regs->tpc = regs->tnpc;
regs->tnpc += 4;
@@ -470,7 +470,7 @@ asmlinkage int solaris_syscall(struct pt_regs *regs)
#ifndef CONFIG_SUNOS_EMUL
asmlinkage int sunos_syscall(struct pt_regs *regs)
{
- static int count = 0;
+ static int count;
regs->tpc = regs->tnpc;
regs->tnpc += 4;
diff --git a/arch/sparc64/kernel/sys_sunos32.c b/arch/sparc64/kernel/sys_sunos32.c
index ae069fe2a5679..ab8c761076226 100644
--- a/arch/sparc64/kernel/sys_sunos32.c
+++ b/arch/sparc64/kernel/sys_sunos32.c
@@ -210,7 +210,7 @@ static char *vstrings[] = {
asmlinkage void sunos_vadvise(u32 strategy)
{
- static int count = 0;
+ static int count;
/* I wanna see who uses this... */
if (count++ < 5)
diff --git a/arch/sparc64/kernel/time.c b/arch/sparc64/kernel/time.c
index 88879f812e93a..852c96d62319c 100644
--- a/arch/sparc64/kernel/time.c
+++ b/arch/sparc64/kernel/time.c
@@ -62,7 +62,7 @@ unsigned long timer_ticks_per_usec_quotient;
static __inline__ void timer_check_rtc(void)
{
/* last time the cmos clock got updated */
- static long last_rtc_update=0;
+ static long last_rtc_update;
/* Determine when to update the Mostek clock. */
if ((time_status & STA_UNSYNC) == 0 &&
@@ -410,7 +410,7 @@ void __init clock_probe(void)
struct linux_ebus *ebus = NULL;
struct isa_bridge *isa_br = NULL;
#endif
- static int invoked = 0;
+ static int invoked;
if (invoked)
return;
diff --git a/arch/sparc64/kernel/trampoline.S b/arch/sparc64/kernel/trampoline.S
index acd6d0a67722f..5c90fbe30a61e 100644
--- a/arch/sparc64/kernel/trampoline.S
+++ b/arch/sparc64/kernel/trampoline.S
@@ -215,13 +215,6 @@ startup_continue:
#define KERN_HIGHBITS ((_PAGE_VALID|_PAGE_SZ4MB)^0xfffff80000000000)
#define KERN_LOWBITS (_PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_W)
-#define VPTE_BASE_SPITFIRE 0xfffffffe00000000
-#if 1
-#define VPTE_BASE_CHEETAH VPTE_BASE_SPITFIRE
-#else
-#define VPTE_BASE_CHEETAH 0xffe0000000000000
-#endif
-
mov TSB_REG, %g1
stxa %g0, [%g1] ASI_DMMU
membar #Sync
@@ -252,8 +245,6 @@ startup_continue:
clr %g7
#undef KERN_HIGHBITS
#undef KERN_LOWBITS
-#undef VPTE_BASE_SPITFIRE
-#undef VPTE_BASE_CHEETAH
wrpr %o1, 0x0, %pstate
ldx [%g6 + TI_TASK], %g4
diff --git a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c
index 05345073c30a7..65ebe704e8fe8 100644
--- a/arch/sparc64/mm/init.c
+++ b/arch/sparc64/mm/init.c
@@ -699,7 +699,7 @@ static void __flush_nucleus_vptes(void)
}
}
-static int prom_ditlb_set = 0;
+static int prom_ditlb_set;
struct prom_tlb_entry {
int tlb_ent;
unsigned long tlb_tag;
diff --git a/arch/sparc64/prom/bootstr.c b/arch/sparc64/prom/bootstr.c
index 064ba247272ff..d5fa8f1c65186 100644
--- a/arch/sparc64/prom/bootstr.c
+++ b/arch/sparc64/prom/bootstr.c
@@ -9,6 +9,11 @@
#include <linux/init.h>
#include <asm/oplib.h>
+/* WARNING: The boot loader knows that these next three variables come one right
+ * after another in the .data section. Do not move this stuff into
+ * the .bss section or it will break things.
+ */
+
#define BARG_LEN 256
int bootstr_len = BARG_LEN;
static int bootstr_valid = 0;
diff --git a/arch/sparc64/prom/misc.c b/arch/sparc64/prom/misc.c
index bb254f7ef321c..6f84b646005b4 100644
--- a/arch/sparc64/prom/misc.c
+++ b/arch/sparc64/prom/misc.c
@@ -171,7 +171,7 @@ int prom_get_mmu_ihandle(void)
static int prom_get_memory_ihandle(void)
{
- static int memory_ihandle_cache = 0;
+ static int memory_ihandle_cache;
int node, ret;
if (memory_ihandle_cache != 0)
diff --git a/arch/sparc64/solaris/misc.c b/arch/sparc64/solaris/misc.c
index 983146450882a..3a122801e2fbf 100644
--- a/arch/sparc64/solaris/misc.c
+++ b/arch/sparc64/solaris/misc.c
@@ -57,7 +57,7 @@ static u32 do_solaris_mmap(u32 addr, u32 len, u32 prot, u32 flags, u32 fd, u64 o
/* Do we need it here? */
set_personality(PER_SVR4);
if (flags & MAP_NORESERVE) {
- static int cnt = 0;
+ static int cnt;
if (cnt < 5) {
printk("%s: unimplemented Solaris MAP_NORESERVE mmap() flag\n",
diff --git a/arch/sparc64/solaris/timod.c b/arch/sparc64/solaris/timod.c
index 59e633f99ca73..8d3b5915dffa5 100644
--- a/arch/sparc64/solaris/timod.c
+++ b/arch/sparc64/solaris/timod.c
@@ -46,7 +46,7 @@ static char * page = NULL ;
void * mykmalloc(size_t s, int gfp)
{
static char * page;
- static size_t free = 0;
+ static size_t free;
void * r;
s = ((s + 63) & ~63);
if( s > PAGE_SIZE ) {
diff --git a/arch/x86_64/kernel/x8664_ksyms.c b/arch/x86_64/kernel/x8664_ksyms.c
index 0845e8867b4e4..a38f476c2c668 100644
--- a/arch/x86_64/kernel/x8664_ksyms.c
+++ b/arch/x86_64/kernel/x8664_ksyms.c
@@ -87,7 +87,6 @@ EXPORT_SYMBOL_NOVERS(__put_user_1);
EXPORT_SYMBOL_NOVERS(__put_user_2);
EXPORT_SYMBOL_NOVERS(__put_user_4);
-EXPORT_SYMBOL(strtok);
EXPORT_SYMBOL(strpbrk);
EXPORT_SYMBOL(strstr);
diff --git a/drivers/acpi/acpi_tables.c b/drivers/acpi/acpi_tables.c
index 490e488bc56bd..403fa5c22601f 100644
--- a/drivers/acpi/acpi_tables.c
+++ b/drivers/acpi/acpi_tables.c
@@ -32,6 +32,7 @@
#include <linux/types.h>
#include <linux/irq.h>
#include <linux/acpi.h>
+#include <linux/err.h>
#define PREFIX "ACPI: "
diff --git a/drivers/atm/eni.c b/drivers/atm/eni.c
index 638e8d0ef7ac2..9f14ddc985a6e 100644
--- a/drivers/atm/eni.c
+++ b/drivers/atm/eni.c
@@ -14,7 +14,6 @@
#include <linux/sonet.h>
#include <linux/skbuff.h>
#include <linux/time.h>
-#include <linux/sched.h> /* for xtime */
#include <linux/delay.h>
#include <linux/uio.h>
#include <linux/init.h>
diff --git a/drivers/block/DAC960.c b/drivers/block/DAC960.c
index d205bf2c4a8d3..13fb4c7c4a16e 100644
--- a/drivers/block/DAC960.c
+++ b/drivers/block/DAC960.c
@@ -5295,7 +5295,7 @@ static int DAC960_Open(Inode_T *Inode, File_T *File)
DAC960_ComputeGenericDiskInfo(Controller);
DAC960_RegisterDisk(Controller, LogicalDriveNumber);
}
- if (Controller->GenericDiskInfo.sizes[MINOR(Inode->i_rdev)] == 0)
+ if (Controller->GenericDiskInfo.sizes[minor(Inode->i_rdev)] == 0)
return -ENXIO;
/*
Increment Controller and Logical Drive Usage Counts.
@@ -6902,3 +6902,5 @@ static void DAC960_DestroyProcEntries(void)
module_init(DAC960_Initialize);
module_exit(DAC960_Finalize);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/block/blkpg.c b/drivers/block/blkpg.c
index 264d9824535ca..4992aa3cbcf98 100644
--- a/drivers/block/blkpg.c
+++ b/drivers/block/blkpg.c
@@ -247,8 +247,8 @@ int blk_ioctl(struct block_device *bdev, unsigned int cmd, unsigned long arg)
case BLKFLSBUF:
if (!capable(CAP_SYS_ADMIN))
return -EACCES;
- fsync_dev(dev);
- invalidate_buffers(dev);
+ fsync_bdev(bdev);
+ invalidate_bdev(bdev, 0);
return 0;
case BLKSSZGET:
diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c
index d87635dd23ea7..9e747ec0d6cf3 100644
--- a/drivers/block/cciss.c
+++ b/drivers/block/cciss.c
@@ -42,6 +42,7 @@
#include <linux/blk.h>
#include <linux/blkdev.h>
#include <linux/genhd.h>
+#include <linux/completion.h>
#define CCISS_DRIVER_VERSION(maj,min,submin) ((maj<<16)|(min<<8)|(submin))
#define DRIVER_NAME "Compaq CISS Driver (v 2.5.0)"
diff --git a/drivers/block/cciss_scsi.c b/drivers/block/cciss_scsi.c
index 5adb5494a6d5f..ceedd2d59575f 100644
--- a/drivers/block/cciss_scsi.c
+++ b/drivers/block/cciss_scsi.c
@@ -32,6 +32,7 @@
#include "../scsi/hosts.h"
#include <asm/atomic.h>
#include <linux/timer.h>
+#include <linux/completion.h>
#include "cciss_scsi.h"
diff --git a/drivers/block/genhd.c b/drivers/block/genhd.c
index bf0cec7f6f39f..e02323f8fd003 100644
--- a/drivers/block/genhd.c
+++ b/drivers/block/genhd.c
@@ -22,6 +22,7 @@
#include <linux/blk.h>
#include <linux/init.h>
#include <linux/spinlock.h>
+#include <linux/seq_file.h>
static rwlock_t gendisk_lock;
@@ -142,39 +143,58 @@ get_nr_sects(kdev_t dev)
}
#ifdef CONFIG_PROC_FS
-int
-get_partition_list(char *page, char **start, off_t offset, int count)
+/* iterator */
+static void *part_start(struct seq_file *part, loff_t *pos)
{
- struct gendisk *gp;
- char buf[64];
- int len, n;
+ loff_t k = *pos;
+ struct gendisk *sgp;
- len = sprintf(page, "major minor #blocks name\n\n");
read_lock(&gendisk_lock);
- for (gp = gendisk_head; gp; gp = gp->next) {
- for (n = 0; n < (gp->nr_real << gp->minor_shift); n++) {
- if (gp->part[n].nr_sects == 0)
- continue;
-
- len += snprintf(page + len, 63,
- "%4d %4d %10d %s\n",
- gp->major, n, gp->sizes[n],
- disk_name(gp, n, buf));
- if (len < offset)
- offset -= len, len = 0;
- else if (len >= offset + count)
- goto out;
- }
+ for (sgp = gendisk_head; sgp; sgp = sgp->next) {
+ if (!k--)
+ return sgp;
}
+ return NULL;
+}
-out:
+static void *part_next(struct seq_file *part, void *v, loff_t *pos)
+{
+ ++*pos;
+ return ((struct gendisk *)v)->next;
+}
+
+static void part_stop(struct seq_file *part, void *v)
+{
read_unlock(&gendisk_lock);
- *start = page + offset;
- len -= offset;
- if (len < 0)
- len = 0;
- return len > count ? count : len;
}
+
+static int show_partition(struct seq_file *part, void *v)
+{
+ struct gendisk *sgp = v;
+ int n;
+ char buf[64];
+
+ if (sgp == gendisk_head)
+ seq_puts(part, "major minor #blocks name\n\n");
+
+ /* show all non-0 size partitions of this disk */
+ for (n = 0; n < (sgp->nr_real << sgp->minor_shift); n++) {
+ if (sgp->part[n].nr_sects == 0)
+ continue;
+ seq_printf(part, "%4d %4d %10d %s\n",
+ sgp->major, n, sgp->sizes[n],
+ disk_name(sgp, n, buf));
+ }
+
+ return 0;
+}
+
+struct seq_operations partitions_op = {
+ start: part_start,
+ next: part_next,
+ stop: part_stop,
+ show: show_partition
+};
#endif
diff --git a/drivers/block/loop.c b/drivers/block/loop.c
index cfce7b234c571..cabf25eff9269 100644
--- a/drivers/block/loop.c
+++ b/drivers/block/loop.c
@@ -36,6 +36,9 @@
* Al Viro too.
* Jens Axboe <axboe@suse.de>, Nov 2000
*
+ * Support up to 256 loop devices
+ * Heinz Mauelshagen <mge@sistina.com>, Feb 2002
+ *
* Still To Fix:
* - Advisory locking is ignored here.
* - Should use an own CAP_* category instead of CAP_SYS_ADMIN
@@ -927,7 +930,7 @@ static struct block_device_operations lo_fops = {
* And now the modules code and kernel interface.
*/
MODULE_PARM(max_loop, "i");
-MODULE_PARM_DESC(max_loop, "Maximum number of loop devices (1-255)");
+MODULE_PARM_DESC(max_loop, "Maximum number of loop devices (1-256)");
MODULE_LICENSE("GPL");
int loop_register_transfer(struct loop_func_table *funcs)
@@ -963,9 +966,9 @@ int __init loop_init(void)
{
int i;
- if ((max_loop < 1) || (max_loop > 255)) {
+ if ((max_loop < 1) || (max_loop > 256)) {
printk(KERN_WARNING "loop: invalid max_loop (must be between"
- " 1 and 255), using default (8)\n");
+ " 1 and 256), using default (8)\n");
max_loop = 8;
}
diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c
index b13f0a88baafa..ff6805fc8a024 100644
--- a/drivers/block/nbd.c
+++ b/drivers/block/nbd.c
@@ -327,7 +327,7 @@ static void do_nbd_request(request_queue_t * q)
req = CURRENT;
#ifdef PARANOIA
if (!req)
- FAIL("que not empty but no request?");
+ FAIL("queue not empty but no request?");
#endif
dev = minor(req->rq_dev);
#ifdef PARANOIA
diff --git a/drivers/block/rd.c b/drivers/block/rd.c
index f9cf01e794122..543ead8532711 100644
--- a/drivers/block/rd.c
+++ b/drivers/block/rd.c
@@ -405,9 +405,10 @@ static void __exit rd_cleanup (void)
for (i = 0 ; i < NUM_RAMDISKS; i++) {
struct block_device *bdev = rd_bdev[i];
rd_bdev[i] = NULL;
- if (bdev)
+ if (bdev) {
+ invalidate_bdev(bdev, 1);
blkdev_put(bdev, BDEV_FILE);
- destroy_buffers(mk_kdev(MAJOR_NR, i));
+ }
}
devfs_unregister (devfs_handle);
diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c
index 14107f29c363e..fc2fa884e1ed0 100644
--- a/drivers/cdrom/cdrom.c
+++ b/drivers/cdrom/cdrom.c
@@ -1107,6 +1107,7 @@ static int dvd_do_auth(struct cdrom_device_info *cdi, dvd_authinfo *ai)
/* Misc */
case DVD_INVALIDATE_AGID:
+ cgc.quiet = 1;
cdinfo(CD_DVD, "entering DVD_INVALIDATE_AGID\n");
setup_report_key(&cgc, ai->lsa.agid, 0x3f);
if ((ret = cdo->generic_packet(cdi, &cgc)))
diff --git a/drivers/char/acquirewdt.c b/drivers/char/acquirewdt.c
index 37a3420c9285a..a7ea69594e03f 100644
--- a/drivers/char/acquirewdt.c
+++ b/drivers/char/acquirewdt.c
@@ -17,6 +17,9 @@
*
* (c) Copyright 1995 Alan Cox <alan@redhat.com>
*
+ * 14-Dec-2001 Matt Domsch <Matt_Domsch@dell.com>
+ * Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT
+ * Can't add timeout - driver doesn't allow changing value
*/
#include <linux/config.h>
@@ -50,8 +53,14 @@ static spinlock_t acq_lock;
#define WDT_STOP 0x43
#define WDT_START 0x443
-#define WD_TIMO (100*60) /* 1 minute */
+#ifdef CONFIG_WATCHDOG_NOWAYOUT
+static int nowayout = 1;
+#else
+static int nowayout = 0;
+#endif
+MODULE_PARM(nowayout,"i");
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
/*
* Kernel methods.
@@ -126,10 +135,13 @@ static int acq_open(struct inode *inode, struct file *file)
spin_unlock(&acq_lock);
return -EBUSY;
}
+ if (nowayout) {
+ MOD_INC_USE_COUNT;
+ }
/*
* Activate
*/
-
+
acq_is_open=1;
inb_p(WDT_START);
spin_unlock(&acq_lock);
@@ -144,9 +156,9 @@ static int acq_close(struct inode *inode, struct file *file)
if(minor(inode->i_rdev)==WATCHDOG_MINOR)
{
spin_lock(&acq_lock);
-#ifndef CONFIG_WATCHDOG_NOWAYOUT
- inb_p(WDT_STOP);
-#endif
+ if (!nowayout) {
+ inb_p(WDT_STOP);
+ }
acq_is_open=0;
spin_unlock(&acq_lock);
}
diff --git a/drivers/char/advantechwdt.c b/drivers/char/advantechwdt.c
index b40df81ce0bad..3e6940fb12d87 100644
--- a/drivers/char/advantechwdt.c
+++ b/drivers/char/advantechwdt.c
@@ -20,6 +20,9 @@
*
* (c) Copyright 1995 Alan Cox <alan@redhat.com>
*
+ * 14-Dec-2001 Matt Domsch <Matt_Domsch@dell.com>
+ * Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT
+ * Added timeout module option to override default
*/
#include <linux/config.h>
@@ -56,8 +59,7 @@ static spinlock_t advwdt_lock;
* the manual says WDT_STOP is 0x43, not 0x443).
* (0x43 is also a write-only control register for the 8254 timer!)
*
- * TODO: module parameters to set the I/O port addresses and NOWAYOUT
- * option at load time.
+ * TODO: module parameters to set the I/O port addresses
*/
#define WDT_STOP 0x443
@@ -65,6 +67,19 @@ static spinlock_t advwdt_lock;
#define WD_TIMO 60 /* 1 minute */
+static int timeout = WD_TIMO; /* in seconds */
+MODULE_PARM(timeout,"i");
+MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds (default=60)");
+
+#ifdef CONFIG_WATCHDOG_NOWAYOUT
+static int nowayout = 1;
+#else
+static int nowayout = 0;
+#endif
+
+MODULE_PARM(nowayout,"i");
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+
/*
* Kernel methods.
*/
@@ -73,7 +88,7 @@ static void
advwdt_ping(void)
{
/* Write a watchdog value */
- outb_p(WD_TIMO, WDT_START);
+ outb_p(timeout, WDT_START);
}
static ssize_t
@@ -135,6 +150,9 @@ advwdt_open(struct inode *inode, struct file *file)
spin_unlock(&advwdt_lock);
return -EBUSY;
}
+ if (nowayout) {
+ MOD_INC_USE_COUNT;
+ }
/*
* Activate
*/
@@ -153,9 +171,9 @@ advwdt_close(struct inode *inode, struct file *file)
{
if (minor(inode->i_rdev) == WATCHDOG_MINOR) {
spin_lock(&advwdt_lock);
-#ifndef CONFIG_WATCHDOG_NOWAYOUT
- inb_p(WDT_STOP);
-#endif
+ if (!nowayout) {
+ inb_p(WDT_STOP);
+ }
advwdt_is_open = 0;
spin_unlock(&advwdt_lock);
}
@@ -207,11 +225,21 @@ static struct notifier_block advwdt_notifier = {
0
};
+static void __init
+advwdt_validate_timeout(void)
+{
+ if (timeout < 1 || timeout > 63) {
+ timeout = WD_TIMO;
+ printk(KERN_INFO "advantechwdt: timeout value must be 1 <= x <= 63, using %d\n", timeout);
+ }
+}
+
static int __init
advwdt_init(void)
{
printk("WDT driver for Advantech single board computer initialising.\n");
+ advwdt_validate_timeout();
spin_lock_init(&advwdt_lock);
misc_register(&advwdt_miscdev);
#if WDT_START != WDT_STOP
diff --git a/drivers/char/agp/agpgart_be.c b/drivers/char/agp/agpgart_be.c
index fdd404f50e0fd..de7f2eda96ac5 100644
--- a/drivers/char/agp/agpgart_be.c
+++ b/drivers/char/agp/agpgart_be.c
@@ -397,7 +397,7 @@ int agp_unbind_memory(agp_memory * curr)
static void agp_generic_agp_enable(u32 mode)
{
struct pci_dev *device = NULL;
- u32 command, scratch, cap_id;
+ u32 command, scratch;
u8 cap_ptr;
pci_read_config_dword(agp_bridge.dev,
@@ -410,34 +410,8 @@ static void agp_generic_agp_enable(u32 mode)
*/
- pci_for_each_dev(device)
- {
- /*
- * Enable AGP devices. Most will be VGA display but
- * some may be coprocessors on non VGA devices too
- */
-
- if((((device->class >> 16) & 0xFF) != PCI_BASE_CLASS_DISPLAY) &&
- (device->class != (PCI_CLASS_PROCESSOR_CO << 8)))
- continue;
-
- pci_read_config_dword(device, 0x04, &scratch);
-
- if (!(scratch & 0x00100000))
- continue;
-
- pci_read_config_byte(device, 0x34, &cap_ptr);
-
- if (cap_ptr != 0x00) {
- do {
- pci_read_config_dword(device,
- cap_ptr, &cap_id);
-
- if ((cap_id & 0xff) != 0x02)
- cap_ptr = (cap_id >> 8) & 0xff;
- }
- while (((cap_id & 0xff) != 0x02) && (cap_ptr != 0x00));
- }
+ pci_for_each_dev(device) {
+ cap_ptr = pci_find_capability(device, PCI_CAP_ID_AGP);
if (cap_ptr != 0x00) {
/*
* Ok, here we have a AGP device. Disable impossible
@@ -506,25 +480,8 @@ static void agp_generic_agp_enable(u32 mode)
* command registers.
*/
- while ((device = pci_find_class(PCI_CLASS_DISPLAY_VGA << 8,
- device)) != NULL) {
- pci_read_config_dword(device, 0x04, &scratch);
-
- if (!(scratch & 0x00100000))
- continue;
-
- pci_read_config_byte(device, 0x34, &cap_ptr);
-
- if (cap_ptr != 0x00) {
- do {
- pci_read_config_dword(device,
- cap_ptr, &cap_id);
-
- if ((cap_id & 0xff) != 0x02)
- cap_ptr = (cap_id >> 8) & 0xff;
- }
- while (((cap_id & 0xff) != 0x02) && (cap_ptr != 0x00));
- }
+ pci_for_each_dev(device) {
+ cap_ptr = pci_find_capability(device, PCI_CAP_ID_AGP);
if (cap_ptr != 0x00)
pci_write_config_dword(device, cap_ptr + 8, command);
}
@@ -809,9 +766,9 @@ static unsigned long agp_generic_alloc_page(void)
struct page * page;
page = alloc_page(GFP_KERNEL);
- if (page == NULL) {
+ if (page == NULL)
return 0;
- }
+
get_page(page);
LockPage(page);
atomic_inc(&agp_bridge.current_memory_agp);
@@ -823,10 +780,9 @@ static void agp_generic_destroy_page(unsigned long addr)
void *pt = (void *) addr;
struct page *page;
- if (pt == NULL) {
+ if (pt == NULL)
return;
- }
-
+
page = virt_to_page(pt);
put_page(page);
UnlockPage(page);
@@ -3318,24 +3274,8 @@ static void serverworks_agp_enable(u32 mode)
*/
- pci_for_each_dev(device)
- {
- /*
- * Enable AGP devices. Most will be VGA display but
- * some may be coprocessors on non VGA devices too
- */
-
- if((((device->class >> 16) & 0xFF) != PCI_BASE_CLASS_DISPLAY) &&
- (device->class != (PCI_CLASS_PROCESSOR_CO << 8)))
- continue;
-
- pci_read_config_dword(device, 0x04, &scratch);
-
- if (!(scratch & 0x00100000))
- continue;
-
- pci_read_config_byte(device, 0x34, &cap_ptr);
-
+ pci_for_each_dev(device) {
+ cap_ptr = pci_find_capability(device, PCI_CAP_ID_AGP);
if (cap_ptr != 0x00) {
do {
pci_read_config_dword(device,
@@ -3413,25 +3353,8 @@ static void serverworks_agp_enable(u32 mode)
* command registers.
*/
- while ((device = pci_find_class(PCI_CLASS_DISPLAY_VGA << 8,
- device)) != NULL) {
- pci_read_config_dword(device, 0x04, &scratch);
-
- if (!(scratch & 0x00100000))
- continue;
-
- pci_read_config_byte(device, 0x34, &cap_ptr);
-
- if (cap_ptr != 0x00) {
- do {
- pci_read_config_dword(device,
- cap_ptr, &cap_id);
-
- if ((cap_id & 0xff) != 0x02)
- cap_ptr = (cap_id >> 8) & 0xff;
- }
- while (((cap_id & 0xff) != 0x02) && (cap_ptr != 0x00));
- }
+ pci_for_each_dev(device) {
+ cap_ptr = pci_find_capability(device, PCI_CAP_ID_AGP);
if (cap_ptr != 0x00)
pci_write_config_dword(device, cap_ptr + 8, command);
}
@@ -3881,7 +3804,6 @@ static int __init agp_find_supported_device(void)
{
struct pci_dev *dev = NULL;
u8 cap_ptr = 0x00;
- u32 cap_id, scratch;
if ((dev = pci_find_class(PCI_CLASS_BRIDGE_HOST << 8, NULL)) == NULL)
return -ENODEV;
@@ -4022,20 +3944,7 @@ static int __init agp_find_supported_device(void)
#endif /* CONFIG_AGP_SWORKS */
/* find capndx */
- pci_read_config_dword(dev, 0x04, &scratch);
- if (!(scratch & 0x00100000))
- return -ENODEV;
-
- pci_read_config_byte(dev, 0x34, &cap_ptr);
- if (cap_ptr != 0x00) {
- do {
- pci_read_config_dword(dev, cap_ptr, &cap_id);
-
- if ((cap_id & 0xff) != 0x02)
- cap_ptr = (cap_id >> 8) & 0xff;
- }
- while (((cap_id & 0xff) != 0x02) && (cap_ptr != 0x00));
- }
+ cap_ptr = pci_find_capability(dev, PCI_CAP_ID_AGP);
if (cap_ptr == 0x00)
return -ENODEV;
agp_bridge.capndx = cap_ptr;
diff --git a/drivers/char/applicom.c b/drivers/char/applicom.c
index fe21688ca37fd..9db606a2a9c98 100644
--- a/drivers/char/applicom.c
+++ b/drivers/char/applicom.c
@@ -36,7 +36,7 @@
#if LINUX_VERSION_CODE < 0x20300
/* These probably want adding to <linux/compatmac.h> */
-#define init_waitqueue_head(x) do { *(x) = NULL; } while (0);
+#define init_waitqueue_head(x) do { *(x) = NULL; } while (0)
#define PCI_BASE_ADDRESS(dev) (dev->base_address[0])
#define DECLARE_WAIT_QUEUE_HEAD(x) struct wait_queue *x
#define __setup(x,y) /* */
diff --git a/drivers/char/cyclades.c b/drivers/char/cyclades.c
index 47f973633f605..0d7a56ad5ff62 100644
--- a/drivers/char/cyclades.c
+++ b/drivers/char/cyclades.c
@@ -4965,6 +4965,8 @@ cy_detect_pci(void)
uclong Ze_addr0[NR_CARDS], Ze_addr2[NR_CARDS], ZeIndex = 0;
uclong Ze_phys0[NR_CARDS], Ze_phys2[NR_CARDS];
unsigned char Ze_irq[NR_CARDS];
+ struct resource *resource;
+ unsigned long res_start, res_len;
for (i = 0; i < NR_CARDS; i++) {
/* look for a Cyclades card by vendor and device id */
@@ -5012,7 +5014,15 @@ cy_detect_pci(void)
/* Although we don't use this I/O region, we should
request it from the kernel anyway, to avoid problems
with other drivers accessing it. */
- request_region(cy_pci_phys1, CyPCI_Yctl, "Cyclom-Y");
+ resource = request_region(cy_pci_phys1,
+ CyPCI_Yctl, "Cyclom-Y");
+ if (resource == NULL) {
+ printk(KERN_ERR "cyclades: failed to allocate IO "
+ "resource at 0x%lx\n", cy_pci_phys1);
+ continue;
+ }
+ res_start = cy_pci_phys1;
+ res_len = CyPCI_Yctl;
#if defined(__alpha__)
if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo) { /* below 1M? */
@@ -5083,7 +5093,11 @@ cy_detect_pci(void)
cy_card[j].bus_index = 1;
cy_card[j].first_line = cy_next_channel;
cy_card[j].num_chips = cy_pci_nchan/4;
-
+ cy_card[j].resource = resource;
+ cy_card[j].res_start = res_start;
+ cy_card[j].res_len = res_len;
+ resource = NULL; /* For next card */
+
/* enable interrupts in the PCI interface */
plx_ver = cy_readb(cy_pci_addr2 + CyPLX_VER) & 0x0f;
switch (plx_ver) {
@@ -5162,8 +5176,16 @@ cy_detect_pci(void)
/* Although we don't use this I/O region, we should
request it from the kernel anyway, to avoid problems
with other drivers accessing it. */
- request_region(cy_pci_phys1, CyPCI_Zctl, "Cyclades-Z");
-
+ resource = request_region(cy_pci_phys1,
+ CyPCI_Zctl, "Cyclades-Z");
+ if (resource == NULL) {
+ printk(KERN_ERR "cyclades: failed ot allocate IO resource "
+ "at 0x%lx\n", cy_pci_phys1);
+ continue;
+ }
+ res_start = cy_pci_phys1;
+ res_len = CyPCI_Zctl;
+
if (mailbox == ZE_V1) {
cy_pci_addr2 = (ulong)ioremap(cy_pci_phys2, CyPCI_Ze_win);
if (ZeIndex == NR_CARDS) {
@@ -5261,6 +5283,10 @@ cy_detect_pci(void)
cy_card[j].bus_index = 1;
cy_card[j].first_line = cy_next_channel;
cy_card[j].num_chips = -1;
+ cy_card[j].resource = resource;
+ cy_card[j].res_start = res_start;
+ cy_card[j].res_len = res_len;
+ resource = NULL; /* For next card */
/* print message */
#ifdef CONFIG_CYZ_INTR
@@ -5279,7 +5305,7 @@ cy_detect_pci(void)
printk("%d channels starting from port %d.\n",
cy_pci_nchan,cy_next_channel);
cy_next_channel += cy_pci_nchan;
- }
+ }
}
for (; ZeIndex != 0 && i < NR_CARDS; i++) {
@@ -5787,6 +5813,8 @@ cy_cleanup_module(void)
#endif /* CONFIG_CYZ_INTR */
)
free_irq(cy_card[i].irq, &cy_card[i]);
+ if (cy_card[i].resource)
+ release_region(cy_card[i].res_start, cy_card[i].res_len);
}
}
if (tmp_buf) {
diff --git a/drivers/char/drm/i810_dma.c b/drivers/char/drm/i810_dma.c
index 8629e0e5fa093..86a97333cb7fa 100644
--- a/drivers/char/drm/i810_dma.c
+++ b/drivers/char/drm/i810_dma.c
@@ -73,7 +73,7 @@
*(volatile unsigned int *)(virt + outring) = n; \
outring += 4; \
outring &= ringmask; \
-} while (0);
+} while (0)
static inline void i810_print_status_page(drm_device_t *dev)
{
diff --git a/drivers/char/esp.c b/drivers/char/esp.c
index 97f842cb21ab2..c6a9c355eb4cb 100644
--- a/drivers/char/esp.c
+++ b/drivers/char/esp.c
@@ -2161,7 +2161,7 @@ static void rs_wait_until_sent(struct tty_struct *tty, int timeout)
if (signal_pending(current))
break;
- if (timeout && ((orig_jiffies + timeout) < jiffies))
+ if (timeout && time_after(jiffies, orig_jiffies + timeout))
break;
serial_out(info, UART_ESI_CMD1, ESI_NO_COMMAND);
diff --git a/drivers/char/eurotechwdt.c b/drivers/char/eurotechwdt.c
index 2907315b6155c..698a2e3eca2fb 100644
--- a/drivers/char/eurotechwdt.c
+++ b/drivers/char/eurotechwdt.c
@@ -20,6 +20,10 @@
* "AS-IS" and at no charge.
*
* (c) Copyright 1995 Alan Cox <alan@lxorguk.ukuu.org.uk>*
+ *
+ * 14-Dec-2001 Matt Domsch <Matt_Domsch@dell.com>
+ * Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT
+ * Added timeout module option to override default
*/
#include <linux/config.h>
@@ -45,7 +49,6 @@
#include <linux/smp_lock.h>
static int eurwdt_is_open;
-static int eurwdt_timeout;
static spinlock_t eurwdt_lock;
/*
@@ -58,6 +61,18 @@ static int irq = 10;
static char *ev = "int";
#define WDT_TIMEOUT 60 /* 1 minute */
+static int timeout = WDT_TIMEOUT;
+
+MODULE_PARM(timeout,"i");
+MODULE_PARM_DESC(timeout, "Eurotech WDT timeout in seconds (default=60)");
+
+#ifdef CONFIG_WATCHDOG_NOWAYOUT
+static int nowayout = 1;
+#else
+static int nowayout = 0;
+#endif
+MODULE_PARM(nowayout,"i");
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
/*
@@ -116,6 +131,15 @@ MODULE_PARM_DESC(ev, "Eurotech WDT event type (default is `reboot')");
* Programming support
*/
+static void __init eurwdt_validate_timeout(void)
+{
+ if (timeout < 0 || timeout > 255) {
+ timeout = WDT_TIMEOUT;
+ printk(KERN_INFO "eurwdt: timeout must be 0 < x < 255, using %d\n",
+ timeout);
+ }
+}
+
static inline void eurwdt_write_reg(u8 index, u8 data)
{
outb(index, io);
@@ -189,7 +213,7 @@ void eurwdt_interrupt(int irq, void *dev_id, struct pt_regs *regs)
static void eurwdt_ping(void)
{
/* Write the watchdog default value */
- eurwdt_set_timeout(eurwdt_timeout);
+ eurwdt_set_timeout(timeout);
}
/**
@@ -263,7 +287,7 @@ static int eurwdt_ioctl(struct inode *inode, struct file *file,
if (time < 0 || time > 255)
return -EINVAL;
- eurwdt_timeout = time;
+ timeout = time;
eurwdt_set_timeout(time);
return 0;
}
@@ -287,9 +311,11 @@ static int eurwdt_open(struct inode *inode, struct file *file)
spin_unlock(&eurwdt_lock);
return -EBUSY;
}
+ if (nowayout) {
+ MOD_INC_USE_COUNT;
+ }
eurwdt_is_open = 1;
- eurwdt_timeout = WDT_TIMEOUT; /* initial timeout */
/* Activate the WDT */
eurwdt_activate_timer();
@@ -323,12 +349,12 @@ static int eurwdt_open(struct inode *inode, struct file *file)
static int eurwdt_release(struct inode *inode, struct file *file)
{
if (minor(inode->i_rdev) == WATCHDOG_MINOR) {
-#ifndef CONFIG_WATCHDOG_NOWAYOUT
- eurwdt_disable_timer();
-#endif
- eurwdt_is_open = 0;
+ if (!nowayout) {
+ eurwdt_disable_timer();
+ }
+ eurwdt_is_open = 0;
- MOD_DEC_USE_COUNT;
+ MOD_DEC_USE_COUNT;
}
return 0;
@@ -422,7 +448,8 @@ static void __exit eurwdt_exit(void)
static int __init eurwdt_init(void)
{
int ret;
-
+
+ eurwdt_validate_timeout();
ret = misc_register(&eurwdt_miscdev);
if (ret) {
printk(KERN_ERR "eurwdt: can't misc_register on minor=%d\n",
diff --git a/drivers/char/i810-tco.c b/drivers/char/i810-tco.c
index 90c8e4878f5be..5b20720551c21 100644
--- a/drivers/char/i810-tco.c
+++ b/drivers/char/i810-tco.c
@@ -1,5 +1,5 @@
/*
- * i810-tco 0.02: TCO timer driver for i810 chipsets
+ * i810-tco 0.03: TCO timer driver for i810 chipsets
*
* (c) Copyright 2000 kernel concepts <nils@kernelconcepts.de>, All Rights Reserved.
* http://www.kernelconcepts.de
@@ -28,6 +28,9 @@
* Initial Version 0.01
* 20000728 Nils Faerber
* 0.02 Fix for SMI_EN->TCO_EN bit, some cleanups
+ * 20011214 Matt Domsch <Matt_Domsch@dell.com>
+ * 0.03 Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT
+ * Didn't add timeout option as i810_margin already exists.
*/
#include <linux/module.h>
@@ -60,6 +63,18 @@ static spinlock_t tco_lock; /* Guards the hardware */
static int i810_margin = TIMER_MARGIN; /* steps of 0.6sec */
MODULE_PARM (i810_margin, "i");
+MODULE_PARM_DESC(i810_margin, "Watchdog timeout in steps of 0.6sec, 2<n<64. Default = 50 (30 seconds)");
+
+
+#ifdef CONFIG_WATCHDOG_NOWAYOUT
+static int nowayout = 1;
+#else
+static int nowayout = 0;
+#endif
+
+MODULE_PARM(nowayout,"i");
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+
/*
* Timer active flag
@@ -167,6 +182,9 @@ static int i810tco_open (struct inode *inode, struct file *file)
if (timer_alive)
return -EBUSY;
+ if (nowayout) {
+ MOD_INC_USE_COUNT;
+ }
/*
* Reload and activate timer
*/
@@ -181,10 +199,10 @@ static int i810tco_release (struct inode *inode, struct file *file)
/*
* Shut off the timer.
*/
-#ifdef CONFIG_WATCHDOG_NOWAYOUT
- tco_timer_stop ();
- timer_alive = 0;
-#endif
+ if (nowayout) {
+ tco_timer_stop ();
+ timer_alive = 0;
+ }
return 0;
}
@@ -342,8 +360,8 @@ static int __init watchdog_init (void)
tco_timer_reload ();
printk (KERN_INFO
- "i810 TCO timer: V0.02, timer margin: %d sec (0x%04x)\n",
- (int) (i810_margin * 6 / 10), TCOBASE);
+ "i810 TCO timer: V0.03, timer margin: %d sec (0x%04x), nowayout: %d\n",
+ (int) (i810_margin * 6 / 10), TCOBASE, nowayout);
return 0;
}
diff --git a/drivers/char/ib700wdt.c b/drivers/char/ib700wdt.c
index 91fb96ca5eb87..8f7c1671d4a7a 100644
--- a/drivers/char/ib700wdt.c
+++ b/drivers/char/ib700wdt.c
@@ -25,6 +25,10 @@
*
* (c) Copyright 1995 Alan Cox <alan@redhat.com>
*
+ * 14-Dec-2001 Matt Domsch <Matt_Domsch@dell.com>
+ * Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT
+ * Added timeout module option to override default
+ *
*/
#include <linux/config.h>
@@ -92,15 +96,36 @@ static spinlock_t ibwdt_lock;
#define WD_TIMO 0 /* 30 seconds +/- 20%, from table */
+static int timeout_val = WD_TIMO; /* value in table */
+static int timeout = 30; /* in seconds */
+MODULE_PARM(timeout,"i");
+MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds, 0 < n < 30, must be even (default=30)");
+
+#ifdef CONFIG_WATCHDOG_NOWAYOUT
+static int nowayout = 1;
+#else
+static int nowayout = 0;
+#endif
+
+MODULE_PARM(nowayout,"i");
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+
/*
* Kernel methods.
*/
+static void __init
+ibwdt_validate_timeout(void)
+{
+ timeout_val = (30 - timeout) / 2;
+ if (timeout_val < 0 || timeout_val > 0xF) timeout_val = WD_TIMO;
+}
+
static void
ibwdt_ping(void)
{
/* Write a watchdog value */
- outb_p(WD_TIMO, WDT_START);
+ outb_p(timeout_val, WDT_START);
}
static ssize_t
@@ -162,6 +187,9 @@ ibwdt_open(struct inode *inode, struct file *file)
spin_unlock(&ibwdt_lock);
return -EBUSY;
}
+ if (nowayout) {
+ MOD_INC_USE_COUNT;
+ }
/*
* Activate
*/
@@ -181,9 +209,9 @@ ibwdt_close(struct inode *inode, struct file *file)
lock_kernel();
if (minor(inode->i_rdev) == WATCHDOG_MINOR) {
spin_lock(&ibwdt_lock);
-#ifndef CONFIG_WATCHDOG_NOWAYOUT
- outb_p(WD_TIMO, WDT_STOP);
-#endif
+ if (!nowayout) {
+ outb_p(timeout_val, WDT_STOP);
+ }
ibwdt_is_open = 0;
spin_unlock(&ibwdt_lock);
}
@@ -201,7 +229,7 @@ ibwdt_notify_sys(struct notifier_block *this, unsigned long code,
{
if (code == SYS_DOWN || code == SYS_HALT) {
/* Turn the WDT off */
- outb_p(WD_TIMO, WDT_STOP);
+ outb_p(timeout_val, WDT_STOP);
}
return NOTIFY_DONE;
}
@@ -241,6 +269,7 @@ ibwdt_init(void)
{
printk("WDT driver for IB700 single board computer initialising.\n");
+ ibwdt_validate_timeout();
spin_lock_init(&ibwdt_lock);
misc_register(&ibwdt_miscdev);
#if WDT_START != WDT_STOP
diff --git a/drivers/char/ip2/i2lib.c b/drivers/char/ip2/i2lib.c
index 9572ee2076a95..4955f59d2edab 100644
--- a/drivers/char/ip2/i2lib.c
+++ b/drivers/char/ip2/i2lib.c
@@ -1330,7 +1330,7 @@ i2DrainOutput(i2ChanStrPtr pCh, int timeout)
// if expires == 0 then timer poped, then do not need to del_timer
if ((timeout > 0) && pCh->BookmarkTimer.expires &&
- (pCh->BookmarkTimer.expires > jiffies)) {
+ time_before(jiffies, pCh->BookmarkTimer.expires)) {
del_timer( &(pCh->BookmarkTimer) );
pCh->BookmarkTimer.expires = 0;
diff --git a/drivers/char/machzwd.c b/drivers/char/machzwd.c
index 8765b677a6dc8..85ba8321a564b 100644
--- a/drivers/char/machzwd.c
+++ b/drivers/char/machzwd.c
@@ -24,6 +24,8 @@
* a system RESET and it starts wd#2 that unconditionaly will RESET
* the system when the counter reaches zero.
*
+ * 14-Dec-2001 Matt Domsch <Matt_Domsch@dell.com>
+ * Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT
*/
#include <linux/config.h>
@@ -103,6 +105,15 @@ MODULE_LICENSE("GPL");
MODULE_PARM(action, "i");
MODULE_PARM_DESC(action, "after watchdog resets, generate: 0 = RESET(*) 1 = SMI 2 = NMI 3 = SCI");
+#ifdef CONFIG_WATCHDOG_NOWAYOUT
+static int nowayout = 1;
+#else
+static int nowayout = 0;
+#endif
+
+MODULE_PARM(nowayout,"i");
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+
#define PFX "machzwd"
static struct watchdog_info zf_info = {
@@ -307,23 +318,23 @@ static ssize_t zf_write(struct file *file, const char *buf, size_t count,
* no need to check for close confirmation
* no way to disable watchdog ;)
*/
-#ifndef CONFIG_WATCHDOG_NOWAYOUT
- size_t ofs;
-
- /*
- * note: just in case someone wrote the magic character
- * five months ago...
- */
- zf_expect_close = 0;
-
- /* now scan */
- for(ofs = 0; ofs != count; ofs++){
- if(buf[ofs] == 'V'){
- zf_expect_close = 1;
- dprintk("zf_expect_close 1\n");
+ if (!nowayout) {
+ size_t ofs;
+
+ /*
+ * note: just in case someone wrote the magic character
+ * five months ago...
+ */
+ zf_expect_close = 0;
+
+ /* now scan */
+ for(ofs = 0; ofs != count; ofs++){
+ if(buf[ofs] == 'V'){
+ zf_expect_close = 1;
+ dprintk("zf_expect_close 1\n");
+ }
}
}
-#endif
/*
* Well, anyhow someone wrote to us,
* we should return that favour
@@ -386,9 +397,9 @@ static int zf_open(struct inode *inode, struct file *file)
return -EBUSY;
}
-#ifdef CONFIG_WATCHDOG_NOWAYOUT
- MOD_INC_USE_COUNT;
-#endif
+ if (nowayout) {
+ MOD_INC_USE_COUNT;
+ }
zf_is_open = 1;
spin_unlock(&zf_lock);
diff --git a/drivers/char/mixcomwd.c b/drivers/char/mixcomwd.c
index 3f6e87a7c0d2d..bbcb881ef1b05 100644
--- a/drivers/char/mixcomwd.c
+++ b/drivers/char/mixcomwd.c
@@ -27,10 +27,13 @@
*
* Version 0.4 (99/11/15):
* - support for one more type board
+ *
+ * Version 0.5 (2001/12/14) Matt Domsch <Matt_Domsch@dell.com>
+ * - added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT
*
*/
-#define VERSION "0.4"
+#define VERSION "0.5"
#include <linux/module.h>
#include <linux/config.h>
@@ -57,26 +60,30 @@ static int mixcomwd_ioports[] = { 0x180, 0x280, 0x380, 0x000 };
static long mixcomwd_opened; /* long req'd for setbit --RR */
static int watchdog_port;
-
-#ifndef CONFIG_WATCHDOG_NOWAYOUT
static int mixcomwd_timer_alive;
static struct timer_list mixcomwd_timer;
+
+#ifdef CONFIG_WATCHDOG_NOWAYOUT
+static int nowayout = 1;
+#else
+static int nowayout = 0;
#endif
+MODULE_PARM(nowayout,"i");
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+
static void mixcomwd_ping(void)
{
outb_p(55,watchdog_port);
return;
}
-#ifndef CONFIG_WATCHDOG_NOWAYOUT
static void mixcomwd_timerfun(unsigned long d)
{
mixcomwd_ping();
mod_timer(&mixcomwd_timer,jiffies+ 5*HZ);
}
-#endif
/*
* Allow only one person to hold it open
@@ -89,31 +96,32 @@ static int mixcomwd_open(struct inode *inode, struct file *file)
}
mixcomwd_ping();
-#ifndef CONFIG_WATCHDOG_NOWAYOUT
- if(mixcomwd_timer_alive) {
- del_timer(&mixcomwd_timer);
- mixcomwd_timer_alive=0;
- }
-#endif
+ if (nowayout) {
+ MOD_INC_USE_COUNT;
+ } else {
+ if(mixcomwd_timer_alive) {
+ del_timer(&mixcomwd_timer);
+ mixcomwd_timer_alive=0;
+ }
+ }
return 0;
}
static int mixcomwd_release(struct inode *inode, struct file *file)
{
-#ifndef CONFIG_WATCHDOG_NOWAYOUT
- if(mixcomwd_timer_alive) {
- printk(KERN_ERR "mixcomwd: release called while internal timer alive");
- return -EBUSY;
+ if (!nowayout) {
+ if(mixcomwd_timer_alive) {
+ printk(KERN_ERR "mixcomwd: release called while internal timer alive");
+ return -EBUSY;
+ }
+ init_timer(&mixcomwd_timer);
+ mixcomwd_timer.expires=jiffies + 5 * HZ;
+ mixcomwd_timer.function=mixcomwd_timerfun;
+ mixcomwd_timer.data=0;
+ mixcomwd_timer_alive=1;
+ add_timer(&mixcomwd_timer);
}
- init_timer(&mixcomwd_timer);
- mixcomwd_timer.expires=jiffies + 5 * HZ;
- mixcomwd_timer.function=mixcomwd_timerfun;
- mixcomwd_timer.data=0;
- mixcomwd_timer_alive=1;
- add_timer(&mixcomwd_timer);
-#endif
-
clear_bit(0,&mixcomwd_opened);
return 0;
}
@@ -145,9 +153,9 @@ static int mixcomwd_ioctl(struct inode *inode, struct file *file,
{
case WDIOC_GETSTATUS:
status=mixcomwd_opened;
-#ifndef CONFIG_WATCHDOG_NOWAYOUT
- status|=mixcomwd_timer_alive;
-#endif
+ if (!nowayout) {
+ status|=mixcomwd_timer_alive;
+ }
if (copy_to_user((int *)arg, &status, sizeof(int))) {
return -EFAULT;
}
@@ -252,14 +260,14 @@ static int __init mixcomwd_init(void)
static void __exit mixcomwd_exit(void)
{
-#ifndef CONFIG_WATCHDOG_NOWAYOUT
- if(mixcomwd_timer_alive) {
- printk(KERN_WARNING "mixcomwd: I quit now, hardware will"
- " probably reboot!\n");
- del_timer(&mixcomwd_timer);
- mixcomwd_timer_alive=0;
+ if (!nowayout) {
+ if(mixcomwd_timer_alive) {
+ printk(KERN_WARNING "mixcomwd: I quit now, hardware will"
+ " probably reboot!\n");
+ del_timer(&mixcomwd_timer);
+ mixcomwd_timer_alive=0;
+ }
}
-#endif
release_region(watchdog_port,1);
misc_deregister(&mixcomwd_miscdev);
}
diff --git a/drivers/char/mxser.c b/drivers/char/mxser.c
index 12a0fd3ccc253..6d0512e0f5972 100644
--- a/drivers/char/mxser.c
+++ b/drivers/char/mxser.c
@@ -32,6 +32,9 @@
* version : 1.2
*
* Fixes for C104H/PCI by Tim Hockin <thockin@sun.com>
+ * Added support for: C102, CI-132, CI-134, CP-132, CP-114, CT-114 cards
+ * by Damian Wrobel <dwrobel@ertel.com.pl>
+ *
*/
#include <linux/config.h>
@@ -61,7 +64,7 @@
#include <asm/bitops.h>
#include <asm/uaccess.h>
-#define MXSER_VERSION "1.2"
+#define MXSER_VERSION "1.2.1"
#define MXSERMAJOR 174
#define MXSERCUMAJOR 175
@@ -114,10 +117,22 @@
#ifndef PCI_DEVICE_ID_C104
#define PCI_DEVICE_ID_C104 0x1040
#endif
+#ifndef PCI_DEVICE_ID_CP132
+#define PCI_DEVICE_ID_CP132 0x1320
+#endif
+#ifndef PCI_DEVICE_ID_CP114
+#define PCI_DEVICE_ID_CP114 0x1141
+#endif
+#ifndef PCI_DEVICE_ID_CT114
+#define PCI_DEVICE_ID_CT114 0x1140
+#endif
#define C168_ASIC_ID 1
#define C104_ASIC_ID 2
+#define CI134_ASIC_ID 3
+#define CI132_ASIC_ID 4
#define CI104J_ASIC_ID 5
+#define C102_ASIC_ID 0xB
enum {
MXSER_BOARD_C168_ISA = 0,
@@ -125,6 +140,12 @@ enum {
MXSER_BOARD_CI104J,
MXSER_BOARD_C168_PCI,
MXSER_BOARD_C104_PCI,
+ MXSER_BOARD_C102_ISA,
+ MXSER_BOARD_CI132,
+ MXSER_BOARD_CI134,
+ MXSER_BOARD_CP132_PCI,
+ MXSER_BOARD_CP114_PCI,
+ MXSER_BOARD_CT114_PCI
};
static char *mxser_brdname[] =
@@ -134,6 +155,12 @@ static char *mxser_brdname[] =
"CI-104J series",
"C168H/PCI series",
"C104H/PCI series",
+ "C102 series",
+ "CI-132 series",
+ "CI-134 series",
+ "CP-132 series",
+ "CP-114 series",
+ "CT-114 series"
};
static int mxser_numports[] =
@@ -143,6 +170,12 @@ static int mxser_numports[] =
4,
8,
4,
+ 2,
+ 2,
+ 4,
+ 2,
+ 4,
+ 4
};
/*
@@ -163,6 +196,12 @@ static struct pci_device_id mxser_pcibrds[] = {
MXSER_BOARD_C168_PCI },
{ PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_C104, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
MXSER_BOARD_C104_PCI },
+ { PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_CP132, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ MXSER_BOARD_CP132_PCI },
+ { PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_CP114, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ MXSER_BOARD_CP114_PCI },
+ { PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_CT114, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ MXSER_BOARD_CT114_PCI },
{ 0 }
};
MODULE_DEVICE_TABLE(pci, mxser_pcibrds);
@@ -613,38 +652,35 @@ int mxser_init(void)
n = (sizeof(mxser_pcibrds) / sizeof(mxser_pcibrds[0])) - 1;
index = 0;
for (b = 0; b < n; b++) {
- pdev = pci_find_device(mxser_pcibrds[b].vendor,
- mxser_pcibrds[b].device, pdev);
- if (!pdev || pci_enable_device(pdev))
- continue;
- hwconf.pdev = pdev;
- printk("Found MOXA %s board(BusNo=%d,DevNo=%d)\n",
- mxser_brdname[mxser_pcibrds[b].driver_data],
- pdev->bus->number, PCI_SLOT(pdev->devfn));
- if (m >= MXSER_BOARDS) {
- printk("Too many Smartio family boards found (maximum %d),board not configured\n", MXSER_BOARDS);
- } else {
- retval = mxser_get_PCI_conf(pdev,
- mxser_pcibrds[b].driver_data, &hwconf);
- if (retval < 0) {
- if (retval == MXSER_ERR_IRQ)
- printk("Invalid interrupt number,board not configured\n");
- else if (retval == MXSER_ERR_IRQ_CONFLIT)
- printk("Invalid interrupt number,board not configured\n");
- else if (retval == MXSER_ERR_VECTOR)
- printk("Invalid interrupt vector,board not configured\n");
- else if (retval == MXSER_ERR_IOADDR)
- printk("Invalid I/O address,board not configured\n");
+ while (pdev = pci_find_device(mxser_pcibrds[b].vendor, mxser_pcibrds[b].device, pdev))
+ {
+ if (pci_enable_device(pdev))
continue;
-
+ hwconf.pdev = pdev;
+ printk("Found MOXA %s board(BusNo=%d,DevNo=%d)\n",
+ mxser_brdname[mxser_pcibrds[b].driver_data],
+ pdev->bus->number, PCI_SLOT(pdev->devfn));
+ if (m >= MXSER_BOARDS) {
+ printk("Too many Smartio family boards found (maximum %d),board not configured\n", MXSER_BOARDS);
+ } else {
+ retval = mxser_get_PCI_conf(pdev, mxser_pcibrds[b].driver_data, &hwconf);
+ if (retval < 0) {
+ if (retval == MXSER_ERR_IRQ)
+ printk("Invalid interrupt number,board not configured\n");
+ else if (retval == MXSER_ERR_IRQ_CONFLIT)
+ printk("Invalid interrupt number,board not configured\n");
+ else if (retval == MXSER_ERR_VECTOR)
+ printk("Invalid interrupt vector,board not configured\n");
+ else if (retval == MXSER_ERR_IOADDR)
+ printk("Invalid I/O address,board not configured\n");
+ continue;
+ }
+ if (mxser_initbrd(m, &hwconf) < 0)
+ continue;
+ mxser_getcfg(m, &hwconf);
+ m++;
}
- if (mxser_initbrd(m, &hwconf) < 0)
- continue;
- mxser_getcfg(m, &hwconf);
- m++;
-
}
-
}
}
#endif
@@ -2306,6 +2342,12 @@ static int mxser_get_ISA_conf(int cap, struct mxser_hwconf *hwconf)
hwconf->board_type = MXSER_BOARD_C168_ISA;
else if (id == C104_ASIC_ID)
hwconf->board_type = MXSER_BOARD_C104_ISA;
+ else if (id == C102_ASIC_ID)
+ hwconf->board_type = MXSER_BOARD_C102_ISA;
+ else if (id == CI132_ASIC_ID)
+ hwconf->board_type = MXSER_BOARD_CI132;
+ else if (id == CI134_ASIC_ID)
+ hwconf->board_type = MXSER_BOARD_CI134;
else if (id == CI104J_ASIC_ID)
hwconf->board_type = MXSER_BOARD_CI104J;
else
@@ -2417,7 +2459,8 @@ static int mxser_program_mode(int port)
(void) inb(port);
restore_flags(flags);
id = inb(port + 1) & 0x1F;
- if ((id != C168_ASIC_ID) && (id != C104_ASIC_ID) && (id != CI104J_ASIC_ID))
+ if ((id != C168_ASIC_ID) && (id != C104_ASIC_ID) && (id != CI104J_ASIC_ID) &&
+ (id != C102_ASIC_ID) && (id != CI132_ASIC_ID) && (id != CI134_ASIC_ID))
return (-1);
for (i = 0, j = 0; i < 4; i++) {
n = inb(port + 2);
diff --git a/drivers/char/raw.c b/drivers/char/raw.c
index 79b5dfebb9aaf..2dcd1ef698a52 100644
--- a/drivers/char/raw.c
+++ b/drivers/char/raw.c
@@ -322,7 +322,7 @@ ssize_t rw_raw_dev(int rw, struct file *filp, char *buf,
if (err)
break;
- err = brw_kiovec(rw, 1, &iobuf, dev, &blocknr, sector_size);
+ err = brw_kiovec(rw, 1, &iobuf, raw_devices[minor].binding, &blocknr, sector_size);
if (rw == READ && err > 0)
mark_dirty_kiobuf(iobuf, err);
diff --git a/drivers/char/rocket.c b/drivers/char/rocket.c
index 7eb8b68269fb8..d6710f5b02947 100644
--- a/drivers/char/rocket.c
+++ b/drivers/char/rocket.c
@@ -42,10 +42,6 @@
#include <linux/config.h>
#include <linux/version.h>
-#ifdef CONFIG_PCI
-#define ENABLE_PCI
-#endif
-
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/major.h>
@@ -63,15 +59,8 @@
#include <linux/fcntl.h>
#include <linux/ptrace.h>
#include <linux/ioport.h>
-#ifdef ENABLE_PCI
#include <linux/pci.h>
-#if (LINUX_VERSION_CODE < 0x020163) /* 2.1.99 */
-#include <linux/bios32.h>
-#endif
-#endif
-#if (LINUX_VERSION_CODE >= 131343) /* 2.1.15 -- XX get correct version */
#include <linux/init.h>
-#endif
#include "rocket_int.h"
#ifdef LOCAL_ROCKET_H
@@ -154,7 +143,6 @@ static unsigned long time_stat_long;
static unsigned long time_counter;
#endif
-#if ((LINUX_VERSION_CODE > 0x020111) && defined(MODULE))
MODULE_AUTHOR("Theodore Ts'o");
MODULE_DESCRIPTION("Comtrol Rocketport driver");
MODULE_LICENSE("GPL");
@@ -170,39 +158,8 @@ MODULE_PARM(controller, "i");
MODULE_PARM_DESC(controller, "I/O port for (ISA) rocketport controller");
MODULE_PARM(support_low_speed, "i");
MODULE_PARM_DESC(support_low_speed, "0 means support 50 baud, 1 means support 460400 baud");
-#endif
-
-#if (LINUX_VERSION_CODE < 131336)
-int copy_from_user(void *to, const void *from_user, unsigned long len)
-{
- int error;
-
- error = verify_area(VERIFY_READ, from_user, len);
- if (error)
- return len;
- memcpy_fromfs(to, from_user, len);
- return 0;
-}
-
-int copy_to_user(void *to_user, const void *from, unsigned long len)
-{
- int error;
-
- error = verify_area(VERIFY_WRITE, to_user, len);
- if (error)
- return len;
- memcpy_tofs(to_user, from, len);
- return 0;
-}
-
-static inline int signal_pending(struct task_struct *p)
-{
- return (p->signal & ~p->blocked) != 0;
-}
-#else
#include <asm/uaccess.h>
-#endif
/*
* tmp_buf is used as a temporary buffer by rp_write. We need to
@@ -497,7 +454,7 @@ static void rp_do_poll(unsigned long dummy)
continue;
ctlp= sCtlNumToCtlPtr(ctrl);
-#ifdef ENABLE_PCI
+#ifdef CONFIG_PCI
if(ctlp->BusType == isPCI)
CtlMask= sPCIGetControllerIntStatus(ctlp);
else
@@ -611,12 +568,6 @@ static void init_r_port(int board, int aiop, int chan)
rp_table[line] = info;
}
-#if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */
-static int baud_table[] = {
- 0, 50, 75, 110, 134, 150, 200, 300,
- 600, 1200, 1800, 2400, 4800, 9600, 19200,
- 38400, 57600, 115200, 230400, 460800, 0 };
-#endif
/*
* This routine configures a rocketport port so according to its
@@ -627,9 +578,6 @@ static void configure_r_port(struct r_port *info)
unsigned cflag;
unsigned long flags;
int bits, baud;
-#if (LINUX_VERSION_CODE < 131393) /* Linux 2.1.65 */
- int i;
-#endif
CHANNEL_t *cp;
if (!info->tty || !info->tty->termios)
@@ -665,31 +613,9 @@ static void configure_r_port(struct r_port *info)
}
/* baud rate */
-#if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */
- i = cflag & CBAUD;
- if (i & CBAUDEX) {
- i &= ~CBAUDEX;
- if (i < 1 || i > 4)
- info->tty->termios->c_cflag &= ~CBAUDEX;
- else
- i += 15;
- }
- if (i == 15) {
- if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_HI)
- i += 1;
- if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_VHI)
- i += 2;
- if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_SHI)
- i += 3;
- if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_WARP)
- i += 4;
- }
- baud = baud_table[i] ? baud_table[i] : 9600;
-#else
baud = tty_get_baud_rate(info->tty);
if (!baud)
baud = 9600;
-#endif
info->cps = baud / bits;
sSetBaud(cp, (rp_baud_base/baud) - 1);
@@ -990,7 +916,6 @@ static int rp_open(struct tty_struct *tty, struct file * filp)
info->flags |= ROCKET_INITIALIZED;
-#if (LINUX_VERSION_CODE >= 131394) /* Linux 2.1.66 */
/*
* Set up the tty->alt_speed kludge
*/
@@ -1002,7 +927,6 @@ static int rp_open(struct tty_struct *tty, struct file * filp)
info->tty->alt_speed = 230400;
if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_WARP)
info->tty->alt_speed = 460800;
-#endif
configure_r_port(info);
if (tty->termios->c_cflag & CBAUD) {
@@ -1094,10 +1018,8 @@ static void rp_close(struct tty_struct *tty, struct file * filp)
* If transmission was throttled by the application request,
* just flush the xmit buffer.
*/
-#if (LINUX_VERSION_CODE >= 131343)
if (tty->flow_stopped)
rp_flush_buffer(tty);
-#endif
/*
* Wait for the transmit buffer to clear
@@ -1218,17 +1140,6 @@ static void rp_set_termios(struct tty_struct *tty, struct termios *old_termios)
/*
* Here are the routines used by rp_ioctl
*/
-#if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */
-static void send_break( struct r_port * info, int duration)
-{
- current->state = TASK_INTERRUPTIBLE;
- cli();
- sSendBreak(&info->channel);
- schedule_timeout(duration);
- sClrBreak(&info->channel);
- sti();
-}
-#else
static void rp_break(struct tty_struct *tty, int break_state)
{
struct r_port * info = (struct r_port *)tty->driver_data;
@@ -1245,7 +1156,6 @@ static void rp_break(struct tty_struct *tty, int break_state)
}
restore_flags(flags);
}
-#endif
static int get_modem_info(struct r_port * info, unsigned int *value)
{
@@ -1348,7 +1258,6 @@ static int set_config(struct r_port * info, struct rocket_config * new_info)
info->close_delay = new_serial.close_delay;
info->closing_wait = new_serial.closing_wait;
-#if (LINUX_VERSION_CODE >= 131394) /* Linux 2.1.66 */
if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_HI)
info->tty->alt_speed = 57600;
if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_VHI)
@@ -1357,7 +1266,6 @@ static int set_config(struct r_port * info, struct rocket_config * new_info)
info->tty->alt_speed = 230400;
if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_WARP)
info->tty->alt_speed = 460800;
-#endif
configure_r_port(info);
return 0;
@@ -1389,54 +1297,13 @@ static int rp_ioctl(struct tty_struct *tty, struct file * file,
unsigned int cmd, unsigned long arg)
{
struct r_port * info = (struct r_port *)tty->driver_data;
-#if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */
- int retval, tmp;
-#endif
if (cmd != RCKP_GET_PORTS &&
rocket_paranoia_check(info, tty->device, "rp_ioctl"))
return -ENODEV;
switch (cmd) {
-#if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */
- case TCSBRK: /* SVID version: non-zero arg --> no break */
- retval = tty_check_change(tty);
- if (retval)
- return retval;
- tty_wait_until_sent(tty, 0);
- if (signal_pending(current))
- return -EINTR;
- if (!arg) {
- send_break(info, HZ/4); /* 1/4 second */
- if (signal_pending(current))
- return -EINTR;
- }
- return 0;
- case TCSBRKP: /* support for POSIX tcsendbreak() */
- retval = tty_check_change(tty);
- if (retval)
- return retval;
- tty_wait_until_sent(tty, 0);
- if (signal_pending(current))
- return -EINTR;
- send_break(info, arg ? arg*(HZ/10) : HZ/4);
- if (signal_pending(current))
- return -EINTR;
- return 0;
- case TIOCGSOFTCAR:
- tmp = C_CLOCAL(tty) ? 1 : 0;
- if (copy_to_user((void *)arg, &tmp, sizeof(int)))
- return -EFAULT;
- return 0;
- case TIOCSSOFTCAR:
- if (copy_from_user(&tmp, (void *)arg, sizeof(int)))
- return -EFAULT;
- tty->termios->c_cflag =
- ((tty->termios->c_cflag & ~CLOCAL) |
- (tmp ? CLOCAL : 0));
- return 0;
-#endif
case TIOCMGET:
return get_modem_info(info, (unsigned int *) arg);
case TIOCMBIS:
@@ -1877,36 +1744,7 @@ static void rp_flush_buffer(struct tty_struct *tty)
sFlushTxFIFO(cp);
}
-#ifdef ENABLE_PCI
-#if (LINUX_VERSION_CODE < 0x020163) /* 2.1.99 */
-/* For compatibility */
-static struct pci_dev *pci_find_slot(unsigned char bus,
- unsigned char device_fn)
-{
- unsigned short vendor_id, device_id;
- int ret, error;
- static struct pci_dev ret_struct;
-
- error = pcibios_read_config_word(bus, device_fn, PCI_VENDOR_ID,
- &vendor_id);
- ret = pcibios_read_config_word(bus, device_fn, PCI_DEVICE_ID,
- &device_id);
- if (error == 0)
- error = ret;
-
- if (error) {
- printk("PCI RocketPort error: %s not initializing due to error"
- "reading configuration space\n",
- pcibios_strerror(error));
- return(0);
- }
-
- memset(&ret_struct, 0, sizeof(ret_struct));
- ret_struct.device = device_id;
-
- return &ret_struct;
-}
-#endif
+#ifdef CONFIG_PCI
int __init register_PCI(int i, unsigned int bus, unsigned int device_fn)
{
@@ -1915,10 +1753,6 @@ int __init register_PCI(int i, unsigned int bus, unsigned int device_fn)
char *str;
CONTROLLER_t *ctlp;
struct pci_dev *dev = pci_find_slot(bus, device_fn);
-#if (LINUX_VERSION_CODE < 0x020163) /* 2.1.99 */
- int ret;
- unsigned int port;
-#endif
if (!dev)
return 0;
@@ -2161,7 +1995,7 @@ int __init rp_init(void)
if(init_ISA(i, &reserved_controller))
isa_boards_found++;
}
-#ifdef ENABLE_PCI
+#ifdef CONFIG_PCI
if (pcibios_present()) {
if(isa_boards_found < NUM_BOARDS)
pci_boards_found = init_PCI(isa_boards_found);
@@ -2219,13 +2053,9 @@ int __init rp_init(void)
rocket_driver.stop = rp_stop;
rocket_driver.start = rp_start;
rocket_driver.hangup = rp_hangup;
-#if (LINUX_VERSION_CODE >= 131394) /* Linux 2.1.66 */
rocket_driver.break_ctl = rp_break;
-#endif
-#if (LINUX_VERSION_CODE >= 131343)
rocket_driver.send_xchar = rp_send_xchar;
rocket_driver.wait_until_sent = rp_wait_until_sent;
-#endif
/*
* The callout device is just like normal device except for
diff --git a/drivers/char/sbc60xxwdt.c b/drivers/char/sbc60xxwdt.c
index ff9a572b13a4b..ac7aeda9bfb5d 100644
--- a/drivers/char/sbc60xxwdt.c
+++ b/drivers/char/sbc60xxwdt.c
@@ -109,6 +109,15 @@ static unsigned long next_heartbeat;
static int wdt_is_open;
static int wdt_expect_close;
+#ifdef CONFIG_WATCHDOG_NOWAYOUT
+static int nowayout = 1;
+#else
+static int nowayout = 0;
+#endif
+
+MODULE_PARM(nowayout,"i");
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+
/*
* Whack the dog
*/
@@ -202,6 +211,9 @@ static int fop_open(struct inode * inode, struct file * file)
/* Just in case we're already talking to someone... */
if(wdt_is_open)
return -EBUSY;
+ if (nowayout) {
+ MOD_INC_USE_COUNT;
+ }
/* Good, fire up the show */
wdt_is_open = 1;
wdt_startup();
@@ -216,7 +228,7 @@ static int fop_close(struct inode * inode, struct file * file)
{
if(minor(inode->i_rdev) == WATCHDOG_MINOR)
{
- if(wdt_expect_close)
+ if(wdt_expect_close && !nowayout)
wdt_turnoff();
else {
del_timer(&timer);
diff --git a/drivers/char/shwdt.c b/drivers/char/shwdt.c
index c636eccc2c1a3..be73b1e2f5b5a 100644
--- a/drivers/char/shwdt.c
+++ b/drivers/char/shwdt.c
@@ -9,6 +9,9 @@
* 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.
+ *
+ * 14-Dec-2001 Matt Domsch <Matt_Domsch@dell.com>
+ * Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT
*/
#include <linux/config.h>
#include <linux/module.h>
@@ -88,6 +91,15 @@ static struct watchdog_info sh_wdt_info;
static struct timer_list timer;
static unsigned long next_heartbeat;
+#ifdef CONFIG_WATCHDOG_NOWAYOUT
+static int nowayout = 1;
+#else
+static int nowayout = 0;
+#endif
+
+MODULE_PARM(nowayout,"i");
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+
/**
* sh_wdt_write_cnt - Write to Counter
*
@@ -175,6 +187,10 @@ static int sh_wdt_open(struct inode *inode, struct file *file)
if (test_and_set_bit(0, &sh_is_open))
return -EBUSY;
+ if (nowayout) {
+ MOD_INC_USE_COUNT;
+ }
+
sh_wdt_start();
break;
@@ -196,9 +212,9 @@ static int sh_wdt_open(struct inode *inode, struct file *file)
static int sh_wdt_close(struct inode *inode, struct file *file)
{
if (minor(inode->i_rdev) == WATCHDOG_MINOR) {
-#ifndef CONFIG_WATCHDOG_NOWAYOUT
- sh_wdt_stop();
-#endif
+ if (!nowayout) {
+ sh_wdt_stop();
+ }
clear_bit(0, &sh_is_open);
}
diff --git a/drivers/char/softdog.c b/drivers/char/softdog.c
index 7635904d932c5..bbc0c8a396c02 100644
--- a/drivers/char/softdog.c
+++ b/drivers/char/softdog.c
@@ -1,5 +1,5 @@
/*
- * SoftDog 0.05: A Software Watchdog Device
+ * SoftDog 0.06: A Software Watchdog Device
*
* (c) Copyright 1996 Alan Cox <alan@redhat.com>, All Rights Reserved.
* http://www.redhat.com
@@ -26,6 +26,10 @@
*
* 19980911 Alan Cox
* Made SMP safe for 2.3.x
+ *
+ * 20011214 Matt Domsch <Matt_Domsch@dell.com>
+ * Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT
+ * Didn't add timeout option, as soft_margin option already exists.
*/
#include <linux/module.h>
@@ -46,6 +50,15 @@
static int soft_margin = TIMER_MARGIN; /* in seconds */
MODULE_PARM(soft_margin,"i");
+
+#ifdef CONFIG_WATCHDOG_NOWAYOUT
+static int nowayout = 1;
+#else
+static int nowayout = 0;
+#endif
+
+MODULE_PARM(nowayout,"i");
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
MODULE_LICENSE("GPL");
/*
@@ -83,9 +96,9 @@ static int softdog_open(struct inode *inode, struct file *file)
{
if(timer_alive)
return -EBUSY;
-#ifdef CONFIG_WATCHDOG_NOWAYOUT
- MOD_INC_USE_COUNT;
-#endif
+ if (nowayout) {
+ MOD_INC_USE_COUNT;
+ }
/*
* Activate timer
*/
@@ -98,11 +111,11 @@ static int softdog_release(struct inode *inode, struct file *file)
{
/*
* Shut off the timer.
- * Lock it in if it's a module and we defined ...NOWAYOUT
+ * Lock it in if it's a module and we set nowayout
*/
-#ifndef CONFIG_WATCHDOG_NOWAYOUT
- del_timer(&watchdog_ticktock);
-#endif
+ if(!nowayout) {
+ del_timer(&watchdog_ticktock);
+ }
timer_alive=0;
return 0;
}
@@ -159,7 +172,7 @@ static struct miscdevice softdog_miscdev = {
fops: &softdog_fops,
};
-static char banner[] __initdata = KERN_INFO "Software Watchdog Timer: 0.05, timer margin: %d sec\n";
+static char banner[] __initdata = KERN_INFO "Software Watchdog Timer: 0.06, soft_margin: %d sec, nowayout: %d\n";
static int __init watchdog_init(void)
{
@@ -170,7 +183,7 @@ static int __init watchdog_init(void)
if (ret)
return ret;
- printk(banner, soft_margin);
+ printk(banner, soft_margin, nowayout);
return 0;
}
diff --git a/drivers/char/sonypi.c b/drivers/char/sonypi.c
index 92bc9c5c4d6af..ced9b9edcb3ba 100644
--- a/drivers/char/sonypi.c
+++ b/drivers/char/sonypi.c
@@ -109,25 +109,29 @@ static inline int sonypi_emptyq(void) {
return result;
}
-static void sonypi_ecrset(u16 addr, u16 value) {
-
- wait_on_command(1, inw_p(SONYPI_CST_IOPORT) & 3);
- outw_p(0x81, SONYPI_CST_IOPORT);
- wait_on_command(0, inw_p(SONYPI_CST_IOPORT) & 2);
- outw_p(addr, SONYPI_DATA_IOPORT);
- wait_on_command(0, inw_p(SONYPI_CST_IOPORT) & 2);
- outw_p(value, SONYPI_DATA_IOPORT);
- wait_on_command(0, inw_p(SONYPI_CST_IOPORT) & 2);
+static void sonypi_ecrset(u8 addr, u8 value) {
+
+ wait_on_command(1, inb_p(SONYPI_CST_IOPORT) & 3);
+ outb_p(0x81, SONYPI_CST_IOPORT);
+ wait_on_command(0, inb_p(SONYPI_CST_IOPORT) & 2);
+ outb_p(addr, SONYPI_DATA_IOPORT);
+ wait_on_command(0, inb_p(SONYPI_CST_IOPORT) & 2);
+ outb_p(value, SONYPI_DATA_IOPORT);
+ wait_on_command(0, inb_p(SONYPI_CST_IOPORT) & 2);
}
-static u16 sonypi_ecrget(u16 addr) {
+static u8 sonypi_ecrget(u8 addr) {
+
+ wait_on_command(1, inb_p(SONYPI_CST_IOPORT) & 3);
+ outb_p(0x80, SONYPI_CST_IOPORT);
+ wait_on_command(0, inb_p(SONYPI_CST_IOPORT) & 2);
+ outb_p(addr, SONYPI_DATA_IOPORT);
+ wait_on_command(0, inb_p(SONYPI_CST_IOPORT) & 2);
+ return inb_p(SONYPI_DATA_IOPORT);
+}
- wait_on_command(1, inw_p(SONYPI_CST_IOPORT) & 3);
- outw_p(0x80, SONYPI_CST_IOPORT);
- wait_on_command(0, inw_p(SONYPI_CST_IOPORT) & 2);
- outw_p(addr, SONYPI_DATA_IOPORT);
- wait_on_command(0, inw_p(SONYPI_CST_IOPORT) & 2);
- return inw_p(SONYPI_DATA_IOPORT);
+static u16 sonypi_ecrget16(u8 addr) {
+ return sonypi_ecrget(addr) | (sonypi_ecrget(addr + 1) << 8);
}
/* Initializes the device - this comes from the AML code in the ACPI bios */
@@ -286,19 +290,38 @@ static void sonypi_camera_on(void) {
sonypi_device.camera_power = 1;
}
+/* sets the bluetooth subsystem power state */
+static void sonypi_setbluetoothpower(u8 state) {
+
+ state = (state != 0);
+ if (sonypi_device.bluetooth_power && state)
+ return;
+ if (!sonypi_device.bluetooth_power && !state)
+ return;
+
+ sonypi_call2(0x96, state);
+ sonypi_call1(0x93);
+ sonypi_device.bluetooth_power = state;
+}
+
/* Interrupt handler: some event is available */
void sonypi_irq(int irq, void *dev_id, struct pt_regs *regs) {
u8 v1, v2, event = 0;
int i;
u8 sonypi_jogger_ev, sonypi_fnkey_ev;
+ u8 sonypi_capture_ev, sonypi_bluetooth_ev;
if (sonypi_device.model == SONYPI_DEVICE_MODEL_TYPE2) {
sonypi_jogger_ev = SONYPI_TYPE2_JOGGER_EV;
sonypi_fnkey_ev = SONYPI_TYPE2_FNKEY_EV;
+ sonypi_capture_ev = SONYPI_TYPE2_CAPTURE_EV;
+ sonypi_bluetooth_ev = SONYPI_TYPE2_BLUETOOTH_EV;
}
else {
sonypi_jogger_ev = SONYPI_TYPE1_JOGGER_EV;
sonypi_fnkey_ev = SONYPI_TYPE1_FNKEY_EV;
+ sonypi_capture_ev = SONYPI_TYPE1_CAPTURE_EV;
+ sonypi_bluetooth_ev = SONYPI_TYPE1_BLUETOOTH_EV;
}
v1 = inb_p(sonypi_device.ioport1);
@@ -318,7 +341,7 @@ void sonypi_irq(int irq, void *dev_id, struct pt_regs *regs) {
goto found;
}
}
- if ((v2 & SONYPI_CAPTURE_EV) == SONYPI_CAPTURE_EV) {
+ if ((v2 & sonypi_capture_ev) == sonypi_capture_ev) {
for (i = 0; sonypi_captureev[i].event; i++)
if (sonypi_captureev[i].data == v1) {
event = sonypi_captureev[i].event;
@@ -332,7 +355,7 @@ void sonypi_irq(int irq, void *dev_id, struct pt_regs *regs) {
goto found;
}
}
- if ((v2 & SONYPI_BLUETOOTH_EV) == SONYPI_BLUETOOTH_EV) {
+ if ((v2 & sonypi_bluetooth_ev) == sonypi_bluetooth_ev) {
for (i = 0; sonypi_blueev[i].event; i++)
if (sonypi_blueev[i].data == v1) {
event = sonypi_blueev[i].event;
@@ -510,24 +533,74 @@ static unsigned int sonypi_misc_poll(struct file *file, poll_table * wait) {
static int sonypi_misc_ioctl(struct inode *ip, struct file *fp,
unsigned int cmd, unsigned long arg) {
int ret = 0;
- u8 val;
+ u8 val8;
+ u16 val16;
down(&sonypi_device.lock);
switch (cmd) {
- case SONYPI_IOCGBRT:
- val = sonypi_ecrget(0x96) & 0xff;
- if (copy_to_user((u8 *)arg, &val, sizeof(val))) {
- ret = -EFAULT;
- goto out;
- }
- break;
- case SONYPI_IOCSBRT:
- if (copy_from_user(&val, (u8 *)arg, sizeof(val))) {
- ret = -EFAULT;
- goto out;
- }
- sonypi_ecrset(0x96, val);
- break;
+ case SONYPI_IOCGBRT:
+ val8 = sonypi_ecrget(0x96);
+ if (copy_to_user((u8 *)arg, &val8, sizeof(val8))) {
+ ret = -EFAULT;
+ goto out;
+ }
+ break;
+ case SONYPI_IOCSBRT:
+ if (copy_from_user(&val8, (u8 *)arg, sizeof(val8))) {
+ ret = -EFAULT;
+ goto out;
+ }
+ sonypi_ecrset(0x96, val8);
+ break;
+ case SONYPI_IOCGBAT1CAP:
+ val16 = sonypi_ecrget16(0xb2);
+ if (copy_to_user((u16 *)arg, &val16, sizeof(val16))) {
+ ret = -EFAULT;
+ goto out;
+ }
+ break;
+ case SONYPI_IOCGBAT1REM:
+ val16 = sonypi_ecrget16(0xa2);
+ if (copy_to_user((u16 *)arg, &val16, sizeof(val16))) {
+ ret = -EFAULT;
+ goto out;
+ }
+ break;
+ case SONYPI_IOCGBAT2CAP:
+ val16 = sonypi_ecrget16(0xba);
+ if (copy_to_user((u16 *)arg, &val16, sizeof(val16))) {
+ ret = -EFAULT;
+ goto out;
+ }
+ break;
+ case SONYPI_IOCGBAT2REM:
+ val16 = sonypi_ecrget16(0xaa);
+ if (copy_to_user((u16 *)arg, &val16, sizeof(val16))) {
+ ret = -EFAULT;
+ goto out;
+ }
+ break;
+ case SONYPI_IOCGBATFLAGS:
+ val8 = sonypi_ecrget(0x81) & 0x07;
+ if (copy_to_user((u8 *)arg, &val8, sizeof(val8))) {
+ ret = -EFAULT;
+ goto out;
+ }
+ break;
+ case SONYPI_IOCGBLUE:
+ val8 = sonypi_device.bluetooth_power;
+ if (copy_to_user((u8 *)arg, &val8, sizeof(val8))) {
+ ret = -EFAULT;
+ goto out;
+ }
+ break;
+ case SONYPI_IOCSBLUE:
+ if (copy_from_user(&val8, (u8 *)arg, sizeof(val8))) {
+ ret = -EFAULT;
+ goto out;
+ }
+ sonypi_setbluetoothpower(val8);
+ break;
default:
ret = -EINVAL;
}
@@ -562,6 +635,7 @@ static int __devinit sonypi_probe(struct pci_dev *pcidev) {
sonypi_device.model = SONYPI_DEVICE_MODEL_TYPE2;
sonypi_initq();
init_MUTEX(&sonypi_device.lock);
+ sonypi_device.bluetooth_power = 0;
if (pcidev && pci_enable_device(pcidev)) {
printk(KERN_ERR "sonypi: pci_enable_device failed\n");
diff --git a/drivers/char/sonypi.h b/drivers/char/sonypi.h
index 9d836086060fe..3937c1eb1dbc0 100644
--- a/drivers/char/sonypi.h
+++ b/drivers/char/sonypi.h
@@ -34,8 +34,8 @@
#ifdef __KERNEL__
-#define SONYPI_DRIVER_MAJORVERSION 1
-#define SONYPI_DRIVER_MINORVERSION 8
+#define SONYPI_DRIVER_MAJORVERSION 1
+#define SONYPI_DRIVER_MINORVERSION 10
#include <linux/types.h>
#include <linux/pci.h>
@@ -132,15 +132,17 @@ static struct sonypi_irq_list sonypi_type2_irq_list[] = {
#define SONYPI_CAMERA_ROMVERSION 9
/* key press event data (ioport2) */
-#define SONYPI_TYPE1_JOGGER_EV 0x10
-#define SONYPI_TYPE2_JOGGER_EV 0x08
-#define SONYPI_CAPTURE_EV 0x60
-#define SONYPI_TYPE1_FNKEY_EV 0x20
-#define SONYPI_TYPE2_FNKEY_EV 0x08
-#define SONYPI_BLUETOOTH_EV 0x30
-#define SONYPI_TYPE1_PKEY_EV 0x40
-#define SONYPI_BACK_EV 0x08
-#define SONYPI_LID_EV 0x38
+#define SONYPI_TYPE1_JOGGER_EV 0x10
+#define SONYPI_TYPE2_JOGGER_EV 0x08
+#define SONYPI_TYPE1_CAPTURE_EV 0x60
+#define SONYPI_TYPE2_CAPTURE_EV 0x08
+#define SONYPI_TYPE1_FNKEY_EV 0x20
+#define SONYPI_TYPE2_FNKEY_EV 0x08
+#define SONYPI_TYPE1_BLUETOOTH_EV 0x30
+#define SONYPI_TYPE2_BLUETOOTH_EV 0x08
+#define SONYPI_TYPE1_PKEY_EV 0x40
+#define SONYPI_BACK_EV 0x08
+#define SONYPI_LID_EV 0x38
struct sonypi_event {
u8 data;
@@ -203,6 +205,8 @@ static struct sonypi_event sonypi_pkeyev[] = {
/* The set of possible bluetooth events */
static struct sonypi_event sonypi_blueev[] = {
{ 0x55, SONYPI_EVENT_BLUETOOTH_PRESSED },
+ { 0x59, SONYPI_EVENT_BLUETOOTH_ON },
+ { 0x5a, SONYPI_EVENT_BLUETOOTH_OFF },
{ 0x00, 0x00 }
};
@@ -241,6 +245,7 @@ struct sonypi_device {
u16 ioport2;
u16 region_size;
int camera_power;
+ int bluetooth_power;
struct semaphore lock;
struct sonypi_queue queue;
int open_count;
diff --git a/drivers/char/stallion.c b/drivers/char/stallion.c
index 80a73a1de70e0..db06f5ad2b10a 100644
--- a/drivers/char/stallion.c
+++ b/drivers/char/stallion.c
@@ -2458,7 +2458,7 @@ static inline int stl_initeio(stlbrd_t *brdp)
}
/*
- * We have verfied that the board is actually present, so now we
+ * We have verified that the board is actually present, so now we
* can complete the setup.
*/
diff --git a/drivers/char/synclink.c b/drivers/char/synclink.c
index de1c67b8e9db9..c50bc72474249 100644
--- a/drivers/char/synclink.c
+++ b/drivers/char/synclink.c
@@ -925,9 +925,9 @@ MODULE_PARM(txholdbufs,"1-" __MODULE_STRING(MAX_TOTAL_DEVICES) "i");
static char *driver_name = "SyncLink serial driver";
static char *driver_version = "$Revision: 3.12 $";
-static int __init synclink_init_one (struct pci_dev *dev,
+static int synclink_init_one (struct pci_dev *dev,
const struct pci_device_id *ent);
-static void __exit synclink_remove_one (struct pci_dev *dev);
+static void synclink_remove_one (struct pci_dev *dev);
static struct pci_device_id synclink_pci_tbl[] __devinitdata = {
{ PCI_VENDOR_ID_MICROGATE, PCI_DEVICE_ID_MICROGATE_USC, PCI_ANY_ID, PCI_ANY_ID, },
diff --git a/drivers/char/tpqic02.c b/drivers/char/tpqic02.c
index 4e5cfcf6a60fb..24b490623b147 100644
--- a/drivers/char/tpqic02.c
+++ b/drivers/char/tpqic02.c
@@ -2748,7 +2748,9 @@ static int qic02_get_resources(void)
* the config parameters have been set using MTSETCONFIG.
*/
- if (check_region(QIC02_TAPE_PORT, QIC02_TAPE_PORT_RANGE)) {
+ /* Grab the IO region. */
+ if (!request_region(QIC02_TAPE_PORT, QIC02_TAPE_PORT_RANGE,
+ TPQIC02_NAME)) {
printk(TPQIC02_NAME
": IO space at 0x%x [%d ports] already reserved\n",
QIC02_TAPE_PORT, QIC02_TAPE_PORT_RANGE);
@@ -2762,6 +2764,7 @@ static int qic02_get_resources(void)
printk(TPQIC02_NAME
": can't allocate IRQ%d for QIC-02 tape\n",
QIC02_TAPE_IRQ);
+ release_region(QIC02_TAPE_PORT, QIC02_TAPE_PORT_RANGE);
return -EBUSY;
}
@@ -2771,13 +2774,10 @@ static int qic02_get_resources(void)
": can't allocate DMA%d for QIC-02 tape\n",
QIC02_TAPE_DMA);
free_irq(QIC02_TAPE_IRQ, NULL);
+ release_region(QIC02_TAPE_PORT, QIC02_TAPE_PORT_RANGE);
return -EBUSY;
}
- /* Grab the IO region. We already made sure it's available. */
- request_region(QIC02_TAPE_PORT, QIC02_TAPE_PORT_RANGE,
- TPQIC02_NAME);
-
/* Setup the page-address for the dma transfer. */
buffaddr =
(void *) __get_dma_pages(GFP_KERNEL, get_order(TPQBUF_SIZE));
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
index 9fdd57eff81c4..d77cfdb24515f 100644
--- a/drivers/char/tty_io.c
+++ b/drivers/char/tty_io.c
@@ -569,6 +569,8 @@ void disassociate_ctty(int on_exit)
struct task_struct *p;
int tty_pgrp = -1;
+ lock_kernel();
+
if (tty) {
tty_pgrp = tty->pgrp;
if (on_exit && tty->driver.type != TTY_DRIVER_TYPE_PTY)
@@ -578,6 +580,7 @@ void disassociate_ctty(int on_exit)
kill_pg(current->tty_old_pgrp, SIGHUP, on_exit);
kill_pg(current->tty_old_pgrp, SIGCONT, on_exit);
}
+ unlock_kernel();
return;
}
if (tty_pgrp > 0) {
@@ -595,6 +598,7 @@ void disassociate_ctty(int on_exit)
if (p->session == current->session)
p->tty = NULL;
read_unlock(&tasklist_lock);
+ unlock_kernel();
}
void stop_tty(struct tty_struct *tty)
diff --git a/drivers/char/vme_scc.c b/drivers/char/vme_scc.c
index 45bbbc747834f..c59fc297f803e 100644
--- a/drivers/char/vme_scc.c
+++ b/drivers/char/vme_scc.c
@@ -214,7 +214,7 @@ static int mvme147_scc_init(void)
{
struct scc_port *port;
- printk("SCC: MVME147 Serial Driver\n");
+ printk(KERN_INFO "SCC: MVME147 Serial Driver\n");
/* Init channel A */
port = &scc_ports[0];
port->channel = CHANNEL_A;
@@ -284,7 +284,7 @@ static int mvme162_scc_init(void)
if (!(mvme16x_config & MVME16x_CONFIG_GOT_SCCA))
return (-ENODEV);
- printk("SCC: MVME162 Serial Driver\n");
+ printk(KERN_INFO "SCC: MVME162 Serial Driver\n");
/* Init channel A */
port = &scc_ports[0];
port->channel = CHANNEL_A;
@@ -352,7 +352,7 @@ static int bvme6000_scc_init(void)
{
struct scc_port *port;
- printk("SCC: BVME6000 Serial Driver\n");
+ printk(KERN_INFO "SCC: BVME6000 Serial Driver\n");
/* Init channel A */
port = &scc_ports[0];
port->channel = CHANNEL_A;
@@ -449,7 +449,7 @@ static void scc_rx_int(int irq, void *data, struct pt_regs *fp)
ch = SCCread_NB(RX_DATA_REG);
if (!tty) {
- printk ("scc_rx_int with NULL tty!\n");
+ printk(KERN_WARNING "scc_rx_int with NULL tty!\n");
SCCwrite_NB(COMMAND_REG, CR_HIGHEST_IUS_RESET);
return;
}
@@ -487,7 +487,7 @@ static void scc_spcond_int(int irq, void *data, struct pt_regs *fp)
SCC_ACCESS_INIT(port);
if (!tty) {
- printk ("scc_spcond_int with NULL tty!\n");
+ printk(KERN_WARNING "scc_spcond_int with NULL tty!\n");
SCCwrite(COMMAND_REG, CR_ERROR_RESET);
SCCwrite_NB(COMMAND_REG, CR_HIGHEST_IUS_RESET);
return;
@@ -533,7 +533,7 @@ static void scc_tx_int(int irq, void *data, struct pt_regs *fp)
SCC_ACCESS_INIT(port);
if (!port->gs.tty) {
- printk ("scc_tx_int with NULL tty!\n");
+ printk(KERN_WARNING "scc_tx_int with NULL tty!\n");
SCCmod (INT_AND_DMA_REG, ~IDR_TX_INT_ENAB, 0);
SCCwrite(COMMAND_REG, CR_TX_PENDING_RESET);
SCCwrite_NB(COMMAND_REG, CR_HIGHEST_IUS_RESET);
@@ -719,7 +719,7 @@ static int scc_set_real_termios (void *ptr)
else if ((MACH_IS_MVME16x && (baud < 50 || baud > 38400)) ||
(MACH_IS_MVME147 && (baud < 50 || baud > 19200)) ||
(MACH_IS_BVME6000 &&(baud < 50 || baud > 76800))) {
- printk("SCC: Bad speed requested, %d\n", baud);
+ printk(KERN_NOTICE "SCC: Bad speed requested, %d\n", baud);
return 0;
}
diff --git a/drivers/char/wdt.c b/drivers/char/wdt.c
index f98face6a689e..1fb85c7c70eb8 100644
--- a/drivers/char/wdt.c
+++ b/drivers/char/wdt.c
@@ -15,7 +15,7 @@
*
* (c) Copyright 1995 Alan Cox <alan@lxorguk.ukuu.org.uk>
*
- * Release 0.08.
+ * Release 0.09.
*
* Fixes
* Dave Gregorich : Modularisation and minor bugs
@@ -27,6 +27,7 @@
* Tim Hockin : Added insmod parameters, comment cleanup
* Parameterized timeout
* Tigran Aivazian : Restructured wdt_init() to handle failures
+ * Matt Domsch : added nowayout and timeout module options
*/
#include <linux/config.h>
@@ -62,6 +63,26 @@ static int irq=11;
#define WD_TIMO (100*60) /* 1 minute */
+static int timeout_val = WD_TIMO; /* value passed to card */
+static int timeout = 60; /* in seconds */
+MODULE_PARM(timeout,"i");
+MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds (default=60)");
+
+#ifdef CONFIG_WATCHDOG_NOWAYOUT
+static int nowayout = 1;
+#else
+static int nowayout = 0;
+#endif
+
+MODULE_PARM(nowayout,"i");
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+
+static void __init
+wdt_validate_timeout(void)
+{
+ timeout_val = timeout * 100;
+}
+
#ifndef MODULE
/**
@@ -216,7 +237,7 @@ static void wdt_ping(void)
/* Write a watchdog value */
inb_p(WDT_DC);
wdt_ctr_mode(1,2);
- wdt_ctr_load(1,WD_TIMO); /* Timeout */
+ wdt_ctr_load(1,timeout_val); /* Timeout */
outb_p(0, WDT_DC);
}
@@ -339,6 +360,9 @@ static int wdt_open(struct inode *inode, struct file *file)
case WATCHDOG_MINOR:
if(test_and_set_bit(0, &wdt_is_open))
return -EBUSY;
+ if (nowayout) {
+ MOD_INC_USE_COUNT;
+ }
/*
* Activate
*/
@@ -348,7 +372,7 @@ static int wdt_open(struct inode *inode, struct file *file)
wdt_ctr_mode(1,2);
wdt_ctr_mode(2,0);
wdt_ctr_load(0, 8948); /* count at 100Hz */
- wdt_ctr_load(1,WD_TIMO); /* Timeout 120 seconds */
+ wdt_ctr_load(1,timeout_val); /* Timeout */
wdt_ctr_load(2,65535);
outb_p(0, WDT_DC); /* Enable */
return 0;
@@ -375,10 +399,10 @@ static int wdt_release(struct inode *inode, struct file *file)
{
if(minor(inode->i_rdev)==WATCHDOG_MINOR)
{
-#ifndef CONFIG_WATCHDOG_NOWAYOUT
- inb_p(WDT_DC); /* Disable counters */
- wdt_ctr_load(2,0); /* 0 length reset pulses now */
-#endif
+ if (!nowayout) {
+ inb_p(WDT_DC); /* Disable counters */
+ wdt_ctr_load(2,0); /* 0 length reset pulses now */
+ }
clear_bit(0, &wdt_is_open);
}
return 0;
@@ -484,6 +508,7 @@ static int __init wdt_init(void)
{
int ret;
+ wdt_validate_timeout();
ret = misc_register(&wdt_miscdev);
if (ret) {
printk(KERN_ERR "wdt: can't misc_register on minor=%d\n", WATCHDOG_MINOR);
diff --git a/drivers/char/wdt977.c b/drivers/char/wdt977.c
index 7f9dde05cf269..0e32706edf895 100644
--- a/drivers/char/wdt977.c
+++ b/drivers/char/wdt977.c
@@ -1,5 +1,5 @@
/*
- * Wdt977 0.01: A Watchdog Device for Netwinder W83977AF chip
+ * Wdt977 0.02: A Watchdog Device for Netwinder W83977AF chip
*
* (c) Copyright 1998 Rebel.com (Woody Suwalski <woody@netwinder.org>)
*
@@ -11,8 +11,13 @@
* 2 of the License, or (at your option) any later version.
*
* -----------------------
+ * 14-Dec-2001 Matt Domsch <Matt_Domsch@dell.com>
+ * Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT
+ * 19-Dec-2001 Woody Suwalski: Netwinder fixes, ioctl interface
+ * 06-Jan-2002 Woody Suwalski: For compatibility, convert all timeouts
+ * from minutes to seconds.
*/
-
+
#include <linux/module.h>
#include <linux/config.h>
#include <linux/types.h>
@@ -21,56 +26,123 @@
#include <linux/miscdevice.h>
#include <linux/init.h>
#include <linux/smp_lock.h>
+#include <linux/watchdog.h>
#include <asm/io.h>
#include <asm/system.h>
#include <asm/mach-types.h>
+#include <asm/uaccess.h>
#define WATCHDOG_MINOR 130
-static int timeout = 3;
+#define DEFAULT_TIMEOUT 1 /* default timeout = 1 minute */
+
+static int timeout = DEFAULT_TIMEOUT*60; /* TO in seconds from user */
+static int timeoutM = DEFAULT_TIMEOUT; /* timeout in minutes */
static int timer_alive;
static int testmode;
+MODULE_PARM(timeout, "i");
+MODULE_PARM_DESC(timeout,"Watchdog timeout in seconds (60..15300), default=60");
+MODULE_PARM(testmode, "i");
+MODULE_PARM_DESC(testmode,"Watchdog testmode (1 = no reboot), default=0");
+
+#ifdef CONFIG_WATCHDOG_NOWAYOUT
+static int nowayout = 1;
+#else
+static int nowayout = 0;
+#endif
+
+MODULE_PARM(nowayout,"i");
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+
+
+/* This is kicking the watchdog by simply re-writing the timeout to reg. 0xF2 */
+int kick_wdog(void)
+{
+ /*
+ * Refresh the timer.
+ */
+
+ /* 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(timeoutM,0x371);
+
+ /* lock the SuperIO chip */
+ outb(0xAA,0x370);
+
+ return 0;
+}
+
+
/*
* Allow only one person to hold it open
*/
-
+
static int wdt977_open(struct inode *inode, struct file *file)
{
+
if(timer_alive)
return -EBUSY;
-#ifdef CONFIG_WATCHDOG_NOWAYOUT
- MOD_INC_USE_COUNT;
-#endif
+
+ /* convert seconds to minutes, rounding up */
+ timeoutM = timeout + 59;
+ timeoutM /= 60;
+
+ if (nowayout)
+ {
+ MOD_INC_USE_COUNT;
+
+ /* do not permit disabling the watchdog by writing 0 to reg. 0xF2 */
+ if (!timeoutM) timeoutM = DEFAULT_TIMEOUT;
+ }
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)
-
+ if (machine_is_netwinder())
+ {
+ /* we have a hw bug somewhere, so each 977 minute is actually only 30sec
+ * this limits the max timeout to half of device max of 255 minutes...
+ */
+ timeoutM += timeoutM;
+ }
+
+ /* max timeout value = 255 minutes (0xFF). Write 0 to disable WatchDog. */
+ if (timeoutM > 255) timeoutM = 255;
+
+ /* convert seconds to minutes */
+ printk(KERN_INFO "Wdt977 Watchdog activated: timeout = %d sec, nowayout = %i, testmode = %i.\n",
+ machine_is_netwinder() ? (timeoutM>>1)*60 : timeoutM*60,
+ nowayout, testmode);
+
+ /* 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 impl.)
+ * 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(timeoutM,0x371);
outb(0xF3,0x370);
- outb(0x00,0x371); //another setting is 0E for kbd/mouse/LED
+ 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
+
+ /* at last select device Aux1 (dev=7) and set GP16 as a watchdog output */
+ /* in test mode watch the bit 1 on F4 to indicate "triggered" */
if (!testmode)
{
outb(0x07,0x370);
@@ -78,9 +150,9 @@ static int wdt977_open(struct inode *inode, struct file *file)
outb(0xE6,0x370);
outb(0x08,0x371);
}
-
- // lock the SuperIO chip
- outb(0xAA,0x370);
+
+ /* lock the SuperIO chip */
+ outb(0xAA,0x370);
return 0;
}
@@ -89,84 +161,163 @@ 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
+ * Lock it in if it's a module and we set 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);
+ if (!nowayout)
+ {
+ lock_kernel();
- timer_alive=0;
+ /* unlock the SuperIO chip */
+ outb(0x87,0x370);
+ outb(0x87,0x370);
- printk(KERN_INFO "Watchdog: shutdown.\n");
-#endif
+ /* 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);
+
+ timer_alive=0;
+ unlock_kernel();
+
+ printk(KERN_INFO "Wdt977 Watchdog: shutdown\n");
+ }
return 0;
}
-static ssize_t wdt977_write(struct file *file, const char *data, size_t len, loff_t *ppos)
+
+/*
+ * wdt977_write:
+ * @file: file handle to the watchdog
+ * @buf: buffer to write (unused as data does not matter here
+ * @count: count of bytes
+ * @ppos: pointer to the position to write. No seeks allowed
+ *
+ * A write to a watchdog device is defined as a keepalive signal. Any
+ * write of data will do, as we we don't define content meaning.
+ */
+
+static ssize_t wdt977_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
{
+ /* Can't seek (pwrite) on this device */
+ if (ppos != &file->f_pos)
+ return -ESPIPE;
- //max timeout value = 255 minutes (0xFF). Write 0 to disable WatchDog.
- if (timeout>255)
- timeout = 255;
+ if(count)
+ {
+ kick_wdog();
+ return 1;
+ }
+ return 0;
+}
- /*
- * 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;
+/*
+ * wdt977_ioctl:
+ * @inode: inode of the device
+ * @file: file handle to the device
+ * @cmd: watchdog command
+ * @arg: argument pointer
+ *
+ * The watchdog API defines a common set of functions for all watchdogs
+ * according to their available features.
+ */
+
+static int wdt977_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+static struct watchdog_info ident = {
+ identity : "Winbond 83977"
+};
+
+int temp;
+
+ switch(cmd)
+ {
+ default:
+ return -ENOTTY;
+
+ case WDIOC_GETSUPPORT:
+ return copy_to_user((struct watchdog_info *)arg, &ident,
+ sizeof(ident)) ? -EFAULT : 0;
+
+ case WDIOC_GETBOOTSTATUS:
+ return put_user(0, (int *) arg);
+
+ case WDIOC_GETSTATUS:
+ /* unlock the SuperIO chip */
+ outb(0x87,0x370);
+ outb(0x87,0x370);
+
+ /* select device Aux2 (device=8) and read watchdog reg F4 */
+ outb(0x07,0x370);
+ outb(0x08,0x371);
+ outb(0xF4,0x370);
+ temp = inb(0x371);
+
+ /* lock the SuperIO chip */
+ outb(0xAA,0x370);
+
+ /* return info if "expired" in test mode */
+ return put_user(temp & 1, (int *) arg);
+
+ case WDIOC_KEEPALIVE:
+ kick_wdog();
+ return 0;
+
+ case WDIOC_SETTIMEOUT:
+ if (copy_from_user(&temp, (int *) arg, sizeof(int)))
+ return -EFAULT;
+
+ /* convert seconds to minutes, rounding up */
+ temp += 59;
+ temp /= 60;
+
+ /* we have a hw bug somewhere, so each 977 minute is actually only 30sec
+ * this limits the max timeout to half of device max of 255 minutes...
+ */
+ if (machine_is_netwinder())
+ {
+ temp += temp;
+ }
+
+ /* Sanity check */
+ if (temp < 0 || temp > 255)
+ return -EINVAL;
+
+ if (!temp && nowayout)
+ return -EINVAL;
+
+ timeoutM = temp;
+ kick_wdog();
+ return 0;
+ }
}
+
static struct file_operations wdt977_fops=
{
owner: THIS_MODULE,
write: wdt977_write,
+ ioctl: wdt977_ioctl,
open: wdt977_open,
release: wdt977_release,
};
@@ -184,9 +335,9 @@ static int __init nwwatchdog_init(void)
return -ENODEV;
misc_register(&wdt977_miscdev);
- printk(KERN_INFO "NetWinder Watchdog sleeping.\n");
+ printk(KERN_INFO "Wdt977 Watchdog sleeping.\n");
return 0;
-}
+}
static void __exit nwwatchdog_exit(void)
{
diff --git a/drivers/char/wdt_pci.c b/drivers/char/wdt_pci.c
index 9097fe9357261..62d3ffef2752a 100644
--- a/drivers/char/wdt_pci.c
+++ b/drivers/char/wdt_pci.c
@@ -15,7 +15,7 @@
*
* (c) Copyright 1995 Alan Cox <alan@lxorguk.ukuu.org.uk>
*
- * Release 0.08.
+ * Release 0.09.
*
* Fixes
* Dave Gregorich : Modularisation and minor bugs
@@ -30,6 +30,7 @@
* Alan Cox : Split ISA and PCI cards into two drivers
* Jeff Garzik : PCI cleanups
* Tigran Aivazian : Restructured wdtpci_init_one() to handle failures
+ * Matt Domsch : added nowayout and timeout module options
*/
#include <linux/config.h>
@@ -83,6 +84,26 @@ static int irq=11;
#define WD_TIMO (100*60) /* 1 minute */
+static int timeout_val = WD_TIMO; /* value passed to card */
+static int timeout = 60; /* in seconds */
+MODULE_PARM(timeout,"i");
+MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds (default=60)");
+
+#ifdef CONFIG_WATCHDOG_NOWAYOUT
+static int nowayout = 1;
+#else
+static int nowayout = 0;
+#endif
+
+MODULE_PARM(nowayout,"i");
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+
+static void __init
+wdtpci_validate_timeout(void)
+{
+ timeout_val = timeout * 100;
+}
+
#ifndef MODULE
/**
@@ -232,7 +253,7 @@ static void wdtpci_ping(void)
/* Write a watchdog value */
inb_p(WDT_DC);
wdtpci_ctr_mode(1,2);
- wdtpci_ctr_load(1,WD_TIMO); /* Timeout */
+ wdtpci_ctr_load(1,timeout_val); /* Timeout */
outb_p(0, WDT_DC);
}
@@ -357,9 +378,9 @@ static int wdtpci_open(struct inode *inode, struct file *file)
{
return -EBUSY;
}
-#ifdef CONFIG_WATCHDOG_NOWAYOUT
- MOD_INC_USE_COUNT;
-#endif
+ if (nowayout) {
+ MOD_INC_USE_COUNT;
+ }
/*
* Activate
*/
@@ -385,7 +406,7 @@ static int wdtpci_open(struct inode *inode, struct file *file)
wdtpci_ctr_mode(1,2);
wdtpci_ctr_mode(2,1);
wdtpci_ctr_load(0,20833); /* count at 100Hz */
- wdtpci_ctr_load(1,WD_TIMO);/* Timeout 60 seconds */
+ wdtpci_ctr_load(1,timeout_val); /* Timeout */
/* DO NOT LOAD CTR2 on PCI card! -- JPN */
outb_p(0, WDT_DC); /* Enable */
return 0;
@@ -412,10 +433,10 @@ static int wdtpci_release(struct inode *inode, struct file *file)
{
if(minor(inode->i_rdev)==WATCHDOG_MINOR)
{
-#ifndef CONFIG_WATCHDOG_NOWAYOUT
- inb_p(WDT_DC); /* Disable counters */
- wdtpci_ctr_load(2,0); /* 0 length reset pulses now */
-#endif
+ if (!nowayout) {
+ inb_p(WDT_DC); /* Disable counters */
+ wdtpci_ctr_load(2,0); /* 0 length reset pulses now */
+ }
clear_bit(0, &wdt_is_open );
}
return 0;
@@ -617,6 +638,8 @@ static int __init wdtpci_init(void)
if (rc < 1)
return -ENODEV;
+
+ wdtpci_validate_timeout();
return 0;
}
diff --git a/drivers/fc4/soc.c b/drivers/fc4/soc.c
index 19aee0628adfb..796c219de2624 100644
--- a/drivers/fc4/soc.c
+++ b/drivers/fc4/soc.c
@@ -742,7 +742,6 @@ static void __exit soc_cleanup(void)
for_each_soc(s) {
irq = s->port[0].fc.irq;
- disable_irq (irq);
free_irq (irq, s);
fcp_release(&(s->port[0].fc), 2);
diff --git a/drivers/fc4/socal.c b/drivers/fc4/socal.c
index 447a4de67f6a2..c923d5ce169fa 100644
--- a/drivers/fc4/socal.c
+++ b/drivers/fc4/socal.c
@@ -881,7 +881,6 @@ static void __exit socal_cleanup(void)
for_each_socal(s) {
irq = s->port[0].fc.irq;
- disable_irq (irq);
free_irq (irq, s);
fcp_release(&(s->port[0].fc), 2);
diff --git a/drivers/i2c/i2c-algo-bit.c b/drivers/i2c/i2c-algo-bit.c
index a576ffe4c239e..e8e2fe6b1a8f8 100644
--- a/drivers/i2c/i2c-algo-bit.c
+++ b/drivers/i2c/i2c-algo-bit.c
@@ -49,7 +49,7 @@
/* respectively. This makes sure that the algorithm works. Some chips */
/* might not like this, as they have an internal timeout of some mils */
/*
-#define SLO_IO jif=jiffies;while(jiffies<=jif+i2c_table[minor].veryslow)\
+#define SLO_IO jif=jiffies;while(time_before_eq(jiffies, jif+i2c_table[minor].veryslow))\
cond_resched();
*/
@@ -117,7 +117,7 @@ static inline int sclhi(struct i2c_algo_bit_data *adap)
* while they are processing data internally.
*/
setscl(adap,1);
- if (start+adap->timeout <= jiffies) {
+ if (time_after_eq(jiffies, start+adap->timeout)) {
return -ETIMEDOUT;
}
cond_resched();
diff --git a/drivers/i2c/i2c-dev.c b/drivers/i2c/i2c-dev.c
index 3b001b5db0e25..0ce05f165b271 100644
--- a/drivers/i2c/i2c-dev.c
+++ b/drivers/i2c/i2c-dev.c
@@ -141,7 +141,7 @@ loff_t i2cdev_lseek (struct file *file, loff_t offset, int origin)
#ifdef DEBUG
struct inode *inode = file->f_dentry->d_inode;
printk("i2c-dev.o: i2c-%d lseek to %ld bytes relative to %d.\n",
- MINOR(inode->i_rdev),(long) offset,origin);
+ minor(inode->i_rdev),(long) offset,origin);
#endif /* DEBUG */
return -ESPIPE;
}
@@ -165,7 +165,7 @@ static ssize_t i2cdev_read (struct file *file, char *buf, size_t count,
return -ENOMEM;
#ifdef DEBUG
- printk("i2c-dev.o: i2c-%d reading %d bytes.\n",MINOR(inode->i_rdev),
+ printk("i2c-dev.o: i2c-%d reading %d bytes.\n",minor(inode->i_rdev),
count);
#endif
@@ -197,7 +197,7 @@ static ssize_t i2cdev_write (struct file *file, const char *buf, size_t count,
}
#ifdef DEBUG
- printk("i2c-dev.o: i2c-%d writing %d bytes.\n",MINOR(inode->i_rdev),
+ printk("i2c-dev.o: i2c-%d writing %d bytes.\n",minor(inode->i_rdev),
count);
#endif
ret = i2c_master_send(client,tmp,count);
@@ -218,7 +218,7 @@ int i2cdev_ioctl (struct inode *inode, struct file *file, unsigned int cmd,
#ifdef DEBUG
printk("i2c-dev.o: i2c-%d ioctl, cmd: 0x%x, arg: %lx.\n",
- MINOR(inode->i_rdev),cmd, arg);
+ minor(inode->i_rdev),cmd, arg);
#endif /* DEBUG */
switch ( cmd ) {
diff --git a/drivers/i2c/i2c-proc.c b/drivers/i2c/i2c-proc.c
index 0145f779ad86a..9935044524103 100644
--- a/drivers/i2c/i2c-proc.c
+++ b/drivers/i2c/i2c-proc.c
@@ -119,6 +119,10 @@ int i2c_create_name(char **name, const char *prefix,
sprintf(name_buffer, "%s-i2c-%d-%02x", prefix, id, addr);
}
*name = kmalloc(strlen(name_buffer) + 1, GFP_KERNEL);
+ if (!*name) {
+ printk (KERN_WARNING "i2c_create_name: not enough memory\n");
+ return -ENOMEM;
+ }
strcpy(*name, name_buffer);
return 0;
}
diff --git a/drivers/ide/aec62xx.c b/drivers/ide/aec62xx.c
index 1f4c535ec563a..185d17ecc3821 100644
--- a/drivers/ide/aec62xx.c
+++ b/drivers/ide/aec62xx.c
@@ -220,7 +220,7 @@ static byte pci_bus_clock_list_ultra (byte speed, struct chipset_bus_clock_list_
static int aec6210_tune_chipset (ide_drive_t *drive, byte speed)
{
- ide_hwif_t *hwif = HWIF(drive);
+ struct ata_channel *hwif = drive->channel;
struct pci_dev *dev = hwif->pci_dev;
int err = 0;
unsigned short d_conf = 0x0000;
@@ -256,10 +256,10 @@ static int aec6210_tune_chipset (ide_drive_t *drive, byte speed)
static int aec6260_tune_chipset (ide_drive_t *drive, byte speed)
{
- ide_hwif_t *hwif = HWIF(drive);
+ struct ata_channel *hwif = drive->channel;
struct pci_dev *dev = hwif->pci_dev;
byte unit = (drive->select.b.unit & 0x01);
- byte ultra_pci = hwif->channel ? 0x45 : 0x44;
+ byte ultra_pci = hwif->unit ? 0x45 : 0x44;
int err = 0;
byte drive_conf = 0x00;
byte ultra_conf = 0x00;
@@ -293,7 +293,7 @@ static int aec6260_tune_chipset (ide_drive_t *drive, byte speed)
static int aec62xx_tune_chipset (ide_drive_t *drive, byte speed)
{
- if (HWIF(drive)->pci_dev->device == PCI_DEVICE_ID_ARTOP_ATP850UF) {
+ if (drive->channel->pci_dev->device == PCI_DEVICE_ID_ARTOP_ATP850UF) {
return ((int) aec6210_tune_chipset(drive, speed));
} else {
return ((int) aec6260_tune_chipset(drive, speed));
@@ -304,7 +304,7 @@ static int aec62xx_tune_chipset (ide_drive_t *drive, byte speed)
static int config_aec6210_chipset_for_dma (ide_drive_t *drive, byte ultra)
{
struct hd_driveid *id = drive->id;
- ide_hwif_t *hwif = HWIF(drive);
+ struct ata_channel *hwif = drive->channel;
byte unit = (drive->select.b.unit & 0x01);
unsigned long dma_base = hwif->dma_base;
byte speed = -1;
@@ -349,7 +349,7 @@ static int config_aec6210_chipset_for_dma (ide_drive_t *drive, byte ultra)
static int config_aec6260_chipset_for_dma (ide_drive_t *drive, byte ultra)
{
struct hd_driveid *id = drive->id;
- ide_hwif_t *hwif = HWIF(drive);
+ struct ata_channel *hwif = drive->channel;
byte unit = (drive->select.b.unit & 0x01);
unsigned long dma_base = hwif->dma_base;
byte speed = -1;
@@ -396,7 +396,7 @@ static int config_aec6260_chipset_for_dma (ide_drive_t *drive, byte ultra)
static int config_chipset_for_dma (ide_drive_t *drive, byte ultra)
{
- switch(HWIF(drive)->pci_dev->device) {
+ switch(drive->channel->pci_dev->device) {
case PCI_DEVICE_ID_ARTOP_ATP850UF:
return config_aec6210_chipset_for_dma(drive, ultra);
case PCI_DEVICE_ID_ARTOP_ATP860:
@@ -418,7 +418,7 @@ static void aec62xx_tune_drive (ide_drive_t *drive, byte pio)
else
speed = XFER_PIO_0 + min_t(byte, pio, 4);
- switch(HWIF(drive)->pci_dev->device) {
+ switch(drive->channel->pci_dev->device) {
case PCI_DEVICE_ID_ARTOP_ATP850UF:
(void) aec6210_tune_chipset(drive, speed);
case PCI_DEVICE_ID_ARTOP_ATP860:
@@ -435,7 +435,7 @@ static int config_drive_xfer_rate (ide_drive_t *drive)
struct hd_driveid *id = drive->id;
ide_dma_action_t dma_func = ide_dma_on;
- if (id && (id->capability & 1) && HWIF(drive)->autodma) {
+ if (id && (id->capability & 1) && drive->channel->autodma) {
/* Consult the list of known "bad" drives */
if (ide_dmaproc(ide_dma_bad_drive, drive)) {
dma_func = ide_dma_off;
@@ -476,7 +476,7 @@ fast_ata_pio:
no_dma_set:
aec62xx_tune_drive(drive, 5);
}
- return HWIF(drive)->dmaproc(dma_func, drive);
+ return drive->channel->dmaproc(dma_func, drive);
}
/*
@@ -489,16 +489,16 @@ int aec62xx_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
return config_drive_xfer_rate(drive);
case ide_dma_lostirq:
case ide_dma_timeout:
- switch(HWIF(drive)->pci_dev->device) {
+ switch(drive->channel->pci_dev->device) {
case PCI_DEVICE_ID_ARTOP_ATP860:
case PCI_DEVICE_ID_ARTOP_ATP860R:
// {
// int i = 0;
// byte reg49h = 0;
-// pci_read_config_byte(HWIF(drive)->pci_dev, 0x49, &reg49h);
+// pci_read_config_byte(drive->channel->pci_dev, 0x49, &reg49h);
// for (i=0;i<256;i++)
-// pci_write_config_byte(HWIF(drive)->pci_dev, 0x49, reg49h|0x10);
-// pci_write_config_byte(HWIF(drive)->pci_dev, 0x49, reg49h & ~0x10);
+// pci_write_config_byte(drive->channel->pci_dev, 0x49, reg49h|0x10);
+// pci_write_config_byte(drive->channel->pci_dev, 0x49, reg49h & ~0x10);
// }
// return 0;
default:
@@ -530,16 +530,16 @@ unsigned int __init pci_init_aec62xx (struct pci_dev *dev)
return dev->irq;
}
-unsigned int __init ata66_aec62xx (ide_hwif_t *hwif)
+unsigned int __init ata66_aec62xx(struct ata_channel *hwif)
{
- byte mask = hwif->channel ? 0x02 : 0x01;
+ byte mask = hwif->unit ? 0x02 : 0x01;
byte ata66 = 0;
pci_read_config_byte(hwif->pci_dev, 0x49, &ata66);
return ((ata66 & mask) ? 0 : 1);
}
-void __init ide_init_aec62xx (ide_hwif_t *hwif)
+void __init ide_init_aec62xx(struct ata_channel *hwif)
{
#ifdef CONFIG_AEC62XX_TUNING
hwif->tuneproc = &aec62xx_tune_drive;
@@ -555,7 +555,7 @@ void __init ide_init_aec62xx (ide_hwif_t *hwif)
#endif /* CONFIG_AEC62XX_TUNING */
}
-void __init ide_dmacapable_aec62xx (ide_hwif_t *hwif, unsigned long dmabase)
+void __init ide_dmacapable_aec62xx(struct ata_channel *hwif, unsigned long dmabase)
{
#ifdef CONFIG_AEC62XX_TUNING
unsigned long flags;
@@ -565,7 +565,7 @@ void __init ide_dmacapable_aec62xx (ide_hwif_t *hwif, unsigned long dmabase)
__cli(); /* local CPU only */
pci_read_config_byte(hwif->pci_dev, 0x54, &reg54h);
- pci_write_config_byte(hwif->pci_dev, 0x54, reg54h & ~(hwif->channel ? 0xF0 : 0x0F));
+ pci_write_config_byte(hwif->pci_dev, 0x54, reg54h & ~(hwif->unit ? 0xF0 : 0x0F));
__restore_flags(flags); /* local CPU only */
#endif /* CONFIG_AEC62XX_TUNING */
diff --git a/drivers/ide/ali14xx.c b/drivers/ide/ali14xx.c
index dd93eeb487c19..10861d49571a9 100644
--- a/drivers/ide/ali14xx.c
+++ b/drivers/ide/ali14xx.c
@@ -134,7 +134,7 @@ static void ali14xx_tune_drive (ide_drive_t *drive, byte pio)
drive->name, pio - XFER_PIO_0, time1, time2, param1, param2, param3, param4);
/* stuff timing parameters into controller registers */
- driveNum = (HWIF(drive)->index << 1) + drive->select.b.unit;
+ driveNum = (drive->channel->index << 1) + drive->select.b.unit;
save_flags(flags); /* all CPUs */
cli(); /* all CPUs */
outb_p(regOn, basePort);
@@ -214,7 +214,7 @@ void __init init_ali14xx (void)
ide_hwifs[1].tuneproc = &ali14xx_tune_drive;
ide_hwifs[0].mate = &ide_hwifs[1];
ide_hwifs[1].mate = &ide_hwifs[0];
- ide_hwifs[1].channel = 1;
+ ide_hwifs[1].unit = 1;
/* initialize controller registers */
if (!initRegisters()) {
diff --git a/drivers/ide/alim15x3.c b/drivers/ide/alim15x3.c
index a7a8fe6a1afbe..b6a8e10b89e8f 100644
--- a/drivers/ide/alim15x3.c
+++ b/drivers/ide/alim15x3.c
@@ -242,13 +242,13 @@ static struct pci_dev *isa_dev;
static void ali15x3_tune_drive (ide_drive_t *drive, byte pio)
{
struct ata_timing *t;
- ide_hwif_t *hwif = HWIF(drive);
+ struct ata_channel *hwif = drive->channel;
struct pci_dev *dev = hwif->pci_dev;
int s_time, a_time, c_time;
byte s_clc, a_clc, r_clc;
unsigned long flags;
- int port = hwif->index ? 0x5c : 0x58;
- int portFIFO = hwif->channel ? 0x55 : 0x54;
+ int port = hwif->unit ? 0x5c : 0x58;
+ int portFIFO = hwif->unit ? 0x55 : 0x54;
byte cd_dma_fifo = 0;
if (pio == 255)
@@ -305,11 +305,11 @@ static void ali15x3_tune_drive (ide_drive_t *drive, byte pio)
static int ali15x3_tune_chipset (ide_drive_t *drive, byte speed)
{
- ide_hwif_t *hwif = HWIF(drive);
+ struct ata_channel *hwif = drive->channel;
struct pci_dev *dev = hwif->pci_dev;
byte unit = (drive->select.b.unit & 0x01);
byte tmpbyte = 0x00;
- int m5229_udma = hwif->channel? 0x57 : 0x56;
+ int m5229_udma = hwif->unit ? 0x57 : 0x56;
int err = 0;
if (speed < XFER_UDMA_0) {
@@ -431,10 +431,10 @@ static byte ali15x3_can_ultra (ide_drive_t *drive)
static int ali15x3_config_drive_for_dma(ide_drive_t *drive)
{
- struct hd_driveid *id = drive->id;
- ide_hwif_t *hwif = HWIF(drive);
- ide_dma_action_t dma_func = ide_dma_on;
- byte can_ultra_dma = ali15x3_can_ultra(drive);
+ struct hd_driveid *id = drive->id;
+ struct ata_channel *hwif = drive->channel;
+ ide_dma_action_t dma_func = ide_dma_on;
+ byte can_ultra_dma = ali15x3_can_ultra(drive);
if ((m5229_revision<=0x20) && (drive->type != ATA_DISK))
return hwif->dmaproc(ide_dma_off_quietly, drive);
@@ -537,7 +537,7 @@ unsigned int __init pci_init_ali15x3(struct pci_dev *dev)
* of UDMA66 transfers. It doesn't check the drives.
* But see note 2 below!
*/
-unsigned int __init ata66_ali15x3 (ide_hwif_t *hwif)
+unsigned int __init ata66_ali15x3(struct ata_channel *hwif)
{
struct pci_dev *dev = hwif->pci_dev;
unsigned int ata66 = 0;
@@ -597,7 +597,7 @@ unsigned int __init ata66_ali15x3 (ide_hwif_t *hwif)
/*
* Allow ata66 if cable of current channel has 80 pins
*/
- ata66 = (hwif->channel)?cable_80_pin[1]:cable_80_pin[0];
+ ata66 = (hwif->unit)?cable_80_pin[1]:cable_80_pin[0];
} else {
/*
* revision 0x20 (1543-E, 1543-F)
@@ -632,14 +632,14 @@ unsigned int __init ata66_ali15x3 (ide_hwif_t *hwif)
return(ata66);
}
-void __init ide_init_ali15x3 (ide_hwif_t *hwif)
+void __init ide_init_ali15x3(struct ata_channel *hwif)
{
#ifndef CONFIG_SPARC64
byte ideic, inmir;
byte irq_routing_table[] = { -1, 9, 3, 10, 4, 5, 7, 6,
1, 11, 0, 12, 0, 14, 0, 15 };
- hwif->irq = hwif->channel ? 15 : 14;
+ hwif->irq = hwif->unit ? 15 : 14;
if (isa_dev) {
/*
@@ -651,14 +651,14 @@ void __init ide_init_ali15x3 (ide_hwif_t *hwif)
ideic = ideic & 0x03;
/* get IRQ for IDE Controller */
- if ((hwif->channel && ideic == 0x03) || (!hwif->channel && !ideic)) {
+ if ((hwif->unit && ideic == 0x03) || (!hwif->unit && !ideic)) {
/*
* get SIRQ1 routing table
*/
pci_read_config_byte(isa_dev, 0x44, &inmir);
inmir = inmir & 0x0f;
hwif->irq = irq_routing_table[inmir];
- } else if (hwif->channel && !(ideic & 0x01)) {
+ } else if (hwif->unit && !(ideic & 0x01)) {
/*
* get SIRQ2 routing table
*/
@@ -690,7 +690,7 @@ void __init ide_init_ali15x3 (ide_hwif_t *hwif)
#endif /* CONFIG_BLK_DEV_IDEDMA */
}
-void __init ide_dmacapable_ali15x3 (ide_hwif_t *hwif, unsigned long dmabase)
+void __init ide_dmacapable_ali15x3(struct ata_channel *hwif, unsigned long dmabase)
{
if ((dmabase) && (m5229_revision < 0x20)) {
return;
diff --git a/drivers/ide/amd74xx.c b/drivers/ide/amd74xx.c
index c1c036e36fb4c..6c9e0ec54be39 100644
--- a/drivers/ide/amd74xx.c
+++ b/drivers/ide/amd74xx.c
@@ -226,7 +226,7 @@ static void amd_set_speed(struct pci_dev *dev, unsigned char dn, struct ata_timi
static int amd_set_drive(ide_drive_t *drive, unsigned char speed)
{
- ide_drive_t *peer = HWIF(drive)->drives + (~drive->dn & 1);
+ ide_drive_t *peer = drive->channel->drives + (~drive->dn & 1);
struct ata_timing t, p;
int T, UT;
@@ -247,7 +247,7 @@ static int amd_set_drive(ide_drive_t *drive, unsigned char speed)
if (speed == XFER_UDMA_5 && amd_clock <= 33333) t.udma = 1;
- amd_set_speed(HWIF(drive)->pci_dev, drive->dn, &t);
+ amd_set_speed(drive->channel->pci_dev, drive->dn, &t);
if (!drive->init_speed)
drive->init_speed = speed;
@@ -263,7 +263,7 @@ static int amd_set_drive(ide_drive_t *drive, unsigned char speed)
static void amd74xx_tune_drive(ide_drive_t *drive, unsigned char pio)
{
- if (!((amd_enabled >> HWIF(drive)->channel) & 1))
+ if (!((amd_enabled >> drive->channel->unit) & 1))
return;
if (pio == 255) {
@@ -287,7 +287,7 @@ int amd74xx_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
if (func == ide_dma_check) {
- short w80 = HWIF(drive)->udma_four;
+ short w80 = drive->channel->udma_four;
short speed = ata_timing_mode(drive,
XFER_PIO | XFER_EPIO | XFER_MWDMA | XFER_UDMA |
@@ -297,7 +297,7 @@ int amd74xx_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
amd_set_drive(drive, speed);
- func = (HWIF(drive)->autodma && (speed & XFER_MODE) != XFER_PIO)
+ func = (drive->channel->autodma && (speed & XFER_MODE) != XFER_PIO)
? ide_dma_on : ide_dma_off_quietly;
}
@@ -409,12 +409,12 @@ unsigned int __init pci_init_amd74xx(struct pci_dev *dev, const char *name)
return 0;
}
-unsigned int __init ata66_amd74xx(ide_hwif_t *hwif)
+unsigned int __init ata66_amd74xx(struct ata_channel *hwif)
{
- return ((amd_enabled & amd_80w) >> hwif->channel) & 1;
+ return ((amd_enabled & amd_80w) >> hwif->unit) & 1;
}
-void __init ide_init_amd74xx(ide_hwif_t *hwif)
+void __init ide_init_amd74xx(struct ata_channel *hwif)
{
int i;
@@ -426,7 +426,7 @@ void __init ide_init_amd74xx(ide_hwif_t *hwif)
hwif->drives[i].io_32bit = 1;
hwif->drives[i].unmask = 1;
hwif->drives[i].autotune = 1;
- hwif->drives[i].dn = hwif->channel * 2 + i;
+ hwif->drives[i].dn = hwif->unit * 2 + i;
}
#ifdef CONFIG_BLK_DEV_IDEDMA
@@ -445,8 +445,8 @@ void __init ide_init_amd74xx(ide_hwif_t *hwif)
* We allow the BM-DMA driver only work on enabled interfaces.
*/
-void __init ide_dmacapable_amd74xx(ide_hwif_t *hwif, unsigned long dmabase)
+void __init ide_dmacapable_amd74xx(struct ata_channel *hwif, unsigned long dmabase)
{
- if ((amd_enabled >> hwif->channel) & 1)
+ if ((amd_enabled >> hwif->unit) & 1)
ide_setup_dma(hwif, dmabase, 8);
}
diff --git a/drivers/ide/buddha.c b/drivers/ide/buddha.c
index 404ddc0ae6ede..b7881df057e82 100644
--- a/drivers/ide/buddha.c
+++ b/drivers/ide/buddha.c
@@ -116,7 +116,7 @@ typedef enum BuddhaType_Enum BuddhaType;
* Check and acknowledge the interrupt status
*/
-static int buddha_ack_intr(ide_hwif_t *hwif)
+static int buddha_ack_intr(struct ata_channel *hwif)
{
unsigned char ch;
@@ -126,7 +126,7 @@ static int buddha_ack_intr(ide_hwif_t *hwif)
return 1;
}
-static int xsurf_ack_intr(ide_hwif_t *hwif)
+static int xsurf_ack_intr(struct ata_channel *hwif)
{
unsigned char ch;
diff --git a/drivers/ide/cmd640.c b/drivers/ide/cmd640.c
index 27413c647376e..65aaf22b781c6 100644
--- a/drivers/ide/cmd640.c
+++ b/drivers/ide/cmd640.c
@@ -187,7 +187,7 @@ static byte recovery_counts[4] = {16, 16, 16, 16}; /* Recovery count (encoded) *
/*
* These are initialized to point at the devices we control
*/
-static ide_hwif_t *cmd_hwif0, *cmd_hwif1;
+static struct ata_channel *cmd_hwif0, *cmd_hwif1;
static ide_drive_t *cmd_drives[4];
/*
@@ -429,7 +429,7 @@ static void __init setup_device_ptrs (void)
cmd_hwif0 = &ide_hwifs[0]; /* default, if not found below */
cmd_hwif1 = &ide_hwifs[1]; /* default, if not found below */
for (i = 0; i < MAX_HWIFS; i++) {
- ide_hwif_t *hwif = &ide_hwifs[i];
+ struct ata_channel *hwif = &ide_hwifs[i];
if (hwif->chipset == ide_unknown || hwif->chipset == ide_generic) {
if (hwif->io_ports[IDE_DATA_OFFSET] == 0x1f0)
cmd_hwif0 = hwif;
@@ -795,7 +795,7 @@ int __init ide_probe_for_cmd640x (void)
cmd_hwif1->chipset = ide_cmd640;
cmd_hwif0->mate = cmd_hwif1;
cmd_hwif1->mate = cmd_hwif0;
- cmd_hwif1->channel = 1;
+ cmd_hwif1->unit = 1;
#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
cmd_hwif1->tuneproc = &cmd640_tune_drive;
#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
diff --git a/drivers/ide/cmd64x.c b/drivers/ide/cmd64x.c
index 39391d7c80e15..8f041daba0522 100644
--- a/drivers/ide/cmd64x.c
+++ b/drivers/ide/cmd64x.c
@@ -211,7 +211,7 @@ static byte prefetch_masks[4] = {CNTRL_DIS_RA0, CNTRL_DIS_RA1, ARTTIM23_DIS_RA2,
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;
+ ide_drive_t *drives = drive->channel->drives;
byte temp_b;
static const byte setup_counts[] = {0x40, 0x40, 0x40, 0x80, 0, 0xc0};
static const byte recovery_counts[] =
@@ -224,7 +224,7 @@ static void program_drive_counts (ide_drive_t *drive, int setup_count, int activ
{ DRWTIM0, DRWTIM1 },
{ DRWTIM2, DRWTIM3 }
};
- int channel = (int) HWIF(drive)->channel;
+ int channel = drive->channel->unit;
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,
@@ -260,10 +260,10 @@ static void program_drive_counts (ide_drive_t *drive, int setup_count, int activ
* 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);
- (void) pci_write_config_byte(HWIF(drive)->pci_dev, arttim_regs[channel][slave],
+ (void) pci_read_config_byte(drive->channel->pci_dev, arttim_regs[channel][slave], &temp_b);
+ (void) pci_write_config_byte(drive->channel->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],
+ (void) pci_write_config_byte(drive->channel->pci_dev, drwtim_regs[channel][slave],
(byte) ((active_count << 4) | recovery_count));
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]);
@@ -333,10 +333,10 @@ static void cmd64x_tuneproc (ide_drive_t *drive, byte mode_wanted)
setup_count, active_count, recovery_count);
}
-static byte cmd680_taskfile_timing (ide_hwif_t *hwif)
+static byte cmd680_taskfile_timing(struct ata_channel *hwif)
{
struct pci_dev *dev = hwif->pci_dev;
- byte addr_mask = (hwif->channel) ? 0xB2 : 0xA2;
+ byte addr_mask = (hwif->unit) ? 0xB2 : 0xA2;
unsigned short timing;
pci_read_config_word(dev, addr_mask, &timing);
@@ -353,7 +353,7 @@ static byte cmd680_taskfile_timing (ide_hwif_t *hwif)
static void cmd680_tuneproc (ide_drive_t *drive, byte mode_wanted)
{
- ide_hwif_t *hwif = HWIF(drive);
+ struct ata_channel *hwif = drive->channel;
struct pci_dev *dev = hwif->pci_dev;
byte drive_pci;
unsigned short speedt;
@@ -394,10 +394,10 @@ static void config_cmd64x_chipset_for_pio (ide_drive_t *drive, byte set_speed)
static void config_cmd680_chipset_for_pio (ide_drive_t *drive, byte set_speed)
{
- ide_hwif_t *hwif = HWIF(drive);
+ struct ata_channel *hwif = drive->channel;
struct pci_dev *dev = hwif->pci_dev;
u8 unit = (drive->select.b.unit & 0x01);
- u8 addr_mask = (hwif->channel) ? 0x84 : 0x80;
+ u8 addr_mask = (hwif->unit) ? 0x84 : 0x80;
u8 speed = 0x00;
u8 mode_pci = 0x00;
u8 channel_timings = cmd680_taskfile_timing(hwif);
@@ -420,7 +420,7 @@ static void config_cmd680_chipset_for_pio (ide_drive_t *drive, byte set_speed)
static void config_chipset_for_pio (ide_drive_t *drive, byte set_speed)
{
- if (HWIF(drive)->pci_dev->device == PCI_DEVICE_ID_CMD_680) {
+ if (drive->channel->pci_dev->device == PCI_DEVICE_ID_CMD_680) {
config_cmd680_chipset_for_pio(drive, set_speed);
} else {
config_cmd64x_chipset_for_pio(drive, set_speed);
@@ -430,13 +430,13 @@ static void config_chipset_for_pio (ide_drive_t *drive, byte set_speed)
static int cmd64x_tune_chipset (ide_drive_t *drive, byte speed)
{
#ifdef CONFIG_BLK_DEV_IDEDMA
- ide_hwif_t *hwif = HWIF(drive);
+ struct ata_channel *hwif = drive->channel;
struct pci_dev *dev = hwif->pci_dev;
int err = 0;
u8 unit = (drive->select.b.unit & 0x01);
- u8 pciU = (hwif->channel) ? UDIDETCR1 : UDIDETCR0;
- u8 pciD = (hwif->channel) ? BMIDESR1 : BMIDESR0;
+ u8 pciU = (hwif->unit) ? UDIDETCR1 : UDIDETCR0;
+ u8 pciD = (hwif->unit) ? BMIDESR1 : BMIDESR0;
u8 regU = 0;
u8 regD = 0;
@@ -498,9 +498,9 @@ static int cmd64x_tune_chipset (ide_drive_t *drive, byte speed)
static int cmd680_tune_chipset (ide_drive_t *drive, byte speed)
{
- ide_hwif_t *hwif = HWIF(drive);
+ struct ata_channel *hwif = drive->channel;
struct pci_dev *dev = hwif->pci_dev;
- u8 addr_mask = (hwif->channel) ? 0x84 : 0x80;
+ u8 addr_mask = (hwif->unit) ? 0x84 : 0x80;
u8 unit = (drive->select.b.unit & 0x01);
u8 dma_pci = 0;
u8 udma_pci = 0;
@@ -615,7 +615,7 @@ speed_break :
static int config_cmd64x_chipset_for_dma (ide_drive_t *drive, unsigned int rev, byte ultra_66)
{
struct hd_driveid *id = drive->id;
- ide_hwif_t *hwif = HWIF(drive);
+ struct ata_channel *hwif = drive->channel;
struct pci_dev *dev = hwif->pci_dev;
byte speed = 0x00;
@@ -741,7 +741,7 @@ static int config_cmd680_chipset_for_dma (ide_drive_t *drive)
static int config_chipset_for_dma (ide_drive_t *drive, unsigned int rev, byte ultra_66)
{
- if (HWIF(drive)->pci_dev->device == PCI_DEVICE_ID_CMD_680)
+ if (drive->channel->pci_dev->device == PCI_DEVICE_ID_CMD_680)
return (config_cmd680_chipset_for_dma(drive));
return (config_cmd64x_chipset_for_dma(drive, rev, ultra_66));
}
@@ -749,7 +749,7 @@ static int config_chipset_for_dma (ide_drive_t *drive, unsigned int rev, byte ul
static int cmd64x_config_drive_for_dma (ide_drive_t *drive)
{
struct hd_driveid *id = drive->id;
- ide_hwif_t *hwif = HWIF(drive);
+ struct ata_channel *hwif = drive->channel;
struct pci_dev *dev = hwif->pci_dev;
unsigned int class_rev = 0;
byte can_ultra_33 = 0;
@@ -822,7 +822,7 @@ fast_ata_pio:
no_dma_set:
config_chipset_for_pio(drive, 1);
}
- return HWIF(drive)->dmaproc(dma_func, drive);
+ return drive->channel->dmaproc(dma_func, drive);
}
static int cmd680_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
@@ -841,9 +841,9 @@ static int cmd64x_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
{
byte dma_stat = 0;
byte dma_alt_stat = 0;
- byte mask = (HWIF(drive)->channel) ? MRDMODE_INTR_CH1 : MRDMODE_INTR_CH0;
- unsigned long dma_base = HWIF(drive)->dma_base;
- struct pci_dev *dev = HWIF(drive)->pci_dev;
+ byte mask = (drive->channel->unit) ? MRDMODE_INTR_CH1 : MRDMODE_INTR_CH0;
+ unsigned long dma_base = drive->channel->dma_base;
+ struct pci_dev *dev = drive->channel->pci_dev;
byte jack_slap = ((dev->device == PCI_DEVICE_ID_CMD_648) || (dev->device == PCI_DEVICE_ID_CMD_649)) ? 1 : 0;
switch (func) {
@@ -856,8 +856,8 @@ static int cmd64x_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
outb(dma_stat|6, dma_base+2); /* clear the INTR & ERROR bits */
if (jack_slap) {
byte dma_intr = 0;
- byte dma_mask = (HWIF(drive)->channel) ? ARTTIM23_INTR_CH1 : CFR_INTR_CH0;
- byte dma_reg = (HWIF(drive)->channel) ? ARTTIM2 : CFR;
+ byte dma_mask = (drive->channel->unit) ? ARTTIM23_INTR_CH1 : CFR_INTR_CH0;
+ byte dma_reg = (drive->channel->unit) ? ARTTIM2 : CFR;
(void) pci_read_config_byte(dev, dma_reg, &dma_intr);
/*
* DAMN BMIDE is not connected to PCI space!
@@ -891,7 +891,7 @@ static int cmd64x_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
*/
static int cmd646_1_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
{
- ide_hwif_t *hwif = HWIF(drive);
+ struct ata_channel *hwif = drive->channel;
unsigned long dma_base = hwif->dma_base;
byte dma_stat;
@@ -917,8 +917,8 @@ static int cmd646_1_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
static int cmd680_busproc (ide_drive_t * drive, int state)
{
#if 0
- ide_hwif_t *hwif = HWIF(drive);
- u8 addr_mask = (hwif->channel) ? 0xB0 : 0xA0;
+ struct ata_channel *hwif = drive->channel;
+ u8 addr_mask = (hwif->unit) ? 0xB0 : 0xA0;
u32 stat_config = 0;
pci_read_config_dword(hwif->pci_dev, addr_mask, &stat_config);
@@ -950,8 +950,8 @@ static int cmd680_busproc (ide_drive_t * drive, int state)
static void cmd680_reset (ide_drive_t *drive)
{
#if 0
- ide_hwif_t *hwif = HWIF(drive);
- u8 addr_mask = (hwif->channel) ? 0xB0 : 0xA0;
+ struct ata_channel *hwif = drive->channel;
+ u8 addr_mask = (hwif->unit) ? 0xB0 : 0xA0;
byte reset = 0;
pci_read_config_byte(hwif->pci_dev, addr_mask, &reset);
@@ -1081,25 +1081,25 @@ unsigned int __init pci_init_cmd64x(struct pci_dev *dev)
return cmd64x_pci_init (dev);
}
-unsigned int cmd680_ata66 (ide_hwif_t *hwif)
+unsigned int cmd680_ata66(struct ata_channel *hwif)
{
byte ata66 = 0;
- byte addr_mask = (hwif->channel) ? 0xB0 : 0xA0;
+ byte addr_mask = (hwif->unit) ? 0xB0 : 0xA0;
pci_read_config_byte(hwif->pci_dev, addr_mask, &ata66);
return (ata66 & 0x01) ? 1 : 0;
}
-unsigned int cmd64x_ata66 (ide_hwif_t *hwif)
+unsigned int cmd64x_ata66(struct ata_channel *hwif)
{
byte ata66 = 0;
- byte mask = (hwif->channel) ? 0x02 : 0x01;
+ byte mask = (hwif->unit) ? 0x02 : 0x01;
pci_read_config_byte(hwif->pci_dev, BMIDECSR, &ata66);
return (ata66 & mask) ? 1 : 0;
}
-unsigned int __init ata66_cmd64x (ide_hwif_t *hwif)
+unsigned int __init ata66_cmd64x(struct ata_channel *hwif)
{
struct pci_dev *dev = hwif->pci_dev;
if (dev->device == PCI_DEVICE_ID_CMD_680)
@@ -1107,7 +1107,7 @@ unsigned int __init ata66_cmd64x (ide_hwif_t *hwif)
return cmd64x_ata66(hwif);
}
-void __init ide_init_cmd64x (ide_hwif_t *hwif)
+void __init ide_init_cmd64x(struct ata_channel *hwif)
{
struct pci_dev *dev = hwif->pci_dev;
unsigned int class_rev;
diff --git a/drivers/ide/cs5530.c b/drivers/ide/cs5530.c
index 23756d92f12d7..34526fa33404e 100644
--- a/drivers/ide/cs5530.c
+++ b/drivers/ide/cs5530.c
@@ -101,7 +101,7 @@ static unsigned int cs5530_pio_timings[2][5] =
* After chip reset, the PIO timings are set to 0x0000e132, which is not valid.
*/
#define CS5530_BAD_PIO(timings) (((timings)&~0x80000000)==0x0000e132)
-#define CS5530_BASEREG(hwif) (((hwif)->dma_base & ~0xf) + ((hwif)->channel ? 0x30 : 0x20))
+#define CS5530_BASEREG(hwif) (((hwif)->dma_base & ~0xf) + ((hwif)->unit ? 0x30 : 0x20))
/*
* cs5530_tuneproc() handles selection/setting of PIO modes
@@ -112,7 +112,7 @@ static unsigned int cs5530_pio_timings[2][5] =
*/
static void cs5530_tuneproc (ide_drive_t *drive, byte pio) /* pio=255 means "autotune" */
{
- ide_hwif_t *hwif = HWIF(drive);
+ struct ata_channel *hwif = drive->channel;
unsigned int format, basereg = CS5530_BASEREG(hwif);
if (pio == 255)
@@ -134,7 +134,7 @@ static void cs5530_tuneproc (ide_drive_t *drive, byte pio) /* pio=255 means "aut
static int cs5530_config_dma (ide_drive_t *drive)
{
int udma_ok = 1, mode = 0;
- ide_hwif_t *hwif = HWIF(drive);
+ struct ata_channel *hwif = drive->channel;
int unit = drive->select.b.unit;
ide_drive_t *mate = &hwif->drives[unit^1];
struct hd_driveid *id = drive->id;
@@ -344,7 +344,7 @@ unsigned int __init pci_init_cs5530(struct pci_dev *dev)
* This gets invoked by the IDE driver once for each channel,
* and performs channel-specific pre-initialization before drive probing.
*/
-void __init ide_init_cs5530 (ide_hwif_t *hwif)
+void __init ide_init_cs5530(struct ata_channel *hwif)
{
if (hwif->mate)
hwif->serialized = hwif->mate->serialized = 1;
diff --git a/drivers/ide/cy82c693.c b/drivers/ide/cy82c693.c
index 0634335e84a97..c4a17c00a107f 100644
--- a/drivers/ide/cy82c693.c
+++ b/drivers/ide/cy82c693.c
@@ -192,7 +192,7 @@ static void cy82c693_dma_enable (ide_drive_t *drive, int mode, int single)
if (mode > drive->id->tDMA) /* to be absolutly sure we have a valid mode */
mode = drive->id->tDMA;
- index = (HWIF(drive)->channel==0) ? CY82_INDEX_CHANNEL0 : CY82_INDEX_CHANNEL1;
+ index = (drive->channel->unit == 0) ? CY82_INDEX_CHANNEL0 : CY82_INDEX_CHANNEL1;
#if CY82C693_DEBUG_LOGS
/* for debug let's show the previous values */
@@ -200,7 +200,7 @@ static void cy82c693_dma_enable (ide_drive_t *drive, int mode, int single)
OUT_BYTE(index, CY82_INDEX_PORT);
data = IN_BYTE(CY82_DATA_PORT);
- printk (KERN_INFO "%s (ch=%d, dev=%d): DMA mode is %d (single=%d)\n", drive->name, HWIF(drive)->channel, drive->select.b.unit, (data&0x3), ((data>>2)&1));
+ printk (KERN_INFO "%s (ch=%d, dev=%d): DMA mode is %d (single=%d)\n", drive->name, drive->channel->unit, drive->select.b.unit, (data&0x3), ((data>>2)&1));
#endif /* CY82C693_DEBUG_LOGS */
data = (byte)mode|(byte)(single<<2);
@@ -209,7 +209,7 @@ static void cy82c693_dma_enable (ide_drive_t *drive, int mode, int single)
OUT_BYTE(data, CY82_DATA_PORT);
#if CY82C693_DEBUG_INFO
- printk (KERN_INFO "%s (ch=%d, dev=%d): set DMA mode to %d (single=%d)\n", drive->name, HWIF(drive)->channel, drive->select.b.unit, mode, single);
+ printk (KERN_INFO "%s (ch=%d, dev=%d): set DMA mode to %d (single=%d)\n", drive->name, drive->channel->unit, drive->select.b.unit, mode, single);
#endif /* CY82C693_DEBUG_INFO */
/*
@@ -271,7 +271,7 @@ static int cy82c693_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
*/
static void cy82c693_tune_drive (ide_drive_t *drive, byte pio)
{
- ide_hwif_t *hwif = HWIF(drive);
+ struct ata_channel *hwif = drive->channel;
struct pci_dev *dev = hwif->pci_dev;
pio_clocks_t pclk;
unsigned int addrCtrl;
@@ -318,7 +318,7 @@ static void cy82c693_tune_drive (ide_drive_t *drive, byte pio)
pci_read_config_byte(dev, CY82_IDE_SLAVE_8BIT, &pclk.time_8);
}
- printk (KERN_INFO "%s (ch=%d, dev=%d): PIO timing is (addr=0x%X, ior=0x%X, iow=0x%X, 8bit=0x%X)\n", drive->name, hwif->channel, drive->select.b.unit, addrCtrl, pclk.time_16r, pclk.time_16w, pclk.time_8);
+ printk (KERN_INFO "%s (ch=%d, dev=%d): PIO timing is (addr=0x%X, ior=0x%X, iow=0x%X, 8bit=0x%X)\n", drive->name, hwif->unit, drive->select.b.unit, addrCtrl, pclk.time_16r, pclk.time_16w, pclk.time_8);
#endif /* CY82C693_DEBUG_LOGS */
/* first let's calc the pio modes */
@@ -371,7 +371,7 @@ static void cy82c693_tune_drive (ide_drive_t *drive, byte pio)
}
#if CY82C693_DEBUG_INFO
- printk (KERN_INFO "%s (ch=%d, dev=%d): set PIO timing to (addr=0x%X, ior=0x%X, iow=0x%X, 8bit=0x%X)\n", drive->name, hwif->channel, drive->select.b.unit, addrCtrl, pclk.time_16r, pclk.time_16w, pclk.time_8);
+ printk (KERN_INFO "%s (ch=%d, dev=%d): set PIO timing to (addr=0x%X, ior=0x%X, iow=0x%X, 8bit=0x%X)\n", drive->name, hwif->unit, drive->select.b.unit, addrCtrl, pclk.time_16r, pclk.time_16w, pclk.time_8);
#endif /* CY82C693_DEBUG_INFO */
}
@@ -431,7 +431,7 @@ unsigned int __init pci_init_cy82c693(struct pci_dev *dev)
/*
* the init function - called for each ide channel once
*/
-void __init ide_init_cy82c693(ide_hwif_t *hwif)
+void __init ide_init_cy82c693(struct ata_channel *hwif)
{
hwif->chipset = ide_cy82c693;
hwif->tuneproc = cy82c693_tune_drive;
diff --git a/drivers/ide/dtc2278.c b/drivers/ide/dtc2278.c
index bc0aac09a4748..b2cf501d9bc37 100644
--- a/drivers/ide/dtc2278.c
+++ b/drivers/ide/dtc2278.c
@@ -89,7 +89,7 @@ static void tune_dtc2278 (ide_drive_t *drive, byte pio)
* 32bit I/O has to be enabled for *both* drives at the same time.
*/
drive->io_32bit = 1;
- HWIF(drive)->drives[!drive->select.b.unit].io_32bit = 1;
+ drive->channel->drives[!drive->select.b.unit].io_32bit = 1;
}
void __init init_dtc2278 (void)
@@ -126,5 +126,5 @@ void __init init_dtc2278 (void)
ide_hwifs[1].drives[1].no_unmask = 1;
ide_hwifs[0].mate = &ide_hwifs[1];
ide_hwifs[1].mate = &ide_hwifs[0];
- ide_hwifs[1].channel = 1;
+ ide_hwifs[1].unit = 1;
}
diff --git a/drivers/ide/gayle.c b/drivers/ide/gayle.c
index 5a5e8c04dc3f9..543e38df9b5ca 100644
--- a/drivers/ide/gayle.c
+++ b/drivers/ide/gayle.c
@@ -84,7 +84,7 @@ int ide_doubler = 0; /* support IDE doublers? */
* Check and acknowledge the interrupt status
*/
-static int gayle_ack_intr_a4000(ide_hwif_t *hwif)
+static int gayle_ack_intr_a4000(struct ata_channel *hwif)
{
unsigned char ch;
@@ -94,7 +94,7 @@ static int gayle_ack_intr_a4000(ide_hwif_t *hwif)
return 1;
}
-static int gayle_ack_intr_a1200(ide_hwif_t *hwif)
+static int gayle_ack_intr_a1200(struct ata_channel *hwif)
{
unsigned char ch;
diff --git a/drivers/ide/hpt34x.c b/drivers/ide/hpt34x.c
index 2d0e82cb266ed..4e0e971ac4dd3 100644
--- a/drivers/ide/hpt34x.c
+++ b/drivers/ide/hpt34x.c
@@ -98,12 +98,12 @@ static void hpt34x_clear_chipset (ide_drive_t *drive)
unsigned int reg1 = 0, tmp1 = 0;
unsigned int reg2 = 0, tmp2 = 0;
- pci_read_config_dword(HWIF(drive)->pci_dev, 0x44, &reg1);
- pci_read_config_dword(HWIF(drive)->pci_dev, 0x48, &reg2);
- tmp1 = ((0x00 << (3*drive->dn)) | (reg1 & ~(7 << (3*drive->dn))));
+ pci_read_config_dword(drive->channel->pci_dev, 0x44, &reg1);
+ pci_read_config_dword(drive->channel->pci_dev, 0x48, &reg2);
+ tmp1 = ((0x00 << (3 * drive->dn)) | (reg1 & ~(7 << (3 * drive->dn))));
tmp2 = (reg2 & ~(0x11 << drive->dn));
- pci_write_config_dword(HWIF(drive)->pci_dev, 0x44, tmp1);
- pci_write_config_dword(HWIF(drive)->pci_dev, 0x48, tmp2);
+ pci_write_config_dword(drive->channel->pci_dev, 0x44, tmp1);
+ pci_write_config_dword(drive->channel->pci_dev, 0x48, tmp2);
}
static int hpt34x_tune_chipset (ide_drive_t *drive, byte speed)
@@ -122,13 +122,13 @@ static int hpt34x_tune_chipset (ide_drive_t *drive, byte speed)
lo_speed >>= 5;
}
- pci_read_config_dword(HWIF(drive)->pci_dev, 0x44, &reg1);
- pci_read_config_dword(HWIF(drive)->pci_dev, 0x48, &reg2);
+ pci_read_config_dword(drive->channel->pci_dev, 0x44, &reg1);
+ pci_read_config_dword(drive->channel->pci_dev, 0x48, &reg2);
tmp1 = ((lo_speed << (3*drive->dn)) | (reg1 & ~(7 << (3*drive->dn))));
tmp2 = ((hi_speed << drive->dn) | reg2);
err = ide_config_drive_speed(drive, speed);
- pci_write_config_dword(HWIF(drive)->pci_dev, 0x44, tmp1);
- pci_write_config_dword(HWIF(drive)->pci_dev, 0x48, tmp2);
+ pci_write_config_dword(drive->channel->pci_dev, 0x44, tmp1);
+ pci_write_config_dword(drive->channel->pci_dev, 0x48, tmp2);
if (!drive->init_speed)
drive->init_speed = speed;
@@ -254,7 +254,7 @@ static int config_drive_xfer_rate (ide_drive_t *drive)
struct hd_driveid *id = drive->id;
ide_dma_action_t dma_func = ide_dma_on;
- if (id && (id->capability & 1) && HWIF(drive)->autodma) {
+ if (id && (id->capability & 1) && drive->channel->autodma) {
/* Consult the list of known "bad" drives */
if (ide_dmaproc(ide_dma_bad_drive, drive)) {
dma_func = ide_dma_off;
@@ -301,7 +301,7 @@ no_dma_set:
dma_func = ide_dma_off;
#endif /* CONFIG_HPT34X_AUTODMA */
- return HWIF(drive)->dmaproc(dma_func, drive);
+ return drive->channel->dmaproc(dma_func, drive);
}
/*
@@ -314,7 +314,7 @@ no_dma_set:
int hpt34x_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
{
- ide_hwif_t *hwif = HWIF(drive);
+ struct ata_channel *hwif = drive->channel;
unsigned long dma_base = hwif->dma_base;
unsigned int count, reading = 0;
byte dma_stat;
@@ -334,6 +334,7 @@ int hpt34x_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
drive->waiting_for_dma = 1;
if (drive->type != ATA_DISK)
return 0;
+ BUG_ON(HWGROUP(drive)->handler);
ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, NULL); /* issue cmd to drive */
OUT_BYTE((reading == 9) ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG);
return 0;
@@ -408,7 +409,7 @@ unsigned int __init pci_init_hpt34x(struct pci_dev *dev)
return dev->irq;
}
-void __init ide_init_hpt34x (ide_hwif_t *hwif)
+void __init ide_init_hpt34x(struct ata_channel *hwif)
{
hwif->tuneproc = &hpt34x_tune_drive;
hwif->speedproc = &hpt34x_tune_chipset;
diff --git a/drivers/ide/hpt366.c b/drivers/ide/hpt366.c
index 364d412639091..0703504f96f7a 100644
--- a/drivers/ide/hpt366.c
+++ b/drivers/ide/hpt366.c
@@ -485,7 +485,7 @@ static unsigned int pci_bus_clock_list (byte speed, struct chipset_bus_clock_lis
static void hpt366_tune_chipset (ide_drive_t *drive, byte speed)
{
byte regtime = (drive->select.b.unit & 0x01) ? 0x44 : 0x40;
- byte regfast = (HWIF(drive)->channel) ? 0x55 : 0x51;
+ byte regfast = (drive->channel->unit) ? 0x55 : 0x51;
/*
* since the channel is always 0 it does not matter.
*/
@@ -497,11 +497,11 @@ static void hpt366_tune_chipset (ide_drive_t *drive, byte speed)
/*
* Disable the "fast interrupt" prediction.
*/
- pci_read_config_byte(HWIF(drive)->pci_dev, regfast, &drive_fast);
+ pci_read_config_byte(drive->channel->pci_dev, regfast, &drive_fast);
if (drive_fast & 0x02)
- pci_write_config_byte(HWIF(drive)->pci_dev, regfast, drive_fast & ~0x20);
+ pci_write_config_byte(drive->channel->pci_dev, regfast, drive_fast & ~0x20);
- pci_read_config_dword(HWIF(drive)->pci_dev, regtime, &reg1);
+ pci_read_config_dword(drive->channel->pci_dev, regtime, &reg1);
/* detect bus speed by looking at control reg timing: */
switch((reg1 >> 8) & 7) {
case 5:
@@ -531,18 +531,18 @@ static void hpt366_tune_chipset (ide_drive_t *drive, byte speed)
}
reg2 &= ~0x80000000;
- pci_write_config_dword(HWIF(drive)->pci_dev, regtime, reg2);
+ pci_write_config_dword(drive->channel->pci_dev, regtime, reg2);
}
static void hpt370_tune_chipset (ide_drive_t *drive, byte speed)
{
- byte regfast = (HWIF(drive)->channel) ? 0x55 : 0x51;
+ byte regfast = (drive->channel->unit) ? 0x55 : 0x51;
unsigned int list_conf = 0;
unsigned int drive_conf = 0;
unsigned int conf_mask = (speed >= XFER_MW_DMA_0) ? 0xc0000000 : 0x30070000;
byte drive_pci = 0x40 + (drive->dn * 4);
byte new_fast, drive_fast = 0;
- struct pci_dev *dev = HWIF(drive)->pci_dev;
+ struct pci_dev *dev = drive->channel->pci_dev;
/*
* Disable the "fast interrupt" prediction.
@@ -561,7 +561,7 @@ static void hpt370_tune_chipset (ide_drive_t *drive, byte speed)
new_fast |= 0x01;
#endif
if (new_fast != drive_fast)
- pci_write_config_byte(HWIF(drive)->pci_dev, regfast, new_fast);
+ pci_write_config_byte(drive->channel->pci_dev, regfast, new_fast);
list_conf = pci_bus_clock_list(speed,
(struct chipset_bus_clock_list_entry *)
@@ -585,7 +585,7 @@ static int hpt3xx_tune_chipset (ide_drive_t *drive, byte speed)
if (!drive->init_speed)
drive->init_speed = speed;
- if (pci_rev_check_hpt3xx(HWIF(drive)->pci_dev)) {
+ if (pci_rev_check_hpt3xx(drive->channel->pci_dev)) {
hpt370_tune_chipset(drive, speed);
} else {
hpt366_tune_chipset(drive, speed);
@@ -670,7 +670,7 @@ static int config_chipset_for_dma (ide_drive_t *drive)
if ((id->dma_ultra & 0x0020) &&
(!check_in_drive_lists(drive, bad_ata100_5)) &&
(HPT370_ALLOW_ATA100_5) &&
- (pci_rev_check_hpt3xx(HWIF(drive)->pci_dev)) &&
+ (pci_rev_check_hpt3xx(drive->channel->pci_dev)) &&
(ultra66)) {
speed = XFER_UDMA_5;
} else if ((id->dma_ultra & 0x0010) &&
@@ -720,23 +720,23 @@ void hpt3xx_intrproc (ide_drive_t *drive)
if (drive->quirk_list) {
/* drives in the quirk_list may not like intr setups/cleanups */
} else {
- OUT_BYTE((drive)->ctl|2, HWIF(drive)->io_ports[IDE_CONTROL_OFFSET]);
+ OUT_BYTE((drive)->ctl|2, drive->channel->io_ports[IDE_CONTROL_OFFSET]);
}
}
void hpt3xx_maskproc (ide_drive_t *drive, int mask)
{
if (drive->quirk_list) {
- if (pci_rev_check_hpt3xx(HWIF(drive)->pci_dev)) {
+ if (pci_rev_check_hpt3xx(drive->channel->pci_dev)) {
byte reg5a = 0;
- pci_read_config_byte(HWIF(drive)->pci_dev, 0x5a, &reg5a);
+ pci_read_config_byte(drive->channel->pci_dev, 0x5a, &reg5a);
if (((reg5a & 0x10) >> 4) != mask)
- pci_write_config_byte(HWIF(drive)->pci_dev, 0x5a, mask ? (reg5a | 0x10) : (reg5a & ~0x10));
+ pci_write_config_byte(drive->channel->pci_dev, 0x5a, mask ? (reg5a | 0x10) : (reg5a & ~0x10));
} else {
if (mask) {
- disable_irq(HWIF(drive)->irq);
+ disable_irq(drive->channel->irq);
} else {
- enable_irq(HWIF(drive)->irq);
+ enable_irq(drive->channel->irq);
}
}
} else {
@@ -750,7 +750,7 @@ static int config_drive_xfer_rate (ide_drive_t *drive)
struct hd_driveid *id = drive->id;
ide_dma_action_t dma_func = ide_dma_on;
- if (id && (id->capability & 1) && HWIF(drive)->autodma) {
+ if (id && (id->capability & 1) && drive->channel->autodma) {
/* Consult the list of known "bad" drives */
if (ide_dmaproc(ide_dma_bad_drive, drive)) {
dma_func = ide_dma_off;
@@ -791,7 +791,7 @@ no_dma_set:
config_chipset_for_pio(drive);
}
- return HWIF(drive)->dmaproc(dma_func, drive);
+ return drive->channel->dmaproc(dma_func, drive);
}
/*
@@ -803,7 +803,7 @@ no_dma_set:
int hpt366_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
{
byte reg50h = 0, reg52h = 0, reg5ah = 0, dma_stat = 0;
- unsigned long dma_base = HWIF(drive)->dma_base;
+ unsigned long dma_base = drive->channel->dma_base;
switch (func) {
case ide_dma_check:
@@ -812,21 +812,21 @@ int hpt366_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
dma_stat = inb(dma_base+2);
return (dma_stat & 4) == 4; /* return 1 if INTR asserted */
case ide_dma_lostirq:
- pci_read_config_byte(HWIF(drive)->pci_dev, 0x50, &reg50h);
- pci_read_config_byte(HWIF(drive)->pci_dev, 0x52, &reg52h);
- pci_read_config_byte(HWIF(drive)->pci_dev, 0x5a, &reg5ah);
+ pci_read_config_byte(drive->channel->pci_dev, 0x50, &reg50h);
+ pci_read_config_byte(drive->channel->pci_dev, 0x52, &reg52h);
+ pci_read_config_byte(drive->channel->pci_dev, 0x5a, &reg5ah);
printk("%s: (%s) reg50h=0x%02x, reg52h=0x%02x, reg5ah=0x%02x\n",
drive->name,
ide_dmafunc_verbose(func),
reg50h, reg52h, reg5ah);
if (reg5ah & 0x10)
- pci_write_config_byte(HWIF(drive)->pci_dev, 0x5a, reg5ah & ~0x10);
+ pci_write_config_byte(drive->channel->pci_dev, 0x5a, reg5ah & ~0x10);
/* fall through to a reset */
#if 0
case ide_dma_begin:
case ide_dma_end:
/* reset the chips state over and over.. */
- pci_write_config_byte(HWIF(drive)->pci_dev, 0x51, 0x13);
+ pci_write_config_byte(drive->channel->pci_dev, 0x51, 0x13);
#endif
break;
case ide_dma_timeout:
@@ -838,10 +838,10 @@ int hpt366_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
int hpt370_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
{
- ide_hwif_t *hwif = HWIF(drive);
+ struct ata_channel *hwif = drive->channel;
unsigned long dma_base = hwif->dma_base;
- byte regstate = hwif->channel ? 0x54 : 0x50;
- byte reginfo = hwif->channel ? 0x56 : 0x52;
+ byte regstate = hwif->unit ? 0x54 : 0x50;
+ byte reginfo = hwif->unit ? 0x56 : 0x52;
byte dma_stat;
switch (func) {
@@ -899,23 +899,23 @@ int hpt370_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
void hpt3xx_reset (ide_drive_t *drive)
{
#if 0
- unsigned long high_16 = pci_resource_start(HWIF(drive)->pci_dev, 4);
- byte reset = (HWIF(drive)->channel) ? 0x80 : 0x40;
+ unsigned long high_16 = pci_resource_start(drive->channel->pci_dev, 4);
+ byte reset = (drive->channel->unit) ? 0x80 : 0x40;
byte reg59h = 0;
- pci_read_config_byte(HWIF(drive)->pci_dev, 0x59, &reg59h);
- pci_write_config_byte(HWIF(drive)->pci_dev, 0x59, reg59h|reset);
- pci_write_config_byte(HWIF(drive)->pci_dev, 0x59, reg59h);
+ pci_read_config_byte(drive->channel->pci_dev, 0x59, &reg59h);
+ pci_write_config_byte(drive->channel->pci_dev, 0x59, reg59h|reset);
+ pci_write_config_byte(drive->channel->pci_dev, 0x59, reg59h);
#endif
}
#if 0
static int hpt3xx_tristate (ide_drive_t * drive, int state)
{
- ide_hwif_t *hwif = HWIF(drive);
+ struct ata_channel *hwif = drive->channel;
struct pci_dev *dev = hwif->pci_dev;
- byte reset = (hwif->channel) ? 0x80 : 0x40;
- byte state_reg = (hwif->channel) ? 0x57 : 0x53;
+ byte reset = (hwif->unit) ? 0x80 : 0x40;
+ byte state_reg = (hwif->unit) ? 0x57 : 0x53;
byte reg59h = 0;
byte regXXh = 0;
@@ -951,7 +951,7 @@ static int hpt3xx_tristate (ide_drive_t * drive, int state)
#define TRISTATE_BIT 0x8000
static int hpt370_busproc(ide_drive_t * drive, int state)
{
- ide_hwif_t *hwif = HWIF(drive);
+ struct ata_channel *hwif = drive->channel;
byte tristate, resetmask, bus_reg;
u16 tri_reg;
@@ -960,7 +960,7 @@ static int hpt370_busproc(ide_drive_t * drive, int state)
hwif->bus_state = state;
- if (hwif->channel) {
+ if (hwif->unit) {
/* secondary channel */
tristate = 0x56;
resetmask = 0x80;
@@ -1136,10 +1136,10 @@ unsigned int __init pci_init_hpt366(struct pci_dev *dev)
return dev->irq;
}
-unsigned int __init ata66_hpt366 (ide_hwif_t *hwif)
+unsigned int __init ata66_hpt366(struct ata_channel *hwif)
{
byte ata66 = 0;
- byte regmask = (hwif->channel) ? 0x01 : 0x02;
+ byte regmask = (hwif->unit) ? 0x01 : 0x02;
pci_read_config_byte(hwif->pci_dev, 0x5a, &ata66);
#ifdef DEBUG
@@ -1150,7 +1150,7 @@ unsigned int __init ata66_hpt366 (ide_hwif_t *hwif)
return ((ata66 & regmask) ? 0 : 1);
}
-void __init ide_init_hpt366 (ide_hwif_t *hwif)
+void __init ide_init_hpt366(struct ata_channel *hwif)
{
int hpt_rev;
@@ -1210,12 +1210,12 @@ void __init ide_init_hpt366 (ide_hwif_t *hwif)
#endif /* CONFIG_BLK_DEV_IDEDMA */
}
-void __init ide_dmacapable_hpt366 (ide_hwif_t *hwif, unsigned long dmabase)
+void __init ide_dmacapable_hpt366(struct ata_channel *hwif, unsigned long dmabase)
{
byte masterdma = 0, slavedma = 0;
byte dma_new = 0, dma_old = inb(dmabase+2);
- byte primary = hwif->channel ? 0x4b : 0x43;
- byte secondary = hwif->channel ? 0x4f : 0x47;
+ byte primary = hwif->unit ? 0x4b : 0x43;
+ byte secondary = hwif->unit ? 0x4f : 0x47;
unsigned long flags;
__save_flags(flags); /* local CPU only */
diff --git a/drivers/ide/ht6560b.c b/drivers/ide/ht6560b.c
index 7a71ef13db404..4212382f45d68 100644
--- a/drivers/ide/ht6560b.c
+++ b/drivers/ide/ht6560b.c
@@ -321,7 +321,7 @@ void __init init_ht6560b (void)
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;
+ ide_hwifs[1].unit = 1;
/*
* Setting default configurations for drives
diff --git a/drivers/ide/icside.c b/drivers/ide/icside.c
index 70cb1be2bf715..4b73826053da1 100644
--- a/drivers/ide/icside.c
+++ b/drivers/ide/icside.c
@@ -224,7 +224,7 @@ static iftype_t __init icside_identifyif (struct expansion_card *ec)
#define NR_ENTRIES 256
#define TABLE_SIZE (NR_ENTRIES * 8)
-static int ide_build_sglist(ide_hwif_t *hwif, struct request *rq)
+static int ide_build_sglist(struct ata_channel *hwif, struct request *rq)
{
request_queue_t *q = &hwif->drives[DEVICE_NR(rq->rq_dev) & 1].queue;
struct scatterlist *sg = hwif->sg_table;
@@ -245,16 +245,16 @@ static int ide_build_sglist(ide_hwif_t *hwif, struct request *rq)
static int
icside_build_dmatable(ide_drive_t *drive, int reading)
{
- return HWIF(drive)->sg_nents = ide_build_sglist(HWIF(drive), HWGROUP(drive)->rq);
+ return drive->channel->sg_nents = ide_build_sglist(drive->channel, HWGROUP(drive)->rq);
}
/* Teardown mappings after DMA has completed. */
static void icside_destroy_dmatable(ide_drive_t *drive)
{
- struct scatterlist *sg = HWIF(drive)->sg_table;
- int nents = HWIF(drive)->sg_nents;
+ struct scatterlist *sg = drive->channel->sg_table;
+ int nents = drive->channel->sg_nents;
- pci_unmap_sg(NULL, sg, nents, HWIF(drive)->sg_dma_direction);
+ pci_unmap_sg(NULL, sg, nents, drive->channel->sg_dma_direction);
}
/*
@@ -333,7 +333,7 @@ static ide_startstop_t icside_dmaintr(ide_drive_t *drive)
int i;
byte stat, dma_stat;
- dma_stat = HWIF(drive)->dmaproc(ide_dma_end, drive);
+ dma_stat = drive->channel->dmaproc(ide_dma_end, drive);
stat = GET_STAT(); /* get drive status */
if (OK_STAT(stat,DRIVE_READY,drive->bad_wstat|DRQ_STAT)) {
if (!dma_stat) {
@@ -356,7 +356,7 @@ static int
icside_dma_check(ide_drive_t *drive)
{
struct hd_driveid *id = drive->id;
- ide_hwif_t *hwif = HWIF(drive);
+ struct ata_channel *hwif = drive->channel;
int autodma = hwif->autodma;
int xfer_mode = XFER_PIO_2;
int func = ide_dma_off_quietly;
@@ -397,7 +397,7 @@ icside_dma_verbose(ide_drive_t *drive)
static int
icside_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
{
- ide_hwif_t *hwif = HWIF(drive);
+ struct ata_channel *hwif = drive->channel;
int count, reading = 0;
switch (func) {
@@ -436,14 +436,15 @@ icside_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
*/
set_dma_speed(hwif->hw.dma, drive->drive_data);
- set_dma_sg(hwif->hw.dma, HWIF(drive)->sg_table, count);
+ set_dma_sg(hwif->hw.dma, drive->channel->sg_table, count);
set_dma_mode(hwif->hw.dma, reading ? DMA_MODE_READ
: DMA_MODE_WRITE);
drive->waiting_for_dma = 1;
- if (drive->media != ide_disk)
+ if (drive->type != ATA_DISK)
return 0;
+ BUG_ON(HWGROUP(drive)->handler);
ide_set_handler(drive, &icside_dmaintr, WAIT_CMD, NULL);
OUT_BYTE(reading ? WIN_READDMA : WIN_WRITEDMA,
IDE_COMMAND_REG);
@@ -473,7 +474,7 @@ icside_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
}
static int
-icside_setup_dma(ide_hwif_t *hwif, int autodma)
+icside_setup_dma(struct ata_channel *hwif, int autodma)
{
printk(" %s: SG-DMA", hwif->name);
@@ -498,7 +499,7 @@ failed:
return 0;
}
-void ide_release_dma(ide_hwif_t *hwif)
+void ide_release_dma(struct ata_channel *hwif)
{
if (hwif->sg_table) {
kfree(hwif->sg_table);
@@ -507,10 +508,10 @@ void ide_release_dma(ide_hwif_t *hwif)
}
#endif
-static ide_hwif_t *
+static struct ata_channel *
icside_find_hwif(unsigned long dataport)
{
- ide_hwif_t *hwif;
+ struct ata_channel *hwif;
int index;
for (index = 0; index < MAX_HWIFS; ++index) {
@@ -530,11 +531,11 @@ found:
return hwif;
}
-static ide_hwif_t *
+static struct ata_channel *
icside_setup(unsigned long base, struct cardinfo *info, int irq)
{
unsigned long port = base + info->dataoffset;
- ide_hwif_t *hwif;
+ struct ata_channel *hwif;
hwif = icside_find_hwif(base);
if (hwif) {
@@ -562,7 +563,7 @@ icside_setup(unsigned long base, struct cardinfo *info, int irq)
static int __init icside_register_v5(struct expansion_card *ec, int autodma)
{
unsigned long slot_port;
- ide_hwif_t *hwif;
+ struct ata_channel *hwif;
slot_port = ecard_address(ec, ECARD_MEMC, 0);
@@ -584,7 +585,8 @@ static int __init icside_register_v5(struct expansion_card *ec, int autodma)
static int __init icside_register_v6(struct expansion_card *ec, int autodma)
{
unsigned long slot_port, port;
- ide_hwif_t *hwif, *mate;
+ struct ata_channel *hwif;
+ struct ata_channel *mate;
int sel = 0;
slot_port = ecard_address(ec, ECARD_IOC, ECARD_FAST);
@@ -620,7 +622,7 @@ static int __init icside_register_v6(struct expansion_card *ec, int autodma)
hwif->hw.dma = ec->dma;
hwif->hw.priv = (void *)
(port + ICS_ARCIN_V6_INTRSTAT_1);
- hwif->channel = 0;
+ hwif->unit = 0;
icside_setup_dma(hwif, autodma);
}
if (mate) {
@@ -629,7 +631,7 @@ static int __init icside_register_v6(struct expansion_card *ec, int autodma)
mate->hw.dma = ec->dma;
mate->hw.priv = (void *)
(port + ICS_ARCIN_V6_INTRSTAT_2);
- mate->channel = 1;
+ mate->unit = 1;
icside_setup_dma(mate, autodma);
}
}
diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c
index c0b2d7057be04..e5ab895df4d05 100644
--- a/drivers/ide/ide-cd.c
+++ b/drivers/ide/ide-cd.c
@@ -723,9 +723,9 @@ static ide_startstop_t cdrom_start_packet_command(ide_drive_t *drive,
if (info->dma) {
if (info->cmd == READ) {
- info->dma = !HWIF(drive)->dmaproc(ide_dma_read, drive);
+ info->dma = !drive->channel->dmaproc(ide_dma_read, drive);
} else if (info->cmd == WRITE) {
- info->dma = !HWIF(drive)->dmaproc(ide_dma_write, drive);
+ info->dma = !drive->channel->dmaproc(ide_dma_write, drive);
} else {
printk("ide-cd: DMA set, but not allowed\n");
}
@@ -740,11 +740,12 @@ static ide_startstop_t cdrom_start_packet_command(ide_drive_t *drive,
OUT_BYTE (xferlen >> 8 , IDE_HCYL_REG);
if (IDE_CONTROL_REG)
OUT_BYTE (drive->ctl, IDE_CONTROL_REG);
-
+
if (info->dma)
- (void) (HWIF(drive)->dmaproc(ide_dma_begin, drive));
+ (void) drive->channel->dmaproc(ide_dma_begin, drive);
if (CDROM_CONFIG_FLAGS (drive)->drq_interrupt) {
+ BUG_ON(HWGROUP(drive)->handler);
ide_set_handler (drive, handler, WAIT_CMD, cdrom_timer_expiry);
OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG); /* packet command */
return ide_started;
@@ -787,6 +788,7 @@ static ide_startstop_t cdrom_transfer_packet_command (ide_drive_t *drive,
}
/* Arm the interrupt handler. */
+ BUG_ON(HWGROUP(drive)->handler);
ide_set_handler (drive, handler, timeout, cdrom_timer_expiry);
/* Send the command to the device. */
@@ -899,8 +901,8 @@ static ide_startstop_t cdrom_read_intr (ide_drive_t *drive)
/* Check for errors. */
if (dma) {
info->dma = 0;
- if ((dma_error = HWIF(drive)->dmaproc(ide_dma_end, drive)))
- HWIF(drive)->dmaproc(ide_dma_off, drive);
+ if ((dma_error = drive->channel->dmaproc(ide_dma_end, drive)))
+ drive->channel->dmaproc(ide_dma_off, drive);
}
if (cdrom_decode_status (&startstop, drive, 0, &stat))
@@ -1005,7 +1007,9 @@ static ide_startstop_t cdrom_read_intr (ide_drive_t *drive)
/* Done moving data!
Wait for another interrupt. */
+ BUG_ON(HWGROUP(drive)->handler);
ide_set_handler(drive, &cdrom_read_intr, WAIT_CMD, NULL);
+
return ide_started;
}
@@ -1335,6 +1339,8 @@ static ide_startstop_t cdrom_pc_intr (ide_drive_t *drive)
}
/* Now we wait for another interrupt. */
+
+ BUG_ON(HWGROUP(drive)->handler);
ide_set_handler (drive, &cdrom_pc_intr, WAIT_CMD, cdrom_timer_expiry);
return ide_started;
}
@@ -1476,9 +1482,9 @@ static ide_startstop_t cdrom_write_intr(ide_drive_t *drive)
/* Check for errors. */
if (dma) {
info->dma = 0;
- if ((dma_error = HWIF(drive)->dmaproc(ide_dma_end, drive))) {
+ if ((dma_error = drive->channel->dmaproc(ide_dma_end, drive))) {
printk("ide-cd: write dma error\n");
- HWIF(drive)->dmaproc(ide_dma_off, drive);
+ drive->channel->dmaproc(ide_dma_off, drive);
}
}
@@ -1559,6 +1565,7 @@ static ide_startstop_t cdrom_write_intr(ide_drive_t *drive)
}
/* re-arm handler */
+ BUG_ON(HWGROUP(drive)->handler);
ide_set_handler(drive, &cdrom_write_intr, 5 * WAIT_CMD, NULL);
return ide_started;
}
@@ -2021,14 +2028,14 @@ static int cdrom_read_toc(ide_drive_t *drive, struct request_sense *sense)
/* Now try to get the total cdrom capacity. */
minor = (drive->select.b.unit) << PARTN_BITS;
- dev = mk_kdev(HWIF(drive)->major, minor);
+ dev = mk_kdev(drive->channel->major, minor);
stat = cdrom_get_last_written(dev, &toc->capacity);
if (stat)
stat = cdrom_read_capacity(drive, &toc->capacity, sense);
if (stat)
toc->capacity = 0x1fffff;
- HWIF(drive)->gd->sizes[drive->select.b.unit << PARTN_BITS] = (toc->capacity * SECTORS_PER_FRAME) >> (BLOCK_SIZE_BITS - 9);
+ drive->channel->gd->sizes[drive->select.b.unit << PARTN_BITS] = (toc->capacity * SECTORS_PER_FRAME) >> (BLOCK_SIZE_BITS - 9);
drive->part[0].nr_sects = toc->capacity * SECTORS_PER_FRAME;
/* Remember that we've read this stuff. */
@@ -2487,7 +2494,7 @@ static int ide_cdrom_register (ide_drive_t *drive, int nslots)
struct cdrom_device_info *devinfo = &info->devinfo;
int minor = (drive->select.b.unit) << PARTN_BITS;
- devinfo->dev = mk_kdev(HWIF(drive)->major, minor);
+ devinfo->dev = mk_kdev(drive->channel->major, minor);
devinfo->ops = &ide_cdrom_dops;
devinfo->mask = 0;
*(int *)&devinfo->speed = CDROM_STATE_FLAGS (drive)->current_speed;
@@ -2519,7 +2526,7 @@ static int ide_cdrom_register (ide_drive_t *drive, int nslots)
*/
devinfo->de = devfs_register(drive->de, "cd", DEVFS_FL_DEFAULT,
- HWIF(drive)->major, minor,
+ drive->channel->major, minor,
S_IFBLK | S_IRUGO | S_IWUGO,
ide_fops, NULL);
@@ -2661,7 +2668,7 @@ int ide_cdrom_probe_capabilities (ide_drive_t *drive)
#ifdef CONFIG_BLK_DEV_IDEDMA
if (drive->using_dma)
- (void) HWIF(drive)->dmaproc(ide_dma_verbose, drive);
+ (void) drive->channel->dmaproc(ide_dma_verbose, drive);
#endif /* CONFIG_BLK_DEV_IDEDMA */
printk("\n");
@@ -2684,8 +2691,8 @@ int ide_cdrom_setup (ide_drive_t *drive)
/*
* default to read-only always and fix latter at the bottom
*/
- set_device_ro(mk_kdev(HWIF(drive)->major, minor), 1);
- set_blocksize(mk_kdev(HWIF(drive)->major, minor), CD_FRAMESIZE);
+ set_device_ro(mk_kdev(drive->channel->major, minor), 1);
+ set_blocksize(mk_kdev(drive->channel->major, minor), CD_FRAMESIZE);
blk_queue_hardsect_size(&drive->queue, CD_FRAMESIZE);
blk_queue_prep_rq(&drive->queue, ll_10byte_cmd_build);
@@ -2807,7 +2814,7 @@ int ide_cdrom_setup (ide_drive_t *drive)
nslots = ide_cdrom_probe_capabilities (drive);
if (CDROM_CONFIG_FLAGS(drive)->dvd_ram)
- set_device_ro(mk_kdev(HWIF(drive)->major, minor), 0);
+ set_device_ro(mk_kdev(drive->channel->major, minor), 0);
if (ide_cdrom_register (drive, nslots)) {
printk ("%s: ide_cdrom_setup failed to register device with the cdrom driver.\n", drive->name);
@@ -2854,7 +2861,7 @@ void ide_cdrom_release (struct inode *inode, struct file *file,
static
int ide_cdrom_check_media_change (ide_drive_t *drive)
{
- return cdrom_media_changed(mk_kdev (HWIF (drive)->major,
+ return cdrom_media_changed(mk_kdev (drive->channel->major,
(drive->select.b.unit) << PARTN_BITS));
}
@@ -2875,14 +2882,14 @@ void ide_cdrom_revalidate (ide_drive_t *drive)
/* for general /dev/cdrom like mounting, one big disc */
drive->part[0].nr_sects = toc->capacity * SECTORS_PER_FRAME;
- HWIF(drive)->gd->sizes[minor] = toc->capacity * BLOCKS_PER_FRAME;
+ drive->channel->gd->sizes[minor] = toc->capacity * BLOCKS_PER_FRAME;
/*
* reset block size, ide_revalidate_disk incorrectly sets it to
* 1024 even for CDROM's
*/
- blk_size[HWIF(drive)->major] = HWIF(drive)->gd->sizes;
- set_blocksize(mk_kdev(HWIF(drive)->major, minor), CD_FRAMESIZE);
+ blk_size[drive->channel->major] = drive->channel->gd->sizes;
+ set_blocksize(mk_kdev(drive->channel->major, minor), CD_FRAMESIZE);
}
static
@@ -2984,15 +2991,14 @@ int ide_cdrom_init(void)
memset (info, 0, sizeof (struct cdrom_info));
drive->driver_data = info;
- /* ATA-PATTERN */
- ata_ops(drive)->busy++;
+ MOD_INC_USE_COUNT;
if (ide_cdrom_setup (drive)) {
- ata_ops(drive)->busy--;
+ MOD_DEC_USE_COUNT;
if (ide_cdrom_cleanup (drive))
printk ("%s: ide_cdrom_cleanup failed in ide_cdrom_init\n", drive->name);
continue;
}
- ata_ops(drive)->busy--;
+ MOD_DEC_USE_COUNT;
failed--;
}
diff --git a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c
index 5f598354bd6a2..7a721387251dc 100644
--- a/drivers/ide/ide-disk.c
+++ b/drivers/ide/ide-disk.c
@@ -51,7 +51,7 @@
#include <asm/io.h>
#ifdef CONFIG_BLK_DEV_PDC4030
-#define IS_PDC4030_DRIVE (HWIF(drive)->chipset == ide_pdc4030)
+#define IS_PDC4030_DRIVE (drive->channel->chipset == ide_pdc4030)
#else
#define IS_PDC4030_DRIVE (0) /* auto-NULLs out pdc4030 code */
#endif
@@ -106,51 +106,7 @@ static int lba_capacity_is_ok (struct hd_driveid *id)
return 0; /* lba_capacity value may be bad */
}
-static ide_startstop_t chs_do_request(ide_drive_t *drive, struct request *rq, unsigned long block);
-static ide_startstop_t lba28_do_request(ide_drive_t *drive, struct request *rq, unsigned long block);
-static ide_startstop_t lba48_do_request(ide_drive_t *drive, struct request *rq, unsigned long long block);
-
-/*
- * Issue a READ or WRITE command to a disk, using LBA if supported, or CHS
- * otherwise, to address sectors. It also takes care of issuing special
- * DRIVE_CMDs.
- */
-static ide_startstop_t idedisk_do_request(ide_drive_t *drive, struct request *rq, unsigned long block)
-{
- /*
- * Wait until all request have bin finished.
- */
-
- while (drive->blocked) {
- yield();
- // panic("ide: Request while drive blocked?");
- }
-
- if (!(rq->flags & REQ_CMD)) {
- blk_dump_rq_flags(rq, "idedisk_do_request - bad command");
- ide_end_request(drive, 0);
- return ide_stopped;
- }
-
- if (IS_PDC4030_DRIVE) {
- extern ide_startstop_t promise_rw_disk(ide_drive_t *, struct request *, unsigned long);
-
- return promise_rw_disk(drive, rq, block);
- }
-
- /* 48-bit LBA */
- if ((drive->id->cfs_enable_2 & 0x0400) && (drive->addressing))
- return lba48_do_request(drive, rq, block);
-
- /* 28-bit LBA */
- if (drive->select.b.lba)
- return lba28_do_request(drive, rq, block);
-
- /* 28-bit CHS */
- return chs_do_request(drive, rq, block);
-}
-
-static task_ioreg_t get_command(ide_drive_t *drive, int cmd)
+static u8 get_command(ide_drive_t *drive, int cmd)
{
int lba48bit = (drive->id->cfs_enable_2 & 0x0400) ? 1 : 0;
@@ -158,20 +114,38 @@ static task_ioreg_t get_command(ide_drive_t *drive, int cmd)
lba48bit = drive->addressing;
#endif
- if (cmd == READ) {
- if (drive->using_dma)
- return (lba48bit) ? WIN_READDMA_EXT : WIN_READDMA;
- else if (drive->mult_count)
- return (lba48bit) ? WIN_MULTREAD_EXT : WIN_MULTREAD;
- else
- return (lba48bit) ? WIN_READ_EXT : WIN_READ;
- } else if (cmd == WRITE) {
- if (drive->using_dma)
- return (lba48bit) ? WIN_WRITEDMA_EXT : WIN_WRITEDMA;
- else if (drive->mult_count)
- return (lba48bit) ? WIN_MULTWRITE_EXT : WIN_MULTWRITE;
- else
- return (lba48bit) ? WIN_WRITE_EXT : WIN_WRITE;
+ if (lba48bit) {
+ if (cmd == READ) {
+ if (drive->using_dma)
+ return WIN_READDMA_EXT;
+ else if (drive->mult_count)
+ return WIN_MULTREAD_EXT;
+ else
+ return WIN_READ_EXT;
+ } else if (cmd == WRITE) {
+ if (drive->using_dma)
+ return WIN_WRITEDMA_EXT;
+ else if (drive->mult_count)
+ return WIN_MULTWRITE_EXT;
+ else
+ return WIN_WRITE_EXT;
+ }
+ } else {
+ if (cmd == READ) {
+ if (drive->using_dma)
+ return WIN_READDMA;
+ else if (drive->mult_count)
+ return WIN_MULTREAD;
+ else
+ return WIN_READ;
+ } else if (cmd == WRITE) {
+ if (drive->using_dma)
+ return WIN_WRITEDMA;
+ else if (drive->mult_count)
+ return WIN_MULTWRITE;
+ else
+ return WIN_WRITE;
+ }
}
return WIN_NOP;
}
@@ -183,27 +157,27 @@ static ide_startstop_t chs_do_request(ide_drive_t *drive, struct request *rq, un
ide_task_t args;
int sectors;
- task_ioreg_t command = get_command(drive, rq_data_dir(rq));
-
unsigned int track = (block / drive->sect);
unsigned int sect = (block % drive->sect) + 1;
unsigned int head = (track % drive->head);
unsigned int cyl = (track / drive->head);
- memset(&taskfile, 0, sizeof(task_struct_t));
- memset(&hobfile, 0, sizeof(hob_struct_t));
+ memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
+ memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
sectors = rq->nr_sectors;
if (sectors == 256)
sectors = 0;
taskfile.sector_count = sectors;
+
taskfile.sector_number = sect;
taskfile.low_cylinder = cyl;
taskfile.high_cylinder = (cyl>>8);
+
taskfile.device_head = head;
taskfile.device_head |= drive->select.all;
- taskfile.command = command;
+ taskfile.command = get_command(drive, rq_data_dir(rq));
#ifdef DEBUG
printk("%s: %sing: ", drive->name,
@@ -214,14 +188,17 @@ static ide_startstop_t chs_do_request(ide_drive_t *drive, struct request *rq, un
printk("buffer=0x%08lx\n", (unsigned long) rq->buffer);
#endif
- memcpy(args.tfRegister, &taskfile, sizeof(struct hd_drive_task_hdr));
- memcpy(args.hobRegister, &hobfile, sizeof(struct hd_drive_hob_hdr));
+ args.taskfile = taskfile;
+ args.hobfile = hobfile;
ide_cmd_type_parser(&args);
- args.rq = rq;
- args.block = block;
rq->special = &args;
- return do_rw_taskfile(drive, &args);
+ return ata_taskfile(drive,
+ &args.taskfile,
+ &args.hobfile,
+ args.handler,
+ args.prehandler,
+ rq);
}
static ide_startstop_t lba28_do_request(ide_drive_t *drive, struct request *rq, unsigned long block)
@@ -231,22 +208,22 @@ static ide_startstop_t lba28_do_request(ide_drive_t *drive, struct request *rq,
ide_task_t args;
int sectors;
- task_ioreg_t command = get_command(drive, rq_data_dir(rq));
-
sectors = rq->nr_sectors;
if (sectors == 256)
sectors = 0;
- memset(&taskfile, 0, sizeof(task_struct_t));
- memset(&hobfile, 0, sizeof(hob_struct_t));
+ memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
+ memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
taskfile.sector_count = sectors;
taskfile.sector_number = block;
- taskfile.low_cylinder = (block>>=8);
- taskfile.high_cylinder = (block>>=8);
- taskfile.device_head = ((block>>8)&0x0f);
+ taskfile.low_cylinder = (block >>= 8);
+
+ taskfile.high_cylinder = (block >>= 8);
+
+ taskfile.device_head = ((block >> 8) & 0x0f);
taskfile.device_head |= drive->select.all;
- taskfile.command = command;
+ taskfile.command = get_command(drive, rq_data_dir(rq));
#ifdef DEBUG
printk("%s: %sing: ", drive->name,
@@ -257,14 +234,17 @@ static ide_startstop_t lba28_do_request(ide_drive_t *drive, struct request *rq,
printk("buffer=0x%08lx\n", (unsigned long) rq->buffer);
#endif
- memcpy(args.tfRegister, &taskfile, sizeof(struct hd_drive_task_hdr));
- memcpy(args.hobRegister, &hobfile, sizeof(struct hd_drive_hob_hdr));
+ args.taskfile = taskfile;
+ args.hobfile = hobfile;
ide_cmd_type_parser(&args);
- args.rq = rq;
- args.block = block;
rq->special = &args;
- return do_rw_taskfile(drive, &args);
+ return ata_taskfile(drive,
+ &args.taskfile,
+ &args.hobfile,
+ args.handler,
+ args.prehandler,
+ rq);
}
/*
@@ -280,10 +260,8 @@ static ide_startstop_t lba48_do_request(ide_drive_t *drive, struct request *rq,
ide_task_t args;
int sectors;
- task_ioreg_t command = get_command(drive, rq_data_dir(rq));
-
- memset(&taskfile, 0, sizeof(task_struct_t));
- memset(&hobfile, 0, sizeof(hob_struct_t));
+ memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
+ memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
sectors = rq->nr_sectors;
if (sectors == 65536)
@@ -297,16 +275,18 @@ static ide_startstop_t lba48_do_request(ide_drive_t *drive, struct request *rq,
hobfile.sector_count = 0x00;
}
- taskfile.sector_number = block; /* low lba */
- taskfile.low_cylinder = (block>>=8); /* mid lba */
- taskfile.high_cylinder = (block>>=8); /* hi lba */
- hobfile.sector_number = (block>>=8); /* low lba */
- hobfile.low_cylinder = (block>>=8); /* mid lba */
- hobfile.high_cylinder = (block>>=8); /* hi lba */
+ taskfile.sector_number = block; /* low lba */
+ taskfile.low_cylinder = (block >>= 8); /* mid lba */
+ taskfile.high_cylinder = (block >>= 8); /* hi lba */
+
+ hobfile.sector_number = (block >>= 8); /* low lba */
+ hobfile.low_cylinder = (block >>= 8); /* mid lba */
+ hobfile.high_cylinder = (block >>= 8); /* hi lba */
+
taskfile.device_head = drive->select.all;
hobfile.device_head = taskfile.device_head;
hobfile.control = (drive->ctl|0x80);
- taskfile.command = command;
+ taskfile.command = get_command(drive, rq_data_dir(rq));
#ifdef DEBUG
printk("%s: %sing: ", drive->name,
@@ -317,14 +297,57 @@ static ide_startstop_t lba48_do_request(ide_drive_t *drive, struct request *rq,
printk("buffer=0x%08lx\n", (unsigned long) rq->buffer);
#endif
- memcpy(args.tfRegister, &taskfile, sizeof(struct hd_drive_task_hdr));
- memcpy(args.hobRegister, &hobfile, sizeof(struct hd_drive_hob_hdr));
+ args.taskfile = taskfile;
+ args.hobfile = hobfile;
ide_cmd_type_parser(&args);
- args.rq = rq;
- args.block = block;
rq->special = &args;
- return do_rw_taskfile(drive, &args);
+ return ata_taskfile(drive,
+ &args.taskfile,
+ &args.hobfile,
+ args.handler,
+ args.prehandler,
+ rq);
+}
+
+/*
+ * Issue a READ or WRITE command to a disk, using LBA if supported, or CHS
+ * otherwise, to address sectors. It also takes care of issuing special
+ * DRIVE_CMDs.
+ */
+static ide_startstop_t idedisk_do_request(ide_drive_t *drive, struct request *rq, unsigned long block)
+{
+ /*
+ * Wait until all request have bin finished.
+ */
+
+ while (drive->blocked) {
+ yield();
+ printk("ide: Request while drive blocked?");
+ }
+
+ if (!(rq->flags & REQ_CMD)) {
+ blk_dump_rq_flags(rq, "idedisk_do_request - bad command");
+ ide_end_request(drive, 0);
+ return ide_stopped;
+ }
+
+ if (IS_PDC4030_DRIVE) {
+ extern ide_startstop_t promise_rw_disk(ide_drive_t *, struct request *, unsigned long);
+
+ return promise_rw_disk(drive, rq, block);
+ }
+
+ /* 48-bit LBA */
+ if ((drive->id->cfs_enable_2 & 0x0400) && (drive->addressing))
+ return lba48_do_request(drive, rq, block);
+
+ /* 28-bit LBA */
+ if (drive->select.b.lba)
+ return lba28_do_request(drive, rq, block);
+
+ /* 28-bit CHS */
+ return chs_do_request(drive, rq, block);
}
static int idedisk_open (struct inode *inode, struct file *filp, ide_drive_t *drive)
@@ -333,10 +356,14 @@ static int idedisk_open (struct inode *inode, struct file *filp, ide_drive_t *dr
if (drive->removable && drive->usage == 1) {
struct hd_drive_task_hdr taskfile;
struct hd_drive_hob_hdr hobfile;
+
memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
+
check_disk_change(inode->i_rdev);
+
taskfile.command = WIN_DOORLOCK;
+
/*
* Ignore the return code from door_lock,
* since the open() has already succeeded,
@@ -353,13 +380,14 @@ static int idedisk_flushcache(ide_drive_t *drive)
{
struct hd_drive_task_hdr taskfile;
struct hd_drive_hob_hdr hobfile;
+
memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
- if (drive->id->cfs_enable_2 & 0x2400) {
- taskfile.command = WIN_FLUSH_CACHE_EXT;
- } else {
- taskfile.command = WIN_FLUSH_CACHE;
- }
+ if (drive->id->cfs_enable_2 & 0x2400)
+ taskfile.command = WIN_FLUSH_CACHE_EXT;
+ else
+ taskfile.command = WIN_FLUSH_CACHE;
+
return ide_wait_taskfile(drive, &taskfile, &hobfile, NULL);
}
@@ -368,9 +396,12 @@ static void idedisk_release (struct inode *inode, struct file *filp, ide_drive_t
if (drive->removable && !drive->usage) {
struct hd_drive_task_hdr taskfile;
struct hd_drive_hob_hdr hobfile;
+
memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
+
invalidate_bdev(inode->i_bdev, 0);
+
taskfile.command = WIN_DOORUNLOCK;
if (drive->doorlocking &&
ide_wait_taskfile(drive, &taskfile, &hobfile, NULL))
@@ -404,21 +435,23 @@ static unsigned long idedisk_read_native_max_address(ide_drive_t *drive)
/* Create IDE/ATA command request structure */
memset(&args, 0, sizeof(ide_task_t));
- args.tfRegister[IDE_SELECT_OFFSET] = 0x40;
- args.tfRegister[IDE_COMMAND_OFFSET] = WIN_READ_NATIVE_MAX;
- args.handler = task_no_data_intr;
+ args.taskfile.device_head = 0x40;
+ args.taskfile.command = WIN_READ_NATIVE_MAX;
+ args.handler = task_no_data_intr;
/* submit command request */
ide_raw_taskfile(drive, &args, NULL);
/* if OK, compute maximum address value */
- if ((args.tfRegister[IDE_STATUS_OFFSET] & 0x01) == 0) {
- addr = ((args.tfRegister[IDE_SELECT_OFFSET] & 0x0f) << 24)
- | ((args.tfRegister[ IDE_HCYL_OFFSET] ) << 16)
- | ((args.tfRegister[ IDE_LCYL_OFFSET] ) << 8)
- | ((args.tfRegister[IDE_SECTOR_OFFSET] ));
+ if ((args.taskfile.command & 0x01) == 0) {
+ addr = ((args.taskfile.device_head & 0x0f) << 24)
+ | (args.taskfile.high_cylinder << 16)
+ | (args.taskfile.low_cylinder << 8)
+ | args.taskfile.sector_number;
}
+
addr++; /* since the return value is (maxlba - 1), we add 1 */
+
return addr;
}
@@ -430,24 +463,26 @@ static unsigned long long idedisk_read_native_max_address_ext(ide_drive_t *drive
/* Create IDE/ATA command request structure */
memset(&args, 0, sizeof(ide_task_t));
- args.tfRegister[IDE_SELECT_OFFSET] = 0x40;
- args.tfRegister[IDE_COMMAND_OFFSET] = WIN_READ_NATIVE_MAX_EXT;
- args.handler = task_no_data_intr;
+ args.taskfile.device_head = 0x40;
+ args.taskfile.command = WIN_READ_NATIVE_MAX_EXT;
+ args.handler = task_no_data_intr;
/* submit command request */
ide_raw_taskfile(drive, &args, NULL);
/* if OK, compute maximum address value */
- if ((args.tfRegister[IDE_STATUS_OFFSET] & 0x01) == 0) {
- u32 high = ((args.hobRegister[IDE_HCYL_OFFSET_HOB])<<16) |
- ((args.hobRegister[IDE_LCYL_OFFSET_HOB])<<8) |
- (args.hobRegister[IDE_SECTOR_OFFSET_HOB]);
- u32 low = ((args.tfRegister[IDE_HCYL_OFFSET])<<16) |
- ((args.tfRegister[IDE_LCYL_OFFSET])<<8) |
- (args.tfRegister[IDE_SECTOR_OFFSET]);
+ if ((args.taskfile.command & 0x01) == 0) {
+ u32 high = (args.hobfile.high_cylinder << 16) |
+ (args.hobfile.low_cylinder << 8) |
+ args.hobfile.sector_number;
+ u32 low = (args.taskfile.high_cylinder << 16) |
+ (args.taskfile.low_cylinder << 8) |
+ args.taskfile.sector_number;
addr = ((__u64)high << 24) | low;
}
+
addr++; /* since the return value is (maxlba - 1), we add 1 */
+
return addr;
}
@@ -464,20 +499,22 @@ static unsigned long idedisk_set_max_address(ide_drive_t *drive, unsigned long a
addr_req--;
/* Create IDE/ATA command request structure */
memset(&args, 0, sizeof(ide_task_t));
- args.tfRegister[IDE_SECTOR_OFFSET] = ((addr_req >> 0) & 0xff);
- args.tfRegister[IDE_LCYL_OFFSET] = ((addr_req >> 8) & 0xff);
- args.tfRegister[IDE_HCYL_OFFSET] = ((addr_req >> 16) & 0xff);
- args.tfRegister[IDE_SELECT_OFFSET] = ((addr_req >> 24) & 0x0f) | 0x40;
- args.tfRegister[IDE_COMMAND_OFFSET] = WIN_SET_MAX;
- args.handler = task_no_data_intr;
+
+ args.taskfile.sector_number = (addr_req >> 0);
+ args.taskfile.low_cylinder = (addr_req >> 8);
+ args.taskfile.high_cylinder = (addr_req >> 16);
+
+ args.taskfile.device_head = ((addr_req >> 24) & 0x0f) | 0x40;
+ args.taskfile.command = WIN_SET_MAX;
+ args.handler = task_no_data_intr;
/* submit command request */
ide_raw_taskfile(drive, &args, NULL);
/* if OK, read new maximum address value */
- if ((args.tfRegister[IDE_STATUS_OFFSET] & 0x01) == 0) {
- addr_set = ((args.tfRegister[IDE_SELECT_OFFSET] & 0x0f) << 24)
- | ((args.tfRegister[ IDE_HCYL_OFFSET] ) << 16)
- | ((args.tfRegister[ IDE_LCYL_OFFSET] ) << 8)
- | ((args.tfRegister[IDE_SECTOR_OFFSET] ));
+ if ((args.taskfile.command & 0x01) == 0) {
+ addr_set = ((args.taskfile.device_head & 0x0f) << 24)
+ | (args.taskfile.high_cylinder << 16)
+ | (args.taskfile.low_cylinder << 8)
+ | args.taskfile.sector_number;
}
addr_set++;
return addr_set;
@@ -491,27 +528,31 @@ static unsigned long long idedisk_set_max_address_ext(ide_drive_t *drive, unsign
addr_req--;
/* Create IDE/ATA command request structure */
memset(&args, 0, sizeof(ide_task_t));
- args.tfRegister[IDE_SECTOR_OFFSET] = ((addr_req >> 0) & 0xff);
- args.tfRegister[IDE_LCYL_OFFSET] = ((addr_req >>= 8) & 0xff);
- args.tfRegister[IDE_HCYL_OFFSET] = ((addr_req >>= 8) & 0xff);
- args.tfRegister[IDE_SELECT_OFFSET] = 0x40;
- args.tfRegister[IDE_COMMAND_OFFSET] = WIN_SET_MAX_EXT;
- args.hobRegister[IDE_SECTOR_OFFSET_HOB] = ((addr_req >>= 8) & 0xff);
- args.hobRegister[IDE_LCYL_OFFSET_HOB] = ((addr_req >>= 8) & 0xff);
- args.hobRegister[IDE_HCYL_OFFSET_HOB] = ((addr_req >>= 8) & 0xff);
- args.hobRegister[IDE_SELECT_OFFSET_HOB] = 0x40;
- args.hobRegister[IDE_CONTROL_OFFSET_HOB]= (drive->ctl|0x80);
- args.handler = task_no_data_intr;
+
+ args.taskfile.sector_number = (addr_req >> 0);
+ args.taskfile.low_cylinder = (addr_req >>= 8);
+ args.taskfile.high_cylinder = (addr_req >>= 8);
+ args.taskfile.device_head = 0x40;
+ args.taskfile.command = WIN_SET_MAX_EXT;
+
+ args.hobfile.sector_number = (addr_req >>= 8);
+ args.hobfile.low_cylinder = (addr_req >>= 8);
+ args.hobfile.high_cylinder = (addr_req >>= 8);
+
+ args.hobfile.device_head = 0x40;
+ args.hobfile.control = (drive->ctl | 0x80);
+
+ args.handler = task_no_data_intr;
/* submit command request */
ide_raw_taskfile(drive, &args, NULL);
/* if OK, compute maximum address value */
- if ((args.tfRegister[IDE_STATUS_OFFSET] & 0x01) == 0) {
- u32 high = ((args.hobRegister[IDE_HCYL_OFFSET_HOB])<<16) |
- ((args.hobRegister[IDE_LCYL_OFFSET_HOB])<<8) |
- (args.hobRegister[IDE_SECTOR_OFFSET_HOB]);
- u32 low = ((args.tfRegister[IDE_HCYL_OFFSET])<<16) |
- ((args.tfRegister[IDE_LCYL_OFFSET])<<8) |
- (args.tfRegister[IDE_SECTOR_OFFSET]);
+ if ((args.taskfile.command & 0x01) == 0) {
+ u32 high = (args.hobfile.high_cylinder << 16) |
+ (args.hobfile.low_cylinder << 8) |
+ args.hobfile.sector_number;
+ u32 low = (args.taskfile.high_cylinder << 16) |
+ (args.taskfile.low_cylinder << 8) |
+ args.taskfile.sector_number;
addr_set = ((__u64)high << 24) | low;
}
return addr_set;
@@ -572,10 +613,10 @@ static void init_idedisk_capacity (ide_drive_t *drive)
drive->select.b.lba = 1;
drive->id->lba_capacity_2 = capacity_2;
}
-#else /* !CONFIG_IDEDISK_STROKE */
+#else
printk("%s: setmax_ext LBA %llu, native %llu\n",
drive->name, set_max_ext, capacity_2);
-#endif /* CONFIG_IDEDISK_STROKE */
+#endif
}
drive->bios_cyl = drive->cyl;
drive->capacity48 = capacity_2;
@@ -598,10 +639,10 @@ static void init_idedisk_capacity (ide_drive_t *drive)
drive->select.b.lba = 1;
drive->id->lba_capacity = capacity;
}
-#else /* !CONFIG_IDEDISK_STROKE */
+#else
printk("%s: setmax LBA %lu, native %lu\n",
drive->name, set_max, capacity);
-#endif /* CONFIG_IDEDISK_STROKE */
+#endif
}
drive->capacity = capacity;
@@ -643,7 +684,7 @@ static ide_startstop_t idedisk_special (ide_drive_t *drive)
taskfile.command = WIN_SPECIFY;
handler = set_geometry_intr;;
}
- do_taskfile(drive, &taskfile, &hobfile, handler);
+ ata_taskfile(drive, &taskfile, &hobfile, handler, NULL, NULL);
} else if (s->b.recalibrate) {
s->b.recalibrate = 0;
if (!IS_PDC4030_DRIVE) {
@@ -653,7 +694,7 @@ static ide_startstop_t idedisk_special (ide_drive_t *drive)
memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
taskfile.sector_count = drive->sect;
taskfile.command = WIN_RESTORE;
- do_taskfile(drive, &taskfile, &hobfile, recal_intr);
+ ata_taskfile(drive, &taskfile, &hobfile, recal_intr, NULL, NULL);
}
} else if (s->b.set_multmode) {
s->b.set_multmode = 0;
@@ -666,7 +707,7 @@ static ide_startstop_t idedisk_special (ide_drive_t *drive)
memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
taskfile.sector_count = drive->mult_req;
taskfile.command = WIN_SETMULT;
- do_taskfile(drive, &taskfile, &hobfile, &set_multmode_intr);
+ ata_taskfile(drive, &taskfile, &hobfile, set_multmode_intr, NULL, NULL);
}
} else if (s->all) {
int special = s->all;
@@ -915,6 +956,9 @@ static int idedisk_suspend(struct device *dev, u32 state, u32 level)
* already been done...
*/
+ if (level != SUSPEND_SAVE_STATE)
+ return 0;
+
/* wait until all commands are finished */
printk("ide_disk_suspend()\n");
while (HWGROUP(drive)->handler)
@@ -934,6 +978,9 @@ static int idedisk_suspend(struct device *dev, u32 state, u32 level)
static int idedisk_resume(struct device *dev, u32 level)
{
ide_drive_t *drive = dev->driver_data;
+
+ if (level != RESUME_RESTORE_STATE)
+ return 0;
if (!drive->blocked)
panic("ide: Resume but not suspended?\n");
@@ -979,7 +1026,7 @@ static void idedisk_setup(ide_drive_t *drive)
}
}
for (i = 0; i < MAX_DRIVES; ++i) {
- ide_hwif_t *hwif = HWIF(drive);
+ struct ata_channel *hwif = drive->channel;
if (drive != &hwif->drives[i])
continue;
@@ -997,7 +1044,7 @@ static void idedisk_setup(ide_drive_t *drive)
sprintf(drive->device.bus_id, "%d", drvid);
sprintf(drive->device.name, "ide-disk");
drive->device.driver = &idedisk_devdrv;
- drive->device.parent = &HWIF(drive)->device;
+ drive->device.parent = &drive->channel->dev;
drive->device.driver_data = drive;
device_register(&drive->device);
}
@@ -1045,11 +1092,11 @@ static void idedisk_setup(ide_drive_t *drive)
if (id->buf_size)
printk (" w/%dKiB Cache", id->buf_size/2);
- printk(", CHS=%d/%d/%d",
+ printk(", CHS=%d/%d/%d",
drive->bios_cyl, drive->bios_head, drive->bios_sect);
#ifdef CONFIG_BLK_DEV_IDEDMA
if (drive->using_dma)
- (void) HWIF(drive)->dmaproc(ide_dma_verbose, drive);
+ (void) drive->channel->dmaproc(ide_dma_verbose, drive);
#endif /* CONFIG_BLK_DEV_IDEDMA */
printk("\n");
@@ -1074,8 +1121,11 @@ static void idedisk_setup(ide_drive_t *drive)
(void) probe_lba_addressing(drive, 1);
}
-static int idedisk_cleanup (ide_drive_t *drive)
+static int idedisk_cleanup(ide_drive_t *drive)
{
+ if (!drive)
+ return 0;
+
put_device(&drive->device);
if ((drive->id->cfs_enable_2 & 0x3000) && drive->wcache)
if (idedisk_flushcache(drive))
diff --git a/drivers/ide/ide-dma.c b/drivers/ide/ide-dma.c
index 9fade24a9c08c..b221a3bf3ad1b 100644
--- a/drivers/ide/ide-dma.c
+++ b/drivers/ide/ide-dma.c
@@ -204,7 +204,7 @@ ide_startstop_t ide_dma_intr (ide_drive_t *drive)
{
byte stat, dma_stat;
- dma_stat = HWIF(drive)->dmaproc(ide_dma_end, drive);
+ dma_stat = drive->channel->dmaproc(ide_dma_end, drive);
stat = GET_STAT(); /* get drive status */
if (OK_STAT(stat,DRIVE_READY,drive->bad_wstat|DRQ_STAT)) {
if (!dma_stat) {
@@ -219,7 +219,7 @@ ide_startstop_t ide_dma_intr (ide_drive_t *drive)
return ide_error(drive, "dma_intr", stat);
}
-static int ide_build_sglist (ide_hwif_t *hwif, struct request *rq)
+static int ide_build_sglist(struct ata_channel *hwif, struct request *rq)
{
request_queue_t *q = &hwif->drives[DEVICE_NR(rq->rq_dev) & 1].queue;
struct scatterlist *sg = hwif->sg_table;
@@ -238,7 +238,7 @@ static int ide_build_sglist (ide_hwif_t *hwif, struct request *rq)
return pci_map_sg(hwif->pci_dev, sg, nents, hwif->sg_dma_direction);
}
-static int ide_raw_build_sglist (ide_hwif_t *hwif, struct request *rq)
+static int ide_raw_build_sglist(struct ata_channel *hwif, struct request *rq)
{
struct scatterlist *sg = hwif->sg_table;
int nents = 0;
@@ -285,7 +285,7 @@ static int ide_raw_build_sglist (ide_hwif_t *hwif, struct request *rq)
*/
int ide_build_dmatable (ide_drive_t *drive, ide_dma_action_t func)
{
- ide_hwif_t *hwif = HWIF(drive);
+ struct ata_channel *hwif = drive->channel;
unsigned int *table = hwif->dmatable_cpu;
#ifdef CONFIG_BLK_DEV_TRM290
unsigned int is_trm290_chipset = (hwif->chipset == ide_trm290);
@@ -371,11 +371,11 @@ int ide_build_dmatable (ide_drive_t *drive, ide_dma_action_t func)
/* Teardown mappings after DMA has completed. */
void ide_destroy_dmatable (ide_drive_t *drive)
{
- struct pci_dev *dev = HWIF(drive)->pci_dev;
- struct scatterlist *sg = HWIF(drive)->sg_table;
- int nents = HWIF(drive)->sg_nents;
+ struct pci_dev *dev = drive->channel->pci_dev;
+ struct scatterlist *sg = drive->channel->sg_table;
+ int nents = drive->channel->sg_nents;
- pci_unmap_sg(dev, sg, nents, HWIF(drive)->sg_dma_direction);
+ pci_unmap_sg(dev, sg, nents, drive->channel->sg_dma_direction);
}
/*
@@ -462,7 +462,7 @@ static int config_drive_for_dma (ide_drive_t *drive)
{
int config_allows_dma = 1;
struct hd_driveid *id = drive->id;
- ide_hwif_t *hwif = HWIF(drive);
+ struct ata_channel *hwif = drive->channel;
#ifdef CONFIG_IDEDMA_ONLYDISK
if (drive->type != ATA_DISK)
@@ -502,7 +502,7 @@ static int config_drive_for_dma (ide_drive_t *drive)
*/
static int dma_timer_expiry(ide_drive_t *drive)
{
- byte dma_stat = inb(HWIF(drive)->dma_base+2);
+ byte dma_stat = inb(drive->channel->dma_base+2);
#ifdef DEBUG
printk("%s: dma_timer_expiry: dma status == 0x%02x\n", drive->name, dma_stat);
@@ -525,11 +525,11 @@ static void ide_toggle_bounce(ide_drive_t *drive, int on)
{
u64 addr = BLK_BOUNCE_HIGH;
- if (on && drive->type == ATA_DISK && HWIF(drive)->highmem) {
+ if (on && drive->type == ATA_DISK && drive->channel->highmem) {
if (!PCI_DMA_BUS_IS_PHYS)
addr = BLK_BOUNCE_ANY;
else
- addr = HWIF(drive)->pci_dev->dma_mask;
+ addr = drive->channel->pci_dev->dma_mask;
}
blk_queue_bounce_limit(&drive->queue, addr);
@@ -553,7 +553,7 @@ static void ide_toggle_bounce(ide_drive_t *drive, int on)
*/
int ide_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
{
- ide_hwif_t *hwif = HWIF(drive);
+ struct ata_channel *hwif = drive->channel;
unsigned long dma_base = hwif->dma_base;
byte unit = (drive->select.b.unit & 0x01);
unsigned int count, reading = 0, set_high = 1;
@@ -588,17 +588,19 @@ int ide_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
drive->waiting_for_dma = 1;
if (drive->type != ATA_DISK)
return 0;
+
+ BUG_ON(HWGROUP(drive)->handler);
ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, dma_timer_expiry); /* issue cmd to drive */
if ((HWGROUP(drive)->rq->flags & REQ_DRIVE_TASKFILE) &&
(drive->addressing == 1)) {
ide_task_t *args = HWGROUP(drive)->rq->special;
- OUT_BYTE(args->tfRegister[IDE_COMMAND_OFFSET], IDE_COMMAND_REG);
+ OUT_BYTE(args->taskfile.command, IDE_COMMAND_REG);
} else if (drive->addressing) {
OUT_BYTE(reading ? WIN_READDMA_EXT : WIN_WRITEDMA_EXT, IDE_COMMAND_REG);
} else {
OUT_BYTE(reading ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG);
}
- return HWIF(drive)->dmaproc(ide_dma_begin, drive);
+ return drive->channel->dmaproc(ide_dma_begin, drive);
case ide_dma_begin:
/* Note that this is done *after* the cmd has
* been issued to the drive, as per the BM-IDE spec.
@@ -644,7 +646,7 @@ int ide_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
/*
* Needed for allowing full modular support of ide-driver
*/
-void ide_release_dma(ide_hwif_t *hwif)
+void ide_release_dma(struct ata_channel *hwif)
{
if (!hwif->dma_base)
return;
@@ -660,7 +662,7 @@ void ide_release_dma(ide_hwif_t *hwif)
kfree(hwif->sg_table);
hwif->sg_table = NULL;
}
- if ((hwif->dma_extra) && (hwif->channel == 0))
+ if ((hwif->dma_extra) && (hwif->unit == 0))
release_region((hwif->dma_base + 16), hwif->dma_extra);
release_region(hwif->dma_base, 8);
hwif->dma_base = 0;
@@ -669,7 +671,7 @@ void ide_release_dma(ide_hwif_t *hwif)
/*
* This can be called for a dynamically installed interface. Don't __init it
*/
-void ide_setup_dma (ide_hwif_t *hwif, unsigned long dma_base, unsigned int num_ports)
+void ide_setup_dma(struct ata_channel *hwif, unsigned long dma_base, unsigned int num_ports)
{
printk(" %s: BM-DMA at 0x%04lx-0x%04lx", hwif->name, dma_base, dma_base + num_ports - 1);
if (check_region(dma_base, num_ports)) {
diff --git a/drivers/ide/ide-features.c b/drivers/ide/ide-features.c
index 840abbaff138c..748b1e629740e 100644
--- a/drivers/ide/ide-features.c
+++ b/drivers/ide/ide-features.c
@@ -2,7 +2,7 @@
* linux/drivers/block/ide-features.c Version 0.04 June 9, 2000
*
* Copyright (C) 1999-2000 Linus Torvalds & authors (see below)
- *
+ *
* Copyright (C) 1999-2000 Andre Hedrick <andre@linux-ide.org>
*
* Extracts if ide.c to address the evolving transfer rate code for
@@ -134,7 +134,7 @@ int ide_driveid_update (ide_drive_t *drive)
struct hd_driveid *id;
unsigned long timeout, flags;
- SELECT_MASK(HWIF(drive), drive, 1);
+ SELECT_MASK(drive->channel, drive, 1);
if (IDE_CONTROL_REG)
OUT_BYTE(drive->ctl,IDE_CONTROL_REG);
ide_delay_50ms();
@@ -142,20 +142,20 @@ int ide_driveid_update (ide_drive_t *drive)
timeout = jiffies + WAIT_WORSTCASE;
do {
if (0 < (signed long)(jiffies - timeout)) {
- SELECT_MASK(HWIF(drive), drive, 0);
+ SELECT_MASK(drive->channel, drive, 0);
return 0; /* drive timed-out */
}
ide_delay_50ms(); /* give drive a breather */
} while (IN_BYTE(IDE_ALTSTATUS_REG) & BUSY_STAT);
ide_delay_50ms(); /* wait for IRQ and DRQ_STAT */
if (!OK_STAT(GET_STAT(),DRQ_STAT,BAD_R_STAT)) {
- SELECT_MASK(HWIF(drive), drive, 0);
+ SELECT_MASK(drive->channel, drive, 0);
printk("%s: CHECK for good STATUS\n", drive->name);
return 0;
}
__save_flags(flags); /* local CPU only */
__cli(); /* local CPU only; some systems need this */
- SELECT_MASK(HWIF(drive), drive, 0);
+ SELECT_MASK(drive->channel, drive, 0);
id = kmalloc(SECTOR_WORDS*4, GFP_ATOMIC);
if (!id) {
__restore_flags(flags); /* local CPU only */
@@ -186,11 +186,11 @@ int ide_driveid_update (ide_drive_t *drive)
*/
int ide_ata66_check (ide_drive_t *drive, ide_task_t *args)
{
- if ((args->tfRegister[IDE_COMMAND_OFFSET] == WIN_SETFEATURES) &&
- (args->tfRegister[IDE_SECTOR_OFFSET] > XFER_UDMA_2) &&
- (args->tfRegister[IDE_FEATURE_OFFSET] == SETFEATURES_XFER)) {
- if (!HWIF(drive)->udma_four) {
- printk("%s: Speed warnings UDMA 3/4/5 is not functional.\n", HWIF(drive)->name);
+ if ((args->taskfile.command == WIN_SETFEATURES) &&
+ (args->taskfile.sector_number > XFER_UDMA_2) &&
+ (args->taskfile.feature == SETFEATURES_XFER)) {
+ if (!drive->channel->udma_four) {
+ printk("%s: Speed warnings UDMA 3/4/5 is not functional.\n", drive->channel->name);
return 1;
}
#ifndef CONFIG_IDEDMA_IVB
@@ -213,9 +213,9 @@ int ide_ata66_check (ide_drive_t *drive, ide_task_t *args)
*/
int set_transfer (ide_drive_t *drive, ide_task_t *args)
{
- if ((args->tfRegister[IDE_COMMAND_OFFSET] == WIN_SETFEATURES) &&
- (args->tfRegister[IDE_SECTOR_OFFSET] >= XFER_SW_DMA_0) &&
- (args->tfRegister[IDE_FEATURE_OFFSET] == SETFEATURES_XFER) &&
+ if ((args->taskfile.command == WIN_SETFEATURES) &&
+ (args->taskfile.sector_number >= XFER_SW_DMA_0) &&
+ (args->taskfile.feature == SETFEATURES_XFER) &&
(drive->id->dma_ultra ||
drive->id->dma_mword ||
drive->id->dma_1word))
@@ -229,7 +229,7 @@ int set_transfer (ide_drive_t *drive, ide_task_t *args)
*/
byte eighty_ninty_three (ide_drive_t *drive)
{
- return ((byte) ((HWIF(drive)->udma_four) &&
+ return ((byte) ((drive->channel->udma_four) &&
#ifndef CONFIG_IDEDMA_IVB
(drive->id->hw_config & 0x4000) &&
#endif /* CONFIG_IDEDMA_IVB */
@@ -249,8 +249,9 @@ byte eighty_ninty_three (ide_drive_t *drive)
*/
int ide_config_drive_speed (ide_drive_t *drive, byte speed)
{
- ide_hwif_t *hwif = HWIF(drive);
- int i, error = 1;
+ struct ata_channel *hwif = drive->channel;
+ int i;
+ int error = 1;
byte stat;
#if defined(CONFIG_BLK_DEV_IDEDMA) && !defined(CONFIG_DMA_NONPCI)
@@ -269,8 +270,8 @@ int ide_config_drive_speed (ide_drive_t *drive, byte speed)
*/
disable_irq(hwif->irq); /* disable_irq_nosync ?? */
udelay(1);
- SELECT_DRIVE(HWIF(drive), drive);
- SELECT_MASK(HWIF(drive), drive, 0);
+ SELECT_DRIVE(drive->channel, drive);
+ SELECT_MASK(drive->channel, drive, 0);
udelay(1);
if (IDE_CONTROL_REG)
OUT_BYTE(drive->ctl | 2, IDE_CONTROL_REG);
@@ -310,7 +311,7 @@ int ide_config_drive_speed (ide_drive_t *drive, byte speed)
}
}
- SELECT_MASK(HWIF(drive), drive, 0);
+ SELECT_MASK(drive->channel, drive, 0);
enable_irq(hwif->irq);
diff --git a/drivers/ide/ide-floppy.c b/drivers/ide/ide-floppy.c
index 7581132da95b1..e988e17cee693 100644
--- a/drivers/ide/ide-floppy.c
+++ b/drivers/ide/ide-floppy.c
@@ -902,7 +902,7 @@ static ide_startstop_t idefloppy_pc_intr (ide_drive_t *drive)
#ifdef CONFIG_BLK_DEV_IDEDMA
if (test_bit (PC_DMA_IN_PROGRESS, &pc->flags)) {
- if (HWIF(drive)->dmaproc(ide_dma_end, drive)) {
+ if (drive->channel->dmaproc(ide_dma_end, drive)) {
set_bit (PC_DMA_ERROR, &pc->flags);
} else {
pc->actually_transferred=pc->request_transfer;
@@ -945,7 +945,7 @@ static ide_startstop_t idefloppy_pc_intr (ide_drive_t *drive)
#ifdef CONFIG_BLK_DEV_IDEDMA
if (test_and_clear_bit (PC_DMA_IN_PROGRESS, &pc->flags)) {
printk (KERN_ERR "ide-floppy: The floppy wants to issue more interrupts in DMA mode\n");
- HWIF(drive)->dmaproc(ide_dma_off, drive);
+ drive->channel->dmaproc(ide_dma_off, drive);
return ide_stopped;
}
#endif /* CONFIG_BLK_DEV_IDEDMA */
@@ -968,6 +968,7 @@ static ide_startstop_t idefloppy_pc_intr (ide_drive_t *drive)
if (temp > pc->buffer_size) {
printk (KERN_ERR "ide-floppy: The floppy wants to send us more data than expected - discarding data\n");
idefloppy_discard_data (drive,bcount.all);
+ BUG_ON(HWGROUP(drive)->handler);
ide_set_handler (drive,&idefloppy_pc_intr,IDEFLOPPY_WAIT_CMD, NULL);
return ide_started;
}
@@ -990,7 +991,9 @@ static ide_startstop_t idefloppy_pc_intr (ide_drive_t *drive)
pc->actually_transferred+=bcount.all; /* Update the current position */
pc->current_position+=bcount.all;
- ide_set_handler (drive,&idefloppy_pc_intr,IDEFLOPPY_WAIT_CMD, NULL); /* And set the interrupt handler again */
+ BUG_ON(HWGROUP(drive)->handler);
+ ide_set_handler(drive,&idefloppy_pc_intr,IDEFLOPPY_WAIT_CMD, NULL); /* And set the interrupt handler again */
+
return ide_started;
}
@@ -1014,8 +1017,11 @@ static ide_startstop_t idefloppy_transfer_pc (ide_drive_t *drive)
printk (KERN_ERR "ide-floppy: (IO,CoD) != (0,1) while issuing a packet command\n");
return ide_stopped;
}
+
+ BUG_ON(HWGROUP(drive)->handler);
ide_set_handler (drive, &idefloppy_pc_intr, IDEFLOPPY_WAIT_CMD, NULL); /* Set the interrupt routine */
atapi_output_bytes (drive, floppy->pc->c, 12); /* Send the actual packet */
+
return ide_started;
}
@@ -1055,17 +1061,19 @@ static ide_startstop_t idefloppy_transfer_pc1 (ide_drive_t *drive)
printk (KERN_ERR "ide-floppy: (IO,CoD) != (0,1) while issuing a packet command\n");
return ide_stopped;
}
- /*
+ /*
* The following delay solves a problem with ATAPI Zip 100 drives where the
* Busy flag was apparently being deasserted before the unit was ready to
* receive data. This was happening on a 1200 MHz Athlon system. 10/26/01
- * 25msec is too short, 40 and 50msec work well. idefloppy_pc_intr will
+ * 25msec is too short, 40 and 50msec work well. idefloppy_pc_intr will
* not be actually used until after the packet is moved in about 50 msec.
*/
- ide_set_handler (drive,
- &idefloppy_pc_intr, /* service routine for packet command */
+ BUG_ON(HWGROUP(drive)->handler);
+ ide_set_handler (drive,
+ &idefloppy_pc_intr, /* service routine for packet command */
floppy->ticks, /* wait this long before "failing" */
&idefloppy_transfer_pc2); /* fail == transfer_pc2 */
+
return ide_started;
}
@@ -1117,10 +1125,10 @@ static ide_startstop_t idefloppy_issue_pc (ide_drive_t *drive, idefloppy_pc_t *p
#ifdef CONFIG_BLK_DEV_IDEDMA
if (test_and_clear_bit (PC_DMA_ERROR, &pc->flags)) {
- (void) HWIF(drive)->dmaproc(ide_dma_off, drive);
+ (void) drive->channel->dmaproc(ide_dma_off, drive);
}
if (test_bit (PC_DMA_RECOMMENDED, &pc->flags) && drive->using_dma)
- dma_ok=!HWIF(drive)->dmaproc(test_bit (PC_WRITING, &pc->flags) ? ide_dma_write : ide_dma_read, drive);
+ dma_ok=!drive->channel->dmaproc(test_bit (PC_WRITING, &pc->flags) ? ide_dma_write : ide_dma_read, drive);
#endif /* CONFIG_BLK_DEV_IDEDMA */
if (IDE_CONTROL_REG)
@@ -1133,7 +1141,7 @@ static ide_startstop_t idefloppy_issue_pc (ide_drive_t *drive, idefloppy_pc_t *p
#ifdef CONFIG_BLK_DEV_IDEDMA
if (dma_ok) { /* Begin DMA, if necessary */
set_bit (PC_DMA_IN_PROGRESS, &pc->flags);
- (void) (HWIF(drive)->dmaproc(ide_dma_begin, drive));
+ (void) drive->channel->dmaproc(ide_dma_begin, drive);
}
#endif /* CONFIG_BLK_DEV_IDEDMA */
@@ -1143,8 +1151,9 @@ static ide_startstop_t idefloppy_issue_pc (ide_drive_t *drive, idefloppy_pc_t *p
} else {
pkt_xfer_routine = &idefloppy_transfer_pc; /* immediate */
}
-
+
if (test_bit (IDEFLOPPY_DRQ_INTERRUPT, &floppy->flags)) {
+ BUG_ON(HWGROUP(drive)->handler);
ide_set_handler (drive, pkt_xfer_routine, IDEFLOPPY_WAIT_CMD, NULL);
OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG); /* Issue the packet command */
return ide_started;
@@ -1156,7 +1165,7 @@ static ide_startstop_t idefloppy_issue_pc (ide_drive_t *drive, idefloppy_pc_t *p
static void idefloppy_rw_callback (ide_drive_t *drive)
{
-#if IDEFLOPPY_DEBUG_LOG
+#if IDEFLOPPY_DEBUG_LOG
printk (KERN_INFO "ide-floppy: Reached idefloppy_rw_callback\n");
#endif /* IDEFLOPPY_DEBUG_LOG */
@@ -2004,7 +2013,7 @@ static void idefloppy_setup (ide_drive_t *drive, idefloppy_floppy_t *floppy)
(void) idefloppy_get_capacity (drive);
idefloppy_add_settings(drive);
for (i = 0; i < MAX_DRIVES; ++i) {
- ide_hwif_t *hwif = HWIF(drive);
+ struct ata_channel *hwif = drive->channel;
if (drive != &hwif->drives[i]) continue;
hwif->gd->de_arr[i] = drive->de;
@@ -2109,10 +2118,9 @@ int idefloppy_init (void)
kfree (floppy);
continue;
}
- /* ATA-PATTERN */
- ata_ops(drive)->busy++;
+ MOD_INC_USE_COUNT;
idefloppy_setup (drive, floppy);
- ata_ops(drive)->busy--;
+ MOD_DEC_USE_COUNT;
failed--;
}
diff --git a/drivers/ide/ide-geometry.c b/drivers/ide/ide-geometry.c
index 7a203365420a9..0671559114b1d 100644
--- a/drivers/ide/ide-geometry.c
+++ b/drivers/ide/ide-geometry.c
@@ -7,6 +7,7 @@
*/
#include <linux/config.h>
+#include <linux/types.h>
#include <linux/ide.h>
#include <linux/mc146818rtc.h>
#include <asm/io.h>
diff --git a/drivers/ide/ide-pci.c b/drivers/ide/ide-pci.c
index d8c32aca8a7b0..486f3bca98cd6 100644
--- a/drivers/ide/ide-pci.c
+++ b/drivers/ide/ide-pci.c
@@ -39,45 +39,45 @@
#ifdef CONFIG_BLK_DEV_AEC62XX
extern unsigned int pci_init_aec62xx(struct pci_dev *);
-extern unsigned int ata66_aec62xx(ide_hwif_t *);
-extern void ide_init_aec62xx(ide_hwif_t *);
-extern void ide_dmacapable_aec62xx(ide_hwif_t *, unsigned long);
+extern unsigned int ata66_aec62xx(struct ata_channel *);
+extern void ide_init_aec62xx(struct ata_channel *);
+extern void ide_dmacapable_aec62xx(struct ata_channel *, unsigned long);
#endif
#ifdef CONFIG_BLK_DEV_ALI15X3
extern unsigned int pci_init_ali15x3(struct pci_dev *);
-extern unsigned int ata66_ali15x3(ide_hwif_t *);
-extern void ide_init_ali15x3(ide_hwif_t *);
-extern void ide_dmacapable_ali15x3(ide_hwif_t *, unsigned long);
+extern unsigned int ata66_ali15x3(struct ata_channel *);
+extern void ide_init_ali15x3(struct ata_channel *);
+extern void ide_dmacapable_ali15x3(struct ata_channel *, unsigned long);
#endif
#ifdef CONFIG_BLK_DEV_AMD74XX
extern unsigned int pci_init_amd74xx(struct pci_dev *);
-extern unsigned int ata66_amd74xx(ide_hwif_t *);
-extern void ide_init_amd74xx(ide_hwif_t *);
-extern void ide_dmacapable_amd74xx(ide_hwif_t *, unsigned long);
+extern unsigned int ata66_amd74xx(struct ata_channel *);
+extern void ide_init_amd74xx(struct ata_channel *);
+extern void ide_dmacapable_amd74xx(struct ata_channel *, unsigned long);
#endif
#ifdef CONFIG_BLK_DEV_CMD64X
extern unsigned int pci_init_cmd64x(struct pci_dev *);
-extern unsigned int ata66_cmd64x(ide_hwif_t *);
-extern void ide_init_cmd64x(ide_hwif_t *);
-extern void ide_dmacapable_cmd64x(ide_hwif_t *, unsigned long);
+extern unsigned int ata66_cmd64x(struct ata_channel *);
+extern void ide_init_cmd64x(struct ata_channel *);
+extern void ide_dmacapable_cmd64x(struct ata_channel *, unsigned long);
#endif
#ifdef CONFIG_BLK_DEV_CY82C693
extern unsigned int pci_init_cy82c693(struct pci_dev *);
-extern void ide_init_cy82c693(ide_hwif_t *);
+extern void ide_init_cy82c693(struct ata_channel *);
#endif
#ifdef CONFIG_BLK_DEV_CS5530
extern unsigned int pci_init_cs5530(struct pci_dev *);
-extern void ide_init_cs5530(ide_hwif_t *);
+extern void ide_init_cs5530(struct ata_channel *);
#endif
#ifdef CONFIG_BLK_DEV_HPT34X
extern unsigned int pci_init_hpt34x(struct pci_dev *);
-extern void ide_init_hpt34x(ide_hwif_t *);
+extern void ide_init_hpt34x(struct ata_channel *);
#endif
#ifdef CONFIG_BLK_DEV_HPT366
@@ -85,9 +85,9 @@ extern byte hpt363_shared_irq;
extern byte hpt363_shared_pin;
extern unsigned int pci_init_hpt366(struct pci_dev *);
-extern unsigned int ata66_hpt366(ide_hwif_t *);
-extern void ide_init_hpt366(ide_hwif_t *);
-extern void ide_dmacapable_hpt366(ide_hwif_t *, unsigned long);
+extern unsigned int ata66_hpt366(struct ata_channel *);
+extern void ide_init_hpt366(struct ata_channel *);
+extern void ide_dmacapable_hpt366(struct ata_channel *, unsigned long);
#else
/* FIXME: those have to be killed */
static byte hpt363_shared_irq;
@@ -95,69 +95,69 @@ static byte hpt363_shared_pin;
#endif
#ifdef CONFIG_BLK_DEV_NS87415
-extern void ide_init_ns87415(ide_hwif_t *);
+extern void ide_init_ns87415(struct ata_channel *);
#endif
#ifdef CONFIG_BLK_DEV_OPTI621
-extern void ide_init_opti621(ide_hwif_t *);
+extern void ide_init_opti621(struct ata_channel *);
#endif
#ifdef CONFIG_BLK_DEV_PDC_ADMA
extern unsigned int pci_init_pdcadma(struct pci_dev *);
-extern unsigned int ata66_pdcadma(ide_hwif_t *);
-extern void ide_init_pdcadma(ide_hwif_t *);
-extern void ide_dmacapable_pdcadma(ide_hwif_t *, unsigned long);
+extern unsigned int ata66_pdcadma(struct ata_channel *);
+extern void ide_init_pdcadma(struct ata_channel *);
+extern void ide_dmacapable_pdcadma(struct ata_channel *, unsigned long);
#endif
#ifdef CONFIG_BLK_DEV_PDC202XX
extern unsigned int pci_init_pdc202xx(struct pci_dev *);
-extern unsigned int ata66_pdc202xx(ide_hwif_t *);
-extern void ide_init_pdc202xx(ide_hwif_t *);
+extern unsigned int ata66_pdc202xx(struct ata_channel *);
+extern void ide_init_pdc202xx(struct ata_channel *);
#endif
#ifdef CONFIG_BLK_DEV_PIIX
extern unsigned int pci_init_piix(struct pci_dev *);
-extern unsigned int ata66_piix(ide_hwif_t *);
-extern void ide_init_piix(ide_hwif_t *);
-extern void ide_dmacapable_piix(ide_hwif_t *, unsigned long);
+extern unsigned int ata66_piix(struct ata_channel *);
+extern void ide_init_piix(struct ata_channel *);
+extern void ide_dmacapable_piix(struct ata_channel *, unsigned long);
#endif
#ifdef CONFIG_BLK_DEV_IT8172
extern unsigned int pci_init_it8172(struct pci_dev *);
-extern void ide_init_it8172(ide_hwif_t *);
+extern void ide_init_it8172(struct ata_channel *);
#endif
#ifdef CONFIG_BLK_DEV_RZ1000
-extern void ide_init_rz1000(ide_hwif_t *);
+extern void ide_init_rz1000(struct ata_channel *);
#endif
#ifdef CONFIG_BLK_DEV_SVWKS
extern unsigned int pci_init_svwks(struct pci_dev *);
-extern unsigned int ata66_svwks(ide_hwif_t *);
-extern void ide_init_svwks(ide_hwif_t *);
+extern unsigned int ata66_svwks(struct ata_channel *);
+extern void ide_init_svwks(struct ata_channel *);
#endif
#ifdef CONFIG_BLK_DEV_SIS5513
extern unsigned int pci_init_sis5513(struct pci_dev *);
-extern unsigned int ata66_sis5513(ide_hwif_t *);
-extern void ide_init_sis5513(ide_hwif_t *);
+extern unsigned int ata66_sis5513(struct ata_channel *);
+extern void ide_init_sis5513(struct ata_channel *);
#endif
#ifdef CONFIG_BLK_DEV_SL82C105
extern unsigned int pci_init_sl82c105(struct pci_dev *);
-extern void dma_init_sl82c105(ide_hwif_t *, unsigned long);
-extern void ide_init_sl82c105(ide_hwif_t *);
+extern void dma_init_sl82c105(struct ata_channel *, unsigned long);
+extern void ide_init_sl82c105(struct ata_channel *);
#endif
#ifdef CONFIG_BLK_DEV_TRM290
-extern void ide_init_trm290(ide_hwif_t *);
+extern void ide_init_trm290(struct ata_channel *);
#endif
#ifdef CONFIG_BLK_DEV_VIA82CXXX
extern unsigned int pci_init_via82cxxx(struct pci_dev *);
-extern unsigned int ata66_via82cxxx(ide_hwif_t *);
-extern void ide_init_via82cxxx(ide_hwif_t *);
-extern void ide_dmacapable_via82cxxx(ide_hwif_t *, unsigned long);
+extern unsigned int ata66_via82cxxx(struct ata_channel *);
+extern void ide_init_via82cxxx(struct ata_channel *);
+extern void ide_dmacapable_via82cxxx(struct ata_channel *, unsigned long);
#endif
typedef struct ide_pci_enablebit_s {
@@ -181,9 +181,9 @@ typedef struct ide_pci_device_s {
unsigned short vendor;
unsigned short device;
unsigned int (*init_chipset)(struct pci_dev *dev);
- unsigned int (*ata66_check)(ide_hwif_t *hwif);
- void (*init_hwif)(ide_hwif_t *hwif);
- void (*dma_init)(ide_hwif_t *hwif, unsigned long dmabase);
+ unsigned int (*ata66_check)(struct ata_channel *hwif);
+ void (*init_hwif)(struct ata_channel *hwif);
+ void (*dma_init)(struct ata_channel *hwif, unsigned long dmabase);
ide_pci_enablebit_t enablebits[2];
unsigned int bootable;
unsigned int extra;
@@ -229,6 +229,7 @@ static ide_pci_device_t pci_chipsets[] __initdata = {
{PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20268R, pci_init_pdc202xx, ata66_pdc202xx, ide_init_pdc202xx, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, OFF_BOARD, 0, ATA_F_IRQ | ATA_F_DMA },
{PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20269, pci_init_pdc202xx, ata66_pdc202xx, ide_init_pdc202xx, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, OFF_BOARD, 0, ATA_F_IRQ | ATA_F_DMA },
{PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20275, pci_init_pdc202xx, ata66_pdc202xx, ide_init_pdc202xx, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, OFF_BOARD, 0, ATA_F_IRQ | ATA_F_DMA },
+ {PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20276, pci_init_pdc202xx, ata66_pdc202xx, ide_init_pdc202xx, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, OFF_BOARD, 0, ATA_F_IRQ | ATA_F_DMA },
#endif
#ifdef CONFIG_BLK_DEV_RZ1000
{PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_RZ1000, NULL, NULL, ide_init_rz1000, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, 0 },
@@ -328,10 +329,10 @@ static unsigned int __init trust_pci_irq(ide_pci_device_t *d, struct pci_dev *de
* Match a PCI IDE port against an entry in ide_hwifs[],
* based on io_base port if possible.
*/
-static ide_hwif_t __init *lookup_hwif (unsigned long io_base, int bootable, const char *name)
+static struct ata_channel __init *lookup_hwif (unsigned long io_base, int bootable, const char *name)
{
int h;
- ide_hwif_t *hwif;
+ struct ata_channel *hwif;
/*
* Look for a hwif with matching io_base specified using
@@ -430,7 +431,7 @@ static int __init setup_pci_baseregs (struct pci_dev *dev, const char *name)
/*
* Fetch the DMA Bus-Master-I/O-Base-Address (BMIBA) from PCI space:
*/
-static unsigned long __init get_dma_base(ide_hwif_t *hwif, int extra, const char *name)
+static unsigned long __init get_dma_base(struct ata_channel *hwif, int extra, const char *name)
{
unsigned long dma_base = 0;
struct pci_dev *dev = hwif->pci_dev;
@@ -441,7 +442,7 @@ static unsigned long __init get_dma_base(ide_hwif_t *hwif, int extra, const char
*/
if (hwif->mate && hwif->mate->dma_base)
- dma_base = hwif->mate->dma_base - (hwif->channel ? 0 : 8);
+ dma_base = hwif->mate->dma_base - (hwif->unit ? 0 : 8);
else
dma_base = pci_resource_start(dev, 4);
@@ -451,7 +452,7 @@ static unsigned long __init get_dma_base(ide_hwif_t *hwif, int extra, const char
if (extra) /* PDC20246, PDC20262, HPT343, & HPT366 */
request_region(dma_base + 16, extra, name);
- dma_base += hwif->channel ? 8 : 0;
+ dma_base += hwif->unit ? 8 : 0;
hwif->dma_extra = extra;
if ((dev->vendor == PCI_VENDOR_ID_AL && dev->device == PCI_DEVICE_ID_AL_M5219) ||
@@ -484,11 +485,11 @@ static unsigned long __init get_dma_base(ide_hwif_t *hwif, int extra, const char
/*
* Setup DMA transfers on a channel.
*/
-static void __init setup_channel_dma(ide_hwif_t *hwif, struct pci_dev *dev,
+static void __init setup_channel_dma(struct ata_channel *hwif, struct pci_dev *dev,
ide_pci_device_t *d,
int port,
u8 class_rev,
- int pciirq, ide_hwif_t **mate,
+ int pciirq, struct ata_channel **mate,
int autodma, unsigned short *pcicmd)
{
unsigned long dma_base;
@@ -535,14 +536,15 @@ static int __init setup_host_channel(struct pci_dev *dev,
ide_pci_device_t *d,
int port,
u8 class_rev,
- int pciirq, ide_hwif_t **mate,
+ int pciirq,
+ struct ata_channel **mate,
int autodma,
unsigned short *pcicmd)
{
unsigned long base = 0;
unsigned long ctl = 0;
ide_pci_enablebit_t *e = &(d->enablebits[port]);
- ide_hwif_t *hwif;
+ struct ata_channel *hwif;
u8 tmp;
if (port == 1) {
@@ -608,7 +610,7 @@ controller_ok:
hwif->chipset = ide_pci;
hwif->pci_dev = dev;
- hwif->channel = port;
+ hwif->unit = port;
if (!hwif->irq)
hwif->irq = pciirq;
@@ -669,7 +671,7 @@ static void __init setup_pci_device(struct pci_dev *dev, ide_pci_device_t *d)
int pciirq = 0;
unsigned short pcicmd = 0;
unsigned short tried_config = 0;
- ide_hwif_t *mate = NULL;
+ struct ata_channel *mate = NULL;
unsigned int class_rev;
#ifdef CONFIG_IDEDMA_AUTO
diff --git a/drivers/ide/ide-pmac.c b/drivers/ide/ide-pmac.c
index 3a717a5f695dc..5223f54a51e1d 100644
--- a/drivers/ide/ide-pmac.c
+++ b/drivers/ide/ide-pmac.c
@@ -71,6 +71,9 @@ enum {
#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
+# define BAD_DMA_DRIVE 0
+# define GOOD_DMA_DRIVE 1
+
typedef struct {
int accessTime;
int cycleTime;
@@ -124,10 +127,10 @@ struct pmu_sleep_notifier idepmac_sleep_notifier = {
static int
pmac_ide_find(ide_drive_t *drive)
{
- ide_hwif_t *hwif = HWIF(drive);
+ struct ata_channel *hwif = drive->channel;
ide_ioreg_t base;
int i;
-
+
for (i=0; i<pmac_ide_count; i++) {
base = pmac_ide[i].regbase;
if (base && base == hwif->io_ports[0])
@@ -258,8 +261,8 @@ pmac_ide_do_setfeature(ide_drive_t *drive, byte command)
save_flags(flags);
cli();
udelay(1);
- SELECT_DRIVE(HWIF(drive), drive);
- SELECT_MASK(HWIF(drive), drive, 0);
+ SELECT_DRIVE(drive->channel, drive);
+ SELECT_MASK(drive->channel, drive, 0);
udelay(1);
if(wait_for_ready(drive)) {
printk(KERN_ERR "pmac_ide_do_setfeature disk not ready before SET_FEATURE!\n");
@@ -507,7 +510,7 @@ pmac_ide_probe(void)
struct device_node *p, **pp, *removables, **rp;
unsigned long base;
int irq, big_delay;
- ide_hwif_t *hwif;
+ struct ata_channel *hwif;
if (_machine != _MACH_Pmac)
return;
@@ -928,12 +931,12 @@ pmac_ide_check_dma(ide_drive_t *drive)
int enable = 1;
drive->using_dma = 0;
-
+
idx = pmac_ide_find(drive);
if (idx < 0)
return 0;
-
- if (drive->media == ide_floppy)
+
+ if (drive->type == ATA_FLOPPY)
enable = 0;
if (((id->capability & 1) == 0) && !check_drive_lists(drive, GOOD_DMA_DRIVE))
enable = 0;
@@ -942,9 +945,9 @@ pmac_ide_check_dma(ide_drive_t *drive)
udma = 0;
ata4 = (pmac_ide[idx].kind == controller_kl_ata4);
-
+
if(enable) {
- if (ata4 && (drive->media == ide_disk) &&
+ if (ata4 && (drive->type == ATA_DISK) &&
(id->field_valid & 0x0004) && (id->dma_ultra & 0x17)) {
/* UltraDMA modes. */
drive->using_dma = pmac_ide_udma_enable(drive, idx);
@@ -991,8 +994,9 @@ int pmac_ide_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
if (!pmac_ide_build_dmatable(drive, ix, func==ide_dma_write))
return 1;
drive->waiting_for_dma = 1;
- if (drive->media != ide_disk)
+ if (drive->type != ATA_DISK)
return 0;
+ BUG_ON(HWGROUP(drive)->handler);
ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, NULL);
OUT_BYTE(func==ide_dma_write? WIN_WRITEDMA: WIN_READDMA,
IDE_COMMAND_REG);
@@ -1051,12 +1055,12 @@ int pmac_ide_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
static void idepmac_sleep_device(ide_drive_t *drive, int i, unsigned base)
{
int j;
-
+
/* FIXME: We only handle the master IDE disk, we shoud
* try to fix CD-ROMs here
*/
- switch (drive->media) {
- case ide_disk:
+ switch (drive->type) {
+ case ATA_DISK:
/* Spin down the drive */
outb(0xa0, base+0x60);
outb(0x0, base+0x30);
@@ -1064,7 +1068,7 @@ static void idepmac_sleep_device(ide_drive_t *drive, int i, unsigned base)
outb(0x0, base+0x40);
outb(0x0, base+0x50);
outb(0xe0, base+0x70);
- outb(0x2, base+0x160);
+ outb(0x2, base+0x160);
for (j = 0; j < 10; j++) {
int status;
mdelay(100);
@@ -1073,10 +1077,10 @@ static void idepmac_sleep_device(ide_drive_t *drive, int i, unsigned base)
break;
}
break;
- case ide_cdrom:
+ case ATA_ROM:
// todo
break;
- case ide_floppy:
+ case ATA_FLOPPY:
// todo
break;
}
@@ -1094,7 +1098,7 @@ static void idepmac_wake_device(ide_drive_t *drive, int used_dma)
DRIVER(drive)->media_change(drive);
/* We kick the VFS too (see fix in ide.c revalidate) */
- check_disk_change(MKDEV(HWIF(drive)->major, (drive->select.b.unit) << PARTN_BITS));
+ check_disk_change(MKDEV(drive->channel->major, (drive->select.b.unit) << PARTN_BITS));
#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
/* We re-enable DMA on the drive if it was active. */
@@ -1198,7 +1202,7 @@ static int idepmac_notify_sleep(struct pmu_sleep_notifier *self, int when)
break;
case PBOOK_SLEEP_NOW:
for (i = 0; i < pmac_ide_count; ++i) {
- ide_hwif_t *hwif;
+ struct ata_channel *hwif;
ide_drive_t *drive;
int unlock = 0;
@@ -1258,8 +1262,8 @@ static int idepmac_notify_sleep(struct pmu_sleep_notifier *self, int when)
mdelay(IDE_WAKEUP_DELAY_MS);
for (i = 0; i < pmac_ide_count; ++i) {
- ide_hwif_t *hwif;
- ide_drive_t *drive;
+ struct ata_channel *hwif;
+ ide_drive_t *drive;
int j, used_dma;
if ((base = pmac_ide[i].regbase) == 0)
diff --git a/drivers/ide/ide-pnp.c b/drivers/ide/ide-pnp.c
index 462de45010721..818689eab6a6d 100644
--- a/drivers/ide/ide-pnp.c
+++ b/drivers/ide/ide-pnp.c
@@ -13,7 +13,7 @@
*
* You should have received a copy of the GNU General Public License
* (for example /usr/src/linux/COPYING); if not, write to the Free
- * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/ide.h>
@@ -57,7 +57,7 @@ struct pnp_dev_t {
static int __init pnpide_generic_init(struct pci_dev *dev, int enable)
{
hw_regs_t hw;
- ide_hwif_t *hwif;
+ struct ata_channel *hwif;
int index;
if (!enable)
diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c
index 69444ac9a65d8..a7857ced574b2 100644
--- a/drivers/ide/ide-probe.c
+++ b/drivers/ide/ide-probe.c
@@ -118,7 +118,7 @@ static inline void do_identify (ide_drive_t *drive, byte cmd)
byte type = (id->config >> 8) & 0x1f;
printk("ATAPI ");
#ifdef CONFIG_BLK_DEV_PDC4030
- if (HWIF(drive)->channel == 1 && HWIF(drive)->chipset == ide_pdc4030) {
+ if (drive->channel->unit == 1 && drive->channel->chipset == ide_pdc4030) {
printk(" -- not supported on 2nd Promise port\n");
goto err_misc;
}
@@ -167,12 +167,16 @@ static inline void do_identify (ide_drive_t *drive, byte cmd)
*/
if (id->config & (1<<7))
drive->removable = 1;
+
/*
- * Prevent long system lockup probing later for non-existant
- * slave drive if the hwif is actually a flash memory card of some variety:
+ * FIXME: This is just plain ugly or plain unnecessary.
+ *
+ * Prevent long system lockup probing later for non-existant slave
+ * drive if the hwif is actually a flash memory card of some variety:
*/
+
if (drive_is_flashcard(drive)) {
- ide_drive_t *mate = &HWIF(drive)->drives[1^drive->select.b.unit];
+ ide_drive_t *mate = &drive->channel->drives[1 ^ drive->select.b.unit];
if (!mate->ata_flash) {
mate->present = 0;
mate->noprobe = 1;
@@ -182,8 +186,8 @@ static inline void do_identify (ide_drive_t *drive, byte cmd)
printk("ATA DISK drive\n");
/* Initialize our quirk list. */
- if (HWIF(drive)->quirkproc)
- drive->quirk_list = HWIF(drive)->quirkproc(drive);
+ if (drive->channel->quirkproc)
+ drive->quirk_list = drive->channel->quirkproc(drive);
return;
@@ -232,7 +236,7 @@ static int actual_try_to_identify (ide_drive_t *drive, byte cmd)
OUT_BYTE(0,IDE_FEATURE_REG); /* disable dma & overlap */
#if CONFIG_BLK_DEV_PDC4030
- if (HWIF(drive)->chipset == ide_pdc4030) {
+ if (drive->channel->chipset == ide_pdc4030) {
/* DC4030 hosted drives need their own identify... */
extern int pdc4030_identify(ide_drive_t *);
if (pdc4030_identify(drive)) {
@@ -270,7 +274,7 @@ static int try_to_identify (ide_drive_t *drive, byte cmd)
int autoprobe = 0;
unsigned long cookie = 0;
- if (IDE_CONTROL_REG && !HWIF(drive)->irq) {
+ if (IDE_CONTROL_REG && !drive->channel->irq) {
autoprobe = 1;
cookie = probe_irq_on();
OUT_BYTE(drive->ctl,IDE_CONTROL_REG); /* enable device irq */
@@ -284,9 +288,9 @@ static int try_to_identify (ide_drive_t *drive, byte cmd)
GET_STAT(); /* clear drive IRQ */
udelay(5);
irq = probe_irq_off(cookie);
- if (!HWIF(drive)->irq) {
+ if (!drive->channel->irq) {
if (irq > 0)
- HWIF(drive)->irq = irq;
+ drive->channel->irq = irq;
else /* Mmmm.. multiple IRQs.. don't know which was ours */
printk("%s: IRQ probe failed (0x%lx)\n", drive->name, cookie);
}
@@ -314,7 +318,7 @@ static int try_to_identify (ide_drive_t *drive, byte cmd)
static int do_probe (ide_drive_t *drive, byte cmd)
{
int rc;
- ide_hwif_t *hwif = HWIF(drive);
+ struct ata_channel *hwif = drive->channel;
if (drive->present) { /* avoid waiting for inappropriate probes */
if ((drive->type != ATA_DISK) && (cmd == WIN_IDENTIFY))
return 4;
@@ -369,12 +373,12 @@ static int do_probe (ide_drive_t *drive, byte cmd)
/*
*
*/
-static void enable_nest (ide_drive_t *drive)
+static void enable_nest(ide_drive_t *drive)
{
unsigned long timeout;
- printk("%s: enabling %s -- ", HWIF(drive)->name, drive->id->model);
- SELECT_DRIVE(HWIF(drive), drive);
+ printk("%s: enabling %s -- ", drive->channel->name, drive->id->model);
+ SELECT_DRIVE(drive->channel, drive);
ide_delay_50ms();
OUT_BYTE(EXABYTE_ENABLE_NEST, IDE_COMMAND_REG);
timeout = jiffies + WAIT_WORSTCASE;
@@ -427,7 +431,7 @@ static inline void probe_for_drive (ide_drive_t *drive)
* ordered sanely. We deal with the CONTROL register
* separately.
*/
-static int hwif_check_regions (ide_hwif_t *hwif)
+static int hwif_check_regions(struct ata_channel *hwif)
{
int region_errors = 0;
@@ -453,20 +457,20 @@ static int hwif_check_regions (ide_hwif_t *hwif)
return(region_errors);
}
-static void hwif_register (ide_hwif_t *hwif)
+static void hwif_register(struct ata_channel *hwif)
{
/* Register this hardware interface within the global device tree.
*/
- sprintf(hwif->device.bus_id, "%04x", hwif->io_ports[IDE_DATA_OFFSET]);
- sprintf(hwif->device.name, "ide");
- hwif->device.driver_data = hwif;
+ sprintf(hwif->dev.bus_id, "%04x", hwif->io_ports[IDE_DATA_OFFSET]);
+ sprintf(hwif->dev.name, "ide");
+ hwif->dev.driver_data = hwif;
#ifdef CONFIG_BLK_DEV_IDEPCI
if (hwif->pci_dev)
- hwif->device.parent = &hwif->pci_dev->dev;
+ hwif->dev.parent = &hwif->pci_dev->dev;
else
#endif
- hwif->device.parent = NULL; /* Would like to do = &device_legacy */
- device_register(&hwif->device);
+ hwif->dev.parent = NULL; /* Would like to do = &device_legacy */
+ device_register(&hwif->dev);
if (((unsigned long)hwif->io_ports[IDE_DATA_OFFSET] | 7) ==
((unsigned long)hwif->io_ports[IDE_STATUS_OFFSET])) {
@@ -503,7 +507,7 @@ static void hwif_register (ide_hwif_t *hwif)
* 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.
*/
-static void probe_hwif (ide_hwif_t *hwif)
+static void probe_hwif(struct ata_channel *hwif)
{
unsigned int unit;
unsigned long flags;
@@ -513,7 +517,7 @@ static void probe_hwif (ide_hwif_t *hwif)
if (
#if CONFIG_BLK_DEV_PDC4030
- (hwif->chipset != ide_pdc4030 || hwif->channel == 0) &&
+ (hwif->chipset != ide_pdc4030 || hwif->unit == 0) &&
#endif
hwif_check_regions(hwif)) {
int msgout = 0;
@@ -562,7 +566,7 @@ static void probe_hwif (ide_hwif_t *hwif)
for (unit = 0; unit < MAX_DRIVES; ++unit) {
ide_drive_t *drive = &hwif->drives[unit];
if (drive->present) {
- ide_tuneproc_t *tuneproc = HWIF(drive)->tuneproc;
+ ide_tuneproc_t *tuneproc = drive->channel->tuneproc;
if (tuneproc != NULL && drive->autotune == 1)
tuneproc(drive, 255); /* auto-tune PIO mode */
}
@@ -583,7 +587,7 @@ static void ide_init_queue(ide_drive_t *drive)
/* IDE can do up to 128K per request, pdc4030 needs smaller limit */
#ifdef CONFIG_BLK_DEV_PDC4030
- if (HWIF(drive)->chipset == ide_pdc4030)
+ if (drive->channel->chipset == ide_pdc4030)
max_sectors = 127;
#endif
blk_queue_max_sectors(q, max_sectors);
@@ -608,9 +612,10 @@ static void ide_init_queue(ide_drive_t *drive)
*
* This routine detects and reports such situations, but does not fix them.
*/
-static void save_match(ide_hwif_t *hwif, ide_hwif_t *new, ide_hwif_t **match)
+static void save_match(struct ata_channel *hwif, struct ata_channel *new,
+ struct ata_channel **match)
{
- ide_hwif_t *m = *match;
+ struct ata_channel *m = *match;
if (m && m->hwgroup && m->hwgroup != new->hwgroup) {
if (!new->hwgroup)
@@ -635,12 +640,12 @@ static void save_match(ide_hwif_t *hwif, ide_hwif_t *new, ide_hwif_t **match)
* but anything else has led to problems on some machines. We re-enable
* interrupts as much as we can safely do in most places.
*/
-static int init_irq (ide_hwif_t *hwif)
+static int init_irq(struct ata_channel *hwif)
{
unsigned long flags;
unsigned int index;
ide_hwgroup_t *hwgroup, *new_hwgroup;
- ide_hwif_t *match = NULL;
+ struct ata_channel *match = NULL;
/* Allocate the buffer and potentially sleep first */
@@ -655,7 +660,7 @@ static int init_irq (ide_hwif_t *hwif)
* Group up with any other hwifs that share our irq(s).
*/
for (index = 0; index < MAX_HWIFS; index++) {
- ide_hwif_t *h = &ide_hwifs[index];
+ struct ata_channel *h = &ide_hwifs[index];
if (h->hwgroup) { /* scan only initialized hwif's */
if (hwif->irq == h->irq) {
hwif->sharing_irq = h->sharing_irq = 1;
@@ -736,7 +741,7 @@ static int init_irq (ide_hwif_t *hwif)
ide_init_queue(drive);
}
if (!hwgroup->hwif) {
- hwgroup->hwif = HWIF(hwgroup->drive);
+ hwgroup->hwif = hwgroup->drive->channel;
#ifdef DEBUG
printk("%s : Adding missed hwif to hwgroup!!\n", hwif->name);
#endif
@@ -770,7 +775,7 @@ static int init_irq (ide_hwif_t *hwif)
* structures needed for the routines in genhd.c. ide_geninit() gets called
* somewhat later, during the partition check.
*/
-static void init_gendisk (ide_hwif_t *hwif)
+static void init_gendisk(struct ata_channel *hwif)
{
struct gendisk *gd;
unsigned int unit, minors, i;
@@ -819,11 +824,11 @@ static void init_gendisk (ide_hwif_t *hwif)
for (unit = 0; unit < MAX_DRIVES; ++unit) {
char name[80];
ide_add_generic_settings(hwif->drives + unit);
- hwif->drives[unit].dn = ((hwif->channel ? 2 : 0) + unit);
+ hwif->drives[unit].dn = ((hwif->unit ? 2 : 0) + unit);
sprintf (name, "host%d/bus%d/target%d/lun%d",
- (hwif->channel && hwif->mate) ?
+ (hwif->unit && hwif->mate) ?
hwif->mate->index : hwif->index,
- hwif->channel, unit, hwif->drives[unit].lun);
+ hwif->unit, unit, hwif->drives[unit].lun);
if (hwif->drives[unit].present)
hwif->drives[unit].de = devfs_mk_dir(ide_devfs_handle, name, NULL);
}
@@ -840,7 +845,7 @@ err_kmalloc_gd:
return;
}
-static int hwif_init (ide_hwif_t *hwif)
+static int hwif_init(struct ata_channel *hwif)
{
if (!hwif->present)
return 0;
diff --git a/drivers/ide/ide-proc.c b/drivers/ide/ide-proc.c
index 83f517e2ae5c6..a80053ba45f50 100644
--- a/drivers/ide/ide-proc.c
+++ b/drivers/ide/ide-proc.c
@@ -138,7 +138,7 @@ static int ide_getdigit(char c)
static int proc_ide_read_imodel
(char *page, char **start, off_t off, int count, int *eof, void *data)
{
- ide_hwif_t *hwif = data;
+ struct ata_channel *hwif = data;
int len;
const char *name;
@@ -167,7 +167,7 @@ static int proc_ide_read_imodel
static int proc_ide_read_mate
(char *page, char **start, off_t off, int count, int *eof, void *data)
{
- ide_hwif_t *hwif = data;
+ struct ata_channel *hwif = data;
int len;
if (hwif && hwif->mate && hwif->mate->present)
@@ -180,10 +180,10 @@ static int proc_ide_read_mate
static int proc_ide_read_channel
(char *page, char **start, off_t off, int count, int *eof, void *data)
{
- ide_hwif_t *hwif = data;
+ struct ata_channel *hwif = data;
int len;
- page[0] = hwif->channel ? '1' : '0';
+ page[0] = hwif->unit ? '1' : '0';
page[1] = '\n';
len = 2;
PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
@@ -435,7 +435,7 @@ void ide_remove_proc_entries(struct proc_dir_entry *dir, ide_proc_entry_t *p)
}
}
-static void create_proc_ide_drives(ide_hwif_t *hwif)
+static void create_proc_ide_drives(struct ata_channel *hwif)
{
int d;
struct proc_dir_entry *ent;
@@ -465,7 +465,7 @@ static void create_proc_ide_drives(ide_hwif_t *hwif)
}
}
-static void destroy_proc_ide_device(ide_hwif_t *hwif, ide_drive_t *drive)
+static void destroy_proc_ide_device(struct ata_channel *hwif, ide_drive_t *drive)
{
struct ata_operations *driver = drive->driver;
@@ -479,7 +479,7 @@ static void destroy_proc_ide_device(ide_hwif_t *hwif, ide_drive_t *drive)
}
}
-void destroy_proc_ide_drives(ide_hwif_t *hwif)
+void destroy_proc_ide_drives(struct ata_channel *hwif)
{
int d;
@@ -503,7 +503,7 @@ void create_proc_ide_interfaces(void)
int h;
for (h = 0; h < MAX_HWIFS; h++) {
- ide_hwif_t *hwif = &ide_hwifs[h];
+ struct ata_channel *hwif = &ide_hwifs[h];
if (!hwif->present)
continue;
@@ -522,7 +522,7 @@ static void destroy_proc_ide_interfaces(void)
int h;
for (h = 0; h < MAX_HWIFS; h++) {
- ide_hwif_t *hwif = &ide_hwifs[h];
+ struct ata_channel *hwif = &ide_hwifs[h];
int exist = (hwif->proc != NULL);
#if 0
if (!hwif->present)
diff --git a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c
index 6cb6144471911..804c0f9dc19f6 100644
--- a/drivers/ide/ide-tape.c
+++ b/drivers/ide/ide-tape.c
@@ -2058,7 +2058,7 @@ static ide_startstop_t idetape_pc_intr (ide_drive_t *drive)
#ifdef CONFIG_BLK_DEV_IDEDMA
if (test_bit (PC_DMA_IN_PROGRESS, &pc->flags)) {
- if (HWIF(drive)->dmaproc(ide_dma_end, drive)) {
+ if (drive->channel->dmaproc(ide_dma_end, drive)) {
/*
* A DMA error is sometimes expected. For example,
* if the tape is crossing a filemark during a
@@ -2132,7 +2132,7 @@ static ide_startstop_t idetape_pc_intr (ide_drive_t *drive)
if (test_and_clear_bit (PC_DMA_IN_PROGRESS, &pc->flags)) {
printk (KERN_ERR "ide-tape: The tape wants to issue more interrupts in DMA mode\n");
printk (KERN_ERR "ide-tape: DMA disabled, reverting to PIO\n");
- HWIF(drive)->dmaproc(ide_dma_off, drive);
+ drive->channel->dmaproc(ide_dma_off, drive);
return ide_stopped;
}
#endif /* CONFIG_BLK_DEV_IDEDMA */
@@ -2155,7 +2155,8 @@ static ide_startstop_t idetape_pc_intr (ide_drive_t *drive)
if (temp > pc->buffer_size) {
printk (KERN_ERR "ide-tape: The tape wants to send us more data than expected - discarding data\n");
idetape_discard_data (drive, bcount.all);
- ide_set_handler (drive, &idetape_pc_intr, IDETAPE_WAIT_CMD, NULL);
+ BUG_ON(HWGROUP(drive)->handler);
+ ide_set_handler(drive, &idetape_pc_intr, IDETAPE_WAIT_CMD, NULL);
return ide_started;
}
#if IDETAPE_DEBUG_LOG
@@ -2181,7 +2182,8 @@ static ide_startstop_t idetape_pc_intr (ide_drive_t *drive)
if (tape->debug_level >= 2)
printk(KERN_INFO "ide-tape: [cmd %x] transferred %d bytes on that interrupt\n", pc->c[0], bcount.all);
#endif
- ide_set_handler (drive, &idetape_pc_intr, IDETAPE_WAIT_CMD, NULL); /* And set the interrupt handler again */
+ BUG_ON(HWGROUP(drive)->handler);
+ ide_set_handler(drive, &idetape_pc_intr, IDETAPE_WAIT_CMD, NULL); /* And set the interrupt handler again */
return ide_started;
}
@@ -2255,6 +2257,7 @@ static ide_startstop_t idetape_transfer_pc(ide_drive_t *drive)
return ide_stopped;
}
tape->cmd_start_time = jiffies;
+ BUG_ON(HWGROUP(drive)->handler);
ide_set_handler(drive, &idetape_pc_intr, IDETAPE_WAIT_CMD, NULL); /* Set the interrupt routine */
atapi_output_bytes (drive,pc->c,12); /* Send the actual packet */
return ide_started;
@@ -2309,10 +2312,10 @@ static ide_startstop_t idetape_issue_packet_command (ide_drive_t *drive, idetape
#ifdef CONFIG_BLK_DEV_IDEDMA
if (test_and_clear_bit (PC_DMA_ERROR, &pc->flags)) {
printk (KERN_WARNING "ide-tape: DMA disabled, reverting to PIO\n");
- (void) HWIF(drive)->dmaproc(ide_dma_off, drive);
+ (void) drive->channel->dmaproc(ide_dma_off, drive);
}
if (test_bit (PC_DMA_RECOMMENDED, &pc->flags) && drive->using_dma)
- dma_ok = !HWIF(drive)->dmaproc(test_bit (PC_WRITING, &pc->flags) ? ide_dma_write : ide_dma_read, drive);
+ dma_ok = !drive->channel->dmaproc(test_bit (PC_WRITING, &pc->flags) ? ide_dma_write : ide_dma_read, drive);
#endif /* CONFIG_BLK_DEV_IDEDMA */
if (IDE_CONTROL_REG)
@@ -2324,10 +2327,11 @@ static ide_startstop_t idetape_issue_packet_command (ide_drive_t *drive, idetape
#ifdef CONFIG_BLK_DEV_IDEDMA
if (dma_ok) { /* Begin DMA, if necessary */
set_bit (PC_DMA_IN_PROGRESS, &pc->flags);
- (void) (HWIF(drive)->dmaproc(ide_dma_begin, drive));
+ (void) drive->channel->dmaproc(ide_dma_begin, drive);
}
#endif /* CONFIG_BLK_DEV_IDEDMA */
if (test_bit(IDETAPE_DRQ_INTERRUPT, &tape->flags)) {
+ BUG_ON(HWGROUP(drive)->handler);
ide_set_handler(drive, &idetape_transfer_pc, IDETAPE_WAIT_CMD, NULL);
OUT_BYTE(WIN_PACKETCMD, IDE_COMMAND_REG);
return ide_started;
@@ -3103,10 +3107,10 @@ static ide_startstop_t idetape_read_position_callback (ide_drive_t *drive)
idetape_tape_t *tape = drive->driver_data;
idetape_read_position_result_t *result;
-//#if IDETAPE_DEBUG_LOG
-// if (tape->debug_level >= 4)
+#if IDETAPE_DEBUG_LOG
+ if (tape->debug_level >= 4)
printk (KERN_INFO "ide-tape: Reached idetape_read_position_callback\n");
-//#endif /* IDETAPE_DEBUG_LOG */
+#endif /* IDETAPE_DEBUG_LOG */
if (!tape->pc->error) {
result = (idetape_read_position_result_t *) tape->pc->buffer;
@@ -3280,10 +3284,10 @@ static int idetape_read_position (ide_drive_t *drive)
idetape_pc_t pc;
int position;
-//#if IDETAPE_DEBUG_LOG
-// if (tape->debug_level >= 4)
- printk (KERN_INFO "ide-tape: Reached idetape_read_position\n");
-//#endif /* IDETAPE_DEBUG_LOG */
+#if IDETAPE_DEBUG_LOG
+ if (tape->debug_level >= 4)
+ printk (KERN_INFO "ide-tape: Reached idetape_read_position\n");
+#endif /* IDETAPE_DEBUG_LOG */
#ifdef NO_LONGER_REQUIRED
idetape_flush_tape_buffers(drive);
@@ -5997,13 +6001,13 @@ static void idetape_setup (ide_drive_t *drive, idetape_tape_t *tape, int minor)
tape->onstream = 1;
drive->dsc_overlap = 1;
#ifdef CONFIG_BLK_DEV_IDEPCI
- if (!tape->onstream && HWIF(drive)->pci_dev != NULL) {
+ if (!tape->onstream && drive->channel->pci_dev != NULL) {
/*
* These two ide-pci host adapters appear to need DSC overlap disabled.
* This probably needs further analysis.
*/
- if ((HWIF(drive)->pci_dev->device == PCI_DEVICE_ID_ARTOP_ATP850UF) ||
- (HWIF(drive)->pci_dev->device == PCI_DEVICE_ID_TTI_HPT343)) {
+ if ((drive->channel->pci_dev->device == PCI_DEVICE_ID_ARTOP_ATP850UF) ||
+ (drive->channel->pci_dev->device == PCI_DEVICE_ID_TTI_HPT343)) {
printk(KERN_INFO "ide-tape: %s: disabling DSC overlap\n", tape->name);
drive->dsc_overlap = 0;
}
@@ -6099,8 +6103,7 @@ static int idetape_cleanup (ide_drive_t *drive)
idetape_chrdevs[minor].drive = NULL;
restore_flags (flags); /* all CPUs (overkill?) */
- /* FIXME: this appears to be totally wrong! */
- ata_ops(drive)->busy = 0;
+ MOD_DEC_USE_COUNT;
ide_unregister_subdriver (drive);
drive->driver_data = NULL;
@@ -6255,12 +6258,12 @@ int idetape_init (void)
idetape_chrdevs[minor].drive = drive;
tape->de_r =
devfs_register (drive->de, "mt", DEVFS_FL_DEFAULT,
- HWIF(drive)->major, minor,
+ drive->channel->major, minor,
S_IFCHR | S_IRUGO | S_IWUGO,
&idetape_fops, NULL);
tape->de_n =
devfs_register (drive->de, "mtn", DEVFS_FL_DEFAULT,
- HWIF(drive)->major, minor + 128,
+ drive->channel->major, minor + 128,
S_IFCHR | S_IRUGO | S_IWUGO,
&idetape_fops, NULL);
devfs_register_tape (tape->de_r);
diff --git a/drivers/ide/ide-taskfile.c b/drivers/ide/ide-taskfile.c
index 29ccab91a8972..33a33670aebb4 100644
--- a/drivers/ide/ide-taskfile.c
+++ b/drivers/ide/ide-taskfile.c
@@ -33,7 +33,7 @@
#define DEBUG_TASKFILE 0 /* unset when fixed */
#if DEBUG_TASKFILE
-#define DTF(x...) printk(##x)
+#define DTF(x...) printk(x)
#else
#define DTF(x...)
#endif
@@ -48,14 +48,14 @@ static inline char *ide_map_rq(struct request *rq, unsigned long *flags)
if (rq->bio)
return bio_kmap_irq(rq->bio, flags) + ide_rq_offset(rq);
else
- return rq->buffer + task_rq_offset(rq);
+ return rq->buffer + ((rq)->nr_sectors - (rq)->current_nr_sectors) * SECTOR_SIZE;
}
static inline void ide_unmap_rq(struct request *rq, char *to,
unsigned long *flags)
{
if (rq->bio)
- bio_kunmap_irq(to, flags);
+ bio_kunmap_irq(to, flags);
}
static void bswap_data (void *buffer, int wcount)
@@ -98,8 +98,8 @@ void ata_input_data(ide_drive_t *drive, void *buffer, unsigned int wcount)
* for handling polled ide transfers
*/
- if (HWIF(drive)->ideproc) {
- HWIF(drive)->ideproc(ideproc_ide_input_data, drive, buffer, wcount);
+ if (drive->channel->ideproc) {
+ drive->channel->ideproc(ideproc_ide_input_data, drive, buffer, wcount);
return;
}
@@ -138,8 +138,8 @@ void ata_output_data(ide_drive_t *drive, void *buffer, unsigned int wcount)
{
byte io_32bit;
- if (HWIF(drive)->ideproc) {
- HWIF(drive)->ideproc(ideproc_ide_output_data, drive, buffer, wcount);
+ if (drive->channel->ideproc) {
+ drive->channel->ideproc(ideproc_ide_output_data, drive, buffer, wcount);
return;
}
@@ -180,8 +180,8 @@ void ata_output_data(ide_drive_t *drive, void *buffer, unsigned int wcount)
*/
void atapi_input_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecount)
{
- if (HWIF(drive)->ideproc) {
- HWIF(drive)->ideproc(ideproc_atapi_input_bytes, drive, buffer, bytecount);
+ if (drive->channel->ideproc) {
+ drive->channel->ideproc(ideproc_atapi_input_bytes, drive, buffer, bytecount);
return;
}
@@ -200,8 +200,8 @@ void atapi_input_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecount
void atapi_output_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecount)
{
- if (HWIF(drive)->ideproc) {
- HWIF(drive)->ideproc(ideproc_atapi_output_bytes, drive, buffer, bytecount);
+ if (drive->channel->ideproc) {
+ drive->channel->ideproc(ideproc_atapi_output_bytes, drive, buffer, bytecount);
return;
}
@@ -243,7 +243,7 @@ int drive_is_ready(ide_drive_t *drive)
{
byte stat = 0;
if (drive->waiting_for_dma)
- return HWIF(drive)->dmaproc(ide_dma_test_irq, drive);
+ return drive->channel->dmaproc(ide_dma_test_irq, drive);
#if 0
/* need to guarantee 400ns since last command was issued */
udelay(1);
@@ -288,83 +288,124 @@ void ata_poll_drive_ready(ide_drive_t *drive)
break;
}
}
-static ide_startstop_t bio_mulout_intr(ide_drive_t *drive);
-/*
- * Handler for command write multiple
- * Called directly from execute_drive_cmd for the first bunch of sectors,
- * afterwards only by the ISR
- */
-static ide_startstop_t task_mulout_intr(ide_drive_t *drive)
+static ide_startstop_t pre_task_mulout_intr(ide_drive_t *drive, struct request *rq)
+{
+ ide_task_t *args = rq->special;
+ ide_startstop_t startstop;
+
+ /*
+ * assign private copy for multi-write
+ */
+ memcpy(&HWGROUP(drive)->wrq, rq, sizeof(struct request));
+
+ if (ide_wait_stat(&startstop, drive, DATA_READY, drive->bad_wstat, WAIT_DRQ))
+ return startstop;
+
+ ata_poll_drive_ready(drive);
+ return args->handler(drive);
+}
+
+static ide_startstop_t task_mulout_intr (ide_drive_t *drive)
{
- unsigned int msect, nsect;
byte stat = GET_STAT();
byte io_32bit = drive->io_32bit;
- struct request *rq = HWGROUP(drive)->rq;
+ struct request *rq = &HWGROUP(drive)->wrq;
ide_hwgroup_t *hwgroup = HWGROUP(drive);
- char *pBuf = NULL;
- unsigned long flags;
+ int mcount = drive->mult_count;
+ ide_startstop_t startstop;
/*
* (ks/hs): Handle last IRQ on multi-sector transfer,
* occurs after all data was sent in this chunk
*/
- if (rq->current_nr_sectors == 0) {
- if (stat & (ERR_STAT|DRQ_STAT))
- return ide_error(drive, "task_mulout_intr", stat);
+ if (!rq->nr_sectors) {
+ if (stat & (ERR_STAT|DRQ_STAT)) {
+ startstop = ide_error(drive, "task_mulout_intr", stat);
+ memcpy(rq, HWGROUP(drive)->rq, sizeof(struct request));
+ return startstop;
+ }
- /*
- * there may be more, ide_do_request will restart it if
- * necessary
- */
- ide_end_request(drive, 1);
+ __ide_end_request(drive, 1, rq->hard_nr_sectors);
+ rq->bio = NULL;
return ide_stopped;
}
- if (!OK_STAT(stat,DATA_READY,BAD_R_STAT)) {
- if (stat & (ERR_STAT|DRQ_STAT)) {
- return ide_error(drive, "task_mulout_intr", stat);
+ if (!OK_STAT(stat, DATA_READY, BAD_R_STAT)) {
+ if (stat & (ERR_STAT | DRQ_STAT)) {
+ startstop = ide_error(drive, "task_mulout_intr", stat);
+ memcpy(rq, HWGROUP(drive)->rq, sizeof(struct request));
+ return startstop;
}
+
/* no data yet, so wait for another interrupt */
if (hwgroup->handler == NULL)
- ide_set_handler(drive, &task_mulout_intr, WAIT_CMD, NULL);
+ ide_set_handler(drive, task_mulout_intr, WAIT_CMD, NULL);
+
return ide_started;
}
- /* (ks/hs): See task_mulin_intr */
- msect = drive->mult_count;
- nsect = rq->current_nr_sectors;
- if (nsect > msect)
- nsect = msect;
+ do {
+ char *buffer;
+ int nsect = rq->current_nr_sectors;
+ unsigned long flags;
+
+ if (nsect > mcount)
+ nsect = mcount;
+ mcount -= nsect;
+
+ buffer = bio_kmap_irq(rq->bio, &flags) + ide_rq_offset(rq);
+ rq->sector += nsect;
+ rq->nr_sectors -= nsect;
+ rq->current_nr_sectors -= nsect;
+
+ /* Do we move to the next bio after this? */
+ if (!rq->current_nr_sectors) {
+ /* remember to fix this up /jens */
+ struct bio *bio = rq->bio->bi_next;
+
+ /* end early if we ran out of requests */
+ if (!bio) {
+ mcount = 0;
+ } else {
+ rq->bio = bio;
+ rq->current_nr_sectors = bio_iovec(bio)->bv_len >> 9;
+ }
+ }
+
+ /*
+ * Ok, we're all setup for the interrupt
+ * re-entering us on the last transfer.
+ */
+ taskfile_output_data(drive, buffer, nsect * SECTOR_WORDS);
+ bio_kunmap_irq(buffer, &flags);
+ } while (mcount);
- pBuf = ide_map_rq(rq, &flags);
- DTF("Multiwrite: %p, nsect: %d , rq->current_nr_sectors: %ld\n",
- pBuf, nsect, rq->current_nr_sectors);
- drive->io_32bit = 0;
- taskfile_output_data(drive, pBuf, nsect * SECTOR_WORDS);
- ide_unmap_rq(rq, pBuf, &flags);
drive->io_32bit = io_32bit;
rq->errors = 0;
- /* Are we sure that this as all been already transfered? */
- rq->current_nr_sectors -= nsect;
if (hwgroup->handler == NULL)
- ide_set_handler(drive, &task_mulout_intr, WAIT_CMD, NULL);
+ ide_set_handler(drive, task_mulout_intr, WAIT_CMD, NULL);
+
return ide_started;
}
-ide_startstop_t do_rw_taskfile(ide_drive_t *drive, ide_task_t *task)
+ide_startstop_t ata_taskfile(ide_drive_t *drive,
+ struct hd_drive_task_hdr *taskfile,
+ struct hd_drive_hob_hdr *hobfile,
+ ide_handler_t *handler,
+ ide_pre_handler_t *prehandler,
+ struct request *rq
+ )
{
- task_struct_t *taskfile = (task_struct_t *) task->tfRegister;
- hob_struct_t *hobfile = (hob_struct_t *) task->hobRegister;
struct hd_driveid *id = drive->id;
- byte HIHI = (drive->addressing) ? 0xE0 : 0xEF;
+ u8 HIHI = (drive->addressing) ? 0xE0 : 0xEF;
/* (ks/hs): Moved to start, do not use for multiple out commands */
- if (task->handler != task_mulout_intr && task->handler != bio_mulout_intr) {
+ if (handler != task_mulout_intr) {
if (IDE_CONTROL_REG)
OUT_BYTE(drive->ctl, IDE_CONTROL_REG); /* clear nIEN */
- SELECT_MASK(HWIF(drive), drive, 0);
+ SELECT_MASK(drive->channel, drive, 0);
}
if ((id->command_set_2 & 0x0400) &&
@@ -386,67 +427,24 @@ ide_startstop_t do_rw_taskfile(ide_drive_t *drive, ide_task_t *task)
OUT_BYTE(taskfile->high_cylinder, IDE_HCYL_REG);
OUT_BYTE((taskfile->device_head & HIHI) | drive->select.all, IDE_SELECT_REG);
- if (task->handler != NULL) {
- ide_set_handler (drive, task->handler, WAIT_CMD, NULL);
+ if (handler != NULL) {
+ ide_set_handler(drive, handler, WAIT_CMD, NULL);
OUT_BYTE(taskfile->command, IDE_COMMAND_REG);
/*
* Warning check for race between handler and prehandler for
* writing first block of data. however since we are well
* inside the boundaries of the seek, we should be okay.
*/
- if (task->prehandler != NULL) {
- return task->prehandler(drive, task->rq);
- }
+ if (prehandler != NULL)
+ return prehandler(drive, rq);
} else {
/* for dma commands we down set the handler */
- if (drive->using_dma && !(HWIF(drive)->dmaproc(((taskfile->command == WIN_WRITEDMA) || (taskfile->command == WIN_WRITEDMA_EXT)) ? ide_dma_write : ide_dma_read, drive)));
+ if (drive->using_dma && !(drive->channel->dmaproc(((taskfile->command == WIN_WRITEDMA) || (taskfile->command == WIN_WRITEDMA_EXT)) ? ide_dma_write : ide_dma_read, drive)));
}
return ide_started;
}
-void do_taskfile(ide_drive_t *drive, struct hd_drive_task_hdr *taskfile,
- struct hd_drive_hob_hdr *hobfile,
- ide_handler_t *handler)
-{
- struct hd_driveid *id = drive->id;
- byte HIHI = (drive->addressing) ? 0xE0 : 0xEF;
-
- /* (ks/hs): Moved to start, do not use for multiple out commands */
- if (*handler != task_mulout_intr && handler != bio_mulout_intr) {
- if (IDE_CONTROL_REG)
- OUT_BYTE(drive->ctl, IDE_CONTROL_REG); /* clear nIEN */
- SELECT_MASK(HWIF(drive), drive, 0);
- }
-
- if ((id->command_set_2 & 0x0400) &&
- (id->cfs_enable_2 & 0x0400) &&
- (drive->addressing == 1)) {
- OUT_BYTE(hobfile->feature, IDE_FEATURE_REG);
- OUT_BYTE(hobfile->sector_count, IDE_NSECTOR_REG);
- OUT_BYTE(hobfile->sector_number, IDE_SECTOR_REG);
- OUT_BYTE(hobfile->low_cylinder, IDE_LCYL_REG);
- OUT_BYTE(hobfile->high_cylinder, IDE_HCYL_REG);
- }
-
- OUT_BYTE(taskfile->feature, IDE_FEATURE_REG);
- OUT_BYTE(taskfile->sector_count, IDE_NSECTOR_REG);
- /* refers to number of sectors to transfer */
- OUT_BYTE(taskfile->sector_number, IDE_SECTOR_REG);
- /* refers to sector offset or start sector */
- OUT_BYTE(taskfile->low_cylinder, IDE_LCYL_REG);
- OUT_BYTE(taskfile->high_cylinder, IDE_HCYL_REG);
-
- OUT_BYTE((taskfile->device_head & HIHI) | drive->select.all, IDE_SELECT_REG);
- if (handler != NULL) {
- ide_set_handler (drive, handler, WAIT_CMD, NULL);
- OUT_BYTE(taskfile->command, IDE_COMMAND_REG);
- } else {
- /* for dma commands we down set the handler */
- if (drive->using_dma && !(HWIF(drive)->dmaproc(((taskfile->command == WIN_WRITEDMA) || (taskfile->command == WIN_WRITEDMA_EXT)) ? ide_dma_write : ide_dma_read, drive)));
- }
-}
-
/*
* This is invoked on completion of a WIN_SETMULT cmd.
*/
@@ -567,8 +565,8 @@ static ide_startstop_t pre_task_out_intr (ide_drive_t *drive, struct request *rq
}
/* (ks/hs): Fixed Multi Write */
- if ((args->tfRegister[IDE_COMMAND_OFFSET] != WIN_MULTWRITE) &&
- (args->tfRegister[IDE_COMMAND_OFFSET] != WIN_MULTWRITE_EXT)) {
+ if ((args->taskfile.command != WIN_MULTWRITE) &&
+ (args->taskfile.command != WIN_MULTWRITE_EXT)) {
unsigned long flags;
char *buf = ide_map_rq(rq, &flags);
/* For Write_sectors we need to stuff the first sector */
@@ -616,107 +614,6 @@ static ide_startstop_t task_out_intr(ide_drive_t *drive)
return ide_started;
}
-static ide_startstop_t pre_bio_out_intr(ide_drive_t *drive, struct request *rq)
-{
- ide_task_t *args = rq->special;
- ide_startstop_t startstop;
-
- /*
- * assign private copy for multi-write
- */
- memcpy(&HWGROUP(drive)->wrq, rq, sizeof(struct request));
-
- if (ide_wait_stat(&startstop, drive, DATA_READY, drive->bad_wstat, WAIT_DRQ))
- return startstop;
-
- ata_poll_drive_ready(drive);
- return args->handler(drive);
-}
-
-
-static ide_startstop_t bio_mulout_intr (ide_drive_t *drive)
-{
- byte stat = GET_STAT();
- byte io_32bit = drive->io_32bit;
- struct request *rq = &HWGROUP(drive)->wrq;
- ide_hwgroup_t *hwgroup = HWGROUP(drive);
- int mcount = drive->mult_count;
- ide_startstop_t startstop;
-
- /*
- * (ks/hs): Handle last IRQ on multi-sector transfer,
- * occurs after all data was sent in this chunk
- */
- if (!rq->nr_sectors) {
- if (stat & (ERR_STAT|DRQ_STAT)) {
- startstop = ide_error(drive, "bio_mulout_intr", stat);
- memcpy(rq, HWGROUP(drive)->rq, sizeof(struct request));
- return startstop;
- }
-
- __ide_end_request(drive, 1, rq->hard_nr_sectors);
- HWGROUP(drive)->wrq.bio = NULL;
- return ide_stopped;
- }
-
- if (!OK_STAT(stat, DATA_READY, BAD_R_STAT)) {
- if (stat & (ERR_STAT | DRQ_STAT)) {
- startstop = ide_error(drive, "bio_mulout_intr", stat);
- memcpy(rq, HWGROUP(drive)->rq, sizeof(struct request));
- return startstop;
- }
-
- /* no data yet, so wait for another interrupt */
- if (hwgroup->handler == NULL)
- ide_set_handler(drive, bio_mulout_intr, WAIT_CMD, NULL);
-
- return ide_started;
- }
-
- do {
- char *buffer;
- int nsect = rq->current_nr_sectors;
- unsigned long flags;
-
- if (nsect > mcount)
- nsect = mcount;
- mcount -= nsect;
-
- buffer = bio_kmap_irq(rq->bio, &flags) + ide_rq_offset(rq);
- rq->sector += nsect;
- rq->nr_sectors -= nsect;
- rq->current_nr_sectors -= nsect;
-
- /* Do we move to the next bio after this? */
- if (!rq->current_nr_sectors) {
- /* remember to fix this up /jens */
- struct bio *bio = rq->bio->bi_next;
-
- /* end early early we ran out of requests */
- if (!bio) {
- mcount = 0;
- } else {
- rq->bio = bio;
- rq->current_nr_sectors = bio_iovec(bio)->bv_len >> 9;
- }
- }
-
- /*
- * Ok, we're all setup for the interrupt
- * re-entering us on the last transfer.
- */
- taskfile_output_data(drive, buffer, nsect * SECTOR_WORDS);
- bio_kunmap_irq(buffer, &flags);
- } while (mcount);
-
- drive->io_32bit = io_32bit;
- rq->errors = 0;
- if (hwgroup->handler == NULL)
- ide_set_handler(drive, bio_mulout_intr, WAIT_CMD, NULL);
-
- return ide_started;
-}
-
/*
* Handler for command with Read Multiple
*/
@@ -774,12 +671,12 @@ static ide_startstop_t task_mulin_intr(ide_drive_t *drive)
/* Called by ioctl to feature out type of command being called */
void ide_cmd_type_parser(ide_task_t *args)
{
- struct hd_drive_task_hdr *taskfile = (struct hd_drive_task_hdr *) args->tfRegister;
+ struct hd_drive_task_hdr *taskfile = &args->taskfile;
args->prehandler = NULL;
args->handler = NULL;
- switch(args->tfRegister[IDE_COMMAND_OFFSET]) {
+ switch(args->taskfile.command) {
case WIN_IDENTIFY:
case WIN_PIDENTIFY:
args->handler = task_in_intr;
@@ -814,8 +711,8 @@ void ide_cmd_type_parser(ide_task_t *args)
case CFA_WRITE_MULTI_WO_ERASE:
case WIN_MULTWRITE:
case WIN_MULTWRITE_EXT:
- args->prehandler = pre_bio_out_intr;
- args->handler = bio_mulout_intr;
+ args->prehandler = pre_task_mulout_intr;
+ args->handler = task_mulout_intr;
args->command_type = IDE_DRIVE_TASK_RAW_WRITE;
return;
@@ -830,9 +727,11 @@ void ide_cmd_type_parser(ide_task_t *args)
case WIN_SMART:
if (taskfile->feature == SMART_WRITE_LOG_SECTOR)
args->prehandler = pre_task_out_intr;
- args->tfRegister[IDE_LCYL_OFFSET] = SMART_LCYL_PASS;
- args->tfRegister[IDE_HCYL_OFFSET] = SMART_HCYL_PASS;
- switch(args->tfRegister[IDE_FEATURE_OFFSET]) {
+
+ args->taskfile.low_cylinder = SMART_LCYL_PASS;
+ args->taskfile.high_cylinder = SMART_HCYL_PASS;
+
+ switch(args->taskfile.feature) {
case SMART_READ_VALUES:
case SMART_READ_THRESHOLDS:
case SMART_READ_LOG_SECTOR:
@@ -870,7 +769,7 @@ void ide_cmd_type_parser(ide_task_t *args)
#endif
case WIN_SETFEATURES:
args->handler = task_no_data_intr;
- switch(args->tfRegister[IDE_FEATURE_OFFSET]) {
+ switch(args->taskfile.feature) {
case SETFEATURES_XFER:
args->command_type = IDE_DRIVE_TASK_SET_XFER;
return;
@@ -960,7 +859,7 @@ void ide_cmd_type_parser(ide_task_t *args)
/*
* This function is intended to be used prior to invoking ide_do_drive_cmd().
*/
-static void ide_init_drive_taskfile (struct request *rq)
+static void init_taskfile_request(struct request *rq)
{
memset(rq, 0, sizeof(*rq));
rq->flags = REQ_DRIVE_TASKFILE;
@@ -968,37 +867,25 @@ static void ide_init_drive_taskfile (struct request *rq)
/*
* This is kept for internal use only !!!
- * This is an internal call and nobody in user-space has a damn
+ * This is an internal call and nobody in user-space has a
* reason to call this taskfile.
*
* ide_raw_taskfile is the one that user-space executes.
*/
+
int ide_wait_taskfile(ide_drive_t *drive, struct hd_drive_task_hdr *taskfile, struct hd_drive_hob_hdr *hobfile, byte *buf)
{
struct request rq;
+ /* FIXME: This is on stack! */
ide_task_t args;
memset(&args, 0, sizeof(ide_task_t));
- args.tfRegister[IDE_DATA_OFFSET] = taskfile->data;
- args.tfRegister[IDE_FEATURE_OFFSET] = taskfile->feature;
- args.tfRegister[IDE_NSECTOR_OFFSET] = taskfile->sector_count;
- args.tfRegister[IDE_SECTOR_OFFSET] = taskfile->sector_number;
- args.tfRegister[IDE_LCYL_OFFSET] = taskfile->low_cylinder;
- args.tfRegister[IDE_HCYL_OFFSET] = taskfile->high_cylinder;
- args.tfRegister[IDE_SELECT_OFFSET] = taskfile->device_head;
- args.tfRegister[IDE_COMMAND_OFFSET] = taskfile->command;
-
- args.hobRegister[IDE_DATA_OFFSET_HOB] = hobfile->data;
- args.hobRegister[IDE_FEATURE_OFFSET_HOB] = hobfile->feature;
- args.hobRegister[IDE_NSECTOR_OFFSET_HOB] = hobfile->sector_count;
- args.hobRegister[IDE_SECTOR_OFFSET_HOB] = hobfile->sector_number;
- args.hobRegister[IDE_LCYL_OFFSET_HOB] = hobfile->low_cylinder;
- args.hobRegister[IDE_HCYL_OFFSET_HOB] = hobfile->high_cylinder;
- args.hobRegister[IDE_SELECT_OFFSET_HOB] = hobfile->device_head;
- args.hobRegister[IDE_CONTROL_OFFSET_HOB] = hobfile->control;
-
- ide_init_drive_taskfile(&rq);
+ args.taskfile = *taskfile;
+ args.hobfile = *hobfile;
+
+ init_taskfile_request(&rq);
+
/* This is kept for internal use only !!! */
ide_cmd_type_parser(&args);
if (args.command_type != IDE_DRIVE_TASK_NO_DATA)
@@ -1006,64 +893,33 @@ int ide_wait_taskfile(ide_drive_t *drive, struct hd_drive_task_hdr *taskfile, st
rq.buffer = buf;
rq.special = &args;
+
return ide_do_drive_cmd(drive, &rq, ide_wait);
}
int ide_raw_taskfile(ide_drive_t *drive, ide_task_t *args, byte *buf)
{
struct request rq;
- ide_init_drive_taskfile(&rq);
+ init_taskfile_request(&rq);
rq.buffer = buf;
if (args->command_type != IDE_DRIVE_TASK_NO_DATA)
- rq.current_nr_sectors = rq.nr_sectors = (args->hobRegister[IDE_NSECTOR_OFFSET_HOB] << 8) | args->tfRegister[IDE_NSECTOR_OFFSET];
+ rq.current_nr_sectors = rq.nr_sectors
+ = (args->hobfile.sector_count << 8)
+ | args->taskfile.sector_count;
rq.special = args;
+
return ide_do_drive_cmd(drive, &rq, ide_wait);
}
/*
- * The taskfile glue table
- *
- * reqtask.data_phase reqtask.req_cmd
- * args.command_type args.handler
- *
- * TASKFILE_P_OUT_DMAQ ?? ??
- * TASKFILE_P_IN_DMAQ ?? ??
- * TASKFILE_P_OUT_DMA ?? ??
- * TASKFILE_P_IN_DMA ?? ??
- * TASKFILE_P_OUT ?? ??
- * TASKFILE_P_IN ?? ??
- *
- * TASKFILE_OUT_DMAQ IDE_DRIVE_TASK_RAW_WRITE NULL
- * TASKFILE_IN_DMAQ IDE_DRIVE_TASK_IN NULL
- *
- * TASKFILE_OUT_DMA IDE_DRIVE_TASK_RAW_WRITE NULL
- * TASKFILE_IN_DMA IDE_DRIVE_TASK_IN NULL
- *
- * TASKFILE_IN_OUT ?? ??
- *
- * TASKFILE_MULTI_OUT IDE_DRIVE_TASK_RAW_WRITE task_mulout_intr
- * TASKFILE_MULTI_IN IDE_DRIVE_TASK_IN task_mulin_intr
- *
- * TASKFILE_OUT IDE_DRIVE_TASK_RAW_WRITE task_out_intr
- * TASKFILE_OUT IDE_DRIVE_TASK_OUT task_out_intr
- *
- * TASKFILE_IN IDE_DRIVE_TASK_IN task_in_intr
- * TASKFILE_NO_DATA IDE_DRIVE_TASK_NO_DATA task_no_data_intr
- *
- * IDE_DRIVE_TASK_SET_XFER task_no_data_intr
- * IDE_DRIVE_TASK_INVALID
- *
- */
-
-/*
- * Issue ATA command and wait for completion. use for implementing commands in
+ * Issue ATA command and wait for completion. Use for implementing commands in
* kernel.
*
* The caller has to make sure buf is never NULL!
*/
-static int ide_wait_cmd(ide_drive_t *drive, int cmd, int nsect, int feature, int sectors, byte *argbuf)
+static int ide_wait_cmd(ide_drive_t *drive, u8 cmd, u8 nsect, u8 feature, u8 sectors, u8 *argbuf)
{
struct request rq;
@@ -1072,10 +928,10 @@ static int ide_wait_cmd(ide_drive_t *drive, int cmd, int nsect, int feature, int
memset(argbuf, 0, 4 + SECTOR_WORDS * 4 * sectors);
ide_init_drive_cmd(&rq);
rq.buffer = argbuf;
- *argbuf++ = cmd;
- *argbuf++ = nsect;
- *argbuf++ = feature;
- *argbuf++ = sectors;
+ argbuf[0] = cmd;
+ argbuf[1] = nsect;
+ argbuf[2] = feature;
+ argbuf[3] = sectors;
return ide_do_drive_cmd(drive, &rq, ide_wait);
}
@@ -1083,7 +939,8 @@ static int ide_wait_cmd(ide_drive_t *drive, int cmd, int nsect, int feature, int
int ide_cmd_ioctl(ide_drive_t *drive, struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
{
int err = 0;
- byte args[4], *argbuf = args;
+ u8 args[4];
+ u8 *argbuf = args;
byte xfer_rate = 0;
int argsize = 4;
ide_task_t tfargs;
@@ -1096,13 +953,13 @@ int ide_cmd_ioctl(ide_drive_t *drive, struct inode *inode, struct file *file, un
if (copy_from_user(args, (void *)arg, 4))
return -EFAULT;
- tfargs.tfRegister[IDE_FEATURE_OFFSET] = args[2];
- tfargs.tfRegister[IDE_NSECTOR_OFFSET] = args[3];
- tfargs.tfRegister[IDE_SECTOR_OFFSET] = args[1];
- tfargs.tfRegister[IDE_LCYL_OFFSET] = 0x00;
- tfargs.tfRegister[IDE_HCYL_OFFSET] = 0x00;
- tfargs.tfRegister[IDE_SELECT_OFFSET] = 0x00;
- tfargs.tfRegister[IDE_COMMAND_OFFSET] = args[0];
+ tfargs.taskfile.feature = args[2];
+ tfargs.taskfile.sector_count = args[3];
+ tfargs.taskfile.sector_number = args[1];
+ tfargs.taskfile.low_cylinder = 0x00;
+ tfargs.taskfile.high_cylinder = 0x00;
+ tfargs.taskfile.device_head = 0x00;
+ tfargs.taskfile.command = args[0];
if (args[3]) {
argsize = 4 + (SECTOR_WORDS * 4 * args[3]);
@@ -1121,8 +978,8 @@ int ide_cmd_ioctl(ide_drive_t *drive, struct inode *inode, struct file *file, un
if (!err && xfer_rate) {
/* active-retuning-calls future */
- if ((HWIF(drive)->speedproc) != NULL)
- HWIF(drive)->speedproc(drive, xfer_rate);
+ if ((drive->channel->speedproc) != NULL)
+ drive->channel->speedproc(drive, xfer_rate);
ide_driveid_update(drive);
}
abort:
@@ -1162,8 +1019,7 @@ EXPORT_SYMBOL(atapi_input_bytes);
EXPORT_SYMBOL(atapi_output_bytes);
EXPORT_SYMBOL(taskfile_input_data);
EXPORT_SYMBOL(taskfile_output_data);
-EXPORT_SYMBOL(do_rw_taskfile);
-EXPORT_SYMBOL(do_taskfile);
+EXPORT_SYMBOL(ata_taskfile);
EXPORT_SYMBOL(recal_intr);
EXPORT_SYMBOL(set_geometry_intr);
diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c
index 6cf6d4e8b9d0e..75f0f19c21f08 100644
--- a/drivers/ide/ide.c
+++ b/drivers/ide/ide.c
@@ -223,7 +223,7 @@ int noautodma = 0;
/*
* This is declared extern in ide.h, for access by other IDE modules:
*/
-ide_hwif_t ide_hwifs[MAX_HWIFS]; /* master data repository */
+struct ata_channel ide_hwifs[MAX_HWIFS]; /* master data repository */
#if (DISK_RECOVERY_TIME > 0)
/*
@@ -244,19 +244,19 @@ static unsigned long read_timer (void)
__restore_flags(flags); /* local CPU only */
return (t - i);
}
-#endif /* DISK_RECOVERY_TIME */
+#endif
-static inline void set_recovery_timer (ide_hwif_t *hwif)
+static inline void set_recovery_timer(struct ata_channel *channel)
{
#if (DISK_RECOVERY_TIME > 0)
- hwif->last_time = read_timer();
-#endif /* DISK_RECOVERY_TIME */
+ channel->last_time = read_timer();
+#endif
}
/*
* Do not even *think* about calling this!
*/
-static void init_hwif_data(ide_hwif_t *hwif, unsigned int index)
+static void init_hwif_data(struct ata_channel *hwif, unsigned int index)
{
static const byte ide_major[] = {
IDE0_MAJOR, IDE1_MAJOR, IDE2_MAJOR, IDE3_MAJOR, IDE4_MAJOR,
@@ -267,7 +267,7 @@ static void init_hwif_data(ide_hwif_t *hwif, unsigned int index)
hw_regs_t hw;
/* bulk initialize hwif & drive info with zeros */
- memset(hwif, 0, sizeof(ide_hwif_t));
+ memset(hwif, 0, sizeof(struct ata_channel));
memset(&hw, 0, sizeof(hw_regs_t));
/* fill in any non-zero initial values */
@@ -288,7 +288,7 @@ static void init_hwif_data(ide_hwif_t *hwif, unsigned int index)
drive->type = ATA_DISK;
drive->select.all = (unit<<4)|0xa0;
- drive->hwif = hwif;
+ drive->channel = hwif;
drive->ctl = 0x08;
drive->ready_stat = READY_STAT;
drive->bad_wstat = BAD_W_STAT;
@@ -445,13 +445,13 @@ static void ata_pre_reset (ide_drive_t *drive)
if (drive->using_dma) {
/* check the DMA crc count */
if (drive->crc_count) {
- HWIF(drive)->dmaproc(ide_dma_off_quietly, drive);
- if ((HWIF(drive)->speedproc) != NULL)
- HWIF(drive)->speedproc(drive, ide_auto_reduce_xfer(drive));
+ drive->channel->dmaproc(ide_dma_off_quietly, drive);
+ if ((drive->channel->speedproc) != NULL)
+ drive->channel->speedproc(drive, ide_auto_reduce_xfer(drive));
if (drive->current_speed >= XFER_SW_DMA_0)
- HWIF(drive)->dmaproc(ide_dma_on, drive);
+ drive->channel->dmaproc(ide_dma_on, drive);
} else
- HWIF(drive)->dmaproc(ide_dma_off, drive);
+ drive->channel->dmaproc(ide_dma_off, drive);
}
}
@@ -483,7 +483,7 @@ static ide_startstop_t ata_special (ide_drive_t *drive)
printk("%s: ata_special: 0x%02x\n", drive->name, s->all);
#endif
if (s->b.set_tune) {
- ide_tuneproc_t *tuneproc = HWIF(drive)->tuneproc;
+ ide_tuneproc_t *tuneproc = drive->channel->tuneproc;
s->b.set_tune = 0;
if (tuneproc != NULL)
tuneproc(drive, drive->tune_req);
@@ -507,9 +507,9 @@ static ide_startstop_t ata_special (ide_drive_t *drive)
extern struct block_device_operations ide_fops[];
/*
- * ide_geninit() is called exactly *once* for each interface.
+ * This is called exactly *once* for each channel.
*/
-void ide_geninit (ide_hwif_t *hwif)
+void ide_geninit(struct ata_channel *hwif)
{
unsigned int unit;
struct gendisk *gd = hwif->gd;
@@ -542,13 +542,14 @@ static ide_startstop_t atapi_reset_pollfunc (ide_drive_t *drive)
ide_hwgroup_t *hwgroup = HWGROUP(drive);
byte stat;
- SELECT_DRIVE(HWIF(drive),drive);
+ SELECT_DRIVE(drive->channel,drive);
udelay (10);
if (OK_STAT(stat=GET_STAT(), 0, BUSY_STAT)) {
printk("%s: ATAPI reset complete\n", drive->name);
} else {
- if (0 < (signed long)(hwgroup->poll_timeout - jiffies)) {
+ if (time_before(jiffies, hwgroup->poll_timeout)) {
+ BUG_ON(HWGROUP(drive)->handler);
ide_set_handler (drive, &atapi_reset_pollfunc, HZ/20, NULL);
return ide_started; /* continue polling */
}
@@ -569,11 +570,12 @@ static ide_startstop_t atapi_reset_pollfunc (ide_drive_t *drive)
static ide_startstop_t reset_pollfunc (ide_drive_t *drive)
{
ide_hwgroup_t *hwgroup = HWGROUP(drive);
- ide_hwif_t *hwif = HWIF(drive);
+ struct ata_channel *hwif = drive->channel;
byte tmp;
if (!OK_STAT(tmp=GET_STAT(), 0, BUSY_STAT)) {
- if (0 < (signed long)(hwgroup->poll_timeout - jiffies)) {
+ if (time_before(jiffies, hwgroup->poll_timeout)) {
+ BUG_ON(HWGROUP(drive)->handler);
ide_set_handler (drive, &reset_pollfunc, HZ/20, NULL);
return ide_started; /* continue polling */
}
@@ -632,7 +634,7 @@ static ide_startstop_t do_reset1 (ide_drive_t *drive, int do_not_try_atapi)
{
unsigned int unit;
unsigned long flags;
- ide_hwif_t *hwif = HWIF(drive);
+ struct ata_channel *hwif = drive->channel;
ide_hwgroup_t *hwgroup = HWGROUP(drive);
__save_flags(flags); /* local CPU only */
@@ -645,6 +647,7 @@ static ide_startstop_t do_reset1 (ide_drive_t *drive, int do_not_try_atapi)
udelay (20);
OUT_BYTE (WIN_SRST, IDE_COMMAND_REG);
hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
+ BUG_ON(HWGROUP(drive)->handler);
ide_set_handler (drive, &atapi_reset_pollfunc, HZ/20, NULL);
__restore_flags (flags); /* local CPU only */
return ide_started;
@@ -679,7 +682,8 @@ static ide_startstop_t do_reset1 (ide_drive_t *drive, int do_not_try_atapi)
}
udelay(10); /* more than enough time */
hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
- ide_set_handler (drive, &reset_pollfunc, HZ/20, NULL);
+ BUG_ON(HWGROUP(drive)->handler);
+ ide_set_handler(drive, &reset_pollfunc, HZ/20, NULL);
/*
* Some weird controller like resetting themselves to a strange
@@ -737,27 +741,25 @@ void ide_end_drive_cmd (ide_drive_t *drive, byte stat, byte err)
ide_task_t *args = (ide_task_t *) rq->special;
rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT);
if (args) {
- if (args->tf_in_flags.b.data) {
- unsigned short data = IN_WORD(IDE_DATA_REG);
- args->tfRegister[IDE_DATA_OFFSET] = (data) & 0xFF;
- args->hobRegister[IDE_DATA_OFFSET_HOB] = (data >> 8) & 0xFF;
- }
- args->tfRegister[IDE_ERROR_OFFSET] = err;
- args->tfRegister[IDE_NSECTOR_OFFSET] = IN_BYTE(IDE_NSECTOR_REG);
- args->tfRegister[IDE_SECTOR_OFFSET] = IN_BYTE(IDE_SECTOR_REG);
- args->tfRegister[IDE_LCYL_OFFSET] = IN_BYTE(IDE_LCYL_REG);
- args->tfRegister[IDE_HCYL_OFFSET] = IN_BYTE(IDE_HCYL_REG);
- args->tfRegister[IDE_SELECT_OFFSET] = IN_BYTE(IDE_SELECT_REG);
- args->tfRegister[IDE_STATUS_OFFSET] = stat;
+ args->taskfile.feature = err;
+ args->taskfile.sector_count = IN_BYTE(IDE_NSECTOR_REG);
+ args->taskfile.sector_number = IN_BYTE(IDE_SECTOR_REG);
+ args->taskfile.low_cylinder = IN_BYTE(IDE_LCYL_REG);
+ args->taskfile.high_cylinder = IN_BYTE(IDE_HCYL_REG);
+ args->taskfile.device_head = IN_BYTE(IDE_SELECT_REG);
+ args->taskfile.command = stat;
if ((drive->id->command_set_2 & 0x0400) &&
(drive->id->cfs_enable_2 & 0x0400) &&
(drive->addressing == 1)) {
- OUT_BYTE(drive->ctl|0x80, IDE_CONTROL_REG_HOB);
- args->hobRegister[IDE_FEATURE_OFFSET_HOB] = IN_BYTE(IDE_FEATURE_REG);
- args->hobRegister[IDE_NSECTOR_OFFSET_HOB] = IN_BYTE(IDE_NSECTOR_REG);
- args->hobRegister[IDE_SECTOR_OFFSET_HOB] = IN_BYTE(IDE_SECTOR_REG);
- args->hobRegister[IDE_LCYL_OFFSET_HOB] = IN_BYTE(IDE_LCYL_REG);
- args->hobRegister[IDE_HCYL_OFFSET_HOB] = IN_BYTE(IDE_HCYL_REG);
+ /* The following command goes to the hob file! */
+
+ OUT_BYTE(drive->ctl|0x80, IDE_CONTROL_REG);
+ args->hobfile.feature = IN_BYTE(IDE_FEATURE_REG);
+ args->hobfile.sector_count = IN_BYTE(IDE_NSECTOR_REG);
+
+ args->hobfile.sector_number = IN_BYTE(IDE_SECTOR_REG);
+ args->hobfile.low_cylinder = IN_BYTE(IDE_LCYL_REG);
+ args->hobfile.high_cylinder = IN_BYTE(IDE_HCYL_REG);
}
}
}
@@ -933,10 +935,11 @@ ide_startstop_t ide_error (ide_drive_t *drive, const char *msg, byte stat)
*/
void ide_cmd (ide_drive_t *drive, byte cmd, byte nsect, ide_handler_t *handler)
{
+ BUG_ON(HWGROUP(drive)->handler);
ide_set_handler (drive, handler, WAIT_CMD, NULL);
if (IDE_CONTROL_REG)
OUT_BYTE(drive->ctl,IDE_CONTROL_REG); /* clear nIEN */
- SELECT_MASK(HWIF(drive),drive,0);
+ SELECT_MASK(drive->channel, drive, 0);
OUT_BYTE(nsect,IDE_NSECTOR_REG);
OUT_BYTE(cmd,IDE_COMMAND_REG);
}
@@ -978,7 +981,7 @@ static ide_startstop_t drive_cmd_intr (ide_drive_t *drive)
* setting a timer to wake up at half second intervals thereafter,
* until timeout is achieved, before timing out.
*/
-int ide_wait_stat (ide_startstop_t *startstop, ide_drive_t *drive, byte good, byte bad, unsigned long timeout) {
+int ide_wait_stat(ide_startstop_t *startstop, ide_drive_t *drive, byte good, byte bad, unsigned long timeout) {
byte stat;
int i;
unsigned long flags;
@@ -1020,90 +1023,6 @@ int ide_wait_stat (ide_startstop_t *startstop, ide_drive_t *drive, byte good, by
}
/*
- * execute_drive_cmd() issues a special drive command,
- * usually initiated by ioctl() from the external hdparm program.
- */
-static ide_startstop_t execute_drive_cmd (ide_drive_t *drive, struct request *rq)
-{
- if (rq->flags & REQ_DRIVE_TASKFILE) {
- ide_task_t *args = rq->special;
-
- if (!(args))
- goto args_error;
-
- do_taskfile(drive,
- (struct hd_drive_task_hdr *)&args->tfRegister,
- (struct hd_drive_hob_hdr *)&args->hobRegister,
- args->handler);
-
- if (((args->command_type == IDE_DRIVE_TASK_RAW_WRITE) ||
- (args->command_type == IDE_DRIVE_TASK_OUT)) &&
- args->prehandler && args->handler)
- return args->prehandler(drive, rq);
- return ide_started;
-
- } else if (rq->flags & REQ_DRIVE_TASK) {
- byte *args = rq->buffer;
- byte sel;
-
- if (!(args)) goto args_error;
-#ifdef DEBUG
- printk("%s: DRIVE_TASK_CMD ", drive->name);
- printk("cmd=0x%02x ", args[0]);
- printk("fr=0x%02x ", args[1]);
- printk("ns=0x%02x ", args[2]);
- printk("sc=0x%02x ", args[3]);
- printk("lcyl=0x%02x ", args[4]);
- printk("hcyl=0x%02x ", args[5]);
- printk("sel=0x%02x\n", args[6]);
-#endif
- OUT_BYTE(args[1], IDE_FEATURE_REG);
- OUT_BYTE(args[3], IDE_SECTOR_REG);
- OUT_BYTE(args[4], IDE_LCYL_REG);
- OUT_BYTE(args[5], IDE_HCYL_REG);
- sel = (args[6] & ~0x10);
- if (drive->select.b.unit)
- sel |= 0x10;
- OUT_BYTE(sel, IDE_SELECT_REG);
- ide_cmd(drive, args[0], args[2], &drive_cmd_intr);
- return ide_started;
- } else if (rq->flags & REQ_DRIVE_CMD) {
-
- byte *args = rq->buffer;
- if (!(args)) goto args_error;
-#ifdef DEBUG
- printk("%s: DRIVE_CMD ", drive->name);
- printk("cmd=0x%02x ", args[0]);
- printk("sc=0x%02x ", args[1]);
- printk("fr=0x%02x ", args[2]);
- printk("xx=0x%02x\n", args[3]);
-#endif
- if (args[0] == WIN_SMART) {
- OUT_BYTE(0x4f, IDE_LCYL_REG);
- OUT_BYTE(0xc2, IDE_HCYL_REG);
- OUT_BYTE(args[2],IDE_FEATURE_REG);
- OUT_BYTE(args[1],IDE_SECTOR_REG);
- ide_cmd(drive, args[0], args[3], &drive_cmd_intr);
- return ide_started;
- }
- OUT_BYTE(args[2],IDE_FEATURE_REG);
- ide_cmd(drive, args[0], args[1], &drive_cmd_intr);
- return ide_started;
- }
-
-args_error:
- /*
- * NULL is actually a valid way of waiting for
- * all current requests to be flushed from the queue.
- */
-#ifdef DEBUG
- printk("%s: DRIVE_CMD (null)\n", drive->name);
-#endif
- ide_end_drive_cmd(drive, GET_STAT(), GET_ERR());
- return ide_stopped;
-}
-
-/*
* start_request() initiates handling of a new I/O request
*/
static ide_startstop_t start_request (ide_drive_t *drive, struct request *rq)
@@ -1111,7 +1030,7 @@ static ide_startstop_t start_request (ide_drive_t *drive, struct request *rq)
ide_startstop_t startstop;
unsigned long block;
unsigned int minor = minor(rq->rq_dev), unit = minor >> PARTN_BITS;
- ide_hwif_t *hwif = HWIF(drive);
+ struct ata_channel *hwif = drive->channel;
BUG_ON(!(rq->flags & REQ_STARTED));
@@ -1150,9 +1069,100 @@ static ide_startstop_t start_request (ide_drive_t *drive, struct request *rq)
printk(KERN_WARNING "%s: drive not ready for command\n", drive->name);
return startstop;
}
+
+ /* FIXME: We can see nicely here that all commands should be submitted
+ * through the request queue and that the special field in drive should
+ * go as soon as possible!
+ */
+
if (!drive->special.all) {
- if (rq->flags & (REQ_DRIVE_CMD | REQ_DRIVE_TASK | REQ_DRIVE_TASKFILE))
- return execute_drive_cmd(drive, rq);
+ if (rq->flags & (REQ_DRIVE_CMD | REQ_DRIVE_TASK | REQ_DRIVE_TASKFILE)) {
+ /* This issues a special drive command, usually
+ * initiated by ioctl() from the external hdparm
+ * program.
+ */
+
+ if (rq->flags & REQ_DRIVE_TASKFILE) {
+ ide_task_t *args = rq->special;
+
+ if (!(args))
+ goto args_error;
+
+ ata_taskfile(drive,
+ &args->taskfile,
+ &args->hobfile,
+ args->handler, NULL, NULL);
+
+ if (((args->command_type == IDE_DRIVE_TASK_RAW_WRITE) ||
+ (args->command_type == IDE_DRIVE_TASK_OUT)) &&
+ args->prehandler && args->handler)
+ return args->prehandler(drive, rq);
+ return ide_started;
+
+ } else if (rq->flags & REQ_DRIVE_TASK) {
+ byte *args = rq->buffer;
+ byte sel;
+
+ if (!(args)) goto args_error;
+#ifdef DEBUG
+ printk("%s: DRIVE_TASK_CMD ", drive->name);
+ printk("cmd=0x%02x ", args[0]);
+ printk("fr=0x%02x ", args[1]);
+ printk("ns=0x%02x ", args[2]);
+ printk("sc=0x%02x ", args[3]);
+ printk("lcyl=0x%02x ", args[4]);
+ printk("hcyl=0x%02x ", args[5]);
+ printk("sel=0x%02x\n", args[6]);
+#endif
+ OUT_BYTE(args[1], IDE_FEATURE_REG);
+ OUT_BYTE(args[3], IDE_SECTOR_REG);
+ OUT_BYTE(args[4], IDE_LCYL_REG);
+ OUT_BYTE(args[5], IDE_HCYL_REG);
+ sel = (args[6] & ~0x10);
+ if (drive->select.b.unit)
+ sel |= 0x10;
+ OUT_BYTE(sel, IDE_SELECT_REG);
+ ide_cmd(drive, args[0], args[2], &drive_cmd_intr);
+ return ide_started;
+ } else if (rq->flags & REQ_DRIVE_CMD) {
+ byte *args = rq->buffer;
+ if (!(args)) goto args_error;
+#ifdef DEBUG
+ printk("%s: DRIVE_CMD ", drive->name);
+ printk("cmd=0x%02x ", args[0]);
+ printk("sc=0x%02x ", args[1]);
+ printk("fr=0x%02x ", args[2]);
+ printk("xx=0x%02x\n", args[3]);
+#endif
+ if (args[0] == WIN_SMART) {
+ OUT_BYTE(0x4f, IDE_LCYL_REG);
+ OUT_BYTE(0xc2, IDE_HCYL_REG);
+ OUT_BYTE(args[2],IDE_FEATURE_REG);
+ OUT_BYTE(args[1],IDE_SECTOR_REG);
+ ide_cmd(drive, args[0], args[3], &drive_cmd_intr);
+
+ return ide_started;
+ }
+ OUT_BYTE(args[2],IDE_FEATURE_REG);
+ ide_cmd(drive, args[0], args[1], &drive_cmd_intr);
+ return ide_started;
+ }
+
+args_error:
+ /*
+ * NULL is actually a valid way of waiting for all
+ * current requests to be flushed from the queue.
+ */
+#ifdef DEBUG
+ printk("%s: DRIVE_CMD (null)\n", drive->name);
+#endif
+ ide_end_drive_cmd(drive, GET_STAT(), GET_ERR());
+ return ide_stopped;
+ }
+
+ /* The normal way of execution is to pass execute the request
+ * handler.
+ */
if (ata_ops(drive)) {
if (ata_ops(drive)->do_request)
@@ -1194,55 +1204,34 @@ ide_startstop_t restart_request (ide_drive_t *drive)
* ide_stall_queue() can be used by a drive to give excess bandwidth back
* to the hwgroup by sleeping for timeout jiffies.
*/
-void ide_stall_queue (ide_drive_t *drive, unsigned long timeout)
+void ide_stall_queue(ide_drive_t *drive, unsigned long timeout)
{
if (timeout > WAIT_WORSTCASE)
timeout = WAIT_WORSTCASE;
- drive->sleep = timeout + jiffies;
+ drive->PADAM_sleep = timeout + jiffies;
}
-#define WAKEUP(drive) ((drive)->service_start + 2 * (drive)->service_time)
-
/*
* choose_drive() selects the next drive which will be serviced.
*/
-static inline ide_drive_t *choose_drive (ide_hwgroup_t *hwgroup)
+static inline ide_drive_t *choose_drive(ide_hwgroup_t *hwgroup)
{
ide_drive_t *drive, *best;
-repeat:
best = NULL;
drive = hwgroup->drive;
do {
- if (!list_empty(&drive->queue.queue_head) && (!drive->sleep || 0 <= (signed long)(jiffies - drive->sleep))) {
+ if (!list_empty(&drive->queue.queue_head)
+ && (!drive->PADAM_sleep || time_after_eq(drive->PADAM_sleep, jiffies))) {
if (!best
- || (drive->sleep && (!best->sleep || 0 < (signed long)(best->sleep - drive->sleep)))
- || (!best->sleep && 0 < (signed long)(WAKEUP(best) - WAKEUP(drive))))
+ || (drive->PADAM_sleep && (!best->PADAM_sleep || time_after(best->PADAM_sleep, drive->PADAM_sleep)))
+ || (!best->PADAM_sleep && time_after(best->PADAM_service_start + 2 * best->PADAM_service_time, drive->PADAM_service_start + 2 * drive->PADAM_service_time)))
{
if (!blk_queue_plugged(&drive->queue))
best = drive;
}
}
} while ((drive = drive->next) != hwgroup->drive);
- if (best && best->nice1 && !best->sleep && best != hwgroup->drive && best->service_time > WAIT_MIN_SLEEP) {
- long t = (signed long)(WAKEUP(best) - jiffies);
- if (t >= WAIT_MIN_SLEEP) {
- /*
- * We *may* have some time to spare, but first let's see if
- * someone can potentially benefit from our nice mood today..
- */
- drive = best->next;
- do {
- if (!drive->sleep
- && 0 < (signed long)(WAKEUP(drive) - (jiffies - best->service_time))
- && 0 < (signed long)((jiffies + t) - WAKEUP(drive)))
- {
- ide_stall_queue(best, min(t, 10L * WAIT_MIN_SLEEP));
- goto repeat;
- }
- } while ((drive = drive->next) != best);
- }
- }
return best;
}
@@ -1278,8 +1267,8 @@ repeat:
*/
static void ide_do_request(ide_hwgroup_t *hwgroup, int masked_irq)
{
- ide_drive_t *drive;
- ide_hwif_t *hwif;
+ ide_drive_t *drive;
+ struct ata_channel *hwif;
ide_startstop_t startstop;
struct request *rq;
@@ -1294,8 +1283,8 @@ static void ide_do_request(ide_hwgroup_t *hwgroup, int masked_irq)
hwgroup->rq = NULL;
drive = hwgroup->drive;
do {
- if (drive->sleep && (!sleep || 0 < (signed long)(sleep - drive->sleep)))
- sleep = drive->sleep;
+ if (drive->PADAM_sleep && (!sleep || time_after(sleep, drive->PADAM_sleep)))
+ sleep = drive->PADAM_sleep;
} while ((drive = drive->next) != hwgroup->drive);
if (sleep) {
/*
@@ -1304,7 +1293,7 @@ static void ide_do_request(ide_hwgroup_t *hwgroup, int masked_irq)
* play fairly with us, just in case there are big differences
* in relative throughputs.. don't want to hog the cpu too much.
*/
- if (0 < (signed long)(jiffies + WAIT_MIN_SLEEP - sleep))
+ if (0 < (signed long)(jiffies + WAIT_MIN_SLEEP - sleep))
sleep = jiffies + WAIT_MIN_SLEEP;
#if 1
if (timer_pending(&hwgroup->timer))
@@ -1320,7 +1309,7 @@ static void ide_do_request(ide_hwgroup_t *hwgroup, int masked_irq)
}
return; /* no more work for this hwgroup (for now) */
}
- hwif = HWIF(drive);
+ hwif = drive->channel;
if (hwgroup->hwif->sharing_irq && hwif != hwgroup->hwif && hwif->io_ports[IDE_CONTROL_OFFSET]) {
/* set nIEN for previous hwif */
@@ -1331,8 +1320,8 @@ static void ide_do_request(ide_hwgroup_t *hwgroup, int masked_irq)
}
hwgroup->hwif = hwif;
hwgroup->drive = drive;
- drive->sleep = 0;
- drive->service_start = jiffies;
+ drive->PADAM_sleep = 0;
+ drive->PADAM_service_start = jiffies;
if (blk_queue_plugged(&drive->queue))
BUG();
@@ -1366,11 +1355,12 @@ static void ide_do_request(ide_hwgroup_t *hwgroup, int masked_irq)
/*
* Returns the queue which corresponds to a given device.
*/
-request_queue_t *ide_get_queue (kdev_t dev)
+request_queue_t *ide_get_queue(kdev_t dev)
{
- ide_hwif_t *hwif = (ide_hwif_t *)blk_dev[major(dev)].data;
+ struct ata_channel *channel = (struct ata_channel *)blk_dev[major(dev)].data;
- return &hwif->drives[DEVICE_NR(dev) & 1].queue;
+ /* FIXME: ALLERT: This discriminates between master and slave! */
+ return &channel->drives[DEVICE_NR(dev) & 1].queue;
}
/*
@@ -1388,7 +1378,7 @@ void do_ide_request(request_queue_t *q)
*/
void ide_dma_timeout_retry(ide_drive_t *drive)
{
- ide_hwif_t *hwif = HWIF(drive);
+ struct ata_channel *hwif = drive->channel;
struct request *rq;
/*
@@ -1461,7 +1451,7 @@ void ide_timer_expiry(unsigned long data)
printk("ide_timer_expiry: hwgroup->drive was NULL\n");
hwgroup->handler = NULL;
} else {
- ide_hwif_t *hwif;
+ struct ata_channel *hwif;
ide_startstop_t startstop;
/* paranoia */
if (!test_and_set_bit(IDE_BUSY, &hwgroup->flags))
@@ -1483,7 +1473,7 @@ void ide_timer_expiry(unsigned long data)
* mask the specific IRQ:
*/
spin_unlock(&ide_lock);
- hwif = HWIF(drive);
+ hwif = drive->channel;
#if DISABLE_IRQ_NOSYNC
disable_irq_nosync(hwif->irq);
#else
@@ -1506,7 +1496,7 @@ void ide_timer_expiry(unsigned long data)
startstop = ide_error(drive, "irq timeout", GET_STAT());
}
set_recovery_timer(hwif);
- drive->service_time = jiffies - drive->service_start;
+ drive->PADAM_service_time = jiffies - drive->PADAM_service_start;
enable_irq(hwif->irq);
spin_lock_irq(&ide_lock);
if (startstop == ide_stopped)
@@ -1540,10 +1530,10 @@ void ide_timer_expiry(unsigned long data)
* accidentally invoked as a result of any valid command completion interrupt.
*
*/
-static void unexpected_intr (int irq, ide_hwgroup_t *hwgroup)
+static void unexpected_intr(int irq, ide_hwgroup_t *hwgroup)
{
byte stat;
- ide_hwif_t *hwif = hwgroup->hwif;
+ struct ata_channel *hwif = hwgroup->hwif;
/*
* handle the unexpected interrupt
@@ -1568,11 +1558,11 @@ static void unexpected_intr (int irq, ide_hwgroup_t *hwgroup)
/*
* entry point for all interrupts, caller does __cli() for us
*/
-void ide_intr (int irq, void *dev_id, struct pt_regs *regs)
+void ide_intr(int irq, void *dev_id, struct pt_regs *regs)
{
unsigned long flags;
ide_hwgroup_t *hwgroup = (ide_hwgroup_t *)dev_id;
- ide_hwif_t *hwif;
+ struct ata_channel *hwif;
ide_drive_t *drive;
ide_handler_t *handler;
ide_startstop_t startstop;
@@ -1611,7 +1601,7 @@ void ide_intr (int irq, void *dev_id, struct pt_regs *regs)
* Whack the status register, just in case we have a leftover pending IRQ.
*/
IN_BYTE(hwif->io_ports[IDE_STATUS_OFFSET]);
-#endif /* CONFIG_BLK_DEV_IDEPCI */
+#endif
}
goto out_lock;
}
@@ -1650,8 +1640,8 @@ void ide_intr (int irq, void *dev_id, struct pt_regs *regs)
* same irq as is currently being serviced here, and Linux
* won't allow another of the same (on any CPU) until we return.
*/
- set_recovery_timer(HWIF(drive));
- drive->service_time = jiffies - drive->service_start;
+ set_recovery_timer(drive->channel);
+ drive->PADAM_service_time = jiffies - drive->PADAM_service_start;
if (startstop == ide_stopped) {
if (hwgroup->handler == NULL) { /* paranoia */
clear_bit(IDE_BUSY, &hwgroup->flags);
@@ -1675,7 +1665,7 @@ ide_drive_t *get_info_ptr(kdev_t i_rdev)
int h;
for (h = 0; h < MAX_HWIFS; ++h) {
- ide_hwif_t *hwif = &ide_hwifs[h];
+ struct ata_channel *hwif = &ide_hwifs[h];
if (hwif->present && major == hwif->major) {
int unit = DEVICE_NR(i_rdev);
if (unit < MAX_DRIVES) {
@@ -1699,41 +1689,39 @@ void ide_init_drive_cmd (struct request *rq)
}
/*
- * This function issues a special IDE device request
- * onto the request queue.
+ * This function issues a special IDE device request onto the request queue.
*
- * If action is ide_wait, then the rq is queued at the end of the
- * request queue, and the function sleeps until it has been processed.
- * This is for use when invoked from an ioctl handler.
+ * If action is ide_wait, then the rq is queued at the end of the request
+ * queue, and the function sleeps until it has been processed. This is for use
+ * when invoked from an ioctl handler.
*
- * If action is ide_preempt, then the rq is queued at the head of
- * the request queue, displacing the currently-being-processed
- * request and this function returns immediately without waiting
- * for the new rq to be completed. This is VERY DANGEROUS, and is
- * intended for careful use by the ATAPI tape/cdrom driver code.
+ * If action is ide_preempt, then the rq is queued at the head of the request
+ * queue, displacing the currently-being-processed request and this function
+ * returns immediately without waiting for the new rq to be completed. This is
+ * VERY DANGEROUS, and is intended for careful use by the ATAPI tape/cdrom
+ * driver code.
*
- * If action is ide_next, then the rq is queued immediately after
- * the currently-being-processed-request (if any), and the function
- * returns without waiting for the new rq to be completed. As above,
- * This is VERY DANGEROUS, and is intended for careful use by the
- * ATAPI tape/cdrom driver code.
+ * If action is ide_next, then the rq is queued immediately after the
+ * currently-being-processed-request (if any), and the function returns without
+ * waiting for the new rq to be completed. As above, This is VERY DANGEROUS,
+ * and is intended for careful use by the ATAPI tape/cdrom driver code.
*
- * If action is ide_end, then the rq is queued at the end of the
- * request queue, and the function returns immediately without waiting
- * for the new rq to be completed. This is again intended for careful
- * use by the ATAPI tape/cdrom driver code.
+ * If action is ide_end, then the rq is queued at the end of the request queue,
+ * and the function returns immediately without waiting for the new rq to be
+ * completed. This is again intended for careful use by the ATAPI tape/cdrom
+ * driver code.
*/
-int ide_do_drive_cmd (ide_drive_t *drive, struct request *rq, ide_action_t action)
+int ide_do_drive_cmd(ide_drive_t *drive, struct request *rq, ide_action_t action)
{
unsigned long flags;
ide_hwgroup_t *hwgroup = HWGROUP(drive);
- unsigned int major = HWIF(drive)->major;
+ unsigned int major = drive->channel->major;
request_queue_t *q = &drive->queue;
struct list_head *queue_head = &q->queue_head;
DECLARE_COMPLETION(wait);
#ifdef CONFIG_BLK_DEV_PDC4030
- if (HWIF(drive)->chipset == ide_pdc4030 && rq->buffer != NULL)
+ if (drive->channel->chipset == ide_pdc4030 && rq->buffer != NULL)
return -ENOSYS; /* special drive cmds not supported */
#endif
rq->errors = 0;
@@ -1812,7 +1800,7 @@ int ide_revalidate_disk (kdev_t i_rdev)
*/
void revalidate_drives(void)
{
- ide_hwif_t *hwif;
+ struct ata_channel *hwif;
ide_drive_t *drive;
int h;
@@ -1935,29 +1923,28 @@ ide_proc_entry_t generic_subdriver_entries[] = {
* Note that we only release the standard ports, and do not even try to handle
* any extra ports allocated for weird IDE interface chipsets.
*/
-static void hwif_unregister(ide_hwif_t *hwif)
+static void hwif_unregister(struct ata_channel *hwif)
{
if (hwif->straight8) {
ide_release_region(hwif->io_ports[IDE_DATA_OFFSET], 8);
- goto jump_eight;
- }
- 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);
-jump_eight:
+ } else {
+ 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 defined(CONFIG_AMIGA) || defined(CONFIG_MAC)
@@ -1966,23 +1953,22 @@ jump_eight:
#endif
}
-void ide_unregister(ide_hwif_t *hwif)
+void ide_unregister(struct ata_channel *channel)
{
struct gendisk *gd;
ide_drive_t *drive, *d;
- ide_hwif_t *g;
ide_hwgroup_t *hwgroup;
- int irq_count = 0, unit, i;
+ int unit, i;
unsigned long flags;
unsigned int p, minor;
- ide_hwif_t old_hwif;
+ struct ata_channel old_hwif;
spin_lock_irqsave(&ide_lock, flags);
- if (!hwif->present)
+ if (!channel->present)
goto abort;
- put_device(&hwif->device);
+ put_device(&channel->dev);
for (unit = 0; unit < MAX_DRIVES; ++unit) {
- drive = &hwif->drives[unit];
+ drive = &channel->drives[unit];
if (!drive->present)
continue;
if (drive->busy || drive->usage)
@@ -1995,43 +1981,47 @@ void ide_unregister(ide_hwif_t *hwif)
ide_unregister_subdriver(drive);
}
}
- hwif->present = 0;
+ channel->present = 0;
/*
* All clear? Then blow away the buffer cache
*/
spin_unlock_irqrestore(&ide_lock, flags);
for (unit = 0; unit < MAX_DRIVES; ++unit) {
- drive = &hwif->drives[unit];
+ drive = &channel->drives[unit];
if (!drive->present)
continue;
minor = drive->select.b.unit << PARTN_BITS;
for (p = 0; p < (1<<PARTN_BITS); ++p) {
if (drive->part[p].nr_sects > 0) {
- kdev_t devp = mk_kdev(hwif->major, minor+p);
+ kdev_t devp = mk_kdev(channel->major, minor+p);
invalidate_device(devp, 0);
}
}
}
#ifdef CONFIG_PROC_FS
- destroy_proc_ide_drives(hwif);
+ destroy_proc_ide_drives(channel);
#endif
spin_lock_irqsave(&ide_lock, flags);
- hwgroup = hwif->hwgroup;
+ hwgroup = channel->hwgroup;
/*
* free the irq if we were the only hwif using it
*/
- g = hwgroup->hwif;
- do {
- if (g->irq == hwif->irq)
- ++irq_count;
- g = g->next;
- } while (g != hwgroup->hwif);
- if (irq_count == 1)
- free_irq(hwif->irq, hwgroup);
+ {
+ struct ata_channel *g;
+ int irq_count = 0;
- hwif_unregister(hwif);
+ g = hwgroup->hwif;
+ do {
+ if (g->irq == channel->irq)
+ ++irq_count;
+ g = g->next;
+ } while (g != hwgroup->hwif);
+ if (irq_count == 1)
+ free_irq(channel->irq, hwgroup);
+ }
+ hwif_unregister(channel);
/*
* Remove us from the hwgroup, and free
@@ -2039,7 +2029,7 @@ void ide_unregister(ide_hwif_t *hwif)
*/
d = hwgroup->drive;
for (i = 0; i < MAX_DRIVES; ++i) {
- drive = &hwif->drives[i];
+ drive = &channel->drives[i];
if (drive->de) {
devfs_unregister (drive->de);
drive->de = NULL;
@@ -2060,27 +2050,27 @@ void ide_unregister(ide_hwif_t *hwif)
}
if (d->present)
hwgroup->drive = d;
- while (hwgroup->hwif->next != hwif)
+ while (hwgroup->hwif->next != channel)
hwgroup->hwif = hwgroup->hwif->next;
- hwgroup->hwif->next = hwif->next;
- if (hwgroup->hwif == hwif)
+ hwgroup->hwif->next = channel->next;
+ if (hwgroup->hwif == channel)
kfree(hwgroup);
else
- hwgroup->hwif = HWIF(hwgroup->drive);
+ hwgroup->hwif = hwgroup->drive->channel;
#if defined(CONFIG_BLK_DEV_IDEDMA) && !defined(CONFIG_DMA_NONPCI)
- ide_release_dma(hwif);
+ ide_release_dma(channel);
#endif
/*
* Remove us from the kernel's knowledge
*/
- unregister_blkdev(hwif->major, hwif->name);
- kfree(blksize_size[hwif->major]);
- blk_dev[hwif->major].data = NULL;
- blk_dev[hwif->major].queue = NULL;
- blk_clear(hwif->major);
- gd = hwif->gd;
+ unregister_blkdev(channel->major, channel->name);
+ kfree(blksize_size[channel->major]);
+ blk_dev[channel->major].data = NULL;
+ blk_dev[channel->major].queue = NULL;
+ blk_clear(channel->major);
+ gd = channel->gd;
if (gd) {
del_gendisk(gd);
kfree(gd->sizes);
@@ -2090,45 +2080,45 @@ void ide_unregister(ide_hwif_t *hwif)
if (gd->flags)
kfree (gd->flags);
kfree(gd);
- hwif->gd = NULL;
+ channel->gd = NULL;
}
/*
- * Reinitialize the hwif handler, but preserve any special methods for
+ * Reinitialize the channel handler, but preserve any special methods for
* it.
*/
- old_hwif = *hwif;
- init_hwif_data(hwif, hwif->index);
- hwif->hwgroup = old_hwif.hwgroup;
- hwif->tuneproc = old_hwif.tuneproc;
- hwif->speedproc = old_hwif.speedproc;
- hwif->selectproc = old_hwif.selectproc;
- hwif->resetproc = old_hwif.resetproc;
- hwif->intrproc = old_hwif.intrproc;
- hwif->maskproc = old_hwif.maskproc;
- hwif->quirkproc = old_hwif.quirkproc;
- hwif->rwproc = old_hwif.rwproc;
- hwif->ideproc = old_hwif.ideproc;
- hwif->dmaproc = old_hwif.dmaproc;
- hwif->busproc = old_hwif.busproc;
- hwif->bus_state = old_hwif.bus_state;
- 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;
+ old_hwif = *channel;
+ init_hwif_data(channel, channel->index);
+ channel->hwgroup = old_hwif.hwgroup;
+ channel->tuneproc = old_hwif.tuneproc;
+ channel->speedproc = old_hwif.speedproc;
+ channel->selectproc = old_hwif.selectproc;
+ channel->resetproc = old_hwif.resetproc;
+ channel->intrproc = old_hwif.intrproc;
+ channel->maskproc = old_hwif.maskproc;
+ channel->quirkproc = old_hwif.quirkproc;
+ channel->rwproc = old_hwif.rwproc;
+ channel->ideproc = old_hwif.ideproc;
+ channel->dmaproc = old_hwif.dmaproc;
+ channel->busproc = old_hwif.busproc;
+ channel->bus_state = old_hwif.bus_state;
+ channel->dma_base = old_hwif.dma_base;
+ channel->dma_extra = old_hwif.dma_extra;
+ channel->config_data = old_hwif.config_data;
+ channel->select_data = old_hwif.select_data;
+ channel->proc = old_hwif.proc;
#ifndef CONFIG_BLK_DEV_IDECS
- hwif->irq = old_hwif.irq;
+ channel->irq = old_hwif.irq;
#endif
- hwif->major = old_hwif.major;
- hwif->chipset = old_hwif.chipset;
- hwif->autodma = old_hwif.autodma;
- hwif->udma_four = old_hwif.udma_four;
+ channel->major = old_hwif.major;
+ channel->chipset = old_hwif.chipset;
+ channel->autodma = old_hwif.autodma;
+ channel->udma_four = old_hwif.udma_four;
#ifdef CONFIG_BLK_DEV_IDEPCI
- hwif->pci_dev = old_hwif.pci_dev;
+ channel->pci_dev = old_hwif.pci_dev;
#endif
- hwif->straight8 = old_hwif.straight8;
+ channel->straight8 = old_hwif.straight8;
abort:
spin_unlock_irqrestore(&ide_lock, flags);
}
@@ -2173,10 +2163,11 @@ void ide_setup_ports ( hw_regs_t *hw,
* Register an IDE interface, specifing exactly the registers etc
* Set init=1 iff calling before probes have taken place.
*/
-int ide_register_hw(hw_regs_t *hw, ide_hwif_t **hwifp)
+int ide_register_hw(hw_regs_t *hw, struct ata_channel **hwifp)
{
- int h, retry = 1;
- ide_hwif_t *hwif;
+ int h;
+ int retry = 1;
+ struct ata_channel *hwif;
do {
for (h = 0; h < MAX_HWIFS; ++h) {
@@ -2193,7 +2184,9 @@ int ide_register_hw(hw_regs_t *hw, ide_hwif_t **hwifp)
for (h = 0; h < MAX_HWIFS; ++h)
ide_unregister(&ide_hwifs[h]);
} while (retry--);
+
return -1;
+
found:
ide_unregister(hwif);
if (hwif->present)
@@ -2375,8 +2368,8 @@ static int set_io_32bit(ide_drive_t *drive, int arg)
{
drive->io_32bit = arg;
#ifdef CONFIG_BLK_DEV_DTC2278
- if (HWIF(drive)->chipset == ide_dtc2278)
- HWIF(drive)->drives[!drive->select.b.unit].io_32bit = arg;
+ if (drive->channel->chipset == ide_dtc2278)
+ drive->channel->drives[!drive->select.b.unit].io_32bit = arg;
#endif /* CONFIG_BLK_DEV_DTC2278 */
return 0;
}
@@ -2385,9 +2378,9 @@ static int set_using_dma (ide_drive_t *drive, int arg)
{
if (!drive->driver)
return -EPERM;
- if (!drive->id || !(drive->id->capability & 1) || !HWIF(drive)->dmaproc)
+ if (!drive->id || !(drive->id->capability & 1) || !drive->channel->dmaproc)
return -EPERM;
- if (HWIF(drive)->dmaproc(arg ? ide_dma_on : ide_dma_off, drive))
+ if (drive->channel->dmaproc(arg ? ide_dma_on : ide_dma_off, drive))
return -EIO;
return 0;
}
@@ -2396,14 +2389,14 @@ static int set_pio_mode (ide_drive_t *drive, int arg)
{
struct request rq;
- if (!HWIF(drive)->tuneproc)
+ if (!drive->channel->tuneproc)
return -ENOSYS;
if (drive->special.b.set_tune)
return -EBUSY;
ide_init_drive_cmd(&rq);
drive->tune_req = (byte) arg;
drive->special.b.set_tune = 1;
- (void) ide_do_drive_cmd (drive, &rq, ide_wait);
+ ide_do_drive_cmd(drive, &rq, ide_wait);
return 0;
}
@@ -2414,7 +2407,6 @@ void ide_add_generic_settings (ide_drive_t *drive)
*/
ide_add_setting(drive, "io_32bit", drive->no_io_32bit ? SETTING_READ : SETTING_RW, HDIO_GET_32BIT, HDIO_SET_32BIT, TYPE_BYTE, 0, 1 + (SUPPORT_VLB_SYNC << 1), 1, 1, &drive->io_32bit, set_io_32bit);
ide_add_setting(drive, "keepsettings", SETTING_RW, HDIO_GET_KEEPSETTINGS, HDIO_SET_KEEPSETTINGS, TYPE_BYTE, 0, 1, 1, 1, &drive->keep_settings, NULL);
- ide_add_setting(drive, "nice1", SETTING_RW, -1, -1, TYPE_BYTE, 0, 1, 1, 1, &drive->nice1, NULL);
ide_add_setting(drive, "pio_mode", SETTING_WRITE, -1, HDIO_SET_PIO_MODE, TYPE_BYTE, 0, 255, 1, 1, NULL, set_pio_mode);
ide_add_setting(drive, "slow", SETTING_RW, -1, -1, TYPE_BYTE, 0, 1, 1, 1, &drive->slow, NULL);
ide_add_setting(drive, "unmaskirq", drive->no_unmask ? SETTING_READ : SETTING_RW, HDIO_GET_UNMASKINTR, HDIO_SET_UNMASKINTR, TYPE_BYTE, 0, 1, 1, 1, &drive->unmask, NULL);
@@ -2540,10 +2532,7 @@ static int ide_ioctl (struct inode *inode, struct file *file,
case HDIO_GET_NICE:
return put_user(drive->dsc_overlap << IDE_NICE_DSC_OVERLAP |
- drive->atapi_overlap << IDE_NICE_ATAPI_OVERLAP |
- drive->nice0 << IDE_NICE_0 |
- drive->nice1 << IDE_NICE_1 |
- drive->nice2 << IDE_NICE_2,
+ drive->atapi_overlap << IDE_NICE_ATAPI_OVERLAP,
(long *) arg);
case HDIO_DRIVE_CMD:
@@ -2558,7 +2547,7 @@ static int ide_ioctl (struct inode *inode, struct file *file,
case HDIO_SET_NICE:
if (!capable(CAP_SYS_ADMIN)) return -EACCES;
- if (arg != (arg & ((1 << IDE_NICE_DSC_OVERLAP) | (1 << IDE_NICE_1))))
+ if (arg != (arg & ((1 << IDE_NICE_DSC_OVERLAP))))
return -EPERM;
drive->dsc_overlap = (arg >> IDE_NICE_DSC_OVERLAP) & 1;
/* Only CD-ROM's and tapes support DSC overlap. */
@@ -2566,7 +2555,6 @@ static int ide_ioctl (struct inode *inode, struct file *file,
drive->dsc_overlap = 0;
return -EPERM;
}
- drive->nice1 = (arg >> IDE_NICE_1) & 1;
return 0;
case BLKGETSIZE:
case BLKGETSIZE64:
@@ -2591,15 +2579,15 @@ static int ide_ioctl (struct inode *inode, struct file *file,
case HDIO_GET_BUSSTATE:
if (!capable(CAP_SYS_ADMIN))
return -EACCES;
- if (put_user(HWIF(drive)->bus_state, (long *)arg))
+ if (put_user(drive->channel->bus_state, (long *)arg))
return -EFAULT;
return 0;
case HDIO_SET_BUSSTATE:
if (!capable(CAP_SYS_ADMIN))
return -EACCES;
- if (HWIF(drive)->busproc)
- HWIF(drive)->busproc(drive, (int)arg);
+ if (drive->channel->busproc)
+ drive->channel->busproc(drive, (int)arg);
return 0;
default:
@@ -2802,7 +2790,7 @@ static int __init match_parm (char *s, const char *keywords[], int vals[], int m
int __init ide_setup (char *s)
{
int i, vals[3];
- ide_hwif_t *hwif;
+ struct ata_channel *hwif;
ide_drive_t *drive;
unsigned int hw, unit;
const char max_drive = 'a' + ((MAX_HWIFS * MAX_DRIVES) - 1);
@@ -3116,7 +3104,7 @@ ide_drive_t *ide_scan_devices(byte type, const char *name, struct ata_operations
unsigned int unit, index, i;
for (index = 0, i = 0; index < MAX_HWIFS; ++index) {
- ide_hwif_t *hwif = &ide_hwifs[index];
+ struct ata_channel *hwif = &ide_hwifs[index];
if (!hwif->present)
continue;
for (unit = 0; unit < MAX_DRIVES; ++unit) {
@@ -3146,7 +3134,7 @@ int ide_register_subdriver(ide_drive_t *drive, struct ata_operations *driver)
}
/* FIXME: This will be pushed to the drivers! Thus allowing us to
- * save one parameter here eparate this out.
+ * save one parameter here separate this out.
*/
drive->driver = driver;
@@ -3154,7 +3142,7 @@ int ide_register_subdriver(ide_drive_t *drive, struct ata_operations *driver)
restore_flags(flags); /* all CPUs */
/* FIXME: Check what this magic number is supposed to be about? */
if (drive->autotune != 2) {
- if (HWIF(drive)->dmaproc != NULL) {
+ if (drive->channel->dmaproc != NULL) {
/*
* Force DMAing for the beginning of the check. Some
@@ -3164,13 +3152,12 @@ int ide_register_subdriver(ide_drive_t *drive, struct ata_operations *driver)
* PARANOIA!!!
*/
- HWIF(drive)->dmaproc(ide_dma_off_quietly, drive);
- HWIF(drive)->dmaproc(ide_dma_check, drive);
+ drive->channel->dmaproc(ide_dma_off_quietly, drive);
+ drive->channel->dmaproc(ide_dma_check, drive);
}
/* Only CD-ROMs and tape drives support DSC overlap. */
drive->dsc_overlap = (drive->next != drive
&& (drive->type == ATA_ROM || drive->type == ATA_TAPE));
- drive->nice1 = 1;
}
drive->revalidate = 1;
drive->suspend_reset = 0;
@@ -3193,10 +3180,19 @@ int ide_unregister_subdriver(ide_drive_t *drive)
save_flags(flags); /* all CPUs */
cli(); /* all CPUs */
- if (drive->usage || drive->busy || !ata_ops(drive) || ata_ops(drive)->busy) {
+
+#if 0
+ if (__MOD_IN_USE(ata_ops(drive)->owner)) {
+ restore_flags(flags);
+ return 1;
+ }
+#endif
+
+ if (drive->usage || drive->busy || !ata_ops(drive)) {
restore_flags(flags); /* all CPUs */
return 1;
}
+
#if defined(CONFIG_BLK_DEV_ISAPNP) && defined(CONFIG_ISAPNP) && defined(MODULE)
pnpide_init(0);
#endif
@@ -3207,7 +3203,10 @@ int ide_unregister_subdriver(ide_drive_t *drive)
#endif
auto_remove_settings(drive);
drive->driver = NULL;
+ drive->present = 0;
+
restore_flags(flags); /* all CPUs */
+
return 0;
}
@@ -3297,7 +3296,7 @@ EXPORT_SYMBOL(get_info_ptr);
static int ide_notify_reboot (struct notifier_block *this, unsigned long event, void *x)
{
- ide_hwif_t *hwif;
+ struct ata_channel *hwif;
ide_drive_t *drive;
int i, unit;
@@ -3316,6 +3315,7 @@ static int ide_notify_reboot (struct notifier_block *this, unsigned long event,
hwif = &ide_hwifs[i];
if (!hwif->present)
continue;
+
for (unit = 0; unit < MAX_DRIVES; ++unit) {
drive = &hwif->drives[unit];
if (!drive->present)
@@ -3479,12 +3479,13 @@ static int __init ata_module_init(void)
initializing = 0;
for (h = 0; h < MAX_HWIFS; ++h) {
- ide_hwif_t *hwif = &ide_hwifs[h];
- if (hwif->present)
- ide_geninit(hwif);
+ struct ata_channel *channel = &ide_hwifs[h];
+ if (channel->present)
+ ide_geninit(channel);
}
register_reboot_notifier(&ide_notifier);
+
return 0;
}
diff --git a/drivers/ide/it8172.c b/drivers/ide/it8172.c
index 12b6faee1148e..6e6a86439fa02 100644
--- a/drivers/ide/it8172.c
+++ b/drivers/ide/it8172.c
@@ -53,7 +53,7 @@ static int it8172_tune_chipset (ide_drive_t *drive, byte speed);
static int it8172_config_drive_for_dma (ide_drive_t *drive);
static int it8172_dmaproc(ide_dma_action_t func, ide_drive_t *drive);
#endif
-void __init ide_init_it8172 (ide_hwif_t *hwif);
+void __init ide_init_it8172(struct ata_channel *channel);
static void it8172_tune_drive (ide_drive_t *drive, byte pio)
@@ -61,7 +61,7 @@ static void it8172_tune_drive (ide_drive_t *drive, byte pio)
unsigned long flags;
u16 master_data;
u32 slave_data;
- int is_slave = (&HWIF(drive)->drives[1] == drive);
+ int is_slave = (&drive->channel->drives[1] == drive);
int master_port = 0x40;
int slave_port = 0x44;
@@ -70,8 +70,8 @@ static void it8172_tune_drive (ide_drive_t *drive, byte pio)
else
pio = min_t(byte, pio, 4);
- pci_read_config_word(HWIF(drive)->pci_dev, master_port, &master_data);
- pci_read_config_dword(HWIF(drive)->pci_dev, slave_port, &slave_data);
+ pci_read_config_word(drive->channel->pci_dev, master_port, &master_data);
+ pci_read_config_dword(drive->channel->pci_dev, slave_port, &slave_data);
/*
* FIX! The DIOR/DIOW pulse width and recovery times in port 0x44
@@ -94,7 +94,7 @@ static void it8172_tune_drive (ide_drive_t *drive, byte pio)
save_flags(flags);
cli();
- pci_write_config_word(HWIF(drive)->pci_dev, master_port, master_data);
+ pci_write_config_word(drive->channel->pci_dev, master_port, master_data);
restore_flags(flags);
}
@@ -133,7 +133,7 @@ static byte it8172_dma_2_pio (byte xfer_rate)
static int it8172_tune_chipset (ide_drive_t *drive, byte speed)
{
- ide_hwif_t *hwif = HWIF(drive);
+ struct ata_channel *hwif = drive->channel;
struct pci_dev *dev = hwif->pci_dev;
int a_speed = 3 << (drive->dn * 4);
int u_flag = 1 << drive->dn;
@@ -231,7 +231,7 @@ unsigned int __init pci_init_it8172 (struct pci_dev *dev)
}
-void __init ide_init_it8172 (ide_hwif_t *hwif)
+void __init ide_init_it8172(struct ata_channel *hwif)
{
struct pci_dev* dev = hwif->pci_dev;
unsigned long cmdBase, ctrlBase;
diff --git a/drivers/ide/macide.c b/drivers/ide/macide.c
index d28eac48044d3..6b74ade155d0f 100644
--- a/drivers/ide/macide.c
+++ b/drivers/ide/macide.c
@@ -69,7 +69,7 @@ static int macide_offsets[IDE_NR_PORTS] = {
IDE_HCYL, IDE_SELECT, IDE_STATUS, IDE_CONTROL
};
-int macide_ack_intr(ide_hwif_t* hwif)
+int macide_ack_intr(struct ata_channel *hwif)
{
if (*ide_ifr & 0x20) {
*ide_ifr &= ~0x20;
diff --git a/drivers/ide/ns87415.c b/drivers/ide/ns87415.c
index c29dd4a5655f3..787cc4bf0bfbe 100644
--- a/drivers/ide/ns87415.c
+++ b/drivers/ide/ns87415.c
@@ -28,12 +28,12 @@ static unsigned int ns87415_count = 0, ns87415_control[MAX_HWIFS] = { 0 };
/*
* This routine either enables/disables (according to drive->present)
- * the IRQ associated with the port (HWIF(drive)),
+ * the IRQ associated with the port (drive->channel),
* and selects either PIO or DMA handshaking for the next I/O operation.
*/
static void ns87415_prepare_drive (ide_drive_t *drive, unsigned int use_dma)
{
- ide_hwif_t *hwif = HWIF(drive);
+ struct ata_channel *hwif = drive->channel;
unsigned int bit, other, new, *old = (unsigned int *) hwif->select_data;
struct pci_dev *dev = hwif->pci_dev;
unsigned long flags;
@@ -43,12 +43,12 @@ static void ns87415_prepare_drive (ide_drive_t *drive, unsigned int use_dma)
new = *old;
/* Adjust IRQ enable bit */
- bit = 1 << (8 + hwif->channel);
+ bit = 1 << (8 + hwif->unit);
new = drive->present ? (new & ~bit) : (new | bit);
/* Select PIO or DMA, DMA may only be selected for one drive/channel. */
- bit = 1 << (20 + drive->select.b.unit + (hwif->channel << 1));
- other = 1 << (20 + (1 - drive->select.b.unit) + (hwif->channel << 1));
+ bit = 1 << (20 + drive->select.b.unit + (hwif->unit << 1));
+ other = 1 << (20 + (1 - drive->select.b.unit) + (hwif->unit << 1));
new = use_dma ? ((new & ~other) | bit) : (new & ~bit);
if (new != *old) {
@@ -84,7 +84,7 @@ static void ns87415_selectproc (ide_drive_t *drive)
#ifdef CONFIG_BLK_DEV_IDEDMA
static int ns87415_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
{
- ide_hwif_t *hwif = HWIF(drive);
+ struct ata_channel *hwif = drive->channel;
byte dma_stat;
switch (func) {
@@ -112,7 +112,7 @@ static int ns87415_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
}
#endif /* CONFIG_BLK_DEV_IDEDMA */
-void __init ide_init_ns87415 (ide_hwif_t *hwif)
+void __init ide_init_ns87415(struct ata_channel *hwif)
{
struct pci_dev *dev = hwif->pci_dev;
unsigned int ctrl, using_inta;
@@ -138,9 +138,9 @@ void __init ide_init_ns87415 (ide_hwif_t *hwif)
(void) pci_read_config_dword(dev, 0x40, &ctrl);
(void) pci_read_config_byte(dev, 0x09, &progif);
/* is irq in "native" mode? */
- using_inta = progif & (1 << (hwif->channel << 1));
+ using_inta = progif & (1 << (hwif->unit << 1));
if (!using_inta)
- using_inta = ctrl & (1 << (4 + hwif->channel));
+ using_inta = ctrl & (1 << (4 + hwif->unit));
if (hwif->mate) {
hwif->select_data = hwif->mate->select_data;
} else {
@@ -180,7 +180,7 @@ void __init ide_init_ns87415 (ide_hwif_t *hwif)
outb(0x60, hwif->dma_base + 2);
if (!using_inta)
- hwif->irq = hwif->channel ? 15 : 14; /* legacy mode */
+ hwif->irq = hwif->unit ? 15 : 14; /* legacy mode */
else if (!hwif->irq && hwif->mate && hwif->mate->irq)
hwif->irq = hwif->mate->irq; /* share IRQ with mate */
diff --git a/drivers/ide/opti621.c b/drivers/ide/opti621.c
index 4b5c901c10fe8..7003b8d6d70fb 100644
--- a/drivers/ide/opti621.c
+++ b/drivers/ide/opti621.c
@@ -142,7 +142,7 @@ static void compute_pios(ide_drive_t *drive, byte pio)
*/
{
int d;
- ide_hwif_t *hwif = HWIF(drive);
+ struct ata_channel *hwif = drive->channel;
if (pio == PIO_DONT_KNOW)
drive->drive_data = min(ata_timing_mode(drive, XFER_PIO | XFER_EPIO) - XFER_PIO_0, OPTI621_MAX_PIO);
@@ -252,7 +252,7 @@ static void opti621_tune_drive (ide_drive_t *drive, byte pio)
pio_clocks_t first, second;
int ax, drdy;
byte cycle1, cycle2, misc;
- ide_hwif_t *hwif = HWIF(drive);
+ struct ata_channel *hwif = drive->channel;
/* sets drive->drive_data for both drives */
compute_pios(drive, pio);
@@ -310,7 +310,7 @@ static void opti621_tune_drive (ide_drive_t *drive, byte pio)
/*
* ide_init_opti621() is called once for each hwif found at boot.
*/
-void __init ide_init_opti621 (ide_hwif_t *hwif)
+void __init ide_init_opti621(struct ata_channel *hwif)
{
hwif->drives[0].drive_data = PIO_DONT_KNOW;
hwif->drives[1].drive_data = PIO_DONT_KNOW;
diff --git a/drivers/ide/pdc202xx.c b/drivers/ide/pdc202xx.c
index 9d072763b8fa4..1ff23c4b4f2c8 100644
--- a/drivers/ide/pdc202xx.c
+++ b/drivers/ide/pdc202xx.c
@@ -217,6 +217,9 @@ static char * pdc202xx_info_new (char *buf, struct pci_dev *dev)
case PCI_DEVICE_ID_PROMISE_20275:
p += sprintf(p, "\n PDC20275 Chipset.\n");
break;
+ case PCI_DEVICE_ID_PROMISE_20276:
+ p += sprintf(p, "\n PDC20276 Chipset.\n");
+ break;
case PCI_DEVICE_ID_PROMISE_20269:
p += sprintf(p, "\n PDC20269 TX2 Chipset.\n");
break;
@@ -236,6 +239,7 @@ static int pdc202xx_get_info (char *buffer, char **addr, off_t offset, int count
char *p = buffer;
switch(bmide_dev->device) {
case PCI_DEVICE_ID_PROMISE_20275:
+ case PCI_DEVICE_ID_PROMISE_20276:
case PCI_DEVICE_ID_PROMISE_20269:
case PCI_DEVICE_ID_PROMISE_20268:
case PCI_DEVICE_ID_PROMISE_20268R:
@@ -395,8 +399,8 @@ static int check_in_drive_lists (ide_drive_t *drive, const char **list)
static int pdc202xx_tune_chipset (ide_drive_t *drive, byte speed)
{
- ide_hwif_t *hwif = HWIF(drive);
- struct pci_dev *dev = hwif->pci_dev;
+ struct ata_channel *hwif = drive->channel;
+ struct pci_dev *dev = hwif->pci_dev;
unsigned int drive_conf;
int err;
@@ -519,14 +523,14 @@ static int pdc202xx_tune_chipset (ide_drive_t *drive, byte speed)
static int pdc202xx_new_tune_chipset (ide_drive_t *drive, byte speed)
{
- ide_hwif_t *hwif = HWIF(drive);
+ struct ata_channel *hwif = drive->channel;
#ifdef CONFIG_BLK_DEV_IDEDMA
unsigned long indexreg = (hwif->dma_base + 1);
unsigned long datareg = (hwif->dma_base + 3);
#else
struct pci_dev *dev = hwif->pci_dev;
unsigned long high_16 = pci_resource_start(dev, 4);
- unsigned long indexreg = high_16 + (hwif->channel ? 0x09 : 0x01);
+ unsigned long indexreg = high_16 + (hwif->unit ? 0x09 : 0x01);
unsigned long datareg = (indexreg + 2);
#endif /* CONFIG_BLK_DEV_IDEDMA */
byte thold = 0x10;
@@ -660,6 +664,7 @@ static int pdc202xx_new_tune_chipset (ide_drive_t *drive, byte speed)
OUT_BYTE(0xac, datareg);
break;
default:
+ ;
}
if (!drive->init_speed)
@@ -698,7 +703,7 @@ static void pdc202xx_tune_drive (ide_drive_t *drive, byte pio)
static int config_chipset_for_dma (ide_drive_t *drive, byte ultra)
{
struct hd_driveid *id = drive->id;
- ide_hwif_t *hwif = HWIF(drive);
+ struct ata_channel *hwif = drive->channel;
struct pci_dev *dev = hwif->pci_dev;
unsigned long high_16 = pci_resource_start(dev, 4);
unsigned long dma_base = hwif->dma_base;
@@ -720,8 +725,8 @@ static int config_chipset_for_dma (ide_drive_t *drive, byte ultra)
byte udma_66 = ((eighty_ninty_three(drive)) && udma_33) ? 1 : 0;
byte udma_100 = 0;
byte udma_133 = 0;
- byte mask = hwif->channel ? 0x08 : 0x02;
- unsigned short c_mask = hwif->channel ? (1<<11) : (1<<10);
+ byte mask = hwif->unit ? 0x08 : 0x02;
+ unsigned short c_mask = hwif->unit ? (1<<11) : (1<<10);
byte ultra_66 = ((id->dma_ultra & 0x0010) ||
(id->dma_ultra & 0x0008)) ? 1 : 0;
@@ -732,6 +737,7 @@ static int config_chipset_for_dma (ide_drive_t *drive, byte ultra)
switch(dev->device) {
case PCI_DEVICE_ID_PROMISE_20275:
+ case PCI_DEVICE_ID_PROMISE_20276:
case PCI_DEVICE_ID_PROMISE_20269:
udma_133 = (udma_66) ? 1 : 0;
udma_100 = (udma_66) ? 1 : 0;
@@ -786,14 +792,14 @@ static int config_chipset_for_dma (ide_drive_t *drive, byte ultra)
if (((ultra_66) || (ultra_100) || (ultra_133)) && (cable)) {
#ifdef DEBUG
- printk("ULTRA66: %s channel of Ultra 66 requires an 80-pin cable for Ultra66 operation.\n", hwif->channel ? "Secondary" : "Primary");
+ printk("ULTRA66: %s channel of Ultra 66 requires an 80-pin cable for Ultra66 operation.\n", hwif->unit ? "Secondary" : "Primary");
printk(" Switching to Ultra33 mode.\n");
#endif /* DEBUG */
/* Primary : zero out second bit */
/* Secondary : zero out fourth bit */
if (!jumpbit)
OUT_BYTE(CLKSPD & ~mask, (high_16 + 0x11));
- printk("Warning: %s channel requires an 80-pin cable for operation.\n", hwif->channel ? "Secondary":"Primary");
+ printk("Warning: %s channel requires an 80-pin cable for operation.\n", hwif->unit ? "Secondary":"Primary");
printk("%s reduced to Ultra33 mode.\n", drive->name);
udma_66 = 0; udma_100 = 0; udma_133 = 0;
} else {
@@ -918,7 +924,7 @@ jumpbit_is_set:
static int config_drive_xfer_rate (ide_drive_t *drive)
{
struct hd_driveid *id = drive->id;
- ide_hwif_t *hwif = HWIF(drive);
+ struct ata_channel *hwif = drive->channel;
ide_dma_action_t dma_func = ide_dma_off_quietly;
if (id && (id->capability & 1) && hwif->autodma) {
@@ -963,7 +969,7 @@ no_dma_set:
(void) config_chipset_for_pio(drive, 5);
}
- return HWIF(drive)->dmaproc(dma_func, drive);
+ return drive->channel->dmaproc(dma_func, drive);
}
int pdc202xx_quirkproc (ide_drive_t *drive)
@@ -981,14 +987,15 @@ int pdc202xx_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
byte newchip = 0;
byte clock = 0;
byte hardware48hack = 0;
- ide_hwif_t *hwif = HWIF(drive);
+ struct ata_channel *hwif = drive->channel;
struct pci_dev *dev = hwif->pci_dev;
unsigned long high_16 = pci_resource_start(dev, 4);
- unsigned long atapi_reg = high_16 + (hwif->channel ? 0x24 : 0x00);
+ unsigned long atapi_reg = high_16 + (hwif->unit ? 0x24 : 0x00);
unsigned long dma_base = hwif->dma_base;
switch (dev->device) {
case PCI_DEVICE_ID_PROMISE_20275:
+ case PCI_DEVICE_ID_PROMISE_20276:
case PCI_DEVICE_ID_PROMISE_20269:
case PCI_DEVICE_ID_PROMISE_20268R:
case PCI_DEVICE_ID_PROMISE_20268:
@@ -1016,7 +1023,7 @@ int pdc202xx_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
struct request *rq = HWGROUP(drive)->rq;
unsigned long word_count = 0;
- outb(clock|(hwif->channel ? 0x08 : 0x02), high_16 + 0x11);
+ outb(clock|(hwif->unit ? 0x08 : 0x02), high_16 + 0x11);
word_count = (rq->nr_sectors << 8);
word_count = (rq_data_dir(rq) == READ) ? word_count | 0x05000000 : word_count | 0x06000000;
outl(word_count, atapi_reg);
@@ -1026,7 +1033,7 @@ int pdc202xx_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
if ((drive->addressing) && (hardware48hack)) {
outl(0, atapi_reg); /* zero out extra */
clock = IN_BYTE(high_16 + 0x11);
- OUT_BYTE(clock & ~(hwif->channel ? 0x08:0x02), high_16 + 0x11);
+ OUT_BYTE(clock & ~(hwif->unit ? 0x08:0x02), high_16 + 0x11);
}
break;
case ide_dma_test_irq: /* returns 1 if dma irq issued, 0 otherwise */
@@ -1035,7 +1042,7 @@ int pdc202xx_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
return (dma_stat & 4) == 4;
sc1d = IN_BYTE(high_16 + 0x001d);
- if (HWIF(drive)->channel) {
+ if (drive->channel->unit) {
if ((sc1d & 0x50) == 0x50) goto somebody_else;
else if ((sc1d & 0x40) == 0x40)
return (dma_stat & 4) == 4;
@@ -1048,8 +1055,8 @@ somebody_else:
return (dma_stat & 4) == 4; /* return 1 if INTR asserted */
case ide_dma_lostirq:
case ide_dma_timeout:
- if (HWIF(drive)->resetproc != NULL)
- HWIF(drive)->resetproc(drive);
+ if (drive->channel->resetproc != NULL)
+ drive->channel->resetproc(drive);
default:
break;
}
@@ -1064,12 +1071,12 @@ void pdc202xx_new_reset (ide_drive_t *drive)
OUT_BYTE(0x00,IDE_CONTROL_REG);
mdelay(1000);
printk("PDC202XX: %s channel reset.\n",
- HWIF(drive)->channel ? "Secondary" : "Primary");
+ drive->channel->unit ? "Secondary" : "Primary");
}
void pdc202xx_reset (ide_drive_t *drive)
{
- unsigned long high_16 = pci_resource_start(HWIF(drive)->pci_dev, 4);
+ unsigned long high_16 = pci_resource_start(drive->channel->pci_dev, 4);
byte udma_speed_flag = IN_BYTE(high_16 + 0x001f);
OUT_BYTE(udma_speed_flag | 0x10, high_16 + 0x001f);
@@ -1077,7 +1084,7 @@ void pdc202xx_reset (ide_drive_t *drive)
OUT_BYTE(udma_speed_flag & ~0x10, high_16 + 0x001f);
mdelay(2000); /* 2 seconds ?! */
printk("PDC202XX: %s channel reset.\n",
- HWIF(drive)->channel ? "Secondary" : "Primary");
+ drive->channel->unit ? "Secondary" : "Primary");
}
/*
@@ -1088,7 +1095,7 @@ void pdc202xx_reset (ide_drive_t *drive)
static int pdc202xx_tristate (ide_drive_t * drive, int state)
{
#if 0
- ide_hwif_t *hwif = HWIF(drive);
+ struct ata_channel *hwif = drive->channel;
unsigned long high_16 = pci_resource_start(hwif->pci_dev, 4);
byte sc1f = inb(high_16 + 0x001f);
@@ -1121,6 +1128,7 @@ unsigned int __init pci_init_pdc202xx(struct pci_dev *dev)
switch (dev->device) {
case PCI_DEVICE_ID_PROMISE_20275:
+ case PCI_DEVICE_ID_PROMISE_20276:
case PCI_DEVICE_ID_PROMISE_20269:
case PCI_DEVICE_ID_PROMISE_20268R:
case PCI_DEVICE_ID_PROMISE_20268:
@@ -1208,13 +1216,14 @@ fttk_tx_series:
return dev->irq;
}
-unsigned int __init ata66_pdc202xx (ide_hwif_t *hwif)
+unsigned int __init ata66_pdc202xx(struct ata_channel *hwif)
{
- unsigned short mask = (hwif->channel) ? (1<<11) : (1<<10);
+ unsigned short mask = (hwif->unit) ? (1<<11) : (1<<10);
unsigned short CIS;
switch(hwif->pci_dev->device) {
case PCI_DEVICE_ID_PROMISE_20275:
+ case PCI_DEVICE_ID_PROMISE_20276:
case PCI_DEVICE_ID_PROMISE_20269:
case PCI_DEVICE_ID_PROMISE_20268:
case PCI_DEVICE_ID_PROMISE_20268R:
@@ -1226,13 +1235,14 @@ unsigned int __init ata66_pdc202xx (ide_hwif_t *hwif)
}
}
-void __init ide_init_pdc202xx (ide_hwif_t *hwif)
+void __init ide_init_pdc202xx(struct ata_channel *hwif)
{
hwif->tuneproc = &pdc202xx_tune_drive;
hwif->quirkproc = &pdc202xx_quirkproc;
switch(hwif->pci_dev->device) {
case PCI_DEVICE_ID_PROMISE_20275:
+ case PCI_DEVICE_ID_PROMISE_20276:
case PCI_DEVICE_ID_PROMISE_20269:
case PCI_DEVICE_ID_PROMISE_20268:
case PCI_DEVICE_ID_PROMISE_20268R:
diff --git a/drivers/ide/pdc4030.c b/drivers/ide/pdc4030.c
index 04e6ad2871bda..70408f3573a2e 100644
--- a/drivers/ide/pdc4030.c
+++ b/drivers/ide/pdc4030.c
@@ -99,7 +99,7 @@ static void promise_selectproc (ide_drive_t *drive)
{
unsigned int number;
- number = (HWIF(drive)->channel << 1) + drive->select.b.unit;
+ number = (drive->channel->unit << 1) + drive->select.b.unit;
OUT_BYTE(number,IDE_FEATURE_REG);
}
@@ -155,10 +155,10 @@ void __init init_pdc4030 (void)
* setup_pdc4030()
* Completes the setup of a Promise DC4030 controller card, once found.
*/
-int __init setup_pdc4030 (ide_hwif_t *hwif)
+int __init setup_pdc4030(struct ata_channel *hwif)
{
ide_drive_t *drive;
- ide_hwif_t *hwif2;
+ struct ata_channel *hwif2;
struct dc_ident ident;
int i;
ide_startstop_t startstop;
@@ -226,13 +226,13 @@ int __init setup_pdc4030 (ide_hwif_t *hwif)
hwif->chipset = hwif2->chipset = ide_pdc4030;
hwif->mate = hwif2;
hwif2->mate = hwif;
- hwif2->channel = 1;
+ hwif2->unit = 1;
hwif->selectproc = hwif2->selectproc = &promise_selectproc;
hwif->serialized = hwif2->serialized = 1;
/* Shift the remaining interfaces down by one */
for (i=MAX_HWIFS-1 ; i > hwif->index+1 ; i--) {
- ide_hwif_t *h = &ide_hwifs[i];
+ struct ata_channel *h = &ide_hwifs[i];
#ifdef DEBUG
printk(KERN_DEBUG "Shifting i/f %d values to i/f %d\n",i-1,i);
@@ -263,7 +263,7 @@ int __init setup_pdc4030 (ide_hwif_t *hwif)
* Tests for the presence of a DC4030 Promise card on this interface
* Returns: 1 if found, 0 if not found
*/
-int __init detect_pdc4030(ide_hwif_t *hwif)
+int __init detect_pdc4030(struct ata_channel *hwif)
{
ide_drive_t *drive = &hwif->drives[0];
@@ -288,7 +288,7 @@ int __init detect_pdc4030(ide_hwif_t *hwif)
void __init ide_probe_for_pdc4030(void)
{
unsigned int index;
- ide_hwif_t *hwif;
+ struct ata_channel *hwif;
if (enable_promise_support == 0)
return;
@@ -394,6 +394,7 @@ static ide_startstop_t promise_complete_pollfunc(ide_drive_t *drive)
if (GET_STAT() & BUSY_STAT) {
if (time_before(jiffies, hwgroup->poll_timeout)) {
+ BUG_ON(HWGROUP(drive)->handler);
ide_set_handler(drive, &promise_complete_pollfunc, HZ/100, NULL);
return ide_started; /* continue polling... */
}
@@ -476,6 +477,7 @@ static ide_startstop_t promise_write_pollfunc (ide_drive_t *drive)
if (IN_BYTE(IDE_NSECTOR_REG) != 0) {
if (time_before(jiffies, hwgroup->poll_timeout)) {
+ BUG_ON(HWGROUP(drive)->handler);
ide_set_handler (drive, &promise_write_pollfunc, HZ/100, NULL);
return ide_started; /* continue polling... */
}
@@ -489,6 +491,7 @@ static ide_startstop_t promise_write_pollfunc (ide_drive_t *drive)
*/
promise_multwrite(drive, 4);
hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
+ BUG_ON(HWGROUP(drive)->handler);
ide_set_handler(drive, &promise_complete_pollfunc, HZ/100, NULL);
#ifdef DEBUG_WRITE
printk(KERN_DEBUG "%s: Done last 4 sectors - status = %02x\n",
@@ -523,6 +526,7 @@ static ide_startstop_t promise_write (ide_drive_t *drive)
if (promise_multwrite(drive, rq->nr_sectors - 4))
return ide_stopped;
hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
+ BUG_ON(HWGROUP(drive)->handler);
ide_set_handler (drive, &promise_write_pollfunc, HZ/100, NULL);
return ide_started;
} else {
@@ -533,6 +537,7 @@ static ide_startstop_t promise_write (ide_drive_t *drive)
if (promise_multwrite(drive, rq->nr_sectors))
return ide_stopped;
hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
+ BUG_ON(HWGROUP(drive)->handler);
ide_set_handler(drive, &promise_complete_pollfunc, HZ/100, NULL);
#ifdef DEBUG_WRITE
printk(KERN_DEBUG "%s: promise_write: <= 4 sectors, "
@@ -549,14 +554,21 @@ static ide_startstop_t promise_write (ide_drive_t *drive)
*/
ide_startstop_t do_pdc4030_io (ide_drive_t *drive, ide_task_t *task)
{
- struct request *rq = HWGROUP(drive)->rq;
- task_struct_t *taskfile = (task_struct_t *) task->tfRegister;
+ struct request *rq = HWGROUP(drive)->rq;
+ struct hd_drive_task_hdr *taskfile = &task->taskfile;
unsigned long timeout;
byte stat;
+ /* Check that it's a regular command. If not, bomb out early. */
+ if (!(rq->flags & REQ_CMD)) {
+ blk_dump_rq_flags(rq, "pdc4030 bad flags");
+ ide_end_request(drive, 0);
+ return ide_stopped;
+ }
+
if (IDE_CONTROL_REG)
OUT_BYTE(drive->ctl, IDE_CONTROL_REG); /* clear nIEN */
- SELECT_MASK(HWIF(drive), drive, 0);
+ SELECT_MASK(drive->channel, drive, 0);
OUT_BYTE(taskfile->feature, IDE_FEATURE_REG);
OUT_BYTE(taskfile->sector_count, IDE_NSECTOR_REG);
@@ -568,20 +580,12 @@ ide_startstop_t do_pdc4030_io (ide_drive_t *drive, ide_task_t *task)
OUT_BYTE(taskfile->device_head, IDE_SELECT_REG);
OUT_BYTE(taskfile->command, IDE_COMMAND_REG);
-/* Check that it's a regular command. If not, bomb out early. */
- if (!(rq->flags & REQ_CMD)) {
- blk_dump_rq_flags(rq, "pdc4030 bad flags");
- ide_end_request(drive, 0);
- return ide_stopped;
- }
-
switch (rq_data_dir(rq)) {
case READ:
- OUT_BYTE(PROMISE_READ, IDE_COMMAND_REG);
/*
* The card's behaviour is odd at this point. If the data is
* available, DRQ will be true, and no interrupt will be
- * generated by the card. If this is the case, we need to call the
+ * generated by the card. If this is the case, we need to call the
* "interrupt" handler (promise_read_intr) directly. Otherwise, if
* an interrupt is going to occur, bit0 of the SELECT register will
* be high, so we can set the handler the just return and be interrupted.
@@ -600,6 +604,7 @@ ide_startstop_t do_pdc4030_io (ide_drive_t *drive, ide_task_t *task)
printk(KERN_DEBUG "%s: read: waiting for "
"interrupt\n", drive->name);
#endif
+ BUG_ON(HWGROUP(drive)->handler);
ide_set_handler(drive, &promise_read_intr, WAIT_CMD, NULL);
return ide_started;
}
@@ -612,7 +617,6 @@ ide_startstop_t do_pdc4030_io (ide_drive_t *drive, ide_task_t *task)
case WRITE: {
ide_startstop_t startstop;
- OUT_BYTE(PROMISE_WRITE, IDE_COMMAND_REG);
/*
* Strategy on write is:
* look for the DRQ that should have been immediately asserted
@@ -624,7 +628,7 @@ ide_startstop_t do_pdc4030_io (ide_drive_t *drive, ide_task_t *task)
printk(KERN_ERR "%s: no DRQ after issuing "
"PROMISE_WRITE\n", drive->name);
return startstop;
- }
+ }
if (!drive->unmask)
__cli(); /* local CPU only */
HWGROUP(drive)->wrq = *rq; /* scratchpad */
@@ -652,15 +656,13 @@ ide_startstop_t promise_rw_disk (ide_drive_t *drive, struct request *rq, unsigne
taskfile.device_head = ((block>>8)&0x0f)|drive->select.all;
taskfile.command = (rq_data_dir(rq)==READ)?PROMISE_READ:PROMISE_WRITE;
- memcpy(args.tfRegister, &taskfile, sizeof(struct hd_drive_task_hdr));
- memcpy(args.hobRegister, NULL, sizeof(struct hd_drive_hob_hdr));
+ args.taskfile = taskfile;
+ memset(&args.hobfile, 0, sizeof(struct hd_drive_hob_hdr));
+
ide_cmd_type_parser(&args);
/* We don't use the generic inerrupt handlers here? */
args.prehandler = NULL;
args.handler = NULL;
- args.rq = rq;
- args.block = block;
- rq->special = NULL;
rq->special = &args;
return do_pdc4030_io(drive, &args);
diff --git a/drivers/ide/pdcadma.c b/drivers/ide/pdcadma.c
index 49fd0042e0a1c..9be48339c1a69 100644
--- a/drivers/ide/pdcadma.c
+++ b/drivers/ide/pdcadma.c
@@ -82,12 +82,12 @@ unsigned int __init pci_init_pdcadma(struct pci_dev *dev)
return 0;
}
-unsigned int __init ata66_pdcadma (ide_hwif_t *hwif)
+unsigned int __init ata66_pdcadma(struct ata_channel *channel)
{
return 1;
}
-void __init ide_init_pdcadma (ide_hwif_t *hwif)
+void __init ide_init_pdcadma(struct ata_channel *hwif)
{
hwif->autodma = 0;
hwif->dma_base = 0;
@@ -101,7 +101,7 @@ void __init ide_init_pdcadma (ide_hwif_t *hwif)
// }
}
-void __init ide_dmacapable_pdcadma (ide_hwif_t *hwif, unsigned long dmabase)
+void __init ide_dmacapable_pdcadma(struct ata_channel *hwif, unsigned long dmabase)
{
// ide_setup_dma(hwif, dmabase, 8);
}
diff --git a/drivers/ide/piix.c b/drivers/ide/piix.c
index 384ea0b2380aa..8e023e8d3d283 100644
--- a/drivers/ide/piix.c
+++ b/drivers/ide/piix.c
@@ -316,7 +316,7 @@ static void piix_set_speed(struct pci_dev *dev, unsigned char dn, struct ata_tim
static int piix_set_drive(ide_drive_t *drive, unsigned char speed)
{
- ide_drive_t *peer = HWIF(drive)->drives + (~drive->dn & 1);
+ ide_drive_t *peer = drive->channel->drives + (~drive->dn & 1);
struct ata_timing t, p;
int err, T, UT, umul;
@@ -341,7 +341,7 @@ static int piix_set_drive(ide_drive_t *drive, unsigned char speed)
ata_timing_merge(&p, &t, &t, IDE_TIMING_ALL);
}
- piix_set_speed(HWIF(drive)->pci_dev, drive->dn, &t, umul);
+ piix_set_speed(drive->channel->pci_dev, drive->dn, &t, umul);
if (!drive->init_speed)
drive->init_speed = speed;
@@ -357,7 +357,7 @@ static int piix_set_drive(ide_drive_t *drive, unsigned char speed)
static void piix_tune_drive(ide_drive_t *drive, unsigned char pio)
{
- if (!((piix_enabled >> HWIF(drive)->channel) & 1))
+ if (!((piix_enabled >> drive->channel->unit) & 1))
return;
if (pio == 255) {
@@ -381,7 +381,7 @@ int piix_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
if (func == ide_dma_check) {
- short w80 = HWIF(drive)->udma_four;
+ short w80 = drive->channel->udma_four;
short speed = ata_timing_mode(drive,
XFER_PIO | XFER_EPIO |
@@ -392,7 +392,7 @@ int piix_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
piix_set_drive(drive, speed);
- func = (HWIF(drive)->autodma && (speed & XFER_MODE) != XFER_PIO)
+ func = (drive->channel->autodma && (speed & XFER_MODE) != XFER_PIO)
? ide_dma_on : ide_dma_off_quietly;
}
@@ -533,12 +533,12 @@ unsigned int __init pci_init_piix(struct pci_dev *dev, const char *name)
return 0;
}
-unsigned int __init ata66_piix(ide_hwif_t *hwif)
+unsigned int __init ata66_piix(struct ata_channel *hwif)
{
- return ((piix_enabled & piix_80w) >> hwif->channel) & 1;
+ return ((piix_enabled & piix_80w) >> hwif->unit) & 1;
}
-void __init ide_init_piix(ide_hwif_t *hwif)
+void __init ide_init_piix(struct ata_channel *hwif)
{
int i;
@@ -550,7 +550,7 @@ void __init ide_init_piix(ide_hwif_t *hwif)
hwif->drives[i].io_32bit = 1;
hwif->drives[i].unmask = 1;
hwif->drives[i].autotune = 1;
- hwif->drives[i].dn = hwif->channel * 2 + i;
+ hwif->drives[i].dn = hwif->unit * 2 + i;
}
#ifdef CONFIG_BLK_DEV_IDEDMA
@@ -570,9 +570,9 @@ void __init ide_init_piix(ide_hwif_t *hwif)
* and only if DMA is safe with the chip and bridge.
*/
-void __init ide_dmacapable_piix(ide_hwif_t *hwif, unsigned long dmabase)
+void __init ide_dmacapable_piix(struct ata_channel *hwif, unsigned long dmabase)
{
- if (((piix_enabled >> hwif->channel) & 1)
+ if (((piix_enabled >> hwif->unit) & 1)
&& !(piix_config->flags & PIIX_NODMA))
ide_setup_dma(hwif, dmabase, 8);
}
diff --git a/drivers/ide/qd65xx.c b/drivers/ide/qd65xx.c
index 609afe5bbd677..8f9a2cc0e679e 100644
--- a/drivers/ide/qd65xx.c
+++ b/drivers/ide/qd65xx.c
@@ -125,11 +125,11 @@ static void qd_select (ide_drive_t *drive)
* qd6500_compute_timing
*
* computes the timing value where
- * lower nibble represents active time, in count of VLB clocks
- * upper nibble represents recovery time, in count of VLB clocks
+ * lower nibble represents active time, in count of VLB clocks
+ * upper nibble represents recovery time, in count of VLB clocks
*/
-static byte qd6500_compute_timing (ide_hwif_t *hwif, int active_time, int recovery_time)
+static byte qd6500_compute_timing(struct ata_channel *hwif, int active_time, int recovery_time)
{
byte active_cycle,recovery_cycle;
@@ -208,7 +208,7 @@ static int qd_timing_ok (ide_drive_t drives[])
static void qd_set_timing (ide_drive_t *drive, byte timing)
{
- ide_hwif_t *hwif = HWIF(drive);
+ struct ata_channel *hwif = drive->channel;
drive->drive_data &= 0xff00;
drive->drive_data |= timing;
@@ -240,7 +240,7 @@ static void qd6500_tune_drive (ide_drive_t *drive, byte pio)
recovery_time = drive->id->eide_pio - 120;
}
- qd_set_timing(drive,qd6500_compute_timing(HWIF(drive),active_time,recovery_time));
+ qd_set_timing(drive,qd6500_compute_timing(drive->channel, active_time,recovery_time));
}
/*
@@ -250,7 +250,7 @@ static void qd6500_tune_drive (ide_drive_t *drive, byte pio)
static void qd6580_tune_drive (ide_drive_t *drive, byte pio)
{
struct ata_timing *t;
- int base = HWIF(drive)->select_data;
+ int base = drive->channel->select_data;
int active_time = 175;
int recovery_time = 415; /* worst case values from the dos driver */
@@ -291,9 +291,9 @@ static void qd6580_tune_drive (ide_drive_t *drive, byte pio)
printk(KERN_INFO "%s: PIO mode%d\n", drive->name, pio - XFER_PIO_0);
}
- if (!HWIF(drive)->channel && drive->type != ATA_DISK) {
+ if (!drive->channel->unit && drive->type != ATA_DISK) {
qd_write_reg(0x5f,QD_CONTROL_PORT);
- printk(KERN_WARNING "%s: ATAPI: disabled read-ahead FIFO and post-write buffer on %s.\n",drive->name,HWIF(drive)->name);
+ printk(KERN_WARNING "%s: ATAPI: disabled read-ahead FIFO and post-write buffer on %s.\n",drive->name, drive->channel->name);
}
qd_set_timing(drive,qd6580_compute_timing(active_time,recovery_time));
@@ -348,7 +348,7 @@ int __init probe (int base)
index = ! (config & QD_CONFIG_IDE_BASEPORT);
if ((config & 0xf0) == QD_CONFIG_QD6500) {
- ide_hwif_t *hwif = &ide_hwifs[index];
+ struct ata_channel *hwif = &ide_hwifs[index];
if (qd_testreg(base)) return 1; /* bad register */
@@ -392,7 +392,7 @@ int __init probe (int base)
config, control, QD_ID3);
if (control & QD_CONTR_SEC_DISABLED) {
- ide_hwif_t *hwif = &ide_hwifs[index];
+ struct ata_channel *hwif = &ide_hwifs[index];
/* secondary disabled */
printk(KERN_INFO "%s: qd6580: single IDE board\n",
@@ -420,7 +420,7 @@ int __init probe (int base)
ide_hwifs[i].chipset = ide_qd65xx;
ide_hwifs[i].mate = &ide_hwifs[i^1];
- ide_hwifs[i].channel = i;
+ ide_hwifs[i].unit = i;
ide_hwifs[i].select_data = base;
ide_hwifs[i].config_data = config | (control <<8);
diff --git a/drivers/ide/rz1000.c b/drivers/ide/rz1000.c
index 644ed6038a44b..10caa414157ea 100644
--- a/drivers/ide/rz1000.c
+++ b/drivers/ide/rz1000.c
@@ -28,7 +28,7 @@
#ifdef CONFIG_BLK_DEV_IDEPCI
-void __init ide_init_rz1000 (ide_hwif_t *hwif) /* called from ide-pci.c */
+void __init ide_init_rz1000(struct ata_channel *hwif) /* called from ide-pci.c */
{
unsigned short reg;
struct pci_dev *dev = hwif->pci_dev;
@@ -62,7 +62,7 @@ static void __init init_rz1000 (struct pci_dev *dev, const char *name)
printk("IDE: disabled chipset read-ahead (buggy %s)\n", name);
} else {
for (h = 0; h < MAX_HWIFS; ++h) {
- ide_hwif_t *hwif = &ide_hwifs[h];
+ struct ata_channel *hwif = &ide_hwifs[h];
if ((hwif->io_ports[IDE_DATA_OFFSET] == 0x1f0 || hwif->io_ports[IDE_DATA_OFFSET] == 0x170)
&& (hwif->chipset == ide_unknown || hwif->chipset == ide_generic))
{
@@ -71,7 +71,7 @@ static void __init init_rz1000 (struct pci_dev *dev, const char *name)
hwif->drives[0].no_unmask = 1;
hwif->drives[1].no_unmask = 1;
if (hwif->io_ports[IDE_DATA_OFFSET] == 0x170)
- hwif->channel = 1;
+ hwif->unit = 1;
printk("%s: serialized, disabled unmasking (buggy %s)\n", hwif->name, name);
}
}
diff --git a/drivers/ide/serverworks.c b/drivers/ide/serverworks.c
index 1e4396c6dec21..1760885e24798 100644
--- a/drivers/ide/serverworks.c
+++ b/drivers/ide/serverworks.c
@@ -243,7 +243,7 @@ static int svwks_tune_chipset (ide_drive_t *drive, byte speed)
byte dma_modes[] = { 0x77, 0x21, 0x20 };
byte pio_modes[] = { 0x5d, 0x47, 0x34, 0x22, 0x20 };
- ide_hwif_t *hwif = HWIF(drive);
+ struct ata_channel *hwif = drive->channel;
struct pci_dev *dev = hwif->pci_dev;
byte unit = (drive->select.b.unit & 0x01);
byte csb5 = (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE) ? 1 : 0;
@@ -255,7 +255,7 @@ static int svwks_tune_chipset (ide_drive_t *drive, byte speed)
byte drive_pci = 0x00;
byte drive_pci2 = 0x00;
- byte drive_pci3 = hwif->channel ? 0x57 : 0x56;
+ byte drive_pci3 = hwif->unit ? 0x57 : 0x56;
byte ultra_enable = 0x00;
byte ultra_timing = 0x00;
@@ -413,7 +413,7 @@ static void svwks_tune_drive (ide_drive_t *drive, byte pio)
static int config_chipset_for_dma (ide_drive_t *drive)
{
struct hd_driveid *id = drive->id;
- struct pci_dev *dev = HWIF(drive)->pci_dev;
+ struct pci_dev *dev = drive->channel->pci_dev;
byte udma_66 = eighty_ninty_three(drive);
int ultra66 = (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE) ? 1 : 0;
int ultra100 = (ultra66 && svwks_revision >= SVWKS_CSB5_REVISION_NEW) ? 1 : 0;
@@ -436,7 +436,7 @@ static int config_drive_xfer_rate (ide_drive_t *drive)
struct hd_driveid *id = drive->id;
ide_dma_action_t dma_func = ide_dma_on;
- if (id && (id->capability & 1) && HWIF(drive)->autodma) {
+ if (id && (id->capability & 1) && drive->channel->autodma) {
/* Consult the list of known "bad" drives */
if (ide_dmaproc(ide_dma_bad_drive, drive)) {
dma_func = ide_dma_off;
@@ -477,7 +477,7 @@ fast_ata_pio:
no_dma_set:
config_chipset_for_pio(drive);
}
- return HWIF(drive)->dmaproc(dma_func, drive);
+ return drive->channel->dmaproc(dma_func, drive);
}
static int svwks_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
@@ -487,7 +487,7 @@ static int svwks_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
return config_drive_xfer_rate(drive);
case ide_dma_end:
{
- ide_hwif_t *hwif = HWIF(drive);
+ struct ata_channel *hwif = drive->channel;
unsigned long dma_base = hwif->dma_base;
if(inb(dma_base+0x02)&1)
@@ -584,13 +584,13 @@ unsigned int __init pci_init_svwks(struct pci_dev *dev)
* Bit 14 clear = primary IDE channel does not have 80-pin cable.
* Bit 14 set = primary IDE channel has 80-pin cable.
*/
-static unsigned int __init ata66_svwks_dell (ide_hwif_t *hwif)
+static unsigned int __init ata66_svwks_dell(struct ata_channel *hwif)
{
struct pci_dev *dev = hwif->pci_dev;
if (dev->subsystem_vendor == PCI_VENDOR_ID_DELL &&
dev->vendor == PCI_VENDOR_ID_SERVERWORKS &&
dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE)
- return ((1 << (hwif->channel + 14)) &
+ return ((1 << (hwif->unit + 14)) &
dev->subsystem_device) ? 1 : 0;
return 0;
}
@@ -601,18 +601,18 @@ static unsigned int __init ata66_svwks_dell (ide_hwif_t *hwif)
*
* WARNING: this only works on Alpine hardware!
*/
-static unsigned int __init ata66_svwks_cobalt (ide_hwif_t *hwif)
+static unsigned int __init ata66_svwks_cobalt(struct ata_channel *hwif)
{
struct pci_dev *dev = hwif->pci_dev;
if (dev->subsystem_vendor == PCI_VENDOR_ID_SUN &&
dev->vendor == PCI_VENDOR_ID_SERVERWORKS &&
dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE)
- return ((1 << (hwif->channel + 14)) &
+ return ((1 << (hwif->unit + 14)) &
dev->subsystem_device) ? 1 : 0;
return 0;
}
-unsigned int __init ata66_svwks (ide_hwif_t *hwif)
+unsigned int __init ata66_svwks(struct ata_channel *hwif)
{
struct pci_dev *dev = hwif->pci_dev;
@@ -627,10 +627,10 @@ unsigned int __init ata66_svwks (ide_hwif_t *hwif)
return 0;
}
-void __init ide_init_svwks (ide_hwif_t *hwif)
+void __init ide_init_svwks(struct ata_channel *hwif)
{
if (!hwif->irq)
- hwif->irq = hwif->channel ? 15 : 14;
+ hwif->irq = hwif->unit ? 15 : 14;
hwif->tuneproc = &svwks_tune_drive;
hwif->speedproc = &svwks_tune_chipset;
diff --git a/drivers/ide/sis5513.c b/drivers/ide/sis5513.c
index bf0cf8dab58b9..9b45da0205f75 100644
--- a/drivers/ide/sis5513.c
+++ b/drivers/ide/sis5513.c
@@ -434,7 +434,7 @@ extern char *ide_xfer_verbose (byte xfer_rate);
/* Enables per-drive prefetch and postwrite */
static void config_drive_art_rwp (ide_drive_t *drive)
{
- ide_hwif_t *hwif = HWIF(drive);
+ struct ata_channel *hwif = drive->channel;
struct pci_dev *dev = hwif->pci_dev;
byte reg4bh = 0;
@@ -460,7 +460,7 @@ static void config_drive_art_rwp (ide_drive_t *drive)
/* Set per-drive active and recovery time */
static void config_art_rwp_pio (ide_drive_t *drive, byte pio)
{
- ide_hwif_t *hwif = HWIF(drive);
+ struct ata_channel *hwif = drive->channel;
struct pci_dev *dev = hwif->pci_dev;
byte timing, drive_pci, test1, test2;
@@ -560,7 +560,7 @@ static int config_chipset_for_pio (ide_drive_t *drive, byte pio)
static int sis5513_tune_chipset (ide_drive_t *drive, byte speed)
{
- ide_hwif_t *hwif = HWIF(drive);
+ struct ata_channel *hwif = drive->channel;
struct pci_dev *dev = hwif->pci_dev;
byte drive_pci, reg;
@@ -640,12 +640,12 @@ static void sis5513_tune_drive (ide_drive_t *drive, byte pio)
#ifdef CONFIG_BLK_DEV_IDEDMA
/*
- * ((id->hw_config & 0x4000|0x2000) && (HWIF(drive)->udma_four))
+ * ((id->hw_config & 0x4000|0x2000) && (drive->channel->udma_four))
*/
static int config_chipset_for_dma (ide_drive_t *drive, byte ultra)
{
- struct hd_driveid *id = drive->id;
- ide_hwif_t *hwif = HWIF(drive);
+ struct hd_driveid *id = drive->id;
+ struct ata_channel *hwif = drive->channel;
byte speed = 0;
@@ -700,7 +700,7 @@ static int config_drive_xfer_rate (ide_drive_t *drive)
struct hd_driveid *id = drive->id;
ide_dma_action_t dma_func = ide_dma_off_quietly;
- if (id && (id->capability & 1) && HWIF(drive)->autodma) {
+ if (id && (id->capability & 1) && drive->channel->autodma) {
/* Consult the list of known "bad" drives */
if (ide_dmaproc(ide_dma_bad_drive, drive)) {
dma_func = ide_dma_off;
@@ -740,7 +740,7 @@ no_dma_set:
(void) config_chipset_for_pio(drive, 5);
}
- return HWIF(drive)->dmaproc(dma_func, drive);
+ return drive->channel->dmaproc(dma_func, drive);
}
/* initiates/aborts (U)DMA read/write operations on a drive. */
@@ -841,10 +841,10 @@ unsigned int __init pci_init_sis5513(struct pci_dev *dev)
return 0;
}
-unsigned int __init ata66_sis5513 (ide_hwif_t *hwif)
+unsigned int __init ata66_sis5513(struct ata_channel *hwif)
{
byte reg48h = 0, ata66 = 0;
- byte mask = hwif->channel ? 0x20 : 0x10;
+ byte mask = hwif->unit ? 0x20 : 0x10;
pci_read_config_byte(hwif->pci_dev, 0x48, &reg48h);
if (dma_capability >= ATA_66) {
@@ -853,10 +853,10 @@ unsigned int __init ata66_sis5513 (ide_hwif_t *hwif)
return ata66;
}
-void __init ide_init_sis5513 (ide_hwif_t *hwif)
+void __init ide_init_sis5513(struct ata_channel *hwif)
{
- hwif->irq = hwif->channel ? 15 : 14;
+ hwif->irq = hwif->unit ? 15 : 14;
hwif->tuneproc = &sis5513_tune_drive;
hwif->speedproc = &sis5513_tune_chipset;
diff --git a/drivers/ide/sl82c105.c b/drivers/ide/sl82c105.c
index fd60ffe2cd074..158070c4150c7 100644
--- a/drivers/ide/sl82c105.c
+++ b/drivers/ide/sl82c105.c
@@ -57,13 +57,13 @@ static unsigned int get_timing_sl82c105(struct ata_timing *t)
*/
static void config_for_pio(ide_drive_t *drive, int pio, int report)
{
- ide_hwif_t *hwif = HWIF(drive);
+ struct ata_channel *hwif = drive->channel;
struct pci_dev *dev = hwif->pci_dev;
struct ata_timing *t;
unsigned short drv_ctrl = 0x909;
unsigned int xfer_mode, reg;
- reg = (hwif->channel ? 0x4c : 0x44) + (drive->select.b.unit ? 4 : 0);
+ reg = (hwif->unit ? 0x4c : 0x44) + (drive->select.b.unit ? 4 : 0);
if (pio == 255)
xfer_mode = ata_timing_mode(drive, XFER_PIO | XFER_EPIO);
@@ -95,12 +95,12 @@ static void config_for_pio(ide_drive_t *drive, int pio, int report)
*/
static int config_for_dma(ide_drive_t *drive)
{
- ide_hwif_t *hwif = HWIF(drive);
+ struct ata_channel *hwif = drive->channel;
struct pci_dev *dev = hwif->pci_dev;
unsigned short drv_ctrl = 0x909;
unsigned int reg;
- reg = (hwif->channel ? 0x4c : 0x44) + (drive->select.b.unit ? 4 : 0);
+ reg = (hwif->unit ? 0x4c : 0x44) + (drive->select.b.unit ? 4 : 0);
if (ide_config_drive_speed(drive, XFER_MW_DMA_2) == 0)
drv_ctrl = 0x0240;
@@ -120,7 +120,7 @@ static int sl82c105_check_drive(ide_drive_t *drive)
do {
struct hd_driveid *id = drive->id;
- ide_hwif_t *hwif = HWIF(drive);
+ struct ata_channel *hwif = drive->channel;
if (!hwif->autodma)
break;
@@ -146,7 +146,7 @@ static int sl82c105_check_drive(ide_drive_t *drive)
}
} while (0);
- return HWIF(drive)->dmaproc(dma_func, drive);
+ return drive->channel->dmaproc(dma_func, drive);
}
/*
@@ -232,7 +232,7 @@ unsigned int __init pci_init_sl82c105(struct pci_dev *dev)
return dev->irq;
}
-void __init dma_init_sl82c105(ide_hwif_t *hwif, unsigned long dma_base)
+void __init dma_init_sl82c105(struct ata_channel *hwif, unsigned long dma_base)
{
unsigned int rev;
byte dma_state;
@@ -261,7 +261,7 @@ void __init dma_init_sl82c105(ide_hwif_t *hwif, unsigned long dma_base)
/*
* Initialise the chip
*/
-void __init ide_init_sl82c105(ide_hwif_t *hwif)
+void __init ide_init_sl82c105(struct ata_channel *hwif)
{
hwif->tuneproc = tune_sl82c105;
}
diff --git a/drivers/ide/trm290.c b/drivers/ide/trm290.c
index 70dffe8906e80..50675cfeed52b 100644
--- a/drivers/ide/trm290.c
+++ b/drivers/ide/trm290.c
@@ -141,7 +141,7 @@
static void trm290_prepare_drive (ide_drive_t *drive, unsigned int use_dma)
{
- ide_hwif_t *hwif = HWIF(drive);
+ struct ata_channel *hwif = drive->channel;
unsigned int reg;
unsigned long flags;
@@ -153,14 +153,14 @@ static void trm290_prepare_drive (ide_drive_t *drive, unsigned int use_dma)
if (reg != hwif->select_data) {
hwif->select_data = reg;
- outb(0x51|(hwif->channel<<3), hwif->config_data+1); /* set PIO/DMA */
+ outb(0x51|(hwif->unit<<3), hwif->config_data+1); /* set PIO/DMA */
outw(reg & 0xff, hwif->config_data);
}
/* enable IRQ if not probing */
if (drive->present) {
reg = inw(hwif->config_data+3) & 0x13;
- reg &= ~(1 << hwif->channel);
+ reg &= ~(1 << hwif->unit);
outw(reg, hwif->config_data+3);
}
@@ -175,7 +175,7 @@ static void trm290_selectproc (ide_drive_t *drive)
#ifdef CONFIG_BLK_DEV_IDEDMA
static int trm290_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
{
- ide_hwif_t *hwif = HWIF(drive);
+ struct ata_channel *hwif = drive->channel;
unsigned int count, reading = 2, writing = 0;
switch (func) {
@@ -194,6 +194,7 @@ static int trm290_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
outw((count * 2) - 1, hwif->dma_base+2); /* start DMA */
if (drive->type != ATA_DISK)
return 0;
+ BUG_ON(HWGROUP(drive)->handler);
ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, NULL);
OUT_BYTE(reading ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG);
return 0;
@@ -216,7 +217,7 @@ static int trm290_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
/*
* Invoked from ide-dma.c at boot time.
*/
-void __init ide_init_trm290 (ide_hwif_t *hwif)
+void __init ide_init_trm290(struct ata_channel *hwif)
{
unsigned int cfgbase = 0;
unsigned long flags;
@@ -237,7 +238,7 @@ void __init ide_init_trm290 (ide_hwif_t *hwif)
__save_flags(flags); /* local CPU only */
__cli(); /* local CPU only */
/* put config reg into first byte of hwif->select_data */
- outb(0x51|(hwif->channel<<3), hwif->config_data+1);
+ outb(0x51|(hwif->unit<<3), hwif->config_data+1);
hwif->select_data = 0x21; /* select PIO as default */
outb(hwif->select_data, hwif->config_data);
reg = inb(hwif->config_data+3); /* get IRQ info */
@@ -246,10 +247,10 @@ void __init ide_init_trm290 (ide_hwif_t *hwif)
__restore_flags(flags); /* local CPU only */
if ((reg & 0x10))
- hwif->irq = hwif->channel ? 15 : 14; /* legacy mode */
+ hwif->irq = hwif->unit ? 15 : 14; /* legacy mode */
else if (!hwif->irq && hwif->mate && hwif->mate->irq)
hwif->irq = hwif->mate->irq; /* sharing IRQ with mate */
- ide_setup_dma(hwif, (hwif->config_data + 4) ^ (hwif->channel ? 0x0080 : 0x0000), 3);
+ ide_setup_dma(hwif, (hwif->config_data + 4) ^ (hwif->unit ? 0x0080 : 0x0000), 3);
#ifdef CONFIG_BLK_DEV_IDEDMA
hwif->dmaproc = &trm290_dmaproc;
@@ -264,10 +265,10 @@ void __init ide_init_trm290 (ide_hwif_t *hwif)
* for the control basereg, so this kludge ensures that we use only
* values that are known to work. Ugh. -ml
*/
- unsigned short old, compat = hwif->channel ? 0x374 : 0x3f4;
+ unsigned short old, compat = hwif->unit ? 0x374 : 0x3f4;
static unsigned short next_offset = 0;
- outb(0x54|(hwif->channel<<3), hwif->config_data+1);
+ outb(0x54|(hwif->unit<<3), hwif->config_data+1);
old = inw(hwif->config_data) & ~1;
if (old != compat && inb(old+2) == 0xff) {
compat += (next_offset += 0x400); /* leave lower 10 bits untouched */
diff --git a/drivers/ide/umc8672.c b/drivers/ide/umc8672.c
index 8f9d98236c542..bb70bc74fab23 100644
--- a/drivers/ide/umc8672.c
+++ b/drivers/ide/umc8672.c
@@ -111,7 +111,7 @@ static void umc_set_speeds (byte speeds[])
static void tune_umc (ide_drive_t *drive, byte pio)
{
unsigned long flags;
- ide_hwgroup_t *hwgroup = ide_hwifs[HWIF(drive)->index^1].hwgroup;
+ ide_hwgroup_t *hwgroup = ide_hwifs[drive->channel->index ^ 1].hwgroup;
if (pio == 255)
pio = ata_timing_mode(drive, XFER_PIO | XFER_EPIO) - XFER_PIO_0;
@@ -160,5 +160,5 @@ void __init init_umc8672 (void) /* called from ide.c */
ide_hwifs[1].tuneproc = &tune_umc;
ide_hwifs[0].mate = &ide_hwifs[1];
ide_hwifs[1].mate = &ide_hwifs[0];
- ide_hwifs[1].channel = 1;
+ ide_hwifs[1].unit = 1;
}
diff --git a/drivers/ide/via82cxxx.c b/drivers/ide/via82cxxx.c
index 38eb933105c9c..d750057899e23 100644
--- a/drivers/ide/via82cxxx.c
+++ b/drivers/ide/via82cxxx.c
@@ -302,7 +302,7 @@ static void via_set_speed(struct pci_dev *dev, unsigned char dn, struct ata_timi
static int via_set_drive(ide_drive_t *drive, unsigned char speed)
{
- ide_drive_t *peer = HWIF(drive)->drives + (~drive->dn & 1);
+ ide_drive_t *peer = drive->channel->drives + (~drive->dn & 1);
struct ata_timing t, p;
unsigned int T, UT;
@@ -328,7 +328,7 @@ static int via_set_drive(ide_drive_t *drive, unsigned char speed)
ata_timing_merge(&p, &t, &t, IDE_TIMING_8BIT);
}
- via_set_speed(HWIF(drive)->pci_dev, drive->dn, &t);
+ via_set_speed(drive->channel->pci_dev, drive->dn, &t);
if (!drive->init_speed)
drive->init_speed = speed;
@@ -344,7 +344,7 @@ static int via_set_drive(ide_drive_t *drive, unsigned char speed)
static void via82cxxx_tune_drive(ide_drive_t *drive, unsigned char pio)
{
- if (!((via_enabled >> HWIF(drive)->channel) & 1))
+ if (!((via_enabled >> drive->channel->unit) & 1))
return;
if (pio == 255) {
@@ -368,7 +368,7 @@ int via82cxxx_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
if (func == ide_dma_check) {
- short w80 = HWIF(drive)->udma_four;
+ short w80 = drive->channel->udma_four;
short speed = ata_timing_mode(drive,
XFER_PIO | XFER_EPIO | XFER_SWDMA | XFER_MWDMA |
@@ -379,7 +379,7 @@ int via82cxxx_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
via_set_drive(drive, speed);
- func = (HWIF(drive)->autodma && (speed & XFER_MODE) != XFER_PIO)
+ func = (drive->channel->autodma && (speed & XFER_MODE) != XFER_PIO)
? ide_dma_on : ide_dma_off_quietly;
}
@@ -523,12 +523,12 @@ unsigned int __init pci_init_via82cxxx(struct pci_dev *dev)
return 0;
}
-unsigned int __init ata66_via82cxxx(ide_hwif_t *hwif)
+unsigned int __init ata66_via82cxxx(struct ata_channel *hwif)
{
- return ((via_enabled & via_80w) >> hwif->channel) & 1;
+ return ((via_enabled & via_80w) >> hwif->unit) & 1;
}
-void __init ide_init_via82cxxx(ide_hwif_t *hwif)
+void __init ide_init_via82cxxx(struct ata_channel *hwif)
{
int i;
@@ -540,7 +540,7 @@ void __init ide_init_via82cxxx(ide_hwif_t *hwif)
hwif->drives[i].io_32bit = 1;
hwif->drives[i].unmask = (via_config->flags & VIA_NO_UNMASK) ? 0 : 1;
hwif->drives[i].autotune = 1;
- hwif->drives[i].dn = hwif->channel * 2 + i;
+ hwif->drives[i].dn = hwif->unit * 2 + i;
}
#ifdef CONFIG_BLK_DEV_IDEDMA
@@ -559,8 +559,8 @@ void __init ide_init_via82cxxx(ide_hwif_t *hwif)
* We allow the BM-DMA driver to only work on enabled interfaces.
*/
-void __init ide_dmacapable_via82cxxx(ide_hwif_t *hwif, unsigned long dmabase)
+void __init ide_dmacapable_via82cxxx(struct ata_channel *hwif, unsigned long dmabase)
{
- if ((via_enabled >> hwif->channel) & 1)
+ if ((via_enabled >> hwif->unit) & 1)
ide_setup_dma(hwif, dmabase, 8);
}
diff --git a/drivers/ieee1394/dv1394.c b/drivers/ieee1394/dv1394.c
index 0a763bc07c600..9055970fa97f2 100644
--- a/drivers/ieee1394/dv1394.c
+++ b/drivers/ieee1394/dv1394.c
@@ -100,7 +100,6 @@
#include <asm/pgtable.h>
#include <asm/page.h>
#include <linux/sched.h>
-#include <asm/segment.h>
#include <linux/types.h>
#include <linux/wrapper.h>
#include <linux/vmalloc.h>
diff --git a/drivers/ieee1394/pcilynx.c b/drivers/ieee1394/pcilynx.c
index 6194e0ceb9d71..5519f5146272b 100644
--- a/drivers/ieee1394/pcilynx.c
+++ b/drivers/ieee1394/pcilynx.c
@@ -56,7 +56,6 @@
#define PRINTD(level, card, fmt, args...) do {} while (0)
#endif
-
static struct hpsb_host_driver *lynx_driver;
static unsigned int card_id;
@@ -636,7 +635,7 @@ static void aux_setup_pcls(struct ti_lynx *lynx)
static int mem_open(struct inode *inode, struct file *file)
{
- int cid = MINOR(inode->i_rdev);
+ int cid = minor(inode->i_rdev);
enum { t_rom, t_aux, t_ram } type;
struct memdata *md;
diff --git a/drivers/ieee1394/video1394.c b/drivers/ieee1394/video1394.c
index 1f895a169813f..6faed1df70e70 100644
--- a/drivers/ieee1394/video1394.c
+++ b/drivers/ieee1394/video1394.c
@@ -43,7 +43,6 @@
#include <asm/pgtable.h>
#include <asm/page.h>
#include <linux/sched.h>
-#include <asm/segment.h>
#include <linux/types.h>
#include <linux/wrapper.h>
#include <linux/vmalloc.h>
diff --git a/drivers/isdn/avmb1/capifs.c b/drivers/isdn/avmb1/capifs.c
index b2d4aedff998c..1974ff61c5ebd 100644
--- a/drivers/isdn/avmb1/capifs.c
+++ b/drivers/isdn/avmb1/capifs.c
@@ -235,10 +235,9 @@ static int capifs_parse_options(char *options, struct capifs_sb_info *sbi)
unsigned int maxncci = 512;
char *this_char, *value;
- this_char = NULL;
- if ( options )
- this_char = strtok(options,",");
- for ( ; this_char; this_char = strtok(NULL,",")) {
+ while ((this_char = strsep(&options,",")) != NULL) {
+ if (!*this_char)
+ continue;
if ((value = strchr(this_char,'=')) != NULL)
*value++ = 0;
if (!strcmp(this_char,"uid")) {
diff --git a/drivers/isdn/avmb1/kcapi.c b/drivers/isdn/avmb1/kcapi.c
index 6ef1f9f33db62..5f6e530b11491 100644
--- a/drivers/isdn/avmb1/kcapi.c
+++ b/drivers/isdn/avmb1/kcapi.c
@@ -102,8 +102,8 @@ static char capi_manufakturer[64] = "AVM Berlin";
#define APPL(a) (&applications[(a)-1])
#define VALID_APPLID(a) ((a) && (a) <= CAPI_MAXAPPL && APPL(a)->applid == a)
#define APPL_IS_FREE(a) (APPL(a)->applid == 0)
-#define APPL_MARK_FREE(a) do{ APPL(a)->applid=0; MOD_DEC_USE_COUNT; }while(0);
-#define APPL_MARK_USED(a) do{ APPL(a)->applid=(a); MOD_INC_USE_COUNT; }while(0);
+#define APPL_MARK_FREE(a) do{ APPL(a)->applid=0; MOD_DEC_USE_COUNT; }while(0)
+#define APPL_MARK_USED(a) do{ APPL(a)->applid=(a); MOD_INC_USE_COUNT; }while(0)
#define NCCI2CTRL(ncci) (((ncci) >> 24) & 0x7f)
diff --git a/drivers/isdn/eicon/eicon_mod.c b/drivers/isdn/eicon/eicon_mod.c
index c0f818d0c5e2c..3a578a2ac8a50 100644
--- a/drivers/isdn/eicon/eicon_mod.c
+++ b/drivers/isdn/eicon/eicon_mod.c
@@ -665,8 +665,11 @@ if_readstatus(u_char * buf, int len, int user, int id, int channel)
else
cnt = skb->len;
- if (user)
+ if (user) {
+ spin_unlock_irqrestore(&eicon_lock, flags);
copy_to_user(p, skb->data, cnt);
+ spin_lock_irqsave(&eicon_lock, flags);
+ }
else
memcpy(p, skb->data, cnt);
diff --git a/drivers/isdn/hisax/hisax_fcpcipnp.c b/drivers/isdn/hisax/hisax_fcpcipnp.c
index 77c9a77d61d07..478f94730b6c6 100644
--- a/drivers/isdn/hisax/hisax_fcpcipnp.c
+++ b/drivers/isdn/hisax/hisax_fcpcipnp.c
@@ -65,6 +65,7 @@ MODULE_DEVICE_TABLE(isapnp, fcpnp_ids);
static int protocol = 2; /* EURO-ISDN Default */
MODULE_PARM(protocol, "i");
+MODULE_LICENSE("GPL");
// ----------------------------------------------------------------------
diff --git a/drivers/isdn/hisax/hisax_isac.c b/drivers/isdn/hisax/hisax_isac.c
index 29a96edf399ff..77f1320fc2690 100644
--- a/drivers/isdn/hisax/hisax_isac.c
+++ b/drivers/isdn/hisax/hisax_isac.c
@@ -44,6 +44,7 @@ static char *ISACVer[] = {
MODULE_AUTHOR("Kai Germaschewski <kai.germaschewski@gmx.de>/Karsten Keil <kkeil@suse.de>");
MODULE_DESCRIPTION("ISAC/ISAC-SX driver");
+MODULE_LICENSE("GPL");
#define DBG_WARN 0x0001
#define DBG_IRQ 0x0002
diff --git a/drivers/md/lvm-snap.c b/drivers/md/lvm-snap.c
index d904ddf9f91cf..ae149d7bb4311 100644
--- a/drivers/md/lvm-snap.c
+++ b/drivers/md/lvm-snap.c
@@ -302,6 +302,7 @@ int lvm_snapshot_COW(kdev_t org_phys_dev,
{
const char * reason;
kdev_t snap_phys_dev;
+ struct block_device *org_bdev, *snap_bdev;
unsigned long org_start, snap_start, virt_start, pe_off;
int idx = lv_snap->u.lv_remap_ptr, chunk_size = lv_snap->u.lv_chunk_size;
struct kiobuf * iobuf;
@@ -321,6 +322,15 @@ int lvm_snapshot_COW(kdev_t org_phys_dev,
snap_phys_dev = lv_snap->u.lv_block_exception[idx].rdev_new;
snap_start = lv_snap->u.lv_block_exception[idx].rsector_new;
+ org_bdev = bdget(kdev_t_to_nr(org_phys_dev));
+ if (!org_bdev)
+ goto fail_enomem;
+ snap_bdev = bdget(kdev_t_to_nr(snap_phys_dev));
+ if (!snap_bdev) {
+ bdput(org_bdev);
+ goto fail_enomem;
+ }
+
#ifdef DEBUG_SNAPSHOT
printk(KERN_INFO
"%s -- COW: "
@@ -356,7 +366,7 @@ int lvm_snapshot_COW(kdev_t org_phys_dev,
nr_sectors, blksize_org))
goto fail_prepare;
- if (brw_kiovec(READ, 1, &iobuf, org_phys_dev,
+ if (brw_kiovec(READ, 1, &iobuf, org_bdev,
lv_snap->blocks, blksize_org) != (nr_sectors<<9))
goto fail_raw_read;
@@ -364,7 +374,7 @@ int lvm_snapshot_COW(kdev_t org_phys_dev,
nr_sectors, blksize_snap))
goto fail_prepare;
- if (brw_kiovec(WRITE, 1, &iobuf, snap_phys_dev,
+ if (brw_kiovec(WRITE, 1, &iobuf, snap_bdev,
lv_snap->blocks, blksize_snap) !=(nr_sectors<<9))
goto fail_raw_write;
}
@@ -387,16 +397,21 @@ int lvm_snapshot_COW(kdev_t org_phys_dev,
if (lv_snap->u.lv_remap_ptr * 100 / lv_snap->u.lv_remap_end >= lv_snap->lv_snapshot_use_rate)
wake_up_interruptible(&lv_snap->lv_snapshot_wait);
}
+ bdput(snap_bdev);
+ bdput(org_bdev);
return 0;
/* slow path */
out:
+ bdput(snap_bdev);
+ bdput(org_bdev);
+ out1:
lvm_drop_snapshot(vg, lv_snap, reason);
return 1;
fail_out_of_space:
reason = "out of space";
- goto out;
+ goto out1;
fail_raw_read:
reason = "read error";
goto out;
@@ -405,7 +420,9 @@ int lvm_snapshot_COW(kdev_t org_phys_dev,
goto out;
fail_blksize:
reason = "blocksize error";
- goto out;
+ fail_enomem:
+ reason = "out of memory";
+ goto out1;
fail_prepare:
reason = "couldn't prepare kiovec blocks "
@@ -569,6 +586,7 @@ static int _write_COW_table_block(vg_t *vg, lv_t *lv_snap,
COW_entries_per_pe, COW_chunks_per_pe, COW_entries_per_block;
ulong blocks[1];
kdev_t snap_phys_dev;
+ struct block_device *bdev;
lv_block_exception_t *be;
struct kiobuf * COW_table_iobuf = lv_snap->lv_COW_table_iobuf;
lv_COW_table_disk_t * lv_COW_table =
@@ -581,6 +599,8 @@ static int _write_COW_table_block(vg_t *vg, lv_t *lv_snap,
snap_phys_dev = lv_snap->u.lv_block_exception[idx].rdev_new;
snap_pe_start = lv_snap->u.lv_block_exception[idx - (idx % COW_entries_per_pe)].rsector_new - lv_snap->u.lv_chunk_size;
+ bdev = bdget(kdev_t_to_nr(snap_phys_dev));
+
blksize_snap = block_size(snap_phys_dev);
COW_entries_per_block = blksize_snap / sizeof(lv_COW_table_disk_t);
@@ -611,7 +631,7 @@ static int _write_COW_table_block(vg_t *vg, lv_t *lv_snap,
COW_table_iobuf->length = blksize_snap;
- if (brw_kiovec(WRITE, 1, &COW_table_iobuf, snap_phys_dev,
+ if (brw_kiovec(WRITE, 1, &COW_table_iobuf, bdev,
blocks, blksize_snap) != blksize_snap)
goto fail_raw_write;
@@ -629,25 +649,30 @@ static int _write_COW_table_block(vg_t *vg, lv_t *lv_snap,
idx++;
snap_phys_dev = lv_snap->u.lv_block_exception[idx].rdev_new;
snap_pe_start = lv_snap->u.lv_block_exception[idx - (idx % COW_entries_per_pe)].rsector_new - lv_snap->u.lv_chunk_size;
+ bdput(bdev);
+ bdev = bdget(kdev_t_to_nr(snap_phys_dev));
blksize_snap = block_size(snap_phys_dev);
blocks[0] = snap_pe_start >> (blksize_snap >> 10);
} else blocks[0]++;
- if (brw_kiovec(WRITE, 1, &COW_table_iobuf, snap_phys_dev,
+ if (brw_kiovec(WRITE, 1, &COW_table_iobuf, bdev,
blocks, blksize_snap) !=
blksize_snap)
goto fail_raw_write;
}
out:
+ bdput(bdev);
return 0;
fail_raw_write:
*reason = "write error";
+ bdput(bdev);
return 1;
fail_pv_get_number:
*reason = "_pv_get_number failed";
+ bdput(bdev);
return 1;
}
diff --git a/drivers/md/md.c b/drivers/md/md.c
index 5e542a243ea4c..800cb26a70c58 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -3768,7 +3768,7 @@ static int __init md_setup(char *str)
printk(KERN_WARNING "md: md=%d, Minor device number too high.\n", minor);
return 0;
} else if (md_setup_args.device_names[minor]) {
- printk(KERN_WARNING "md: md=%d, Specified more then once. "
+ printk(KERN_WARNING "md: md=%d, Specified more than once. "
"Replacing previous definition.\n", minor);
}
switch (get_option(&str, &level)) { /* RAID Personality */
diff --git a/drivers/media/radio/radio-gemtek-pci.c b/drivers/media/radio/radio-gemtek-pci.c
index fe72982f1ce6d..818fa08f0f598 100644
--- a/drivers/media/radio/radio-gemtek-pci.c
+++ b/drivers/media/radio/radio-gemtek-pci.c
@@ -385,7 +385,7 @@ static struct pci_driver gemtek_pci_driver =
name: "gemtek_pci",
id_table: gemtek_pci_id,
probe: gemtek_pci_probe,
- remove: __devexit_p(gemtek_pci_remove)
+ remove: __devexit_p(gemtek_pci_remove),
};
static int __init gemtek_pci_init_module( void )
diff --git a/drivers/media/video/videodev.c b/drivers/media/video/videodev.c
index d69f8378ca794..834d86e45f49c 100644
--- a/drivers/media/video/videodev.c
+++ b/drivers/media/video/videodev.c
@@ -107,20 +107,18 @@ static int video_open(struct inode *inode, struct file *file)
}
/*
- * ioctl helper function -- handles userspace copying
+ * helper function -- handles userspace copying for ioctl arguments
*/
int
-video_generic_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
+video_usercopy(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg,
+ int (*func)(struct inode *inode, struct file *file,
+ unsigned int cmd, void *arg))
{
- struct video_device *vfl = video_devdata(file);
char sbuf[128];
void *mbuf = NULL;
void *parg = NULL;
int err = -EINVAL;
-
- if (vfl->kernel_ioctl == NULL)
- return -EINVAL;
/* Copy arguments into temp kernel buffer */
switch (_IOC_DIR(cmd)) {
@@ -147,7 +145,7 @@ video_generic_ioctl(struct inode *inode, struct file *file,
}
/* call driver */
- err = vfl->kernel_ioctl(inode, file, cmd, parg);
+ err = func(inode, file, cmd, parg);
if (err == -ENOIOCTLCMD)
err = -EINVAL;
if (err < 0)
@@ -512,7 +510,7 @@ module_exit(videodev_exit)
EXPORT_SYMBOL(video_register_device);
EXPORT_SYMBOL(video_unregister_device);
EXPORT_SYMBOL(video_devdata);
-EXPORT_SYMBOL(video_generic_ioctl);
+EXPORT_SYMBOL(video_usercopy);
EXPORT_SYMBOL(video_exclusive_open);
EXPORT_SYMBOL(video_exclusive_release);
diff --git a/drivers/mtd/chips/sharp.c b/drivers/mtd/chips/sharp.c
index 2c52149cace0b..85df53b919f93 100644
--- a/drivers/mtd/chips/sharp.c
+++ b/drivers/mtd/chips/sharp.c
@@ -440,7 +440,7 @@ static int sharp_do_wait_for_ready(struct map_info *map, struct flchip *chip,
timeo = jiffies + HZ;
- while(jiffies<timeo){
+ while(time_before(jiffies, timeo)){
map->write32(map,CMD_READ_STATUS,adr);
status = map->read32(map,adr);
if((status & SR_READY)==SR_READY){
diff --git a/drivers/mtd/devices/blkmtd.c b/drivers/mtd/devices/blkmtd.c
index cadcc6ccae9c1..fccc6c7a4afb4 100644
--- a/drivers/mtd/devices/blkmtd.c
+++ b/drivers/mtd/devices/blkmtd.c
@@ -264,7 +264,7 @@ static int blkmtd_readpage(mtd_raw_dev_data_t *rawdevice, struct page *page)
DEBUG(3, "bklmtd: readpage: starting brw_kiovec\n");
- err = brw_kiovec(READ, 1, &iobuf, dev, blocks, rawdevice->sector_size);
+ err = brw_kiovec(READ, 1, &iobuf, rawdevice->binding, blocks, rawdevice->sector_size);
DEBUG(3, "blkmtd: readpage: finished, err = %d\n", err);
iobuf->locked = 0;
free_kiovec(1, &iobuf);
@@ -401,7 +401,7 @@ static int write_queue_task(void *data)
iobuf->nr_pages = cpagecnt;
iobuf->length = cursectors << item->rawdevice->sector_bits;
DEBUG(3, "blkmtd: write_task: about to kiovec\n");
- err = brw_kiovec(WRITE, 1, &iobuf, dev, blocks, item->rawdevice->sector_size);
+ err = brw_kiovec(WRITE, 1, &iobuf, item->rawdevice->binding, blocks, item->rawdevice->sector_size);
DEBUG(3, "bklmtd: write_task: done, err = %d\n", err);
if(err != (cursectors << item->rawdevice->sector_bits)) {
/* if an error occured - set this to exit the loop */
diff --git a/drivers/mtd/ftl.c b/drivers/mtd/ftl.c
index 1fc63d360def9..947b797d19f2f 100644
--- a/drivers/mtd/ftl.c
+++ b/drivers/mtd/ftl.c
@@ -195,7 +195,7 @@ static int ftl_ioctl(struct inode *inode, struct file *file,
u_int cmd, u_long arg);
static int ftl_open(struct inode *inode, struct file *file);
static release_t ftl_close(struct inode *inode, struct file *file);
-static int ftl_reread_partitions(int minor);
+static int ftl_reread_partitions(kdev_t dev);
static void ftl_erase_callback(struct erase_info *done);
@@ -842,7 +842,7 @@ static u_int32_t find_free(partition_t *part)
static int ftl_open(struct inode *inode, struct file *file)
{
- int minor = MINOR(inode->i_rdev);
+ int minor = minor(inode->i_rdev);
partition_t *partition;
if (minor>>4 >= MAX_MTD_DEVICES)
@@ -878,7 +878,7 @@ static int ftl_open(struct inode *inode, struct file *file)
static release_t ftl_close(struct inode *inode, struct file *file)
{
- int minor = MINOR(inode->i_rdev);
+ int minor = minor(inode->i_rdev);
partition_t *part = myparts[minor >> 4];
int i;
@@ -1114,7 +1114,7 @@ static int ftl_ioctl(struct inode *inode, struct file *file,
u_int cmd, u_long arg)
{
struct hd_geometry *geo = (struct hd_geometry *)arg;
- int ret = 0, minor = MINOR(inode->i_rdev);
+ int ret = 0, minor = minor(inode->i_rdev);
partition_t *part= myparts[minor >> 4];
u_long sect;
@@ -1139,7 +1139,7 @@ static int ftl_ioctl(struct inode *inode, struct file *file,
ret = put_user((u64)ftl_hd[minor].nr_sects << 9, (u64 *)arg);
break;
case BLKRRPART:
- ret = ftl_reread_partitions(minor);
+ ret = ftl_reread_partitions(inode->i_rdev);
break;
case BLKROSET:
case BLKROGET:
@@ -1161,7 +1161,7 @@ static int ftl_ioctl(struct inode *inode, struct file *file,
static int ftl_reread_partitions(kdev_t dev)
{
- int minor = MINOR(dev);
+ int minor = minor(dev);
partition_t *part = myparts[minor >> 4];
int res;
@@ -1197,7 +1197,7 @@ static void do_ftl_request(request_arg_t)
// sti();
INIT_REQUEST;
- minor = MINOR(CURRENT->rq_dev);
+ minor = minor(CURRENT->rq_dev);
part = myparts[minor >> 4];
if (part) {
@@ -1369,7 +1369,7 @@ static void __exit cleanup_ftl(void)
unregister_blkdev(FTL_MAJOR, "ftl");
blk_cleanup_queue(BLK_DEFAULT_QUEUE(FTL_MAJOR));
- bklk_clear(FTL_MAJOR);
+ blk_clear(FTL_MAJOR);
del_gendisk(&ftl_gendisk);
}
diff --git a/drivers/mtd/mtdblock.c b/drivers/mtd/mtdblock.c
index 8dfec3a98ea9e..08782d2c84f7b 100644
--- a/drivers/mtd/mtdblock.c
+++ b/drivers/mtd/mtdblock.c
@@ -541,7 +541,7 @@ static int mtdblock_ioctl(struct inode * inode, struct file * file,
return -EACCES;
#endif
fsync_bdev(inode->i_bdev);
- invalidate_buffers(inode->i_rdev);
+ invalidate_bdev(inode->b_rdev, 0);
down(&mtdblk->cache_sem);
write_cached_data(mtdblk);
up(&mtdblk->cache_sem);
diff --git a/drivers/mtd/mtdblock_ro.c b/drivers/mtd/mtdblock_ro.c
index 79f4a0132a2a9..a3f4c6c8e83d4 100644
--- a/drivers/mtd/mtdblock_ro.c
+++ b/drivers/mtd/mtdblock_ro.c
@@ -222,7 +222,7 @@ static int mtdblock_ioctl(struct inode * inode, struct file * file,
if(!capable(CAP_SYS_ADMIN)) return -EACCES;
#endif
fsync_bdev(inode->i_bdev);
- invalidate_buffers(inode->i_rdev);
+ invalidate_bdev(inode->i_bdev, 0);
if (mtd->sync)
mtd->sync(mtd);
return 0;
diff --git a/drivers/mtd/nand/nand_ecc.c b/drivers/mtd/nand/nand_ecc.c
index baaefc3440707..419352a59a9a3 100644
--- a/drivers/mtd/nand/nand_ecc.c
+++ b/drivers/mtd/nand/nand_ecc.c
@@ -207,3 +207,5 @@ int nand_correct_data (u_char *dat, u_char *read_ecc, u_char *calc_ecc)
EXPORT_SYMBOL(nand_calculate_ecc);
EXPORT_SYMBOL(nand_correct_data);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/mtd/nftlcore.c b/drivers/mtd/nftlcore.c
index 2b60ed1319e44..8fdf2171aa7a5 100644
--- a/drivers/mtd/nftlcore.c
+++ b/drivers/mtd/nftlcore.c
@@ -796,7 +796,7 @@ static int nftl_ioctl(struct inode * inode, struct file * file, unsigned int cmd
case BLKFLSBUF:
if (!capable(CAP_SYS_ADMIN)) return -EACCES;
fsync_bdev(inode->i_bdev);
- invalidate_buffers(inode->i_rdev);
+ invalidate_bdev(inode->i_bdev, 0);
if (nftl->mtd->sync)
nftl->mtd->sync(nftl->mtd);
return 0;
diff --git a/drivers/net/3c503.c b/drivers/net/3c503.c
index 945476049d310..b66a44a74f32e 100644
--- a/drivers/net/3c503.c
+++ b/drivers/net/3c503.c
@@ -263,13 +263,13 @@ el2_probe1(struct net_device *dev, int ioaddr)
#endif /* EL2MEMTEST */
if (dev->mem_start)
- dev->mem_end = dev->rmem_end = dev->mem_start + EL2_MEMSIZE;
+ dev->mem_end = ei_status.rmem_end = dev->mem_start + EL2_MEMSIZE;
if (wordlength) { /* No Tx pages to skip over to get to Rx */
- dev->rmem_start = dev->mem_start;
+ ei_status.rmem_start = dev->mem_start;
ei_status.name = "3c503/16";
} else {
- dev->rmem_start = TX_PAGES*256 + dev->mem_start;
+ ei_status.rmem_start = TX_PAGES*256 + dev->mem_start;
ei_status.name = "3c503";
}
}
@@ -549,7 +549,7 @@ el2_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring
unsigned short int *buf;
unsigned short word;
- int end_of_ring = dev->rmem_end;
+ int end_of_ring = ei_status.rmem_end;
/* Maybe enable shared memory just be to be safe... nahh.*/
if (dev->mem_start) { /* Use the shared memory. */
@@ -559,7 +559,7 @@ el2_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring
int semi_count = end_of_ring - (dev->mem_start + ring_offset);
isa_memcpy_fromio(skb->data, dev->mem_start + ring_offset, semi_count);
count -= semi_count;
- isa_memcpy_fromio(skb->data + semi_count, dev->rmem_start, count);
+ isa_memcpy_fromio(skb->data + semi_count, ei_status.rmem_start, count);
} else {
/* Packet is in one chunk -- we can copy + cksum. */
isa_eth_io_copy_and_sum(skb, dev->mem_start + ring_offset, count, 0);
diff --git a/drivers/net/3c505.c b/drivers/net/3c505.c
index c49bf47697457..ed6c39fae6ca8 100644
--- a/drivers/net/3c505.c
+++ b/drivers/net/3c505.c
@@ -1383,7 +1383,7 @@ static inline void elp_init(struct net_device *dev)
/*
* memory information
*/
- dev->mem_start = dev->mem_end = dev->rmem_end = dev->rmem_start = 0;
+ dev->mem_start = dev->mem_end = 0;
}
/************************************************************
diff --git a/drivers/net/8390.h b/drivers/net/8390.h
index a098e7f1399d8..91db251922b5c 100644
--- a/drivers/net/8390.h
+++ b/drivers/net/8390.h
@@ -51,8 +51,6 @@ extern int ei_open(struct net_device *dev);
extern int ei_close(struct net_device *dev);
extern void ei_interrupt(int irq, void *dev_id, struct pt_regs *regs);
-/* Most of these entries should be in 'struct net_device' (or most of the
- things in there should be here!) */
/* You have one of these per-board */
struct ei_device {
const char *name;
@@ -60,6 +58,8 @@ struct ei_device {
void (*get_8390_hdr)(struct net_device *, struct e8390_pkt_hdr *, int);
void (*block_output)(struct net_device *, int, const unsigned char *, int);
void (*block_input)(struct net_device *, int, struct sk_buff *, int);
+ unsigned long rmem_start;
+ unsigned long rmem_end;
unsigned char mcfilter[8];
unsigned open:1;
unsigned word16:1; /* We have the 16-bit (vs 8-bit) version of the card. */
diff --git a/drivers/net/Config.in b/drivers/net/Config.in
index c715ce2ec6a8b..29ffbae9923b9 100644
--- a/drivers/net/Config.in
+++ b/drivers/net/Config.in
@@ -57,6 +57,9 @@ if [ "$CONFIG_NET_ETHERNET" = "y" ]; then
if [ "$CONFIG_MIPS_AU1000" = "y" ]; then
bool ' MIPS AU1000 Ethernet support' CONFIG_MIPS_AU1000_ENET
fi
+ if [ "$CONFIG_SIBYTE_SB1250" = "y" ]; then
+ tristate ' SB1250 Ethernet support' CONFIG_NET_SB1250_MAC
+ fi
if [ "$CONFIG_SGI_IP27" = "y" ]; then
bool ' SGI IOC3 Ethernet' CONFIG_SGI_IOC3_ETH
fi
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index f423ce03e25a0..ba862018f2a29 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -82,6 +82,7 @@ obj-$(CONFIG_NS83820) += ns83820.o
obj-$(CONFIG_STNIC) += stnic.o 8390.o
obj-$(CONFIG_FEALNX) += fealnx.o mii.o
obj-$(CONFIG_TIGON3) += tg3.o
+obj-$(CONFIG_TC35815) += tc35815.o
ifeq ($(CONFIG_SK98LIN),y)
obj-y += sk98lin/sk98lin.o
@@ -133,6 +134,7 @@ obj-$(CONFIG_E2100) += e2100.o 8390.o
obj-$(CONFIG_ES3210) += es3210.o 8390.o
obj-$(CONFIG_LNE390) += lne390.o 8390.o
obj-$(CONFIG_NE3210) += ne3210.o 8390.o
+obj-$(CONFIG_NET_SB1250_MAC) += sb1250-mac.o
obj-$(CONFIG_PPP) += ppp_generic.o slhc.o
obj-$(CONFIG_PPP_ASYNC) += ppp_async.o
@@ -153,6 +155,7 @@ obj-$(CONFIG_DE600) += de600.o
obj-$(CONFIG_DE620) += de620.o
obj-$(CONFIG_AT1500) += lance.o
obj-$(CONFIG_LANCE) += lance.o
+obj-$(CONFIG_SUN3_82586) += sun3_82586.o
obj-$(CONFIG_SUN3LANCE) += sun3lance.o
obj-$(CONFIG_DEFXX) += defxx.o
obj-$(CONFIG_SGISEEQ) += sgiseeq.o
diff --git a/drivers/net/Space.c b/drivers/net/Space.c
index 671588da63427..db7a696ea7ce5 100644
--- a/drivers/net/Space.c
+++ b/drivers/net/Space.c
@@ -12,6 +12,8 @@
* Donald J. Becker, <becker@scyld.com>
*
* Changelog:
+ * Paul Gortmaker (03/2002)
+ - struct init cleanup, enable multiple ISA autoprobes.
* Arnaldo Carvalho de Melo <acme@conectiva.com.br> - 09/1999
* - fix sbni: s/device/net_device/
* Paul Gortmaker (06/98):
@@ -86,6 +88,7 @@ extern int smc_init( struct net_device * );
extern int sgiseeq_probe(struct net_device *);
extern int atarilance_probe(struct net_device *);
extern int sun3lance_probe(struct net_device *);
+extern int sun3_82586_probe(struct net_device *);
extern int apne_probe(struct net_device *);
extern int bionet_probe(struct net_device *);
extern int pamsnet_probe(struct net_device *);
@@ -332,6 +335,9 @@ static struct devprobe m68k_probes[] __initdata = {
#ifdef CONFIG_SUN3LANCE /* sun3 onboard Lance chip */
{sun3lance_probe, 0},
#endif
+#ifdef CONFIG_SUN3_82586 /* sun3 onboard Intel 82586 chip */
+ {sun3_82586_probe, 0},
+#endif
#ifdef CONFIG_APNE /* A1200 PCMCIA NE2000 */
{apne_probe, 0},
#endif
@@ -410,14 +416,7 @@ static int __init ethif_probe(struct net_device *dev)
return 0;
if (probe_list(dev, mca_probes) == 0)
return 0;
- /*
- * Backwards compatibility - an I/O of 0xffe0 was used to indicate
- * that we shouldn't do a bunch of potentially risky ISA probes
- * for ethN (N>1). Since the widespread use of modules, *nobody*
- * compiles a kernel with all the ISA drivers built in anymore,
- * and so we should delete this check in linux 2.3 - Paul G.
- */
- if (base_addr != 0xffe0 && probe_list(dev, isa_probes) == 0)
+ if (probe_list(dev, isa_probes) == 0)
return 0;
if (probe_list(dev, parport_probes) == 0)
return 0;
@@ -466,74 +465,102 @@ static int fcif_probe(struct net_device *dev)
#ifdef CONFIG_ETHERTAP
- static struct net_device tap0_dev = { "tap0", 0, 0, 0, 0, NETLINK_TAPBASE, 0, 0, 0, 0, NEXT_DEV, ethertap_probe, };
-# undef NEXT_DEV
-# define NEXT_DEV (&tap0_dev)
+static struct net_device tap0_dev = {
+ name: "tap0",
+ base_addr: NETLINK_TAPBASE,
+ next: NEXT_DEV,
+ init: ethertap_probe,
+};
+#undef NEXT_DEV
+#define NEXT_DEV (&tap0_dev)
#endif
#ifdef CONFIG_SDLA
- extern int sdla_init(struct net_device *);
- static struct net_device sdla0_dev = { "sdla0", 0, 0, 0, 0, 0, 0, 0, 0, 0, NEXT_DEV, sdla_init, };
-
-# undef NEXT_DEV
-# define NEXT_DEV (&sdla0_dev)
+extern int sdla_init(struct net_device *);
+static struct net_device sdla0_dev = {
+ name: "sdla0",
+ next: NEXT_DEV,
+ init: sdla_init,
+};
+#undef NEXT_DEV
+#define NEXT_DEV (&sdla0_dev)
#endif
#if defined(CONFIG_LTPC)
- extern int ltpc_probe(struct net_device *);
- static struct net_device dev_ltpc = {
- "lt0",
- 0, 0, 0, 0,
- 0x0, 0,
- 0, 0, 0, NEXT_DEV, ltpc_probe };
-# undef NEXT_DEV
-# define NEXT_DEV (&dev_ltpc)
+extern int ltpc_probe(struct net_device *);
+static struct net_device dev_ltpc = {
+ name: "lt0",
+ next: NEXT_DEV,
+ init: ltpc_probe
+};
+#undef NEXT_DEV
+#define NEXT_DEV (&dev_ltpc)
#endif /* LTPC */
#if defined(CONFIG_COPS)
- extern int cops_probe(struct net_device *);
- static struct net_device cops2_dev = { "lt2", 0, 0, 0, 0, 0x0, 0, 0, 0, 0, NEXT_DEV, cops_probe };
- static struct net_device cops1_dev = { "lt1", 0, 0, 0, 0, 0x0, 0, 0, 0, 0, &cops2_dev, cops_probe };
- static struct net_device cops0_dev = { "lt0", 0, 0, 0, 0, 0x0, 0, 0, 0, 0, &cops1_dev, cops_probe };
-# undef NEXT_DEV
-# define NEXT_DEV (&cops0_dev)
+extern int cops_probe(struct net_device *);
+static struct net_device cops2_dev = {
+ name: "lt2",
+ next: NEXT_DEV,
+ init: cops_probe,
+};
+static struct net_device cops1_dev = {
+ name: "lt1",
+ next: &cops2_dev,
+ init: cops_probe,
+};
+static struct net_device cops0_dev = {
+ name: "lt0",
+ next: &cops1_dev,
+ init: cops_probe,
+};
+#undef NEXT_DEV
+#define NEXT_DEV (&cops0_dev)
#endif /* COPS */
-
-/* The first device defaults to I/O base '0', which means autoprobe. */
-#ifndef ETH0_ADDR
-# define ETH0_ADDR 0
-#endif
-#ifndef ETH0_IRQ
-# define ETH0_IRQ 0
-#endif
-
-/* "eth0" defaults to autoprobe (== 0), other use a base of 0xffe0 (== -0x20),
- which means "don't do ISA probes". Distributions don't ship kernels with
- all ISA drivers compiled in anymore, so its probably no longer an issue. */
-
-#define ETH_NOPROBE_ADDR 0xffe0
-
static struct net_device eth7_dev = {
- "eth%d", 0,0,0,0,ETH_NOPROBE_ADDR /* I/O base*/, 0,0,0,0, NEXT_DEV, ethif_probe };
+ name: "eth%d",
+ next: NEXT_DEV,
+ init: ethif_probe,
+};
static struct net_device eth6_dev = {
- "eth%d", 0,0,0,0,ETH_NOPROBE_ADDR /* I/O base*/, 0,0,0,0, &eth7_dev, ethif_probe };
+ name: "eth%d",
+ next: &eth7_dev,
+ init: ethif_probe,
+};
static struct net_device eth5_dev = {
- "eth%d", 0,0,0,0,ETH_NOPROBE_ADDR /* I/O base*/, 0,0,0,0, &eth6_dev, ethif_probe };
+ name: "eth%d",
+ next: &eth6_dev,
+ init: ethif_probe,
+};
static struct net_device eth4_dev = {
- "eth%d", 0,0,0,0,ETH_NOPROBE_ADDR /* I/O base*/, 0,0,0,0, &eth5_dev, ethif_probe };
+ name: "eth%d",
+ next: &eth5_dev,
+ init: ethif_probe,
+};
static struct net_device eth3_dev = {
- "eth%d", 0,0,0,0,ETH_NOPROBE_ADDR /* I/O base*/, 0,0,0,0, &eth4_dev, ethif_probe };
+ name: "eth%d",
+ next: &eth4_dev,
+ init: ethif_probe,
+};
static struct net_device eth2_dev = {
- "eth%d", 0,0,0,0,ETH_NOPROBE_ADDR /* I/O base*/, 0,0,0,0, &eth3_dev, ethif_probe };
+ name: "eth%d",
+ next: &eth3_dev,
+ init: ethif_probe,
+};
static struct net_device eth1_dev = {
- "eth%d", 0,0,0,0,ETH_NOPROBE_ADDR /* I/O base*/, 0,0,0,0, &eth2_dev, ethif_probe };
-
+ name: "eth%d",
+ next: &eth2_dev,
+ init: ethif_probe,
+};
static struct net_device eth0_dev = {
- "eth%d", 0, 0, 0, 0, ETH0_ADDR, ETH0_IRQ, 0, 0, 0, &eth1_dev, ethif_probe };
+ name: "eth%d",
+ next: &eth1_dev,
+ init: ethif_probe,
+};
-# undef NEXT_DEV
-# define NEXT_DEV (&eth0_dev)
+#undef NEXT_DEV
+#define NEXT_DEV (&eth0_dev)
@@ -558,75 +585,153 @@ trif_probe(struct net_device *dev)
return 0;
}
static struct net_device tr7_dev = {
- "tr%d",0,0,0,0,0,0,0,0,0, NEXT_DEV, trif_probe };
+ name: "tr%d",
+ next: NEXT_DEV,
+ init: trif_probe,
+};
static struct net_device tr6_dev = {
- "tr%d",0,0,0,0,0,0,0,0,0, &tr7_dev, trif_probe };
+ name: "tr%d",
+ next: &tr7_dev,
+ init: trif_probe,
+};
static struct net_device tr5_dev = {
- "tr%d",0,0,0,0,0,0,0,0,0, &tr6_dev, trif_probe };
+ name: "tr%d",
+ next: &tr6_dev,
+ init: trif_probe,
+};
static struct net_device tr4_dev = {
- "tr%d",0,0,0,0,0,0,0,0,0, &tr5_dev, trif_probe };
+ name: "tr%d",
+ next: &tr5_dev,
+ init: trif_probe,
+};
static struct net_device tr3_dev = {
- "tr%d",0,0,0,0,0,0,0,0,0, &tr4_dev, trif_probe };
+ name: "tr%d",
+ next: &tr4_dev,
+ init: trif_probe,
+};
static struct net_device tr2_dev = {
- "tr%d",0,0,0,0,0,0,0,0,0, &tr3_dev, trif_probe };
+ name: "tr%d",
+ next: &tr3_dev,
+ init: trif_probe,
+};
static struct net_device tr1_dev = {
- "tr%d",0,0,0,0,0,0,0,0,0, &tr2_dev, trif_probe };
+ name: "tr%d",
+ next: &tr2_dev,
+ init: trif_probe,
+};
static struct net_device tr0_dev = {
- "tr%d",0,0,0,0,0,0,0,0,0, &tr1_dev, trif_probe };
-# undef NEXT_DEV
-# define NEXT_DEV (&tr0_dev)
+ name: "tr%d",
+ next: &tr1_dev,
+ init: trif_probe,
+};
+#undef NEXT_DEV
+#define NEXT_DEV (&tr0_dev)
#endif
#ifdef CONFIG_FDDI
- static struct net_device fddi7_dev =
- {"fddi7", 0, 0, 0, 0, 0, 0, 0, 0, 0, NEXT_DEV, fddiif_probe};
- static struct net_device fddi6_dev =
- {"fddi6", 0, 0, 0, 0, 0, 0, 0, 0, 0, &fddi7_dev, fddiif_probe};
- static struct net_device fddi5_dev =
- {"fddi5", 0, 0, 0, 0, 0, 0, 0, 0, 0, &fddi6_dev, fddiif_probe};
- static struct net_device fddi4_dev =
- {"fddi4", 0, 0, 0, 0, 0, 0, 0, 0, 0, &fddi5_dev, fddiif_probe};
- static struct net_device fddi3_dev =
- {"fddi3", 0, 0, 0, 0, 0, 0, 0, 0, 0, &fddi4_dev, fddiif_probe};
- static struct net_device fddi2_dev =
- {"fddi2", 0, 0, 0, 0, 0, 0, 0, 0, 0, &fddi3_dev, fddiif_probe};
- static struct net_device fddi1_dev =
- {"fddi1", 0, 0, 0, 0, 0, 0, 0, 0, 0, &fddi2_dev, fddiif_probe};
- static struct net_device fddi0_dev =
- {"fddi0", 0, 0, 0, 0, 0, 0, 0, 0, 0, &fddi1_dev, fddiif_probe};
+static struct net_device fddi7_dev = {
+ name: "fddi7",
+ next: NEXT_DEV,
+ init: fddiif_probe
+};
+static struct net_device fddi6_dev = {
+ name: "fddi6",
+ next: &fddi7_dev,
+ init: fddiif_probe
+};
+static struct net_device fddi5_dev = {
+ name: "fddi5",
+ next: &fddi6_dev,
+ init: fddiif_probe
+};
+static struct net_device fddi4_dev = {
+ name: "fddi4",
+ next: &fddi5_dev,
+ init: fddiif_probe
+};
+static struct net_device fddi3_dev = {
+ name: "fddi3",
+ next: &fddi4_dev,
+ init: fddiif_probe
+};
+static struct net_device fddi2_dev = {
+ name: "fddi2",
+ next: &fddi3_dev,
+ init: fddiif_probe
+};
+static struct net_device fddi1_dev = {
+ name: "fddi1",
+ next: &fddi2_dev,
+ init: fddiif_probe
+};
+static struct net_device fddi0_dev = {
+ name: "fddi0",
+ next: &fddi1_dev,
+ init: fddiif_probe
+};
#undef NEXT_DEV
#define NEXT_DEV (&fddi0_dev)
#endif
#ifdef CONFIG_NET_FC
- static struct net_device fc1_dev = {
- "fc1", 0, 0, 0, 0, 0, 0, 0, 0, 0, NEXT_DEV, fcif_probe};
- static struct net_device fc0_dev = {
- "fc0", 0, 0, 0, 0, 0, 0, 0, 0, 0, &fc1_dev, fcif_probe};
-# undef NEXT_DEV
-# define NEXT_DEV (&fc0_dev)
+static struct net_device fc1_dev = {
+ name: "fc1",
+ next: NEXT_DEV,
+ init: fcif_probe
+};
+static struct net_device fc0_dev = {
+ name: "fc0",
+ next: &fc1_dev,
+ init: fcif_probe
+};
+#undef NEXT_DEV
+#define NEXT_DEV (&fc0_dev)
#endif
#ifdef CONFIG_SBNI
- static struct net_device sbni7_dev =
- {"sbni7", 0, 0, 0, 0, 0, 0, 0, 0, 0, NEXT_DEV, sbni_probe};
- static struct net_device sbni6_dev =
- {"sbni6", 0, 0, 0, 0, 0, 0, 0, 0, 0, &sbni7_dev, sbni_probe};
- static struct net_device sbni5_dev =
- {"sbni5", 0, 0, 0, 0, 0, 0, 0, 0, 0, &sbni6_dev, sbni_probe};
- static struct net_device sbni4_dev =
- {"sbni4", 0, 0, 0, 0, 0, 0, 0, 0, 0, &sbni5_dev, sbni_probe};
- static struct net_device sbni3_dev =
- {"sbni3", 0, 0, 0, 0, 0, 0, 0, 0, 0, &sbni4_dev, sbni_probe};
- static struct net_device sbni2_dev =
- {"sbni2", 0, 0, 0, 0, 0, 0, 0, 0, 0, &sbni3_dev, sbni_probe};
- static struct net_device sbni1_dev =
- {"sbni1", 0, 0, 0, 0, 0, 0, 0, 0, 0, &sbni2_dev, sbni_probe};
- static struct net_device sbni0_dev =
- {"sbni0", 0, 0, 0, 0, 0, 0, 0, 0, 0, &sbni1_dev, sbni_probe};
+static struct net_device sbni7_dev = {
+ name: "sbni7",
+ next: NEXT_DEV,
+ init: sbni_probe,
+};
+static struct net_device sbni6_dev =
+ name: "sbni6",
+ next: &sbni7_dev,
+ init: sbni_probe,
+};
+static struct net_device sbni5_dev =
+ name: "sbni5",
+ next: &sbni6_dev,
+ init: sbni_probe,
+};
+static struct net_device sbni4_dev =
+ name: "sbni4",
+ next: &sbni5_dev,
+ init: sbni_probe,
+};
+static struct net_device sbni3_dev =
+ name: "sbni3",
+ next: &sbni4_dev,
+ init: sbni_probe,
+};
+static struct net_device sbni2_dev =
+ name: "sbni2",
+ next: &sbni3_dev,
+ init: sbni_probe,
+};
+static struct net_device sbni1_dev =
+ name: "sbni1",
+ next: &sbni2_dev,
+ init: sbni_probe,
+};
+static struct net_device sbni0_dev =
+ name: "sbni0",
+ next: &sbni1_dev,
+ init: sbni_probe,
+};
#undef NEXT_DEV
#define NEXT_DEV (&sbni0_dev)
@@ -638,8 +743,11 @@ static struct net_device tr0_dev = {
*/
extern int loopback_init(struct net_device *dev);
-struct net_device loopback_dev =
- {"lo", 0, 0, 0, 0, 0, 0, 0, 0, 0, NEXT_DEV, loopback_init};
+struct net_device loopback_dev = {
+ name: "lo",
+ next: NEXT_DEV,
+ init: loopback_init
+};
/*
* The @dev_base list is protected by @dev_base_lock and the rtln
diff --git a/drivers/net/ac3200.c b/drivers/net/ac3200.c
index ced6b5033411a..4a730e250400f 100644
--- a/drivers/net/ac3200.c
+++ b/drivers/net/ac3200.c
@@ -226,8 +226,8 @@ static int __init ac_probe1(int ioaddr, struct net_device *dev)
AC_STOP_PG/4, dev->mem_start);
}
- dev->rmem_start = dev->mem_start + TX_PAGES*256;
- dev->mem_end = dev->rmem_end = dev->mem_start
+ ei_status.rmem_start = dev->mem_start + TX_PAGES*256;
+ dev->mem_end = ei_status.rmem_end = dev->mem_start
+ (AC_STOP_PG - AC_START_PG)*256;
ei_status.name = "AC3200";
@@ -302,12 +302,12 @@ static void ac_block_input(struct net_device *dev, int count, struct sk_buff *sk
{
unsigned long xfer_start = dev->mem_start + ring_offset - (AC_START_PG<<8);
- if (xfer_start + count > dev->rmem_end) {
+ if (xfer_start + count > ei_status.rmem_end) {
/* We must wrap the input move. */
- int semi_count = dev->rmem_end - xfer_start;
+ int semi_count = ei_status.rmem_end - xfer_start;
isa_memcpy_fromio(skb->data, xfer_start, semi_count);
count -= semi_count;
- isa_memcpy_fromio(skb->data + semi_count, dev->rmem_start, count);
+ isa_memcpy_fromio(skb->data + semi_count, ei_status.rmem_start, count);
} else {
/* Packet is in one chunk -- we can copy + cksum. */
isa_eth_io_copy_and_sum(skb, xfer_start, count, 0);
diff --git a/drivers/net/acenic.c b/drivers/net/acenic.c
index 7f9390dd4863f..4a890e944b3f3 100644
--- a/drivers/net/acenic.c
+++ b/drivers/net/acenic.c
@@ -65,7 +65,10 @@
#include <linux/mm.h>
#include <linux/highmem.h>
#include <linux/sockios.h>
+
+#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
#include <linux/if_vlan.h>
+#endif
#ifdef SIOCETHTOOL
#include <linux/ethtool.h>
@@ -320,9 +323,11 @@ static inline void tasklet_init(struct tasklet_struct *tasklet,
#if (defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)) && \
defined(NETIF_F_HW_VLAN_RX)
-#define ACENIC_DO_VLAN 1
+#define ACENIC_DO_VLAN 1
+#define ACE_RCB_VLAN_FLAG RCB_FLG_VLAN_ASSIST
#else
-#define ACENIC_DO_VLAN 0
+#define ACENIC_DO_VLAN 0
+#define ACE_RCB_VLAN_FLAG 0
#endif
#include "acenic.h"
@@ -563,7 +568,7 @@ static int tx_ratio[ACE_MAX_MOD_PARMS];
static int dis_pci_mem_inval[ACE_MAX_MOD_PARMS] = {1, 1, 1, 1, 1, 1, 1, 1};
static char version[] __initdata =
- "acenic.c: v0.88 03/14/2002 Jes Sorensen, linux-acenic@SunSITE.dk\n"
+ "acenic.c: v0.89 03/15/2002 Jes Sorensen, linux-acenic@SunSITE.dk\n"
" http://home.cern.ch/~jes/gige/acenic.html\n";
static struct net_device *root_dev;
@@ -1461,10 +1466,8 @@ static int __init ace_init(struct net_device *dev)
set_aceaddr(&info->rx_std_ctrl.rngptr, ap->rx_ring_base_dma);
info->rx_std_ctrl.max_len = ACE_STD_MTU + ETH_HLEN + 4;
- info->rx_std_ctrl.flags = RCB_FLG_TCP_UDP_SUM|RCB_FLG_NO_PSEUDO_HDR;
-#if ACENIC_DO_VLAN
- info->rx_std_ctrl.flags |= RCB_FLG_VLAN_ASSIST;
-#endif
+ info->rx_std_ctrl.flags =
+ RCB_FLG_TCP_UDP_SUM | RCB_FLG_NO_PSEUDO_HDR | ACE_RCB_VLAN_FLAG;
memset(ap->rx_std_ring, 0,
RX_STD_RING_ENTRIES * sizeof(struct rx_desc));
@@ -1479,10 +1482,8 @@ static int __init ace_init(struct net_device *dev)
(ap->rx_ring_base_dma +
(sizeof(struct rx_desc) * RX_STD_RING_ENTRIES)));
info->rx_jumbo_ctrl.max_len = 0;
- info->rx_jumbo_ctrl.flags = RCB_FLG_TCP_UDP_SUM|RCB_FLG_NO_PSEUDO_HDR;
-#if ACENIC_DO_VLAN
- info->rx_jumbo_ctrl.flags |= RCB_FLG_VLAN_ASSIST;
-#endif
+ info->rx_jumbo_ctrl.flags =
+ RCB_FLG_TCP_UDP_SUM | RCB_FLG_NO_PSEUDO_HDR | ACE_RCB_VLAN_FLAG;
memset(ap->rx_jumbo_ring, 0,
RX_JUMBO_RING_ENTRIES * sizeof(struct rx_desc));
@@ -1504,10 +1505,7 @@ static int __init ace_init(struct net_device *dev)
RX_JUMBO_RING_ENTRIES))));
info->rx_mini_ctrl.max_len = ACE_MINI_SIZE;
info->rx_mini_ctrl.flags =
- RCB_FLG_TCP_UDP_SUM|RCB_FLG_NO_PSEUDO_HDR;
-#if ACENIC_DO_VLAN
- info->rx_mini_ctrl.flags |= RCB_FLG_VLAN_ASSIST;
-#endif
+ RCB_FLG_TCP_UDP_SUM|RCB_FLG_NO_PSEUDO_HDR|ACE_RCB_VLAN_FLAG;
for (i = 0; i < RX_MINI_RING_ENTRIES; i++)
ap->rx_mini_ring[i].flags =
@@ -1554,7 +1552,7 @@ static int __init ace_init(struct net_device *dev)
}
info->tx_ctrl.max_len = ACE_TX_RING_ENTRIES(ap);
- tmp = RCB_FLG_TCP_UDP_SUM|RCB_FLG_NO_PSEUDO_HDR;
+ tmp = RCB_FLG_TCP_UDP_SUM | RCB_FLG_NO_PSEUDO_HDR | ACE_RCB_VLAN_FLAG;
/*
* The Tigon I does not like having the TX ring in host memory ;-(
@@ -1564,9 +1562,6 @@ static int __init ace_init(struct net_device *dev)
#if TX_COAL_INTS_ONLY
tmp |= RCB_FLG_COAL_INT_ONLY;
#endif
-#if ACENIC_DO_VLAN
- tmp |= RCB_FLG_VLAN_ASSIST;
-#endif
info->tx_ctrl.flags = tmp;
set_aceaddr(&info->tx_csm_ptr, ap->tx_csm_dma);
@@ -1592,7 +1587,7 @@ static int __init ace_init(struct net_device *dev)
ace_set_rxtx_parms(dev, 0);
if (board_idx == BOARD_IDX_OVERFLOW) {
- printk(KERN_WARNING "%s: more then %i NICs detected, "
+ printk(KERN_WARNING "%s: more than %i NICs detected, "
"ignoring module parameters!\n",
dev->name, ACE_MAX_MOD_PARMS);
} else if (board_idx >= 0) {
@@ -2181,14 +2176,6 @@ static u32 ace_handle_event(struct net_device *dev, u32 evtcsm, u32 evtprd)
}
-#if ACENIC_DO_VLAN
-static int ace_vlan_rx(struct ace_private *ap, struct sk_buff *skb, u16 vlan_tag)
-{
- return vlan_hwaccel_rx(skb, ap->vlgrp, vlan_tag);
-}
-#endif
-
-
static void ace_rx_int(struct net_device *dev, u32 rxretprd, u32 rxretcsm)
{
struct ace_private *ap = dev->priv;
@@ -2274,11 +2261,9 @@ static void ace_rx_int(struct net_device *dev, u32 rxretprd, u32 rxretcsm)
}
/* send it up */
-
#if ACENIC_DO_VLAN
- if (ap->vlgrp != NULL &&
- (bd_flags & BD_FLG_VLAN_TAG)) {
- ace_vlan_rx(ap, skb, retdesc->vlan);
+ if (ap->vlgrp && (bd_flags & BD_FLG_VLAN_TAG)) {
+ vlan_hwaccel_rx(skb, ap->vlgrp, retdesc->vlan);
} else
#endif
netif_rx(skb);
diff --git a/drivers/net/acenic.h b/drivers/net/acenic.h
index 8933695b83a93..61eeecf8887ac 100644
--- a/drivers/net/acenic.h
+++ b/drivers/net/acenic.h
@@ -642,10 +642,6 @@ struct ace_private
struct ace_skb *skb;
dma_addr_t info_dma; /* 32/64 bit */
-#if ACENIC_DO_VLAN
- struct vlan_group *vlgrp;
-#endif
-
int version, link;
int promisc, mcast_all;
@@ -655,7 +651,6 @@ struct ace_private
struct tx_desc *tx_ring;
u32 tx_prd;
volatile u32 tx_ret_csm;
- struct timer_list timer;
int tx_ring_entries;
/*
@@ -675,6 +670,10 @@ struct ace_private
struct rx_desc *rx_mini_ring;
struct rx_desc *rx_return_ring;
+#if ACENIC_DO_VLAN
+ struct vlan_group *vlgrp;
+#endif
+
int tasklet_pending, jumbo;
struct tasklet_struct ace_tasklet;
diff --git a/drivers/net/aironet4500.h b/drivers/net/aironet4500.h
index 9f64d4ad3bf3b..24eebfa6ecca7 100644
--- a/drivers/net/aironet4500.h
+++ b/drivers/net/aironet4500.h
@@ -450,7 +450,7 @@ struct awc_fid_queue {
};
-extern __inline__ void
+static __inline__ void
awc_fid_queue_init(struct awc_fid_queue * queue){
unsigned long flags;
@@ -463,7 +463,7 @@ awc_fid_queue_init(struct awc_fid_queue * queue){
spin_unlock_irqrestore(&queue->spinlock,flags);
};
-extern inline void
+static inline void
awc_fid_queue_push_tail( struct awc_fid_queue * queue,
struct awc_fid * fid){
@@ -488,7 +488,7 @@ awc_fid_queue_push_tail( struct awc_fid_queue * queue,
};
-extern inline void
+static inline void
awc_fid_queue_push_head( struct awc_fid_queue * queue,
struct awc_fid * fid){
@@ -513,7 +513,7 @@ awc_fid_queue_push_head( struct awc_fid_queue * queue,
-extern inline void
+static inline void
awc_fid_queue_rm( struct awc_fid_queue * queue,
struct awc_fid * fid){
@@ -541,7 +541,7 @@ awc_fid_queue_rm( struct awc_fid_queue * queue,
}
};
-extern inline void
+static inline void
awc_fid_queue_remove( struct awc_fid_queue * queue,
struct awc_fid * fid){
unsigned long flags;
@@ -555,7 +555,7 @@ awc_fid_queue_remove( struct awc_fid_queue * queue,
-extern inline struct awc_fid *
+static inline struct awc_fid *
awc_fid_queue_pop_head( struct awc_fid_queue * queue){
unsigned long flags;
@@ -575,7 +575,7 @@ awc_fid_queue_pop_head( struct awc_fid_queue * queue){
-extern inline struct awc_fid *
+static inline struct awc_fid *
awc_fid_queue_pop_tail( struct awc_fid_queue * queue){
unsigned long flags;
diff --git a/drivers/net/arcnet/arc-rimi.c b/drivers/net/arcnet/arc-rimi.c
index 571670eaeb84c..b2f16c36b2c24 100644
--- a/drivers/net/arcnet/arc-rimi.c
+++ b/drivers/net/arcnet/arc-rimi.c
@@ -153,8 +153,6 @@ static int __init arcrimi_found(struct net_device *dev)
dev->mem_start = first_mirror;
dev->mem_end = last_mirror + MIRROR_SIZE - 1;
- dev->rmem_start = dev->mem_start + BUFFER_SIZE * 0;
- dev->rmem_end = dev->mem_start + BUFFER_SIZE * 2 - 1;
/* initialize the rest of the device structure. */
diff --git a/drivers/net/arcnet/com90xx.c b/drivers/net/arcnet/com90xx.c
index fd92d5e808f6c..9d208f400df71 100644
--- a/drivers/net/arcnet/com90xx.c
+++ b/drivers/net/arcnet/com90xx.c
@@ -447,8 +447,6 @@ static int __init com90xx_found(struct net_device *dev0, int ioaddr, int airq,
dev->mem_start = first_mirror;
dev->mem_end = last_mirror + MIRROR_SIZE - 1;
- dev->rmem_start = dev->mem_start + BUFFER_SIZE * 0;
- dev->rmem_end = dev->mem_start + BUFFER_SIZE * 2 - 1;
/* Initialize the rest of the device structure. */
memset(lp, 0, sizeof(struct arcnet_local));
diff --git a/drivers/net/arlan.c b/drivers/net/arlan.c
index 1bc62e2ecd26d..968a7692104b9 100644
--- a/drivers/net/arlan.c
+++ b/drivers/net/arlan.c
@@ -128,7 +128,7 @@ int arlan_command(struct net_device * dev, int command);
EXPORT_SYMBOL(arlan_command);
-extern inline long long arlan_time(void)
+static inline long long arlan_time(void)
{
struct timeval timev;
do_gettimeofday(&timev);
@@ -186,7 +186,7 @@ extern inline long long arlan_time(void)
-extern inline int arlan_drop_tx(struct net_device *dev)
+static inline int arlan_drop_tx(struct net_device *dev)
{
struct arlan_private *priv = ((struct arlan_private *) dev->priv);
@@ -554,7 +554,7 @@ command_busy_end:
};
-extern inline void arlan_command_process(struct net_device *dev)
+static inline void arlan_command_process(struct net_device *dev)
{
struct arlan_private *priv = ((struct arlan_private *) dev->priv);
@@ -575,7 +575,7 @@ extern inline void arlan_command_process(struct net_device *dev)
}
-extern inline void arlan_retransmit_now(struct net_device *dev)
+static inline void arlan_retransmit_now(struct net_device *dev)
{
struct arlan_private *priv = ((struct arlan_private *) dev->priv);
@@ -1405,7 +1405,7 @@ bad_end:
}
-extern inline int DoNotReTransmitCrap(struct net_device *dev)
+static inline int DoNotReTransmitCrap(struct net_device *dev)
{
struct arlan_private *priv = ((struct arlan_private *) dev->priv);
@@ -1415,7 +1415,7 @@ extern inline int DoNotReTransmitCrap(struct net_device *dev)
}
-extern inline int DoNotWaitReTransmitCrap(struct net_device *dev)
+static inline int DoNotWaitReTransmitCrap(struct net_device *dev)
{
struct arlan_private *priv = ((struct arlan_private *) dev->priv);
@@ -1424,7 +1424,7 @@ extern inline int DoNotWaitReTransmitCrap(struct net_device *dev)
return 0;
}
-extern inline void arlan_queue_retransmit(struct net_device *dev)
+static inline void arlan_queue_retransmit(struct net_device *dev)
{
struct arlan_private *priv = ((struct arlan_private *) dev->priv);
diff --git a/drivers/net/at1700.c b/drivers/net/at1700.c
index 01d144e50a804..ccd7c8e138c2e 100644
--- a/drivers/net/at1700.c
+++ b/drivers/net/at1700.c
@@ -465,7 +465,7 @@ err_out:
#define EE_DATA_READ 0x80 /* EEPROM chip data out, in reg. 17. */
/* Delay between EEPROM clock transitions. */
-#define eeprom_delay() do {} while (0);
+#define eeprom_delay() do { } while (0)
/* The EEPROM commands include the alway-set leading bit. */
#define EE_WRITE_CMD (5 << 6)
diff --git a/drivers/net/atp.c b/drivers/net/atp.c
index 5a31cfe28fd93..c3904af3bbe3d 100644
--- a/drivers/net/atp.c
+++ b/drivers/net/atp.c
@@ -667,7 +667,7 @@ static void atp_interrupt(int irq, void *dev_instance, struct pt_regs * regs)
}
num_tx_since_rx++;
} else if (num_tx_since_rx > 8
- && jiffies > dev->last_rx + HZ) {
+ && time_after(jiffies, dev->last_rx + HZ)) {
if (net_debug > 2)
printk(KERN_DEBUG "%s: Missed packet? No Rx after %d Tx and "
"%ld jiffies status %02x CMR1 %02x.\n", dev->name,
diff --git a/drivers/net/daynaport.c b/drivers/net/daynaport.c
index cc13e328cae63..ea424dcb74370 100644
--- a/drivers/net/daynaport.c
+++ b/drivers/net/daynaport.c
@@ -513,14 +513,14 @@ static int __init ns8390_probe1(struct net_device *dev, int word16, char *model_
ei_status.tx_start_page = CABLETRON_TX_START_PG;
ei_status.rx_start_page = CABLETRON_RX_START_PG;
ei_status.stop_page = CABLETRON_RX_STOP_PG;
- dev->rmem_start = dev->mem_start;
- dev->rmem_end = dev->mem_start + CABLETRON_RX_STOP_PG*256;
+ ei_status.rmem_start = dev->mem_start;
+ ei_status.rmem_end = dev->mem_start + CABLETRON_RX_STOP_PG*256;
} else {
ei_status.tx_start_page = WD_START_PG;
ei_status.rx_start_page = WD_START_PG + TX_PAGES;
ei_status.stop_page = (dev->mem_end - dev->mem_start)/256;
- dev->rmem_start = dev->mem_start + TX_PAGES*256;
- dev->rmem_end = dev->mem_end;
+ ei_status.rmem_start = dev->mem_start + TX_PAGES*256;
+ ei_status.rmem_end = dev->mem_end;
}
if(promoff==-1) /* Use nubus resources ? */
@@ -779,14 +779,14 @@ static void dayna_block_input(struct net_device *dev, int count, struct sk_buff
* is word per long onto our space.
*/
- if (xfer_start + count > dev->rmem_end)
+ if (xfer_start + count > ei_status.rmem_end)
{
/* We must wrap the input move. */
- int semi_count = dev->rmem_end - xfer_start;
+ int semi_count = ei_status.rmem_end - xfer_start;
dayna_memcpy_fromcard(dev, skb->data, xfer_base, semi_count);
count -= semi_count;
dayna_memcpy_fromcard(dev, skb->data + semi_count,
- dev->rmem_start - dev->mem_start, count);
+ ei_status.rmem_start - dev->mem_start, count);
}
else
{
@@ -820,14 +820,14 @@ static void sane_block_input(struct net_device *dev, int count, struct sk_buff *
unsigned long xfer_base = ring_offset - (WD_START_PG<<8);
unsigned long xfer_start = xfer_base+dev->mem_start;
- if (xfer_start + count > dev->rmem_end)
+ if (xfer_start + count > ei_status.rmem_end)
{
/* We must wrap the input move. */
- int semi_count = dev->rmem_end - xfer_start;
+ int semi_count = ei_status.rmem_end - xfer_start;
memcpy(skb->data, (char *)dev->mem_start+xfer_base, semi_count);
count -= semi_count;
memcpy(skb->data + semi_count,
- (char *)dev->rmem_start, count);
+ (char *)ei_status.rmem_start, count);
}
else
{
@@ -881,14 +881,14 @@ static void slow_sane_block_input(struct net_device *dev, int count, struct sk_b
unsigned long xfer_base = ring_offset - (WD_START_PG<<8);
unsigned long xfer_start = xfer_base+dev->mem_start;
- if (xfer_start + count > dev->rmem_end)
+ if (xfer_start + count > ei_status.rmem_end)
{
/* We must wrap the input move. */
- int semi_count = dev->rmem_end - xfer_start;
+ int semi_count = ei_status.rmem_end - xfer_start;
word_memcpy_fromcard(skb->data, (char *)dev->mem_start+xfer_base, semi_count);
count -= semi_count;
word_memcpy_fromcard(skb->data + semi_count,
- (char *)dev->rmem_start, count);
+ (char *)ei_status.rmem_start, count);
}
else
{
diff --git a/drivers/net/de620.c b/drivers/net/de620.c
index 98d8216215011..e8ec685354d43 100644
--- a/drivers/net/de620.c
+++ b/drivers/net/de620.c
@@ -449,11 +449,17 @@ static int de620_open(struct net_device *dev)
return ret;
}
- if (adapter_init(dev))
- return -EIO;
+ if (adapter_init(dev)) {
+ ret = -EIO;
+ goto out_free_irq;
+ }
netif_start_queue(dev);
return 0;
+
+out_free_irq:
+ free_irq(dev->irq, dev);
+ return ret;
}
/************************************************
@@ -850,7 +856,10 @@ int __init de620_probe(struct net_device *dev)
return -EBUSY;
}
#endif
- request_region(dev->base_addr, 3, "de620");
+ if (!request_region(dev->base_addr, 3, "de620")) {
+ printk(KERN_ERR "io 0x%3lX, which is busy.\n", dev->base_addr);
+ return -EBUSY;
+ }
/* else, got it! */
printk(", Ethernet Address: %2.2X",
diff --git a/drivers/net/dl2k.c b/drivers/net/dl2k.c
index 8869df646b2a7..62414c0ce4af7 100644
--- a/drivers/net/dl2k.c
+++ b/drivers/net/dl2k.c
@@ -1,6 +1,6 @@
/* D-Link DL2000-based Gigabit Ethernet Adapter Linux driver */
/*
- Copyright (c) 2001 by D-Link Corporation
+ Copyright (c) 2001,2002 by D-Link Corporation
Written by Edward Peng.<edward_peng@dlink.com.tw>
Created 03-May-2001, base on Linux' sundance.c.
@@ -27,12 +27,14 @@
Added tx_coalesce paramter.
1.07 2002/01/03 Fixed miscount of RX frame error.
1.08 2002/01/17 Fixed the multicast bug.
+ 1.09 2002/03/07 Move rx-poll-now to re-fill loop.
+ Added rio_timer() to watch rx buffers.
*/
#include "dl2k.h"
static char version[] __devinitdata =
- KERN_INFO "D-Link DL2000-based linux driver v1.08 2002/01/17\n";
+ KERN_INFO "D-Link DL2000-based linux driver v1.09 2002/03/07\n";
#define MAX_UNITS 8
static int mtu[MAX_UNITS];
@@ -42,9 +44,10 @@ static char *media[MAX_UNITS];
static int tx_flow[MAX_UNITS];
static int rx_flow[MAX_UNITS];
static int copy_thresh;
-static int rx_coalesce = DEFAULT_RXC;
-static int rx_timeout = DEFAULT_RXT;
-static int tx_coalesce = DEFAULT_TXC;
+static int rx_coalesce; /* Rx frame count each interrupt */
+static int rx_timeout; /* Rx DMA wait time in 64ns increments */
+static int tx_coalesce = DEFAULT_TXC; /* HW xmit count each TxComplete [1-8] */
+
MODULE_AUTHOR ("Edward Peng");
MODULE_DESCRIPTION ("D-Link DL2000-based Gigabit Ethernet Adapter");
@@ -71,6 +74,7 @@ static int max_intrloop = 50;
static int multicast_filter_limit = 0x40;
static int rio_open (struct net_device *dev);
+static void rio_timer (unsigned long data);
static void tx_timeout (struct net_device *dev);
static void alloc_list (struct net_device *dev);
static int start_xmit (struct sk_buff *skb, struct net_device *dev);
@@ -146,6 +150,7 @@ rio_probe1 (struct pci_dev *pdev, const struct pci_device_id *ent)
np->chip_id = chip_idx;
np->pdev = pdev;
spin_lock_init (&np->lock);
+ spin_lock_init (&np->rx_lock);
/* Parse manual configuration */
np->an_enable = 1;
@@ -260,6 +265,7 @@ rio_probe1 (struct pci_dev *pdev, const struct pci_device_id *ent)
np->an_enable = 1;
mii_set_media (dev);
}
+ pci_read_config_byte(pdev, PCI_REVISION_ID, &np->pci_rev_id);
/* Reset all logic functions */
writew (GlobalReset | DMAReset | FIFOReset | NetworkReset | HostReset,
@@ -340,7 +346,7 @@ parse_eeprom (struct net_device *dev)
}
/* Check CRC */
- crc = ~ether_crc_le(256 - 4, sromdata);
+ crc = ~ether_crc_le(256 - 4, sromdata);
if (psrom->crc != crc) {
printk (KERN_ERR "%s: EEPROM data CRC error.\n", dev->name);
return -1;
@@ -421,8 +427,10 @@ rio_open (struct net_device *dev)
ioaddr + RxDMAIntCtrl);
}
/* Set RIO to poll every N*320nsec. */
- writeb (0xff, ioaddr + RxDMAPollPeriod);
+ writeb (0x20, ioaddr + RxDMAPollPeriod);
writeb (0xff, ioaddr + TxDMAPollPeriod);
+ writeb (0x30, ioaddr + RxDMABurstThresh);
+ writeb (0x30, ioaddr + RxDMAUrgentThresh);
netif_start_queue (dev);
writel (StatsEnable | RxEnable | TxEnable, ioaddr + MACCtrl);
/* VLAN supported */
@@ -445,9 +453,59 @@ rio_open (struct net_device *dev)
/* clear statistics */
get_stats (dev);
+ init_timer (&np->timer);
+ np->timer.expires = jiffies + 1*HZ;
+ np->timer.data = (unsigned long) dev;
+ np->timer.function = &rio_timer;
+ add_timer (&np->timer);
return 0;
}
+static void
+rio_timer (unsigned long data)
+{
+ struct net_device *dev = (struct net_device *)data;
+ struct netdev_private *np = dev->priv;
+ unsigned int entry;
+ int next_tick = 1*HZ;
+ unsigned long flags;
+ /* Recover rx ring exhausted error */
+ if (np->cur_rx - np->old_rx >= RX_RING_SIZE) {
+ printk(KERN_INFO "Try to recover rx ring exhausted...\n");
+ spin_lock_irqsave(&np->rx_lock, flags);
+ /* Re-allocate skbuffs to fill the descriptor ring */
+ for (; np->cur_rx - np->old_rx > 0; np->old_rx++) {
+ struct sk_buff *skb;
+ entry = np->old_rx % RX_RING_SIZE;
+ /* Dropped packets don't need to re-allocate */
+ if (np->rx_skbuff[entry] == NULL) {
+ skb = dev_alloc_skb (np->rx_buf_sz);
+ if (skb == NULL) {
+ np->rx_ring[entry].fraginfo = 0;
+ printk (KERN_INFO
+ "%s: Still unable to re-allocate Rx skbuff.#%d\n",
+ dev->name, entry);
+ break;
+ }
+ np->rx_skbuff[entry] = skb;
+ skb->dev = dev;
+ /* 16 byte align the IP header */
+ skb_reserve (skb, 2);
+ np->rx_ring[entry].fraginfo =
+ cpu_to_le64 (pci_map_single
+ (np->pdev, skb->tail, np->rx_buf_sz,
+ PCI_DMA_FROMDEVICE));
+ }
+ np->rx_ring[entry].fraginfo |=
+ cpu_to_le64 (np->rx_buf_sz) << 48;
+ np->rx_ring[entry].status = 0;
+ } /* end for */
+ spin_unlock_irqrestore (&np->rx_lock, flags);
+ } /* end if */
+ np->timer.expires = jiffies + next_tick;
+ add_timer(&np->timer);
+}
+
static void
tx_timeout (struct net_device *dev)
{
@@ -499,16 +557,14 @@ alloc_list (struct net_device *dev)
np->tx_ring[i].status = cpu_to_le64 (TFDDone);
np->tx_ring[i].next_desc = cpu_to_le64 (np->tx_ring_dma +
((i+1)%TX_RING_SIZE) *
- sizeof (struct
- netdev_desc));
+ sizeof (struct netdev_desc));
}
/* Initialize Rx descriptors */
for (i = 0; i < RX_RING_SIZE; i++) {
np->rx_ring[i].next_desc = cpu_to_le64 (np->rx_ring_dma +
((i + 1) % RX_RING_SIZE) *
- sizeof (struct
- netdev_desc));
+ sizeof (struct netdev_desc));
np->rx_ring[i].status = 0;
np->rx_ring[i].fraginfo = 0;
np->rx_skbuff[i] = 0;
@@ -529,8 +585,8 @@ alloc_list (struct net_device *dev)
skb_reserve (skb, 2); /* 16 byte align the IP header. */
/* Rubicon now supports 40 bits of addressing space. */
np->rx_ring[i].fraginfo =
- cpu_to_le64 (pci_map_single
- (np->pdev, skb->tail, np->rx_buf_sz,
+ cpu_to_le64 ( pci_map_single (
+ np->pdev, skb->tail, np->rx_buf_sz,
PCI_DMA_FROMDEVICE));
np->rx_ring[i].fraginfo |= cpu_to_le64 (np->rx_buf_sz) << 48;
}
@@ -773,6 +829,8 @@ receive_packet (struct net_device *dev)
int entry = np->cur_rx % RX_RING_SIZE;
int cnt = np->old_rx + RX_RING_SIZE - np->cur_rx;
int rx_shift;
+
+ spin_lock (&np->rx_lock);
if (np->old_rx > RX_RING_SIZE) {
rx_shift = RX_RING_SIZE;
np->old_rx -= rx_shift;
@@ -828,12 +886,14 @@ receive_packet (struct net_device *dev)
skb_put (skb, pkt_len);
}
skb->protocol = eth_type_trans (skb, dev);
-#if 0
+#if 0
/* Checksum done by hw, but csum value unavailable. */
- if (!(frame_status & (TCPError | UDPError | IPError))) {
+ if (np->pci_rev_id >= 0x0c &&
+ !(frame_status & (TCPError | UDPError | IPError))) {
skb->ip_summed = CHECKSUM_UNNECESSARY;
- }
+ }
#endif
+
netif_rx (skb);
dev->last_rx = jiffies;
}
@@ -849,9 +909,10 @@ receive_packet (struct net_device *dev)
skb = dev_alloc_skb (np->rx_buf_sz);
if (skb == NULL) {
np->rx_ring[entry].fraginfo = 0;
- printk (KERN_ERR
- "%s: Allocate Rx buffer error!",
- dev->name);
+ printk (KERN_INFO
+ "%s: receive_packet: "
+ "Unable to re-allocate Rx skbuff.#%d\n",
+ dev->name, entry);
break;
}
np->rx_skbuff[entry] = skb;
@@ -866,13 +927,12 @@ receive_packet (struct net_device *dev)
np->rx_ring[entry].fraginfo |=
cpu_to_le64 (np->rx_buf_sz) << 48;
np->rx_ring[entry].status = 0;
+ /* RxDMAPollNow */
+ writel (readl (dev->base_addr + DMACtrl) | 0x00000010,
+ dev->base_addr + DMACtrl);
}
-
- /* RxDMAPollNow */
- writel (readl (dev->base_addr + DMACtrl) | 0x00000010,
- dev->base_addr + DMACtrl);
-
DEBUG_RFD_DUMP (np, 2);
+ spin_unlock(&np->rx_lock);
return 0;
}
@@ -1006,7 +1066,7 @@ set_multicast (struct net_device *dev)
hash_table[0] = hash_table[1] = 0;
/* RxFlowcontrol DA: 01-80-C2-00-00-01. Hash index=0x39 */
- hash_table[1] |= 0x02000000;
+ hash_table[1] |= cpu_to_le32(0x02000000);
if (dev->flags & IFF_PROMISC) {
/* Receive all frames promiscuously. */
rx_mode = ReceiveAllFrames;
@@ -1020,11 +1080,16 @@ set_multicast (struct net_device *dev)
rx_mode =
ReceiveBroadcast | ReceiveMulticastHash | ReceiveUnicast;
for (i=0, mclist = dev->mc_list; mclist && i < dev->mc_count;
- i++, mclist=mclist->next) {
+ i++, mclist=mclist->next) {
+
crc = ether_crc_le (ETH_ALEN, mclist->dmi_addr);
- for (index=0, bit=0; bit<6; bit++, crc<<=1) {
- if (crc & 0x80000000) index |= 1 << bit;
- }
+
+ /* The inverted high significant 6 bits of CRC are
+ used as an index to hashtable */
+ for (index = 0, bit = 0; bit < 6; bit++)
+ if (test_bit(31 - bit, &crc))
+ set_bit(bit, &index);
+
hash_table[index / 32] |= (1 << (index % 32));
}
} else {
@@ -1094,6 +1159,7 @@ rio_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
np->old_rx);
break;
case SIOCDEVPRIVATE + 8:
+ printk("TX ring:\n");
for (i = 0; i < TX_RING_SIZE; i++) {
desc = &np->tx_ring[i];
printk
@@ -1629,7 +1695,8 @@ rio_close (struct net_device *dev)
writel (TxDisable | RxDisable | StatsDisable, ioaddr + MACCtrl);
synchronize_irq ();
free_irq (dev->irq, dev);
-
+ del_timer_sync (&np->timer);
+
/* Free all the skbuffs in the queue. */
for (i = 0; i < RX_RING_SIZE; i++) {
np->rx_ring[i].status = 0;
@@ -1679,10 +1746,10 @@ rio_remove1 (struct pci_dev *pdev)
}
static struct pci_driver rio_driver = {
- name:"dl2k",
- id_table:rio_pci_tbl,
- probe:rio_probe1,
- remove: __devexit_p(rio_remove1),
+ name: "dl2k",
+ id_table: rio_pci_tbl,
+ probe: rio_probe1,
+ remove: __devexit_p(rio_remove1),
};
static int __init
diff --git a/drivers/net/dl2k.h b/drivers/net/dl2k.h
index 0ee3bbb817b5d..656832f2ca1d6 100644
--- a/drivers/net/dl2k.h
+++ b/drivers/net/dl2k.h
@@ -1,6 +1,6 @@
/* D-Link DL2000-based Gigabit Ethernet Adapter Linux driver */
/*
- Copyright (c) 2001 by D-Link Corporation
+ Copyright (c) 2001, 2002 by D-Link Corporation
Written by Edward Peng.<edward_peng@dlink.com.tw>
Created 03-May-2001, base on Linux' sundance.c.
@@ -649,6 +649,7 @@ struct netdev_private {
dma_addr_t rx_ring_dma;
struct pci_dev *pdev;
spinlock_t lock;
+ spinlock_t rx_lock;
struct net_device_stats stats;
unsigned int rx_buf_sz; /* Based on MTU+slack. */
unsigned int speed; /* Operating speed */
@@ -664,9 +665,11 @@ struct netdev_private {
unsigned int tx_flow:1; /* Tx flow control enable */
unsigned int rx_flow:1; /* Rx flow control enable */
unsigned int phy_media:1; /* 1: fiber, 0: copper */
+ unsigned char pci_rev_id; /* PCI revision ID */
struct netdev_desc *last_tx; /* Last Tx descriptor used. */
unsigned long cur_rx, old_rx; /* Producer/consumer ring indices */
unsigned long cur_tx, old_tx;
+ struct timer_list timer;
int wake_polarity;
char name[256]; /* net device description */
u8 duplex_polarity;
diff --git a/drivers/net/e100/Makefile b/drivers/net/e100/Makefile
index 587a0f1ff5ed2..066956eac1a20 100644
--- a/drivers/net/e100/Makefile
+++ b/drivers/net/e100/Makefile
@@ -10,7 +10,7 @@
O_TARGET := e100.o
obj-y := e100_main.o e100_config.o e100_proc.o e100_phy.o \
- e100_eeprom.o
+ e100_eeprom.o e100_test.o
obj-m := $(O_TARGET)
include $(TOPDIR)/Rules.make
diff --git a/drivers/net/e100/e100.h b/drivers/net/e100/e100.h
index 4295e9c85712f..cd380d8f027c0 100644
--- a/drivers/net/e100/e100.h
+++ b/drivers/net/e100/e100.h
@@ -899,6 +899,15 @@ struct cfg_params {
int PollingMaxWork;
u32 b_params;
};
+#ifdef ETHTOOL_TEST
+struct ethtool_lpbk_data{
+ dma_addr_t dma_handle;
+ tcb_t *tcb;
+ rfd_t *rfd;
+
+};
+#endif
+
struct e100_private {
u32 flags; /* board management flags */
@@ -988,6 +997,9 @@ struct e100_private {
u32 wolopts;
u16 ip_lbytes;
#endif
+#ifdef ETHTOOL_TEST
+struct ethtool_lpbk_data loopback;
+#endif
#ifdef CONFIG_PM
u32 pci_state[16];
@@ -1028,4 +1040,23 @@ extern void e100_deisolate_driver(struct e100_private *bdp,
extern unsigned char e100_hw_reset_recover(struct e100_private *bdp,
u32 reset_cmd);
+#ifdef ETHTOOL_TEST
+
+#define ROM_TEST_FAIL 0x01
+#define REGISTER_TEST_FAIL 0x02
+#define SELF_TEST_FAIL 0x04
+#define TEST_TIMEOUT 0x08
+
+enum test_offsets {
+ E100_EEPROM_TEST_FAIL = 0,
+ E100_CHIP_TIMEOUT,
+ E100_ROM_TEST_FAIL,
+ E100_REG_TEST_FAIL,
+ E100_MAC_TEST_FAIL,
+ E100_LPBK_MAC_FAIL,
+ E100_LPBK_PHY_FAIL,
+ E100_MAX_TEST_RES
+};
+#endif
+
#endif
diff --git a/drivers/net/e100/e100_config.c b/drivers/net/e100/e100_config.c
index 2606aff405ccf..c965393db4e27 100644
--- a/drivers/net/e100/e100_config.c
+++ b/drivers/net/e100/e100_config.c
@@ -593,3 +593,102 @@ e100_config_wol(struct e100_private *bdp)
}
#endif
+#ifdef ETHTOOL_TEST
+/**
+ * e100_config_loopback_mode
+ * @bdp: atapter's private data struct
+ * @mode: loopback mode(phy/mac/none)
+ *
+ */
+unsigned char
+e100_config_loopback_mode(struct e100_private *bdp, u8 mode)
+{
+ unsigned char bc_changed = false;
+ u8 config_byte;
+
+ spin_lock_bh(&(bdp->config_lock));
+
+ switch (mode) {
+ case NO_LOOPBACK:
+ config_byte = CB_CFIG_LOOPBACK_NORMAL;
+ break;
+ case MAC_LOOPBACK:
+ config_byte = CB_CFIG_LOOPBACK_INTERNAL;
+ break;
+ case PHY_LOOPBACK:
+ config_byte = CB_CFIG_LOOPBACK_EXTERNAL;
+ break;
+ default:
+ printk(KERN_NOTICE "e100_config_loopback_mode: "
+ "Invalid argument 'mode': %d\n", mode);
+ goto exit;
+ }
+
+ if ((bdp->config[10] & CB_CFIG_LOOPBACK_MODE) != config_byte) {
+
+ bdp->config[10] &= (~CB_CFIG_LOOPBACK_MODE);
+ bdp->config[10] |= config_byte;
+ E100_CONFIG(bdp, 10);
+ bc_changed = true;
+ }
+
+exit:
+ spin_unlock_bh(&(bdp->config_lock));
+ return bc_changed;
+}
+unsigned char
+e100_config_tcb_ext_enable(struct e100_private *bdp, unsigned char enable)
+{
+ unsigned char bc_changed = false;
+
+ spin_lock_bh(&(bdp->config_lock));
+
+ if (enable) {
+ if (bdp->config[6] & CB_CFIG_EXT_TCB_DIS) {
+
+ bdp->config[6] &= (~CB_CFIG_EXT_TCB_DIS);
+ E100_CONFIG(bdp, 6);
+ bc_changed = true;
+ }
+
+ } else {
+ if (!(bdp->config[6] & CB_CFIG_EXT_TCB_DIS)) {
+
+ bdp->config[6] |= CB_CFIG_EXT_TCB_DIS;
+ E100_CONFIG(bdp, 6);
+ bc_changed = true;
+ }
+ }
+ spin_unlock_bh(&(bdp->config_lock));
+
+ return bc_changed;
+}
+unsigned char
+e100_config_dynamic_tbd(struct e100_private *bdp, unsigned char enable)
+{
+ unsigned char bc_changed = false;
+
+ spin_lock_bh(&(bdp->config_lock));
+
+ if (enable) {
+ if (!(bdp->config[7] & CB_CFIG_DYNTBD_EN)) {
+
+ bdp->config[7] |= CB_CFIG_DYNTBD_EN;
+ E100_CONFIG(bdp, 7);
+ bc_changed = true;
+ }
+
+ } else {
+ if (bdp->config[7] & CB_CFIG_DYNTBD_EN) {
+
+ bdp->config[7] &= (~CB_CFIG_DYNTBD_EN);
+ E100_CONFIG(bdp, 7);
+ bc_changed = true;
+ }
+ }
+ spin_unlock_bh(&(bdp->config_lock));
+
+ return bc_changed;
+}
+#endif
+
diff --git a/drivers/net/e100/e100_config.h b/drivers/net/e100/e100_config.h
index a46e531e564f1..6172ce27ef4b5 100644
--- a/drivers/net/e100/e100_config.h
+++ b/drivers/net/e100/e100_config.h
@@ -190,6 +190,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#define CB_CFIG_LONG_RX_OK BIT_3
+#define NO_LOOPBACK 0
+#define MAC_LOOPBACK 0x01
+#define PHY_LOOPBACK 0x02
+
/* function prototypes */
extern void e100_config_init(struct e100_private *bdp);
extern unsigned char e100_force_config(struct e100_private *bdp);
@@ -201,5 +205,8 @@ extern void e100_config_mulcast_enbl(struct e100_private *bdp,
unsigned char enable);
extern void e100_config_ifs(struct e100_private *bdp);
extern void e100_config_force_dplx(struct e100_private *bdp);
+extern u8 e100_config_loopback_mode(struct e100_private *bdp, u8 mode);
+extern u8 e100_config_dynamic_tbd(struct e100_private *bdp, u8 enable);
+extern u8 e100_config_tcb_ext_enable(struct e100_private *bdp, u8 enable);
#endif /* _E100_CONFIG_INC_ */
diff --git a/drivers/net/e100/e100_main.c b/drivers/net/e100/e100_main.c
index 3dcc137c218f1..7b8c32f351f93 100644
--- a/drivers/net/e100/e100_main.c
+++ b/drivers/net/e100/e100_main.c
@@ -147,6 +147,23 @@ static void e100_do_wol(struct pci_dev *pcid, struct e100_private *bdp);
static u16 e100_get_ip_lbytes(struct net_device *dev);
extern void e100_config_wol(struct e100_private *bdp);
#endif
+#ifdef ETHTOOL_TEST
+extern u32 e100_run_diag(struct net_device *dev, u64 *test_info, u32 flags);
+static int e100_ethtool_test(struct net_device *, struct ifreq *);
+#endif
+#ifdef ETHTOOL_GSTRINGS
+static int e100_ethtool_gstrings(struct net_device *, struct ifreq *);
+static char *test_strings[] = {
+ "E100_EEPROM_TEST_FAIL",
+ "E100_CHIP_TIMEOUT",
+ "E100_ROM_TEST_FAIL",
+ "E100_REG_TEST_FAIL",
+ "E100_MAC_TEST_FAIL",
+ "E100_LPBK_MAC_FAIL",
+ "E100_LPBK_PHY_FAIL"
+};
+
+#endif
#endif /*E100_ETHTOOL_IOCTL */
#ifdef SIOCGMIIPHY
@@ -165,7 +182,7 @@ static void e100_non_tx_background(unsigned long);
/* Global Data structures and variables */
char e100_copyright[] __devinitdata = "Copyright (c) 2002 Intel Corporation";
-#define E100_VERSION "2.0.24-pre1"
+#define E100_VERSION "2.0.25-pre1"
#define E100_FULL_DRIVER_NAME "Intel(R) PRO/100 Fast Ethernet Adapter - Loadable driver, ver "
@@ -382,6 +399,7 @@ static void e100_set_multi_exec(struct net_device *dev);
MODULE_AUTHOR("Intel Corporation, <linux.nics@intel.com>");
MODULE_DESCRIPTION(E100_FULL_DRIVER_NAME E100_VERSION);
MODULE_LICENSE("Dual BSD/GPL");
+EXPORT_NO_SYMBOLS;
E100_PARAM(TxDescriptors, "Number of transmit descriptors");
E100_PARAM(RxDescriptors, "Number of receive descriptors");
@@ -2715,8 +2733,10 @@ e100_exec_non_cu_cmd(struct e100_private *bdp, nxmit_cb_entry_t *command)
ntcb_hdr->cb_lnk_ptr = 0;
wmb();
+ if (in_interrupt())
+ return e100_delayed_exec_non_cu_cmd(bdp, command);
- if (in_interrupt() || netif_running(bdp->device))
+ if (netif_running(bdp->device) && (!bdp->driver_isolated))
return e100_delayed_exec_non_cu_cmd(bdp, command);
spin_lock_bh(&(bdp->bd_non_tx_lock));
@@ -3302,6 +3322,16 @@ e100_do_ethtool_ioctl(struct net_device *dev, struct ifreq *ifr)
rc = e100_ethtool_wol(dev, ifr);
break;
#endif
+#ifdef ETHTOOL_TEST
+ case ETHTOOL_TEST:
+ rc = e100_ethtool_test(dev, ifr);
+ break;
+#endif
+#ifdef ETHTOOL_GSTRINGS
+ case ETHTOOL_GSTRINGS:
+ rc = e100_ethtool_gstrings(dev,ifr);
+ break;
+#endif
default:
break;
} //switch
@@ -3464,6 +3494,36 @@ e100_ethtool_glink(struct net_device *dev, struct ifreq *ifr)
}
#endif
+#ifdef ETHTOOL_TEST
+static int
+e100_ethtool_test(struct net_device *dev, struct ifreq *ifr)
+{
+ struct ethtool_test *info;
+ int rc = -EFAULT;
+
+ info = kmalloc(sizeof(*info) + E100_MAX_TEST_RES * sizeof(u64),
+ GFP_ATOMIC);
+
+ if (!info)
+ return -EFAULT;
+
+ memset((void *) info, 0, sizeof(*info) +
+ E100_MAX_TEST_RES * sizeof(u64));
+
+ if (copy_from_user(info, ifr->ifr_data, sizeof(*info)))
+ goto exit;
+
+ info->flags = e100_run_diag(dev, info->data, info->flags);
+
+ if (!copy_to_user(ifr->ifr_data, info,
+ sizeof(*info) + E100_MAX_TEST_RES * sizeof(u64)))
+ rc = 0;
+exit:
+ kfree(info);
+ return rc;
+}
+#endif
+
#ifdef ETHTOOL_NWAY_RST
static int
e100_ethtool_nway_rst(struct net_device *dev, struct ifreq *ifr)
@@ -3505,7 +3565,9 @@ e100_ethtool_get_drvinfo(struct net_device *dev, struct ifreq *ifr)
#ifdef ETHTOOL_GEEPROM
info.eedump_len = (bdp->eeprom_size << 1);
#endif
-
+#ifdef ETHTOOL_TEST
+ info.testinfo_len = E100_MAX_TEST_RES;
+#endif
if (copy_to_user(ifr->ifr_data, &info, sizeof (info)))
return -EFAULT;
@@ -3738,6 +3800,51 @@ e100_ethtool_wol(struct net_device *dev, struct ifreq *ifr)
}
#endif
+
+#ifdef ETHTOOL_GSTRINGS
+static int e100_ethtool_gstrings(struct net_device *dev, struct ifreq *ifr)
+{
+ struct ethtool_gstrings info;
+ char *strings = NULL;
+ char *usr_strings;
+ int i;
+
+ memset((void *) &info, 0, sizeof(info));
+
+ usr_strings = (u8 *) (ifr->ifr_data +
+ offsetof(struct ethtool_gstrings, data));
+
+ if (copy_from_user(&info, ifr->ifr_data, sizeof (info)))
+ return -EFAULT;
+
+ switch (info.string_set) {
+ case ETH_SS_TEST:
+ if (info.len > E100_MAX_TEST_RES)
+ info.len = E100_MAX_TEST_RES;
+ strings = kmalloc(info.len * ETH_GSTRING_LEN, GFP_ATOMIC);
+ if (!strings)
+ return -EFAULT;
+ memset(strings, 0, info.len * ETH_GSTRING_LEN);
+
+ for (i = 0; i < info.len; i++) {
+ sprintf(strings + i * ETH_GSTRING_LEN, "%-31s",
+ test_strings[i]);
+ }
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ if (copy_to_user(ifr->ifr_data, &info, sizeof (info)))
+ return -EFAULT;
+
+ if (copy_to_user(usr_strings, strings, info.len * ETH_GSTRING_LEN))
+ return -EFAULT;
+
+ kfree(strings);
+ return 0;
+}
+#endif
#endif /*E100_ETHTOOL_IOCTL */
#ifdef E100_MII_IOCTL
diff --git a/drivers/net/e100/e100_test.c b/drivers/net/e100/e100_test.c
new file mode 100644
index 0000000000000..77918c9f8f9c7
--- /dev/null
+++ b/drivers/net/e100/e100_test.c
@@ -0,0 +1,467 @@
+/*******************************************************************************
+
+This software program is available to you under a choice of one of two
+licenses. You may choose to be licensed under either the GNU General Public
+License 2.0, June 1991, available at http://www.fsf.org/copyleft/gpl.html,
+or the Intel BSD + Patent License, the text of which follows:
+
+Recipient has requested a license and Intel Corporation ("Intel") is willing
+to grant a license for the software entitled Linux Base Driver for the
+Intel(R) PRO/100 Family of Adapters (e100) (the "Software") being provided
+by Intel Corporation. The following definitions apply to this license:
+
+"Licensed Patents" means patent claims licensable by Intel Corporation which
+are necessarily infringed by the use of sale of the Software alone or when
+combined with the operating system referred to below.
+
+"Recipient" means the party to whom Intel delivers this Software.
+
+"Licensee" means Recipient and those third parties that receive a license to
+any operating system available under the GNU General Public License 2.0 or
+later.
+
+Copyright (c) 1999 - 2002 Intel Corporation.
+All rights reserved.
+
+The license is provided to Recipient and Recipient's Licensees under the
+following terms.
+
+Redistribution and use in source and binary forms of the Software, with or
+without modification, are permitted provided that the following conditions
+are met:
+
+Redistributions of source code of the Software may retain the above
+copyright notice, this list of conditions and the following disclaimer.
+
+Redistributions in binary form of the Software may reproduce the above
+copyright notice, this list of conditions and the following disclaimer in
+the documentation and/or materials provided with the distribution.
+
+Neither the name of Intel Corporation nor the names of its contributors
+shall be used to endorse or promote products derived from this Software
+without specific prior written permission.
+
+Intel hereby grants Recipient and Licensees a non-exclusive, worldwide,
+royalty-free patent license under Licensed Patents to make, use, sell, offer
+to sell, import and otherwise transfer the Software, if any, in source code
+and object code form. This license shall include changes to the Software
+that are error corrections or other minor changes to the Software that do
+not add functionality or features when the Software is incorporated in any
+version of an operating system that has been distributed under the GNU
+General Public License 2.0 or later. This patent license shall apply to the
+combination of the Software and any operating system licensed under the GNU
+General Public License 2.0 or later if, at the time Intel provides the
+Software to Recipient, such addition of the Software to the then publicly
+available versions of such operating systems available under the GNU General
+Public License 2.0 or later (whether in gold, beta or alpha form) causes
+such combination to be covered by the Licensed Patents. The patent license
+shall not apply to any other combinations which include the Software. NO
+hardware per se is licensed hereunder.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MECHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR IT CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ANY LOSS OF USE; DATA, OR PROFITS; OR BUSINESS INTERUPTION) HOWEVER CAUSED
+AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY OR
+TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*******************************************************************************/
+#include "e100.h"
+#include "e100_config.h"
+#ifdef ETHTOOL_TEST
+
+extern u16 e100_eeprom_read(struct e100_private *, u16);
+extern int e100_wait_exec_cmplx(struct e100_private *, u32,u8);
+extern void e100_phy_reset(struct e100_private *bdp);
+
+static u8 e100_diag_selftest(struct net_device *);
+static u8 e100_diag_eeprom(struct net_device *);
+static u8 e100_diag_loopback(struct net_device *);
+
+static u8 e100_diag_one_loopback (struct net_device *, u8);
+static u8 e100_diag_rcv_loopback_pkt(struct e100_private *);
+static void e100_diag_config_loopback(struct e100_private *, u8, u8, u8 *,u8 *);
+static u8 e100_diag_loopback_alloc(struct e100_private *);
+static void e100_diag_loopback_cu_ru_exec(struct e100_private *);
+static u8 e100_diag_check_pkt(u8 *);
+static void e100_diag_loopback_free(struct e100_private *);
+
+#define LB_PACKET_SIZE 1500
+
+/**
+ * e100_run_diag - main test execution handler - checks mask of requests and calls the diag routines
+ * @dev: atapter's net device data struct
+ * @test_info: array with test request mask also used to store test results
+ *
+ * RETURNS: updated flags field of struct ethtool_test
+ */
+u32
+e100_run_diag(struct net_device *dev, u64 *test_info, u32 flags)
+{
+ struct e100_private* bdp = dev->priv;
+ u8 test_result = true;
+
+ e100_isolate_driver(bdp);
+
+ if (flags & ETH_TEST_FL_OFFLINE) {
+ u8 fail_mask;
+
+ fail_mask = e100_diag_selftest(dev);
+ if (fail_mask) {
+ test_result = false;
+ if (fail_mask & REGISTER_TEST_FAIL)
+ test_info [E100_REG_TEST_FAIL] = true;
+ if (fail_mask & ROM_TEST_FAIL)
+ test_info [E100_ROM_TEST_FAIL] = true;
+ if (fail_mask & SELF_TEST_FAIL)
+ test_info [E100_MAC_TEST_FAIL] = true;
+ if (fail_mask & TEST_TIMEOUT)
+ test_info [E100_CHIP_TIMEOUT] = true;
+ }
+
+ fail_mask = e100_diag_loopback(dev);
+ if (fail_mask) {
+ test_result = false;
+ if (fail_mask & PHY_LOOPBACK)
+ test_info [E100_LPBK_PHY_FAIL] = true;
+ if (fail_mask & MAC_LOOPBACK)
+ test_info [E100_LPBK_MAC_FAIL] = true;
+ }
+ }
+
+ if (!e100_diag_eeprom(dev)) {
+ test_result = false;
+ test_info [E100_EEPROM_TEST_FAIL] = true;
+ }
+
+ /* fully recover only if the device is open*/
+ if (netif_running(dev)) {
+ e100_deisolate_driver(bdp, true, false);
+ } else {
+ e100_deisolate_driver(bdp, false, false);
+ }
+ /*Let card recover from the test*/
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(HZ * 2);
+
+ return flags | (test_result ? 0 : ETH_TEST_FL_FAILED);
+}
+
+/**
+ * e100_diag_selftest - run hardware selftest
+ * @dev: atapter's net device data struct
+ */
+static u8
+e100_diag_selftest(struct net_device *dev)
+{
+ struct e100_private *bdp = dev->priv;
+ u32 st_timeout, st_result;
+ u8 retval = 0;
+
+ if (!e100_selftest(bdp, &st_timeout, &st_result)) {
+ if (!st_timeout) {
+ if (st_result & CB_SELFTEST_REGISTER_BIT)
+ retval |= REGISTER_TEST_FAIL;
+ if (st_result & CB_SELFTEST_DIAG_BIT)
+ retval |= SELF_TEST_FAIL;
+ if (st_result & CB_SELFTEST_ROM_BIT)
+ retval |= ROM_TEST_FAIL;
+ } else {
+ retval = TEST_TIMEOUT;
+ }
+ }
+
+ e100_hw_reset_recover(bdp,PORT_SOFTWARE_RESET);
+
+ return retval;
+}
+
+/**
+ * e100_diag_eeprom - validate eeprom checksum correctness
+ * @dev: atapter's net device data struct
+ *
+ */
+static u8
+e100_diag_eeprom (struct net_device *dev)
+{
+ struct e100_private *bdp = dev->priv;
+ u16 i, eeprom_sum, eeprom_actual_csm;
+
+ for (i = 0, eeprom_sum = 0; i < (bdp->eeprom_size - 1); i++) {
+ eeprom_sum += e100_eeprom_read(bdp, i);
+ }
+
+ eeprom_actual_csm = e100_eeprom_read(bdp, bdp->eeprom_size - 1);
+
+ if (eeprom_actual_csm == (u16)(EEPROM_SUM - eeprom_sum)) {
+ return true;
+ }
+
+ return false;
+}
+
+/**
+ * e100_diag_loopback - performs loopback test
+ * @dev: atapter's net device data struct
+ */
+static u8
+e100_diag_loopback (struct net_device *dev)
+{
+ u8 rc = 0;
+
+ if (!e100_diag_one_loopback(dev, PHY_LOOPBACK)) {
+ rc |= PHY_LOOPBACK;
+ }
+
+ if (!e100_diag_one_loopback(dev, MAC_LOOPBACK)) {
+ rc |= MAC_LOOPBACK;
+ }
+
+ return rc;
+}
+
+/**
+ * e100_diag_loopback - performs loopback test
+ * @dev: atapter's net device data struct
+ * @mode: lopback test type
+ */
+static u8
+e100_diag_one_loopback (struct net_device *dev, u8 mode)
+{
+ struct e100_private *bdp = dev->priv;
+ u8 res = false;
+ u8 saved_dynamic_tbd = false;
+ u8 saved_extended_tcb = false;
+
+ if (!e100_diag_loopback_alloc(bdp))
+ return false;
+
+ /* change the config block to standard tcb and the correct loopback */
+ e100_diag_config_loopback(bdp, true, mode,
+ &saved_extended_tcb, &saved_dynamic_tbd);
+
+ e100_diag_loopback_cu_ru_exec(bdp);
+
+ if (e100_diag_rcv_loopback_pkt(bdp)) {
+ res = true;
+ }
+
+ e100_diag_loopback_free(bdp);
+
+ /* change the config block to previous tcb mode and the no loopback */
+ e100_diag_config_loopback(bdp, false, mode,
+ &saved_extended_tcb, &saved_dynamic_tbd);
+ return res;
+}
+
+/**
+ * e100_diag_config_loopback - setup/clear loopback before/after lpbk test
+ * @bdp: atapter's private data struct
+ * @set_loopback: true if the function is called to set lb
+ * @loopback_mode: the loopback mode(MAC or PHY)
+ * @tcb_extended: true if need to set extended tcb mode after clean loopback
+ * @dynamic_tbd: true if needed to set dynamic tbd mode after clean loopback
+ *
+ */
+void
+e100_diag_config_loopback(struct e100_private* bdp,
+ u8 set_loopback,
+ u8 loopback_mode,
+ u8* tcb_extended,
+ u8* dynamic_tbd)
+{
+ /* if set_loopback == true - we want to clear tcb_extended/dynamic_tbd.
+ * the previous values are saved in the params tcb_extended/dynamic_tbd
+ * if set_loopback == false - we want to restore previous value.
+ */
+ if (set_loopback || (*tcb_extended))
+ *tcb_extended = e100_config_tcb_ext_enable(bdp,*tcb_extended);
+
+ if (set_loopback || (*dynamic_tbd))
+ *dynamic_tbd = e100_config_dynamic_tbd(bdp,*dynamic_tbd);
+
+ if (set_loopback) {
+ e100_config_loopback_mode(bdp,loopback_mode);
+ } else {
+ e100_config_loopback_mode(bdp,NO_LOOPBACK);
+ }
+
+ e100_config(bdp);
+
+ if (loopback_mode == PHY_LOOPBACK) {
+ unsigned long expires = jiffies + HZ * 5;
+
+ if (set_loopback)
+ e100_phy_reset(bdp);
+
+ /* wait up to 5 secs for PHY loopback ON/OFF to take effect */
+ while ((e100_get_link_state(bdp) != set_loopback) &&
+ time_before(jiffies, expires)) {
+ yield();
+ }
+ } else { /* For MAC loopback wait 500 msec to take effect */
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(HZ / 2);
+ }
+}
+
+/**
+ * e100_diag_loopback_alloc - alloc & initate tcb and rfd for the loopback
+ * @bdp: atapter's private data struct
+ *
+ */
+static u8
+e100_diag_loopback_alloc(struct e100_private *bdp)
+{
+ dma_addr_t dma_handle;
+ tcb_t *tcb;
+ rfd_t *rfd;
+ tbd_t *tbd;
+
+ tcb = pci_alloc_consistent(bdp->pdev,
+ (sizeof (tcb_t) + sizeof (tbd_t) +
+ LB_PACKET_SIZE),
+ &dma_handle);
+ if (tcb == NULL)
+ return false;
+
+ memset(tcb, 0x00, sizeof (tcb_t) + LB_PACKET_SIZE);
+ tcb->tcb_phys = dma_handle;
+ tcb->tcb_hdr.cb_status = 0;
+ tcb->tcb_hdr.cb_cmd =
+ cpu_to_le16(CB_EL_BIT | CB_TRANSMIT | CB_TX_SF_BIT);
+ tcb->tcb_hdr.cb_lnk_ptr = cpu_to_le32(tcb->tcb_phys);
+ tcb->tcb_tbd_ptr = cpu_to_le32(0xffffffff);
+ tcb->tcb_cnt = 0;
+ tcb->tcb_thrshld = bdp->tx_thld;
+ tcb->tcb_tbd_num = 1;
+ tcb->tcb_tbd_ptr = cpu_to_le32(tcb->tcb_phys + sizeof (tcb_t));
+ tbd = (tbd_t *) ((u8 *) tcb + sizeof (tcb_t));
+ tbd->tbd_buf_addr =
+ cpu_to_le32(le32_to_cpu(tcb->tcb_tbd_ptr) + sizeof (tbd_t));
+ tbd->tbd_buf_cnt = __constant_cpu_to_le16(1024);
+ memset((void *) ((u8 *) tbd + sizeof (tbd_t)), 0xFF, 1024);
+ memset((void *) ((u8 *) tbd + sizeof (tbd_t) + 512), 0xBA, 512);
+ wmb();
+ rfd = pci_alloc_consistent(bdp->pdev, sizeof (rfd_t), &dma_handle);
+
+ if (rfd == NULL) {
+ pci_free_consistent(bdp->pdev,
+ sizeof (tcb_t) + sizeof (tbd_t) +
+ LB_PACKET_SIZE, tcb, tcb->tcb_phys);
+ return false;
+ }
+
+ memset(rfd, 0x00, sizeof (rfd_t));
+
+ /* init all fields in rfd */
+ rfd->rfd_header.cb_status = 0;
+ rfd->rfd_header.cb_cmd = cpu_to_le16(RFD_EL_BIT);
+ rfd->rfd_act_cnt = 0;
+ rfd->rfd_sz = cpu_to_le16(ETH_FRAME_LEN + CHKSUM_SIZE);
+ bdp->loopback.dma_handle = dma_handle;
+ bdp->loopback.tcb = tcb;
+ bdp->loopback.rfd = rfd;
+ wmb();
+ return true;
+}
+
+/**
+ * e100_diag_loopback_cu_ru_exec - activates cu and ru to send & receive the pkt
+ * @bdp: atapter's private data struct
+ *
+ */
+static void
+e100_diag_loopback_cu_ru_exec(struct e100_private *bdp)
+{
+ /*load CU & RU base */
+ if (!e100_wait_exec_cmplx(bdp, 0, SCB_CUC_LOAD_BASE))
+ printk("@@@ SCB_CUC_LOAD_BASE failed\n");
+ if(!e100_wait_exec_cmplx(bdp, 0, SCB_RUC_LOAD_BASE))
+ printk("@@@ SCB_RUC_LOAD_BASE failed!\n");
+ if(!e100_wait_exec_cmplx(bdp, bdp->loopback.dma_handle, SCB_RUC_START))
+ printk("@@@ SCB_RUC_START failed!\n");
+
+ bdp->next_cu_cmd = START_WAIT;
+ e100_start_cu(bdp, bdp->loopback.tcb);
+ bdp->last_tcb = NULL;
+ rmb();
+}
+/**
+ * e100_diag_check_pkt - checks if a given packet is a loopback packet
+ * @bdp: atapter's private data struct
+ *
+ * Returns true if OK false otherwise.
+ */
+static u8
+e100_diag_check_pkt(u8 *datap)
+{
+ if( (*datap)==0xFF) {
+ if(*(datap + 600) == 0xBA) {
+ return true;
+ }
+ }
+ return false;
+}
+
+/**
+ * e100_diag_rcv_loopback_pkt - waits for receive and checks lpbk packet
+ * @bdp: atapter's private data struct
+ *
+ * Returns true if OK false otherwise.
+ */
+static u8
+e100_diag_rcv_loopback_pkt(struct e100_private* bdp)
+{
+ rfd_t *rfdp;
+ u16 rfd_status;
+ unsigned long expires = jiffies + HZ * 2;
+
+ rfdp =bdp->loopback.rfd;
+
+ rfd_status = le16_to_cpu(rfdp->rfd_header.cb_status);
+
+ while (!(rfd_status & RFD_STATUS_COMPLETE)) {
+ if (time_before(jiffies, expires)) {
+ yield();
+ rmb();
+ rfd_status = le16_to_cpu(rfdp->rfd_header.cb_status);
+ } else {
+ break;
+ }
+ }
+
+ if (rfd_status & RFD_STATUS_COMPLETE)
+ return e100_diag_check_pkt(((u8 *)rfdp+bdp->rfd_size));
+ else
+ return false;
+}
+
+/**
+ * e100_diag_loopback_free - free data allocated for loopback pkt send/receive
+ * @bdp: atapter's private data struct
+ *
+ */
+static void
+e100_diag_loopback_free (struct e100_private *bdp)
+{
+ pci_free_consistent(bdp->pdev,
+ sizeof(tcb_t) + sizeof(tbd_t) + LB_PACKET_SIZE,
+ bdp->loopback.tcb, bdp->loopback.tcb->tcb_phys);
+
+ pci_free_consistent(bdp->pdev, sizeof(rfd_t), bdp->loopback.rfd,
+ bdp->loopback.dma_handle);
+}
+
+#endif
+
+
+
+
+
+
+
+
diff --git a/drivers/net/e1000/LICENSE b/drivers/net/e1000/LICENSE
index 8dbf9d9ee04ce..ab83d56a34712 100644
--- a/drivers/net/e1000/LICENSE
+++ b/drivers/net/e1000/LICENSE
@@ -1,8 +1,7 @@
This software program is available to you under a choice of one of two
licenses. You may choose to be licensed under either the GNU General Public
-License (GPL) Version 2, June 1991, available at
-http://www.fsf.org/copyleft/gpl.html, or the Intel BSD + Patent License, the
-text of which follows:
+License 2.0, June 1991, available at http://www.fsf.org/copyleft/gpl.html,
+or the Intel BSD + Patent License, the text of which follows:
Recipient has requested a license and Intel Corporation ("Intel") is willing
to grant a license for the software entitled Linux Base Driver for the
@@ -16,7 +15,7 @@ combined with the operating system referred to below.
"Recipient" means the party to whom Intel delivers this Software.
"Licensee" means Recipient and those third parties that receive a license to
-any operating system available under the GNU Public License version 2.0 or
+any operating system available under the GNU General Public License 2.0 or
later.
Copyright (c) 1999 - 2002 Intel Corporation.
@@ -49,10 +48,10 @@ not add functionality or features when the Software is incorporated in any
version of an operating system that has been distributed under the GNU
General Public License 2.0 or later. This patent license shall apply to the
combination of the Software and any operating system licensed under the GNU
-Public License version 2.0 or later if, at the time Intel provides the
+General Public License 2.0 or later if, at the time Intel provides the
Software to Recipient, such addition of the Software to the then publicly
-available versions of such operating systems available under the GNU Public
-License version 2.0 or later (whether in gold, beta or alpha form) causes
+available versions of such operating systems available under the GNU General
+Public License 2.0 or later (whether in gold, beta or alpha form) causes
such combination to be covered by the Licensed Patents. The patent license
shall not apply to any other combinations which include the Software. NO
hardware per se is licensed hereunder.
diff --git a/drivers/net/e1000/Makefile b/drivers/net/e1000/Makefile
index 6fc1468d012b8..0e99ae2369e07 100644
--- a/drivers/net/e1000/Makefile
+++ b/drivers/net/e1000/Makefile
@@ -9,8 +9,7 @@
O_TARGET := e1000.o
-obj-y := e1000_main.o e1000_mac.o e1000_phy.o \
- e1000_ethtool.o e1000_param.o e1000_proc.o
+obj-y := e1000_main.o e1000_hw.o e1000_ethtool.o e1000_param.o e1000_proc.o
obj-m := $(O_TARGET)
include $(TOPDIR)/Rules.make
diff --git a/drivers/net/e1000/e1000.h b/drivers/net/e1000/e1000.h
index 9a09b351e5491..5424cca61c849 100644
--- a/drivers/net/e1000/e1000.h
+++ b/drivers/net/e1000/e1000.h
@@ -2,9 +2,8 @@
This software program is available to you under a choice of one of two
licenses. You may choose to be licensed under either the GNU General Public
- License (GPL) Version 2, June 1991, available at
- http://www.fsf.org/copyleft/gpl.html, or the Intel BSD + Patent License, the
- text of which follows:
+ License 2.0, June 1991, available at http://www.fsf.org/copyleft/gpl.html,
+ or the Intel BSD + Patent License, the text of which follows:
Recipient has requested a license and Intel Corporation ("Intel") is willing
to grant a license for the software entitled Linux Base Driver for the
@@ -18,7 +17,7 @@
"Recipient" means the party to whom Intel delivers this Software.
"Licensee" means Recipient and those third parties that receive a license to
- any operating system available under the GNU Public License version 2.0 or
+ any operating system available under the GNU General Public License 2.0 or
later.
Copyright (c) 1999 - 2002 Intel Corporation.
@@ -51,10 +50,10 @@
version of an operating system that has been distributed under the GNU
General Public License 2.0 or later. This patent license shall apply to the
combination of the Software and any operating system licensed under the GNU
- Public License version 2.0 or later if, at the time Intel provides the
+ General Public License 2.0 or later if, at the time Intel provides the
Software to Recipient, such addition of the Software to the then publicly
- available versions of such operating systems available under the GNU Public
- License version 2.0 or later (whether in gold, beta or alpha form) causes
+ available versions of such operating systems available under the GNU General
+ Public License 2.0 or later (whether in gold, beta or alpha form) causes
such combination to be covered by the Licensed Patents. The patent license
shall not apply to any other combinations which include the Software. NO
hardware per se is licensed hereunder.
@@ -109,11 +108,14 @@
#include <net/pkt_sched.h>
#include <linux/list.h>
#include <asm/uaccess.h>
+#include <linux/ethtool.h>
+#ifdef NETIF_F_HW_VLAN_TX
+#include <linux/if_vlan.h>
+#endif
struct e1000_adapter;
-#include "e1000_mac.h"
-#include "e1000_phy.h"
+#include "e1000_hw.h"
#define BAR_0 0
@@ -138,7 +140,9 @@ struct e1000_adapter;
#define E1000_RXBUFFER_16384 16384
/* How many Tx Descriptors do we need to call netif_wake_queue ? */
-#define E1000_TX_QUEUE_WAKE 16
+#define E1000_TX_QUEUE_WAKE 16
+/* How many Rx Buffers do we bundle into one write to the hardware ? */
+#define E1000_RX_BUFFER_WRITE 16
#define E1000_JUMBO_PBA 0x00000028
#define E1000_DEFAULT_PBA 0x00000030
@@ -163,10 +167,6 @@ struct e1000_desc_ring {
unsigned int size;
/* number of descriptors in the ring */
unsigned int count;
- /* (atomic) number of desc with no buffer */
- atomic_t unused;
- /* number of desc with no buffer */
- unsigned int unused_count;
/* next descriptor to associate a buffer with */
unsigned int next_to_use;
/* next descriptor to check for DD status bit */
@@ -175,14 +175,13 @@ struct e1000_desc_ring {
struct e1000_buffer *buffer_info;
};
-#define E1000_RX_DESC(ring, i) \
- (&(((struct e1000_rx_desc *)((ring).desc))[i]))
-
-#define E1000_TX_DESC(ring, i) \
- (&(((struct e1000_tx_desc *)((ring).desc))[i]))
+#define E1000_DESC_UNUSED(R) \
+((((R)->next_to_clean + (R)->count) - ((R)->next_to_use + 1)) % ((R)->count))
-#define E1000_CONTEXT_DESC(ring, i) \
- (&(((struct e1000_context_desc *)((ring).desc))[i]))
+#define E1000_GET_DESC(R, i, type) (&(((struct type *)((R).desc))[i]))
+#define E1000_RX_DESC(R, i) E1000_GET_DESC(R, i, e1000_rx_desc)
+#define E1000_TX_DESC(R, i) E1000_GET_DESC(R, i, e1000_tx_desc)
+#define E1000_CONTEXT_DESC(R, i) E1000_GET_DESC(R, i, e1000_context_desc)
/* board specific private data structure */
@@ -192,6 +191,9 @@ struct e1000_adapter {
#ifdef CONFIG_PROC_FS
struct list_head proc_list_head;
#endif
+#ifdef NETIF_F_HW_VLAN_TX
+ struct vlan_group *vlgrp;
+#endif
char *id_string;
uint32_t bd_number;
uint32_t rx_buffer_len;
@@ -201,28 +203,29 @@ struct e1000_adapter {
uint16_t link_duplex;
spinlock_t stats_lock;
atomic_t irq_sem;
- boolean_t rx_csum;
/* TX */
struct e1000_desc_ring tx_ring;
unsigned long trans_finish;
- uint32_t tx_int_delay;
+ spinlock_t tx_lock;
uint32_t txd_cmd;
+ int max_data_per_txd;
/* RX */
struct e1000_desc_ring rx_ring;
uint64_t hw_csum_err;
uint64_t hw_csum_good;
uint32_t rx_int_delay;
+ boolean_t rx_csum;
/* OS defined structs */
struct net_device *netdev;
struct pci_dev *pdev;
struct net_device_stats net_stats;
- /* structs defined in e1000_mac.h or e1000_phy.h */
- struct e1000_shared_adapter shared;
- struct e1000_shared_stats stats;
+ /* structs defined in e1000_hw.h */
+ struct e1000_hw hw;
+ struct e1000_hw_stats stats;
struct e1000_phy_info phy_info;
struct e1000_phy_stats phy_stats;
};
diff --git a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c
index 2d609aed890f2..7ed6f8ebe931d 100644
--- a/drivers/net/e1000/e1000_ethtool.c
+++ b/drivers/net/e1000/e1000_ethtool.c
@@ -2,9 +2,8 @@
This software program is available to you under a choice of one of two
licenses. You may choose to be licensed under either the GNU General Public
- License (GPL) Version 2, June 1991, available at
- http://www.fsf.org/copyleft/gpl.html, or the Intel BSD + Patent License, the
- text of which follows:
+ License 2.0, June 1991, available at http://www.fsf.org/copyleft/gpl.html,
+ or the Intel BSD + Patent License, the text of which follows:
Recipient has requested a license and Intel Corporation ("Intel") is willing
to grant a license for the software entitled Linux Base Driver for the
@@ -18,7 +17,7 @@
"Recipient" means the party to whom Intel delivers this Software.
"Licensee" means Recipient and those third parties that receive a license to
- any operating system available under the GNU Public License version 2.0 or
+ any operating system available under the GNU General Public License 2.0 or
later.
Copyright (c) 1999 - 2002 Intel Corporation.
@@ -51,10 +50,10 @@
version of an operating system that has been distributed under the GNU
General Public License 2.0 or later. This patent license shall apply to the
combination of the Software and any operating system licensed under the GNU
- Public License version 2.0 or later if, at the time Intel provides the
+ General Public License 2.0 or later if, at the time Intel provides the
Software to Recipient, such addition of the Software to the then publicly
- available versions of such operating systems available under the GNU Public
- License version 2.0 or later (whether in gold, beta or alpha form) causes
+ available versions of such operating systems available under the GNU General
+ Public License 2.0 or later (whether in gold, beta or alpha form) causes
such combination to be covered by the Licensed Patents. The patent license
shall not apply to any other combinations which include the Software. NO
hardware per se is licensed hereunder.
@@ -89,9 +88,9 @@ extern void e1000_enable_WOL(struct e1000_adapter *adapter);
static void
e1000_ethtool_gset(struct e1000_adapter *adapter, struct ethtool_cmd *ecmd)
{
- struct e1000_shared_adapter *shared = &adapter->shared;
+ struct e1000_hw *hw = &adapter->hw;
- if(shared->media_type == e1000_media_type_copper) {
+ if(hw->media_type == e1000_media_type_copper) {
ecmd->supported = (SUPPORTED_10baseT_Half |
SUPPORTED_10baseT_Full |
@@ -103,18 +102,18 @@ e1000_ethtool_gset(struct e1000_adapter *adapter, struct ethtool_cmd *ecmd)
ecmd->advertising = ADVERTISED_TP;
- if(shared->autoneg == 1) {
+ if(hw->autoneg == 1) {
ecmd->advertising |= ADVERTISED_Autoneg;
/* the e1000 autoneg seems to match ethtool nicely */
- ecmd->advertising |= shared->autoneg_advertised;
+ ecmd->advertising |= hw->autoneg_advertised;
}
ecmd->port = PORT_TP;
- ecmd->phy_address = shared->phy_addr;
+ ecmd->phy_address = hw->phy_addr;
- if(shared->mac_type == e1000_82543)
+ if(hw->mac_type == e1000_82543)
ecmd->transceiver = XCVR_EXTERNAL;
else
ecmd->transceiver = XCVR_INTERNAL;
@@ -129,13 +128,12 @@ e1000_ethtool_gset(struct e1000_adapter *adapter, struct ethtool_cmd *ecmd)
SUPPORTED_Autoneg);
ecmd->port = PORT_FIBRE;
-
ecmd->transceiver = XCVR_EXTERNAL;
}
if(netif_carrier_ok(adapter->netdev)) {
- e1000_get_speed_and_duplex(shared, &adapter->link_speed,
+ e1000_get_speed_and_duplex(hw, &adapter->link_speed,
&adapter->link_duplex);
ecmd->speed = adapter->link_speed;
@@ -151,37 +149,35 @@ e1000_ethtool_gset(struct e1000_adapter *adapter, struct ethtool_cmd *ecmd)
ecmd->duplex = -1;
}
- ecmd->autoneg = (shared->autoneg ? AUTONEG_ENABLE : AUTONEG_DISABLE);
-
- return;
+ ecmd->autoneg = (hw->autoneg ? AUTONEG_ENABLE : AUTONEG_DISABLE);
}
static int
e1000_ethtool_sset(struct e1000_adapter *adapter, struct ethtool_cmd *ecmd)
{
- struct e1000_shared_adapter *shared = &adapter->shared;
+ struct e1000_hw *hw = &adapter->hw;
if(ecmd->autoneg == AUTONEG_ENABLE) {
- shared->autoneg = 1;
- shared->autoneg_advertised = (ecmd->advertising & 0x002F);
+ hw->autoneg = 1;
+ hw->autoneg_advertised = (ecmd->advertising & 0x002F);
} else {
- shared->autoneg = 0;
+ hw->autoneg = 0;
switch(ecmd->speed + ecmd->duplex) {
case SPEED_10 + DUPLEX_HALF:
- shared->forced_speed_duplex = e1000_10_half;
+ hw->forced_speed_duplex = e1000_10_half;
break;
case SPEED_10 + DUPLEX_FULL:
- shared->forced_speed_duplex = e1000_10_full;
+ hw->forced_speed_duplex = e1000_10_full;
break;
case SPEED_100 + DUPLEX_HALF:
- shared->forced_speed_duplex = e1000_100_half;
+ hw->forced_speed_duplex = e1000_100_half;
break;
case SPEED_100 + DUPLEX_FULL:
- shared->forced_speed_duplex = e1000_100_full;
+ hw->forced_speed_duplex = e1000_100_full;
break;
case SPEED_1000 + DUPLEX_FULL:
- shared->autoneg = 1;
- shared->autoneg_advertised = ADVERTISE_1000_FULL;
+ hw->autoneg = 1;
+ hw->autoneg_advertised = ADVERTISE_1000_FULL;
break;
case SPEED_1000 + DUPLEX_HALF: /* not supported */
default:
@@ -198,9 +194,13 @@ e1000_ethtool_sset(struct e1000_adapter *adapter, struct ethtool_cmd *ecmd)
}
static inline int
-e1000_eeprom_size(struct e1000_shared_adapter *shared)
+e1000_eeprom_size(struct e1000_hw *hw)
{
- return 128;
+ if((hw->mac_type > e1000_82544) &&
+ (E1000_READ_REG(hw, EECD) & E1000_EECD_SIZE))
+ return 512;
+ else
+ return 128;
}
static void
@@ -211,36 +211,33 @@ e1000_ethtool_gdrvinfo(struct e1000_adapter *adapter,
strncpy(drvinfo->version, e1000_driver_version, 32);
strncpy(drvinfo->fw_version, "", 32);
strncpy(drvinfo->bus_info, adapter->pdev->slot_name, 32);
- drvinfo->eedump_len = e1000_eeprom_size(&adapter->shared);
- return;
+ drvinfo->eedump_len = e1000_eeprom_size(&adapter->hw);
}
static void
e1000_ethtool_geeprom(struct e1000_adapter *adapter,
struct ethtool_eeprom *eeprom, uint16_t *eeprom_buff)
{
- struct e1000_shared_adapter *shared = &adapter->shared;
+ struct e1000_hw *hw = &adapter->hw;
int i, max_len;
- eeprom->magic = shared->vendor_id | (shared->device_id << 16);
+ eeprom->magic = hw->vendor_id | (hw->device_id << 16);
- max_len = e1000_eeprom_size(shared);
+ max_len = e1000_eeprom_size(hw);
if ((eeprom->offset + eeprom->len) > max_len)
eeprom->len = (max_len - eeprom->offset);
for(i = 0; i < max_len; i++)
- eeprom_buff[i] = e1000_read_eeprom(&adapter->shared, i);
-
- return;
+ e1000_read_eeprom(&adapter->hw, i, &eeprom_buff[i]);
}
static void
e1000_ethtool_gwol(struct e1000_adapter *adapter, struct ethtool_wolinfo *wol)
{
- struct e1000_shared_adapter *shared = &adapter->shared;
+ struct e1000_hw *hw = &adapter->hw;
- if(shared->mac_type < e1000_82544) {
+ if(hw->mac_type < e1000_82544) {
wol->supported = 0;
wol->wolopts = 0;
return;
@@ -260,17 +257,15 @@ e1000_ethtool_gwol(struct e1000_adapter *adapter, struct ethtool_wolinfo *wol)
wol->wolopts |= WAKE_BCAST;
if(adapter->wol & E1000_WUFC_MAG)
wol->wolopts |= WAKE_MAGIC;
-
- return;
}
static int
e1000_ethtool_swol(struct e1000_adapter *adapter, struct ethtool_wolinfo *wol)
{
- struct e1000_shared_adapter *shared = &adapter->shared;
+ struct e1000_hw *hw = &adapter->hw;
- if(shared->mac_type < e1000_82544)
- return wol->wolopts == 0 ? 0 : -EOPNOTSUPP;
+ if(hw->mac_type < e1000_82544)
+ return wol->wolopts ? -EOPNOTSUPP : 0;
adapter->wol = 0;
diff --git a/drivers/net/e1000/e1000_hw.c b/drivers/net/e1000/e1000_hw.c
new file mode 100644
index 0000000000000..0be1c61457711
--- /dev/null
+++ b/drivers/net/e1000/e1000_hw.c
@@ -0,0 +1,3228 @@
+/*******************************************************************************
+
+ This software program is available to you under a choice of one of two
+ licenses. You may choose to be licensed under either the GNU General Public
+ License 2.0, June 1991, available at http://www.fsf.org/copyleft/gpl.html,
+ or the Intel BSD + Patent License, the text of which follows:
+
+ Recipient has requested a license and Intel Corporation ("Intel") is willing
+ to grant a license for the software entitled Linux Base Driver for the
+ Intel(R) PRO/1000 Family of Adapters (e1000) (the "Software") being provided
+ by Intel Corporation. The following definitions apply to this license:
+
+ "Licensed Patents" means patent claims licensable by Intel Corporation which
+ are necessarily infringed by the use of sale of the Software alone or when
+ combined with the operating system referred to below.
+
+ "Recipient" means the party to whom Intel delivers this Software.
+
+ "Licensee" means Recipient and those third parties that receive a license to
+ any operating system available under the GNU General Public License 2.0 or
+ later.
+
+ Copyright (c) 1999 - 2002 Intel Corporation.
+ All rights reserved.
+
+ The license is provided to Recipient and Recipient's Licensees under the
+ following terms.
+
+ Redistribution and use in source and binary forms of the Software, with or
+ without modification, are permitted provided that the following conditions
+ are met:
+
+ Redistributions of source code of the Software may retain the above
+ copyright notice, this list of conditions and the following disclaimer.
+
+ Redistributions in binary form of the Software may reproduce the above
+ copyright notice, this list of conditions and the following disclaimer in
+ the documentation and/or materials provided with the distribution.
+
+ Neither the name of Intel Corporation nor the names of its contributors
+ shall be used to endorse or promote products derived from this Software
+ without specific prior written permission.
+
+ Intel hereby grants Recipient and Licensees a non-exclusive, worldwide,
+ royalty-free patent license under Licensed Patents to make, use, sell, offer
+ to sell, import and otherwise transfer the Software, if any, in source code
+ and object code form. This license shall include changes to the Software
+ that are error corrections or other minor changes to the Software that do
+ not add functionality or features when the Software is incorporated in any
+ version of an operating system that has been distributed under the GNU
+ General Public License 2.0 or later. This patent license shall apply to the
+ combination of the Software and any operating system licensed under the GNU
+ General Public License 2.0 or later if, at the time Intel provides the
+ Software to Recipient, such addition of the Software to the then publicly
+ available versions of such operating systems available under the GNU General
+ Public License 2.0 or later (whether in gold, beta or alpha form) causes
+ such combination to be covered by the Licensed Patents. The patent license
+ shall not apply to any other combinations which include the Software. NO
+ hardware per se is licensed hereunder.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MECHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR IT CONTRIBUTORS BE LIABLE FOR ANY
+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ ANY LOSS OF USE; DATA, OR PROFITS; OR BUSINESS INTERUPTION) HOWEVER CAUSED
+ AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY OR
+ TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*******************************************************************************/
+
+/* e1000_hw.c
+ * Shared functions for accessing and configuring the MAC
+ */
+
+#include "e1000_hw.h"
+
+static int32_t e1000_setup_fiber_link(struct e1000_hw *hw);
+static int32_t e1000_setup_copper_link(struct e1000_hw *hw);
+static int32_t e1000_phy_force_speed_duplex(struct e1000_hw *hw);
+static int32_t e1000_config_mac_to_phy(struct e1000_hw *hw);
+static int32_t e1000_force_mac_fc(struct e1000_hw *hw);
+static void e1000_raise_mdi_clk(struct e1000_hw *hw, uint32_t *ctrl);
+static void e1000_lower_mdi_clk(struct e1000_hw *hw, uint32_t *ctrl);
+static void e1000_shift_out_mdi_bits(struct e1000_hw *hw, uint32_t data, uint16_t count);
+static uint16_t e1000_shift_in_mdi_bits(struct e1000_hw *hw);
+static int32_t e1000_phy_reset_dsp(struct e1000_hw *hw);
+static void e1000_raise_ee_clk(struct e1000_hw *hw, uint32_t *eecd);
+static void e1000_lower_ee_clk(struct e1000_hw *hw, uint32_t *eecd);
+static void e1000_shift_out_ee_bits(struct e1000_hw *hw, uint16_t data, uint16_t count);
+static uint16_t e1000_shift_in_ee_bits(struct e1000_hw *hw);
+static void e1000_setup_eeprom(struct e1000_hw *hw);
+static void e1000_standby_eeprom(struct e1000_hw *hw);
+
+/******************************************************************************
+ * Reset the transmit and receive units; mask and clear all interrupts.
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+void
+e1000_reset_hw(struct e1000_hw *hw)
+{
+ uint32_t ctrl;
+ uint32_t ctrl_ext;
+ uint32_t icr;
+ uint32_t manc;
+ uint16_t pci_cmd_word;
+
+ DEBUGFUNC("e1000_reset_hw");
+
+ /* For 82542 (rev 2.0), disable MWI before issuing a device reset */
+ if(hw->mac_type == e1000_82542_rev2_0) {
+ if(hw->pci_cmd_word & CMD_MEM_WRT_INVALIDATE) {
+ DEBUGOUT("Disabling MWI on 82542 rev 2.0\n");
+ pci_cmd_word = hw->pci_cmd_word & ~CMD_MEM_WRT_INVALIDATE;
+ e1000_write_pci_cfg(hw, PCI_COMMAND_REGISTER, &pci_cmd_word);
+ }
+ }
+
+ /* Clear interrupt mask to stop board from generating interrupts */
+ DEBUGOUT("Masking off all interrupts\n");
+ E1000_WRITE_REG(hw, IMC, 0xffffffff);
+
+ /* Disable the Transmit and Receive units. Then delay to allow
+ * any pending transactions to complete before we hit the MAC with
+ * the global reset.
+ */
+ E1000_WRITE_REG(hw, RCTL, 0);
+ E1000_WRITE_REG(hw, TCTL, E1000_TCTL_PSP);
+
+ /* The tbi_compatibility_on Flag must be cleared when Rctl is cleared. */
+ hw->tbi_compatibility_on = FALSE;
+
+ /* Delay to allow any outstanding PCI transactions to complete before
+ * resetting the device
+ */
+ msec_delay(10);
+
+ /* Issue a global reset to the MAC. This will reset the chip's
+ * transmit, receive, DMA, and link units. It will not effect
+ * the current PCI configuration. The global reset bit is self-
+ * clearing, and should clear within a microsecond.
+ */
+ DEBUGOUT("Issuing a global reset to MAC\n");
+ ctrl = E1000_READ_REG(hw, CTRL);
+ E1000_WRITE_REG(hw, CTRL, (ctrl | E1000_CTRL_RST));
+
+ /* Force a reload from the EEPROM if necessary */
+ if(hw->mac_type < e1000_82540) {
+ /* Wait for reset to complete */
+ usec_delay(10);
+ ctrl_ext = E1000_READ_REG(hw, CTRL_EXT);
+ ctrl_ext |= E1000_CTRL_EXT_EE_RST;
+ E1000_WRITE_REG(hw, CTRL_EXT, ctrl_ext);
+ /* Wait for EEPROM reload */
+ msec_delay(2);
+ } else {
+ /* Wait for EEPROM reload (it happens automatically) */
+ msec_delay(4);
+ /* Dissable HW ARPs on ASF enabled adapters */
+ manc = E1000_READ_REG(hw, MANC);
+ manc &= ~(E1000_MANC_ARP_EN);
+ E1000_WRITE_REG(hw, MANC, manc);
+ }
+
+ /* Clear interrupt mask to stop board from generating interrupts */
+ DEBUGOUT("Masking off all interrupts\n");
+ E1000_WRITE_REG(hw, IMC, 0xffffffff);
+
+ /* Clear any pending interrupt events. */
+ icr = E1000_READ_REG(hw, ICR);
+
+ /* If MWI was previously enabled, reenable it. */
+ if(hw->mac_type == e1000_82542_rev2_0) {
+ if(hw->pci_cmd_word & CMD_MEM_WRT_INVALIDATE)
+ e1000_write_pci_cfg(hw, PCI_COMMAND_REGISTER, &hw->pci_cmd_word);
+ }
+}
+
+/******************************************************************************
+ * Performs basic configuration of the adapter.
+ *
+ * hw - Struct containing variables accessed by shared code
+ *
+ * Assumes that the controller has previously been reset and is in a
+ * post-reset uninitialized state. Initializes the receive address registers,
+ * multicast table, and VLAN filter table. Calls routines to setup link
+ * configuration and flow control settings. Clears all on-chip counters. Leaves
+ * the transmit and receive units disabled and uninitialized.
+ *****************************************************************************/
+int32_t
+e1000_init_hw(struct e1000_hw *hw)
+{
+ uint32_t ctrl, status;
+ uint32_t i;
+ int32_t ret_val;
+ uint16_t pci_cmd_word;
+
+ DEBUGFUNC("e1000_init_hw");
+
+ /* Set the Media Type and exit with error if it is not valid. */
+ if(hw->mac_type != e1000_82543) {
+ /* tbi_compatibility is only valid on 82543 */
+ hw->tbi_compatibility_en = FALSE;
+ }
+
+ if(hw->mac_type >= e1000_82543) {
+ status = E1000_READ_REG(hw, STATUS);
+ if(status & E1000_STATUS_TBIMODE) {
+ hw->media_type = e1000_media_type_fiber;
+ /* tbi_compatibility not valid on fiber */
+ hw->tbi_compatibility_en = FALSE;
+ } else {
+ hw->media_type = e1000_media_type_copper;
+ }
+ } else {
+ /* This is an 82542 (fiber only) */
+ hw->media_type = e1000_media_type_fiber;
+ }
+
+ /* Disabling VLAN filtering. */
+ DEBUGOUT("Initializing the IEEE VLAN\n");
+ E1000_WRITE_REG(hw, VET, 0);
+
+ e1000_clear_vfta(hw);
+
+ /* For 82542 (rev 2.0), disable MWI and put the receiver into reset */
+ if(hw->mac_type == e1000_82542_rev2_0) {
+ if(hw->pci_cmd_word & CMD_MEM_WRT_INVALIDATE) {
+ DEBUGOUT("Disabling MWI on 82542 rev 2.0\n");
+ pci_cmd_word = hw->pci_cmd_word & ~CMD_MEM_WRT_INVALIDATE;
+ e1000_write_pci_cfg(hw, PCI_COMMAND_REGISTER, &pci_cmd_word);
+ }
+ E1000_WRITE_REG(hw, RCTL, E1000_RCTL_RST);
+ msec_delay(5);
+ }
+
+ /* Setup the receive address. This involves initializing all of the Receive
+ * Address Registers (RARs 0 - 15).
+ */
+ e1000_init_rx_addrs(hw);
+
+ /* For 82542 (rev 2.0), take the receiver out of reset and enable MWI */
+ if(hw->mac_type == e1000_82542_rev2_0) {
+ E1000_WRITE_REG(hw, RCTL, 0);
+ msec_delay(1);
+ if(hw->pci_cmd_word & CMD_MEM_WRT_INVALIDATE)
+ e1000_write_pci_cfg(hw, PCI_COMMAND_REGISTER, &hw->pci_cmd_word);
+ }
+
+ /* Zero out the Multicast HASH table */
+ DEBUGOUT("Zeroing the MTA\n");
+ for(i = 0; i < E1000_MC_TBL_SIZE; i++)
+ E1000_WRITE_REG_ARRAY(hw, MTA, i, 0);
+
+ /* Set the PCI priority bit correctly in the CTRL register. This
+ * determines if the adapter gives priority to receives, or if it
+ * gives equal priority to transmits and receives.
+ */
+ if(hw->dma_fairness) {
+ ctrl = E1000_READ_REG(hw, CTRL);
+ E1000_WRITE_REG(hw, CTRL, ctrl | E1000_CTRL_PRIOR);
+ }
+
+ /* Call a subroutine to configure the link and setup flow control. */
+ ret_val = e1000_setup_link(hw);
+
+ /* Clear all of the statistics registers (clear on read). It is
+ * important that we do this after we have tried to establish link
+ * because the symbol error count will increment wildly if there
+ * is no link.
+ */
+ e1000_clear_hw_cntrs(hw);
+
+ return ret_val;
+}
+
+/******************************************************************************
+ * Configures flow control and link settings.
+ *
+ * hw - Struct containing variables accessed by shared code
+ *
+ * Determines which flow control settings to use. Calls the apropriate media-
+ * specific link configuration function. Configures the flow control settings.
+ * Assuming the adapter has a valid link partner, a valid link should be
+ * established. Assumes the hardware has previously been reset and the
+ * transmitter and receiver are not enabled.
+ *****************************************************************************/
+int32_t
+e1000_setup_link(struct e1000_hw *hw)
+{
+ uint32_t ctrl_ext;
+ int32_t ret_val;
+ uint16_t eeprom_data;
+
+ DEBUGFUNC("e1000_setup_link");
+
+ /* Read and store word 0x0F of the EEPROM. This word contains bits
+ * that determine the hardware's default PAUSE (flow control) mode,
+ * a bit that determines whether the HW defaults to enabling or
+ * disabling auto-negotiation, and the direction of the
+ * SW defined pins. If there is no SW over-ride of the flow
+ * control setting, then the variable hw->fc will
+ * be initialized based on a value in the EEPROM.
+ */
+ if(e1000_read_eeprom(hw, EEPROM_INIT_CONTROL2_REG, &eeprom_data) < 0) {
+ DEBUGOUT("EEPROM Read Error\n");
+ return -E1000_ERR_EEPROM;
+ }
+
+ if(hw->fc == e1000_fc_default) {
+ if((eeprom_data & EEPROM_WORD0F_PAUSE_MASK) == 0)
+ hw->fc = e1000_fc_none;
+ else if((eeprom_data & EEPROM_WORD0F_PAUSE_MASK) ==
+ EEPROM_WORD0F_ASM_DIR)
+ hw->fc = e1000_fc_tx_pause;
+ else
+ hw->fc = e1000_fc_full;
+ }
+
+ /* We want to save off the original Flow Control configuration just
+ * in case we get disconnected and then reconnected into a different
+ * hub or switch with different Flow Control capabilities.
+ */
+ if(hw->mac_type == e1000_82542_rev2_0)
+ hw->fc &= (~e1000_fc_tx_pause);
+
+ if((hw->mac_type < e1000_82543) && (hw->report_tx_early == 1))
+ hw->fc &= (~e1000_fc_rx_pause);
+
+ hw->original_fc = hw->fc;
+
+ DEBUGOUT1("After fix-ups FlowControl is now = %x\n", hw->fc);
+
+ /* Take the 4 bits from EEPROM word 0x0F that determine the initial
+ * polarity value for the SW controlled pins, and setup the
+ * Extended Device Control reg with that info.
+ * This is needed because one of the SW controlled pins is used for
+ * signal detection. So this should be done before e1000_setup_pcs_link()
+ * or e1000_phy_setup() is called.
+ */
+ if(hw->mac_type == e1000_82543) {
+ ctrl_ext = ((eeprom_data & EEPROM_WORD0F_SWPDIO_EXT) <<
+ SWDPIO__EXT_SHIFT);
+ E1000_WRITE_REG(hw, CTRL_EXT, ctrl_ext);
+ }
+
+ /* Call the necessary subroutine to configure the link. */
+ ret_val = (hw->media_type == e1000_media_type_fiber) ?
+ e1000_setup_fiber_link(hw) :
+ e1000_setup_copper_link(hw);
+
+ /* Initialize the flow control address, type, and PAUSE timer
+ * registers to their default values. This is done even if flow
+ * control is disabled, because it does not hurt anything to
+ * initialize these registers.
+ */
+ DEBUGOUT("Initializing the Flow Control address, type and timer regs\n");
+
+ E1000_WRITE_REG(hw, FCAL, FLOW_CONTROL_ADDRESS_LOW);
+ E1000_WRITE_REG(hw, FCAH, FLOW_CONTROL_ADDRESS_HIGH);
+ E1000_WRITE_REG(hw, FCT, FLOW_CONTROL_TYPE);
+ E1000_WRITE_REG(hw, FCTTV, hw->fc_pause_time);
+
+ /* Set the flow control receive threshold registers. Normally,
+ * these registers will be set to a default threshold that may be
+ * adjusted later by the driver's runtime code. However, if the
+ * ability to transmit pause frames in not enabled, then these
+ * registers will be set to 0.
+ */
+ if(!(hw->fc & e1000_fc_tx_pause)) {
+ E1000_WRITE_REG(hw, FCRTL, 0);
+ E1000_WRITE_REG(hw, FCRTH, 0);
+ } else {
+ /* We need to set up the Receive Threshold high and low water marks
+ * as well as (optionally) enabling the transmission of XON frames.
+ */
+ if(hw->fc_send_xon) {
+ E1000_WRITE_REG(hw, FCRTL, (hw->fc_low_water | E1000_FCRTL_XONE));
+ E1000_WRITE_REG(hw, FCRTH, hw->fc_high_water);
+ } else {
+ E1000_WRITE_REG(hw, FCRTL, hw->fc_low_water);
+ E1000_WRITE_REG(hw, FCRTH, hw->fc_high_water);
+ }
+ }
+ return ret_val;
+}
+
+/******************************************************************************
+ * Sets up link for a fiber based adapter
+ *
+ * hw - Struct containing variables accessed by shared code
+ * ctrl - Current value of the device control register
+ *
+ * Manipulates Physical Coding Sublayer functions in order to configure
+ * link. Assumes the hardware has been previously reset and the transmitter
+ * and receiver are not enabled.
+ *****************************************************************************/
+static int32_t
+e1000_setup_fiber_link(struct e1000_hw *hw)
+{
+ uint32_t ctrl;
+ uint32_t status;
+ uint32_t txcw = 0;
+ uint32_t i;
+ uint32_t signal;
+ int32_t ret_val;
+
+ DEBUGFUNC("e1000_setup_fiber_link");
+
+ /* On adapters with a MAC newer that 82544, SW Defineable pin 1 will be
+ * set when the optics detect a signal. On older adapters, it will be
+ * cleared when there is a signal
+ */
+ ctrl = E1000_READ_REG(hw, CTRL);
+ if(hw->mac_type > e1000_82544) signal = E1000_CTRL_SWDPIN1;
+ else signal = 0;
+
+ /* Take the link out of reset */
+ ctrl &= ~(E1000_CTRL_LRST);
+
+ e1000_config_collision_dist(hw);
+
+ /* Check for a software override of the flow control settings, and setup
+ * the device accordingly. If auto-negotiation is enabled, then software
+ * will have to set the "PAUSE" bits to the correct value in the Tranmsit
+ * Config Word Register (TXCW) and re-start auto-negotiation. However, if
+ * auto-negotiation is disabled, then software will have to manually
+ * configure the two flow control enable bits in the CTRL register.
+ *
+ * The possible values of the "fc" parameter are:
+ * 0: Flow control is completely disabled
+ * 1: Rx flow control is enabled (we can receive pause frames, but
+ * not send pause frames).
+ * 2: Tx flow control is enabled (we can send pause frames but we do
+ * not support receiving pause frames).
+ * 3: Both Rx and TX flow control (symmetric) are enabled.
+ */
+ switch (hw->fc) {
+ case e1000_fc_none:
+ /* Flow control is completely disabled by a software over-ride. */
+ txcw = (E1000_TXCW_ANE | E1000_TXCW_FD);
+ break;
+ case e1000_fc_rx_pause:
+ /* RX Flow control is enabled and TX Flow control is disabled by a
+ * software over-ride. Since there really isn't a way to advertise
+ * that we are capable of RX Pause ONLY, we will advertise that we
+ * support both symmetric and asymmetric RX PAUSE. Later, we will
+ * disable the adapter's ability to send PAUSE frames.
+ */
+ txcw = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_PAUSE_MASK);
+ break;
+ case e1000_fc_tx_pause:
+ /* TX Flow control is enabled, and RX Flow control is disabled, by a
+ * software over-ride.
+ */
+ txcw = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_ASM_DIR);
+ break;
+ case e1000_fc_full:
+ /* Flow control (both RX and TX) is enabled by a software over-ride. */
+ txcw = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_PAUSE_MASK);
+ break;
+ default:
+ DEBUGOUT("Flow control param set incorrectly\n");
+ return -E1000_ERR_CONFIG;
+ break;
+ }
+
+ /* Since auto-negotiation is enabled, take the link out of reset (the link
+ * will be in reset, because we previously reset the chip). This will
+ * restart auto-negotiation. If auto-neogtiation is successful then the
+ * link-up status bit will be set and the flow control enable bits (RFCE
+ * and TFCE) will be set according to their negotiated value.
+ */
+ DEBUGOUT("Auto-negotiation enabled\n");
+
+ E1000_WRITE_REG(hw, TXCW, txcw);
+ E1000_WRITE_REG(hw, CTRL, ctrl);
+
+ hw->txcw = txcw;
+ msec_delay(1);
+
+ /* If we have a signal (the cable is plugged in) then poll for a "Link-Up"
+ * indication in the Device Status Register. Time-out if a link isn't
+ * seen in 500 milliseconds seconds (Auto-negotiation should complete in
+ * less than 500 milliseconds even if the other end is doing it in SW).
+ */
+ if((E1000_READ_REG(hw, CTRL) & E1000_CTRL_SWDPIN1) == signal) {
+ DEBUGOUT("Looking for Link\n");
+ for(i = 0; i < (LINK_UP_TIMEOUT / 10); i++) {
+ msec_delay(10);
+ status = E1000_READ_REG(hw, STATUS);
+ if(status & E1000_STATUS_LU) break;
+ }
+ if(i == (LINK_UP_TIMEOUT / 10)) {
+ /* AutoNeg failed to achieve a link, so we'll call
+ * e1000_check_for_link. This routine will force the link up if we
+ * detect a signal. This will allow us to communicate with
+ * non-autonegotiating link partners.
+ */
+ DEBUGOUT("Never got a valid link from auto-neg!!!\n");
+ hw->autoneg_failed = 1;
+ ret_val = e1000_check_for_link(hw);
+ if(ret_val < 0) {
+ DEBUGOUT("Error while checking for link\n");
+ return ret_val;
+ }
+ hw->autoneg_failed = 0;
+ } else {
+ hw->autoneg_failed = 0;
+ DEBUGOUT("Valid Link Found\n");
+ }
+ } else {
+ DEBUGOUT("No Signal Detected\n");
+ }
+ return 0;
+}
+
+/******************************************************************************
+* Detects which PHY is present and the speed and duplex
+*
+* hw - Struct containing variables accessed by shared code
+* ctrl - current value of the device control register
+******************************************************************************/
+static int32_t
+e1000_setup_copper_link(struct e1000_hw *hw)
+{
+ uint32_t ctrl;
+ int32_t ret_val;
+ uint16_t i;
+ uint16_t phy_data;
+
+ DEBUGFUNC("e1000_setup_copper_link");
+
+ ctrl = E1000_READ_REG(hw, CTRL);
+ /* With 82543, we need to force speed and duplex on the MAC equal to what
+ * the PHY speed and duplex configuration is. In addition, we need to
+ * perform a hardware reset on the PHY to take it out of reset.
+ */
+ if(hw->mac_type > e1000_82543) {
+ ctrl |= E1000_CTRL_SLU;
+ E1000_WRITE_REG(hw, CTRL, ctrl);
+ } else {
+ ctrl |= (E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX | E1000_CTRL_SLU);
+ E1000_WRITE_REG(hw, CTRL, ctrl);
+ e1000_phy_hw_reset(hw);
+ }
+
+ /* Make sure we have a valid PHY */
+ ret_val = e1000_detect_gig_phy(hw);
+ if(ret_val < 0) {
+ DEBUGOUT("Error, did not detect valid phy.\n");
+ return ret_val;
+ }
+ DEBUGOUT1("Phy ID = %x \n", hw->phy_id);
+
+ /* Enable CRS on TX. This must be set for half-duplex operation. */
+ if(e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data) < 0) {
+ DEBUGOUT("PHY Read Error\n");
+ return -E1000_ERR_PHY;
+ }
+ phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX;
+
+ /* Options:
+ * MDI/MDI-X = 0 (default)
+ * 0 - Auto for all speeds
+ * 1 - MDI mode
+ * 2 - MDI-X mode
+ * 3 - Auto for 1000Base-T only (MDI-X for 10/100Base-T modes)
+ */
+ phy_data &= ~M88E1000_PSCR_AUTO_X_MODE;
+
+ switch (hw->mdix) {
+ case 1:
+ phy_data |= M88E1000_PSCR_MDI_MANUAL_MODE;
+ break;
+ case 2:
+ phy_data |= M88E1000_PSCR_MDIX_MANUAL_MODE;
+ break;
+ case 3:
+ phy_data |= M88E1000_PSCR_AUTO_X_1000T;
+ break;
+ case 0:
+ default:
+ phy_data |= M88E1000_PSCR_AUTO_X_MODE;
+ break;
+ }
+
+ /* Options:
+ * disable_polarity_correction = 0 (default)
+ * Automatic Correction for Reversed Cable Polarity
+ * 0 - Disabled
+ * 1 - Enabled
+ */
+ phy_data &= ~M88E1000_PSCR_POLARITY_REVERSAL;
+ if(hw->disable_polarity_correction == 1)
+ phy_data |= M88E1000_PSCR_POLARITY_REVERSAL;
+ if(e1000_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data) < 0) {
+ DEBUGOUT("PHY Write Error\n");
+ return -E1000_ERR_PHY;
+ }
+
+ /* Force TX_CLK in the Extended PHY Specific Control Register
+ * to 25MHz clock.
+ */
+ if(e1000_read_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, &phy_data) < 0) {
+ DEBUGOUT("PHY Read Error\n");
+ return -E1000_ERR_PHY;
+ }
+ phy_data |= M88E1000_EPSCR_TX_CLK_25;
+ /* Configure Master and Slave downshift values */
+ phy_data &= ~(M88E1000_EPSCR_MASTER_DOWNSHIFT_MASK |
+ M88E1000_EPSCR_SLAVE_DOWNSHIFT_MASK);
+ phy_data |= (M88E1000_EPSCR_MASTER_DOWNSHIFT_1X |
+ M88E1000_EPSCR_SLAVE_DOWNSHIFT_1X);
+ if(e1000_write_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, phy_data) < 0) {
+ DEBUGOUT("PHY Write Error\n");
+ return -E1000_ERR_PHY;
+ }
+
+ /* SW Reset the PHY so all changes take effect */
+ ret_val = e1000_phy_reset(hw);
+ if(ret_val < 0) {
+ DEBUGOUT("Error Resetting the PHY\n");
+ return ret_val;
+ }
+
+ /* Options:
+ * autoneg = 1 (default)
+ * PHY will advertise value(s) parsed from
+ * autoneg_advertised and fc
+ * autoneg = 0
+ * PHY will be set to 10H, 10F, 100H, or 100F
+ * depending on value parsed from forced_speed_duplex.
+ */
+
+ /* Is autoneg enabled? This is enabled by default or by software override.
+ * If so, call e1000_phy_setup_autoneg routine to parse the
+ * autoneg_advertised and fc options. If autoneg is NOT enabled, then the
+ * user should have provided a speed/duplex override. If so, then call
+ * e1000_phy_force_speed_duplex to parse and set this up.
+ */
+ if(hw->autoneg) {
+ /* Perform some bounds checking on the hw->autoneg_advertised
+ * parameter. If this variable is zero, then set it to the default.
+ */
+ hw->autoneg_advertised &= AUTONEG_ADVERTISE_SPEED_DEFAULT;
+
+ /* If autoneg_advertised is zero, we assume it was not defaulted
+ * by the calling code so we set to advertise full capability.
+ */
+ if(hw->autoneg_advertised == 0)
+ hw->autoneg_advertised = AUTONEG_ADVERTISE_SPEED_DEFAULT;
+
+ DEBUGOUT("Reconfiguring auto-neg advertisement params\n");
+ ret_val = e1000_phy_setup_autoneg(hw);
+ if(ret_val < 0) {
+ DEBUGOUT("Error Setting up Auto-Negotiation\n");
+ return ret_val;
+ }
+ DEBUGOUT("Restarting Auto-Neg\n");
+
+ /* Restart auto-negotiation by setting the Auto Neg Enable bit and
+ * the Auto Neg Restart bit in the PHY control register.
+ */
+ if(e1000_read_phy_reg(hw, PHY_CTRL, &phy_data) < 0) {
+ DEBUGOUT("PHY Read Error\n");
+ return -E1000_ERR_PHY;
+ }
+ phy_data |= (MII_CR_AUTO_NEG_EN | MII_CR_RESTART_AUTO_NEG);
+ if(e1000_write_phy_reg(hw, PHY_CTRL, phy_data) < 0) {
+ DEBUGOUT("PHY Write Error\n");
+ return -E1000_ERR_PHY;
+ }
+
+ /* Does the user want to wait for Auto-Neg to complete here, or
+ * check at a later time (for example, callback routine).
+ */
+ if(hw->wait_autoneg_complete) {
+ ret_val = e1000_wait_autoneg(hw);
+ if(ret_val < 0) {
+ DEBUGOUT("Error while waiting for autoneg to complete\n");
+ return ret_val;
+ }
+ }
+ } else {
+ DEBUGOUT("Forcing speed and duplex\n");
+ ret_val = e1000_phy_force_speed_duplex(hw);
+ if(ret_val < 0) {
+ DEBUGOUT("Error Forcing Speed and Duplex\n");
+ return ret_val;
+ }
+ }
+
+ /* Check link status. Wait up to 100 microseconds for link to become
+ * valid.
+ */
+ for(i = 0; i < 10; i++) {
+ if(e1000_read_phy_reg(hw, PHY_STATUS, &phy_data) < 0) {
+ DEBUGOUT("PHY Read Error\n");
+ return -E1000_ERR_PHY;
+ }
+ if(e1000_read_phy_reg(hw, PHY_STATUS, &phy_data) < 0) {
+ DEBUGOUT("PHY Read Error\n");
+ return -E1000_ERR_PHY;
+ }
+ if(phy_data & MII_SR_LINK_STATUS) {
+ /* We have link, so we need to finish the config process:
+ * 1) Set up the MAC to the current PHY speed/duplex
+ * if we are on 82543. If we
+ * are on newer silicon, we only need to configure
+ * collision distance in the Transmit Control Register.
+ * 2) Set up flow control on the MAC to that established with
+ * the link partner.
+ */
+ if(hw->mac_type >= e1000_82544) {
+ e1000_config_collision_dist(hw);
+ } else {
+ ret_val = e1000_config_mac_to_phy(hw);
+ if(ret_val < 0) {
+ DEBUGOUT("Error configuring MAC to PHY settings\n");
+ return ret_val;
+ }
+ }
+ ret_val = e1000_config_fc_after_link_up(hw);
+ if(ret_val < 0) {
+ DEBUGOUT("Error Configuring Flow Control\n");
+ return ret_val;
+ }
+ DEBUGOUT("Valid link established!!!\n");
+ return 0;
+ }
+ usec_delay(10);
+ }
+
+ DEBUGOUT("Unable to establish link!!!\n");
+ return 0;
+}
+
+/******************************************************************************
+* Configures PHY autoneg and flow control advertisement settings
+*
+* hw - Struct containing variables accessed by shared code
+******************************************************************************/
+int32_t
+e1000_phy_setup_autoneg(struct e1000_hw *hw)
+{
+ uint16_t mii_autoneg_adv_reg;
+ uint16_t mii_1000t_ctrl_reg;
+
+ DEBUGFUNC("e1000_phy_setup_autoneg");
+
+ /* Read the MII Auto-Neg Advertisement Register (Address 4). */
+ if(e1000_read_phy_reg(hw, PHY_AUTONEG_ADV, &mii_autoneg_adv_reg) < 0) {
+ DEBUGOUT("PHY Read Error\n");
+ return -E1000_ERR_PHY;
+ }
+
+ /* Read the MII 1000Base-T Control Register (Address 9). */
+ if(e1000_read_phy_reg(hw, PHY_1000T_CTRL, &mii_1000t_ctrl_reg) < 0) {
+ DEBUGOUT("PHY Read Error\n");
+ return -E1000_ERR_PHY;
+ }
+
+ /* Need to parse both autoneg_advertised and fc and set up
+ * the appropriate PHY registers. First we will parse for
+ * autoneg_advertised software override. Since we can advertise
+ * a plethora of combinations, we need to check each bit
+ * individually.
+ */
+
+ /* First we clear all the 10/100 mb speed bits in the Auto-Neg
+ * Advertisement Register (Address 4) and the 1000 mb speed bits in
+ * the 1000Base-T Control Register (Address 9).
+ */
+ mii_autoneg_adv_reg &= ~REG4_SPEED_MASK;
+ mii_1000t_ctrl_reg &= ~REG9_SPEED_MASK;
+
+ DEBUGOUT1("autoneg_advertised %x\n", hw->autoneg_advertised);
+
+ /* Do we want to advertise 10 Mb Half Duplex? */
+ if(hw->autoneg_advertised & ADVERTISE_10_HALF) {
+ DEBUGOUT("Advertise 10mb Half duplex\n");
+ mii_autoneg_adv_reg |= NWAY_AR_10T_HD_CAPS;
+ }
+
+ /* Do we want to advertise 10 Mb Full Duplex? */
+ if(hw->autoneg_advertised & ADVERTISE_10_FULL) {
+ DEBUGOUT("Advertise 10mb Full duplex\n");
+ mii_autoneg_adv_reg |= NWAY_AR_10T_FD_CAPS;
+ }
+
+ /* Do we want to advertise 100 Mb Half Duplex? */
+ if(hw->autoneg_advertised & ADVERTISE_100_HALF) {
+ DEBUGOUT("Advertise 100mb Half duplex\n");
+ mii_autoneg_adv_reg |= NWAY_AR_100TX_HD_CAPS;
+ }
+
+ /* Do we want to advertise 100 Mb Full Duplex? */
+ if(hw->autoneg_advertised & ADVERTISE_100_FULL) {
+ DEBUGOUT("Advertise 100mb Full duplex\n");
+ mii_autoneg_adv_reg |= NWAY_AR_100TX_FD_CAPS;
+ }
+
+ /* We do not allow the Phy to advertise 1000 Mb Half Duplex */
+ if(hw->autoneg_advertised & ADVERTISE_1000_HALF) {
+ DEBUGOUT("Advertise 1000mb Half duplex requested, request denied!\n");
+ }
+
+ /* Do we want to advertise 1000 Mb Full Duplex? */
+ if(hw->autoneg_advertised & ADVERTISE_1000_FULL) {
+ DEBUGOUT("Advertise 1000mb Full duplex\n");
+ mii_1000t_ctrl_reg |= CR_1000T_FD_CAPS;
+ }
+
+ /* Check for a software override of the flow control settings, and
+ * setup the PHY advertisement registers accordingly. If
+ * auto-negotiation is enabled, then software will have to set the
+ * "PAUSE" bits to the correct value in the Auto-Negotiation
+ * Advertisement Register (PHY_AUTONEG_ADV) and re-start auto-negotiation.
+ *
+ * The possible values of the "fc" parameter are:
+ * 0: Flow control is completely disabled
+ * 1: Rx flow control is enabled (we can receive pause frames
+ * but not send pause frames).
+ * 2: Tx flow control is enabled (we can send pause frames
+ * but we do not support receiving pause frames).
+ * 3: Both Rx and TX flow control (symmetric) are enabled.
+ * other: No software override. The flow control configuration
+ * in the EEPROM is used.
+ */
+ switch (hw->fc) {
+ case e1000_fc_none: /* 0 */
+ /* Flow control (RX & TX) is completely disabled by a
+ * software over-ride.
+ */
+ mii_autoneg_adv_reg &= ~(NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
+ break;
+ case e1000_fc_rx_pause: /* 1 */
+ /* RX Flow control is enabled, and TX Flow control is
+ * disabled, by a software over-ride.
+ */
+ /* Since there really isn't a way to advertise that we are
+ * capable of RX Pause ONLY, we will advertise that we
+ * support both symmetric and asymmetric RX PAUSE. Later
+ * (in e1000_config_fc_after_link_up) we will disable the
+ *hw's ability to send PAUSE frames.
+ */
+ mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
+ break;
+ case e1000_fc_tx_pause: /* 2 */
+ /* TX Flow control is enabled, and RX Flow control is
+ * disabled, by a software over-ride.
+ */
+ mii_autoneg_adv_reg |= NWAY_AR_ASM_DIR;
+ mii_autoneg_adv_reg &= ~NWAY_AR_PAUSE;
+ break;
+ case e1000_fc_full: /* 3 */
+ /* Flow control (both RX and TX) is enabled by a software
+ * over-ride.
+ */
+ mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
+ break;
+ default:
+ DEBUGOUT("Flow control param set incorrectly\n");
+ return -E1000_ERR_CONFIG;
+ }
+
+ if(e1000_write_phy_reg(hw, PHY_AUTONEG_ADV, mii_autoneg_adv_reg) < 0) {
+ DEBUGOUT("PHY Write Error\n");
+ return -E1000_ERR_PHY;
+ }
+
+ DEBUGOUT1("Auto-Neg Advertising %x\n", mii_autoneg_adv_reg);
+
+ if(e1000_write_phy_reg(hw, PHY_1000T_CTRL, mii_1000t_ctrl_reg) < 0) {
+ DEBUGOUT("PHY Write Error\n");
+ return -E1000_ERR_PHY;
+ }
+ return 0;
+}
+
+/******************************************************************************
+* Force PHY speed and duplex settings to hw->forced_speed_duplex
+*
+* hw - Struct containing variables accessed by shared code
+******************************************************************************/
+static int32_t
+e1000_phy_force_speed_duplex(struct e1000_hw *hw)
+{
+ uint32_t ctrl;
+ int32_t ret_val;
+ uint16_t mii_ctrl_reg;
+ uint16_t mii_status_reg;
+ uint16_t phy_data;
+ uint16_t i;
+
+ DEBUGFUNC("e1000_phy_force_speed_duplex");
+
+ /* Turn off Flow control if we are forcing speed and duplex. */
+ hw->fc = e1000_fc_none;
+
+ DEBUGOUT1("hw->fc = %d\n", hw->fc);
+
+ /* Read the Device Control Register. */
+ ctrl = E1000_READ_REG(hw, CTRL);
+
+ /* Set the bits to Force Speed and Duplex in the Device Ctrl Reg. */
+ ctrl |= (E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
+ ctrl &= ~(DEVICE_SPEED_MASK);
+
+ /* Clear the Auto Speed Detect Enable bit. */
+ ctrl &= ~E1000_CTRL_ASDE;
+
+ /* Read the MII Control Register. */
+ if(e1000_read_phy_reg(hw, PHY_CTRL, &mii_ctrl_reg) < 0) {
+ DEBUGOUT("PHY Read Error\n");
+ return -E1000_ERR_PHY;
+ }
+
+ /* We need to disable autoneg in order to force link and duplex. */
+
+ mii_ctrl_reg &= ~MII_CR_AUTO_NEG_EN;
+
+ /* Are we forcing Full or Half Duplex? */
+ if(hw->forced_speed_duplex == e1000_100_full ||
+ hw->forced_speed_duplex == e1000_10_full) {
+ /* We want to force full duplex so we SET the full duplex bits in the
+ * Device and MII Control Registers.
+ */
+ ctrl |= E1000_CTRL_FD;
+ mii_ctrl_reg |= MII_CR_FULL_DUPLEX;
+ DEBUGOUT("Full Duplex\n");
+ } else {
+ /* We want to force half duplex so we CLEAR the full duplex bits in
+ * the Device and MII Control Registers.
+ */
+ ctrl &= ~E1000_CTRL_FD;
+ mii_ctrl_reg &= ~MII_CR_FULL_DUPLEX;
+ DEBUGOUT("Half Duplex\n");
+ }
+
+ /* Are we forcing 100Mbps??? */
+ if(hw->forced_speed_duplex == e1000_100_full ||
+ hw->forced_speed_duplex == e1000_100_half) {
+ /* Set the 100Mb bit and turn off the 1000Mb and 10Mb bits. */
+ ctrl |= E1000_CTRL_SPD_100;
+ mii_ctrl_reg |= MII_CR_SPEED_100;
+ mii_ctrl_reg &= ~(MII_CR_SPEED_1000 | MII_CR_SPEED_10);
+ DEBUGOUT("Forcing 100mb ");
+ } else {
+ /* Set the 10Mb bit and turn off the 1000Mb and 100Mb bits. */
+ ctrl &= ~(E1000_CTRL_SPD_1000 | E1000_CTRL_SPD_100);
+ mii_ctrl_reg |= MII_CR_SPEED_10;
+ mii_ctrl_reg &= ~(MII_CR_SPEED_1000 | MII_CR_SPEED_100);
+ DEBUGOUT("Forcing 10mb ");
+ }
+
+ e1000_config_collision_dist(hw);
+
+ /* Write the configured values back to the Device Control Reg. */
+ E1000_WRITE_REG(hw, CTRL, ctrl);
+
+ /* Write the MII Control Register with the new PHY configuration. */
+ if(e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data) < 0) {
+ DEBUGOUT("PHY Read Error\n");
+ return -E1000_ERR_PHY;
+ }
+
+ /* Clear Auto-Crossover to force MDI manually. M88E1000 requires MDI
+ * forced whenever speed are duplex are forced.
+ */
+ phy_data &= ~M88E1000_PSCR_AUTO_X_MODE;
+ if(e1000_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data) < 0) {
+ DEBUGOUT("PHY Write Error\n");
+ return -E1000_ERR_PHY;
+ }
+ DEBUGOUT1("M88E1000 PSCR: %x \n", phy_data);
+
+ /* Need to reset the PHY or these changes will be ignored */
+ mii_ctrl_reg |= MII_CR_RESET;
+ if(e1000_write_phy_reg(hw, PHY_CTRL, mii_ctrl_reg) < 0) {
+ DEBUGOUT("PHY Write Error\n");
+ return -E1000_ERR_PHY;
+ }
+ usec_delay(1);
+
+ /* The wait_autoneg_complete flag may be a little misleading here.
+ * Since we are forcing speed and duplex, Auto-Neg is not enabled.
+ * But we do want to delay for a period while forcing only so we
+ * don't generate false No Link messages. So we will wait here
+ * only if the user has set wait_autoneg_complete to 1, which is
+ * the default.
+ */
+ if(hw->wait_autoneg_complete) {
+ /* We will wait for autoneg to complete. */
+ DEBUGOUT("Waiting for forced speed/duplex link.\n");
+ mii_status_reg = 0;
+
+ /* We will wait for autoneg to complete or 4.5 seconds to expire. */
+ for(i = PHY_FORCE_TIME; i > 0; i--) {
+ /* Read the MII Status Register and wait for Auto-Neg Complete bit
+ * to be set.
+ */
+ if(e1000_read_phy_reg(hw, PHY_STATUS, &mii_status_reg) < 0) {
+ DEBUGOUT("PHY Read Error\n");
+ return -E1000_ERR_PHY;
+ }
+ if(e1000_read_phy_reg(hw, PHY_STATUS, &mii_status_reg) < 0) {
+ DEBUGOUT("PHY Read Error\n");
+ return -E1000_ERR_PHY;
+ }
+ if(mii_status_reg & MII_SR_LINK_STATUS) break;
+ msec_delay(100);
+ }
+ if(i == 0) { /* We didn't get link */
+ /* Reset the DSP and wait again for link. */
+
+ ret_val = e1000_phy_reset_dsp(hw);
+ if(ret_val < 0) {
+ DEBUGOUT("Error Resetting PHY DSP\n");
+ return ret_val;
+ }
+ }
+ /* This loop will early-out if the link condition has been met. */
+ for(i = PHY_FORCE_TIME; i > 0; i--) {
+ if(mii_status_reg & MII_SR_LINK_STATUS) break;
+ msec_delay(100);
+ /* Read the MII Status Register and wait for Auto-Neg Complete bit
+ * to be set.
+ */
+ if(e1000_read_phy_reg(hw, PHY_STATUS, &mii_status_reg) < 0) {
+ DEBUGOUT("PHY Read Error\n");
+ return -E1000_ERR_PHY;
+ }
+ if(e1000_read_phy_reg(hw, PHY_STATUS, &mii_status_reg) < 0) {
+ DEBUGOUT("PHY Read Error\n");
+ return -E1000_ERR_PHY;
+ }
+ }
+ }
+
+ /* Because we reset the PHY above, we need to re-force TX_CLK in the
+ * Extended PHY Specific Control Register to 25MHz clock. This value
+ * defaults back to a 2.5MHz clock when the PHY is reset.
+ */
+ if(e1000_read_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, &phy_data) < 0) {
+ DEBUGOUT("PHY Read Error\n");
+ return -E1000_ERR_PHY;
+ }
+ phy_data |= M88E1000_EPSCR_TX_CLK_25;
+ if(e1000_write_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, phy_data) < 0) {
+ DEBUGOUT("PHY Write Error\n");
+ return -E1000_ERR_PHY;
+ }
+
+ /* In addition, because of the s/w reset above, we need to enable CRS on
+ * TX. This must be set for both full and half duplex operation.
+ */
+ if(e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data) < 0) {
+ DEBUGOUT("PHY Read Error\n");
+ return -E1000_ERR_PHY;
+ }
+ phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX;
+ if(e1000_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data) < 0) {
+ DEBUGOUT("PHY Write Error\n");
+ return -E1000_ERR_PHY;
+ }
+ return 0;
+}
+
+/******************************************************************************
+* Sets the collision distance in the Transmit Control register
+*
+* hw - Struct containing variables accessed by shared code
+*
+* Link should have been established previously. Reads the speed and duplex
+* information from the Device Status register.
+******************************************************************************/
+void
+e1000_config_collision_dist(struct e1000_hw *hw)
+{
+ uint32_t tctl;
+
+ tctl = E1000_READ_REG(hw, TCTL);
+
+ tctl &= ~E1000_TCTL_COLD;
+ tctl |= E1000_COLLISION_DISTANCE << E1000_COLD_SHIFT;
+
+ E1000_WRITE_REG(hw, TCTL, tctl);
+}
+
+/******************************************************************************
+* Sets MAC speed and duplex settings to reflect the those in the PHY
+*
+* hw - Struct containing variables accessed by shared code
+* mii_reg - data to write to the MII control register
+*
+* The contents of the PHY register containing the needed information need to
+* be passed in.
+******************************************************************************/
+static int32_t
+e1000_config_mac_to_phy(struct e1000_hw *hw)
+{
+ uint32_t ctrl;
+ uint16_t phy_data;
+
+ DEBUGFUNC("e1000_config_mac_to_phy");
+
+ /* Read the Device Control Register and set the bits to Force Speed
+ * and Duplex.
+ */
+ ctrl = E1000_READ_REG(hw, CTRL);
+ ctrl |= (E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
+ ctrl &= ~(E1000_CTRL_SPD_SEL | E1000_CTRL_ILOS);
+
+ /* Set up duplex in the Device Control and Transmit Control
+ * registers depending on negotiated values.
+ */
+ if(e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data) < 0) {
+ DEBUGOUT("PHY Read Error\n");
+ return -E1000_ERR_PHY;
+ }
+ if(phy_data & M88E1000_PSSR_DPLX) ctrl |= E1000_CTRL_FD;
+ else ctrl &= ~E1000_CTRL_FD;
+
+ e1000_config_collision_dist(hw);
+
+ /* Set up speed in the Device Control register depending on
+ * negotiated values.
+ */
+ if((phy_data & M88E1000_PSSR_SPEED) == M88E1000_PSSR_1000MBS)
+ ctrl |= E1000_CTRL_SPD_1000;
+ else if((phy_data & M88E1000_PSSR_SPEED) == M88E1000_PSSR_100MBS)
+ ctrl |= E1000_CTRL_SPD_100;
+ /* Write the configured values back to the Device Control Reg. */
+ E1000_WRITE_REG(hw, CTRL, ctrl);
+ return 0;
+}
+
+/******************************************************************************
+ * Forces the MAC's flow control settings.
+ *
+ * hw - Struct containing variables accessed by shared code
+ *
+ * Sets the TFCE and RFCE bits in the device control register to reflect
+ * the adapter settings. TFCE and RFCE need to be explicitly set by
+ * software when a Copper PHY is used because autonegotiation is managed
+ * by the PHY rather than the MAC. Software must also configure these
+ * bits when link is forced on a fiber connection.
+ *****************************************************************************/
+static int32_t
+e1000_force_mac_fc(struct e1000_hw *hw)
+{
+ uint32_t ctrl;
+
+ DEBUGFUNC("e1000_force_mac_fc");
+
+ /* Get the current configuration of the Device Control Register */
+ ctrl = E1000_READ_REG(hw, CTRL);
+
+ /* Because we didn't get link via the internal auto-negotiation
+ * mechanism (we either forced link or we got link via PHY
+ * auto-neg), we have to manually enable/disable transmit an
+ * receive flow control.
+ *
+ * The "Case" statement below enables/disable flow control
+ * according to the "hw->fc" parameter.
+ *
+ * The possible values of the "fc" parameter are:
+ * 0: Flow control is completely disabled
+ * 1: Rx flow control is enabled (we can receive pause
+ * frames but not send pause frames).
+ * 2: Tx flow control is enabled (we can send pause frames
+ * frames but we do not receive pause frames).
+ * 3: Both Rx and TX flow control (symmetric) is enabled.
+ * other: No other values should be possible at this point.
+ */
+
+ switch (hw->fc) {
+ case e1000_fc_none:
+ ctrl &= (~(E1000_CTRL_TFCE | E1000_CTRL_RFCE));
+ break;
+ case e1000_fc_rx_pause:
+ ctrl &= (~E1000_CTRL_TFCE);
+ ctrl |= E1000_CTRL_RFCE;
+ break;
+ case e1000_fc_tx_pause:
+ ctrl &= (~E1000_CTRL_RFCE);
+ ctrl |= E1000_CTRL_TFCE;
+ break;
+ case e1000_fc_full:
+ ctrl |= (E1000_CTRL_TFCE | E1000_CTRL_RFCE);
+ break;
+ default:
+ DEBUGOUT("Flow control param set incorrectly\n");
+ return -E1000_ERR_CONFIG;
+ }
+
+ /* Disable TX Flow Control for 82542 (rev 2.0) */
+ if(hw->mac_type == e1000_82542_rev2_0)
+ ctrl &= (~E1000_CTRL_TFCE);
+
+ E1000_WRITE_REG(hw, CTRL, ctrl);
+ return 0;
+}
+
+/******************************************************************************
+ * Configures flow control settings after link is established
+ *
+ * hw - Struct containing variables accessed by shared code
+ *
+ * Should be called immediately after a valid link has been established.
+ * Forces MAC flow control settings if link was forced. When in MII/GMII mode
+ * and autonegotiation is enabled, the MAC flow control settings will be set
+ * based on the flow control negotiated by the PHY. In TBI mode, the TFCE
+ * and RFCE bits will be automaticaly set to the negotiated flow control mode.
+ *****************************************************************************/
+int32_t
+e1000_config_fc_after_link_up(struct e1000_hw *hw)
+{
+ int32_t ret_val;
+ uint16_t mii_status_reg;
+ uint16_t mii_nway_adv_reg;
+ uint16_t mii_nway_lp_ability_reg;
+ uint16_t speed;
+ uint16_t duplex;
+
+ DEBUGFUNC("e1000_config_fc_after_link_up");
+
+ /* Check for the case where we have fiber media and auto-neg failed
+ * so we had to force link. In this case, we need to force the
+ * configuration of the MAC to match the "fc" parameter.
+ */
+ if(((hw->media_type == e1000_media_type_fiber) && (hw->autoneg_failed)) ||
+ ((hw->media_type == e1000_media_type_copper) && (!hw->autoneg))) {
+ ret_val = e1000_force_mac_fc(hw);
+ if(ret_val < 0) {
+ DEBUGOUT("Error forcing flow control settings\n");
+ return ret_val;
+ }
+ }
+
+ /* Check for the case where we have copper media and auto-neg is
+ * enabled. In this case, we need to check and see if Auto-Neg
+ * has completed, and if so, how the PHY and link partner has
+ * flow control configured.
+ */
+ if((hw->media_type == e1000_media_type_copper) && hw->autoneg) {
+ /* Read the MII Status Register and check to see if AutoNeg
+ * has completed. We read this twice because this reg has
+ * some "sticky" (latched) bits.
+ */
+ if(e1000_read_phy_reg(hw, PHY_STATUS, &mii_status_reg) < 0) {
+ DEBUGOUT("PHY Read Error \n");
+ return -E1000_ERR_PHY;
+ }
+ if(e1000_read_phy_reg(hw, PHY_STATUS, &mii_status_reg) < 0) {
+ DEBUGOUT("PHY Read Error \n");
+ return -E1000_ERR_PHY;
+ }
+
+ if(mii_status_reg & MII_SR_AUTONEG_COMPLETE) {
+ /* The AutoNeg process has completed, so we now need to
+ * read both the Auto Negotiation Advertisement Register
+ * (Address 4) and the Auto_Negotiation Base Page Ability
+ * Register (Address 5) to determine how flow control was
+ * negotiated.
+ */
+ if(e1000_read_phy_reg(hw, PHY_AUTONEG_ADV, &mii_nway_adv_reg) < 0) {
+ DEBUGOUT("PHY Read Error\n");
+ return -E1000_ERR_PHY;
+ }
+ if(e1000_read_phy_reg(hw, PHY_LP_ABILITY, &mii_nway_lp_ability_reg) < 0) {
+ DEBUGOUT("PHY Read Error\n");
+ return -E1000_ERR_PHY;
+ }
+
+ /* Two bits in the Auto Negotiation Advertisement Register
+ * (Address 4) and two bits in the Auto Negotiation Base
+ * Page Ability Register (Address 5) determine flow control
+ * for both the PHY and the link partner. The following
+ * table, taken out of the IEEE 802.3ab/D6.0 dated March 25,
+ * 1999, describes these PAUSE resolution bits and how flow
+ * control is determined based upon these settings.
+ * NOTE: DC = Don't Care
+ *
+ * LOCAL DEVICE | LINK PARTNER
+ * PAUSE | ASM_DIR | PAUSE | ASM_DIR | NIC Resolution
+ *-------|---------|-------|---------|--------------------
+ * 0 | 0 | DC | DC | e1000_fc_none
+ * 0 | 1 | 0 | DC | e1000_fc_none
+ * 0 | 1 | 1 | 0 | e1000_fc_none
+ * 0 | 1 | 1 | 1 | e1000_fc_tx_pause
+ * 1 | 0 | 0 | DC | e1000_fc_none
+ * 1 | DC | 1 | DC | e1000_fc_full
+ * 1 | 1 | 0 | 0 | e1000_fc_none
+ * 1 | 1 | 0 | 1 | e1000_fc_rx_pause
+ *
+ */
+ /* Are both PAUSE bits set to 1? If so, this implies
+ * Symmetric Flow Control is enabled at both ends. The
+ * ASM_DIR bits are irrelevant per the spec.
+ *
+ * For Symmetric Flow Control:
+ *
+ * LOCAL DEVICE | LINK PARTNER
+ * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
+ *-------|---------|-------|---------|--------------------
+ * 1 | DC | 1 | DC | e1000_fc_full
+ *
+ */
+ if((mii_nway_adv_reg & NWAY_AR_PAUSE) &&
+ (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE)) {
+ /* Now we need to check if the user selected RX ONLY
+ * of pause frames. In this case, we had to advertise
+ * FULL flow control because we could not advertise RX
+ * ONLY. Hence, we must now check to see if we need to
+ * turn OFF the TRANSMISSION of PAUSE frames.
+ */
+ if(hw->original_fc == e1000_fc_full) {
+ hw->fc = e1000_fc_full;
+ DEBUGOUT("Flow Control = FULL.\r\n");
+ } else {
+ hw->fc = e1000_fc_rx_pause;
+ DEBUGOUT("Flow Control = RX PAUSE frames only.\r\n");
+ }
+ }
+ /* For receiving PAUSE frames ONLY.
+ *
+ * LOCAL DEVICE | LINK PARTNER
+ * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
+ *-------|---------|-------|---------|--------------------
+ * 0 | 1 | 1 | 1 | e1000_fc_tx_pause
+ *
+ */
+ else if(!(mii_nway_adv_reg & NWAY_AR_PAUSE) &&
+ (mii_nway_adv_reg & NWAY_AR_ASM_DIR) &&
+ (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) &&
+ (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) {
+ hw->fc = e1000_fc_tx_pause;
+ DEBUGOUT("Flow Control = TX PAUSE frames only.\r\n");
+ }
+ /* For transmitting PAUSE frames ONLY.
+ *
+ * LOCAL DEVICE | LINK PARTNER
+ * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
+ *-------|---------|-------|---------|--------------------
+ * 1 | 1 | 0 | 1 | e1000_fc_rx_pause
+ *
+ */
+ else if((mii_nway_adv_reg & NWAY_AR_PAUSE) &&
+ (mii_nway_adv_reg & NWAY_AR_ASM_DIR) &&
+ !(mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) &&
+ (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) {
+ hw->fc = e1000_fc_rx_pause;
+ DEBUGOUT("Flow Control = RX PAUSE frames only.\r\n");
+ }
+ /* Per the IEEE spec, at this point flow control should be
+ * disabled. However, we want to consider that we could
+ * be connected to a legacy switch that doesn't advertise
+ * desired flow control, but can be forced on the link
+ * partner. So if we advertised no flow control, that is
+ * what we will resolve to. If we advertised some kind of
+ * receive capability (Rx Pause Only or Full Flow Control)
+ * and the link partner advertised none, we will configure
+ * ourselves to enable Rx Flow Control only. We can do
+ * this safely for two reasons: If the link partner really
+ * didn't want flow control enabled, and we enable Rx, no
+ * harm done since we won't be receiving any PAUSE frames
+ * anyway. If the intent on the link partner was to have
+ * flow control enabled, then by us enabling RX only, we
+ * can at least receive pause frames and process them.
+ * This is a good idea because in most cases, since we are
+ * predominantly a server NIC, more times than not we will
+ * be asked to delay transmission of packets than asking
+ * our link partner to pause transmission of frames.
+ */
+ else if(hw->original_fc == e1000_fc_none ||
+ hw->original_fc == e1000_fc_tx_pause) {
+ hw->fc = e1000_fc_none;
+ DEBUGOUT("Flow Control = NONE.\r\n");
+ } else {
+ hw->fc = e1000_fc_rx_pause;
+ DEBUGOUT("Flow Control = RX PAUSE frames only.\r\n");
+ }
+
+ /* Now we need to do one last check... If we auto-
+ * negotiated to HALF DUPLEX, flow control should not be
+ * enabled per IEEE 802.3 spec.
+ */
+ e1000_get_speed_and_duplex(hw, &speed, &duplex);
+
+ if(duplex == HALF_DUPLEX)
+ hw->fc = e1000_fc_none;
+
+ /* Now we call a subroutine to actually force the MAC
+ * controller to use the correct flow control settings.
+ */
+ ret_val = e1000_force_mac_fc(hw);
+ if(ret_val < 0) {
+ DEBUGOUT("Error forcing flow control settings\n");
+ return ret_val;
+ }
+ } else {
+ DEBUGOUT("Copper PHY and Auto Neg has not completed.\r\n");
+ }
+ }
+ return 0;
+}
+
+/******************************************************************************
+ * Checks to see if the link status of the hardware has changed.
+ *
+ * hw - Struct containing variables accessed by shared code
+ *
+ * Called by any function that needs to check the link status of the adapter.
+ *****************************************************************************/
+int32_t
+e1000_check_for_link(struct e1000_hw *hw)
+{
+ uint32_t rxcw;
+ uint32_t ctrl;
+ uint32_t status;
+ uint32_t rctl;
+ uint32_t signal;
+ int32_t ret_val;
+ uint16_t phy_data;
+ uint16_t lp_capability;
+
+ DEBUGFUNC("e1000_check_for_link");
+
+ /* On adapters with a MAC newer that 82544, SW Defineable pin 1 will be
+ * set when the optics detect a signal. On older adapters, it will be
+ * cleared when there is a signal
+ */
+ if(hw->mac_type > e1000_82544) signal = E1000_CTRL_SWDPIN1;
+ else signal = 0;
+
+ ctrl = E1000_READ_REG(hw, CTRL);
+ status = E1000_READ_REG(hw, STATUS);
+ rxcw = E1000_READ_REG(hw, RXCW);
+
+ /* If we have a copper PHY then we only want to go out to the PHY
+ * registers to see if Auto-Neg has completed and/or if our link
+ * status has changed. The get_link_status flag will be set if we
+ * receive a Link Status Change interrupt or we have Rx Sequence
+ * Errors.
+ */
+ if((hw->media_type == e1000_media_type_copper) && hw->get_link_status) {
+ /* First we want to see if the MII Status Register reports
+ * link. If so, then we want to get the current speed/duplex
+ * of the PHY.
+ * Read the register twice since the link bit is sticky.
+ */
+ if(e1000_read_phy_reg(hw, PHY_STATUS, &phy_data) < 0) {
+ DEBUGOUT("PHY Read Error\n");
+ return -E1000_ERR_PHY;
+ }
+ if(e1000_read_phy_reg(hw, PHY_STATUS, &phy_data) < 0) {
+ DEBUGOUT("PHY Read Error\n");
+ return -E1000_ERR_PHY;
+ }
+
+ if(phy_data & MII_SR_LINK_STATUS) {
+ hw->get_link_status = FALSE;
+ } else {
+ /* No link detected */
+ return 0;
+ }
+
+ /* If we are forcing speed/duplex, then we simply return since
+ * we have already determined whether we have link or not.
+ */
+ if(!hw->autoneg) return -E1000_ERR_CONFIG;
+
+ /* We have a M88E1000 PHY and Auto-Neg is enabled. If we
+ * have Si on board that is 82544 or newer, Auto
+ * Speed Detection takes care of MAC speed/duplex
+ * configuration. So we only need to configure Collision
+ * Distance in the MAC. Otherwise, we need to force
+ * speed/duplex on the MAC to the current PHY speed/duplex
+ * settings.
+ */
+ if(hw->mac_type >= e1000_82544)
+ e1000_config_collision_dist(hw);
+ else {
+ ret_val = e1000_config_mac_to_phy(hw);
+ if(ret_val < 0) {
+ DEBUGOUT("Error configuring MAC to PHY settings\n");
+ return ret_val;
+ }
+ }
+
+ /* Configure Flow Control now that Auto-Neg has completed. First, we
+ * need to restore the desired flow control settings because we may
+ * have had to re-autoneg with a different link partner.
+ */
+ ret_val = e1000_config_fc_after_link_up(hw);
+ if(ret_val < 0) {
+ DEBUGOUT("Error configuring flow control\n");
+ return ret_val;
+ }
+
+ /* At this point we know that we are on copper and we have
+ * auto-negotiated link. These are conditions for checking the link
+ * parter capability register. We use the link partner capability to
+ * determine if TBI Compatibility needs to be turned on or off. If
+ * the link partner advertises any speed in addition to Gigabit, then
+ * we assume that they are GMII-based, and TBI compatibility is not
+ * needed. If no other speeds are advertised, we assume the link
+ * partner is TBI-based, and we turn on TBI Compatibility.
+ */
+ if(hw->tbi_compatibility_en) {
+ if(e1000_read_phy_reg(hw, PHY_LP_ABILITY, &lp_capability) < 0) {
+ DEBUGOUT("PHY Read Error\n");
+ return -E1000_ERR_PHY;
+ }
+ if(lp_capability & (NWAY_LPAR_10T_HD_CAPS |
+ NWAY_LPAR_10T_FD_CAPS |
+ NWAY_LPAR_100TX_HD_CAPS |
+ NWAY_LPAR_100TX_FD_CAPS |
+ NWAY_LPAR_100T4_CAPS)) {
+ /* If our link partner advertises anything in addition to
+ * gigabit, we do not need to enable TBI compatibility.
+ */
+ if(hw->tbi_compatibility_on) {
+ /* If we previously were in the mode, turn it off. */
+ rctl = E1000_READ_REG(hw, RCTL);
+ rctl &= ~E1000_RCTL_SBP;
+ E1000_WRITE_REG(hw, RCTL, rctl);
+ hw->tbi_compatibility_on = FALSE;
+ }
+ } else {
+ /* If TBI compatibility is was previously off, turn it on. For
+ * compatibility with a TBI link partner, we will store bad
+ * packets. Some frames have an additional byte on the end and
+ * will look like CRC errors to to the hardware.
+ */
+ if(!hw->tbi_compatibility_on) {
+ hw->tbi_compatibility_on = TRUE;
+ rctl = E1000_READ_REG(hw, RCTL);
+ rctl |= E1000_RCTL_SBP;
+ E1000_WRITE_REG(hw, RCTL, rctl);
+ }
+ }
+ }
+ }
+ /* If we don't have link (auto-negotiation failed or link partner cannot
+ * auto-negotiate), the cable is plugged in (we have signal), and our
+ * link partner is not trying to auto-negotiate with us (we are receiving
+ * idles or data), we need to force link up. We also need to give
+ * auto-negotiation time to complete, in case the cable was just plugged
+ * in. The autoneg_failed flag does this.
+ */
+ else if((hw->media_type == e1000_media_type_fiber) &&
+ (!(status & E1000_STATUS_LU)) &&
+ ((ctrl & E1000_CTRL_SWDPIN1) == signal) &&
+ (!(rxcw & E1000_RXCW_C))) {
+ if(hw->autoneg_failed == 0) {
+ hw->autoneg_failed = 1;
+ return 0;
+ }
+ DEBUGOUT("NOT RXing /C/, disable AutoNeg and force link.\r\n");
+
+ /* Disable auto-negotiation in the TXCW register */
+ E1000_WRITE_REG(hw, TXCW, (hw->txcw & ~E1000_TXCW_ANE));
+
+ /* Force link-up and also force full-duplex. */
+ ctrl = E1000_READ_REG(hw, CTRL);
+ ctrl |= (E1000_CTRL_SLU | E1000_CTRL_FD);
+ E1000_WRITE_REG(hw, CTRL, ctrl);
+
+ /* Configure Flow Control after forcing link up. */
+ ret_val = e1000_config_fc_after_link_up(hw);
+ if(ret_val < 0) {
+ DEBUGOUT("Error configuring flow control\n");
+ return ret_val;
+ }
+ }
+ /* If we are forcing link and we are receiving /C/ ordered sets, re-enable
+ * auto-negotiation in the TXCW register and disable forced link in the
+ * Device Control register in an attempt to auto-negotiate with our link
+ * partner.
+ */
+ else if((hw->media_type == e1000_media_type_fiber) &&
+ (ctrl & E1000_CTRL_SLU) &&
+ (rxcw & E1000_RXCW_C)) {
+ DEBUGOUT("RXing /C/, enable AutoNeg and stop forcing link.\r\n");
+ E1000_WRITE_REG(hw, TXCW, hw->txcw);
+ E1000_WRITE_REG(hw, CTRL, (ctrl & ~E1000_CTRL_SLU));
+ }
+ return 0;
+}
+
+/******************************************************************************
+ * Detects the current speed and duplex settings of the hardware.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * speed - Speed of the connection
+ * duplex - Duplex setting of the connection
+ *****************************************************************************/
+void
+e1000_get_speed_and_duplex(struct e1000_hw *hw,
+ uint16_t *speed,
+ uint16_t *duplex)
+{
+ uint32_t status;
+
+ DEBUGFUNC("e1000_get_speed_and_duplex");
+
+ if(hw->mac_type >= e1000_82543) {
+ status = E1000_READ_REG(hw, STATUS);
+ if(status & E1000_STATUS_SPEED_1000) {
+ *speed = SPEED_1000;
+ DEBUGOUT("1000 Mbs, ");
+ } else if(status & E1000_STATUS_SPEED_100) {
+ *speed = SPEED_100;
+ DEBUGOUT("100 Mbs, ");
+ } else {
+ *speed = SPEED_10;
+ DEBUGOUT("10 Mbs, ");
+ }
+
+ if(status & E1000_STATUS_FD) {
+ *duplex = FULL_DUPLEX;
+ DEBUGOUT("Full Duplex\r\n");
+ } else {
+ *duplex = HALF_DUPLEX;
+ DEBUGOUT(" Half Duplex\r\n");
+ }
+ } else {
+ DEBUGOUT("1000 Mbs, Full Duplex\r\n");
+ *speed = SPEED_1000;
+ *duplex = FULL_DUPLEX;
+ }
+}
+
+/******************************************************************************
+* Blocks until autoneg completes or times out (~4.5 seconds)
+*
+* hw - Struct containing variables accessed by shared code
+******************************************************************************/
+int32_t
+e1000_wait_autoneg(struct e1000_hw *hw)
+{
+ uint16_t i;
+ uint16_t phy_data;
+
+ DEBUGFUNC("e1000_wait_autoneg");
+ DEBUGOUT("Waiting for Auto-Neg to complete.\n");
+
+ /* We will wait for autoneg to complete or 4.5 seconds to expire. */
+ for(i = PHY_AUTO_NEG_TIME; i > 0; i--) {
+ /* Read the MII Status Register and wait for Auto-Neg
+ * Complete bit to be set.
+ */
+ if(e1000_read_phy_reg(hw, PHY_STATUS, &phy_data) < 0) {
+ DEBUGOUT("PHY Read Error\n");
+ return -E1000_ERR_PHY;
+ }
+ if(e1000_read_phy_reg(hw, PHY_STATUS, &phy_data) < 0) {
+ DEBUGOUT("PHY Read Error\n");
+ return -E1000_ERR_PHY;
+ }
+ if(phy_data & MII_SR_AUTONEG_COMPLETE) {
+ return 0;
+ }
+ msec_delay(100);
+ }
+ return 0;
+}
+
+/******************************************************************************
+* Raises the Management Data Clock
+*
+* hw - Struct containing variables accessed by shared code
+* ctrl - Device control register's current value
+******************************************************************************/
+static void
+e1000_raise_mdi_clk(struct e1000_hw *hw,
+ uint32_t *ctrl)
+{
+ /* Raise the clock input to the Management Data Clock (by setting the MDC
+ * bit), and then delay 2 microseconds.
+ */
+ E1000_WRITE_REG(hw, CTRL, (*ctrl | E1000_CTRL_MDC));
+ usec_delay(2);
+}
+
+/******************************************************************************
+* Lowers the Management Data Clock
+*
+* hw - Struct containing variables accessed by shared code
+* ctrl - Device control register's current value
+******************************************************************************/
+static void
+e1000_lower_mdi_clk(struct e1000_hw *hw,
+ uint32_t *ctrl)
+{
+ /* Lower the clock input to the Management Data Clock (by clearing the MDC
+ * bit), and then delay 2 microseconds.
+ */
+ E1000_WRITE_REG(hw, CTRL, (*ctrl & ~E1000_CTRL_MDC));
+ usec_delay(2);
+}
+
+/******************************************************************************
+* Shifts data bits out to the PHY
+*
+* hw - Struct containing variables accessed by shared code
+* data - Data to send out to the PHY
+* count - Number of bits to shift out
+*
+* Bits are shifted out in MSB to LSB order.
+******************************************************************************/
+static void
+e1000_shift_out_mdi_bits(struct e1000_hw *hw,
+ uint32_t data,
+ uint16_t count)
+{
+ uint32_t ctrl;
+ uint32_t mask;
+
+ /* We need to shift "count" number of bits out to the PHY. So, the value
+ * in the "data" parameter will be shifted out to the PHY one bit at a
+ * time. In order to do this, "data" must be broken down into bits.
+ */
+ mask = 0x01;
+ mask <<= (count - 1);
+
+ ctrl = E1000_READ_REG(hw, CTRL);
+
+ /* Set MDIO_DIR and MDC_DIR direction bits to be used as output pins. */
+ ctrl |= (E1000_CTRL_MDIO_DIR | E1000_CTRL_MDC_DIR);
+
+ while(mask) {
+ /* A "1" is shifted out to the PHY by setting the MDIO bit to "1" and
+ * then raising and lowering the Management Data Clock. A "0" is
+ * shifted out to the PHY by setting the MDIO bit to "0" and then
+ * raising and lowering the clock.
+ */
+ if(data & mask) ctrl |= E1000_CTRL_MDIO;
+ else ctrl &= ~E1000_CTRL_MDIO;
+
+ E1000_WRITE_REG(hw, CTRL, ctrl);
+
+ usec_delay(2);
+
+ e1000_raise_mdi_clk(hw, &ctrl);
+ e1000_lower_mdi_clk(hw, &ctrl);
+
+ mask = mask >> 1;
+ }
+
+ /* Clear the data bit just before leaving this routine. */
+ ctrl &= ~E1000_CTRL_MDIO;
+}
+
+/******************************************************************************
+* Shifts data bits in from the PHY
+*
+* hw - Struct containing variables accessed by shared code
+*
+* Bits are shifted in in MSB to LSB order.
+******************************************************************************/
+static uint16_t
+e1000_shift_in_mdi_bits(struct e1000_hw *hw)
+{
+ uint32_t ctrl;
+ uint16_t data = 0;
+ uint8_t i;
+
+ /* In order to read a register from the PHY, we need to shift in a total
+ * of 18 bits from the PHY. The first two bit (turnaround) times are used
+ * to avoid contention on the MDIO pin when a read operation is performed.
+ * These two bits are ignored by us and thrown away. Bits are "shifted in"
+ * by raising the input to the Management Data Clock (setting the MDC bit),
+ * and then reading the value of the MDIO bit.
+ */
+ ctrl = E1000_READ_REG(hw, CTRL);
+
+ /* Clear MDIO_DIR (SWDPIO1) to indicate this bit is to be used as input. */
+ ctrl &= ~E1000_CTRL_MDIO_DIR;
+ ctrl &= ~E1000_CTRL_MDIO;
+
+ E1000_WRITE_REG(hw, CTRL, ctrl);
+
+ /* Raise and Lower the clock before reading in the data. This accounts for
+ * the turnaround bits. The first clock occurred when we clocked out the
+ * last bit of the Register Address.
+ */
+ e1000_raise_mdi_clk(hw, &ctrl);
+ e1000_lower_mdi_clk(hw, &ctrl);
+
+ for(data = 0, i = 0; i < 16; i++) {
+ data = data << 1;
+ e1000_raise_mdi_clk(hw, &ctrl);
+ ctrl = E1000_READ_REG(hw, CTRL);
+ /* Check to see if we shifted in a "1". */
+ if(ctrl & E1000_CTRL_MDIO) data |= 1;
+ e1000_lower_mdi_clk(hw, &ctrl);
+ }
+
+ e1000_raise_mdi_clk(hw, &ctrl);
+ e1000_lower_mdi_clk(hw, &ctrl);
+
+ /* Clear the MDIO bit just before leaving this routine. */
+ ctrl &= ~E1000_CTRL_MDIO;
+
+ return data;
+}
+
+/*****************************************************************************
+* Reads the value from a PHY register
+*
+* hw - Struct containing variables accessed by shared code
+* reg_addr - address of the PHY register to read
+******************************************************************************/
+int32_t
+e1000_read_phy_reg(struct e1000_hw *hw,
+ uint32_t reg_addr,
+ uint16_t *phy_data)
+{
+ uint32_t i;
+ uint32_t mdic = 0;
+ const uint32_t phy_addr = 1;
+
+ DEBUGFUNC("e1000_read_phy_reg");
+
+ if(reg_addr > MAX_PHY_REG_ADDRESS) {
+ DEBUGOUT1("PHY Address %d is out of range\n", reg_addr);
+ return -E1000_ERR_PARAM;
+ }
+
+ if(hw->mac_type > e1000_82543) {
+ /* Set up Op-code, Phy Address, and register address in the MDI
+ * Control register. The MAC will take care of interfacing with the
+ * PHY to retrieve the desired data.
+ */
+ mdic = ((reg_addr << E1000_MDIC_REG_SHIFT) |
+ (phy_addr << E1000_MDIC_PHY_SHIFT) |
+ (E1000_MDIC_OP_READ));
+
+ E1000_WRITE_REG(hw, MDIC, mdic);
+
+ /* Poll the ready bit to see if the MDI read completed */
+ for(i = 0; i < 64; i++) {
+ usec_delay(10);
+ mdic = E1000_READ_REG(hw, MDIC);
+ if(mdic & E1000_MDIC_READY) break;
+ }
+ if(!(mdic & E1000_MDIC_READY)) {
+ DEBUGOUT("MDI Read did not complete\n");
+ return -E1000_ERR_PHY;
+ }
+ if(mdic & E1000_MDIC_ERROR) {
+ DEBUGOUT("MDI Error\n");
+ return -E1000_ERR_PHY;
+ }
+ *phy_data = (uint16_t) mdic;
+ } else {
+ /* We must first send a preamble through the MDIO pin to signal the
+ * beginning of an MII instruction. This is done by sending 32
+ * consecutive "1" bits.
+ */
+ e1000_shift_out_mdi_bits(hw, PHY_PREAMBLE, PHY_PREAMBLE_SIZE);
+
+ /* Now combine the next few fields that are required for a read
+ * operation. We use this method instead of calling the
+ * e1000_shift_out_mdi_bits routine five different times. The format of
+ * a MII read instruction consists of a shift out of 14 bits and is
+ * defined as follows:
+ * <Preamble><SOF><Op Code><Phy Addr><Reg Addr>
+ * followed by a shift in of 18 bits. This first two bits shifted in
+ * are TurnAround bits used to avoid contention on the MDIO pin when a
+ * READ operation is performed. These two bits are thrown away
+ * followed by a shift in of 16 bits which contains the desired data.
+ */
+ mdic = ((reg_addr) | (phy_addr << 5) |
+ (PHY_OP_READ << 10) | (PHY_SOF << 12));
+
+ e1000_shift_out_mdi_bits(hw, mdic, 14);
+
+ /* Now that we've shifted out the read command to the MII, we need to
+ * "shift in" the 16-bit value (18 total bits) of the requested PHY
+ * register address.
+ */
+ *phy_data = e1000_shift_in_mdi_bits(hw);
+ }
+ return 0;
+}
+
+/******************************************************************************
+* Writes a value to a PHY register
+*
+* hw - Struct containing variables accessed by shared code
+* reg_addr - address of the PHY register to write
+* data - data to write to the PHY
+******************************************************************************/
+int32_t
+e1000_write_phy_reg(struct e1000_hw *hw,
+ uint32_t reg_addr,
+ uint16_t phy_data)
+{
+ uint32_t i;
+ uint32_t mdic = 0;
+ const uint32_t phy_addr = 1;
+
+ DEBUGFUNC("e1000_write_phy_reg");
+
+ if(reg_addr > MAX_PHY_REG_ADDRESS) {
+ DEBUGOUT1("PHY Address %d is out of range\n", reg_addr);
+ return -E1000_ERR_PARAM;
+ }
+
+ if(hw->mac_type > e1000_82543) {
+ /* Set up Op-code, Phy Address, register address, and data intended
+ * for the PHY register in the MDI Control register. The MAC will take
+ * care of interfacing with the PHY to send the desired data.
+ */
+ mdic = (((uint32_t) phy_data) |
+ (reg_addr << E1000_MDIC_REG_SHIFT) |
+ (phy_addr << E1000_MDIC_PHY_SHIFT) |
+ (E1000_MDIC_OP_WRITE));
+
+ E1000_WRITE_REG(hw, MDIC, mdic);
+
+ /* Poll the ready bit to see if the MDI read completed */
+ for(i = 0; i < 64; i++) {
+ usec_delay(10);
+ mdic = E1000_READ_REG(hw, MDIC);
+ if(mdic & E1000_MDIC_READY) break;
+ }
+ if(!(mdic & E1000_MDIC_READY)) {
+ DEBUGOUT("MDI Write did not complete\n");
+ return -E1000_ERR_PHY;
+ }
+ } else {
+ /* We'll need to use the SW defined pins to shift the write command
+ * out to the PHY. We first send a preamble to the PHY to signal the
+ * beginning of the MII instruction. This is done by sending 32
+ * consecutive "1" bits.
+ */
+ e1000_shift_out_mdi_bits(hw, PHY_PREAMBLE, PHY_PREAMBLE_SIZE);
+
+ /* Now combine the remaining required fields that will indicate a
+ * write operation. We use this method instead of calling the
+ * e1000_shift_out_mdi_bits routine for each field in the command. The
+ * format of a MII write instruction is as follows:
+ * <Preamble><SOF><Op Code><Phy Addr><Reg Addr><Turnaround><Data>.
+ */
+ mdic = ((PHY_TURNAROUND) | (reg_addr << 2) | (phy_addr << 7) |
+ (PHY_OP_WRITE << 12) | (PHY_SOF << 14));
+ mdic <<= 16;
+ mdic |= (uint32_t) phy_data;
+
+ e1000_shift_out_mdi_bits(hw, mdic, 32);
+ }
+ return 0;
+}
+
+/******************************************************************************
+* Returns the PHY to the power-on reset state
+*
+* hw - Struct containing variables accessed by shared code
+******************************************************************************/
+void
+e1000_phy_hw_reset(struct e1000_hw *hw)
+{
+ uint32_t ctrl;
+ uint32_t ctrl_ext;
+
+ DEBUGFUNC("e1000_phy_hw_reset");
+
+ DEBUGOUT("Resetting Phy...\n");
+
+ if(hw->mac_type > e1000_82543) {
+ /* Read the device control register and assert the E1000_CTRL_PHY_RST
+ * bit. Then, take it out of reset.
+ */
+ ctrl = E1000_READ_REG(hw, CTRL);
+ E1000_WRITE_REG(hw, CTRL, ctrl | E1000_CTRL_PHY_RST);
+ msec_delay(10);
+ E1000_WRITE_REG(hw, CTRL, ctrl);
+ } else {
+ /* Read the Extended Device Control Register, assert the PHY_RESET_DIR
+ * bit to put the PHY into reset. Then, take it out of reset.
+ */
+ ctrl_ext = E1000_READ_REG(hw, CTRL_EXT);
+ ctrl_ext |= E1000_CTRL_EXT_SDP4_DIR;
+ ctrl_ext &= ~E1000_CTRL_EXT_SDP4_DATA;
+ E1000_WRITE_REG(hw, CTRL_EXT, ctrl_ext);
+ msec_delay(10);
+ ctrl_ext |= E1000_CTRL_EXT_SDP4_DATA;
+ E1000_WRITE_REG(hw, CTRL_EXT, ctrl_ext);
+ }
+ usec_delay(150);
+}
+
+/******************************************************************************
+* Resets the PHY
+*
+* hw - Struct containing variables accessed by shared code
+*
+* Sets bit 15 of the MII Control regiser
+******************************************************************************/
+int32_t
+e1000_phy_reset(struct e1000_hw *hw)
+{
+ uint16_t phy_data;
+
+ DEBUGFUNC("e1000_phy_reset");
+
+ if(e1000_read_phy_reg(hw, PHY_CTRL, &phy_data) < 0) {
+ DEBUGOUT("PHY Read Error\n");
+ return -E1000_ERR_PHY;
+ }
+ phy_data |= MII_CR_RESET;
+ if(e1000_write_phy_reg(hw, PHY_CTRL, phy_data) < 0) {
+ DEBUGOUT("PHY Write Error\n");
+ return -E1000_ERR_PHY;
+ }
+ usec_delay(1);
+ return 0;
+}
+
+/******************************************************************************
+* Probes the expected PHY address for known PHY IDs
+*
+* hw - Struct containing variables accessed by shared code
+******************************************************************************/
+int32_t
+e1000_detect_gig_phy(struct e1000_hw *hw)
+{
+ uint16_t phy_id_high, phy_id_low;
+ boolean_t match = FALSE;
+
+ DEBUGFUNC("e1000_detect_gig_phy");
+
+ /* Read the PHY ID Registers to identify which PHY is onboard. */
+ if(e1000_read_phy_reg(hw, PHY_ID1, &phy_id_high) < 0) {
+ DEBUGOUT("PHY Read Error\n");
+ return -E1000_ERR_PHY;
+ }
+ hw->phy_id = (uint32_t) (phy_id_high << 16);
+ usec_delay(2);
+ if(e1000_read_phy_reg(hw, PHY_ID2, &phy_id_low) < 0) {
+ DEBUGOUT("PHY Read Error\n");
+ return -E1000_ERR_PHY;
+ }
+ hw->phy_id |= (uint32_t) (phy_id_low & PHY_REVISION_MASK);
+
+ switch(hw->mac_type) {
+ case e1000_82543:
+ if(hw->phy_id == M88E1000_E_PHY_ID) match = TRUE;
+ break;
+ case e1000_82544:
+ if(hw->phy_id == M88E1000_I_PHY_ID) match = TRUE;
+ break;
+ case e1000_82540:
+ if(hw->phy_id == M88E1011_I_PHY_ID) match = TRUE;
+ break;
+ default:
+ DEBUGOUT1("Invalid MAC type %d\n", hw->mac_type);
+ return -E1000_ERR_CONFIG;
+ }
+ if(match) {
+ DEBUGOUT1("PHY ID 0x%X detected\n", hw->phy_id);
+ return 0;
+ }
+ DEBUGOUT1("Invalid PHY ID 0x%X\n", hw->phy_id);
+ return -E1000_ERR_PHY;
+}
+
+/******************************************************************************
+* Resets the PHY's DSP
+*
+* hw - Struct containing variables accessed by shared code
+******************************************************************************/
+static int32_t
+e1000_phy_reset_dsp(struct e1000_hw *hw)
+{
+ int32_t ret_val = -E1000_ERR_PHY;
+ DEBUGFUNC("e1000_phy_reset_dsp");
+
+ do {
+ if(e1000_write_phy_reg(hw, 29, 0x1d) < 0) break;
+ if(e1000_write_phy_reg(hw, 30, 0xc1) < 0) break;
+ if(e1000_write_phy_reg(hw, 30, 0x00) < 0) break;
+ ret_val = 0;
+ } while(0);
+
+ if(ret_val < 0) DEBUGOUT("PHY Write Error\n");
+ return ret_val;
+}
+
+/******************************************************************************
+* Get PHY information from various PHY registers
+*
+* hw - Struct containing variables accessed by shared code
+* phy_info - PHY information structure
+******************************************************************************/
+int32_t
+e1000_phy_get_info(struct e1000_hw *hw,
+ struct e1000_phy_info *phy_info)
+{
+ int32_t ret_val = -E1000_ERR_PHY;
+ uint16_t phy_data;
+
+ DEBUGFUNC("e1000_phy_get_info");
+
+ phy_info->cable_length = e1000_cable_length_undefined;
+ phy_info->extended_10bt_distance = e1000_10bt_ext_dist_enable_undefined;
+ phy_info->cable_polarity = e1000_rev_polarity_undefined;
+ phy_info->polarity_correction = e1000_polarity_reversal_undefined;
+ phy_info->mdix_mode = e1000_auto_x_mode_undefined;
+ phy_info->local_rx = e1000_1000t_rx_status_undefined;
+ phy_info->remote_rx = e1000_1000t_rx_status_undefined;
+
+ if(hw->media_type != e1000_media_type_copper) {
+ DEBUGOUT("PHY info is only valid for copper media\n");
+ return -E1000_ERR_CONFIG;
+ }
+
+ do {
+ if(e1000_read_phy_reg(hw, PHY_STATUS, &phy_data) < 0) break;
+ if(e1000_read_phy_reg(hw, PHY_STATUS, &phy_data) < 0) break;
+ if((phy_data & MII_SR_LINK_STATUS) != MII_SR_LINK_STATUS) {
+ DEBUGOUT("PHY info is only valid if link is up\n");
+ return -E1000_ERR_CONFIG;
+ }
+
+ if(e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data) < 0)
+ break;
+ phy_info->extended_10bt_distance =
+ (phy_data & M88E1000_PSCR_10BT_EXT_DIST_ENABLE) >>
+ M88E1000_PSCR_10BT_EXT_DIST_ENABLE_SHIFT;
+ phy_info->polarity_correction =
+ (phy_data & M88E1000_PSCR_POLARITY_REVERSAL) >>
+ M88E1000_PSCR_POLARITY_REVERSAL_SHIFT;
+
+ if(e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data) < 0)
+ break;
+ phy_info->cable_polarity = (phy_data & M88E1000_PSSR_REV_POLARITY) >>
+ M88E1000_PSSR_REV_POLARITY_SHIFT;
+ phy_info->mdix_mode = (phy_data & M88E1000_PSSR_MDIX) >>
+ M88E1000_PSSR_MDIX_SHIFT;
+ if(phy_data & M88E1000_PSSR_1000MBS) {
+ /* Cable Length Estimation and Local/Remote Receiver Informatoion
+ * are only valid at 1000 Mbps
+ */
+ phy_info->cable_length = ((phy_data & M88E1000_PSSR_CABLE_LENGTH) >>
+ M88E1000_PSSR_CABLE_LENGTH_SHIFT);
+ if(e1000_read_phy_reg(hw, PHY_1000T_STATUS, &phy_data) < 0)
+ break;
+ phy_info->local_rx = (phy_data & SR_1000T_LOCAL_RX_STATUS) >>
+ SR_1000T_LOCAL_RX_STATUS_SHIFT;
+ phy_info->remote_rx = (phy_data & SR_1000T_REMOTE_RX_STATUS) >>
+ SR_1000T_REMOTE_RX_STATUS_SHIFT;
+ }
+ ret_val = 0;
+ } while(0);
+
+ if(ret_val < 0) DEBUGOUT("PHY Read Error\n");
+ return ret_val;
+}
+
+int32_t
+e1000_validate_mdi_setting(struct e1000_hw *hw)
+{
+ DEBUGFUNC("e1000_validate_mdi_settings");
+
+ if(!hw->autoneg && (hw->mdix == 0 || hw->mdix == 3)) {
+ DEBUGOUT("Invalid MDI setting detected\n");
+ hw->mdix = 1;
+ return -E1000_ERR_CONFIG;
+ }
+ return 0;
+}
+
+/******************************************************************************
+ * Raises the EEPROM's clock input.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * eecd - EECD's current value
+ *****************************************************************************/
+static void
+e1000_raise_ee_clk(struct e1000_hw *hw,
+ uint32_t *eecd)
+{
+ /* Raise the clock input to the EEPROM (by setting the SK bit), and then
+ * wait 50 microseconds.
+ */
+ *eecd = *eecd | E1000_EECD_SK;
+ E1000_WRITE_REG(hw, EECD, *eecd);
+ usec_delay(50);
+}
+
+/******************************************************************************
+ * Lowers the EEPROM's clock input.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * eecd - EECD's current value
+ *****************************************************************************/
+static void
+e1000_lower_ee_clk(struct e1000_hw *hw,
+ uint32_t *eecd)
+{
+ /* Lower the clock input to the EEPROM (by clearing the SK bit), and then
+ * wait 50 microseconds.
+ */
+ *eecd = *eecd & ~E1000_EECD_SK;
+ E1000_WRITE_REG(hw, EECD, *eecd);
+ usec_delay(50);
+}
+
+/******************************************************************************
+ * Shift data bits out to the EEPROM.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * data - data to send to the EEPROM
+ * count - number of bits to shift out
+ *****************************************************************************/
+static void
+e1000_shift_out_ee_bits(struct e1000_hw *hw,
+ uint16_t data,
+ uint16_t count)
+{
+ uint32_t eecd;
+ uint32_t mask;
+
+ /* We need to shift "count" bits out to the EEPROM. So, value in the
+ * "data" parameter will be shifted out to the EEPROM one bit at a time.
+ * In order to do this, "data" must be broken down into bits.
+ */
+ mask = 0x01 << (count - 1);
+ eecd = E1000_READ_REG(hw, EECD);
+ eecd &= ~(E1000_EECD_DO | E1000_EECD_DI);
+ do {
+ /* A "1" is shifted out to the EEPROM by setting bit "DI" to a "1",
+ * and then raising and then lowering the clock (the SK bit controls
+ * the clock input to the EEPROM). A "0" is shifted out to the EEPROM
+ * by setting "DI" to "0" and then raising and then lowering the clock.
+ */
+ eecd &= ~E1000_EECD_DI;
+
+ if(data & mask)
+ eecd |= E1000_EECD_DI;
+
+ E1000_WRITE_REG(hw, EECD, eecd);
+
+ usec_delay(50);
+
+ e1000_raise_ee_clk(hw, &eecd);
+ e1000_lower_ee_clk(hw, &eecd);
+
+ mask = mask >> 1;
+
+ } while(mask);
+
+ /* We leave the "DI" bit set to "0" when we leave this routine. */
+ eecd &= ~E1000_EECD_DI;
+ E1000_WRITE_REG(hw, EECD, eecd);
+}
+
+/******************************************************************************
+ * Shift data bits in from the EEPROM
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+static uint16_t
+e1000_shift_in_ee_bits(struct e1000_hw *hw)
+{
+ uint32_t eecd;
+ uint32_t i;
+ uint16_t data;
+
+ /* In order to read a register from the EEPROM, we need to shift 16 bits
+ * in from the EEPROM. Bits are "shifted in" by raising the clock input to
+ * the EEPROM (setting the SK bit), and then reading the value of the "DO"
+ * bit. During this "shifting in" process the "DI" bit should always be
+ * clear..
+ */
+
+ eecd = E1000_READ_REG(hw, EECD);
+
+ eecd &= ~(E1000_EECD_DO | E1000_EECD_DI);
+ data = 0;
+
+ for(i = 0; i < 16; i++) {
+ data = data << 1;
+ e1000_raise_ee_clk(hw, &eecd);
+
+ eecd = E1000_READ_REG(hw, EECD);
+
+ eecd &= ~(E1000_EECD_DI);
+ if(eecd & E1000_EECD_DO)
+ data |= 1;
+
+ e1000_lower_ee_clk(hw, &eecd);
+ }
+
+ return data;
+}
+
+/******************************************************************************
+ * Prepares EEPROM for access
+ *
+ * hw - Struct containing variables accessed by shared code
+ *
+ * Lowers EEPROM clock. Clears input pin. Sets the chip select pin. This
+ * function should be called before issuing a command to the EEPROM.
+ *****************************************************************************/
+static void
+e1000_setup_eeprom(struct e1000_hw *hw)
+{
+ uint32_t eecd;
+
+ eecd = E1000_READ_REG(hw, EECD);
+
+ /* Clear SK and DI */
+ eecd &= ~(E1000_EECD_SK | E1000_EECD_DI);
+ E1000_WRITE_REG(hw, EECD, eecd);
+
+ /* Set CS */
+ eecd |= E1000_EECD_CS;
+ E1000_WRITE_REG(hw, EECD, eecd);
+}
+
+/******************************************************************************
+ * Returns EEPROM to a "standby" state
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+static void
+e1000_standby_eeprom(struct e1000_hw *hw)
+{
+ uint32_t eecd;
+
+ eecd = E1000_READ_REG(hw, EECD);
+
+ /* Deselct EEPROM */
+ eecd &= ~(E1000_EECD_CS | E1000_EECD_SK);
+ E1000_WRITE_REG(hw, EECD, eecd);
+ usec_delay(50);
+
+ /* Clock high */
+ eecd |= E1000_EECD_SK;
+ E1000_WRITE_REG(hw, EECD, eecd);
+ usec_delay(50);
+
+ /* Select EEPROM */
+ eecd |= E1000_EECD_CS;
+ E1000_WRITE_REG(hw, EECD, eecd);
+ usec_delay(50);
+
+ /* Clock low */
+ eecd &= ~E1000_EECD_SK;
+ E1000_WRITE_REG(hw, EECD, eecd);
+ usec_delay(50);
+}
+
+
+/******************************************************************************
+ * Reads a 16 bit word from the EEPROM.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * offset - offset of word in the EEPROM to read
+ * data - word read from the EEPROM
+ *****************************************************************************/
+int32_t
+e1000_read_eeprom(struct e1000_hw *hw,
+ uint16_t offset,
+ uint16_t *data)
+{
+ uint32_t eecd;
+ uint32_t i = 0;
+ boolean_t large_eeprom = FALSE;
+
+ DEBUGFUNC("e1000_read_eeprom");
+
+ /* Request EEPROM Access */
+ if(hw->mac_type > e1000_82544) {
+ eecd = E1000_READ_REG(hw, EECD);
+ if(eecd & E1000_EECD_SIZE) large_eeprom = TRUE;
+ eecd |= E1000_EECD_REQ;
+ E1000_WRITE_REG(hw, EECD, eecd);
+ eecd = E1000_READ_REG(hw, EECD);
+ while((!(eecd & E1000_EECD_GNT)) && (i < 100)) {
+ i++;
+ usec_delay(5);
+ eecd = E1000_READ_REG(hw, EECD);
+ }
+ if(!(eecd & E1000_EECD_GNT)) {
+ eecd &= ~E1000_EECD_REQ;
+ E1000_WRITE_REG(hw, EECD, eecd);
+ DEBUGOUT("Could not acquire EEPROM grant\n");
+ return -E1000_ERR_EEPROM;
+ }
+ }
+
+ /* Prepare the EEPROM for reading */
+ e1000_setup_eeprom(hw);
+
+ /* Send the READ command (opcode + addr) */
+ e1000_shift_out_ee_bits(hw, EEPROM_READ_OPCODE, 3);
+ if(large_eeprom) {
+ /* If we have a 256 word EEPROM, there are 8 address bits */
+ e1000_shift_out_ee_bits(hw, offset, 8);
+ } else {
+ /* If we have a 64 word EEPROM, there are 6 address bits */
+ e1000_shift_out_ee_bits(hw, offset, 6);
+ }
+
+ /* Read the data */
+ *data = e1000_shift_in_ee_bits(hw);
+
+ /* End this read operation */
+ e1000_standby_eeprom(hw);
+
+ /* Stop requesting EEPROM access */
+ if(hw->mac_type > e1000_82544) {
+ eecd = E1000_READ_REG(hw, EECD);
+ eecd &= ~E1000_EECD_REQ;
+ E1000_WRITE_REG(hw, EECD, eecd);
+ }
+
+ return 0;
+}
+
+/******************************************************************************
+ * Verifies that the EEPROM has a valid checksum
+ *
+ * hw - Struct containing variables accessed by shared code
+ *
+ * Reads the first 64 16 bit words of the EEPROM and sums the values read.
+ * If the the sum of the 64 16 bit words is 0xBABA, the EEPROM's checksum is
+ * valid.
+ *****************************************************************************/
+int32_t
+e1000_validate_eeprom_checksum(struct e1000_hw *hw)
+{
+ uint16_t checksum = 0;
+ uint16_t i, eeprom_data;
+
+ DEBUGFUNC("e1000_validate_eeprom_checksum");
+
+ for(i = 0; i < (EEPROM_CHECKSUM_REG + 1); i++) {
+ if(e1000_read_eeprom(hw, i, &eeprom_data) < 0) {
+ DEBUGOUT("EEPROM Read Error\n");
+ return -E1000_ERR_EEPROM;
+ }
+ checksum += eeprom_data;
+ }
+
+ if(checksum == (uint16_t) EEPROM_SUM) {
+ return 0;
+ } else {
+ DEBUGOUT("EEPROM Checksum Invalid\n");
+ return -E1000_ERR_EEPROM;
+ }
+}
+
+/******************************************************************************
+ * Reads the adapter's part number from the EEPROM
+ *
+ * hw - Struct containing variables accessed by shared code
+ * part_num - Adapter's part number
+ *****************************************************************************/
+int32_t
+e1000_read_part_num(struct e1000_hw *hw,
+ uint32_t *part_num)
+{
+ uint16_t offset = EEPROM_PBA_BYTE_1;
+ uint16_t eeprom_data;
+
+ DEBUGFUNC("e1000_read_part_num");
+
+ /* Get word 0 from EEPROM */
+ if(e1000_read_eeprom(hw, offset, &eeprom_data) < 0) {
+ DEBUGOUT("EEPROM Read Error\n");
+ return -E1000_ERR_EEPROM;
+ }
+ /* Save word 0 in upper half of part_num */
+ *part_num = (uint32_t) (eeprom_data << 16);
+
+ /* Get word 1 from EEPROM */
+ if(e1000_read_eeprom(hw, ++offset, &eeprom_data) < 0) {
+ DEBUGOUT("EEPROM Read Error\n");
+ return -E1000_ERR_EEPROM;
+ }
+ /* Save word 1 in lower half of part_num */
+ *part_num |= eeprom_data;
+
+ return 0;
+}
+
+/******************************************************************************
+ * Reads the adapter's MAC address from the EEPROM and inverts the LSB for the
+ * second function of dual function devices
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+int32_t
+e1000_read_mac_addr(struct e1000_hw * hw)
+{
+ uint16_t offset;
+ uint16_t eeprom_data, i;
+
+ DEBUGFUNC("e1000_read_mac_addr");
+
+ for(i = 0; i < NODE_ADDRESS_SIZE; i += 2) {
+ offset = i >> 1;
+ if(e1000_read_eeprom(hw, offset, &eeprom_data) < 0) {
+ DEBUGOUT("EEPROM Read Error\n");
+ return -E1000_ERR_EEPROM;
+ }
+ hw->perm_mac_addr[i] = (uint8_t) (eeprom_data & 0x00FF);
+ hw->perm_mac_addr[i+1] = (uint8_t) (eeprom_data >> 8);
+ }
+ for(i = 0; i < NODE_ADDRESS_SIZE; i++)
+ hw->mac_addr[i] = hw->perm_mac_addr[i];
+ return 0;
+}
+
+/******************************************************************************
+ * Initializes receive address filters.
+ *
+ * hw - Struct containing variables accessed by shared code
+ *
+ * Places the MAC address in receive address register 0 and clears the rest
+ * of the receive addresss registers. Clears the multicast table. Assumes
+ * the receiver is in reset when the routine is called.
+ *****************************************************************************/
+void
+e1000_init_rx_addrs(struct e1000_hw *hw)
+{
+ uint32_t i;
+ uint32_t addr_low;
+ uint32_t addr_high;
+
+ DEBUGFUNC("e1000_init_rx_addrs");
+
+ /* Setup the receive address. */
+ DEBUGOUT("Programming MAC Address into RAR[0]\n");
+ addr_low = (hw->mac_addr[0] |
+ (hw->mac_addr[1] << 8) |
+ (hw->mac_addr[2] << 16) | (hw->mac_addr[3] << 24));
+
+ addr_high = (hw->mac_addr[4] |
+ (hw->mac_addr[5] << 8) | E1000_RAH_AV);
+
+ E1000_WRITE_REG_ARRAY(hw, RA, 0, addr_low);
+ E1000_WRITE_REG_ARRAY(hw, RA, 1, addr_high);
+
+ /* Zero out the other 15 receive addresses. */
+ DEBUGOUT("Clearing RAR[1-15]\n");
+ for(i = 1; i < E1000_RAR_ENTRIES; i++) {
+ E1000_WRITE_REG_ARRAY(hw, RA, (i << 1), 0);
+ E1000_WRITE_REG_ARRAY(hw, RA, ((i << 1) + 1), 0);
+ }
+}
+
+/******************************************************************************
+ * Updates the MAC's list of multicast addresses.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * mc_addr_list - the list of new multicast addresses
+ * mc_addr_count - number of addresses
+ * pad - number of bytes between addresses in the list
+ *
+ * The given list replaces any existing list. Clears the last 15 receive
+ * address registers and the multicast table. Uses receive address registers
+ * for the first 15 multicast addresses, and hashes the rest into the
+ * multicast table.
+ *****************************************************************************/
+void
+e1000_mc_addr_list_update(struct e1000_hw *hw,
+ uint8_t *mc_addr_list,
+ uint32_t mc_addr_count,
+ uint32_t pad)
+{
+ uint32_t hash_value;
+ uint32_t i;
+ uint32_t rar_used_count = 1; /* RAR[0] is used for our MAC address */
+
+ DEBUGFUNC("e1000_mc_addr_list_update");
+
+ /* Set the new number of MC addresses that we are being requested to use. */
+ hw->num_mc_addrs = mc_addr_count;
+
+ /* Clear RAR[1-15] */
+ DEBUGOUT(" Clearing RAR[1-15]\n");
+ for(i = rar_used_count; i < E1000_RAR_ENTRIES; i++) {
+ E1000_WRITE_REG_ARRAY(hw, RA, (i << 1), 0);
+ E1000_WRITE_REG_ARRAY(hw, RA, ((i << 1) + 1), 0);
+ }
+
+ /* Clear the MTA */
+ DEBUGOUT(" Clearing MTA\n");
+ for(i = 0; i < E1000_NUM_MTA_REGISTERS; i++) {
+ E1000_WRITE_REG_ARRAY(hw, MTA, i, 0);
+ }
+
+ /* Add the new addresses */
+ for(i = 0; i < mc_addr_count; i++) {
+ DEBUGOUT(" Adding the multicast addresses:\n");
+ DEBUGOUT7(" MC Addr #%d =%.2X %.2X %.2X %.2X %.2X %.2X\n", i,
+ mc_addr_list[i * (ETH_LENGTH_OF_ADDRESS + pad)],
+ mc_addr_list[i * (ETH_LENGTH_OF_ADDRESS + pad) + 1],
+ mc_addr_list[i * (ETH_LENGTH_OF_ADDRESS + pad) + 2],
+ mc_addr_list[i * (ETH_LENGTH_OF_ADDRESS + pad) + 3],
+ mc_addr_list[i * (ETH_LENGTH_OF_ADDRESS + pad) + 4],
+ mc_addr_list[i * (ETH_LENGTH_OF_ADDRESS + pad) + 5]);
+
+ hash_value = e1000_hash_mc_addr(hw,
+ mc_addr_list +
+ (i * (ETH_LENGTH_OF_ADDRESS + pad)));
+
+ DEBUGOUT1(" Hash value = 0x%03X\n", hash_value);
+
+ /* Place this multicast address in the RAR if there is room, *
+ * else put it in the MTA
+ */
+ if(rar_used_count < E1000_RAR_ENTRIES) {
+ e1000_rar_set(hw,
+ mc_addr_list + (i * (ETH_LENGTH_OF_ADDRESS + pad)),
+ rar_used_count);
+ rar_used_count++;
+ } else {
+ e1000_mta_set(hw, hash_value);
+ }
+ }
+ DEBUGOUT("MC Update Complete\n");
+}
+
+/******************************************************************************
+ * Hashes an address to determine its location in the multicast table
+ *
+ * hw - Struct containing variables accessed by shared code
+ * mc_addr - the multicast address to hash
+ *****************************************************************************/
+uint32_t
+e1000_hash_mc_addr(struct e1000_hw *hw,
+ uint8_t *mc_addr)
+{
+ uint32_t hash_value = 0;
+
+ /* The portion of the address that is used for the hash table is
+ * determined by the mc_filter_type setting.
+ */
+ switch (hw->mc_filter_type) {
+ /* [0] [1] [2] [3] [4] [5]
+ * 01 AA 00 12 34 56
+ * LSB MSB
+ */
+ case 0:
+ /* [47:36] i.e. 0x563 for above example address */
+ hash_value = ((mc_addr[4] >> 4) | (((uint16_t) mc_addr[5]) << 4));
+ break;
+ case 1:
+ /* [46:35] i.e. 0xAC6 for above example address */
+ hash_value = ((mc_addr[4] >> 3) | (((uint16_t) mc_addr[5]) << 5));
+ break;
+ case 2:
+ /* [45:34] i.e. 0x5D8 for above example address */
+ hash_value = ((mc_addr[4] >> 2) | (((uint16_t) mc_addr[5]) << 6));
+ break;
+ case 3:
+ /* [43:32] i.e. 0x634 for above example address */
+ hash_value = ((mc_addr[4]) | (((uint16_t) mc_addr[5]) << 8));
+ break;
+ }
+
+ hash_value &= 0xFFF;
+ return hash_value;
+}
+
+/******************************************************************************
+ * Sets the bit in the multicast table corresponding to the hash value.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * hash_value - Multicast address hash value
+ *****************************************************************************/
+void
+e1000_mta_set(struct e1000_hw *hw,
+ uint32_t hash_value)
+{
+ uint32_t hash_bit, hash_reg;
+ uint32_t mta;
+ uint32_t temp;
+
+ /* The MTA is a register array of 128 32-bit registers.
+ * It is treated like an array of 4096 bits. We want to set
+ * bit BitArray[hash_value]. So we figure out what register
+ * the bit is in, read it, OR in the new bit, then write
+ * back the new value. The register is determined by the
+ * upper 7 bits of the hash value and the bit within that
+ * register are determined by the lower 5 bits of the value.
+ */
+ hash_reg = (hash_value >> 5) & 0x7F;
+ hash_bit = hash_value & 0x1F;
+
+ mta = E1000_READ_REG_ARRAY(hw, MTA, hash_reg);
+
+ mta |= (1 << hash_bit);
+
+ /* If we are on an 82544 and we are trying to write an odd offset
+ * in the MTA, save off the previous entry before writing and
+ * restore the old value after writing.
+ */
+ if((hw->mac_type == e1000_82544) && ((hash_reg & 0x1) == 1)) {
+ temp = E1000_READ_REG_ARRAY(hw, MTA, (hash_reg - 1));
+ E1000_WRITE_REG_ARRAY(hw, MTA, hash_reg, mta);
+ E1000_WRITE_REG_ARRAY(hw, MTA, (hash_reg - 1), temp);
+ } else {
+ E1000_WRITE_REG_ARRAY(hw, MTA, hash_reg, mta);
+ }
+}
+
+/******************************************************************************
+ * Puts an ethernet address into a receive address register.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * addr - Address to put into receive address register
+ * index - Receive address register to write
+ *****************************************************************************/
+void
+e1000_rar_set(struct e1000_hw *hw,
+ uint8_t *addr,
+ uint32_t index)
+{
+ uint32_t rar_low, rar_high;
+
+ /* HW expects these in little endian so we reverse the byte order
+ * from network order (big endian) to little endian
+ */
+ rar_low = ((uint32_t) addr[0] |
+ ((uint32_t) addr[1] << 8) |
+ ((uint32_t) addr[2] << 16) | ((uint32_t) addr[3] << 24));
+
+ rar_high = ((uint32_t) addr[4] | ((uint32_t) addr[5] << 8) | E1000_RAH_AV);
+
+ E1000_WRITE_REG_ARRAY(hw, RA, (index << 1), rar_low);
+ E1000_WRITE_REG_ARRAY(hw, RA, ((index << 1) + 1), rar_high);
+}
+
+/******************************************************************************
+ * Writes a value to the specified offset in the VLAN filter table.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * offset - Offset in VLAN filer table to write
+ * value - Value to write into VLAN filter table
+ *****************************************************************************/
+void
+e1000_write_vfta(struct e1000_hw *hw,
+ uint32_t offset,
+ uint32_t value)
+{
+ uint32_t temp;
+
+ if((hw->mac_type == e1000_82544) && ((offset & 0x1) == 1)) {
+ temp = E1000_READ_REG_ARRAY(hw, VFTA, (offset - 1));
+ E1000_WRITE_REG_ARRAY(hw, VFTA, offset, value);
+ E1000_WRITE_REG_ARRAY(hw, VFTA, (offset - 1), temp);
+ } else {
+ E1000_WRITE_REG_ARRAY(hw, VFTA, offset, value);
+ }
+}
+
+/******************************************************************************
+ * Clears the VLAN filer table
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+void
+e1000_clear_vfta(struct e1000_hw *hw)
+{
+ uint32_t offset;
+
+ for(offset = 0; offset < E1000_VLAN_FILTER_TBL_SIZE; offset++)
+ E1000_WRITE_REG_ARRAY(hw, VFTA, offset, 0);
+}
+
+/******************************************************************************
+ * Prepares SW controlable LED for use and saves the current state of the LED.
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+int32_t
+e1000_setup_led(struct e1000_hw *hw)
+{
+ uint32_t ledctl;
+
+ DEBUGFUNC("e1000_setup_led");
+
+ switch(hw->device_id) {
+ case E1000_DEV_ID_82542:
+ case E1000_DEV_ID_82543GC_FIBER:
+ case E1000_DEV_ID_82543GC_COPPER:
+ case E1000_DEV_ID_82544EI_COPPER:
+ case E1000_DEV_ID_82544EI_FIBER:
+ case E1000_DEV_ID_82544GC_COPPER:
+ case E1000_DEV_ID_82544GC_LOM:
+ /* No setup necessary */
+ break;
+ case E1000_DEV_ID_82540EM:
+ case E1000_DEV_ID_82540EM_LOM:
+ ledctl = E1000_READ_REG(hw, LEDCTL);
+ /* Save current LEDCTL settings */
+ hw->ledctl = ledctl;
+ /* Turn off LED2 and LED3 */
+ ledctl &= ~(E1000_LEDCTL_LED2_IVRT |
+ E1000_LEDCTL_LED2_BLINK |
+ E1000_LEDCTL_LED2_MODE_MASK);
+ ledctl |= (E1000_LEDCTL_MODE_LED_OFF << E1000_LEDCTL_LED2_MODE_SHIFT);
+ ledctl &= ~(E1000_LEDCTL_LED3_IVRT |
+ E1000_LEDCTL_LED3_BLINK |
+ E1000_LEDCTL_LED3_MODE_MASK);
+ ledctl |= (E1000_LEDCTL_MODE_LED_OFF << E1000_LEDCTL_LED3_MODE_SHIFT);
+ E1000_WRITE_REG(hw, LEDCTL, ledctl);
+ break;
+ default:
+ DEBUGOUT("Invalid device ID\n");
+ return -E1000_ERR_CONFIG;
+ }
+ return 0;
+}
+
+/******************************************************************************
+ * Restores the saved state of the SW controlable LED.
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+int32_t
+e1000_cleanup_led(struct e1000_hw *hw)
+{
+ DEBUGFUNC("e1000_cleanup_led");
+
+ switch(hw->device_id) {
+ case E1000_DEV_ID_82542:
+ case E1000_DEV_ID_82543GC_FIBER:
+ case E1000_DEV_ID_82543GC_COPPER:
+ case E1000_DEV_ID_82544EI_COPPER:
+ case E1000_DEV_ID_82544EI_FIBER:
+ case E1000_DEV_ID_82544GC_COPPER:
+ case E1000_DEV_ID_82544GC_LOM:
+ /* No cleanup necessary */
+ break;
+ case E1000_DEV_ID_82540EM:
+ case E1000_DEV_ID_82540EM_LOM:
+ /* Restore LEDCTL settings */
+ E1000_WRITE_REG(hw, LEDCTL, hw->ledctl);
+ break;
+ default:
+ DEBUGOUT("Invalid device ID\n");
+ return -E1000_ERR_CONFIG;
+ }
+ return 0;
+}
+
+/******************************************************************************
+ * Turns on the software controllable LED
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+int32_t
+e1000_led_on(struct e1000_hw *hw)
+{
+ uint32_t ctrl;
+ uint32_t ledctl;
+
+ DEBUGFUNC("e1000_led_on");
+
+ switch(hw->device_id) {
+ case E1000_DEV_ID_82542:
+ case E1000_DEV_ID_82543GC_FIBER:
+ case E1000_DEV_ID_82543GC_COPPER:
+ case E1000_DEV_ID_82544EI_FIBER:
+ ctrl = E1000_READ_REG(hw, CTRL);
+ /* Set SW Defineable Pin 0 to turn on the LED */
+ ctrl |= E1000_CTRL_SWDPIN0;
+ ctrl |= E1000_CTRL_SWDPIO0;
+ E1000_WRITE_REG(hw, CTRL, ctrl);
+ break;
+ case E1000_DEV_ID_82544EI_COPPER:
+ case E1000_DEV_ID_82544GC_COPPER:
+ case E1000_DEV_ID_82544GC_LOM:
+ ctrl = E1000_READ_REG(hw, CTRL);
+ /* Clear SW Defineable Pin 0 to turn on the LED */
+ ctrl &= ~E1000_CTRL_SWDPIN0;
+ ctrl |= E1000_CTRL_SWDPIO0;
+ E1000_WRITE_REG(hw, CTRL, ctrl);
+ break;
+ case E1000_DEV_ID_82540EM:
+ case E1000_DEV_ID_82540EM_LOM:
+ ledctl = E1000_READ_REG(hw, LEDCTL);
+ /* Set LED 3 mode to on */
+ ledctl &= ~E1000_LEDCTL_LED3_MODE_MASK;
+ ledctl |= (E1000_LEDCTL_MODE_LED_ON << E1000_LEDCTL_LED3_MODE_SHIFT);
+ E1000_WRITE_REG(hw, LEDCTL, ledctl);
+ break;
+ default:
+ DEBUGOUT("Invalid device ID\n");
+ return -E1000_ERR_CONFIG;
+ }
+ return 0;
+}
+
+/******************************************************************************
+ * Turns off the software controllable LED
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+int32_t
+e1000_led_off(struct e1000_hw *hw)
+{
+ uint32_t ctrl;
+ uint32_t ledctl;
+
+ DEBUGFUNC("e1000_led_off");
+
+ switch(hw->device_id) {
+ case E1000_DEV_ID_82542:
+ case E1000_DEV_ID_82543GC_FIBER:
+ case E1000_DEV_ID_82543GC_COPPER:
+ case E1000_DEV_ID_82544EI_FIBER:
+ ctrl = E1000_READ_REG(hw, CTRL);
+ /* Clear SW Defineable Pin 0 to turn off the LED */
+ ctrl &= ~E1000_CTRL_SWDPIN0;
+ ctrl |= E1000_CTRL_SWDPIO0;
+ E1000_WRITE_REG(hw, CTRL, ctrl);
+ break;
+ case E1000_DEV_ID_82544EI_COPPER:
+ case E1000_DEV_ID_82544GC_COPPER:
+ case E1000_DEV_ID_82544GC_LOM:
+ ctrl = E1000_READ_REG(hw, CTRL);
+ /* Set SW Defineable Pin 0 to turn off the LED */
+ ctrl |= E1000_CTRL_SWDPIN0;
+ ctrl |= E1000_CTRL_SWDPIO0;
+ E1000_WRITE_REG(hw, CTRL, ctrl);
+ break;
+ case E1000_DEV_ID_82540EM:
+ case E1000_DEV_ID_82540EM_LOM:
+ ledctl = E1000_READ_REG(hw, LEDCTL);
+ /* Set LED 3 mode to off */
+ ledctl &= ~E1000_LEDCTL_LED3_MODE_MASK;
+ ledctl |= (E1000_LEDCTL_MODE_LED_OFF << E1000_LEDCTL_LED3_MODE_SHIFT);
+ E1000_WRITE_REG(hw, LEDCTL, ledctl);
+ break;
+ default:
+ DEBUGOUT("Invalid device ID\n");
+ return -E1000_ERR_CONFIG;
+ }
+ return 0;
+}
+
+/******************************************************************************
+ * Clears all hardware statistics counters.
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+void
+e1000_clear_hw_cntrs(struct e1000_hw *hw)
+{
+ volatile uint32_t temp;
+
+ temp = E1000_READ_REG(hw, CRCERRS);
+ temp = E1000_READ_REG(hw, SYMERRS);
+ temp = E1000_READ_REG(hw, MPC);
+ temp = E1000_READ_REG(hw, SCC);
+ temp = E1000_READ_REG(hw, ECOL);
+ temp = E1000_READ_REG(hw, MCC);
+ temp = E1000_READ_REG(hw, LATECOL);
+ temp = E1000_READ_REG(hw, COLC);
+ temp = E1000_READ_REG(hw, DC);
+ temp = E1000_READ_REG(hw, SEC);
+ temp = E1000_READ_REG(hw, RLEC);
+ temp = E1000_READ_REG(hw, XONRXC);
+ temp = E1000_READ_REG(hw, XONTXC);
+ temp = E1000_READ_REG(hw, XOFFRXC);
+ temp = E1000_READ_REG(hw, XOFFTXC);
+ temp = E1000_READ_REG(hw, FCRUC);
+ temp = E1000_READ_REG(hw, PRC64);
+ temp = E1000_READ_REG(hw, PRC127);
+ temp = E1000_READ_REG(hw, PRC255);
+ temp = E1000_READ_REG(hw, PRC511);
+ temp = E1000_READ_REG(hw, PRC1023);
+ temp = E1000_READ_REG(hw, PRC1522);
+ temp = E1000_READ_REG(hw, GPRC);
+ temp = E1000_READ_REG(hw, BPRC);
+ temp = E1000_READ_REG(hw, MPRC);
+ temp = E1000_READ_REG(hw, GPTC);
+ temp = E1000_READ_REG(hw, GORCL);
+ temp = E1000_READ_REG(hw, GORCH);
+ temp = E1000_READ_REG(hw, GOTCL);
+ temp = E1000_READ_REG(hw, GOTCH);
+ temp = E1000_READ_REG(hw, RNBC);
+ temp = E1000_READ_REG(hw, RUC);
+ temp = E1000_READ_REG(hw, RFC);
+ temp = E1000_READ_REG(hw, ROC);
+ temp = E1000_READ_REG(hw, RJC);
+ temp = E1000_READ_REG(hw, TORL);
+ temp = E1000_READ_REG(hw, TORH);
+ temp = E1000_READ_REG(hw, TOTL);
+ temp = E1000_READ_REG(hw, TOTH);
+ temp = E1000_READ_REG(hw, TPR);
+ temp = E1000_READ_REG(hw, TPT);
+ temp = E1000_READ_REG(hw, PTC64);
+ temp = E1000_READ_REG(hw, PTC127);
+ temp = E1000_READ_REG(hw, PTC255);
+ temp = E1000_READ_REG(hw, PTC511);
+ temp = E1000_READ_REG(hw, PTC1023);
+ temp = E1000_READ_REG(hw, PTC1522);
+ temp = E1000_READ_REG(hw, MPTC);
+ temp = E1000_READ_REG(hw, BPTC);
+
+ if(hw->mac_type < e1000_82543) return;
+
+ temp = E1000_READ_REG(hw, ALGNERRC);
+ temp = E1000_READ_REG(hw, RXERRC);
+ temp = E1000_READ_REG(hw, TNCRS);
+ temp = E1000_READ_REG(hw, CEXTERR);
+ temp = E1000_READ_REG(hw, TSCTC);
+ temp = E1000_READ_REG(hw, TSCTFC);
+
+ if(hw->mac_type <= e1000_82544) return;
+
+ temp = E1000_READ_REG(hw, MGTPRC);
+ temp = E1000_READ_REG(hw, MGTPDC);
+ temp = E1000_READ_REG(hw, MGTPTC);
+}
+
+/******************************************************************************
+ * Resets Adaptive IFS to its default state.
+ *
+ * hw - Struct containing variables accessed by shared code
+ *
+ * Call this after e1000_init_hw. You may override the IFS defaults by setting
+ * hw->ifs_params_forced to TRUE. However, you must initialize hw->
+ * current_ifs_val, ifs_min_val, ifs_max_val, ifs_step_size, and ifs_ratio
+ * before calling this function.
+ *****************************************************************************/
+void
+e1000_reset_adaptive(struct e1000_hw *hw)
+{
+ DEBUGFUNC("e1000_reset_adaptive");
+
+ if(hw->adaptive_ifs) {
+ if(!hw->ifs_params_forced) {
+ hw->current_ifs_val = 0;
+ hw->ifs_min_val = IFS_MIN;
+ hw->ifs_max_val = IFS_MAX;
+ hw->ifs_step_size = IFS_STEP;
+ hw->ifs_ratio = IFS_RATIO;
+ }
+ hw->in_ifs_mode = FALSE;
+ E1000_WRITE_REG(hw, AIT, 0);
+ } else {
+ DEBUGOUT("Not in Adaptive IFS mode!\n");
+ }
+}
+
+/******************************************************************************
+ * Called during the callback/watchdog routine to update IFS value based on
+ * the ratio of transmits to collisions.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * tx_packets - Number of transmits since last callback
+ * total_collisions - Number of collisions since last callback
+ *****************************************************************************/
+void
+e1000_update_adaptive(struct e1000_hw *hw)
+{
+ DEBUGFUNC("e1000_update_adaptive");
+
+ if(hw->adaptive_ifs) {
+ if((hw->collision_delta * hw->ifs_ratio) >
+ hw->tx_packet_delta) {
+ if(hw->tx_packet_delta > MIN_NUM_XMITS) {
+ hw->in_ifs_mode = TRUE;
+ if(hw->current_ifs_val < hw->ifs_max_val) {
+ if(hw->current_ifs_val == 0)
+ hw->current_ifs_val = hw->ifs_min_val;
+ else
+ hw->current_ifs_val += hw->ifs_step_size;
+ E1000_WRITE_REG(hw, AIT, hw->current_ifs_val);
+ }
+ }
+ } else {
+ if((hw->in_ifs_mode == TRUE) &&
+ (hw->tx_packet_delta <= MIN_NUM_XMITS)) {
+ hw->current_ifs_val = 0;
+ hw->in_ifs_mode = FALSE;
+ E1000_WRITE_REG(hw, AIT, 0);
+ }
+ }
+ } else {
+ DEBUGOUT("Not in Adaptive IFS mode!\n");
+ }
+}
+
+/******************************************************************************
+ * Adjusts the statistic counters when a frame is accepted by TBI_ACCEPT
+ *
+ * hw - Struct containing variables accessed by shared code
+ * frame_len - The length of the frame in question
+ * mac_addr - The Ethernet destination address of the frame in question
+ *****************************************************************************/
+void
+e1000_tbi_adjust_stats(struct e1000_hw *hw,
+ struct e1000_hw_stats *stats,
+ uint32_t frame_len,
+ uint8_t *mac_addr)
+{
+ uint64_t carry_bit;
+
+ /* First adjust the frame length. */
+ frame_len--;
+ /* We need to adjust the statistics counters, since the hardware
+ * counters overcount this packet as a CRC error and undercount
+ * the packet as a good packet
+ */
+ /* This packet should not be counted as a CRC error. */
+ stats->crcerrs--;
+ /* This packet does count as a Good Packet Received. */
+ stats->gprc++;
+
+ /* Adjust the Good Octets received counters */
+ carry_bit = 0x80000000 & stats->gorcl;
+ stats->gorcl += frame_len;
+ /* If the high bit of Gorcl (the low 32 bits of the Good Octets
+ * Received Count) was one before the addition,
+ * AND it is zero after, then we lost the carry out,
+ * need to add one to Gorch (Good Octets Received Count High).
+ * This could be simplified if all environments supported
+ * 64-bit integers.
+ */
+ if(carry_bit && ((stats->gorcl & 0x80000000) == 0))
+ stats->gorch++;
+ /* Is this a broadcast or multicast? Check broadcast first,
+ * since the test for a multicast frame will test positive on
+ * a broadcast frame.
+ */
+ if((mac_addr[0] == (uint8_t) 0xff) && (mac_addr[1] == (uint8_t) 0xff))
+ /* Broadcast packet */
+ stats->bprc++;
+ else if(*mac_addr & 0x01)
+ /* Multicast packet */
+ stats->mprc++;
+
+ if(frame_len == hw->max_frame_size) {
+ /* In this case, the hardware has overcounted the number of
+ * oversize frames.
+ */
+ if(stats->roc > 0)
+ stats->roc--;
+ }
+
+ /* Adjust the bin counters when the extra byte put the frame in the
+ * wrong bin. Remember that the frame_len was adjusted above.
+ */
+ if(frame_len == 64) {
+ stats->prc64++;
+ stats->prc127--;
+ } else if(frame_len == 127) {
+ stats->prc127++;
+ stats->prc255--;
+ } else if(frame_len == 255) {
+ stats->prc255++;
+ stats->prc511--;
+ } else if(frame_len == 511) {
+ stats->prc511++;
+ stats->prc1023--;
+ } else if(frame_len == 1023) {
+ stats->prc1023++;
+ stats->prc1522--;
+ } else if(frame_len == 1522) {
+ stats->prc1522++;
+ }
+}
+
+/******************************************************************************
+ * Gets the current PCI bus type, speed, and width of the hardware
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+void
+e1000_get_bus_info(struct e1000_hw *hw)
+{
+ uint32_t status;
+
+ if(hw->mac_type < e1000_82543) {
+ hw->bus_type = e1000_bus_type_unknown;
+ hw->bus_speed = e1000_bus_speed_unknown;
+ hw->bus_width = e1000_bus_width_unknown;
+ return;
+ }
+
+ status = E1000_READ_REG(hw, STATUS);
+ hw->bus_type = (status & E1000_STATUS_PCIX_MODE) ?
+ e1000_bus_type_pcix : e1000_bus_type_pci;
+ if(hw->bus_type == e1000_bus_type_pci) {
+ hw->bus_speed = (status & E1000_STATUS_PCI66) ?
+ e1000_bus_speed_66 : e1000_bus_speed_33;
+ } else {
+ switch (status & E1000_STATUS_PCIX_SPEED) {
+ case E1000_STATUS_PCIX_SPEED_66:
+ hw->bus_speed = e1000_bus_speed_66;
+ break;
+ case E1000_STATUS_PCIX_SPEED_100:
+ hw->bus_speed = e1000_bus_speed_100;
+ break;
+ case E1000_STATUS_PCIX_SPEED_133:
+ hw->bus_speed = e1000_bus_speed_133;
+ break;
+ default:
+ hw->bus_speed = e1000_bus_speed_reserved;
+ break;
+ }
+ }
+ hw->bus_width = (status & E1000_STATUS_BUS64) ?
+ e1000_bus_width_64 : e1000_bus_width_32;
+}
+
diff --git a/drivers/net/e1000/e1000_mac.h b/drivers/net/e1000/e1000_hw.h
index 928c277ac28dc..7031ebde588ad 100644
--- a/drivers/net/e1000/e1000_mac.h
+++ b/drivers/net/e1000/e1000_hw.h
@@ -2,9 +2,8 @@
This software program is available to you under a choice of one of two
licenses. You may choose to be licensed under either the GNU General Public
- License (GPL) Version 2, June 1991, available at
- http://www.fsf.org/copyleft/gpl.html, or the Intel BSD + Patent License, the
- text of which follows:
+ License 2.0, June 1991, available at http://www.fsf.org/copyleft/gpl.html,
+ or the Intel BSD + Patent License, the text of which follows:
Recipient has requested a license and Intel Corporation ("Intel") is willing
to grant a license for the software entitled Linux Base Driver for the
@@ -18,7 +17,7 @@
"Recipient" means the party to whom Intel delivers this Software.
"Licensee" means Recipient and those third parties that receive a license to
- any operating system available under the GNU Public License version 2.0 or
+ any operating system available under the GNU General Public License 2.0 or
later.
Copyright (c) 1999 - 2002 Intel Corporation.
@@ -51,10 +50,10 @@
version of an operating system that has been distributed under the GNU
General Public License 2.0 or later. This patent license shall apply to the
combination of the Software and any operating system licensed under the GNU
- Public License version 2.0 or later if, at the time Intel provides the
+ General Public License 2.0 or later if, at the time Intel provides the
Software to Recipient, such addition of the Software to the then publicly
- available versions of such operating systems available under the GNU Public
- License version 2.0 or later (whether in gold, beta or alpha form) causes
+ available versions of such operating systems available under the GNU General
+ Public License 2.0 or later (whether in gold, beta or alpha form) causes
such combination to be covered by the Licensed Patents. The patent license
shall not apply to any other combinations which include the Software. NO
hardware per se is licensed hereunder.
@@ -72,18 +71,18 @@
*******************************************************************************/
-/* e1000_mac.h
+/* e1000_hw.h
* Structures, enums, and macros for the MAC
*/
-#ifndef _E1000_MAC_H_
-#define _E1000_MAC_H_
+#ifndef _E1000_HW_H_
+#define _E1000_HW_H_
#include "e1000_osdep.h"
/* Forward declarations of structures used by the shared code */
-struct e1000_shared_adapter;
-struct e1000_shared_stats;
+struct e1000_hw;
+struct e1000_hw_stats;
/* Enumerated types specific to the e1000 hardware */
/* Media Access Controlers */
@@ -92,6 +91,7 @@ typedef enum {
e1000_82542_rev2_1,
e1000_82543,
e1000_82544,
+ e1000_82540,
e1000_num_macs
} e1000_mac_type;
@@ -142,40 +142,125 @@ typedef enum {
e1000_bus_width_64
} e1000_bus_width;
+/* PHY status info structure and supporting enums */
+typedef enum {
+ e1000_cable_length_50 = 0,
+ e1000_cable_length_50_80,
+ e1000_cable_length_80_110,
+ e1000_cable_length_110_140,
+ e1000_cable_length_140,
+ e1000_cable_length_undefined = 0xFF
+} e1000_cable_length;
+typedef enum {
+ e1000_10bt_ext_dist_enable_normal = 0,
+ e1000_10bt_ext_dist_enable_lower,
+ e1000_10bt_ext_dist_enable_undefined = 0xFF
+} e1000_10bt_ext_dist_enable;
-/* Function prototypes */
-/* Setup */
-void e1000_adapter_stop(struct e1000_shared_adapter *shared);
-boolean_t e1000_init_hw(struct e1000_shared_adapter *shared);
-void e1000_init_rx_addrs(struct e1000_shared_adapter *shared);
+typedef enum {
+ e1000_rev_polarity_normal = 0,
+ e1000_rev_polarity_reversed,
+ e1000_rev_polarity_undefined = 0xFF
+} e1000_rev_polarity;
-/* Filters (multicast, vlan, receive) */
-void e1000_mc_addr_list_update(struct e1000_shared_adapter *shared, uint8_t * mc_addr_list, uint32_t mc_addr_count, uint32_t pad);
-uint32_t e1000_hash_mc_addr(struct e1000_shared_adapter *shared, uint8_t * mc_addr);
-void e1000_mta_set(struct e1000_shared_adapter *shared, uint32_t hash_value);
-void e1000_rar_set(struct e1000_shared_adapter *shared, uint8_t * mc_addr, uint32_t rar_index);
-void e1000_write_vfta(struct e1000_shared_adapter *shared, uint32_t offset, uint32_t value);
-void e1000_clear_vfta(struct e1000_shared_adapter *shared);
-
-/* Link layer setup functions */
-boolean_t e1000_setup_fc_and_link(struct e1000_shared_adapter *shared);
-boolean_t e1000_setup_pcs_link(struct e1000_shared_adapter *shared, uint32_t dev_ctrl_reg);
-void e1000_config_fc_after_link_up(struct e1000_shared_adapter *shared);
-void e1000_check_for_link(struct e1000_shared_adapter *shared);
-void e1000_get_speed_and_duplex(struct e1000_shared_adapter *shared, uint16_t * speed, uint16_t * duplex);
+typedef enum {
+ e1000_polarity_reversal_enabled = 0,
+ e1000_polarity_reversal_disabled,
+ e1000_polarity_reversal_undefined = 0xFF
+} e1000_polarity_reversal;
+
+typedef enum {
+ e1000_auto_x_mode_manual_mdi = 0,
+ e1000_auto_x_mode_manual_mdix,
+ e1000_auto_x_mode_auto1,
+ e1000_auto_x_mode_auto2,
+ e1000_auto_x_mode_undefined = 0xFF
+} e1000_auto_x_mode;
+
+typedef enum {
+ e1000_1000t_rx_status_not_ok = 0,
+ e1000_1000t_rx_status_ok,
+ e1000_1000t_rx_status_undefined = 0xFF
+} e1000_1000t_rx_status;
+
+struct e1000_phy_info {
+ e1000_cable_length cable_length;
+ e1000_10bt_ext_dist_enable extended_10bt_distance;
+ e1000_rev_polarity cable_polarity;
+ e1000_polarity_reversal polarity_correction;
+ e1000_auto_x_mode mdix_mode;
+ e1000_1000t_rx_status local_rx;
+ e1000_1000t_rx_status remote_rx;
+};
+
+struct e1000_phy_stats {
+ uint32_t idle_errors;
+ uint32_t receive_errors;
+};
+
+
+
+/* Error Codes */
+#define E1000_SUCCESS 0
+#define E1000_ERR_EEPROM 1
+#define E1000_ERR_PHY 2
+#define E1000_ERR_CONFIG 3
+#define E1000_ERR_PARAM 4
+
+/* Function prototypes */
+/* Initialization */
+void e1000_reset_hw(struct e1000_hw *hw);
+int32_t e1000_init_hw(struct e1000_hw *hw);
+
+/* Link Configuration */
+int32_t e1000_setup_link(struct e1000_hw *hw);
+int32_t e1000_phy_setup_autoneg(struct e1000_hw *hw);
+void e1000_config_collision_dist(struct e1000_hw *hw);
+int32_t e1000_config_fc_after_link_up(struct e1000_hw *hw);
+int32_t e1000_check_for_link(struct e1000_hw *hw);
+void e1000_get_speed_and_duplex(struct e1000_hw *hw, uint16_t * speed, uint16_t * duplex);
+int32_t e1000_wait_autoneg(struct e1000_hw *hw);
+
+/* PHY */
+int32_t e1000_read_phy_reg(struct e1000_hw *hw, uint32_t reg_addr, uint16_t *phy_data);
+int32_t e1000_write_phy_reg(struct e1000_hw *hw, uint32_t reg_addr, uint16_t data);
+void e1000_phy_hw_reset(struct e1000_hw *hw);
+int32_t e1000_phy_reset(struct e1000_hw *hw);
+int32_t e1000_detect_gig_phy(struct e1000_hw *hw);
+int32_t e1000_phy_get_info(struct e1000_hw *hw, struct e1000_phy_info *phy_info);
+int32_t e1000_validate_mdi_setting(struct e1000_hw *hw);
/* EEPROM Functions */
-uint16_t e1000_read_eeprom(struct e1000_shared_adapter *shared, uint16_t reg);
-boolean_t e1000_validate_eeprom_checksum(struct e1000_shared_adapter *shared);
+int32_t e1000_read_eeprom(struct e1000_hw *hw, uint16_t reg, uint16_t *data);
+int32_t e1000_validate_eeprom_checksum(struct e1000_hw *hw);
+int32_t e1000_read_part_num(struct e1000_hw *hw, uint32_t * part_num);
+int32_t e1000_read_mac_addr(struct e1000_hw * hw);
+
+/* Filters (multicast, vlan, receive) */
+void e1000_init_rx_addrs(struct e1000_hw *hw);
+void e1000_mc_addr_list_update(struct e1000_hw *hw, uint8_t * mc_addr_list, uint32_t mc_addr_count, uint32_t pad);
+uint32_t e1000_hash_mc_addr(struct e1000_hw *hw, uint8_t * mc_addr);
+void e1000_mta_set(struct e1000_hw *hw, uint32_t hash_value);
+void e1000_rar_set(struct e1000_hw *hw, uint8_t * mc_addr, uint32_t rar_index);
+void e1000_write_vfta(struct e1000_hw *hw, uint32_t offset, uint32_t value);
+void e1000_clear_vfta(struct e1000_hw *hw);
+
+/* LED functions */
+int32_t e1000_setup_led(struct e1000_hw *hw);
+int32_t e1000_cleanup_led(struct e1000_hw *hw);
+int32_t e1000_led_on(struct e1000_hw *hw);
+int32_t e1000_led_off(struct e1000_hw *hw);
+
+/* Adaptive IFS Functions */
/* Everything else */
-void e1000_clear_hw_cntrs(struct e1000_shared_adapter *shared);
-boolean_t e1000_read_part_num(struct e1000_shared_adapter *shared, uint32_t * part_num);
-void e1000_read_mac_addr(struct e1000_shared_adapter * shared);
-void e1000_get_bus_info(struct e1000_shared_adapter *shared);
-uint32_t e1000_tbi_adjust_stats(struct e1000_shared_adapter *shared, struct e1000_shared_stats *stats, uint32_t frame_len, uint8_t * mac_addr);
-void e1000_write_pci_cfg(struct e1000_shared_adapter *shared, uint32_t reg, uint16_t * value);
+void e1000_clear_hw_cntrs(struct e1000_hw *hw);
+void e1000_reset_adaptive(struct e1000_hw *hw);
+void e1000_update_adaptive(struct e1000_hw *hw);
+void e1000_tbi_adjust_stats(struct e1000_hw *hw, struct e1000_hw_stats *stats, uint32_t frame_len, uint8_t * mac_addr);
+void e1000_get_bus_info(struct e1000_hw *hw);
+void e1000_write_pci_cfg(struct e1000_hw *hw, uint32_t reg, uint16_t * value);
/* PCI Device IDs */
#define E1000_DEV_ID_82542 0x1000
@@ -185,7 +270,9 @@ void e1000_write_pci_cfg(struct e1000_shared_adapter *shared, uint32_t reg, uint
#define E1000_DEV_ID_82544EI_FIBER 0x1009
#define E1000_DEV_ID_82544GC_COPPER 0x100C
#define E1000_DEV_ID_82544GC_LOM 0x100D
-#define NUM_DEV_IDS 7
+#define E1000_DEV_ID_82540EM 0x100E
+#define E1000_DEV_ID_82540EM_LOM 0x1015
+#define NUM_DEV_IDS 9
#define NODE_ADDRESS_SIZE 6
#define ETH_LENGTH_OF_ADDRESS 6
@@ -204,9 +291,14 @@ void e1000_write_pci_cfg(struct e1000_shared_adapter *shared, uint32_t reg, uint
/* The sizes (in bytes) of a ethernet packet */
#define ENET_HEADER_SIZE 14
-#define MAXIMUM_ETHERNET_PACKET_SIZE 1514 /* Without FCS */
-#define MINIMUM_ETHERNET_PACKET_SIZE 60 /* Without FCS */
-#define CRC_LENGTH 4
+#define MAXIMUM_ETHERNET_FRAME_SIZE 1518 /* With FCS */
+#define MINIMUM_ETHERNET_FRAME_SIZE 64 /* With FCS */
+#define ETHERNET_FCS_SIZE 4
+#define MAXIMUM_ETHERNET_PACKET_SIZE \
+ (MAXIMUM_ETHERNET_FRAME_SIZE - ETHERNET_FCS_SIZE)
+#define MINIMUM_ETHERNET_PACKET_SIZE \
+ (MINIMUM_ETHERNET_FRAME_SIZE - ETHERNET_FCS_SIZE)
+#define CRC_LENGTH ETHERNET_FCS_SIZE
#define MAX_JUMBO_FRAME_SIZE 0x3F00
@@ -481,6 +573,7 @@ struct e1000_ffvt_entry {
#define E1000_TCTL 0x00400 /* TX Control - RW */
#define E1000_TIPG 0x00410 /* TX Inter-packet gap -RW */
#define E1000_TBT 0x00448 /* TX Burst Timer - RW */
+#define E1000_AIT 0x00458 /* Adaptive Interframe Spacing Throttle - RW */
#define E1000_LEDCTL 0x00E00 /* LED Control - RW */
#define E1000_PBA 0x01000 /* Packet Buffer Allocation - RW */
#define E1000_FCRTL 0x02160 /* Flow Control Receive Threshold Low - RW */
@@ -623,6 +716,7 @@ struct e1000_ffvt_entry {
#define E1000_82542_TDT 0x00438
#define E1000_82542_TIDV 0x00440
#define E1000_82542_TBT E1000_TBT
+#define E1000_82542_AIT E1000_AIT
#define E1000_82542_VFTA 0x00600
#define E1000_82542_LEDCTL E1000_LEDCTL
#define E1000_82542_PBA E1000_PBA
@@ -706,7 +800,7 @@ struct e1000_ffvt_entry {
#define E1000_82542_FFVT E1000_FFVT
/* Statistics counters collected by the MAC */
-struct e1000_shared_stats {
+struct e1000_hw_stats {
uint64_t crcerrs;
uint64_t algnerrc;
uint64_t symerrs;
@@ -767,10 +861,8 @@ struct e1000_shared_stats {
uint64_t tsctfc;
};
-/* Structure containing variables used by the shared code (e1000_mac.c and
- * e1000_phy.c)
- */
-struct e1000_shared_adapter {
+/* Structure containing variables used by the shared code (e1000_hw.c) */
+struct e1000_hw {
uint8_t *hw_addr;
e1000_mac_type mac_type;
e1000_media_type media_type;
@@ -782,29 +874,30 @@ struct e1000_shared_adapter {
uint32_t phy_id;
uint32_t phy_addr;
uint32_t original_fc;
- uint32_t txcw_reg;
+ uint32_t txcw;
uint32_t autoneg_failed;
uint32_t max_frame_size;
uint32_t min_frame_size;
uint32_t mc_filter_type;
uint32_t num_mc_addrs;
+ uint32_t collision_delta;
+ uint32_t tx_packet_delta;
+ uint32_t ledctl;
uint16_t autoneg_advertised;
uint16_t pci_cmd_word;
uint16_t fc_high_water;
uint16_t fc_low_water;
uint16_t fc_pause_time;
+ uint16_t current_ifs_val;
+ uint16_t ifs_min_val;
+ uint16_t ifs_max_val;
+ uint16_t ifs_step_size;
+ uint16_t ifs_ratio;
uint16_t device_id;
uint16_t vendor_id;
uint16_t subsystem_id;
uint16_t subsystem_vendor_id;
uint8_t revision_id;
- boolean_t disable_polarity_correction;
- boolean_t get_link_status;
- boolean_t tbi_compatibility_en;
- boolean_t tbi_compatibility_on;
- boolean_t adapter_stopped;
- boolean_t fc_send_xon;
- boolean_t report_tx_early;
uint8_t autoneg;
uint8_t mdix;
uint8_t forced_speed_duplex;
@@ -812,6 +905,15 @@ struct e1000_shared_adapter {
uint8_t dma_fairness;
uint8_t mac_addr[NODE_ADDRESS_SIZE];
uint8_t perm_mac_addr[NODE_ADDRESS_SIZE];
+ boolean_t disable_polarity_correction;
+ boolean_t get_link_status;
+ boolean_t tbi_compatibility_en;
+ boolean_t tbi_compatibility_on;
+ boolean_t fc_send_xon;
+ boolean_t report_tx_early;
+ boolean_t adaptive_ifs;
+ boolean_t ifs_params_forced;
+ boolean_t in_ifs_mode;
};
@@ -1254,8 +1356,9 @@ struct e1000_shared_adapter {
/* Collision related configuration parameters */
#define E1000_COLLISION_THRESHOLD 16
#define E1000_CT_SHIFT 4
-#define E1000_FDX_COLLISION_DISTANCE 64
-#define E1000_HDX_COLLISION_DISTANCE 64
+#define E1000_COLLISION_DISTANCE 64
+#define E1000_FDX_COLLISION_DISTANCE E1000_COLLISION_DISTANCE
+#define E1000_HDX_COLLISION_DISTANCE E1000_COLLISION_DISTANCE
#define E1000_GB_HDX_COLLISION_DISTANCE 512
#define E1000_COLD_SHIFT 12
@@ -1282,6 +1385,19 @@ struct e1000_shared_adapter {
#define E1000_TXDMAC_DPP 0x00000001
+/* Adaptive IFS defines */
+#define TX_THRESHOLD_START 8
+#define TX_THRESHOLD_INCREMENT 10
+#define TX_THRESHOLD_DECREMENT 1
+#define TX_THRESHOLD_STOP 190
+#define TX_THRESHOLD_DISABLE 0
+#define TX_THRESHOLD_TIMER_MS 10000
+#define MIN_NUM_XMITS 1000
+#define IFS_MAX 80
+#define IFS_STEP 10
+#define IFS_MIN 40
+#define IFS_RATIO 4
+
/* PBA constants */
#define E1000_PBA_16K 0x0010 /* 16KB, default TX allocation */
#define E1000_PBA_24K 0x0018
@@ -1337,17 +1453,9 @@ struct e1000_shared_adapter {
/* TBI_ACCEPT macro definition:
*
- * If Tbi Compatibility mode is turned-on, then we should accept frames with
- * receive errors if and only if:
- * 1) errors is equal to the CRC error bit.
- * 2) The last byte is a Carrier extension (0x0F).
- * 3) The frame length (as reported by Hardware) is greater than 64 (60
- * if a VLAN tag was stripped from the frame.
- * 4) " " " " " " " <= max_frame_size+1.
- *
* This macro requires:
- * adapter = a pointer to struct e1000_shared_adapter
- * special = the 16 bit special field of the RX descriptor with EOP set
+ * adapter = a pointer to struct e1000_hw
+ * status = the 8 bit status field of the RX descriptor with EOP set
* error = the 8 bit error field of the RX descriptor with EOP set
* length = the sum of all the length fields of the RX descriptors that
* make up the current frame
@@ -1370,14 +1478,290 @@ struct e1000_shared_adapter {
* ...
*/
-#define TBI_ACCEPT(adapter, special, errors, length, last_byte) \
+#define TBI_ACCEPT(adapter, status, errors, length, last_byte) \
((adapter)->tbi_compatibility_on && \
(((errors) & E1000_RXD_ERR_FRAME_ERR_MASK) == E1000_RXD_ERR_CE) && \
((last_byte) == CARRIER_EXTENSION) && \
- ((length) <= ((adapter)->max_frame_size + 1)) && \
- ((length) > ((special == 0x0000) ? \
- ((adapter)->min_frame_size) : \
- ((adapter)->min_frame_size - VLAN_TAG_SIZE))))
+ (((status) & E1000_RXD_STAT_VP) ? \
+ (((length) > ((adapter)->min_frame_size - VLAN_TAG_SIZE)) && \
+ ((length) <= ((adapter)->max_frame_size + 1))) : \
+ (((length) > (adapter)->min_frame_size) && \
+ ((length) <= ((adapter)->max_frame_size + VLAN_TAG_SIZE + 1)))))
-#endif /* _E1000_MAC_H_ */
+/* Structures, enums, and macros for the PHY */
+
+/* Bit definitions for the Management Data IO (MDIO) and Management Data
+ * Clock (MDC) pins in the Device Control Register.
+ */
+#define E1000_CTRL_PHY_RESET_DIR E1000_CTRL_SWDPIO0
+#define E1000_CTRL_PHY_RESET E1000_CTRL_SWDPIN0
+#define E1000_CTRL_MDIO_DIR E1000_CTRL_SWDPIO2
+#define E1000_CTRL_MDIO E1000_CTRL_SWDPIN2
+#define E1000_CTRL_MDC_DIR E1000_CTRL_SWDPIO3
+#define E1000_CTRL_MDC E1000_CTRL_SWDPIN3
+#define E1000_CTRL_PHY_RESET_DIR4 E1000_CTRL_EXT_SDP4_DIR
+#define E1000_CTRL_PHY_RESET4 E1000_CTRL_EXT_SDP4_DATA
+
+/* PHY 1000 MII Register/Bit Definitions */
+/* PHY Registers defined by IEEE */
+#define PHY_CTRL 0x00 /* Control Register */
+#define PHY_STATUS 0x01 /* Status Regiser */
+#define PHY_ID1 0x02 /* Phy Id Reg (word 1) */
+#define PHY_ID2 0x03 /* Phy Id Reg (word 2) */
+#define PHY_AUTONEG_ADV 0x04 /* Autoneg Advertisement */
+#define PHY_LP_ABILITY 0x05 /* Link Partner Ability (Base Page) */
+#define PHY_AUTONEG_EXP 0x06 /* Autoneg Expansion Reg */
+#define PHY_NEXT_PAGE_TX 0x07 /* Next Page TX */
+#define PHY_LP_NEXT_PAGE 0x08 /* Link Partner Next Page */
+#define PHY_1000T_CTRL 0x09 /* 1000Base-T Control Reg */
+#define PHY_1000T_STATUS 0x0A /* 1000Base-T Status Reg */
+#define PHY_EXT_STATUS 0x0F /* Extended Status Reg */
+
+/* M88E1000 Specific Registers */
+#define M88E1000_PHY_SPEC_CTRL 0x10 /* PHY Specific Control Register */
+#define M88E1000_PHY_SPEC_STATUS 0x11 /* PHY Specific Status Register */
+#define M88E1000_INT_ENABLE 0x12 /* Interrupt Enable Register */
+#define M88E1000_INT_STATUS 0x13 /* Interrupt Status Register */
+#define M88E1000_EXT_PHY_SPEC_CTRL 0x14 /* Extended PHY Specific Control */
+#define M88E1000_RX_ERR_CNTR 0x15 /* Receive Error Counter */
+
+#define MAX_PHY_REG_ADDRESS 0x1F /* 5 bit address bus (0-0x1F) */
+
+/* PHY Control Register */
+#define MII_CR_SPEED_SELECT_MSB 0x0040 /* bits 6,13: 10=1000, 01=100, 00=10 */
+#define MII_CR_COLL_TEST_ENABLE 0x0080 /* Collision test enable */
+#define MII_CR_FULL_DUPLEX 0x0100 /* FDX =1, half duplex =0 */
+#define MII_CR_RESTART_AUTO_NEG 0x0200 /* Restart auto negotiation */
+#define MII_CR_ISOLATE 0x0400 /* Isolate PHY from MII */
+#define MII_CR_POWER_DOWN 0x0800 /* Power down */
+#define MII_CR_AUTO_NEG_EN 0x1000 /* Auto Neg Enable */
+#define MII_CR_SPEED_SELECT_LSB 0x2000 /* bits 6,13: 10=1000, 01=100, 00=10 */
+#define MII_CR_LOOPBACK 0x4000 /* 0 = normal, 1 = loopback */
+#define MII_CR_RESET 0x8000 /* 0 = normal, 1 = PHY reset */
+
+/* PHY Status Register */
+#define MII_SR_EXTENDED_CAPS 0x0001 /* Extended register capabilities */
+#define MII_SR_JABBER_DETECT 0x0002 /* Jabber Detected */
+#define MII_SR_LINK_STATUS 0x0004 /* Link Status 1 = link */
+#define MII_SR_AUTONEG_CAPS 0x0008 /* Auto Neg Capable */
+#define MII_SR_REMOTE_FAULT 0x0010 /* Remote Fault Detect */
+#define MII_SR_AUTONEG_COMPLETE 0x0020 /* Auto Neg Complete */
+#define MII_SR_PREAMBLE_SUPPRESS 0x0040 /* Preamble may be suppressed */
+#define MII_SR_EXTENDED_STATUS 0x0100 /* Ext. status info in Reg 0x0F */
+#define MII_SR_100T2_HD_CAPS 0x0200 /* 100T2 Half Duplex Capable */
+#define MII_SR_100T2_FD_CAPS 0x0400 /* 100T2 Full Duplex Capable */
+#define MII_SR_10T_HD_CAPS 0x0800 /* 10T Half Duplex Capable */
+#define MII_SR_10T_FD_CAPS 0x1000 /* 10T Full Duplex Capable */
+#define MII_SR_100X_HD_CAPS 0x2000 /* 100X Half Duplex Capable */
+#define MII_SR_100X_FD_CAPS 0x4000 /* 100X Full Duplex Capable */
+#define MII_SR_100T4_CAPS 0x8000 /* 100T4 Capable */
+
+/* Autoneg Advertisement Register */
+#define NWAY_AR_SELECTOR_FIELD 0x0001 /* indicates IEEE 802.3 CSMA/CD */
+#define NWAY_AR_10T_HD_CAPS 0x0020 /* 10T Half Duplex Capable */
+#define NWAY_AR_10T_FD_CAPS 0x0040 /* 10T Full Duplex Capable */
+#define NWAY_AR_100TX_HD_CAPS 0x0080 /* 100TX Half Duplex Capable */
+#define NWAY_AR_100TX_FD_CAPS 0x0100 /* 100TX Full Duplex Capable */
+#define NWAY_AR_100T4_CAPS 0x0200 /* 100T4 Capable */
+#define NWAY_AR_PAUSE 0x0400 /* Pause operation desired */
+#define NWAY_AR_ASM_DIR 0x0800 /* Asymmetric Pause Direction bit */
+#define NWAY_AR_REMOTE_FAULT 0x2000 /* Remote Fault detected */
+#define NWAY_AR_NEXT_PAGE 0x8000 /* Next Page ability supported */
+
+/* Link Partner Ability Register (Base Page) */
+#define NWAY_LPAR_SELECTOR_FIELD 0x0000 /* LP protocol selector field */
+#define NWAY_LPAR_10T_HD_CAPS 0x0020 /* LP is 10T Half Duplex Capable */
+#define NWAY_LPAR_10T_FD_CAPS 0x0040 /* LP is 10T Full Duplex Capable */
+#define NWAY_LPAR_100TX_HD_CAPS 0x0080 /* LP is 100TX Half Duplex Capable */
+#define NWAY_LPAR_100TX_FD_CAPS 0x0100 /* LP is 100TX Full Duplex Capable */
+#define NWAY_LPAR_100T4_CAPS 0x0200 /* LP is 100T4 Capable */
+#define NWAY_LPAR_PAUSE 0x0400 /* LP Pause operation desired */
+#define NWAY_LPAR_ASM_DIR 0x0800 /* LP Asymmetric Pause Direction bit */
+#define NWAY_LPAR_REMOTE_FAULT 0x2000 /* LP has detected Remote Fault */
+#define NWAY_LPAR_ACKNOWLEDGE 0x4000 /* LP has rx'd link code word */
+#define NWAY_LPAR_NEXT_PAGE 0x8000 /* Next Page ability supported */
+
+/* Autoneg Expansion Register */
+#define NWAY_ER_LP_NWAY_CAPS 0x0001 /* LP has Auto Neg Capability */
+#define NWAY_ER_PAGE_RXD 0x0002 /* LP is 10T Half Duplex Capable */
+#define NWAY_ER_NEXT_PAGE_CAPS 0x0004 /* LP is 10T Full Duplex Capable */
+#define NWAY_ER_LP_NEXT_PAGE_CAPS 0x0008 /* LP is 100TX Half Duplex Capable */
+#define NWAY_ER_PAR_DETECT_FAULT 0x0100 /* LP is 100TX Full Duplex Capable */
+
+/* Next Page TX Register */
+#define NPTX_MSG_CODE_FIELD 0x0001 /* NP msg code or unformatted data */
+#define NPTX_TOGGLE 0x0800 /* Toggles between exchanges
+ * of different NP
+ */
+#define NPTX_ACKNOWLDGE2 0x1000 /* 1 = will comply with msg
+ * 0 = cannot comply with msg
+ */
+#define NPTX_MSG_PAGE 0x2000 /* formatted(1)/unformatted(0) pg */
+#define NPTX_NEXT_PAGE 0x8000 /* 1 = addition NP will follow
+ * 0 = sending last NP
+ */
+
+/* Link Partner Next Page Register */
+#define LP_RNPR_MSG_CODE_FIELD 0x0001 /* NP msg code or unformatted data */
+#define LP_RNPR_TOGGLE 0x0800 /* Toggles between exchanges
+ * of different NP
+ */
+#define LP_RNPR_ACKNOWLDGE2 0x1000 /* 1 = will comply with msg
+ * 0 = cannot comply with msg
+ */
+#define LP_RNPR_MSG_PAGE 0x2000 /* formatted(1)/unformatted(0) pg */
+#define LP_RNPR_ACKNOWLDGE 0x4000 /* 1 = ACK / 0 = NO ACK */
+#define LP_RNPR_NEXT_PAGE 0x8000 /* 1 = addition NP will follow
+ * 0 = sending last NP
+ */
+
+/* 1000BASE-T Control Register */
+#define CR_1000T_ASYM_PAUSE 0x0080 /* Advertise asymmetric pause bit */
+#define CR_1000T_HD_CAPS 0x0100 /* Advertise 1000T HD capability */
+#define CR_1000T_FD_CAPS 0x0200 /* Advertise 1000T FD capability */
+#define CR_1000T_REPEATER_DTE 0x0400 /* 1=Repeater/switch device port */
+ /* 0=DTE device */
+#define CR_1000T_MS_VALUE 0x0800 /* 1=Configure PHY as Master */
+ /* 0=Configure PHY as Slave */
+#define CR_1000T_MS_ENABLE 0x1000 /* 1=Master/Slave manual config value */
+ /* 0=Automatic Master/Slave config */
+#define CR_1000T_TEST_MODE_NORMAL 0x0000 /* Normal Operation */
+#define CR_1000T_TEST_MODE_1 0x2000 /* Transmit Waveform test */
+#define CR_1000T_TEST_MODE_2 0x4000 /* Master Transmit Jitter test */
+#define CR_1000T_TEST_MODE_3 0x6000 /* Slave Transmit Jitter test */
+#define CR_1000T_TEST_MODE_4 0x8000 /* Transmitter Distortion test */
+
+/* 1000BASE-T Status Register */
+#define SR_1000T_IDLE_ERROR_CNT 0x00FF /* Num idle errors since last read */
+#define SR_1000T_ASYM_PAUSE_DIR 0x0100 /* LP asymmetric pause direction bit */
+#define SR_1000T_LP_HD_CAPS 0x0400 /* LP is 1000T HD capable */
+#define SR_1000T_LP_FD_CAPS 0x0800 /* LP is 1000T FD capable */
+#define SR_1000T_REMOTE_RX_STATUS 0x1000 /* Remote receiver OK */
+#define SR_1000T_LOCAL_RX_STATUS 0x2000 /* Local receiver OK */
+#define SR_1000T_MS_CONFIG_RES 0x4000 /* 1=Local TX is Master, 0=Slave */
+#define SR_1000T_MS_CONFIG_FAULT 0x8000 /* Master/Slave config fault */
+#define SR_1000T_REMOTE_RX_STATUS_SHIFT 12
+#define SR_1000T_LOCAL_RX_STATUS_SHIFT 13
+
+/* Extended Status Register */
+#define IEEE_ESR_1000T_HD_CAPS 0x1000 /* 1000T HD capable */
+#define IEEE_ESR_1000T_FD_CAPS 0x2000 /* 1000T FD capable */
+#define IEEE_ESR_1000X_HD_CAPS 0x4000 /* 1000X HD capable */
+#define IEEE_ESR_1000X_FD_CAPS 0x8000 /* 1000X FD capable */
+
+#define PHY_TX_POLARITY_MASK 0x0100 /* register 10h bit 8 (polarity bit) */
+#define PHY_TX_NORMAL_POLARITY 0 /* register 10h bit 8 (normal polarity) */
+
+#define AUTO_POLARITY_DISABLE 0x0010 /* register 11h bit 4 */
+ /* (0=enable, 1=disable) */
+
+/* M88E1000 PHY Specific Control Register */
+#define M88E1000_PSCR_JABBER_DISABLE 0x0001 /* 1=Jabber Function disabled */
+#define M88E1000_PSCR_POLARITY_REVERSAL 0x0002 /* 1=Polarity Reversal enabled */
+#define M88E1000_PSCR_SQE_TEST 0x0004 /* 1=SQE Test enabled */
+#define M88E1000_PSCR_CLK125_DISABLE 0x0010 /* 1=CLK125 low,
+ * 0=CLK125 toggling
+ */
+#define M88E1000_PSCR_MDI_MANUAL_MODE 0x0000 /* MDI Crossover Mode bits 6:5 */
+ /* Manual MDI configuration */
+#define M88E1000_PSCR_MDIX_MANUAL_MODE 0x0020 /* Manual MDIX configuration */
+#define M88E1000_PSCR_AUTO_X_1000T 0x0040 /* 1000BASE-T: Auto crossover,
+ * 100BASE-TX/10BASE-T:
+ * MDI Mode
+ */
+#define M88E1000_PSCR_AUTO_X_MODE 0x0060 /* Auto crossover enabled
+ * all speeds.
+ */
+#define M88E1000_PSCR_10BT_EXT_DIST_ENABLE 0x0080
+ /* 1=Enable Extended 10BASE-T distance
+ * (Lower 10BASE-T RX Threshold)
+ * 0=Normal 10BASE-T RX Threshold */
+#define M88E1000_PSCR_MII_5BIT_ENABLE 0x0100
+ /* 1=5-Bit interface in 100BASE-TX
+ * 0=MII interface in 100BASE-TX */
+#define M88E1000_PSCR_SCRAMBLER_DISABLE 0x0200 /* 1=Scrambler disable */
+#define M88E1000_PSCR_FORCE_LINK_GOOD 0x0400 /* 1=Force link good */
+#define M88E1000_PSCR_ASSERT_CRS_ON_TX 0x0800 /* 1=Assert CRS on Transmit */
+
+#define M88E1000_PSCR_POLARITY_REVERSAL_SHIFT 1
+#define M88E1000_PSCR_AUTO_X_MODE_SHIFT 5
+#define M88E1000_PSCR_10BT_EXT_DIST_ENABLE_SHIFT 7
+
+/* M88E1000 PHY Specific Status Register */
+#define M88E1000_PSSR_JABBER 0x0001 /* 1=Jabber */
+#define M88E1000_PSSR_REV_POLARITY 0x0002 /* 1=Polarity reversed */
+#define M88E1000_PSSR_MDIX 0x0040 /* 1=MDIX; 0=MDI */
+#define M88E1000_PSSR_CABLE_LENGTH 0x0380 /* 0=<50M;1=50-80M;2=80-110M;
+ * 3=110-140M;4=>140M */
+#define M88E1000_PSSR_LINK 0x0400 /* 1=Link up, 0=Link down */
+#define M88E1000_PSSR_SPD_DPLX_RESOLVED 0x0800 /* 1=Speed & Duplex resolved */
+#define M88E1000_PSSR_PAGE_RCVD 0x1000 /* 1=Page received */
+#define M88E1000_PSSR_DPLX 0x2000 /* 1=Duplex 0=Half Duplex */
+#define M88E1000_PSSR_SPEED 0xC000 /* Speed, bits 14:15 */
+#define M88E1000_PSSR_10MBS 0x0000 /* 00=10Mbs */
+#define M88E1000_PSSR_100MBS 0x4000 /* 01=100Mbs */
+#define M88E1000_PSSR_1000MBS 0x8000 /* 10=1000Mbs */
+
+#define M88E1000_PSSR_REV_POLARITY_SHIFT 1
+#define M88E1000_PSSR_MDIX_SHIFT 6
+#define M88E1000_PSSR_CABLE_LENGTH_SHIFT 7
+
+/* M88E1000 Extended PHY Specific Control Register */
+#define M88E1000_EPSCR_FIBER_LOOPBACK 0x4000 /* 1=Fiber loopback */
+#define M88E1000_EPSCR_DOWN_NO_IDLE 0x8000 /* 1=Lost lock detect enabled.
+ * Will assert lost lock and bring
+ * link down if idle not seen
+ * within 1ms in 1000BASE-T
+ */
+/* Number of times we will attempt to autonegotiate before downshifting if we
+ * are the master */
+#define M88E1000_EPSCR_MASTER_DOWNSHIFT_MASK 0x0C00
+#define M88E1000_EPSCR_MASTER_DOWNSHIFT_1X 0x0000
+#define M88E1000_EPSCR_MASTER_DOWNSHIFT_2X 0x0400
+#define M88E1000_EPSCR_MASTER_DOWNSHIFT_3X 0x0800
+#define M88E1000_EPSCR_MASTER_DOWNSHIFT_4X 0x0C00
+/* Number of times we will attempt to autonegotiate before downshifting if we
+ * are the slave */
+#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_MASK 0x0300
+#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_DIS 0x0000
+#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_1X 0x0100
+#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_2X 0x0200
+#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_3X 0x0300
+#define M88E1000_EPSCR_TX_CLK_2_5 0x0060 /* 2.5 MHz TX_CLK */
+#define M88E1000_EPSCR_TX_CLK_25 0x0070 /* 25 MHz TX_CLK */
+#define M88E1000_EPSCR_TX_CLK_0 0x0000 /* NO TX_CLK */
+
+/* Bit definitions for valid PHY IDs. */
+#define M88E1000_E_PHY_ID 0x01410C50
+#define M88E1000_I_PHY_ID 0x01410C30
+#define M88E1011_I_PHY_ID 0x01410C20
+#define M88E1000_12_PHY_ID M88E1000_E_PHY_ID
+#define M88E1000_14_PHY_ID M88E1000_E_PHY_ID
+
+/* Miscellaneous PHY bit definitions. */
+#define PHY_PREAMBLE 0xFFFFFFFF
+#define PHY_SOF 0x01
+#define PHY_OP_READ 0x02
+#define PHY_OP_WRITE 0x01
+#define PHY_TURNAROUND 0x02
+#define PHY_PREAMBLE_SIZE 32
+#define MII_CR_SPEED_1000 0x0040
+#define MII_CR_SPEED_100 0x2000
+#define MII_CR_SPEED_10 0x0000
+#define E1000_PHY_ADDRESS 0x01
+#define PHY_AUTO_NEG_TIME 45 /* 4.5 Seconds */
+#define PHY_FORCE_TIME 20 /* 2.0 Seconds */
+#define PHY_REVISION_MASK 0xFFFFFFF0
+#define DEVICE_SPEED_MASK 0x00000300 /* Device Ctrl Reg Speed Mask */
+#define REG4_SPEED_MASK 0x01E0
+#define REG9_SPEED_MASK 0x0300
+#define ADVERTISE_10_HALF 0x0001
+#define ADVERTISE_10_FULL 0x0002
+#define ADVERTISE_100_HALF 0x0004
+#define ADVERTISE_100_FULL 0x0008
+#define ADVERTISE_1000_HALF 0x0010
+#define ADVERTISE_1000_FULL 0x0020
+#define AUTONEG_ADVERTISE_SPEED_DEFAULT 0x002F /* Everything but 1000-Half */
+
+#endif /* _E1000_HW_H_ */
diff --git a/drivers/net/e1000/e1000_mac.c b/drivers/net/e1000/e1000_mac.c
deleted file mode 100644
index fcbba64b1cb32..0000000000000
--- a/drivers/net/e1000/e1000_mac.c
+++ /dev/null
@@ -1,1821 +0,0 @@
-/*******************************************************************************
-
- This software program is available to you under a choice of one of two
- licenses. You may choose to be licensed under either the GNU General Public
- License (GPL) Version 2, June 1991, available at
- http://www.fsf.org/copyleft/gpl.html, or the Intel BSD + Patent License, the
- text of which follows:
-
- Recipient has requested a license and Intel Corporation ("Intel") is willing
- to grant a license for the software entitled Linux Base Driver for the
- Intel(R) PRO/1000 Family of Adapters (e1000) (the "Software") being provided
- by Intel Corporation. The following definitions apply to this license:
-
- "Licensed Patents" means patent claims licensable by Intel Corporation which
- are necessarily infringed by the use of sale of the Software alone or when
- combined with the operating system referred to below.
-
- "Recipient" means the party to whom Intel delivers this Software.
-
- "Licensee" means Recipient and those third parties that receive a license to
- any operating system available under the GNU Public License version 2.0 or
- later.
-
- Copyright (c) 1999 - 2002 Intel Corporation.
- All rights reserved.
-
- The license is provided to Recipient and Recipient's Licensees under the
- following terms.
-
- Redistribution and use in source and binary forms of the Software, with or
- without modification, are permitted provided that the following conditions
- are met:
-
- Redistributions of source code of the Software may retain the above
- copyright notice, this list of conditions and the following disclaimer.
-
- Redistributions in binary form of the Software may reproduce the above
- copyright notice, this list of conditions and the following disclaimer in
- the documentation and/or materials provided with the distribution.
-
- Neither the name of Intel Corporation nor the names of its contributors
- shall be used to endorse or promote products derived from this Software
- without specific prior written permission.
-
- Intel hereby grants Recipient and Licensees a non-exclusive, worldwide,
- royalty-free patent license under Licensed Patents to make, use, sell, offer
- to sell, import and otherwise transfer the Software, if any, in source code
- and object code form. This license shall include changes to the Software
- that are error corrections or other minor changes to the Software that do
- not add functionality or features when the Software is incorporated in any
- version of an operating system that has been distributed under the GNU
- General Public License 2.0 or later. This patent license shall apply to the
- combination of the Software and any operating system licensed under the GNU
- Public License version 2.0 or later if, at the time Intel provides the
- Software to Recipient, such addition of the Software to the then publicly
- available versions of such operating systems available under the GNU Public
- License version 2.0 or later (whether in gold, beta or alpha form) causes
- such combination to be covered by the Licensed Patents. The patent license
- shall not apply to any other combinations which include the Software. NO
- hardware per se is licensed hereunder.
-
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- IMPLIED WARRANTIES OF MECHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR IT CONTRIBUTORS BE LIABLE FOR ANY
- DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- (INCLUDING, BUT NOT LIMITED, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- ANY LOSS OF USE; DATA, OR PROFITS; OR BUSINESS INTERUPTION) HOWEVER CAUSED
- AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY OR
- TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*******************************************************************************/
-
-/* e1000_mac.c
- * Shared functions for accessing and configuring the MAC
- */
-
-#include "e1000_mac.h"
-#include "e1000_phy.h"
-
-/******************************************************************************
- * Raises the EEPROM's clock input.
- *
- * shared - Struct containing variables accessed by shared code
- * eecd_reg - EECD's current value
- *****************************************************************************/
-static void
-e1000_raise_clock(struct e1000_shared_adapter *shared,
- uint32_t *eecd_reg)
-{
- /* Raise the clock input to the EEPROM (by setting the SK bit), and then
- * wait 50 microseconds.
- */
- *eecd_reg = *eecd_reg | E1000_EECD_SK;
- E1000_WRITE_REG(shared, EECD, *eecd_reg);
- usec_delay(50);
- return;
-}
-
-/******************************************************************************
- * Lowers the EEPROM's clock input.
- *
- * shared - Struct containing variables accessed by shared code
- * eecd_reg - EECD's current value
- *****************************************************************************/
-static void
-e1000_lower_clock(struct e1000_shared_adapter *shared,
- uint32_t *eecd_reg)
-{
- /* Lower the clock input to the EEPROM (by clearing the SK bit), and then
- * wait 50 microseconds.
- */
- *eecd_reg = *eecd_reg & ~E1000_EECD_SK;
- E1000_WRITE_REG(shared, EECD, *eecd_reg);
- usec_delay(50);
- return;
-}
-
-/******************************************************************************
- * Shift data bits out to the EEPROM.
- *
- * shared - Struct containing variables accessed by shared code
- * data - data to send to the EEPROM
- * count - number of bits to shift out
- *****************************************************************************/
-static void
-e1000_shift_out_bits(struct e1000_shared_adapter *shared,
- uint16_t data,
- uint16_t count)
-{
- uint32_t eecd_reg;
- uint32_t mask;
-
- /* We need to shift "count" bits out to the EEPROM. So, value in the
- * "data" parameter will be shifted out to the EEPROM one bit at a time.
- * In order to do this, "data" must be broken down into bits.
- */
- mask = 0x01 << (count - 1);
- eecd_reg = E1000_READ_REG(shared, EECD);
- eecd_reg &= ~(E1000_EECD_DO | E1000_EECD_DI);
- do {
- /* A "1" is shifted out to the EEPROM by setting bit "DI" to a "1",
- * and then raising and then lowering the clock (the SK bit controls
- * the clock input to the EEPROM). A "0" is shifted out to the EEPROM
- * by setting "DI" to "0" and then raising and then lowering the clock.
- */
- eecd_reg &= ~E1000_EECD_DI;
-
- if(data & mask)
- eecd_reg |= E1000_EECD_DI;
-
- E1000_WRITE_REG(shared, EECD, eecd_reg);
-
- usec_delay(50);
-
- e1000_raise_clock(shared, &eecd_reg);
- e1000_lower_clock(shared, &eecd_reg);
-
- mask = mask >> 1;
-
- } while(mask);
-
- /* We leave the "DI" bit set to "0" when we leave this routine. */
- eecd_reg &= ~E1000_EECD_DI;
- E1000_WRITE_REG(shared, EECD, eecd_reg);
- return;
-}
-
-/******************************************************************************
- * Shift data bits in from the EEPROM
- *
- * shared - Struct containing variables accessed by shared code
- *****************************************************************************/
-static uint16_t
-e1000_shift_in_bits(struct e1000_shared_adapter *shared)
-{
- uint32_t eecd_reg;
- uint32_t i;
- uint16_t data;
-
- /* In order to read a register from the EEPROM, we need to shift 16 bits
- * in from the EEPROM. Bits are "shifted in" by raising the clock input to
- * the EEPROM (setting the SK bit), and then reading the value of the "DO"
- * bit. During this "shifting in" process the "DI" bit should always be
- * clear..
- */
-
- eecd_reg = E1000_READ_REG(shared, EECD);
-
- eecd_reg &= ~(E1000_EECD_DO | E1000_EECD_DI);
- data = 0;
-
- for(i = 0; i < 16; i++) {
- data = data << 1;
- e1000_raise_clock(shared, &eecd_reg);
-
- eecd_reg = E1000_READ_REG(shared, EECD);
-
- eecd_reg &= ~(E1000_EECD_DI);
- if(eecd_reg & E1000_EECD_DO)
- data |= 1;
-
- e1000_lower_clock(shared, &eecd_reg);
- }
-
- return data;
-}
-
-/******************************************************************************
- * Prepares EEPROM for access
- *
- * shared - Struct containing variables accessed by shared code
- *
- * Lowers EEPROM clock. Clears input pin. Sets the chip select pin. This
- * function should be called before issuing a command to the EEPROM.
- *****************************************************************************/
-static void
-e1000_setup_eeprom(struct e1000_shared_adapter *shared)
-{
- uint32_t eecd_reg;
-
- eecd_reg = E1000_READ_REG(shared, EECD);
-
- /* Clear SK and DI */
- eecd_reg &= ~(E1000_EECD_SK | E1000_EECD_DI);
- E1000_WRITE_REG(shared, EECD, eecd_reg);
-
- /* Set CS */
- eecd_reg |= E1000_EECD_CS;
- E1000_WRITE_REG(shared, EECD, eecd_reg);
- return;
-}
-
-/******************************************************************************
- * Returns EEPROM to a "standby" state
- *
- * shared - Struct containing variables accessed by shared code
- *****************************************************************************/
-static void
-e1000_standby_eeprom(struct e1000_shared_adapter *shared)
-{
- uint32_t eecd_reg;
-
- eecd_reg = E1000_READ_REG(shared, EECD);
-
- /* Deselct EEPROM */
- eecd_reg &= ~(E1000_EECD_CS | E1000_EECD_SK);
- E1000_WRITE_REG(shared, EECD, eecd_reg);
- usec_delay(50);
-
- /* Clock high */
- eecd_reg |= E1000_EECD_SK;
- E1000_WRITE_REG(shared, EECD, eecd_reg);
- usec_delay(50);
-
- /* Select EEPROM */
- eecd_reg |= E1000_EECD_CS;
- E1000_WRITE_REG(shared, EECD, eecd_reg);
- usec_delay(50);
-
- /* Clock low */
- eecd_reg &= ~E1000_EECD_SK;
- E1000_WRITE_REG(shared, EECD, eecd_reg);
- usec_delay(50);
- return;
-}
-
-
-/******************************************************************************
- * Forces the MAC's flow control settings.
- *
- * shared - Struct containing variables accessed by shared code
- *
- * Sets the TFCE and RFCE bits in the device control register to reflect
- * the adapter settings. TFCE and RFCE need to be explicitly set by
- * software when a Copper PHY is used because autonegotiation is managed
- * by the PHY rather than the MAC. Software must also configure these
- * bits when link is forced on a fiber connection.
- *****************************************************************************/
-static void
-e1000_force_mac_fc(struct e1000_shared_adapter *shared)
-{
- uint32_t ctrl_reg;
-
- DEBUGFUNC("e1000_force_mac_fc");
-
- /* Get the current configuration of the Device Control Register */
- ctrl_reg = E1000_READ_REG(shared, CTRL);
-
- /* Because we didn't get link via the internal auto-negotiation
- * mechanism (we either forced link or we got link via PHY
- * auto-neg), we have to manually enable/disable transmit an
- * receive flow control.
- *
- * The "Case" statement below enables/disable flow control
- * according to the "shared->fc" parameter.
- *
- * The possible values of the "fc" parameter are:
- * 0: Flow control is completely disabled
- * 1: Rx flow control is enabled (we can receive pause
- * frames but not send pause frames).
- * 2: Tx flow control is enabled (we can send pause frames
- * frames but we do not receive pause frames).
- * 3: Both Rx and TX flow control (symmetric) is enabled.
- * other: No other values should be possible at this point.
- */
-
- switch (shared->fc) {
- case e1000_fc_none:
- ctrl_reg &= (~(E1000_CTRL_TFCE | E1000_CTRL_RFCE));
- break;
- case e1000_fc_rx_pause:
- ctrl_reg &= (~E1000_CTRL_TFCE);
- ctrl_reg |= E1000_CTRL_RFCE;
- break;
- case e1000_fc_tx_pause:
- ctrl_reg &= (~E1000_CTRL_RFCE);
- ctrl_reg |= E1000_CTRL_TFCE;
- break;
- case e1000_fc_full:
- ctrl_reg |= (E1000_CTRL_TFCE | E1000_CTRL_RFCE);
- break;
- default:
- DEBUGOUT("Flow control param set incorrectly\n");
- ASSERT(0);
- break;
- }
-
- /* Disable TX Flow Control for 82542 (rev 2.0) */
- if(shared->mac_type == e1000_82542_rev2_0)
- ctrl_reg &= (~E1000_CTRL_TFCE);
-
-
- E1000_WRITE_REG(shared, CTRL, ctrl_reg);
- return;
-}
-
-/******************************************************************************
- * Reset the transmit and receive units; mask and clear all interrupts.
- *
- * shared - Struct containing variables accessed by shared code
- *****************************************************************************/
-void
-e1000_adapter_stop(struct e1000_shared_adapter *shared)
-{
- uint32_t ctrl_reg;
- uint32_t ctrl_ext_reg;
- uint32_t icr_reg;
- uint16_t pci_cmd_word;
-
- DEBUGFUNC("e1000_shared_adapter_stop");
-
- /* If we are stopped or resetting exit gracefully and wait to be
- * started again before accessing the hardware.
- */
- if(shared->adapter_stopped) {
- DEBUGOUT("Exiting because the adapter is already stopped!!!\n");
- return;
- }
-
- /* Set the Adapter Stopped flag so other driver functions stop
- * touching the Hardware.
- */
- shared->adapter_stopped = TRUE;
-
- /* For 82542 (rev 2.0), disable MWI before issuing a device reset */
- if(shared->mac_type == e1000_82542_rev2_0) {
- if(shared->pci_cmd_word & CMD_MEM_WRT_INVALIDATE) {
- DEBUGOUT("Disabling MWI on 82542 rev 2.0\n");
-
- pci_cmd_word = shared->pci_cmd_word & ~CMD_MEM_WRT_INVALIDATE;
-
- e1000_write_pci_cfg(shared, PCI_COMMAND_REGISTER, &pci_cmd_word);
- }
- }
-
- /* Clear interrupt mask to stop board from generating interrupts */
- DEBUGOUT("Masking off all interrupts\n");
- E1000_WRITE_REG(shared, IMC, 0xffffffff);
-
- /* Disable the Transmit and Receive units. Then delay to allow
- * any pending transactions to complete before we hit the MAC with
- * the global reset.
- */
- E1000_WRITE_REG(shared, RCTL, 0);
- E1000_WRITE_REG(shared, TCTL, E1000_TCTL_PSP);
-
- /* The tbi_compatibility_on Flag must be cleared when Rctl is cleared. */
- shared->tbi_compatibility_on = FALSE;
-
- msec_delay(10);
-
- /* Issue a global reset to the MAC. This will reset the chip's
- * transmit, receive, DMA, and link units. It will not effect
- * the current PCI configuration. The global reset bit is self-
- * clearing, and should clear within a microsecond.
- */
- DEBUGOUT("Issuing a global reset to MAC\n");
- ctrl_reg = E1000_READ_REG(shared, CTRL);
- E1000_WRITE_REG(shared, CTRL, (ctrl_reg | E1000_CTRL_RST));
-
- /* Delay a few ms just to allow the reset to complete */
- msec_delay(10);
-
-#if DBG
- /* Make sure the self-clearing global reset bit did self clear */
- ctrl_reg = E1000_READ_REG(shared, CTRL);
-
- ASSERT(!(ctrl_reg & E1000_CTRL_RST));
-#endif
-
- /* Force a reload from the EEPROM */
- ctrl_ext_reg = E1000_READ_REG(shared, CTRL_EXT);
- ctrl_ext_reg |= E1000_CTRL_EXT_EE_RST;
- E1000_WRITE_REG(shared, CTRL_EXT, ctrl_ext_reg);
- msec_delay(2);
-
- /* Clear interrupt mask to stop board from generating interrupts */
- DEBUGOUT("Masking off all interrupts\n");
- E1000_WRITE_REG(shared, IMC, 0xffffffff);
-
- /* Clear any pending interrupt events. */
- icr_reg = E1000_READ_REG(shared, ICR);
-
- /* If MWI was previously enabled, reenable it. */
- if(shared->mac_type == e1000_82542_rev2_0) {
- if(shared->pci_cmd_word & CMD_MEM_WRT_INVALIDATE) {
- e1000_write_pci_cfg(shared,
- PCI_COMMAND_REGISTER, &shared->pci_cmd_word);
- }
- }
- return;
-}
-
-/******************************************************************************
- * Performs basic configuration of the adapter.
- *
- * shared - Struct containing variables accessed by shared code
- *
- * Assumes that the controller has previously been reset and is in a
- * post-reset uninitialized state. Initializes the receive address registers,
- * multicast table, and VLAN filter table. Calls routines to setup link
- * configuration and flow control settings. Clears all on-chip counters. Leaves
- * the transmit and receive units disabled and uninitialized.
- *****************************************************************************/
-boolean_t
-e1000_init_hw(struct e1000_shared_adapter *shared)
-{
- uint32_t status_reg;
- uint32_t i;
- uint16_t pci_cmd_word;
- boolean_t status;
-
- DEBUGFUNC("e1000_init_hw");
-
- /* Set the Media Type and exit with error if it is not valid. */
- if(shared->mac_type != e1000_82543) {
- /* tbi_compatibility is only valid on 82543 */
- shared->tbi_compatibility_en = FALSE;
- }
-
- if(shared->mac_type >= e1000_82543) {
- status_reg = E1000_READ_REG(shared, STATUS);
- if(status_reg & E1000_STATUS_TBIMODE) {
- shared->media_type = e1000_media_type_fiber;
- /* tbi_compatibility not valid on fiber */
- shared->tbi_compatibility_en = FALSE;
- } else {
- shared->media_type = e1000_media_type_copper;
- }
- } else {
- /* This is an 82542 (fiber only) */
- shared->media_type = e1000_media_type_fiber;
- }
-
- /* Disabling VLAN filtering. */
- DEBUGOUT("Initializing the IEEE VLAN\n");
- E1000_WRITE_REG(shared, VET, 0);
-
- e1000_clear_vfta(shared);
-
- /* For 82542 (rev 2.0), disable MWI and put the receiver into reset */
- if(shared->mac_type == e1000_82542_rev2_0) {
- if(shared->pci_cmd_word & CMD_MEM_WRT_INVALIDATE) {
- DEBUGOUT("Disabling MWI on 82542 rev 2.0\n");
- pci_cmd_word = shared->pci_cmd_word & ~CMD_MEM_WRT_INVALIDATE;
- e1000_write_pci_cfg(shared, PCI_COMMAND_REGISTER, &pci_cmd_word);
- }
- E1000_WRITE_REG(shared, RCTL, E1000_RCTL_RST);
-
- msec_delay(5);
- }
-
- /* Setup the receive address. This involves initializing all of the Receive
- * Address Registers (RARs 0 - 15).
- */
- e1000_init_rx_addrs(shared);
-
- /* For 82542 (rev 2.0), take the receiver out of reset and enable MWI */
- if(shared->mac_type == e1000_82542_rev2_0) {
- E1000_WRITE_REG(shared, RCTL, 0);
-
- msec_delay(1);
-
- if(shared->pci_cmd_word & CMD_MEM_WRT_INVALIDATE) {
- e1000_write_pci_cfg(shared,
- PCI_COMMAND_REGISTER, &shared->pci_cmd_word);
- }
- }
-
- /* Zero out the Multicast HASH table */
- DEBUGOUT("Zeroing the MTA\n");
- for(i = 0; i < E1000_MC_TBL_SIZE; i++)
- E1000_WRITE_REG_ARRAY(shared, MTA, i, 0);
-
- /* Call a subroutine to configure the link and setup flow control. */
- status = e1000_setup_fc_and_link(shared);
-
- /* Clear all of the statistics registers (clear on read). It is
- * important that we do this after we have tried to establish link
- * because the symbol error count will increment wildly if there
- * is no link.
- */
- e1000_clear_hw_cntrs(shared);
-
- return (status);
-}
-
-/******************************************************************************
- * Initializes receive address filters.
- *
- * shared - Struct containing variables accessed by shared code
- *
- * Places the MAC address in receive address register 0 and clears the rest
- * of the receive addresss registers. Clears the multicast table. Assumes
- * the receiver is in reset when the routine is called.
- *****************************************************************************/
-void
-e1000_init_rx_addrs(struct e1000_shared_adapter *shared)
-{
- uint32_t i;
- uint32_t addr_low;
- uint32_t addr_high;
-
- DEBUGFUNC("e1000_init_rx_addrs");
-
- /* Setup the receive address. */
- DEBUGOUT("Programming MAC Address into RAR[0]\n");
- addr_low = (shared->mac_addr[0] |
- (shared->mac_addr[1] << 8) |
- (shared->mac_addr[2] << 16) | (shared->mac_addr[3] << 24));
-
- addr_high = (shared->mac_addr[4] |
- (shared->mac_addr[5] << 8) | E1000_RAH_AV);
-
- E1000_WRITE_REG_ARRAY(shared, RA, 0, addr_low);
- E1000_WRITE_REG_ARRAY(shared, RA, 1, addr_high);
-
- /* Zero out the other 15 receive addresses. */
- DEBUGOUT("Clearing RAR[1-15]\n");
- for(i = 1; i < E1000_RAR_ENTRIES; i++) {
- E1000_WRITE_REG_ARRAY(shared, RA, (i << 1), 0);
- E1000_WRITE_REG_ARRAY(shared, RA, ((i << 1) + 1), 0);
- }
-
- return;
-}
-
-/******************************************************************************
- * Updates the MAC's list of multicast addresses.
- *
- * shared - Struct containing variables accessed by shared code
- * mc_addr_list - the list of new multicast addresses
- * mc_addr_count - number of addresses
- * pad - number of bytes between addresses in the list
- *
- * The given list replaces any existing list. Clears the last 15 receive
- * address registers and the multicast table. Uses receive address registers
- * for the first 15 multicast addresses, and hashes the rest into the
- * multicast table.
- *****************************************************************************/
-void
-e1000_mc_addr_list_update(struct e1000_shared_adapter *shared,
- uint8_t *mc_addr_list,
- uint32_t mc_addr_count,
- uint32_t pad)
-{
- uint32_t hash_value;
- uint32_t i;
- uint32_t rar_used_count = 1; /* RAR[0] is used for our MAC address */
-
- DEBUGFUNC("e1000_mc_addr_list_update");
-
- /* Set the new number of MC addresses that we are being requested to use. */
- shared->num_mc_addrs = mc_addr_count;
-
- /* Clear RAR[1-15] */
- DEBUGOUT(" Clearing RAR[1-15]\n");
- for(i = rar_used_count; i < E1000_RAR_ENTRIES; i++) {
- E1000_WRITE_REG_ARRAY(shared, RA, (i << 1), 0);
- E1000_WRITE_REG_ARRAY(shared, RA, ((i << 1) + 1), 0);
- }
-
- /* Clear the MTA */
- DEBUGOUT(" Clearing MTA\n");
- for(i = 0; i < E1000_NUM_MTA_REGISTERS; i++) {
- E1000_WRITE_REG_ARRAY(shared, MTA, i, 0);
- }
-
- /* Add the new addresses */
- for(i = 0; i < mc_addr_count; i++) {
- DEBUGOUT(" Adding the multicast addresses:\n");
- DEBUGOUT7(" MC Addr #%d =%.2X %.2X %.2X %.2X %.2X %.2X\n", i,
- mc_addr_list[i * (ETH_LENGTH_OF_ADDRESS + pad)],
- mc_addr_list[i * (ETH_LENGTH_OF_ADDRESS + pad) + 1],
- mc_addr_list[i * (ETH_LENGTH_OF_ADDRESS + pad) + 2],
- mc_addr_list[i * (ETH_LENGTH_OF_ADDRESS + pad) + 3],
- mc_addr_list[i * (ETH_LENGTH_OF_ADDRESS + pad) + 4],
- mc_addr_list[i * (ETH_LENGTH_OF_ADDRESS + pad) + 5]);
-
- hash_value = e1000_hash_mc_addr(shared,
- mc_addr_list +
- (i * (ETH_LENGTH_OF_ADDRESS + pad)));
-
- DEBUGOUT1(" Hash value = 0x%03X\n", hash_value);
-
- /* Place this multicast address in the RAR if there is room, *
- * else put it in the MTA
- */
- if(rar_used_count < E1000_RAR_ENTRIES) {
- e1000_rar_set(shared,
- mc_addr_list + (i * (ETH_LENGTH_OF_ADDRESS + pad)),
- rar_used_count);
- rar_used_count++;
- } else {
- e1000_mta_set(shared, hash_value);
- }
- }
-
- DEBUGOUT("MC Update Complete\n");
- return;
-}
-
-/******************************************************************************
- * Hashes an address to determine its location in the multicast table
- *
- * shared - Struct containing variables accessed by shared code
- * mc_addr - the multicast address to hash
- *****************************************************************************/
-uint32_t
-e1000_hash_mc_addr(struct e1000_shared_adapter *shared,
- uint8_t *mc_addr)
-{
- uint32_t hash_value = 0;
-
- /* The portion of the address that is used for the hash table is
- * determined by the mc_filter_type setting.
- */
- switch (shared->mc_filter_type) {
- /* [0] [1] [2] [3] [4] [5]
- * 01 AA 00 12 34 56
- * LSB MSB - According to H/W docs */
- case 0:
- /* [47:36] i.e. 0x563 for above example address */
- hash_value = ((mc_addr[4] >> 4) | (((uint16_t) mc_addr[5]) << 4));
- break;
- case 1: /* [46:35] i.e. 0xAC6 for above example address */
- hash_value = ((mc_addr[4] >> 3) | (((uint16_t) mc_addr[5]) << 5));
- break;
- case 2: /* [45:34] i.e. 0x5D8 for above example address */
- hash_value = ((mc_addr[4] >> 2) | (((uint16_t) mc_addr[5]) << 6));
- break;
- case 3: /* [43:32] i.e. 0x634 for above example address */
- hash_value = ((mc_addr[4]) | (((uint16_t) mc_addr[5]) << 8));
- break;
- }
-
- hash_value &= 0xFFF;
- return (hash_value);
-}
-
-/******************************************************************************
- * Sets the bit in the multicast table corresponding to the hash value.
- *
- * shared - Struct containing variables accessed by shared code
- * hash_value - Multicast address hash value
- *****************************************************************************/
-void
-e1000_mta_set(struct e1000_shared_adapter *shared,
- uint32_t hash_value)
-{
- uint32_t hash_bit, hash_reg;
- uint32_t mta_reg;
- uint32_t temp;
-
- /* The MTA is a register array of 128 32-bit registers.
- * It is treated like an array of 4096 bits. We want to set
- * bit BitArray[hash_value]. So we figure out what register
- * the bit is in, read it, OR in the new bit, then write
- * back the new value. The register is determined by the
- * upper 7 bits of the hash value and the bit within that
- * register are determined by the lower 5 bits of the value.
- */
- hash_reg = (hash_value >> 5) & 0x7F;
- hash_bit = hash_value & 0x1F;
-
- mta_reg = E1000_READ_REG_ARRAY(shared, MTA, hash_reg);
-
- mta_reg |= (1 << hash_bit);
-
- /* If we are on an 82544 and we are trying to write an odd offset
- * in the MTA, save off the previous entry before writing and
- * restore the old value after writing.
- */
- if((shared->mac_type == e1000_82544) && ((hash_reg & 0x1) == 1)) {
- temp = E1000_READ_REG_ARRAY(shared, MTA, (hash_reg - 1));
- E1000_WRITE_REG_ARRAY(shared, MTA, hash_reg, mta_reg);
- E1000_WRITE_REG_ARRAY(shared, MTA, (hash_reg - 1), temp);
- } else {
- E1000_WRITE_REG_ARRAY(shared, MTA, hash_reg, mta_reg);
- }
- return;
-}
-
-/******************************************************************************
- * Puts an ethernet address into a receive address register.
- *
- * shared - Struct containing variables accessed by shared code
- * addr - Address to put into receive address register
- * index - Receive address register to write
- *****************************************************************************/
-void
-e1000_rar_set(struct e1000_shared_adapter *shared,
- uint8_t *addr,
- uint32_t index)
-{
- uint32_t rar_low, rar_high;
-
- /* HW expects these in little endian so we reverse the byte order
- * from network order (big endian) to little endian
- */
- rar_low = ((uint32_t) addr[0] |
- ((uint32_t) addr[1] << 8) |
- ((uint32_t) addr[2] << 16) | ((uint32_t) addr[3] << 24));
-
- rar_high = ((uint32_t) addr[4] | ((uint32_t) addr[5] << 8) | E1000_RAH_AV);
-
- E1000_WRITE_REG_ARRAY(shared, RA, (index << 1), rar_low);
- E1000_WRITE_REG_ARRAY(shared, RA, ((index << 1) + 1), rar_high);
- return;
-}
-
-/******************************************************************************
- * Writes a value to the specified offset in the VLAN filter table.
- *
- * shared - Struct containing variables accessed by shared code
- * offset - Offset in VLAN filer table to write
- * value - Value to write into VLAN filter table
- *****************************************************************************/
-void
-e1000_write_vfta(struct e1000_shared_adapter *shared,
- uint32_t offset,
- uint32_t value)
-{
- uint32_t temp;
-
- if((shared->mac_type == e1000_82544) && ((offset & 0x1) == 1)) {
- temp = E1000_READ_REG_ARRAY(shared, VFTA, (offset - 1));
- E1000_WRITE_REG_ARRAY(shared, VFTA, offset, value);
- E1000_WRITE_REG_ARRAY(shared, VFTA, (offset - 1), temp);
- } else {
- E1000_WRITE_REG_ARRAY(shared, VFTA, offset, value);
- }
- return;
-}
-
-/******************************************************************************
- * Clears the VLAN filer table
- *
- * shared - Struct containing variables accessed by shared code
- *****************************************************************************/
-void
-e1000_clear_vfta(struct e1000_shared_adapter *shared)
-{
- uint32_t offset;
-
- for(offset = 0; offset < E1000_VLAN_FILTER_TBL_SIZE; offset++)
- E1000_WRITE_REG_ARRAY(shared, VFTA, offset, 0);
- return;
-}
-
-/******************************************************************************
- * Configures flow control and link settings.
- *
- * shared - Struct containing variables accessed by shared code
- *
- * Determines which flow control settings to use. Calls the apropriate media-
- * specific link configuration function. Configures the flow control settings.
- * Assuming the adapter has a valid link partner, a valid link should be
- * established. Assumes the hardware has previously been reset and the
- * transmitter and receiver are not enabled.
- *****************************************************************************/
-boolean_t
-e1000_setup_fc_and_link(struct e1000_shared_adapter *shared)
-{
- uint32_t ctrl_reg;
- uint32_t eecd_reg;
- uint32_t ctrl_ext_reg;
- boolean_t status = TRUE;
-
- DEBUGFUNC("e1000_setup_fc_and_link");
-
- /* Read the SWDPIO bits and the ILOS bit out of word 0x0A in the
- * EEPROM. Store these bits in a variable that we will later write
- * to the Device Control Register (CTRL).
- */
- eecd_reg = e1000_read_eeprom(shared, EEPROM_INIT_CONTROL1_REG);
-
- ctrl_reg =
- (((eecd_reg & EEPROM_WORD0A_SWDPIO) << SWDPIO_SHIFT) |
- ((eecd_reg & EEPROM_WORD0A_ILOS) << ILOS_SHIFT));
-
- /* Set the PCI priority bit correctly in the CTRL register. This
- * determines if the adapter gives priority to receives, or if it
- * gives equal priority to transmits and receives.
- */
- if(shared->dma_fairness)
- ctrl_reg |= E1000_CTRL_PRIOR;
-
- /* Read and store word 0x0F of the EEPROM. This word contains bits
- * that determine the hardware's default PAUSE (flow control) mode,
- * a bit that determines whether the HW defaults to enabling or
- * disabling auto-negotiation, and the direction of the
- * SW defined pins. If there is no SW over-ride of the flow
- * control setting, then the variable shared->fc will
- * be initialized based on a value in the EEPROM.
- */
- eecd_reg = e1000_read_eeprom(shared, EEPROM_INIT_CONTROL2_REG);
-
- if(shared->fc > e1000_fc_full) {
- if((eecd_reg & EEPROM_WORD0F_PAUSE_MASK) == 0)
- shared->fc = e1000_fc_none;
- else if((eecd_reg & EEPROM_WORD0F_PAUSE_MASK) == EEPROM_WORD0F_ASM_DIR)
- shared->fc = e1000_fc_tx_pause;
- else
- shared->fc = e1000_fc_full;
- }
-
- /* We want to save off the original Flow Control configuration just
- * in case we get disconnected and then reconnected into a different
- * hub or switch with different Flow Control capabilities.
- */
- shared->original_fc = shared->fc;
-
- if(shared->mac_type == e1000_82542_rev2_0)
- shared->fc &= (~e1000_fc_tx_pause);
-
- if((shared->mac_type < e1000_82543) && (shared->report_tx_early == 1))
- shared->fc &= (~e1000_fc_rx_pause);
-
- DEBUGOUT1("After fix-ups FlowControl is now = %x\n", shared->fc);
-
- /* Take the 4 bits from EEPROM word 0x0F that determine the initial
- * polarity value for the SW controlled pins, and setup the
- * Extended Device Control reg with that info.
- * This is needed because one of the SW controlled pins is used for
- * signal detection. So this should be done before e1000_setup_pcs_link()
- * or e1000_phy_setup() is called.
- */
- if(shared->mac_type == e1000_82543) {
- ctrl_ext_reg = ((eecd_reg & EEPROM_WORD0F_SWPDIO_EXT)
- << SWDPIO__EXT_SHIFT);
- E1000_WRITE_REG(shared, CTRL_EXT, ctrl_ext_reg);
- }
-
- /* Call the necessary subroutine to configure the link. */
- if(shared->media_type == e1000_media_type_fiber)
- status = e1000_setup_pcs_link(shared, ctrl_reg);
- else
- status = e1000_phy_setup(shared, ctrl_reg);
-
- /* Initialize the flow control address, type, and PAUSE timer
- * registers to their default values. This is done even if flow
- * control is disabled, because it does not hurt anything to
- * initialize these registers.
- */
- DEBUGOUT("Initializing the Flow Control address, type and timer regs\n");
-
- E1000_WRITE_REG(shared, FCAL, FLOW_CONTROL_ADDRESS_LOW);
- E1000_WRITE_REG(shared, FCAH, FLOW_CONTROL_ADDRESS_HIGH);
- E1000_WRITE_REG(shared, FCT, FLOW_CONTROL_TYPE);
- E1000_WRITE_REG(shared, FCTTV, shared->fc_pause_time);
-
- /* Set the flow control receive threshold registers. Normally,
- * these registers will be set to a default threshold that may be
- * adjusted later by the driver's runtime code. However, if the
- * ability to transmit pause frames in not enabled, then these
- * registers will be set to 0.
- */
- if(!(shared->fc & e1000_fc_tx_pause)) {
- E1000_WRITE_REG(shared, FCRTL, 0);
- E1000_WRITE_REG(shared, FCRTH, 0);
- } else {
- /* We need to set up the Receive Threshold high and low water marks
- * as well as (optionally) enabling the transmission of XON frames.
- */
- if(shared->fc_send_xon) {
- E1000_WRITE_REG(shared, FCRTL,
- (shared->fc_low_water | E1000_FCRTL_XONE));
- E1000_WRITE_REG(shared, FCRTH, shared->fc_high_water);
- } else {
- E1000_WRITE_REG(shared, FCRTL, shared->fc_low_water);
- E1000_WRITE_REG(shared, FCRTH, shared->fc_high_water);
- }
- }
- return (status);
-}
-
-/******************************************************************************
- * Sets up link for a fiber based adapter
- *
- * shared - Struct containing variables accessed by shared code
- * ctrl_reg - Current value of the device control register
- *
- * Manipulates Physical Coding Sublayer functions in order to configure
- * link. Assumes the hardware has been previously reset and the transmitter
- * and receiver are not enabled.
- *****************************************************************************/
-boolean_t
-e1000_setup_pcs_link(struct e1000_shared_adapter *shared,
- uint32_t ctrl_reg)
-{
- uint32_t status_reg;
- uint32_t tctl_reg;
- uint32_t txcw_reg = 0;
- uint32_t i;
-
- DEBUGFUNC("e1000_setup_pcs_link");
-
- /* Setup the collsion distance. Since this is configuring the
- * TBI it is assumed that we are in Full Duplex.
- */
- tctl_reg = E1000_READ_REG(shared, TCTL);
- i = E1000_FDX_COLLISION_DISTANCE;
- i <<= E1000_COLD_SHIFT;
- tctl_reg |= i;
- E1000_WRITE_REG(shared, TCTL, tctl_reg);
-
- /* Check for a software override of the flow control settings, and
- * setup the device accordingly. If auto-negotiation is enabled,
- * then software will have to set the "PAUSE" bits to the correct
- * value in the Tranmsit Config Word Register (TXCW) and re-start
- * auto-negotiation. However, if auto-negotiation is disabled,
- * then software will have to manually configure the two flow
- * control enable bits in the CTRL register.
- *
- * The possible values of the "fc" parameter are:
- * 0: Flow control is completely disabled
- * 1: Rx flow control is enabled (we can receive pause frames
- * but not send pause frames).
- * 2: Tx flow control is enabled (we can send pause frames
- * but we do not support receiving pause frames).
- * 3: Both Rx and TX flow control (symmetric) are enabled.
- * other: No software override. The flow control configuration
- * in the EEPROM is used.
- */
- switch (shared->fc) {
- case e1000_fc_none: /* 0 */
- /* Flow control (RX & TX) is completely disabled by a
- * software over-ride.
- */
- txcw_reg = (E1000_TXCW_ANE | E1000_TXCW_FD);
- break;
- case e1000_fc_rx_pause: /* 1 */
- /* RX Flow control is enabled, and TX Flow control is
- * disabled, by a software over-ride.
- */
- /* Since there really isn't a way to advertise that we are
- * capable of RX Pause ONLY, we will advertise that we
- * support both symmetric and asymmetric RX PAUSE. Later
- * we will disable the adapter's ability to send PAUSE
- * frames.
- */
- txcw_reg = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_PAUSE_MASK);
- break;
- case e1000_fc_tx_pause: /* 2 */
- /* TX Flow control is enabled, and RX Flow control is
- * disabled, by a software over-ride.
- */
- txcw_reg = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_ASM_DIR);
- break;
- case e1000_fc_full: /* 3 */
- /* Flow control (both RX and TX) is enabled by a software
- * over-ride.
- */
- txcw_reg = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_PAUSE_MASK);
- break;
- default:
- /* We should never get here. The value should be 0-3. */
- DEBUGOUT("Flow control param set incorrectly\n");
- ASSERT(0);
- break;
- }
-
- /* Since auto-negotiation is enabled, take the link out of reset.
- * (the link will be in reset, because we previously reset the
- * chip). This will restart auto-negotiation. If auto-neogtiation
- * is successful then the link-up status bit will be set and the
- * flow control enable bits (RFCE and TFCE) will be set according
- * to their negotiated value.
- */
- DEBUGOUT("Auto-negotiation enabled\n");
-
- E1000_WRITE_REG(shared, TXCW, txcw_reg);
- E1000_WRITE_REG(shared, CTRL, ctrl_reg);
-
- shared->txcw_reg = txcw_reg;
- msec_delay(1);
-
- /* If we have a signal then poll for a "Link-Up" indication in the
- * Device Status Register. Time-out if a link isn't seen in 500
- * milliseconds seconds (Auto-negotiation should complete in less
- * than 500 milliseconds even if the other end is doing it in SW).
- */
- if(!(E1000_READ_REG(shared, CTRL) & E1000_CTRL_SWDPIN1)) {
-
- DEBUGOUT("Looking for Link\n");
- for(i = 0; i < (LINK_UP_TIMEOUT / 10); i++) {
- msec_delay(10);
- status_reg = E1000_READ_REG(shared, STATUS);
- if(status_reg & E1000_STATUS_LU)
- break;
- }
-
- if(i == (LINK_UP_TIMEOUT / 10)) {
- /* AutoNeg failed to achieve a link, so we'll call the
- * "CheckForLink" routine. This routine will force the link
- * up if we have "signal-detect". This will allow us to
- * communicate with non-autonegotiating link partners.
- */
- DEBUGOUT("Never got a valid link from auto-neg!!!\n");
-
- shared->autoneg_failed = 1;
- e1000_check_for_link(shared);
- shared->autoneg_failed = 0;
- } else {
- shared->autoneg_failed = 0;
- DEBUGOUT("Valid Link Found\n");
- }
- } else {
- DEBUGOUT("No Signal Detected\n");
- }
-
- return (TRUE);
-}
-
-/******************************************************************************
- * Configures flow control settings after link is established
- *
- * shared - Struct containing variables accessed by shared code
- *
- * Should be called immediately after a valid link has been established.
- * Forces MAC flow control settings if link was forced. When in MII/GMII mode
- * and autonegotiation is enabled, the MAC flow control settings will be set
- * based on the flow control negotiated by the PHY. In TBI mode, the TFCE
- * and RFCE bits will be automaticaly set to the negotiated flow control mode.
- *****************************************************************************/
-void
-e1000_config_fc_after_link_up(struct e1000_shared_adapter *shared)
-{
- uint16_t mii_status_reg;
- uint16_t mii_nway_adv_reg;
- uint16_t mii_nway_lp_ability_reg;
- uint16_t speed;
- uint16_t duplex;
-
- DEBUGFUNC("e1000_config_fc_after_link_up");
-
- /* Check for the case where we have fiber media and auto-neg failed
- * so we had to force link. In this case, we need to force the
- * configuration of the MAC to match the "fc" parameter.
- */
- if(((shared->media_type == e1000_media_type_fiber)
- && (shared->autoneg_failed))
- || ((shared->media_type == e1000_media_type_copper)
- && (!shared->autoneg))) {
- e1000_force_mac_fc(shared);
- }
-
- /* Check for the case where we have copper media and auto-neg is
- * enabled. In this case, we need to check and see if Auto-Neg
- * has completed, and if so, how the PHY and link partner has
- * flow control configured.
- */
- if((shared->media_type == e1000_media_type_copper) && shared->autoneg) {
- /* Read the MII Status Register and check to see if AutoNeg
- * has completed. We read this twice because this reg has
- * some "sticky" (latched) bits.
- */
- mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS);
- mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS);
-
- if(mii_status_reg & MII_SR_AUTONEG_COMPLETE) {
- /* The AutoNeg process has completed, so we now need to
- * read both the Auto Negotiation Advertisement Register
- * (Address 4) and the Auto_Negotiation Base Page Ability
- * Register (Address 5) to determine how flow control was
- * negotiated.
- */
- mii_nway_adv_reg = e1000_read_phy_reg(shared,
- PHY_AUTONEG_ADV);
- mii_nway_lp_ability_reg = e1000_read_phy_reg(shared,
- PHY_LP_ABILITY);
-
- /* Two bits in the Auto Negotiation Advertisement Register
- * (Address 4) and two bits in the Auto Negotiation Base
- * Page Ability Register (Address 5) determine flow control
- * for both the PHY and the link partner. The following
- * table, taken out of the IEEE 802.3ab/D6.0 dated March 25,
- * 1999, describes these PAUSE resolution bits and how flow
- * control is determined based upon these settings.
- * NOTE: DC = Don't Care
- *
- * LOCAL DEVICE | LINK PARTNER
- * PAUSE | ASM_DIR | PAUSE | ASM_DIR | NIC Resolution
- *-------|---------|-------|---------|--------------------
- * 0 | 0 | DC | DC | e1000_fc_none
- * 0 | 1 | 0 | DC | e1000_fc_none
- * 0 | 1 | 1 | 0 | e1000_fc_none
- * 0 | 1 | 1 | 1 | e1000_fc_tx_pause
- * 1 | 0 | 0 | DC | e1000_fc_none
- * 1 | DC | 1 | DC | e1000_fc_full
- * 1 | 1 | 0 | 0 | e1000_fc_none
- * 1 | 1 | 0 | 1 | e1000_fc_rx_pause
- *
- */
- /* Are both PAUSE bits set to 1? If so, this implies
- * Symmetric Flow Control is enabled at both ends. The
- * ASM_DIR bits are irrelevant per the spec.
- *
- * For Symmetric Flow Control:
- *
- * LOCAL DEVICE | LINK PARTNER
- * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
- *-------|---------|-------|---------|--------------------
- * 1 | DC | 1 | DC | e1000_fc_full
- *
- */
- if((mii_nway_adv_reg & NWAY_AR_PAUSE) &&
- (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE)) {
- /* Now we need to check if the user selected RX ONLY
- * of pause frames. In this case, we had to advertise
- * FULL flow control because we could not advertise RX
- * ONLY. Hence, we must now check to see if we need to
- * turn OFF the TRANSMISSION of PAUSE frames.
- */
- if(shared->original_fc == e1000_fc_full) {
- shared->fc = e1000_fc_full;
- DEBUGOUT("Flow Control = FULL.\r\n");
- } else {
- shared->fc = e1000_fc_rx_pause;
- DEBUGOUT("Flow Control = RX PAUSE frames only.\r\n");
- }
- }
- /* For receiving PAUSE frames ONLY.
- *
- * LOCAL DEVICE | LINK PARTNER
- * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
- *-------|---------|-------|---------|--------------------
- * 0 | 1 | 1 | 1 | e1000_fc_tx_pause
- *
- */
- else if(!(mii_nway_adv_reg & NWAY_AR_PAUSE) &&
- (mii_nway_adv_reg & NWAY_AR_ASM_DIR) &&
- (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) &&
- (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) {
- shared->fc = e1000_fc_tx_pause;
- DEBUGOUT("Flow Control = TX PAUSE frames only.\r\n");
- }
- /* For transmitting PAUSE frames ONLY.
- *
- * LOCAL DEVICE | LINK PARTNER
- * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
- *-------|---------|-------|---------|--------------------
- * 1 | 1 | 0 | 1 | e1000_fc_rx_pause
- *
- */
- else if((mii_nway_adv_reg & NWAY_AR_PAUSE) &&
- (mii_nway_adv_reg & NWAY_AR_ASM_DIR) &&
- !(mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) &&
- (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) {
- shared->fc = e1000_fc_rx_pause;
- DEBUGOUT("Flow Control = RX PAUSE frames only.\r\n");
- }
- /* Per the IEEE spec, at this point flow control should be
- * disabled. However, we want to consider that we could
- * be connected to a legacy switch that doesn't advertise
- * desired flow control, but can be forced on the link
- * partner. So if we advertised no flow control, that is
- * what we will resolve to. If we advertised some kind of
- * receive capability (Rx Pause Only or Full Flow Control)
- * and the link partner advertised none, we will configure
- * ourselves to enable Rx Flow Control only. We can do
- * this safely for two reasons: If the link partner really
- * didn't want flow control enabled, and we enable Rx, no
- * harm done since we won't be receiving any PAUSE frames
- * anyway. If the intent on the link partner was to have
- * flow control enabled, then by us enabling RX only, we
- * can at least receive pause frames and process them.
- * This is a good idea because in most cases, since we are
- * predominantly a server NIC, more times than not we will
- * be asked to delay transmission of packets than asking
- * our link partner to pause transmission of frames.
- */
- else if(shared->original_fc == e1000_fc_none ||
- shared->original_fc == e1000_fc_tx_pause) {
- shared->fc = e1000_fc_none;
- DEBUGOUT("Flow Control = NONE.\r\n");
- } else {
- shared->fc = e1000_fc_rx_pause;
- DEBUGOUT("Flow Control = RX PAUSE frames only.\r\n");
- }
-
- /* Now we need to do one last check... If we auto-
- * negotiated to HALF DUPLEX, flow control should not be
- * enabled per IEEE 802.3 spec.
- */
- e1000_get_speed_and_duplex(shared, &speed, &duplex);
-
- if(duplex == HALF_DUPLEX)
- shared->fc = e1000_fc_none;
-
- /* Now we call a subroutine to actually force the MAC
- * controller to use the correct flow control settings.
- */
- e1000_force_mac_fc(shared);
- } else {
- DEBUGOUT("Copper PHY and Auto Neg has not completed.\r\n");
- }
- }
- return;
-}
-
-/******************************************************************************
- * Checks to see if the link status of the hardware has changed.
- *
- * shared - Struct containing variables accessed by shared code
- *
- * Called by any function that needs to check the link status of the adapter.
- *****************************************************************************/
-void
-e1000_check_for_link(struct e1000_shared_adapter *shared)
-{
- uint32_t rxcw_reg;
- uint32_t ctrl_reg;
- uint32_t status_reg;
- uint32_t rctl_reg;
- uint16_t phy_data;
- uint16_t lp_capability;
-
- DEBUGFUNC("e1000_check_for_link");
-
- ctrl_reg = E1000_READ_REG(shared, CTRL);
- status_reg = E1000_READ_REG(shared, STATUS);
- rxcw_reg = E1000_READ_REG(shared, RXCW);
-
- /* If we have a copper PHY then we only want to go out to the PHY
- * registers to see if Auto-Neg has completed and/or if our link
- * status has changed. The get_link_status flag will be set if we
- * receive a Link Status Change interrupt or we have Rx Sequence
- * Errors.
- */
- if(shared->media_type == e1000_media_type_copper
- && shared->get_link_status) {
- /* First we want to see if the MII Status Register reports
- * link. If so, then we want to get the current speed/duplex
- * of the PHY.
- * Read the register twice since the link bit is sticky.
- */
- phy_data = e1000_read_phy_reg(shared, PHY_STATUS);
- phy_data = e1000_read_phy_reg(shared, PHY_STATUS);
-
- if(phy_data & MII_SR_LINK_STATUS) {
- shared->get_link_status = FALSE;
- } else {
- DEBUGOUT("**** CFL - No link detected. ****\r\n");
- return;
- }
-
- /* If we are forcing speed/duplex, then we simply return since
- * we have already determined whether we have link or not.
- */
- if(!shared->autoneg) {
- return;
- }
-
- switch (shared->phy_id) {
- case M88E1000_12_PHY_ID:
- case M88E1000_14_PHY_ID:
- case M88E1000_I_PHY_ID:
- /* We have a M88E1000 PHY and Auto-Neg is enabled. If we
- * have Si on board that is 82544 or newer, Auto
- * Speed Detection takes care of MAC speed/duplex
- * configuration. So we only need to configure Collision
- * Distance in the MAC. Otherwise, we need to force
- * speed/duplex on the MAC to the current PHY speed/duplex
- * settings.
- */
- if(shared->mac_type >= e1000_82544) {
- DEBUGOUT("CFL - Auto-Neg complete.");
- DEBUGOUT("Configuring Collision Distance.");
- e1000_config_collision_dist(shared);
- } else {
- /* Read the Phy Specific Status register to get the
- * resolved speed/duplex settings. Then call
- * e1000_config_mac_to_phy which will retrieve
- * PHY register information and configure the MAC to
- * equal the negotiated speed/duplex.
- */
- phy_data = e1000_read_phy_reg(shared,
- M88E1000_PHY_SPEC_STATUS);
-
- DEBUGOUT1("CFL - Auto-Neg complete. phy_data = %x\r\n",
- phy_data);
- e1000_config_mac_to_phy(shared, phy_data);
- }
-
- /* Configure Flow Control now that Auto-Neg has completed.
- * We need to first restore the users desired Flow
- * Control setting since we may have had to re-autoneg
- * with a different link partner.
- */
- e1000_config_fc_after_link_up(shared);
- break;
-
- default:
- DEBUGOUT("CFL - Invalid PHY detected.\r\n");
-
- } /* end switch statement */
-
- /* At this point we know that we are on copper, link is up,
- * and we are auto-neg'd. These are pre-conditions for checking
- * the link parter capabilities register. We use the link partner
- * capabilities to determine if TBI Compatibility needs to be turned on
- * or turned off. If the link partner advertises any speed in addition
- * to Gigabit, then we assume that they are GMII-based and TBI
- * compatibility is not needed.
- * If no other speeds are advertised, then we assume the link partner
- * is TBI-based and we turn on TBI Compatibility.
- */
- if(shared->tbi_compatibility_en) {
- lp_capability = e1000_read_phy_reg(shared, PHY_LP_ABILITY);
- if(lp_capability & (NWAY_LPAR_10T_HD_CAPS |
- NWAY_LPAR_10T_FD_CAPS |
- NWAY_LPAR_100TX_HD_CAPS |
- NWAY_LPAR_100TX_FD_CAPS |
- NWAY_LPAR_100T4_CAPS)) {
- /* If our link partner advertises below Gig, then they do not
- * need the special Tbi Compatibility mode.
- */
- if(shared->tbi_compatibility_on) {
- /* If we previously were in the mode, turn it off, now. */
- rctl_reg = E1000_READ_REG(shared, RCTL);
- rctl_reg &= ~E1000_RCTL_SBP;
- E1000_WRITE_REG(shared, RCTL, rctl_reg);
- shared->tbi_compatibility_on = FALSE;
- }
- } else {
- /* If the mode is was previously off, turn it on.
- * For compatibility with a suspected Tbi link partners,
- * we will store bad packets.
- * (Certain frames have an additional byte on the end and will
- * look like CRC errors to to the hardware).
- */
- if(!shared->tbi_compatibility_on) {
- shared->tbi_compatibility_on = TRUE;
- rctl_reg = E1000_READ_REG(shared, RCTL);
- rctl_reg |= E1000_RCTL_SBP;
- E1000_WRITE_REG(shared, RCTL, rctl_reg);
- }
- }
- }
- } /* end if e1000_media_type_copper statement */
- /* If we don't have link (auto-negotiation failed or link partner
- * cannot auto-negotiate) and the cable is plugged in since we don't
- * have Loss-Of-Signal (we HAVE a signal) and our link partner is
- * not trying to AutoNeg with us (we are receiving idles/data
- * then we need to force our link to connect to a non
- * auto-negotiating link partner. We also need to give
- * auto-negotiation time to complete in case the cable was just
- * plugged in. The autoneg_failed flag does this.
- */
- else if((shared->media_type == e1000_media_type_fiber) && /* Fiber PHY */
- (!(status_reg & E1000_STATUS_LU)) && /* no link and */
- (!(ctrl_reg & E1000_CTRL_SWDPIN1)) && /* we have signal */
- (!(rxcw_reg & E1000_RXCW_C))) { /* and rxing idle/data */
- if(shared->autoneg_failed == 0) { /* given AutoNeg time */
- shared->autoneg_failed = 1;
- return;
- }
-
- DEBUGOUT("NOT RXing /C/, disable AutoNeg and force link.\r\n");
-
- /* Disable auto-negotiation in the TXCW register */
- E1000_WRITE_REG(shared, TXCW, (shared->txcw_reg & ~E1000_TXCW_ANE));
-
- /* Force link-up and also force full-duplex. */
- ctrl_reg = E1000_READ_REG(shared, CTRL);
- ctrl_reg |= (E1000_CTRL_SLU | E1000_CTRL_FD);
- E1000_WRITE_REG(shared, CTRL, ctrl_reg);
-
- /* Configure Flow Control after forcing link up. */
- e1000_config_fc_after_link_up(shared);
-
- } else if((shared->media_type == e1000_media_type_fiber) && /* Fiber */
- (ctrl_reg & E1000_CTRL_SLU) && /* we have forced link */
- (rxcw_reg & E1000_RXCW_C)) { /* and Rxing /C/ ordered sets */
- /* If we are forcing link and we are receiving /C/ ordered sets,
- * then re-enable auto-negotiation in the RXCW register and
- * disable forced link in the Device Control register in an attempt
- * to AutoNeg with our link partner.
- */
- DEBUGOUT("RXing /C/, enable AutoNeg and stop forcing link.\r\n");
-
- /* Enable auto-negotiation in the TXCW register and stop
- * forcing link.
- */
- E1000_WRITE_REG(shared, TXCW, shared->txcw_reg);
-
- E1000_WRITE_REG(shared, CTRL, (ctrl_reg & ~E1000_CTRL_SLU));
- }
-
- return;
-}
-
-/******************************************************************************
- * Clears all hardware statistics counters.
- *
- * shared - Struct containing variables accessed by shared code
- *****************************************************************************/
-void
-e1000_clear_hw_cntrs(struct e1000_shared_adapter *shared)
-{
- volatile uint32_t temp_reg;
-
- DEBUGFUNC("e1000_clear_hw_cntrs");
-
- /* if we are stopped or resetting exit gracefully */
- if(shared->adapter_stopped) {
- DEBUGOUT("Exiting because the adapter is stopped!!!\n");
- return;
- }
-
- temp_reg = E1000_READ_REG(shared, CRCERRS);
- temp_reg = E1000_READ_REG(shared, SYMERRS);
- temp_reg = E1000_READ_REG(shared, MPC);
- temp_reg = E1000_READ_REG(shared, SCC);
- temp_reg = E1000_READ_REG(shared, ECOL);
- temp_reg = E1000_READ_REG(shared, MCC);
- temp_reg = E1000_READ_REG(shared, LATECOL);
- temp_reg = E1000_READ_REG(shared, COLC);
- temp_reg = E1000_READ_REG(shared, DC);
- temp_reg = E1000_READ_REG(shared, SEC);
- temp_reg = E1000_READ_REG(shared, RLEC);
- temp_reg = E1000_READ_REG(shared, XONRXC);
- temp_reg = E1000_READ_REG(shared, XONTXC);
- temp_reg = E1000_READ_REG(shared, XOFFRXC);
- temp_reg = E1000_READ_REG(shared, XOFFTXC);
- temp_reg = E1000_READ_REG(shared, FCRUC);
- temp_reg = E1000_READ_REG(shared, PRC64);
- temp_reg = E1000_READ_REG(shared, PRC127);
- temp_reg = E1000_READ_REG(shared, PRC255);
- temp_reg = E1000_READ_REG(shared, PRC511);
- temp_reg = E1000_READ_REG(shared, PRC1023);
- temp_reg = E1000_READ_REG(shared, PRC1522);
- temp_reg = E1000_READ_REG(shared, GPRC);
- temp_reg = E1000_READ_REG(shared, BPRC);
- temp_reg = E1000_READ_REG(shared, MPRC);
- temp_reg = E1000_READ_REG(shared, GPTC);
- temp_reg = E1000_READ_REG(shared, GORCL);
- temp_reg = E1000_READ_REG(shared, GORCH);
- temp_reg = E1000_READ_REG(shared, GOTCL);
- temp_reg = E1000_READ_REG(shared, GOTCH);
- temp_reg = E1000_READ_REG(shared, RNBC);
- temp_reg = E1000_READ_REG(shared, RUC);
- temp_reg = E1000_READ_REG(shared, RFC);
- temp_reg = E1000_READ_REG(shared, ROC);
- temp_reg = E1000_READ_REG(shared, RJC);
- temp_reg = E1000_READ_REG(shared, TORL);
- temp_reg = E1000_READ_REG(shared, TORH);
- temp_reg = E1000_READ_REG(shared, TOTL);
- temp_reg = E1000_READ_REG(shared, TOTH);
- temp_reg = E1000_READ_REG(shared, TPR);
- temp_reg = E1000_READ_REG(shared, TPT);
- temp_reg = E1000_READ_REG(shared, PTC64);
- temp_reg = E1000_READ_REG(shared, PTC127);
- temp_reg = E1000_READ_REG(shared, PTC255);
- temp_reg = E1000_READ_REG(shared, PTC511);
- temp_reg = E1000_READ_REG(shared, PTC1023);
- temp_reg = E1000_READ_REG(shared, PTC1522);
- temp_reg = E1000_READ_REG(shared, MPTC);
- temp_reg = E1000_READ_REG(shared, BPTC);
-
- if(shared->mac_type < e1000_82543)
- return;
-
- temp_reg = E1000_READ_REG(shared, ALGNERRC);
- temp_reg = E1000_READ_REG(shared, RXERRC);
- temp_reg = E1000_READ_REG(shared, TNCRS);
- temp_reg = E1000_READ_REG(shared, CEXTERR);
- temp_reg = E1000_READ_REG(shared, TSCTC);
- temp_reg = E1000_READ_REG(shared, TSCTFC);
- return;
-}
-
-/******************************************************************************
- * Detects the current speed and duplex settings of the hardware.
- *
- * shared - Struct containing variables accessed by shared code
- * speed - Speed of the connection
- * duplex - Duplex setting of the connection
- *****************************************************************************/
-void
-e1000_get_speed_and_duplex(struct e1000_shared_adapter *shared,
- uint16_t *speed,
- uint16_t *duplex)
-{
- uint32_t status_reg;
-#if DBG
- uint16_t phy_data;
-#endif
-
- DEBUGFUNC("e1000_get_speed_and_duplex");
-
- /* If the adapter is stopped we don't have a speed or duplex */
- if(shared->adapter_stopped) {
- *speed = 0;
- *duplex = 0;
- return;
- }
-
- if(shared->mac_type >= e1000_82543) {
- status_reg = E1000_READ_REG(shared, STATUS);
- if(status_reg & E1000_STATUS_SPEED_1000) {
- *speed = SPEED_1000;
- DEBUGOUT("1000 Mbs, ");
- } else if(status_reg & E1000_STATUS_SPEED_100) {
- *speed = SPEED_100;
- DEBUGOUT("100 Mbs, ");
- } else {
- *speed = SPEED_10;
- DEBUGOUT("10 Mbs, ");
- }
-
- if(status_reg & E1000_STATUS_FD) {
- *duplex = FULL_DUPLEX;
- DEBUGOUT("Full Duplex\r\n");
- } else {
- *duplex = HALF_DUPLEX;
- DEBUGOUT(" Half Duplex\r\n");
- }
- } else {
- DEBUGOUT("1000 Mbs, Full Duplex\r\n");
- *speed = SPEED_1000;
- *duplex = FULL_DUPLEX;
- }
-
-#if DBG
- if(shared->phy_id == M88E1000_12_PHY_ID ||
- shared->phy_id == M88E1000_14_PHY_ID ||
- shared->phy_id == M88E1000_I_PHY_ID) {
- /* read the phy specific status register */
- phy_data = e1000_read_phy_reg(shared, M88E1000_PHY_SPEC_STATUS);
- DEBUGOUT1("M88E1000 Phy Specific Status Reg contents = %x\n", phy_data);
- phy_data = e1000_read_phy_reg(shared, PHY_STATUS);
- DEBUGOUT1("Phy MII Status Reg contents = %x\n", phy_data);
- DEBUGOUT1("Device Status Reg contents = %x\n",
- E1000_READ_REG(shared, STATUS));
- }
-#endif
- return;
-}
-
-/******************************************************************************
- * Reads a 16 bit word from the EEPROM.
- *
- * shared - Struct containing variables accessed by shared code
- * offset - offset of 16 bit word in the EEPROM to read
- *****************************************************************************/
-uint16_t
-e1000_read_eeprom(struct e1000_shared_adapter *shared,
- uint16_t offset)
-{
- uint16_t data;
-
- /* Prepare the EEPROM for reading */
- e1000_setup_eeprom(shared);
-
- /* Send the READ command (opcode + addr) */
- e1000_shift_out_bits(shared, EEPROM_READ_OPCODE, 3);
- e1000_shift_out_bits(shared, offset, 6);
-
- /* Read the data */
- data = e1000_shift_in_bits(shared);
-
- /* End this read operation */
- e1000_standby_eeprom(shared);
-
- return (data);
-}
-
-/******************************************************************************
- * Verifies that the EEPROM has a valid checksum
- *
- * shared - Struct containing variables accessed by shared code
- *
- * Reads the first 64 16 bit words of the EEPROM and sums the values read.
- * If the the sum of the 64 16 bit words is 0xBABA, the EEPROM's checksum is
- * valid.
- *****************************************************************************/
-boolean_t
-e1000_validate_eeprom_checksum(struct e1000_shared_adapter *shared)
-{
- uint16_t checksum = 0;
- uint16_t i;
-
- for(i = 0; i < (EEPROM_CHECKSUM_REG + 1); i++)
- checksum += e1000_read_eeprom(shared, i);
-
- if(checksum == (uint16_t) EEPROM_SUM)
- return (TRUE);
- else
- return (FALSE);
-}
-/******************************************************************************
- * Reads the adapter's part number from the EEPROM
- *
- * shared - Struct containing variables accessed by shared code
- * part_num - Adapter's part number
- *****************************************************************************/
-boolean_t
-e1000_read_part_num(struct e1000_shared_adapter *shared,
- uint32_t *part_num)
-{
- uint16_t eeprom_word;
-
- DEBUGFUNC("e1000_read_part_num");
-
- /* Don't read the EEPROM if we are stopped */
- if(shared->adapter_stopped) {
- *part_num = 0;
- return (FALSE);
- }
-
- /* Get word 0 from EEPROM */
- eeprom_word = e1000_read_eeprom(shared, (uint16_t) (EEPROM_PBA_BYTE_1));
-
- DEBUGOUT("Read first part number word\n");
-
- /* Save word 0 in upper half is PartNumber */
- *part_num = (uint32_t) eeprom_word;
- *part_num = *part_num << 16;
-
- /* Get word 1 from EEPROM */
- eeprom_word =
- e1000_read_eeprom(shared, (uint16_t) (EEPROM_PBA_BYTE_1 + 1));
-
- DEBUGOUT("Read second part number word\n");
-
- /* Save word 1 in lower half of PartNumber */
- *part_num |= eeprom_word;
-
- /* read a valid part number */
- return (TRUE);
-}
-
-void
-e1000_read_mac_addr(struct e1000_shared_adapter * shared)
-{
- uint16_t temp, x;
-
- for(x = 0; x < NODE_ADDRESS_SIZE; x += 2) {
- temp = e1000_read_eeprom(shared, (uint16_t)
- (EEPROM_NODE_ADDRESS_BYTE_0 + (x/2)));
- shared->perm_mac_addr[x] = (uint8_t) (temp & 0x00FF);
- shared->perm_mac_addr[x+1] = (uint8_t) (temp >> 8);
- }
-
- for(x = 0; x < NODE_ADDRESS_SIZE; x++)
- shared->mac_addr[x] = shared->perm_mac_addr[x];
-}
-
-/******************************************************************************
- * Adjusts the statistic counters when a frame is accepted by TBI_ACCEPT
- *
- * shared - Struct containing variables accessed by shared code
- * frame_len - The length of the frame in question
- * mac_addr - The Ethernet destination address of the frame in question
- *****************************************************************************/
-uint32_t
-e1000_tbi_adjust_stats(struct e1000_shared_adapter *shared,
- struct e1000_shared_stats *stats,
- uint32_t frame_len,
- uint8_t *mac_addr)
-{
- uint64_t carry_bit;
-
- /* First adjust the frame length. */
- frame_len--;
- /* We need to adjust the statistics counters, since the hardware
- * counters overcount this packet as a CRC error and undercount
- * the packet as a good packet
- */
- /* This packet should not be counted as a CRC error. */
- stats->crcerrs--;
- /* This packet does count as a Good Packet Received. */
- stats->gprc++;
-
- /* Adjust the Good Octets received counters */
- carry_bit = 0x80000000 & stats->gorcl;
- stats->gorcl += frame_len;
- /* If the high bit of Gorcl (the low 32 bits of the Good Octets
- * Received Count) was one before the addition,
- * AND it is zero after, then we lost the carry out,
- * need to add one to Gorch (Good Octets Received Count High).
- * This could be simplified if all environments supported
- * 64-bit integers.
- */
- if(carry_bit && ((stats->gorcl & 0x80000000) == 0))
- stats->gorch++;
- /* Is this a broadcast or multicast? Check broadcast first,
- * since the test for a multicast frame will test positive on
- * a broadcast frame.
- */
- if((mac_addr[0] == (uint8_t) 0xff) && (mac_addr[1] == (uint8_t) 0xff))
- /* Broadcast packet */
- stats->bprc++;
- else if(*mac_addr & 0x01)
- /* Multicast packet */
- stats->mprc++;
-
- if(frame_len == shared->max_frame_size) {
- /* In this case, the hardware has overcounted the number of
- * oversize frames.
- */
- if(stats->roc > 0)
- stats->roc--;
- }
-
- /* Adjust the bin counters when the extra byte put the frame in the
- * wrong bin. Remember that the frame_len was adjusted above.
- */
- if(frame_len == 64) {
- stats->prc64++;
- stats->prc127--;
- } else if(frame_len == 127) {
- stats->prc127++;
- stats->prc255--;
- } else if(frame_len == 255) {
- stats->prc255++;
- stats->prc511--;
- } else if(frame_len == 511) {
- stats->prc511++;
- stats->prc1023--;
- } else if(frame_len == 1023) {
- stats->prc1023++;
- stats->prc1522--;
- } else if(frame_len == 1522) {
- stats->prc1522++;
- }
- return frame_len;
-}
-
-/******************************************************************************
- * Gets the current PCI bus type, speed, and width of the hardware
- *
- * shared - Struct containing variables accessed by shared code
- *****************************************************************************/
-void
-e1000_get_bus_info(struct e1000_shared_adapter *shared)
-{
- uint32_t status_reg;
-
- if(shared->mac_type < e1000_82543) {
- shared->bus_type = e1000_bus_type_unknown;
- shared->bus_speed = e1000_bus_speed_unknown;
- shared->bus_width = e1000_bus_width_unknown;
- return;
- }
-
- status_reg = E1000_READ_REG(shared, STATUS);
-
- shared->bus_type = (status_reg & E1000_STATUS_PCIX_MODE) ?
- e1000_bus_type_pcix : e1000_bus_type_pci;
-
- if(shared->bus_type == e1000_bus_type_pci) {
- shared->bus_speed = (status_reg & E1000_STATUS_PCI66) ?
- e1000_bus_speed_66 : e1000_bus_speed_33;
- } else {
- switch (status_reg & E1000_STATUS_PCIX_SPEED) {
- case E1000_STATUS_PCIX_SPEED_66:
- shared->bus_speed = e1000_bus_speed_66;
- break;
- case E1000_STATUS_PCIX_SPEED_100:
- shared->bus_speed = e1000_bus_speed_100;
- break;
- case E1000_STATUS_PCIX_SPEED_133:
- shared->bus_speed = e1000_bus_speed_133;
- break;
- default:
- shared->bus_speed = e1000_bus_speed_reserved;
- break;
- }
- }
-
- shared->bus_width = (status_reg & E1000_STATUS_BUS64) ?
- e1000_bus_width_64 : e1000_bus_width_32;
-
- return;
-}
diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c
index 1192f7cf424ab..cede9df83e7d6 100644
--- a/drivers/net/e1000/e1000_main.c
+++ b/drivers/net/e1000/e1000_main.c
@@ -2,9 +2,8 @@
This software program is available to you under a choice of one of two
licenses. You may choose to be licensed under either the GNU General Public
- License (GPL) Version 2, June 1991, available at
- http://www.fsf.org/copyleft/gpl.html, or the Intel BSD + Patent License, the
- text of which follows:
+ License 2.0, June 1991, available at http://www.fsf.org/copyleft/gpl.html,
+ or the Intel BSD + Patent License, the text of which follows:
Recipient has requested a license and Intel Corporation ("Intel") is willing
to grant a license for the software entitled Linux Base Driver for the
@@ -18,7 +17,7 @@
"Recipient" means the party to whom Intel delivers this Software.
"Licensee" means Recipient and those third parties that receive a license to
- any operating system available under the GNU Public License version 2.0 or
+ any operating system available under the GNU General Public License 2.0 or
later.
Copyright (c) 1999 - 2002 Intel Corporation.
@@ -51,10 +50,10 @@
version of an operating system that has been distributed under the GNU
General Public License 2.0 or later. This patent license shall apply to the
combination of the Software and any operating system licensed under the GNU
- Public License version 2.0 or later if, at the time Intel provides the
+ General Public License 2.0 or later if, at the time Intel provides the
Software to Recipient, such addition of the Software to the then publicly
- available versions of such operating systems available under the GNU Public
- License version 2.0 or later (whether in gold, beta or alpha form) causes
+ available versions of such operating systems available under the GNU General
+ Public License 2.0 or later (whether in gold, beta or alpha form) causes
such combination to be covered by the Licensed Patents. The patent license
shall not apply to any other combinations which include the Software. NO
hardware per se is licensed hereunder.
@@ -76,11 +75,8 @@
#include "e1000.h"
char e1000_driver_name[] = "e1000";
-
char e1000_driver_string[] = "Intel(R) PRO/1000 Network Driver";
-
-char e1000_driver_version[] = "4.2.4-k2";
-
+char e1000_driver_version[] = "4.2.8";
char e1000_copyright[] = "Copyright (c) 1999-2002 Intel Corporation.";
/* e1000_pci_tbl - PCI Device ID Table
@@ -100,6 +96,7 @@ static struct pci_device_id e1000_pci_tbl[] __devinitdata = {
{0x8086, 0x1008, 0x8086, 0x1107, 0, 0, 0},
{0x8086, 0x1009, 0x8086, 0x1109, 0, 0, 0},
{0x8086, 0x100C, 0x8086, 0x1112, 0, 0, 0},
+ {0x8086, 0x100E, 0x8086, 0x001E, 0, 0, 0},
/* Compaq Gigabit Ethernet Server Adapter */
{0x8086, 0x1000, 0x0E11, PCI_ANY_ID, 0, 0, 1},
{0x8086, 0x1001, 0x0E11, PCI_ANY_ID, 0, 0, 1},
@@ -116,6 +113,7 @@ static struct pci_device_id e1000_pci_tbl[] __devinitdata = {
{0x8086, 0x1009, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
{0x8086, 0x100C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
{0x8086, 0x100D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ {0x8086, 0x100E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
/* required last entry */
{0,}
};
@@ -132,6 +130,8 @@ static char *e1000_strings[] = {
int e1000_up(struct e1000_adapter *adapter);
void e1000_down(struct e1000_adapter *adapter);
+void e1000_reset(struct e1000_adapter *adapter);
+
static int e1000_init_module(void);
static void e1000_exit_module(void);
static int e1000_probe(struct pci_dev *pdev, const struct pci_device_id *ent);
@@ -164,13 +164,17 @@ static void e1000_clean_tx_irq(struct e1000_adapter *adapter);
static void e1000_clean_rx_irq(struct e1000_adapter *adapter);
static void e1000_alloc_rx_buffers(struct e1000_adapter *adapter);
static int e1000_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd);
-static void e1000_reset(struct e1000_adapter *adapter);
static void e1000_enter_82542_rst(struct e1000_adapter *adapter);
static void e1000_leave_82542_rst(struct e1000_adapter *adapter);
static inline void e1000_rx_checksum(struct e1000_adapter *adapter,
struct e1000_rx_desc *rx_desc,
struct sk_buff *skb);
void e1000_enable_WOL(struct e1000_adapter *adapter);
+#ifdef NETIF_F_HW_VLAN_TX
+static void e1000_vlan_rx_register(struct net_device *netdev, struct vlan_group *grp);
+static void e1000_vlan_rx_add_vid(struct net_device *netdev, uint16_t vid);
+static void e1000_vlan_rx_kill_vid(struct net_device *netdev, uint16_t vid);
+#endif
/* Exported from other modules */
@@ -192,6 +196,7 @@ static struct pci_driver e1000_driver = {
MODULE_AUTHOR("Intel Corporation, <linux.nics@intel.com>");
MODULE_DESCRIPTION("Intel(R) PRO/1000 Network Driver");
MODULE_LICENSE("Dual BSD/GPL");
+EXPORT_NO_SYMBOLS;
/**
* e1000_init_module - Driver Registration Routine
@@ -224,8 +229,6 @@ static void __exit
e1000_exit_module(void)
{
pci_unregister_driver(&e1000_driver);
-
- return;
}
module_exit(e1000_exit_module);
@@ -249,8 +252,6 @@ e1000_up(struct e1000_adapter *adapter)
e1000_configure_rx(adapter);
e1000_alloc_rx_buffers(adapter);
- e1000_clear_hw_cntrs(&adapter->shared);
-
mod_timer(&adapter->watchdog_timer, jiffies);
e1000_irq_enable(adapter);
@@ -260,74 +261,41 @@ e1000_up(struct e1000_adapter *adapter)
void
e1000_down(struct e1000_adapter *adapter)
{
- struct e1000_shared_adapter *shared = &adapter->shared;
struct net_device *netdev = adapter->netdev;
e1000_irq_disable(adapter);
free_irq(netdev->irq, netdev);
del_timer_sync(&adapter->watchdog_timer);
del_timer_sync(&adapter->phy_info_timer);
+ adapter->link_speed = 0;
+ adapter->link_duplex = 0;
netif_carrier_off(netdev);
netif_stop_queue(netdev);
- /* disable the transmit and receive units */
-
- E1000_WRITE_REG(shared, RCTL, 0);
- E1000_WRITE_REG(shared, TCTL, E1000_TCTL_PSP);
-
- /* delay to allow PCI transactions to complete */
-
- msec_delay(10);
-
+ e1000_reset(adapter);
e1000_clean_tx_ring(adapter);
e1000_clean_rx_ring(adapter);
-
- e1000_reset(adapter);
}
-static void
+void
e1000_reset(struct e1000_adapter *adapter)
{
- struct e1000_shared_adapter *shared = &adapter->shared;
- uint32_t ctrl_ext;
-
/* Repartition Pba for greater than 9k mtu
* To take effect CTRL.RST is required.
*/
if(adapter->rx_buffer_len > E1000_RXBUFFER_8192)
- E1000_WRITE_REG(shared, PBA, E1000_JUMBO_PBA);
+ E1000_WRITE_REG(&adapter->hw, PBA, E1000_JUMBO_PBA);
else
- E1000_WRITE_REG(shared, PBA, E1000_DEFAULT_PBA);
-
- /* 82542 2.0 needs MWI disabled while issuing a reset */
-
- if(shared->mac_type == e1000_82542_rev2_0)
- e1000_enter_82542_rst(adapter);
-
- /* global reset */
-
- E1000_WRITE_REG(shared, CTRL, E1000_CTRL_RST);
- msec_delay(10);
-
- /* EEPROM reload */
-
- ctrl_ext = E1000_READ_REG(shared, CTRL_EXT);
- ctrl_ext |= E1000_CTRL_EXT_EE_RST;
- E1000_WRITE_REG(shared, CTRL_EXT, ctrl_ext);
- msec_delay(5);
-
- if(shared->mac_type == e1000_82542_rev2_0)
- e1000_leave_82542_rst(adapter);
+ E1000_WRITE_REG(&adapter->hw, PBA, E1000_DEFAULT_PBA);
- shared->tbi_compatibility_on = FALSE;
- shared->fc = shared->original_fc;
-
- e1000_init_hw(shared);
+ adapter->hw.fc = adapter->hw.original_fc;
+ e1000_reset_hw(&adapter->hw);
+ e1000_init_hw(&adapter->hw);
+ e1000_reset_adaptive(&adapter->hw);
+ e1000_phy_get_info(&adapter->hw, &adapter->phy_info);
e1000_enable_WOL(adapter);
-
- return;
}
/**
@@ -382,13 +350,13 @@ e1000_probe(struct pci_dev *pdev,
adapter = netdev->priv;
adapter->netdev = netdev;
adapter->pdev = pdev;
- adapter->shared.back = adapter;
+ adapter->hw.back = adapter;
mmio_start = pci_resource_start(pdev, BAR_0);
mmio_len = pci_resource_len(pdev, BAR_0);
- adapter->shared.hw_addr = ioremap(mmio_start, mmio_len);
- if(!adapter->shared.hw_addr)
+ adapter->hw.hw_addr = ioremap(mmio_start, mmio_len);
+ if(!adapter->hw.hw_addr)
goto err_ioremap;
netdev->open = &e1000_open;
@@ -401,6 +369,11 @@ e1000_probe(struct pci_dev *pdev,
netdev->do_ioctl = &e1000_ioctl;
netdev->tx_timeout = &e1000_tx_timeout;
netdev->watchdog_timeo = HZ;
+#ifdef NETIF_F_HW_VLAN_TX
+ netdev->vlan_rx_register = e1000_vlan_rx_register;
+ netdev->vlan_rx_add_vid = e1000_vlan_rx_add_vid;
+ netdev->vlan_rx_kill_vid = e1000_vlan_rx_kill_vid;
+#endif
netdev->irq = pdev->irq;
netdev->base_addr = mmio_start;
@@ -412,8 +385,16 @@ e1000_probe(struct pci_dev *pdev,
e1000_sw_init(adapter);
- if(adapter->shared.mac_type >= e1000_82543) {
+ if(adapter->hw.mac_type >= e1000_82543) {
+#ifdef NETIF_F_HW_VLAN_TX
+ netdev->features = NETIF_F_SG |
+ NETIF_F_HW_CSUM |
+ NETIF_F_HW_VLAN_TX |
+ NETIF_F_HW_VLAN_RX |
+ NETIF_F_HW_VLAN_FILTER;
+#else
netdev->features = NETIF_F_SG | NETIF_F_HW_CSUM;
+#endif
} else {
netdev->features = NETIF_F_SG;
}
@@ -423,19 +404,28 @@ e1000_probe(struct pci_dev *pdev,
/* make sure the EEPROM is good */
- if(!e1000_validate_eeprom_checksum(&adapter->shared))
+ if(e1000_validate_eeprom_checksum(&adapter->hw) < 0)
goto err_eeprom;
/* copy the MAC address out of the EEPROM */
- e1000_read_mac_addr(&adapter->shared);
- memcpy(netdev->dev_addr, adapter->shared.mac_addr, netdev->addr_len);
+ e1000_read_mac_addr(&adapter->hw);
+ memcpy(netdev->dev_addr, adapter->hw.mac_addr, netdev->addr_len);
if(!is_valid_ether_addr(netdev->dev_addr))
goto err_eeprom;
- e1000_read_part_num(&adapter->shared, &(adapter->part_num));
- e1000_get_bus_info(&adapter->shared);
+ e1000_read_part_num(&adapter->hw, &(adapter->part_num));
+
+ e1000_get_bus_info(&adapter->hw);
+
+ if((adapter->hw.mac_type == e1000_82544) &&
+ (adapter->hw.bus_type == e1000_bus_type_pcix))
+
+ adapter->max_data_per_txd = 4096;
+ else
+ adapter->max_data_per_txd = MAX_JUMBO_FRAME_SIZE;
+
init_timer(&adapter->watchdog_timer);
adapter->watchdog_timer.function = &e1000_watchdog;
@@ -464,7 +454,7 @@ e1000_probe(struct pci_dev *pdev,
return 0;
err_eeprom:
- iounmap(adapter->shared.hw_addr);
+ iounmap(adapter->hw.hw_addr);
err_ioremap:
pci_release_regions(pdev);
kfree(netdev);
@@ -480,10 +470,6 @@ err_alloc_etherdev:
* that it should release a PCI device. The could be caused by a
* Hot-Plug event, or because the driver is going to be removed from
* memory.
- *
- * This routine is also called to clean up from a failure in
- * e1000_probe. The Adapter struct and netdev will always exist,
- * all other pointers must be checked for NULL before freeing.
**/
static void __devexit
@@ -494,15 +480,14 @@ e1000_remove(struct pci_dev *pdev)
unregister_netdev(netdev);
- e1000_phy_hw_reset(&adapter->shared);
+ e1000_phy_hw_reset(&adapter->hw);
e1000_proc_dev_free(adapter);
- iounmap(adapter->shared.hw_addr);
+ iounmap(adapter->hw.hw_addr);
pci_release_regions(pdev);
kfree(netdev);
- return;
}
/**
@@ -517,17 +502,17 @@ e1000_remove(struct pci_dev *pdev)
static void __devinit
e1000_sw_init(struct e1000_adapter *adapter)
{
- struct e1000_shared_adapter *shared = &adapter->shared;
+ struct e1000_hw *hw = &adapter->hw;
struct net_device *netdev = adapter->netdev;
struct pci_dev *pdev = adapter->pdev;
/* PCI config space info */
- uint16_t *vendor = &shared->vendor_id;
- uint16_t *device = &shared->device_id;
- uint16_t *subvendor = &shared->subsystem_vendor_id;
- uint16_t *subsystem = &shared->subsystem_id;
- uint8_t *revision = &shared->revision_id;
+ uint16_t *vendor = &hw->vendor_id;
+ uint16_t *device = &hw->device_id;
+ uint16_t *subvendor = &hw->subsystem_vendor_id;
+ uint16_t *subsystem = &hw->subsystem_id;
+ uint8_t *revision = &hw->revision_id;
pci_read_config_word(pdev, PCI_VENDOR_ID, vendor);
pci_read_config_word(pdev, PCI_DEVICE_ID, device);
@@ -535,11 +520,12 @@ e1000_sw_init(struct e1000_adapter *adapter)
pci_read_config_word(pdev, PCI_SUBSYSTEM_VENDOR_ID, subvendor);
pci_read_config_word(pdev, PCI_SUBSYSTEM_ID, subsystem);
- pci_read_config_word(pdev, PCI_COMMAND, &shared->pci_cmd_word);
+ pci_read_config_word(pdev, PCI_COMMAND, &hw->pci_cmd_word);
adapter->rx_buffer_len = E1000_RXBUFFER_2048;
- shared->max_frame_size = netdev->mtu + ENET_HEADER_SIZE + CRC_LENGTH;
- shared->min_frame_size = MINIMUM_ETHERNET_PACKET_SIZE + CRC_LENGTH;
+ hw->max_frame_size = netdev->mtu +
+ ENET_HEADER_SIZE + ETHERNET_FCS_SIZE;
+ hw->min_frame_size = MINIMUM_ETHERNET_FRAME_SIZE;
/* identify the MAC */
@@ -547,25 +533,28 @@ e1000_sw_init(struct e1000_adapter *adapter)
case E1000_DEV_ID_82542:
switch (*revision) {
case E1000_82542_2_0_REV_ID:
- shared->mac_type = e1000_82542_rev2_0;
+ hw->mac_type = e1000_82542_rev2_0;
break;
case E1000_82542_2_1_REV_ID:
- shared->mac_type = e1000_82542_rev2_1;
+ hw->mac_type = e1000_82542_rev2_1;
break;
default:
- shared->mac_type = e1000_82542_rev2_0;
+ hw->mac_type = e1000_82542_rev2_0;
E1000_ERR("Could not identify 82542 revision\n");
}
break;
case E1000_DEV_ID_82543GC_FIBER:
case E1000_DEV_ID_82543GC_COPPER:
- shared->mac_type = e1000_82543;
+ hw->mac_type = e1000_82543;
break;
case E1000_DEV_ID_82544EI_COPPER:
case E1000_DEV_ID_82544EI_FIBER:
case E1000_DEV_ID_82544GC_COPPER:
case E1000_DEV_ID_82544GC_LOM:
- shared->mac_type = e1000_82544;
+ hw->mac_type = e1000_82544;
+ break;
+ case E1000_DEV_ID_82540EM:
+ hw->mac_type = e1000_82540;
break;
default:
/* should never have loaded on this device */
@@ -574,33 +563,35 @@ e1000_sw_init(struct e1000_adapter *adapter)
/* flow control settings */
- shared->fc_high_water = FC_DEFAULT_HI_THRESH;
- shared->fc_low_water = FC_DEFAULT_LO_THRESH;
- shared->fc_pause_time = FC_DEFAULT_TX_TIMER;
- shared->fc_send_xon = 1;
+ hw->fc_high_water = FC_DEFAULT_HI_THRESH;
+ hw->fc_low_water = FC_DEFAULT_LO_THRESH;
+ hw->fc_pause_time = FC_DEFAULT_TX_TIMER;
+ hw->fc_send_xon = 1;
/* Media type - copper or fiber */
- if(shared->mac_type >= e1000_82543) {
- uint32_t status = E1000_READ_REG(shared, STATUS);
+ if(hw->mac_type >= e1000_82543) {
+ uint32_t status = E1000_READ_REG(hw, STATUS);
if(status & E1000_STATUS_TBIMODE)
- shared->media_type = e1000_media_type_fiber;
+ hw->media_type = e1000_media_type_fiber;
else
- shared->media_type = e1000_media_type_copper;
+ hw->media_type = e1000_media_type_copper;
} else {
- shared->media_type = e1000_media_type_fiber;
+ hw->media_type = e1000_media_type_fiber;
}
- if(shared->mac_type < e1000_82543)
- shared->report_tx_early = 0;
+ if(hw->mac_type < e1000_82543)
+ hw->report_tx_early = 0;
else
- shared->report_tx_early = 1;
+ hw->report_tx_early = 1;
- shared->wait_autoneg_complete = FALSE;
- shared->tbi_compatibility_en = TRUE;
+ hw->wait_autoneg_complete = FALSE;
+ hw->tbi_compatibility_en = TRUE;
+ hw->adaptive_ifs = TRUE;
atomic_set(&adapter->irq_sem, 1);
+ spin_lock_init(&adapter->tx_lock);
spin_lock_init(&adapter->stats_lock);
}
@@ -677,9 +668,6 @@ e1000_close(struct net_device *netdev)
* @adapter: board private structure
*
* Return 0 on success, negative on failure
- *
- * e1000_setup_tx_resources allocates all software transmit resources
- * and enabled the Tx unit of the MAC.
**/
static int
@@ -708,7 +696,6 @@ e1000_setup_tx_resources(struct e1000_adapter *adapter)
}
memset(txdr->desc, 0, txdr->size);
- atomic_set(&txdr->unused, txdr->count);
txdr->next_to_use = 0;
txdr->next_to_clean = 0;
@@ -729,19 +716,19 @@ e1000_configure_tx(struct e1000_adapter *adapter)
uint32_t tdlen = adapter->tx_ring.count * sizeof(struct e1000_tx_desc);
uint32_t tctl, tipg;
- E1000_WRITE_REG(&adapter->shared, TDBAL, (tdba & 0x00000000FFFFFFFF));
- E1000_WRITE_REG(&adapter->shared, TDBAH, (tdba >> 32));
+ E1000_WRITE_REG(&adapter->hw, TDBAL, (tdba & 0x00000000FFFFFFFF));
+ E1000_WRITE_REG(&adapter->hw, TDBAH, (tdba >> 32));
- E1000_WRITE_REG(&adapter->shared, TDLEN, tdlen);
+ E1000_WRITE_REG(&adapter->hw, TDLEN, tdlen);
/* Setup the HW Tx Head and Tail descriptor pointers */
- E1000_WRITE_REG(&adapter->shared, TDH, 0);
- E1000_WRITE_REG(&adapter->shared, TDT, 0);
+ E1000_WRITE_REG(&adapter->hw, TDH, 0);
+ E1000_WRITE_REG(&adapter->hw, TDT, 0);
/* Set the default values for the Tx Inter Packet Gap timer */
- switch (adapter->shared.mac_type) {
+ switch (adapter->hw.mac_type) {
case e1000_82542_rev2_0:
case e1000_82542_rev2_1:
tipg = DEFAULT_82542_TIPG_IPGT;
@@ -749,53 +736,45 @@ e1000_configure_tx(struct e1000_adapter *adapter)
tipg |= DEFAULT_82542_TIPG_IPGR2 << E1000_TIPG_IPGR2_SHIFT;
break;
default:
- if(adapter->shared.media_type == e1000_media_type_fiber)
+ if(adapter->hw.media_type == e1000_media_type_fiber)
tipg = DEFAULT_82543_TIPG_IPGT_FIBER;
else
tipg = DEFAULT_82543_TIPG_IPGT_COPPER;
tipg |= DEFAULT_82543_TIPG_IPGR1 << E1000_TIPG_IPGR1_SHIFT;
tipg |= DEFAULT_82543_TIPG_IPGR2 << E1000_TIPG_IPGR2_SHIFT;
}
- E1000_WRITE_REG(&adapter->shared, TIPG, tipg);
+ E1000_WRITE_REG(&adapter->hw, TIPG, tipg);
/* Set the Tx Interrupt Delay register */
- E1000_WRITE_REG(&adapter->shared, TIDV, adapter->tx_int_delay);
+ E1000_WRITE_REG(&adapter->hw, TIDV, 64);
/* Program the Transmit Control Register */
- tctl = E1000_TCTL_PSP | E1000_TCTL_EN |
+ tctl = E1000_READ_REG(&adapter->hw, TCTL);
+
+ tctl &= ~E1000_TCTL_CT;
+ tctl |= E1000_TCTL_EN | E1000_TCTL_PSP |
(E1000_COLLISION_THRESHOLD << E1000_CT_SHIFT);
- if(adapter->link_duplex == FULL_DUPLEX) {
- tctl |= E1000_FDX_COLLISION_DISTANCE << E1000_COLD_SHIFT;
- } else {
- tctl |= E1000_HDX_COLLISION_DISTANCE << E1000_COLD_SHIFT;
- }
+ E1000_WRITE_REG(&adapter->hw, TCTL, tctl);
- E1000_WRITE_REG(&adapter->shared, TCTL, tctl);
+ e1000_config_collision_dist(&adapter->hw);
/* Setup Transmit Descriptor Settings for this adapter */
- adapter->txd_cmd = E1000_TXD_CMD_IFCS;
+ adapter->txd_cmd = E1000_TXD_CMD_IFCS | E1000_TXD_CMD_IDE;
- if(adapter->tx_int_delay > 0)
- adapter->txd_cmd |= E1000_TXD_CMD_IDE;
- if(adapter->shared.report_tx_early == 1)
+ if(adapter->hw.report_tx_early == 1)
adapter->txd_cmd |= E1000_TXD_CMD_RS;
else
adapter->txd_cmd |= E1000_TXD_CMD_RPS;
-
- return;
}
/**
- * e1000_setup_rx_resources - allocate Rx resources (Descriptors, receive SKBs)
+ * e1000_setup_rx_resources - allocate Rx resources (Descriptors)
* @adapter: board private structure
*
* Returns 0 on success, negative on failure
- *
- * e1000_setup_rx_resources allocates all software receive resources
- * and network buffers, and enables the Rx unit of the MAC.
**/
static int
@@ -826,7 +805,6 @@ e1000_setup_rx_resources(struct e1000_adapter *adapter)
memset(rxdr->desc, 0, rxdr->size);
rxdr->next_to_clean = 0;
- rxdr->unused_count = rxdr->count;
rxdr->next_to_use = 0;
return 0;
@@ -842,18 +820,25 @@ e1000_setup_rctl(struct e1000_adapter *adapter)
{
uint32_t rctl;
- /* Setup the Receive Control Register */
- rctl = E1000_RCTL_EN | E1000_RCTL_BAM |
- E1000_RCTL_LBM_NO | E1000_RCTL_RDMTS_HALF |
- (adapter->shared.mc_filter_type << E1000_RCTL_MO_SHIFT);
+ rctl = E1000_READ_REG(&adapter->hw, RCTL);
+
+ rctl &= ~(3 << E1000_RCTL_MO_SHIFT);
- if(adapter->shared.tbi_compatibility_on == 1)
+ rctl |= E1000_RCTL_EN | E1000_RCTL_BAM |
+ E1000_RCTL_LBM_NO | E1000_RCTL_RDMTS_HALF |
+ (adapter->hw.mc_filter_type << E1000_RCTL_MO_SHIFT);
+
+ if(adapter->hw.tbi_compatibility_on == 1)
rctl |= E1000_RCTL_SBP;
+ else
+ rctl &= ~E1000_RCTL_SBP;
+ rctl &= ~(E1000_RCTL_SZ_4096);
switch (adapter->rx_buffer_len) {
case E1000_RXBUFFER_2048:
default:
rctl |= E1000_RCTL_SZ_2048;
+ rctl &= ~(E1000_RCTL_BSEX | E1000_RCTL_LPE);
break;
case E1000_RXBUFFER_4096:
rctl |= E1000_RCTL_SZ_4096 | E1000_RCTL_BSEX | E1000_RCTL_LPE;
@@ -866,7 +851,7 @@ e1000_setup_rctl(struct e1000_adapter *adapter)
break;
}
- E1000_WRITE_REG(&adapter->shared, RCTL, rctl);
+ E1000_WRITE_REG(&adapter->hw, RCTL, rctl);
}
/**
@@ -886,38 +871,47 @@ e1000_configure_rx(struct e1000_adapter *adapter)
/* make sure receives are disabled while setting up the descriptors */
- rctl = E1000_READ_REG(&adapter->shared, RCTL);
- E1000_WRITE_REG(&adapter->shared, RCTL, rctl & ~E1000_RCTL_EN);
+ rctl = E1000_READ_REG(&adapter->hw, RCTL);
+ E1000_WRITE_REG(&adapter->hw, RCTL, rctl & ~E1000_RCTL_EN);
/* set the Receive Delay Timer Register */
- E1000_WRITE_REG(&adapter->shared, RDTR,
- adapter->rx_int_delay | E1000_RDT_FPDB);
+ if(adapter->hw.mac_type == e1000_82540) {
+ E1000_WRITE_REG(&adapter->hw, RADV, adapter->rx_int_delay);
+ E1000_WRITE_REG(&adapter->hw, RDTR, 64);
+
+ /* Set the interrupt throttling rate. Value is calculated
+ * as DEFAULT_ITR = 1/(MAX_INTS_PER_SEC * 256ns) */
+#define MAX_INTS_PER_SEC 8000
+#define DEFAULT_ITR 1000000000/(MAX_INTS_PER_SEC * 256)
+ E1000_WRITE_REG(&adapter->hw, ITR, DEFAULT_ITR);
+
+ } else {
+ E1000_WRITE_REG(&adapter->hw, RDTR, adapter->rx_int_delay);
+ }
/* Setup the Base and Length of the Rx Descriptor Ring */
- E1000_WRITE_REG(&adapter->shared, RDBAL, (rdba & 0x00000000FFFFFFFF));
- E1000_WRITE_REG(&adapter->shared, RDBAH, (rdba >> 32));
+ E1000_WRITE_REG(&adapter->hw, RDBAL, (rdba & 0x00000000FFFFFFFF));
+ E1000_WRITE_REG(&adapter->hw, RDBAH, (rdba >> 32));
- E1000_WRITE_REG(&adapter->shared, RDLEN, rdlen);
+ E1000_WRITE_REG(&adapter->hw, RDLEN, rdlen);
/* Setup the HW Rx Head and Tail Descriptor Pointers */
- E1000_WRITE_REG(&adapter->shared, RDH, 0);
- E1000_WRITE_REG(&adapter->shared, RDT, 0);
+ E1000_WRITE_REG(&adapter->hw, RDH, 0);
+ E1000_WRITE_REG(&adapter->hw, RDT, 0);
/* Enable 82543 Receive Checksum Offload for TCP and UDP */
- if((adapter->shared.mac_type >= e1000_82543) &&
+ if((adapter->hw.mac_type >= e1000_82543) &&
(adapter->rx_csum == TRUE)) {
- rxcsum = E1000_READ_REG(&adapter->shared, RXCSUM);
+ rxcsum = E1000_READ_REG(&adapter->hw, RXCSUM);
rxcsum |= E1000_RXCSUM_TUOFL;
- E1000_WRITE_REG(&adapter->shared, RXCSUM, rxcsum);
+ E1000_WRITE_REG(&adapter->hw, RXCSUM, rxcsum);
}
/* Enable Receives */
- E1000_WRITE_REG(&adapter->shared, RCTL, rctl);
-
- return;
+ E1000_WRITE_REG(&adapter->hw, RCTL, rctl);
}
/**
@@ -941,8 +935,6 @@ e1000_free_tx_resources(struct e1000_adapter *adapter)
adapter->tx_ring.desc, adapter->tx_ring.dma);
adapter->tx_ring.desc = NULL;
-
- return;
}
/**
@@ -980,14 +972,11 @@ e1000_clean_tx_ring(struct e1000_adapter *adapter)
memset(adapter->tx_ring.desc, 0, adapter->tx_ring.size);
- atomic_set(&adapter->tx_ring.unused, adapter->tx_ring.count);
adapter->tx_ring.next_to_use = 0;
adapter->tx_ring.next_to_clean = 0;
- E1000_WRITE_REG(&adapter->shared, TDH, 0);
- E1000_WRITE_REG(&adapter->shared, TDT, 0);
-
- return;
+ E1000_WRITE_REG(&adapter->hw, TDH, 0);
+ E1000_WRITE_REG(&adapter->hw, TDT, 0);
}
/**
@@ -1011,8 +1000,6 @@ e1000_free_rx_resources(struct e1000_adapter *adapter)
adapter->rx_ring.desc, adapter->rx_ring.dma);
adapter->rx_ring.desc = NULL;
-
- return;
}
/**
@@ -1050,14 +1037,11 @@ e1000_clean_rx_ring(struct e1000_adapter *adapter)
memset(adapter->rx_ring.desc, 0, adapter->rx_ring.size);
- adapter->rx_ring.unused_count = adapter->rx_ring.count;
adapter->rx_ring.next_to_clean = 0;
adapter->rx_ring.next_to_use = 0;
- E1000_WRITE_REG(&adapter->shared, RDH, 0);
- E1000_WRITE_REG(&adapter->shared, RDT, 0);
-
- return;
+ E1000_WRITE_REG(&adapter->hw, RDH, 0);
+ E1000_WRITE_REG(&adapter->hw, RDT, 0);
}
/* The 82542 2.0 (revision 2) needs to have the receive unit in reset
@@ -1068,7 +1052,7 @@ e1000_enter_82542_rst(struct e1000_adapter *adapter)
{
struct pci_dev *pdev = adapter->pdev;
struct net_device *netdev = adapter->netdev;
- uint16_t pci_command_word = adapter->shared.pci_cmd_word;
+ uint16_t pci_command_word = adapter->hw.pci_cmd_word;
uint32_t rctl;
if(pci_command_word & PCI_COMMAND_INVALIDATE) {
@@ -1076,14 +1060,13 @@ e1000_enter_82542_rst(struct e1000_adapter *adapter)
pci_write_config_word(pdev, PCI_COMMAND, pci_command_word);
}
- rctl = E1000_READ_REG(&adapter->shared, RCTL);
+ rctl = E1000_READ_REG(&adapter->hw, RCTL);
rctl |= E1000_RCTL_RST;
- E1000_WRITE_REG(&adapter->shared, RCTL, rctl);
+ E1000_WRITE_REG(&adapter->hw, RCTL, rctl);
msec_delay(5);
if(netif_running(netdev))
e1000_clean_rx_ring(adapter);
- return;
}
static void
@@ -1091,12 +1074,12 @@ e1000_leave_82542_rst(struct e1000_adapter *adapter)
{
struct pci_dev *pdev = adapter->pdev;
struct net_device *netdev = adapter->netdev;
- uint16_t pci_command_word = adapter->shared.pci_cmd_word;
+ uint16_t pci_command_word = adapter->hw.pci_cmd_word;
uint32_t rctl;
- rctl = E1000_READ_REG(&adapter->shared, RCTL);
+ rctl = E1000_READ_REG(&adapter->hw, RCTL);
rctl &= ~E1000_RCTL_RST;
- E1000_WRITE_REG(&adapter->shared, RCTL, rctl);
+ E1000_WRITE_REG(&adapter->hw, RCTL, rctl);
msec_delay(5);
if(pci_command_word & PCI_COMMAND_INVALIDATE)
@@ -1106,7 +1089,6 @@ e1000_leave_82542_rst(struct e1000_adapter *adapter)
e1000_configure_rx(adapter);
e1000_alloc_rx_buffers(adapter);
}
- return;
}
/**
@@ -1125,15 +1107,15 @@ e1000_set_mac(struct net_device *netdev, void *p)
/* 82542 2.0 needs to be in reset to write receive address registers */
- if(adapter->shared.mac_type == e1000_82542_rev2_0)
+ if(adapter->hw.mac_type == e1000_82542_rev2_0)
e1000_enter_82542_rst(adapter);
memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len);
- memcpy(adapter->shared.mac_addr, addr->sa_data, netdev->addr_len);
+ memcpy(adapter->hw.mac_addr, addr->sa_data, netdev->addr_len);
- e1000_rar_set(&adapter->shared, adapter->shared.mac_addr, 0);
+ e1000_rar_set(&adapter->hw, adapter->hw.mac_addr, 0);
- if(adapter->shared.mac_type == e1000_82542_rev2_0)
+ if(adapter->hw.mac_type == e1000_82542_rev2_0)
e1000_leave_82542_rst(adapter);
return 0;
@@ -1153,7 +1135,7 @@ static void
e1000_set_multi(struct net_device *netdev)
{
struct e1000_adapter *adapter = netdev->priv;
- struct e1000_shared_adapter *shared = &adapter->shared;
+ struct e1000_hw *hw = &adapter->hw;
struct dev_mc_list *mc_ptr;
uint32_t rctl;
uint32_t hash_value;
@@ -1161,7 +1143,7 @@ e1000_set_multi(struct net_device *netdev)
/* Check for Promiscuous and All Multicast modes */
- rctl = E1000_READ_REG(shared, RCTL);
+ rctl = E1000_READ_REG(hw, RCTL);
if(netdev->flags & IFF_PROMISC) {
rctl |= (E1000_RCTL_UPE | E1000_RCTL_MPE);
@@ -1172,11 +1154,11 @@ e1000_set_multi(struct net_device *netdev)
rctl &= ~(E1000_RCTL_UPE | E1000_RCTL_MPE);
}
- E1000_WRITE_REG(shared, RCTL, rctl);
+ E1000_WRITE_REG(hw, RCTL, rctl);
/* 82542 2.0 needs to be in reset to write receive address registers */
- if(shared->mac_type == e1000_82542_rev2_0)
+ if(hw->mac_type == e1000_82542_rev2_0)
e1000_enter_82542_rst(adapter);
/* load the first 15 multicast address into the exact filters 1-15
@@ -1187,29 +1169,28 @@ e1000_set_multi(struct net_device *netdev)
for(i = 1; i < E1000_RAR_ENTRIES; i++) {
if(mc_ptr) {
- e1000_rar_set(shared, mc_ptr->dmi_addr, i);
+ e1000_rar_set(hw, mc_ptr->dmi_addr, i);
mc_ptr = mc_ptr->next;
} else {
- E1000_WRITE_REG_ARRAY(shared, RA, i << 1, 0);
- E1000_WRITE_REG_ARRAY(shared, RA, (i << 1) + 1, 0);
+ E1000_WRITE_REG_ARRAY(hw, RA, i << 1, 0);
+ E1000_WRITE_REG_ARRAY(hw, RA, (i << 1) + 1, 0);
}
}
/* clear the old settings from the multicast hash table */
for(i = 0; i < E1000_NUM_MTA_REGISTERS; i++)
- E1000_WRITE_REG_ARRAY(shared, MTA, i, 0);
+ E1000_WRITE_REG_ARRAY(hw, MTA, i, 0);
/* load any remaining addresses into the hash table */
for(; mc_ptr; mc_ptr = mc_ptr->next) {
- hash_value = e1000_hash_mc_addr(shared, mc_ptr->dmi_addr);
- e1000_mta_set(shared, hash_value);
+ hash_value = e1000_hash_mc_addr(hw, mc_ptr->dmi_addr);
+ e1000_mta_set(hw, hash_value);
}
- if(shared->mac_type == e1000_82542_rev2_0)
+ if(hw->mac_type == e1000_82542_rev2_0)
e1000_leave_82542_rst(adapter);
- return;
}
@@ -1219,8 +1200,7 @@ static void
e1000_update_phy_info(unsigned long data)
{
struct e1000_adapter *adapter = (struct e1000_adapter *) data;
- e1000_phy_get_info(&adapter->shared, &adapter->phy_info);
- return;
+ e1000_phy_get_info(&adapter->hw, &adapter->phy_info);
}
/**
@@ -1234,11 +1214,11 @@ e1000_watchdog(unsigned long data)
struct e1000_adapter *adapter = (struct e1000_adapter *) data;
struct net_device *netdev = adapter->netdev;
- e1000_check_for_link(&adapter->shared);
+ e1000_check_for_link(&adapter->hw);
- if(E1000_READ_REG(&adapter->shared, STATUS) & E1000_STATUS_LU) {
+ if(E1000_READ_REG(&adapter->hw, STATUS) & E1000_STATUS_LU) {
if(!netif_carrier_ok(netdev)) {
- e1000_get_speed_and_duplex(&adapter->shared,
+ e1000_get_speed_and_duplex(&adapter->hw,
&adapter->link_speed,
&adapter->link_duplex);
@@ -1262,171 +1242,203 @@ e1000_watchdog(unsigned long data)
netdev->name);
netif_carrier_off(netdev);
netif_stop_queue(netdev);
+ mod_timer(&adapter->phy_info_timer, jiffies + 2 * HZ);
}
}
e1000_update_stats(adapter);
+ e1000_update_adaptive(&adapter->hw);
/* Reset the timer */
mod_timer(&adapter->watchdog_timer, jiffies + 2 * HZ);
-
- return;
}
-/**
- * e1000_xmit_frame - Transmit entry point
- * @skb: buffer with frame data to transmit
- * @netdev: network interface device structure
- *
- * Returns 0 on success, 1 on error
- *
- * e1000_xmit_frame is called by the stack to initiate a transmit.
- * The out of resource condition is checked after each successful Tx
- * so that the stack can be notified, preventing the driver from
- * ever needing to drop a frame. The atomic operations on
- * tx_ring.unused are used to syncronize with the transmit
- * interrupt processing code without the need for a spinlock.
- **/
+#define E1000_TX_FLAGS_CSUM 0x00000001
+#define E1000_TX_FLAGS_VLAN 0x00000002
+#define E1000_TX_FLAGS_VLAN_MASK 0xffff0000
+#define E1000_TX_FLAGS_VLAN_SHIFT 16
-#define TXD_USE_COUNT(x) (((x) >> 12) + ((x) & 0x0fff ? 1 : 0))
+static inline boolean_t
+e1000_tx_csum(struct e1000_adapter *adapter, struct sk_buff *skb)
+{
+ struct e1000_context_desc *context_desc;
+ int i;
+ uint8_t css, cso;
-#define SETUP_TXD_PAGE(L, P, O) do { \
- tx_ring->buffer_info[i].length = (L); \
- tx_ring->buffer_info[i].dma = \
- pci_map_page(pdev, (P), (O), (L), PCI_DMA_TODEVICE); \
- tx_desc->buffer_addr = cpu_to_le64(tx_ring->buffer_info[i].dma); \
- tx_desc->lower.data = cpu_to_le32(txd_lower | (L)); \
- tx_desc->upper.data = cpu_to_le32(txd_upper); \
-} while (0)
+ if(skb->ip_summed == CHECKSUM_HW) {
+ css = skb->h.raw - skb->data;
+ cso = (skb->h.raw + skb->csum) - skb->data;
-#define SETUP_TXD_PTR(L, P) \
- SETUP_TXD_PAGE((L), virt_to_page(P), (unsigned long)(P) & ~PAGE_MASK)
+ i = adapter->tx_ring.next_to_use;
+ context_desc = E1000_CONTEXT_DESC(adapter->tx_ring, i);
-#define QUEUE_TXD() do { i = (i + 1) % tx_ring->count; \
- atomic_dec(&tx_ring->unused); } while (0)
+ context_desc->upper_setup.tcp_fields.tucss = css;
+ context_desc->upper_setup.tcp_fields.tucso = cso;
+ context_desc->upper_setup.tcp_fields.tucse = 0;
+ context_desc->tcp_seg_setup.data = 0;
+ context_desc->cmd_and_length =
+ cpu_to_le32(adapter->txd_cmd | E1000_TXD_CMD_DEXT);
+ i = (i + 1) % adapter->tx_ring.count;
+ adapter->tx_ring.next_to_use = i;
-static int
-e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static inline int
+e1000_tx_map(struct e1000_adapter *adapter, struct sk_buff *skb)
{
- struct e1000_adapter *adapter = netdev->priv;
struct e1000_desc_ring *tx_ring = &adapter->tx_ring;
- struct pci_dev *pdev = adapter->pdev;
- struct e1000_tx_desc *tx_desc;
- int f, len, offset, txd_needed;
- skb_frag_t *frag;
+ int len, offset, size, count, i;
- int i = tx_ring->next_to_use;
- uint32_t txd_upper = 0;
- uint32_t txd_lower = adapter->txd_cmd;
+ int f;
+ len = skb->len - skb->data_len;
+ i = (tx_ring->next_to_use + tx_ring->count - 1) % tx_ring->count;
+ count = 0;
- /* If controller appears hung, force transmit timeout */
+ offset = 0;
- if (time_after(netdev->trans_start, adapter->trans_finish + HZ) &&
- /* If transmitting XOFFs, we're not really hung */
- !(E1000_READ_REG(&adapter->shared, STATUS) & E1000_STATUS_TXOFF)) {
- adapter->trans_finish = jiffies;
- netif_stop_queue(netdev);
- return 1;
+ while(len) {
+ i = (i + 1) % tx_ring->count;
+ size = min(len, adapter->max_data_per_txd);
+ tx_ring->buffer_info[i].length = size;
+ tx_ring->buffer_info[i].dma =
+ pci_map_single(adapter->pdev,
+ skb->data + offset,
+ size,
+ PCI_DMA_TODEVICE);
+
+ len -= size;
+ offset += size;
+ count++;
}
- txd_needed = TXD_USE_COUNT(skb->len - skb->data_len);
-
for(f = 0; f < skb_shinfo(skb)->nr_frags; f++) {
- frag = &skb_shinfo(skb)->frags[f];
- txd_needed += TXD_USE_COUNT(frag->size);
- }
+ struct skb_frag_struct *frag;
- if(skb->ip_summed == CHECKSUM_HW)
- txd_needed += 1;
-
- /* make sure there are enough Tx descriptors available in the ring */
+ frag = &skb_shinfo(skb)->frags[f];
+ len = frag->size;
+ offset = 0;
- if(atomic_read(&tx_ring->unused) <= (txd_needed + 1)) {
- adapter->net_stats.tx_dropped++;
- netif_stop_queue(netdev);
- return 1;
+ while(len) {
+ i = (i + 1) % tx_ring->count;
+ size = min(len, adapter->max_data_per_txd);
+ tx_ring->buffer_info[i].length = size;
+ tx_ring->buffer_info[i].dma =
+ pci_map_page(adapter->pdev,
+ frag->page,
+ frag->page_offset + offset,
+ size,
+ PCI_DMA_TODEVICE);
+
+ len -= size;
+ offset += size;
+ count++;
+ }
}
+ tx_ring->buffer_info[i].skb = skb;
- if(skb->ip_summed == CHECKSUM_HW) {
- struct e1000_context_desc *context_desc;
- uint8_t css = skb->h.raw - skb->data;
- uint8_t cso = (skb->h.raw + skb->csum) - skb->data;
-
- context_desc = E1000_CONTEXT_DESC(*tx_ring, i);
+ return count;
+}
- context_desc->upper_setup.tcp_fields.tucss = css;
- context_desc->upper_setup.tcp_fields.tucso = cso;
- context_desc->upper_setup.tcp_fields.tucse = 0;
- context_desc->tcp_seg_setup.data = 0;
- context_desc->cmd_and_length =
- cpu_to_le32(txd_lower | E1000_TXD_CMD_DEXT);
+static inline void
+e1000_tx_queue(struct e1000_adapter *adapter, int count, int tx_flags)
+{
+ struct e1000_desc_ring *tx_ring = &adapter->tx_ring;
+ struct e1000_tx_desc *tx_desc = NULL;
+ uint32_t txd_upper, txd_lower;
+ int i;
- QUEUE_TXD();
+ txd_upper = 0;
+ txd_lower = adapter->txd_cmd;
- txd_upper |= E1000_TXD_POPTS_TXSM << 8;
+ if(tx_flags & E1000_TX_FLAGS_CSUM) {
txd_lower |= E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D;
+ txd_upper |= E1000_TXD_POPTS_TXSM << 8;
}
- tx_desc = E1000_TX_DESC(*tx_ring, i);
- len = skb->len - skb->data_len;
- offset = 0;
+ if(tx_flags & E1000_TX_FLAGS_VLAN) {
+ txd_lower |= E1000_TXD_CMD_VLE;
+ txd_upper |= (tx_flags & E1000_TX_FLAGS_VLAN_MASK);
+ }
- while(len > 4096) {
- SETUP_TXD_PTR(4096, skb->data + offset);
- QUEUE_TXD();
+ i = tx_ring->next_to_use;
+ while(count--) {
tx_desc = E1000_TX_DESC(*tx_ring, i);
- len -= 4096;
- offset += 4096;
+ tx_desc->buffer_addr = cpu_to_le64(tx_ring->buffer_info[i].dma);
+ tx_desc->lower.data =
+ cpu_to_le32(txd_lower | tx_ring->buffer_info[i].length);
+ tx_desc->upper.data = cpu_to_le32(txd_upper);
+ i = (i + 1) % tx_ring->count;
}
- SETUP_TXD_PTR(len, skb->data + offset);
+ tx_desc->lower.data |= cpu_to_le32(E1000_TXD_CMD_EOP);
- for(f = 0; f < skb_shinfo(skb)->nr_frags; f++) {
- frag = &skb_shinfo(skb)->frags[f];
+ tx_ring->next_to_use = i;
+ E1000_WRITE_REG(&adapter->hw, TDT, i);
+}
- QUEUE_TXD();
+#define TXD_USE_COUNT(S, X) (((S) / (X)) + (((S) % (X)) ? 1 : 0))
- tx_desc = E1000_TX_DESC(*tx_ring, i);
- len = frag->size;
- offset = 0;
+static int
+e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
+{
+ struct e1000_adapter *adapter = netdev->priv;
+ unsigned long flags;
+ int tx_flags = 0, count;
- while(len > 4096) {
- SETUP_TXD_PAGE(4096, frag->page,
- frag->page_offset + offset);
- QUEUE_TXD();
+ int f;
- tx_desc = E1000_TX_DESC(*tx_ring, i);
- len -= 4096;
- offset += 4096;
- }
- SETUP_TXD_PAGE(len, frag->page, frag->page_offset + offset);
- }
- /* EOP and SKB pointer go with the last fragment */
+ if(time_after(netdev->trans_start, adapter->trans_finish + HZ) &&
+ !(E1000_READ_REG(&adapter->hw, STATUS) & E1000_STATUS_TXOFF)) {
- tx_desc->lower.data |= cpu_to_le32(E1000_TXD_CMD_EOP);
- tx_ring->buffer_info[i].skb = skb;
+ adapter->trans_finish = jiffies;
+ netif_stop_queue(netdev);
+ return 1;
+ }
- QUEUE_TXD();
+ count = TXD_USE_COUNT(skb->len - skb->data_len,
+ adapter->max_data_per_txd);
+ for(f = 0; f < skb_shinfo(skb)->nr_frags; f++)
+ count += TXD_USE_COUNT(skb_shinfo(skb)->frags[f].size,
+ adapter->max_data_per_txd);
+ if(skb->ip_summed == CHECKSUM_HW)
+ count++;
- tx_ring->next_to_use = i;
+ spin_lock_irqsave(&adapter->tx_lock, flags);
+ e1000_clean_tx_irq(adapter);
+ if(E1000_DESC_UNUSED(&adapter->tx_ring) < count) {
+ netif_stop_queue(netdev);
+ spin_unlock_irqrestore(&adapter->tx_lock, flags);
+ return 1;
+ }
+ spin_unlock_irqrestore(&adapter->tx_lock, flags);
+
+ if(e1000_tx_csum(adapter, skb))
+ tx_flags |= E1000_TX_FLAGS_CSUM;
- /* Move the HW Tx Tail Pointer */
+#ifdef NETIF_F_HW_VLAN_TX
+ if(adapter->vlgrp && vlan_tx_tag_present(skb)) {
+ tx_flags |= E1000_TX_FLAGS_VLAN;
+ tx_flags |= (vlan_tx_tag_get(skb) << E1000_TX_FLAGS_VLAN_SHIFT);
+ }
+#endif
+
+ count = e1000_tx_map(adapter, skb);
- E1000_WRITE_REG(&adapter->shared, TDT, i);
+ e1000_tx_queue(adapter, count, tx_flags);
netdev->trans_start = jiffies;
return 0;
}
-#undef TXD_USE_COUNT
-#undef SETUP_TXD
-#undef QUEUE_TXD
-
/**
* e1000_tx_timeout - Respond to a Tx Hang
* @netdev: network interface device structure
@@ -1470,24 +1482,21 @@ e1000_change_mtu(struct net_device *netdev, int new_mtu)
{
struct e1000_adapter *adapter = netdev->priv;
int old_mtu = adapter->rx_buffer_len;
- int max_frame = new_mtu + ENET_HEADER_SIZE + CRC_LENGTH;
+ int max_frame = new_mtu + ENET_HEADER_SIZE + ETHERNET_FCS_SIZE;
- if((max_frame < MINIMUM_ETHERNET_PACKET_SIZE + CRC_LENGTH) ||
- (max_frame > MAX_JUMBO_FRAME_SIZE + CRC_LENGTH)) {
+ if((max_frame < MINIMUM_ETHERNET_FRAME_SIZE) ||
+ (max_frame > MAX_JUMBO_FRAME_SIZE)) {
E1000_ERR("Invalid MTU setting\n");
return -EINVAL;
}
- if(max_frame <= MAXIMUM_ETHERNET_PACKET_SIZE + CRC_LENGTH) {
+ if(max_frame <= E1000_RXBUFFER_2048) {
adapter->rx_buffer_len = E1000_RXBUFFER_2048;
- } else if(adapter->shared.mac_type < e1000_82543) {
+ } else if(adapter->hw.mac_type < e1000_82543) {
E1000_ERR("Jumbo Frames not supported on 82542\n");
return -EINVAL;
- } else if(max_frame <= E1000_RXBUFFER_2048) {
- adapter->rx_buffer_len = E1000_RXBUFFER_2048;
-
} else if(max_frame <= E1000_RXBUFFER_4096) {
adapter->rx_buffer_len = E1000_RXBUFFER_4096;
@@ -1501,13 +1510,11 @@ e1000_change_mtu(struct net_device *netdev, int new_mtu)
if(old_mtu != adapter->rx_buffer_len && netif_running(netdev)) {
e1000_down(adapter);
- e1000_clean_rx_ring(adapter);
- e1000_clean_tx_ring(adapter);
e1000_up(adapter);
}
netdev->mtu = new_mtu;
- adapter->shared.max_frame_size = max_frame;
+ adapter->hw.max_frame_size = max_frame;
return 0;
}
@@ -1520,8 +1527,9 @@ e1000_change_mtu(struct net_device *netdev, int new_mtu)
static void
e1000_update_stats(struct e1000_adapter *adapter)
{
- struct e1000_shared_adapter *shared = &adapter->shared;
+ struct e1000_hw *hw = &adapter->hw;
unsigned long flags;
+ uint16_t phy_tmp;
#define PHY_IDLE_ERROR_COUNT_MASK 0x00FF
@@ -1532,68 +1540,73 @@ e1000_update_stats(struct e1000_adapter *adapter)
* be written while holding adapter->stats_lock
*/
- adapter->stats.crcerrs += E1000_READ_REG(shared, CRCERRS);
- adapter->stats.gprc += E1000_READ_REG(shared, GPRC);
- adapter->stats.gorcl += E1000_READ_REG(shared, GORCL);
- adapter->stats.gorch += E1000_READ_REG(shared, GORCH);
- adapter->stats.bprc += E1000_READ_REG(shared, BPRC);
- adapter->stats.mprc += E1000_READ_REG(shared, MPRC);
- adapter->stats.roc += E1000_READ_REG(shared, ROC);
- adapter->stats.prc64 += E1000_READ_REG(shared, PRC64);
- adapter->stats.prc127 += E1000_READ_REG(shared, PRC127);
- adapter->stats.prc255 += E1000_READ_REG(shared, PRC255);
- adapter->stats.prc511 += E1000_READ_REG(shared, PRC511);
- adapter->stats.prc1023 += E1000_READ_REG(shared, PRC1023);
- adapter->stats.prc1522 += E1000_READ_REG(shared, PRC1522);
+ adapter->stats.crcerrs += E1000_READ_REG(hw, CRCERRS);
+ adapter->stats.gprc += E1000_READ_REG(hw, GPRC);
+ adapter->stats.gorcl += E1000_READ_REG(hw, GORCL);
+ adapter->stats.gorch += E1000_READ_REG(hw, GORCH);
+ adapter->stats.bprc += E1000_READ_REG(hw, BPRC);
+ adapter->stats.mprc += E1000_READ_REG(hw, MPRC);
+ adapter->stats.roc += E1000_READ_REG(hw, ROC);
+ adapter->stats.prc64 += E1000_READ_REG(hw, PRC64);
+ adapter->stats.prc127 += E1000_READ_REG(hw, PRC127);
+ adapter->stats.prc255 += E1000_READ_REG(hw, PRC255);
+ adapter->stats.prc511 += E1000_READ_REG(hw, PRC511);
+ adapter->stats.prc1023 += E1000_READ_REG(hw, PRC1023);
+ adapter->stats.prc1522 += E1000_READ_REG(hw, PRC1522);
spin_unlock_irqrestore(&adapter->stats_lock, flags);
/* the rest of the counters are only modified here */
- adapter->stats.symerrs += E1000_READ_REG(shared, SYMERRS);
- adapter->stats.mpc += E1000_READ_REG(shared, MPC);
- adapter->stats.scc += E1000_READ_REG(shared, SCC);
- adapter->stats.ecol += E1000_READ_REG(shared, ECOL);
- adapter->stats.mcc += E1000_READ_REG(shared, MCC);
- adapter->stats.latecol += E1000_READ_REG(shared, LATECOL);
- adapter->stats.colc += E1000_READ_REG(shared, COLC);
- adapter->stats.dc += E1000_READ_REG(shared, DC);
- adapter->stats.sec += E1000_READ_REG(shared, SEC);
- adapter->stats.rlec += E1000_READ_REG(shared, RLEC);
- adapter->stats.xonrxc += E1000_READ_REG(shared, XONRXC);
- adapter->stats.xontxc += E1000_READ_REG(shared, XONTXC);
- adapter->stats.xoffrxc += E1000_READ_REG(shared, XOFFRXC);
- adapter->stats.xofftxc += E1000_READ_REG(shared, XOFFTXC);
- adapter->stats.fcruc += E1000_READ_REG(shared, FCRUC);
- adapter->stats.gptc += E1000_READ_REG(shared, GPTC);
- adapter->stats.gotcl += E1000_READ_REG(shared, GOTCL);
- adapter->stats.gotch += E1000_READ_REG(shared, GOTCH);
- adapter->stats.rnbc += E1000_READ_REG(shared, RNBC);
- adapter->stats.ruc += E1000_READ_REG(shared, RUC);
- adapter->stats.rfc += E1000_READ_REG(shared, RFC);
- adapter->stats.rjc += E1000_READ_REG(shared, RJC);
- adapter->stats.torl += E1000_READ_REG(shared, TORL);
- adapter->stats.torh += E1000_READ_REG(shared, TORH);
- adapter->stats.totl += E1000_READ_REG(shared, TOTL);
- adapter->stats.toth += E1000_READ_REG(shared, TOTH);
- adapter->stats.tpr += E1000_READ_REG(shared, TPR);
- adapter->stats.tpt += E1000_READ_REG(shared, TPT);
- adapter->stats.ptc64 += E1000_READ_REG(shared, PTC64);
- adapter->stats.ptc127 += E1000_READ_REG(shared, PTC127);
- adapter->stats.ptc255 += E1000_READ_REG(shared, PTC255);
- adapter->stats.ptc511 += E1000_READ_REG(shared, PTC511);
- adapter->stats.ptc1023 += E1000_READ_REG(shared, PTC1023);
- adapter->stats.ptc1522 += E1000_READ_REG(shared, PTC1522);
- adapter->stats.mptc += E1000_READ_REG(shared, MPTC);
- adapter->stats.bptc += E1000_READ_REG(shared, BPTC);
-
- if(adapter->shared.mac_type >= e1000_82543) {
- adapter->stats.algnerrc += E1000_READ_REG(shared, ALGNERRC);
- adapter->stats.rxerrc += E1000_READ_REG(shared, RXERRC);
- adapter->stats.tncrs += E1000_READ_REG(shared, TNCRS);
- adapter->stats.cexterr += E1000_READ_REG(shared, CEXTERR);
- adapter->stats.tsctc += E1000_READ_REG(shared, TSCTC);
- adapter->stats.tsctfc += E1000_READ_REG(shared, TSCTFC);
+ adapter->stats.symerrs += E1000_READ_REG(hw, SYMERRS);
+ adapter->stats.mpc += E1000_READ_REG(hw, MPC);
+ adapter->stats.scc += E1000_READ_REG(hw, SCC);
+ adapter->stats.ecol += E1000_READ_REG(hw, ECOL);
+ adapter->stats.mcc += E1000_READ_REG(hw, MCC);
+ adapter->stats.latecol += E1000_READ_REG(hw, LATECOL);
+ adapter->stats.dc += E1000_READ_REG(hw, DC);
+ adapter->stats.sec += E1000_READ_REG(hw, SEC);
+ adapter->stats.rlec += E1000_READ_REG(hw, RLEC);
+ adapter->stats.xonrxc += E1000_READ_REG(hw, XONRXC);
+ adapter->stats.xontxc += E1000_READ_REG(hw, XONTXC);
+ adapter->stats.xoffrxc += E1000_READ_REG(hw, XOFFRXC);
+ adapter->stats.xofftxc += E1000_READ_REG(hw, XOFFTXC);
+ adapter->stats.fcruc += E1000_READ_REG(hw, FCRUC);
+ adapter->stats.gptc += E1000_READ_REG(hw, GPTC);
+ adapter->stats.gotcl += E1000_READ_REG(hw, GOTCL);
+ adapter->stats.gotch += E1000_READ_REG(hw, GOTCH);
+ adapter->stats.rnbc += E1000_READ_REG(hw, RNBC);
+ adapter->stats.ruc += E1000_READ_REG(hw, RUC);
+ adapter->stats.rfc += E1000_READ_REG(hw, RFC);
+ adapter->stats.rjc += E1000_READ_REG(hw, RJC);
+ adapter->stats.torl += E1000_READ_REG(hw, TORL);
+ adapter->stats.torh += E1000_READ_REG(hw, TORH);
+ adapter->stats.totl += E1000_READ_REG(hw, TOTL);
+ adapter->stats.toth += E1000_READ_REG(hw, TOTH);
+ adapter->stats.tpr += E1000_READ_REG(hw, TPR);
+ adapter->stats.ptc64 += E1000_READ_REG(hw, PTC64);
+ adapter->stats.ptc127 += E1000_READ_REG(hw, PTC127);
+ adapter->stats.ptc255 += E1000_READ_REG(hw, PTC255);
+ adapter->stats.ptc511 += E1000_READ_REG(hw, PTC511);
+ adapter->stats.ptc1023 += E1000_READ_REG(hw, PTC1023);
+ adapter->stats.ptc1522 += E1000_READ_REG(hw, PTC1522);
+ adapter->stats.mptc += E1000_READ_REG(hw, MPTC);
+ adapter->stats.bptc += E1000_READ_REG(hw, BPTC);
+
+ /* used for adaptive IFS */
+
+ hw->tx_packet_delta = E1000_READ_REG(hw, TPT);
+ adapter->stats.tpt += hw->tx_packet_delta;
+ hw->collision_delta = E1000_READ_REG(hw, COLC);
+ adapter->stats.colc += hw->collision_delta;
+
+ if(hw->mac_type >= e1000_82543) {
+ adapter->stats.algnerrc += E1000_READ_REG(hw, ALGNERRC);
+ adapter->stats.rxerrc += E1000_READ_REG(hw, RXERRC);
+ adapter->stats.tncrs += E1000_READ_REG(hw, TNCRS);
+ adapter->stats.cexterr += E1000_READ_REG(hw, CEXTERR);
+ adapter->stats.tsctc += E1000_READ_REG(hw, TSCTC);
+ adapter->stats.tsctfc += E1000_READ_REG(hw, TSCTFC);
}
/* Fill out the OS statistics structure */
@@ -1627,14 +1640,18 @@ e1000_update_stats(struct e1000_adapter *adapter)
/* Tx Dropped needs to be maintained elsewhere */
- if(adapter->shared.media_type == e1000_media_type_copper) {
- adapter->phy_stats.idle_errors +=
- (e1000_read_phy_reg(shared, PHY_1000T_STATUS)
- & PHY_IDLE_ERROR_COUNT_MASK);
- adapter->phy_stats.receive_errors +=
- e1000_read_phy_reg(shared, M88E1000_RX_ERR_CNTR);
+ /* Phy Stats */
+
+ if(hw->media_type == e1000_media_type_copper) {
+ if((adapter->link_speed == SPEED_1000) &&
+ (!e1000_read_phy_reg(hw, PHY_1000T_STATUS, &phy_tmp))) {
+ phy_tmp &= PHY_IDLE_ERROR_COUNT_MASK;
+ adapter->phy_stats.idle_errors += phy_tmp;
+ }
+
+ if(!e1000_read_phy_reg(hw, M88E1000_RX_ERR_CNTR, &phy_tmp))
+ adapter->phy_stats.receive_errors += phy_tmp;
}
- return;
}
/**
@@ -1646,9 +1663,8 @@ static inline void
e1000_irq_disable(struct e1000_adapter *adapter)
{
atomic_inc(&adapter->irq_sem);
- E1000_WRITE_REG(&adapter->shared, IMC, ~0);
+ E1000_WRITE_REG(&adapter->hw, IMC, ~0);
synchronize_irq();
- return;
}
/**
@@ -1660,8 +1676,7 @@ static inline void
e1000_irq_enable(struct e1000_adapter *adapter)
{
if(atomic_dec_and_test(&adapter->irq_sem))
- E1000_WRITE_REG(&adapter->shared, IMS, IMS_ENABLE_MASK);
- return;
+ E1000_WRITE_REG(&adapter->hw, IMS, IMS_ENABLE_MASK);
}
/**
@@ -1679,20 +1694,23 @@ e1000_intr(int irq, void *data, struct pt_regs *regs)
uint32_t icr;
int i = E1000_MAX_INTR;
- while(i && (icr = E1000_READ_REG(&adapter->shared, ICR))) {
+ while(i && (icr = E1000_READ_REG(&adapter->hw, ICR))) {
if(icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) {
- /* run the watchdog ASAP */
- adapter->shared.get_link_status = 1;
+ adapter->hw.get_link_status = 1;
mod_timer(&adapter->watchdog_timer, jiffies);
}
e1000_clean_rx_irq(adapter);
- e1000_clean_tx_irq(adapter);
+
+ if((icr & E1000_ICR_TXDW) && spin_trylock(&adapter->tx_lock)) {
+ e1000_clean_tx_irq(adapter);
+ spin_unlock(&adapter->tx_lock);
+ }
+
i--;
- }
- return;
+ }
}
/**
@@ -1726,7 +1744,7 @@ e1000_clean_tx_irq(struct e1000_adapter *adapter)
if(tx_ring->buffer_info[i].skb) {
- dev_kfree_skb_irq(tx_ring->buffer_info[i].skb);
+ dev_kfree_skb_any(tx_ring->buffer_info[i].skb);
tx_ring->buffer_info[i].skb = NULL;
}
@@ -1734,7 +1752,6 @@ e1000_clean_tx_irq(struct e1000_adapter *adapter)
memset(tx_desc, 0, sizeof(struct e1000_tx_desc));
mb();
- atomic_inc(&tx_ring->unused);
i = (i + 1) % tx_ring->count;
tx_desc = E1000_TX_DESC(*tx_ring, i);
@@ -1744,11 +1761,10 @@ e1000_clean_tx_irq(struct e1000_adapter *adapter)
tx_ring->next_to_clean = i;
if(netif_queue_stopped(netdev) && netif_carrier_ok(netdev) &&
- (atomic_read(&tx_ring->unused) > E1000_TX_QUEUE_WAKE)) {
+ (E1000_DESC_UNUSED(tx_ring) > E1000_TX_QUEUE_WAKE)) {
netif_wake_queue(netdev);
}
- return;
}
/**
@@ -1789,12 +1805,10 @@ e1000_clean_rx_irq(struct e1000_adapter *adapter)
E1000_DBG("Receive packet consumed multiple buffers\n");
dev_kfree_skb_irq(skb);
- memset(rx_desc, 0, 16);
+ memset(rx_desc, 0, sizeof(struct e1000_rx_desc));
mb();
rx_ring->buffer_info[i].skb = NULL;
- rx_ring->unused_count++;
-
i = (i + 1) % rx_ring->count;
rx_desc = E1000_RX_DESC(*rx_ring, i);
@@ -1805,12 +1819,12 @@ e1000_clean_rx_irq(struct e1000_adapter *adapter)
last_byte = *(skb->data + length - 1);
- if(TBI_ACCEPT(&adapter->shared, rx_desc->special,
+ if(TBI_ACCEPT(&adapter->hw, rx_desc->status,
rx_desc->errors, length, last_byte)) {
spin_lock_irqsave(&adapter->stats_lock, flags);
- e1000_tbi_adjust_stats(&adapter->shared,
+ e1000_tbi_adjust_stats(&adapter->hw,
&adapter->stats,
length, skb->data);
@@ -1820,11 +1834,10 @@ e1000_clean_rx_irq(struct e1000_adapter *adapter)
} else {
dev_kfree_skb_irq(skb);
- memset(rx_desc, 0, 16);
+ memset(rx_desc, 0, sizeof(struct e1000_rx_desc));
mb();
rx_ring->buffer_info[i].skb = NULL;
- rx_ring->unused_count++;
i = (i + 1) % rx_ring->count;
rx_desc = E1000_RX_DESC(*rx_ring, i);
@@ -1833,20 +1846,28 @@ e1000_clean_rx_irq(struct e1000_adapter *adapter)
}
/* Good Receive */
- skb_put(skb, length - CRC_LENGTH);
+ skb_put(skb, length - ETHERNET_FCS_SIZE);
/* Receive Checksum Offload */
e1000_rx_checksum(adapter, rx_desc, skb);
skb->protocol = eth_type_trans(skb, netdev);
+#ifdef NETIF_F_HW_VLAN_TX
+ if(adapter->vlgrp && (rx_desc->status & E1000_RXD_STAT_VP)) {
+ vlan_hwaccel_rx(skb, adapter->vlgrp,
+ (rx_desc->special & E1000_RXD_SPC_VLAN_MASK));
+ } else {
+ netif_rx(skb);
+ }
+#else
netif_rx(skb);
+#endif
+ netdev->last_rx = jiffies;
memset(rx_desc, 0, sizeof(struct e1000_rx_desc));
mb();
rx_ring->buffer_info[i].skb = NULL;
- rx_ring->unused_count++;
-
i = (i + 1) % rx_ring->count;
rx_desc = E1000_RX_DESC(*rx_ring, i);
@@ -1855,8 +1876,6 @@ e1000_clean_rx_irq(struct e1000_adapter *adapter)
rx_ring->next_to_clean = i;
e1000_alloc_rx_buffers(adapter);
-
- return;
}
/**
@@ -1911,16 +1930,13 @@ e1000_alloc_rx_buffers(struct e1000_adapter *adapter)
rx_desc->buffer_addr = cpu_to_le64(rx_ring->buffer_info[i].dma);
- /* move tail */
- E1000_WRITE_REG(&adapter->shared, RDT, i);
-
- atomic_dec(&rx_ring->unused);
+ if(!(i % E1000_RX_BUFFER_WRITE))
+ E1000_WRITE_REG(&adapter->hw, RDT, i);
i = (i + 1) % rx_ring->count;
}
rx_ring->next_to_use = i;
- return;
}
/**
@@ -1954,7 +1970,7 @@ e1000_rx_checksum(struct e1000_adapter *adapter,
struct sk_buff *skb)
{
/* 82543 or newer only */
- if((adapter->shared.mac_type < e1000_82543) ||
+ if((adapter->hw.mac_type < e1000_82543) ||
/* Ignore Checksum bit is set */
(rx_desc->status & E1000_RXD_STAT_IXSM) ||
/* TCP Checksum has not been calculated */
@@ -1974,10 +1990,8 @@ e1000_rx_checksum(struct e1000_adapter *adapter,
skb->ip_summed = CHECKSUM_UNNECESSARY;
adapter->hw_csum_good++;
}
- return;
}
-
/**
* e1000_enable_WOL - Wake On Lan Support (Magic Pkt)
* @adapter: Adapter structure
@@ -1988,29 +2002,104 @@ e1000_enable_WOL(struct e1000_adapter *adapter)
{
uint32_t wuc;
- if(adapter->shared.mac_type < e1000_82544)
+ if(adapter->hw.mac_type < e1000_82544)
return;
if(adapter->wol) {
wuc = E1000_WUC_APME | E1000_WUC_PME_EN |
E1000_WUC_PME_STATUS | E1000_WUC_APMPME;
- E1000_WRITE_REG(&adapter->shared, WUC, wuc);
+ E1000_WRITE_REG(&adapter->hw, WUC, wuc);
- E1000_WRITE_REG(&adapter->shared, WUFC, adapter->wol);
+ E1000_WRITE_REG(&adapter->hw, WUFC, adapter->wol);
}
-
- return;
}
void
-e1000_write_pci_cfg(struct e1000_shared_adapter *shared,
+e1000_write_pci_cfg(struct e1000_hw *hw,
uint32_t reg, uint16_t *value)
{
- struct e1000_adapter *adapter = shared->back;
+ struct e1000_adapter *adapter = hw->back;
pci_write_config_word(adapter->pdev, reg, *value);
- return;
}
+#ifdef NETIF_F_HW_VLAN_TX
+static void
+e1000_vlan_rx_register(struct net_device *netdev, struct vlan_group *grp)
+{
+ struct e1000_adapter *adapter = netdev->priv;
+ uint32_t ctrl, rctl;
+
+ e1000_irq_disable(adapter);
+ adapter->vlgrp = grp;
+
+ if(grp) {
+ /* enable VLAN tag insert/strip */
+
+ E1000_WRITE_REG(&adapter->hw, VET, ETHERNET_IEEE_VLAN_TYPE);
+
+ ctrl = E1000_READ_REG(&adapter->hw, CTRL);
+ ctrl |= E1000_CTRL_VME;
+ E1000_WRITE_REG(&adapter->hw, CTRL, ctrl);
+
+ /* enable VLAN receive filtering */
+
+ rctl = E1000_READ_REG(&adapter->hw, RCTL);
+ rctl |= E1000_RCTL_VFE;
+ rctl &= ~E1000_RCTL_CFIEN;
+ E1000_WRITE_REG(&adapter->hw, RCTL, rctl);
+ } else {
+ /* disable VLAN tag insert/strip */
+
+ ctrl = E1000_READ_REG(&adapter->hw, CTRL);
+ ctrl &= ~E1000_CTRL_VME;
+ E1000_WRITE_REG(&adapter->hw, CTRL, ctrl);
+
+ /* disable VLAN filtering */
+
+ rctl = E1000_READ_REG(&adapter->hw, RCTL);
+ rctl &= ~E1000_RCTL_VFE;
+ E1000_WRITE_REG(&adapter->hw, RCTL, rctl);
+ }
+
+ e1000_irq_enable(adapter);
+}
+
+static void
+e1000_vlan_rx_add_vid(struct net_device *netdev, uint16_t vid)
+{
+ struct e1000_adapter *adapter = netdev->priv;
+ uint32_t vfta, index;
+
+ /* add VID to filter table */
+
+ index = (vid >> 5) & 0x7F;
+ vfta = E1000_READ_REG_ARRAY(&adapter->hw, VFTA, index);
+ vfta |= (1 << (vid & 0x1F));
+ e1000_write_vfta(&adapter->hw, index, vfta);
+}
+
+static void
+e1000_vlan_rx_kill_vid(struct net_device *netdev, uint16_t vid)
+{
+ struct e1000_adapter *adapter = netdev->priv;
+ uint32_t vfta, index;
+
+ e1000_irq_disable(adapter);
+
+ if(adapter->vlgrp)
+ adapter->vlgrp->vlan_devices[vid] = NULL;
+
+ e1000_irq_enable(adapter);
+
+ /* remove VID from filter table*/
+
+ index = (vid >> 5) & 0x7F;
+ vfta = E1000_READ_REG_ARRAY(&adapter->hw, VFTA, index);
+ vfta &= ~(1 << (vid & 0x1F));
+ e1000_write_vfta(&adapter->hw, index, vfta);
+}
+#endif
+
/* e1000_main.c */
diff --git a/drivers/net/e1000/e1000_osdep.h b/drivers/net/e1000/e1000_osdep.h
index a7a1be20bc7c8..3990e01eb1dc7 100644
--- a/drivers/net/e1000/e1000_osdep.h
+++ b/drivers/net/e1000/e1000_osdep.h
@@ -2,9 +2,8 @@
This software program is available to you under a choice of one of two
licenses. You may choose to be licensed under either the GNU General Public
- License (GPL) Version 2, June 1991, available at
- http://www.fsf.org/copyleft/gpl.html, or the Intel BSD + Patent License, the
- text of which follows:
+ License 2.0, June 1991, available at http://www.fsf.org/copyleft/gpl.html,
+ or the Intel BSD + Patent License, the text of which follows:
Recipient has requested a license and Intel Corporation ("Intel") is willing
to grant a license for the software entitled Linux Base Driver for the
@@ -18,7 +17,7 @@
"Recipient" means the party to whom Intel delivers this Software.
"Licensee" means Recipient and those third parties that receive a license to
- any operating system available under the GNU Public License version 2.0 or
+ any operating system available under the GNU General Public License 2.0 or
later.
Copyright (c) 1999 - 2002 Intel Corporation.
@@ -51,10 +50,10 @@
version of an operating system that has been distributed under the GNU
General Public License 2.0 or later. This patent license shall apply to the
combination of the Software and any operating system licensed under the GNU
- Public License version 2.0 or later if, at the time Intel provides the
+ General Public License 2.0 or later if, at the time Intel provides the
Software to Recipient, such addition of the Software to the then publicly
- available versions of such operating systems available under the GNU Public
- License version 2.0 or later (whether in gold, beta or alpha form) causes
+ available versions of such operating systems available under the GNU General
+ Public License 2.0 or later (whether in gold, beta or alpha form) causes
such combination to be covered by the Licensed Patents. The patent license
shall not apply to any other combinations which include the Software. NO
hardware per se is licensed hereunder.
diff --git a/drivers/net/e1000/e1000_param.c b/drivers/net/e1000/e1000_param.c
index b93595df24f25..618515ae94f25 100644
--- a/drivers/net/e1000/e1000_param.c
+++ b/drivers/net/e1000/e1000_param.c
@@ -2,9 +2,8 @@
This software program is available to you under a choice of one of two
licenses. You may choose to be licensed under either the GNU General Public
- License (GPL) Version 2, June 1991, available at
- http://www.fsf.org/copyleft/gpl.html, or the Intel BSD + Patent License, the
- text of which follows:
+ License 2.0, June 1991, available at http://www.fsf.org/copyleft/gpl.html,
+ or the Intel BSD + Patent License, the text of which follows:
Recipient has requested a license and Intel Corporation ("Intel") is willing
to grant a license for the software entitled Linux Base Driver for the
@@ -18,7 +17,7 @@
"Recipient" means the party to whom Intel delivers this Software.
"Licensee" means Recipient and those third parties that receive a license to
- any operating system available under the GNU Public License version 2.0 or
+ any operating system available under the GNU General Public License 2.0 or
later.
Copyright (c) 1999 - 2002 Intel Corporation.
@@ -51,10 +50,10 @@
version of an operating system that has been distributed under the GNU
General Public License 2.0 or later. This patent license shall apply to the
combination of the Software and any operating system licensed under the GNU
- Public License version 2.0 or later if, at the time Intel provides the
+ General Public License 2.0 or later if, at the time Intel provides the
Software to Recipient, such addition of the Software to the then publicly
- available versions of such operating systems available under the GNU Public
- License version 2.0 or later (whether in gold, beta or alpha form) causes
+ available versions of such operating systems available under the GNU General
+ Public License 2.0 or later (whether in gold, beta or alpha form) causes
such combination to be covered by the Licensed Patents. The patent license
shall not apply to any other combinations which include the Software. NO
hardware per se is licensed hereunder.
@@ -153,7 +152,7 @@ E1000_PARAM(Duplex, "Duplex setting");
/* Auto-negotiation Advertisement Override
*
- * Valid Range: 0x00-0x0F, 0x20-0x2F
+ * Valid Range: 0x01-0x0F, 0x20-0x2F
*
* The AutoNeg value is a bit mask describing which speed and duplex
* combinations should be advertised during auto-negotiation.
@@ -193,20 +192,11 @@ E1000_PARAM(FlowControl, "Flow Control setting");
E1000_PARAM(XsumRX, "Disable or enable Receive Checksum offload");
-/* Transmit Interrupt Delay in units of 1.024 microseconds
- *
- * Valid Range: 0-65535
- *
- * Default Value: 64
- */
-
-E1000_PARAM(TxIntDelay, "Transmit Interrupt Delay");
-
/* Receive Interrupt Delay in units of 1.024 microseconds
*
* Valid Range: 0-65535
*
- * Default Value: 64
+ * Default Value: 64/128
*/
E1000_PARAM(RxIntDelay, "Receive Interrupt Delay");
@@ -252,13 +242,10 @@ E1000_PARAM(DisablePolarityCorrection,
#define MIN_RXD 80
#define MAX_82544_RXD 4096
-#define DEFAULT_TIDV 64
-#define MAX_TIDV 0xFFFF
-#define MIN_TIDV 0
-
-#define DEFAULT_RIDV 64
-#define MAX_RIDV 0xFFFF
-#define MIN_RIDV 0
+#define DEFAULT_RDTR 64
+#define DEFAULT_RADV 128
+#define MAX_RXDELAY 0xFFFF
+#define MIN_RXDELAY 0
#define DEFAULT_MDIX 0
#define MAX_MDIX 3
@@ -332,8 +319,6 @@ e1000_validate_option(int *value, struct e1000_option *opt)
return -1;
}
-#define LIST_LEN(l) (sizeof(l) / sizeof(l[0]))
-
static void e1000_check_fiber_options(struct e1000_adapter *adapter);
static void e1000_check_copper_options(struct e1000_adapter *adapter);
@@ -367,7 +352,7 @@ e1000_check_options(struct e1000_adapter *adapter)
arg: { r: { min: MIN_TXD }}
};
struct e1000_desc_ring *tx_ring = &adapter->tx_ring;
- e1000_mac_type mac_type = adapter->shared.mac_type;
+ e1000_mac_type mac_type = adapter->hw.mac_type;
opt.arg.r.max = mac_type < e1000_82544 ? MAX_TXD : MAX_82544_TXD;
tx_ring->count = TxDescriptors[bd];
@@ -383,7 +368,7 @@ e1000_check_options(struct e1000_adapter *adapter)
arg: { r: { min: MIN_RXD }}
};
struct e1000_desc_ring *rx_ring = &adapter->rx_ring;
- e1000_mac_type mac_type = adapter->shared.mac_type;
+ e1000_mac_type mac_type = adapter->hw.mac_type;
opt.arg.r.max = mac_type < e1000_82544 ? MAX_RXD : MAX_82544_RXD;
rx_ring->count = RxDescriptors[bd];
@@ -416,39 +401,30 @@ e1000_check_options(struct e1000_adapter *adapter)
name: "Flow Control",
err: "reading default settings from EEPROM",
def: e1000_fc_default,
- arg: { l: { nr: LIST_LEN(fc_list), p: fc_list }}
+ arg: { l: { nr: ARRAY_SIZE(fc_list), p: fc_list }}
};
int fc = FlowControl[bd];
e1000_validate_option(&fc, &opt);
- adapter->shared.fc = adapter->shared.original_fc = fc;
- }
- { /* Transmit Interrupt Delay */
- struct e1000_option opt = {
- type: range_option,
- name: "Transmit Interrupt Delay",
- err: "using default of " __MODULE_STRING(DEFAULT_TIDV),
- def: DEFAULT_TIDV,
- arg: { r: { min: MIN_TIDV, max: MAX_TIDV }}
- };
-
- adapter->tx_int_delay = TxIntDelay[bd];
- e1000_validate_option(&adapter->tx_int_delay, &opt);
+ adapter->hw.fc = adapter->hw.original_fc = fc;
}
{ /* Receive Interrupt Delay */
+ char *rdtr = "using default of " __MODULE_STRING(DEFAULT_RDTR);
+ char *radv = "using default of " __MODULE_STRING(DEFAULT_RADV);
struct e1000_option opt = {
type: range_option,
name: "Receive Interrupt Delay",
- err: "using default of " __MODULE_STRING(DEFAULT_RIDV),
- def: DEFAULT_RIDV,
- arg: { r: { min: MIN_RIDV, max: MAX_RIDV }}
+ arg: { r: { min: MIN_RXDELAY, max: MAX_RXDELAY }}
};
+ e1000_mac_type mac_type = adapter->hw.mac_type;
+ opt.def = mac_type < e1000_82540 ? DEFAULT_RDTR : DEFAULT_RADV;
+ opt.err = mac_type < e1000_82540 ? rdtr : radv;
adapter->rx_int_delay = RxIntDelay[bd];
e1000_validate_option(&adapter->rx_int_delay, &opt);
}
- switch(adapter->shared.media_type) {
+ switch(adapter->hw.media_type) {
case e1000_media_type_fiber:
e1000_check_fiber_options(adapter);
break;
@@ -511,7 +487,7 @@ e1000_check_copper_options(struct e1000_adapter *adapter)
name: "Speed",
err: "parameter ignored",
def: 0,
- arg: { l: { nr: LIST_LEN(speed_list), p: speed_list }}
+ arg: { l: { nr: ARRAY_SIZE(speed_list), p: speed_list }}
};
speed = Speed[bd];
@@ -526,7 +502,7 @@ e1000_check_copper_options(struct e1000_adapter *adapter)
name: "Duplex",
err: "parameter ignored",
def: 0,
- arg: { l: { nr: LIST_LEN(dplx_list), p: dplx_list }}
+ arg: { l: { nr: ARRAY_SIZE(dplx_list), p: dplx_list }}
};
dplx = Duplex[bd];
@@ -537,10 +513,10 @@ e1000_check_copper_options(struct e1000_adapter *adapter)
printk(KERN_INFO
"AutoNeg specified along with Speed or Duplex, "
"parameter ignored\n");
- adapter->shared.autoneg_advertised = AUTONEG_ADV_DEFAULT;
+ adapter->hw.autoneg_advertised = AUTONEG_ADV_DEFAULT;
} else { /* Autoneg */
struct e1000_opt_list an_list[] =
- #define AA "Autoneg advertising "
+ #define AA "AutoNeg advertising "
{{ 0x01, AA "10/HD" },
{ 0x02, AA "10/FD" },
{ 0x03, AA "10/FD, 10/HD" },
@@ -575,20 +551,20 @@ e1000_check_copper_options(struct e1000_adapter *adapter)
struct e1000_option opt = {
type: list_option,
- name: "Autoneg",
+ name: "AutoNeg",
err: "parameter ignored",
def: AUTONEG_ADV_DEFAULT,
- arg: { l: { nr: LIST_LEN(an_list), p: an_list }}
+ arg: { l: { nr: ARRAY_SIZE(an_list), p: an_list }}
};
int an = AutoNeg[bd];
e1000_validate_option(&an, &opt);
- adapter->shared.autoneg_advertised = an;
+ adapter->hw.autoneg_advertised = an;
}
switch (speed + dplx) {
case 0:
- adapter->shared.autoneg = 1;
+ adapter->hw.autoneg = 1;
if(Speed[bd] != OPTION_UNSET || Duplex[bd] != OPTION_UNSET)
printk(KERN_INFO
"Speed and duplex autonegotiation enabled\n");
@@ -596,75 +572,75 @@ e1000_check_copper_options(struct e1000_adapter *adapter)
case HALF_DUPLEX:
printk(KERN_INFO "Half Duplex specified without Speed\n");
printk(KERN_INFO "Using Autonegotiation at Half Duplex only\n");
- adapter->shared.autoneg = 1;
- adapter->shared.autoneg_advertised = ADVERTISE_10_HALF |
- ADVERTISE_100_HALF;
+ adapter->hw.autoneg = 1;
+ adapter->hw.autoneg_advertised = ADVERTISE_10_HALF |
+ ADVERTISE_100_HALF;
break;
case FULL_DUPLEX:
printk(KERN_INFO "Full Duplex specified without Speed\n");
printk(KERN_INFO "Using Autonegotiation at Full Duplex only\n");
- adapter->shared.autoneg = 1;
- adapter->shared.autoneg_advertised = ADVERTISE_10_FULL |
- ADVERTISE_100_FULL |
- ADVERTISE_1000_FULL;
+ adapter->hw.autoneg = 1;
+ adapter->hw.autoneg_advertised = ADVERTISE_10_FULL |
+ ADVERTISE_100_FULL |
+ ADVERTISE_1000_FULL;
break;
case SPEED_10:
printk(KERN_INFO "10 Mbps Speed specified without Duplex\n");
printk(KERN_INFO "Using Autonegotiation at 10 Mbps only\n");
- adapter->shared.autoneg = 1;
- adapter->shared.autoneg_advertised = ADVERTISE_10_HALF |
- ADVERTISE_10_FULL;
+ adapter->hw.autoneg = 1;
+ adapter->hw.autoneg_advertised = ADVERTISE_10_HALF |
+ ADVERTISE_10_FULL;
break;
case SPEED_10 + HALF_DUPLEX:
printk(KERN_INFO "Forcing to 10 Mbps Half Duplex\n");
- adapter->shared.autoneg = 0;
- adapter->shared.forced_speed_duplex = e1000_10_half;
- adapter->shared.autoneg_advertised = 0;
+ adapter->hw.autoneg = 0;
+ adapter->hw.forced_speed_duplex = e1000_10_half;
+ adapter->hw.autoneg_advertised = 0;
break;
case SPEED_10 + FULL_DUPLEX:
printk(KERN_INFO "Forcing to 10 Mbps Full Duplex\n");
- adapter->shared.autoneg = 0;
- adapter->shared.forced_speed_duplex = e1000_10_full;
- adapter->shared.autoneg_advertised = 0;
+ adapter->hw.autoneg = 0;
+ adapter->hw.forced_speed_duplex = e1000_10_full;
+ adapter->hw.autoneg_advertised = 0;
break;
case SPEED_100:
printk(KERN_INFO "100 Mbps Speed specified without Duplex\n");
printk(KERN_INFO "Using Autonegotiation at 100 Mbps only\n");
- adapter->shared.autoneg = 1;
- adapter->shared.autoneg_advertised = ADVERTISE_100_HALF |
- ADVERTISE_100_FULL;
+ adapter->hw.autoneg = 1;
+ adapter->hw.autoneg_advertised = ADVERTISE_100_HALF |
+ ADVERTISE_100_FULL;
break;
case SPEED_100 + HALF_DUPLEX:
printk(KERN_INFO "Forcing to 100 Mbps Half Duplex\n");
- adapter->shared.autoneg = 0;
- adapter->shared.forced_speed_duplex = e1000_100_half;
- adapter->shared.autoneg_advertised = 0;
+ adapter->hw.autoneg = 0;
+ adapter->hw.forced_speed_duplex = e1000_100_half;
+ adapter->hw.autoneg_advertised = 0;
break;
case SPEED_100 + FULL_DUPLEX:
printk(KERN_INFO "Forcing to 100 Mbps Full Duplex\n");
- adapter->shared.autoneg = 0;
- adapter->shared.forced_speed_duplex = e1000_100_full;
- adapter->shared.autoneg_advertised = 0;
+ adapter->hw.autoneg = 0;
+ adapter->hw.forced_speed_duplex = e1000_100_full;
+ adapter->hw.autoneg_advertised = 0;
break;
case SPEED_1000:
printk(KERN_INFO "1000 Mbps Speed specified without Duplex\n");
printk(KERN_INFO
"Using Autonegotiation at 1000 Mbps Full Duplex only\n");
- adapter->shared.autoneg = 1;
- adapter->shared.autoneg_advertised = ADVERTISE_1000_FULL;
+ adapter->hw.autoneg = 1;
+ adapter->hw.autoneg_advertised = ADVERTISE_1000_FULL;
break;
case SPEED_1000 + HALF_DUPLEX:
printk(KERN_INFO "Half Duplex is not supported at 1000 Mbps\n");
printk(KERN_INFO
"Using Autonegotiation at 1000 Mbps Full Duplex only\n");
- adapter->shared.autoneg = 1;
- adapter->shared.autoneg_advertised = ADVERTISE_1000_FULL;
+ adapter->hw.autoneg = 1;
+ adapter->hw.autoneg_advertised = ADVERTISE_1000_FULL;
break;
case SPEED_1000 + FULL_DUPLEX:
printk(KERN_INFO
"Using Autonegotiation at 1000 Mbps Full Duplex only\n");
- adapter->shared.autoneg = 1;
- adapter->shared.autoneg_advertised = ADVERTISE_1000_FULL;
+ adapter->hw.autoneg = 1;
+ adapter->hw.autoneg_advertised = ADVERTISE_1000_FULL;
break;
default:
BUG();
@@ -683,7 +659,7 @@ e1000_check_copper_options(struct e1000_adapter *adapter)
int mdix = MdiX[bd];
e1000_validate_option(&mdix, &opt);
- adapter->shared.mdix = mdix;
+ adapter->hw.mdix = mdix;
}
{ /* Automatic Correction for Reverse Cable Polarity */
/* option is actually to disable polarity correction,
@@ -697,11 +673,11 @@ e1000_check_copper_options(struct e1000_adapter *adapter)
int dpc = DisablePolarityCorrection[bd];
e1000_validate_option(&dpc, &opt);
- adapter->shared.disable_polarity_correction = dpc;
+ adapter->hw.disable_polarity_correction = dpc;
}
/* Speed, AutoNeg and MDI/MDI-X must all play nice */
- if (!e1000_validate_mdi_setting(&(adapter->shared))) {
+ if (e1000_validate_mdi_setting(&(adapter->hw)) < 0) {
printk(KERN_INFO "Speed, AutoNeg and MDI-X specifications are "
"incompatible. Setting MDI-X to a compatible value.\n");
}
diff --git a/drivers/net/e1000/e1000_phy.c b/drivers/net/e1000/e1000_phy.c
deleted file mode 100644
index a1e61ccfa84a2..0000000000000
--- a/drivers/net/e1000/e1000_phy.c
+++ /dev/null
@@ -1,1485 +0,0 @@
-/*******************************************************************************
-
- This software program is available to you under a choice of one of two
- licenses. You may choose to be licensed under either the GNU General Public
- License (GPL) Version 2, June 1991, available at
- http://www.fsf.org/copyleft/gpl.html, or the Intel BSD + Patent License, the
- text of which follows:
-
- Recipient has requested a license and Intel Corporation ("Intel") is willing
- to grant a license for the software entitled Linux Base Driver for the
- Intel(R) PRO/1000 Family of Adapters (e1000) (the "Software") being provided
- by Intel Corporation. The following definitions apply to this license:
-
- "Licensed Patents" means patent claims licensable by Intel Corporation which
- are necessarily infringed by the use of sale of the Software alone or when
- combined with the operating system referred to below.
-
- "Recipient" means the party to whom Intel delivers this Software.
-
- "Licensee" means Recipient and those third parties that receive a license to
- any operating system available under the GNU Public License version 2.0 or
- later.
-
- Copyright (c) 1999 - 2002 Intel Corporation.
- All rights reserved.
-
- The license is provided to Recipient and Recipient's Licensees under the
- following terms.
-
- Redistribution and use in source and binary forms of the Software, with or
- without modification, are permitted provided that the following conditions
- are met:
-
- Redistributions of source code of the Software may retain the above
- copyright notice, this list of conditions and the following disclaimer.
-
- Redistributions in binary form of the Software may reproduce the above
- copyright notice, this list of conditions and the following disclaimer in
- the documentation and/or materials provided with the distribution.
-
- Neither the name of Intel Corporation nor the names of its contributors
- shall be used to endorse or promote products derived from this Software
- without specific prior written permission.
-
- Intel hereby grants Recipient and Licensees a non-exclusive, worldwide,
- royalty-free patent license under Licensed Patents to make, use, sell, offer
- to sell, import and otherwise transfer the Software, if any, in source code
- and object code form. This license shall include changes to the Software
- that are error corrections or other minor changes to the Software that do
- not add functionality or features when the Software is incorporated in any
- version of an operating system that has been distributed under the GNU
- General Public License 2.0 or later. This patent license shall apply to the
- combination of the Software and any operating system licensed under the GNU
- Public License version 2.0 or later if, at the time Intel provides the
- Software to Recipient, such addition of the Software to the then publicly
- available versions of such operating systems available under the GNU Public
- License version 2.0 or later (whether in gold, beta or alpha form) causes
- such combination to be covered by the Licensed Patents. The patent license
- shall not apply to any other combinations which include the Software. NO
- hardware per se is licensed hereunder.
-
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- IMPLIED WARRANTIES OF MECHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR IT CONTRIBUTORS BE LIABLE FOR ANY
- DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- (INCLUDING, BUT NOT LIMITED, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- ANY LOSS OF USE; DATA, OR PROFITS; OR BUSINESS INTERUPTION) HOWEVER CAUSED
- AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY OR
- TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*******************************************************************************/
-
-/* e1000_phy.c
- * Shared functions for accessing and configuring the PHY
- */
-
-#include "e1000_mac.h"
-#include "e1000_phy.h"
-
-/******************************************************************************
-* Raises the Management Data Clock
-*
-* shared - Struct containing variables accessed by shared code
-* ctrl_reg - Device control register's current value
-******************************************************************************/
-static void
-e1000_raise_mdc(struct e1000_shared_adapter *shared,
- uint32_t *ctrl_reg)
-{
- /* Raise the clock input to the Management Data Clock (by setting
- * the MDC bit), and then delay 2 microseconds.
- */
- E1000_WRITE_REG(shared, CTRL, (*ctrl_reg | E1000_CTRL_MDC));
- usec_delay(2);
- return;
-}
-
-/******************************************************************************
-* Lowers the Management Data Clock
-*
-* shared - Struct containing variables accessed by shared code
-* ctrl_reg - Device control register's current value
-******************************************************************************/
-static void
-e1000_lower_mdc(struct e1000_shared_adapter *shared,
- uint32_t *ctrl_reg)
-{
- /* Lower the clock input to the Management Data Clock (by clearing
- * the MDC bit), and then delay 2 microseconds.
- */
- E1000_WRITE_REG(shared, CTRL, (*ctrl_reg & ~E1000_CTRL_MDC));
- usec_delay(2);
- return;
-}
-
-/******************************************************************************
-* Shifts data bits out to the PHY
-*
-* shared - Struct containing variables accessed by shared code
-* data - Data to send out to the PHY
-* count - Number of bits to shift out
-*
-* Bits are shifted out in MSB to LSB order.
-******************************************************************************/
-static void
-e1000_phy_shift_out(struct e1000_shared_adapter *shared,
- uint32_t data,
- uint16_t count)
-{
- uint32_t ctrl_reg;
- uint32_t mask;
-
- ASSERT(count <= 32);
-
- /* We need to shift "count" number of bits out to the PHY. So, the
- * value in the "Data" parameter will be shifted out to the PHY
- * one bit at a time. In order to do this, "Data" must be broken
- * down into bits, which is what the "while" logic does below.
- */
- mask = 0x01;
- mask <<= (count - 1);
-
- ctrl_reg = E1000_READ_REG(shared, CTRL);
-
- /* Set MDIO_DIR (SWDPIO1) and MDC_DIR (SWDPIO2) direction bits to
- * be used as output pins.
- */
- ctrl_reg |= (E1000_CTRL_MDIO_DIR | E1000_CTRL_MDC_DIR);
-
- while(mask) {
- /* A "1" is shifted out to the PHY by setting the MDIO bit to
- * "1" and then raising and lowering the Management Data Clock
- * (MDC). A "0" is shifted out to the PHY by setting the MDIO
- * bit to "0" and then raising and lowering the clock.
- */
- if(data & mask)
- ctrl_reg |= E1000_CTRL_MDIO;
- else
- ctrl_reg &= ~E1000_CTRL_MDIO;
-
- E1000_WRITE_REG(shared, CTRL, ctrl_reg);
-
- usec_delay(2);
-
- e1000_raise_mdc(shared, &ctrl_reg);
- e1000_lower_mdc(shared, &ctrl_reg);
-
- mask = mask >> 1;
- }
-
- /* Clear the data bit just before leaving this routine. */
- ctrl_reg &= ~E1000_CTRL_MDIO;
- return;
-}
-
-/******************************************************************************
-* Shifts data bits in from the PHY
-*
-* shared - Struct containing variables accessed by shared code
-*
-* Bits are shifted in in MSB to LSB order.
-******************************************************************************/
-static uint16_t
-e1000_phy_shift_in(struct e1000_shared_adapter *shared)
-{
- uint32_t ctrl_reg;
- uint16_t data = 0;
- uint8_t i;
-
- /* In order to read a register from the PHY, we need to shift in a
- * total of 18 bits from the PHY. The first two bit (TurnAround)
- * times are used to avoid contention on the MDIO pin when a read
- * operation is performed. These two bits are ignored by us and
- * thrown away. Bits are "shifted in" by raising the clock input
- * to the Management Data Clock (setting the MDC bit), and then
- * reading the value of the MDIO bit.
- */
- ctrl_reg = E1000_READ_REG(shared, CTRL);
-
- /* Clear MDIO_DIR (SWDPIO1) to indicate this bit is to be used as
- * input.
- */
- ctrl_reg &= ~E1000_CTRL_MDIO_DIR;
- ctrl_reg &= ~E1000_CTRL_MDIO;
-
- E1000_WRITE_REG(shared, CTRL, ctrl_reg);
-
- /* Raise and Lower the clock before reading in the data. This
- * accounts for the TurnAround bits. The first clock occurred
- * when we clocked out the last bit of the Register Address.
- */
- e1000_raise_mdc(shared, &ctrl_reg);
- e1000_lower_mdc(shared, &ctrl_reg);
-
- for(data = 0, i = 0; i < 16; i++) {
- data = data << 1;
- e1000_raise_mdc(shared, &ctrl_reg);
-
- ctrl_reg = E1000_READ_REG(shared, CTRL);
-
- /* Check to see if we shifted in a "1". */
- if(ctrl_reg & E1000_CTRL_MDIO)
- data |= 1;
-
- e1000_lower_mdc(shared, &ctrl_reg);
- }
-
- e1000_raise_mdc(shared, &ctrl_reg);
- e1000_lower_mdc(shared, &ctrl_reg);
-
- /* Clear the MDIO bit just before leaving this routine. */
- ctrl_reg &= ~E1000_CTRL_MDIO;
-
- return (data);
-}
-
-/******************************************************************************
-* Force PHY speed and duplex settings to shared->forced_speed_duplex
-*
-* shared - Struct containing variables accessed by shared code
-******************************************************************************/
-static void
-e1000_phy_force_speed_duplex(struct e1000_shared_adapter *shared)
-{
- uint32_t tctl_reg;
- uint32_t ctrl_reg;
- uint32_t shift;
- uint16_t mii_ctrl_reg;
- uint16_t mii_status_reg;
- uint16_t phy_data;
- uint16_t i;
-
- DEBUGFUNC("e1000_phy_force_speed_duplex");
-
- /* Turn off Flow control if we are forcing speed and duplex. */
- shared->fc = e1000_fc_none;
-
- DEBUGOUT1("shared->fc = %d\n", shared->fc);
-
- /* Read the Device Control Register. */
- ctrl_reg = E1000_READ_REG(shared, CTRL);
-
- /* Set the bits to Force Speed and Duplex in the Device Ctrl Reg. */
- ctrl_reg |= (E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
- ctrl_reg &= ~(DEVICE_SPEED_MASK);
-
- /* Clear the Auto Speed Detect Enable bit. */
- ctrl_reg &= ~E1000_CTRL_ASDE;
-
- /* Read the MII Control Register. */
- mii_ctrl_reg = e1000_read_phy_reg(shared, PHY_CTRL);
-
- /* We need to disable autoneg in order to force link and duplex. */
-
- mii_ctrl_reg &= ~MII_CR_AUTO_NEG_EN;
-
- /* Are we forcing Full or Half Duplex? */
- if(shared->forced_speed_duplex == e1000_100_full ||
- shared->forced_speed_duplex == e1000_10_full) {
-
- /* We want to force full duplex so we SET the full duplex bits
- * in the Device and MII Control Registers.
- */
- ctrl_reg |= E1000_CTRL_FD;
- mii_ctrl_reg |= MII_CR_FULL_DUPLEX;
-
- DEBUGOUT("Full Duplex\n");
- } else {
-
- /* We want to force half duplex so we CLEAR the full duplex
- * bits in the Device and MII Control Registers.
- */
- ctrl_reg &= ~E1000_CTRL_FD;
- mii_ctrl_reg &= ~MII_CR_FULL_DUPLEX; /* Do this implies HALF */
-
- DEBUGOUT("Half Duplex\n");
- }
-
- /* Are we forcing 100Mbps??? */
- if(shared->forced_speed_duplex == e1000_100_full ||
- shared->forced_speed_duplex == e1000_100_half) {
-
- /* Set the 100Mb bit and turn off the 1000Mb and 10Mb bits. */
- ctrl_reg |= E1000_CTRL_SPD_100;
- mii_ctrl_reg |= MII_CR_SPEED_100;
- mii_ctrl_reg &= ~(MII_CR_SPEED_1000 | MII_CR_SPEED_10);
-
- DEBUGOUT("Forcing 100mb ");
- } else { /* Force 10MB Full or Half */
-
- /* Set the 10Mb bit and turn off the 1000Mb and 100Mb bits. */
- ctrl_reg &= ~(E1000_CTRL_SPD_1000 | E1000_CTRL_SPD_100);
- mii_ctrl_reg |= MII_CR_SPEED_10;
- mii_ctrl_reg &= ~(MII_CR_SPEED_1000 | MII_CR_SPEED_100);
-
- DEBUGOUT("Forcing 10mb ");
- }
-
- /* Now we need to configure the Collision Distance. We need to read
- * the Transmit Control Register to do this.
- * Note: This must be done for both Half or Full Duplex.
- */
- tctl_reg = E1000_READ_REG(shared, TCTL);
- DEBUGOUT1("tctl_reg = %x\n", tctl_reg);
-
- if(!(mii_ctrl_reg & MII_CR_FULL_DUPLEX)) {
-
- /* We are in Half Duplex mode so we need to set up our collision
- * distance for 10/100.
- */
- tctl_reg &= ~E1000_TCTL_COLD;
- shift = E1000_HDX_COLLISION_DISTANCE;
- shift <<= E1000_COLD_SHIFT;
- tctl_reg |= shift;
- } else {
- /* We are in Full Duplex mode. We have the same collision
- * distance regardless of speed.
- */
- tctl_reg &= ~E1000_TCTL_COLD;
- shift = E1000_FDX_COLLISION_DISTANCE;
- shift <<= E1000_COLD_SHIFT;
- tctl_reg |= shift;
- }
-
- /* Write the configured values back to the Transmit Control Reg. */
- E1000_WRITE_REG(shared, TCTL, tctl_reg);
-
- /* Write the configured values back to the Device Control Reg. */
- E1000_WRITE_REG(shared, CTRL, ctrl_reg);
-
- /* Write the MII Control Register with the new PHY configuration. */
- phy_data = e1000_read_phy_reg(shared, M88E1000_PHY_SPEC_CTRL);
-
- /* Clear Auto-Crossover to force MDI manually.
- * M88E1000 requires MDI forced whenever speed/duplex is forced
- */
- phy_data &= ~M88E1000_PSCR_AUTO_X_MODE;
-
- e1000_write_phy_reg(shared, M88E1000_PHY_SPEC_CTRL, phy_data);
-
- DEBUGOUT1("M88E1000 PSCR: %x \n", phy_data);
-
- /* Need to reset the PHY or these bits will get ignored. */
- mii_ctrl_reg |= MII_CR_RESET;
-
- e1000_write_phy_reg(shared, PHY_CTRL, mii_ctrl_reg);
-
- /* The wait_autoneg_complete flag may be a little misleading here.
- * Since we are forcing speed and duplex, Auto-Neg is not enabled.
- * But we do want to delay for a period while forcing only so we
- * don't generate false No Link messages. So we will wait here
- * only if the user has set wait_autoneg_complete to 1, which is
- * the default.
- */
- if(shared->wait_autoneg_complete) {
- /* We will wait for autoneg to complete. */
- DEBUGOUT("Waiting for forced speed/duplex link.\n");
- mii_status_reg = 0;
-
- /* We will wait for autoneg to complete or 4.5 seconds to expire. */
- for(i = PHY_FORCE_TIME; i > 0; i--) {
- /* Read the MII Status Register and wait for Auto-Neg
- * Complete bit to be set.
- */
- mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS);
- mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS);
-
- if(mii_status_reg & MII_SR_LINK_STATUS)
- break;
-
- msec_delay(100);
- } /* end for loop */
-
- if(i == 0) { /* We didn't get link */
-
- /* Reset the DSP and wait again for link. */
- e1000_phy_reset_dsp(shared);
- }
-
- /* This loop will early-out if the link condition has been met. */
- for(i = PHY_FORCE_TIME; i > 0; i--) {
- if(mii_status_reg & MII_SR_LINK_STATUS)
- break;
-
- msec_delay(100);
- /* Read the MII Status Register and wait for Auto-Neg
- * Complete bit to be set.
- */
- mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS);
- mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS);
-
- } /* end for loop */
- } /* end if wait_autoneg_complete */
- /*
- * Because we reset the PHY above, we need to re-force TX_CLK in the
- * Extended PHY Specific Control Register to 25MHz clock. This
- * value defaults back to a 2.5MHz clock when the PHY is reset.
- */
- phy_data = e1000_read_phy_reg(shared, M88E1000_EXT_PHY_SPEC_CTRL);
-
- phy_data |= M88E1000_EPSCR_TX_CLK_25;
-
- e1000_write_phy_reg(shared, M88E1000_EXT_PHY_SPEC_CTRL, phy_data);
-
- /* In addition, because of the s/w reset above, we need to enable
- * CRS on TX. This must be set for both full and half duplex
- * operation.
- */
- phy_data = e1000_read_phy_reg(shared, M88E1000_PHY_SPEC_CTRL);
-
- phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX;
-
- e1000_write_phy_reg(shared, M88E1000_PHY_SPEC_CTRL, phy_data);
- DEBUGOUT1("M88E1000 Phy Specific Ctrl Reg = %4x\r\n", phy_data);
-
- return;
-}
-
-/*****************************************************************************
-* Reads the value from a PHY register
-*
-* shared - Struct containing variables accessed by shared code
-* reg_addr - address of the PHY register to read
-******************************************************************************/
-uint16_t
-e1000_read_phy_reg(struct e1000_shared_adapter *shared,
- uint32_t reg_addr)
-{
- uint32_t i;
- uint32_t data = 0;
- uint32_t command = 0;
-
- ASSERT(reg_addr <= MAX_PHY_REG_ADDRESS);
-
- if(shared->mac_type > e1000_82543) {
- /* Set up Op-code, Phy Address, and
- * register address in the MDI Control register. The MAC will
- * take care of interfacing with the PHY to retrieve the
- * desired data.
- */
- command = ((reg_addr << E1000_MDIC_REG_SHIFT) |
- (shared->phy_addr << E1000_MDIC_PHY_SHIFT) |
- (E1000_MDIC_OP_READ));
-
- E1000_WRITE_REG(shared, MDIC, command);
-
- /* Check every 10 usec to see if the read completed. The read
- * may take as long as 64 usecs (we'll wait 100 usecs max)
- * from the CPU Write to the Ready bit assertion.
- */
- for(i = 0; i < 64; i++) {
- usec_delay(10);
-
- data = E1000_READ_REG(shared, MDIC);
-
- if(data & E1000_MDIC_READY)
- break;
- }
- } else {
- /* We must first send a preamble through the MDIO pin to signal the
- * beginning of an MII instruction. This is done by sending 32
- * consecutive "1" bits.
- */
- e1000_phy_shift_out(shared, PHY_PREAMBLE, PHY_PREAMBLE_SIZE);
-
- /* Now combine the next few fields that are required for a read
- * operation. We use this method instead of calling the
- * e1000_phy_shift_out routine five different times. The format of
- * a MII read instruction consists of a shift out of 14 bits and is
- * defined as follows:
- * <Preamble><SOF><Op Code><Phy Addr><Reg Addr>
- * followed by a shift in of 18 bits. This first two bits shifted
- * in are TurnAround bits used to avoid contention on the MDIO pin
- * when a READ operation is performed. These two bits are thrown
- * away followed by a shift in of 16 bits which contains the
- * desired data.
- */
- command = ((reg_addr) |
- (shared->phy_addr << 5) |
- (PHY_OP_READ << 10) | (PHY_SOF << 12));
-
- e1000_phy_shift_out(shared, command, 14);
-
- /* Now that we've shifted out the read command to the MII, we need
- * to "shift in" the 16-bit value (18 total bits) of the requested
- * PHY register address.
- */
- data = (uint32_t) e1000_phy_shift_in(shared);
- }
-
- ASSERT(!(data & E1000_MDIC_ERROR));
-
- return ((uint16_t) data);
-}
-
-/******************************************************************************
-* Writes a value to a PHY register
-*
-* shared - Struct containing variables accessed by shared code
-* reg_addr - address of the PHY register to write
-* data - data to write to the PHY
-******************************************************************************/
-void
-e1000_write_phy_reg(struct e1000_shared_adapter *shared,
- uint32_t reg_addr,
- uint16_t data)
-{
- uint32_t i;
- uint32_t command = 0;
- uint32_t mdic_reg;
-
- ASSERT(reg_addr <= MAX_PHY_REG_ADDRESS);
-
- if(shared->mac_type > e1000_82543) {
- /* Set up Op-code, Phy Address, register
- * address, and data intended for the PHY register in the MDI
- * Control register. The MAC will take care of interfacing
- * with the PHY to send the desired data.
- */
- command = (((uint32_t) data) |
- (reg_addr << E1000_MDIC_REG_SHIFT) |
- (shared->phy_addr << E1000_MDIC_PHY_SHIFT) |
- (E1000_MDIC_OP_WRITE));
-
- E1000_WRITE_REG(shared, MDIC, command);
-
- /* Check every 10 usec to see if the read completed. The read
- * may take as long as 64 usecs (we'll wait 100 usecs max)
- * from the CPU Write to the Ready bit assertion.
- */
- for(i = 0; i < 10; i++) {
- usec_delay(10);
-
- mdic_reg = E1000_READ_REG(shared, MDIC);
-
- if(mdic_reg & E1000_MDIC_READY)
- break;
- }
- } else {
- /* We'll need to use the SW defined pins to shift the write command
- * out to the PHY. We first send a preamble to the PHY to signal the
- * beginning of the MII instruction. This is done by sending 32
- * consecutive "1" bits.
- */
- e1000_phy_shift_out(shared, PHY_PREAMBLE, PHY_PREAMBLE_SIZE);
-
- /* Now combine the remaining required fields that will indicate
- * a write operation. We use this method instead of calling the
- * e1000_phy_shift_out routine for each field in the command. The
- * format of a MII write instruction is as follows:
- * <Preamble><SOF><Op Code><Phy Addr><Reg Addr><Turnaround><Data>.
- */
- command = ((PHY_TURNAROUND) |
- (reg_addr << 2) |
- (shared->phy_addr << 7) |
- (PHY_OP_WRITE << 12) | (PHY_SOF << 14));
- command <<= 16;
- command |= ((uint32_t) data);
-
- e1000_phy_shift_out(shared, command, 32);
- }
- return;
-}
-
-/******************************************************************************
-* Returns the PHY to the power-on reset state
-*
-* shared - Struct containing variables accessed by shared code
-******************************************************************************/
-void
-e1000_phy_hw_reset(struct e1000_shared_adapter *shared)
-{
- uint32_t ctrl_reg;
- uint32_t ctrl_ext_reg;
-
- DEBUGFUNC("e1000_phy_hw_reset");
-
- DEBUGOUT("Resetting Phy...\n");
-
- if(shared->mac_type > e1000_82543) {
- /* Read the device control register and assert the
- * E1000_CTRL_PHY_RST bit. Hold for 20ms and then take it out
- * of reset.
- */
- ctrl_reg = E1000_READ_REG(shared, CTRL);
-
- ctrl_reg |= E1000_CTRL_PHY_RST;
-
- E1000_WRITE_REG(shared, CTRL, ctrl_reg);
-
- msec_delay(20);
-
- ctrl_reg &= ~E1000_CTRL_PHY_RST;
-
- E1000_WRITE_REG(shared, CTRL, ctrl_reg);
-
- msec_delay(20);
- } else {
- /* Read the Extended Device Control Register, assert the
- * PHY_RESET_DIR bit. Then clock it out to the PHY.
- */
- ctrl_ext_reg = E1000_READ_REG(shared, CTRL_EXT);
-
- ctrl_ext_reg |= E1000_CTRL_PHY_RESET_DIR4;
-
- E1000_WRITE_REG(shared, CTRL_EXT, ctrl_ext_reg);
-
- msec_delay(20);
-
- /* Set the reset bit in the device control register and clock
- * it out to the PHY.
- */
- ctrl_ext_reg = E1000_READ_REG(shared, CTRL_EXT);
-
- ctrl_ext_reg &= ~E1000_CTRL_PHY_RESET4;
-
- E1000_WRITE_REG(shared, CTRL_EXT, ctrl_ext_reg);
-
- msec_delay(20);
-
- ctrl_ext_reg = E1000_READ_REG(shared, CTRL_EXT);
-
- ctrl_ext_reg |= E1000_CTRL_PHY_RESET4;
-
- E1000_WRITE_REG(shared, CTRL_EXT, ctrl_ext_reg);
-
- msec_delay(20);
- }
- return;
-}
-
-/******************************************************************************
-* Resets the PHY
-*
-* shared - Struct containing variables accessed by shared code
-*
-* Sets bit 15 of the MII Control regiser
-******************************************************************************/
-boolean_t
-e1000_phy_reset(struct e1000_shared_adapter *shared)
-{
- uint16_t reg_data;
- uint16_t i;
-
- DEBUGFUNC("e1000_phy_reset");
-
- /* Read the MII control register, set the reset bit and write the
- * value back by clocking it out to the PHY.
- */
- reg_data = e1000_read_phy_reg(shared, PHY_CTRL);
-
- reg_data |= MII_CR_RESET;
-
- e1000_write_phy_reg(shared, PHY_CTRL, reg_data);
-
- /* Wait for bit 15 of the MII Control Register to be cleared
- * indicating the PHY has been reset.
- */
- i = 0;
- while((reg_data & MII_CR_RESET) && i++ < 500) {
- reg_data = e1000_read_phy_reg(shared, PHY_CTRL);
- usec_delay(1);
- }
-
- if(i >= 500) {
- DEBUGOUT("Timeout waiting for PHY to reset.\n");
- return FALSE;
- }
- return TRUE;
-}
-
-/******************************************************************************
-* Detects which PHY is present and the speed and duplex
-*
-* shared - Struct containing variables accessed by shared code
-* ctrl_reg - current value of the device control register
-******************************************************************************/
-boolean_t
-e1000_phy_setup(struct e1000_shared_adapter *shared,
- uint32_t ctrl_reg)
-{
- uint16_t mii_ctrl_reg;
- uint16_t mii_status_reg;
- uint16_t phy_specific_ctrl_reg;
- uint16_t mii_autoneg_adv_reg;
- uint16_t mii_1000t_ctrl_reg;
- uint16_t i;
- uint16_t data;
- uint16_t autoneg_hw_setting;
- uint16_t autoneg_fc_setting;
- boolean_t restart_autoneg = FALSE;
- boolean_t force_autoneg_restart = FALSE;
-
- DEBUGFUNC("e1000_phy_setup");
-
- /* We want to enable the Auto-Speed Detection bit in the Device
- * Control Register. When set to 1, the MAC automatically detects
- * the resolved speed of the link and self-configures appropriately.
- * The Set Link Up bit must also be set for this behavior work
- * properly.
- */
- /* Nothing but 82543 and newer */
- ASSERT(shared->mac_type >= e1000_82543);
-
- /* With 82543, we need to force speed/duplex
- * on the MAC equal to what the PHY speed/duplex configuration is.
- * In addition, on 82543, we need to perform a hardware reset
- * on the PHY to take it out of reset.
- */
- if(shared->mac_type >= e1000_82544) {
- ctrl_reg |= E1000_CTRL_SLU;
- E1000_WRITE_REG(shared, CTRL, ctrl_reg);
- } else {
- ctrl_reg |= (E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX | E1000_CTRL_SLU);
- E1000_WRITE_REG(shared, CTRL, ctrl_reg);
-
- if(shared->mac_type == e1000_82543)
- e1000_phy_hw_reset(shared);
- }
-
- if(!e1000_detect_gig_phy(shared)) {
- /* No PHY detected, return FALSE */
- DEBUGOUT("PhySetup failure, did not detect valid phy.\n");
- return (FALSE);
- }
-
- DEBUGOUT1("Phy ID = %x \n", shared->phy_id);
-
- /* Read the MII Control Register. */
- mii_ctrl_reg = e1000_read_phy_reg(shared, PHY_CTRL);
-
- DEBUGOUT1("MII Ctrl Reg contents = %x\n", mii_ctrl_reg);
-
- /* Check to see if the Auto Neg Enable bit is set in the MII Control
- * Register. If not, we could be in a situation where a driver was
- * loaded previously and was forcing speed and duplex. Then the
- * driver was unloaded but a e1000_phy_hw_reset was not performed, so
- * link was still being forced and link was still achieved. Then
- * the driver was reloaded with the intention to auto-negotiate, but
- * since link is already established we end up not restarting
- * auto-neg. So if the auto-neg bit is not enabled and the driver
- * is being loaded with the desire to auto-neg, we set this flag to
- * to ensure the restart of the auto-neg engine later in the logic.
- */
- if(!(mii_ctrl_reg & MII_CR_AUTO_NEG_EN))
- force_autoneg_restart = TRUE;
-
- /* Clear the isolate bit for normal operation and write it back to
- * the MII Control Reg. Although the spec says this doesn't need
- * to be done when the PHY address is not equal to zero, we do it
- * anyway just to be safe.
- */
- mii_ctrl_reg &= ~(MII_CR_ISOLATE);
-
- e1000_write_phy_reg(shared, PHY_CTRL, mii_ctrl_reg);
-
- data = e1000_read_phy_reg(shared, M88E1000_PHY_SPEC_CTRL);
-
- /* Enable CRS on TX. This must be set for half-duplex operation. */
- data |= M88E1000_PSCR_ASSERT_CRS_ON_TX;
-
- DEBUGOUT1("M88E1000 PSCR: %x \n", data);
-
- e1000_write_phy_reg(shared, M88E1000_PHY_SPEC_CTRL, data);
-
- data = e1000_read_phy_reg(shared, M88E1000_EXT_PHY_SPEC_CTRL);
-
- /* Force TX_CLK in the Extended PHY Specific Control Register
- * to 25MHz clock.
- */
- data |= M88E1000_EPSCR_TX_CLK_25;
-
- e1000_write_phy_reg(shared, M88E1000_EXT_PHY_SPEC_CTRL, data);
-
- /* Certain PHYs will set the default of MII register 4 differently.
- * We need to check this against our fc value. If it is
- * different, we need to setup up register 4 correctly and restart
- * autonegotiation.
- */
- /* Read the MII Auto-Neg Advertisement Register (Address 4). */
- mii_autoneg_adv_reg = e1000_read_phy_reg(shared, PHY_AUTONEG_ADV);
-
- /* Shift right to put 10T-Half bit in bit 0
- * Isolate the four bits for 100/10 Full/Half.
- */
- autoneg_hw_setting = (mii_autoneg_adv_reg >> 5) & 0xF;
-
- /* Get the 1000T settings. */
- mii_1000t_ctrl_reg = e1000_read_phy_reg(shared, PHY_1000T_CTRL);
-
- /* Isolate and OR in the 1000T settings. */
- autoneg_hw_setting |= ((mii_1000t_ctrl_reg & 0x0300) >> 4);
-
- /* mask all bits in the MII Auto-Neg Advertisement Register
- * except for ASM_DIR and PAUSE and shift. This value
- * will be used later to see if we need to restart Auto-Negotiation.
- */
- autoneg_fc_setting = ((mii_autoneg_adv_reg & 0x0C00) >> 10);
-
- /* Perform some bounds checking on the shared->autoneg_advertised
- * parameter. If this variable is zero, then set it to the default.
- */
- shared->autoneg_advertised &= AUTONEG_ADVERTISE_SPEED_DEFAULT;
-
- /* If autoneg_advertised is zero, we assume it was not defaulted
- * by the calling code so we set to advertise full capability.
- */
- if(shared->autoneg_advertised == 0)
- shared->autoneg_advertised = AUTONEG_ADVERTISE_SPEED_DEFAULT;
-
- /* We could be in the situation where Auto-Neg has already completed
- * and the user has not indicated any overrides. In this case we
- * simply need to call e1000_get_speed_and_duplex to obtain the Auto-
- * Negotiated speed and duplex, then return.
- */
- if(!force_autoneg_restart && shared->autoneg &&
- (shared->autoneg_advertised == autoneg_hw_setting) &&
- (shared->fc == autoneg_fc_setting)) {
-
- DEBUGOUT("No overrides - Reading MII Status Reg..\n");
-
- /* Read the MII Status Register. We read this twice because
- * certain bits are "sticky" and need to be read twice.
- */
- mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS);
- mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS);
-
- DEBUGOUT1("MII Status Reg contents = %x\n", mii_status_reg);
-
- /* Do we have link now? (if so, auto-neg has completed) */
- if(mii_status_reg & MII_SR_LINK_STATUS) {
- data = e1000_read_phy_reg(shared, M88E1000_PHY_SPEC_STATUS);
- DEBUGOUT1("M88E1000 Phy Specific Status Reg contents = %x\n", data);
-
- /* We have link, so we need to finish the config process:
- * 1) Set up the MAC to the current PHY speed/duplex
- * if we are on 82543. If we
- * are on newer silicon, we only need to configure
- * collision distance in the Transmit Control Register.
- * 2) Set up flow control on the MAC to that established
- * with the link partner.
- */
- if(shared->mac_type >= e1000_82544)
- e1000_config_collision_dist(shared);
- else
- e1000_config_mac_to_phy(shared, data);
-
- e1000_config_fc_after_link_up(shared);
-
- return (TRUE);
- }
- }
-
- /* Options:
- * MDI/MDI-X = 0 (default)
- * 0 - Auto for all speeds
- * 1 - MDI mode
- * 2 - MDI-X mode
- * 3 - Auto for 1000Base-T only (MDI-X for 10/100Base-T modes)
- */
- phy_specific_ctrl_reg = e1000_read_phy_reg(shared, M88E1000_PHY_SPEC_CTRL);
-
- phy_specific_ctrl_reg &= ~M88E1000_PSCR_AUTO_X_MODE;
-
- switch (shared->mdix) {
- case 1:
- phy_specific_ctrl_reg |= M88E1000_PSCR_MDI_MANUAL_MODE;
- break;
- case 2:
- phy_specific_ctrl_reg |= M88E1000_PSCR_MDIX_MANUAL_MODE;
- break;
- case 3:
- phy_specific_ctrl_reg |= M88E1000_PSCR_AUTO_X_1000T;
- break;
- case 0:
- default:
- phy_specific_ctrl_reg |= M88E1000_PSCR_AUTO_X_MODE;
- break;
- }
-
- e1000_write_phy_reg(shared, M88E1000_PHY_SPEC_CTRL, phy_specific_ctrl_reg);
-
- /* Options:
- * disable_polarity_correction = 0 (default)
- * Automatic Correction for Reversed Cable Polarity
- * 0 - Disabled
- * 1 - Enabled
- */
- phy_specific_ctrl_reg = e1000_read_phy_reg(shared, M88E1000_PHY_SPEC_CTRL);
-
- phy_specific_ctrl_reg &= ~M88E1000_PSCR_POLARITY_REVERSAL;
-
- if(shared->disable_polarity_correction == 1)
- phy_specific_ctrl_reg |= M88E1000_PSCR_POLARITY_REVERSAL;
-
- e1000_write_phy_reg(shared, M88E1000_PHY_SPEC_CTRL, phy_specific_ctrl_reg);
-
- /* Options:
- * autoneg = 1 (default)
- * PHY will advertise value(s) parsed from
- * autoneg_advertised and fc
- * autoneg = 0
- * PHY will be set to 10H, 10F, 100H, or 100F
- * depending on value parsed from forced_speed_duplex.
- */
-
- /* Is autoneg enabled? This is enabled by default or by software override.
- * If so, call e1000_phy_setup_autoneg routine to parse the
- * autoneg_advertised and fc options. If autoneg is NOT enabled, then the
- * user should have provided a speed/duplex override. If so, then call
- * e1000_phy_force_speed_duplex to parse and set this up. Otherwise,
- * we are in an error situation and need to bail.
- */
- if(shared->autoneg) {
- DEBUGOUT("Reconfiguring auto-neg advertisement params\n");
- restart_autoneg = e1000_phy_setup_autoneg(shared);
- } else {
- DEBUGOUT("Forcing speed and duplex\n");
- e1000_phy_force_speed_duplex(shared);
- }
-
- /* Based on information parsed above, check the flag to indicate
- * whether we need to restart Auto-Neg.
- */
- if(restart_autoneg) {
- DEBUGOUT("Restarting Auto-Neg\n");
-
- /* Read the MII Control Register. */
- mii_ctrl_reg = e1000_read_phy_reg(shared, PHY_CTRL);
-
- /* Restart auto-negotiation by setting the Auto Neg Enable bit and
- * the Auto Neg Restart bit.
- */
- mii_ctrl_reg |= (MII_CR_AUTO_NEG_EN | MII_CR_RESTART_AUTO_NEG);
-
- e1000_write_phy_reg(shared, PHY_CTRL, mii_ctrl_reg);
-
- /* Does the user want to wait for Auto-Neg to complete here, or
- * check at a later time (for example, callback routine).
- */
- if(shared->wait_autoneg_complete)
- e1000_wait_autoneg(shared);
- } /* end if restart_autoneg */
-
- /* Read the MII Status Register. */
- mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS);
- mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS);
-
- DEBUGOUT1("Checking for link status - MII Status Reg contents = %x\n",
- mii_status_reg);
-
- /* Check link status. Wait up to 100 microseconds for link to
- * become valid.
- */
- for(i = 0; i < 10; i++) {
- if(mii_status_reg & MII_SR_LINK_STATUS)
- break;
- usec_delay(10);
- DEBUGOUT(". ");
-
- mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS);
- mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS);
- }
-
- if(mii_status_reg & MII_SR_LINK_STATUS) {
- /* Yes, so configure MAC to PHY settings as well as flow control
- * registers.
- */
- data = e1000_read_phy_reg(shared, M88E1000_PHY_SPEC_STATUS);
-
- DEBUGOUT1("M88E1000 Phy Specific Status Reg contents = %x\n", data);
-
- /* We have link, so we need to finish the config process:
- * 1) Set up the MAC to the current PHY speed/duplex
- * if we are on 82543. If we
- * are on newer silicon, we only need to configure
- * collision distance in the Transmit Control Register.
- * 2) Set up flow control on the MAC to that established with
- * the link partner.
- */
- if(shared->mac_type >= e1000_82544)
- e1000_config_collision_dist(shared);
- else
- e1000_config_mac_to_phy(shared, data);
-
- e1000_config_fc_after_link_up(shared);
-
- DEBUGOUT("Valid link established!!!\n");
- } else {
- DEBUGOUT("Unable to establish link!!!\n");
- }
-
- return (TRUE);
-}
-
-/******************************************************************************
-* Configures PHY autoneg and flow control advertisement settings
-*
-* shared - Struct containing variables accessed by shared code
-******************************************************************************/
-boolean_t
-e1000_phy_setup_autoneg(struct e1000_shared_adapter *shared)
-{
- uint16_t mii_autoneg_adv_reg;
- uint16_t mii_1000t_ctrl_reg;
-
- DEBUGFUNC("e1000_phy_setup_autoneg");
-
- /* Read the MII Auto-Neg Advertisement Register (Address 4). */
- mii_autoneg_adv_reg = e1000_read_phy_reg(shared, PHY_AUTONEG_ADV);
-
- /* Read the MII 1000Base-T Control Register (Address 9). */
- mii_1000t_ctrl_reg = e1000_read_phy_reg(shared, PHY_1000T_CTRL);
-
- /* Need to parse both autoneg_advertised and fc and set up
- * the appropriate PHY registers. First we will parse for
- * autoneg_advertised software override. Since we can advertise
- * a plethora of combinations, we need to check each bit
- * individually.
- */
-
- /* First we clear all the 10/100 mb speed bits in the Auto-Neg
- * Advertisement Register (Address 4) and the 1000 mb speed bits in
- * the 1000Base-T Control Register (Address 9).
- */
- mii_autoneg_adv_reg &= ~REG4_SPEED_MASK;
- mii_1000t_ctrl_reg &= ~REG9_SPEED_MASK;
-
- DEBUGOUT1("autoneg_advertised %x\n", shared->autoneg_advertised);
-
- /* Do we want to advertise 10 Mb Half Duplex? */
- if(shared->autoneg_advertised & ADVERTISE_10_HALF) {
- DEBUGOUT("Advertise 10mb Half duplex\n");
- mii_autoneg_adv_reg |= NWAY_AR_10T_HD_CAPS;
- }
-
- /* Do we want to advertise 10 Mb Full Duplex? */
- if(shared->autoneg_advertised & ADVERTISE_10_FULL) {
- DEBUGOUT("Advertise 10mb Full duplex\n");
- mii_autoneg_adv_reg |= NWAY_AR_10T_FD_CAPS;
- }
-
- /* Do we want to advertise 100 Mb Half Duplex? */
- if(shared->autoneg_advertised & ADVERTISE_100_HALF) {
- DEBUGOUT("Advertise 100mb Half duplex\n");
- mii_autoneg_adv_reg |= NWAY_AR_100TX_HD_CAPS;
- }
-
- /* Do we want to advertise 100 Mb Full Duplex? */
- if(shared->autoneg_advertised & ADVERTISE_100_FULL) {
- DEBUGOUT("Advertise 100mb Full duplex\n");
- mii_autoneg_adv_reg |= NWAY_AR_100TX_FD_CAPS;
- }
-
- /* We do not allow the Phy to advertise 1000 Mb Half Duplex */
- if(shared->autoneg_advertised & ADVERTISE_1000_HALF) {
- DEBUGOUT("Advertise 1000mb Half duplex requested, request denied!\n");
- }
-
- /* Do we want to advertise 1000 Mb Full Duplex? */
- if(shared->autoneg_advertised & ADVERTISE_1000_FULL) {
- DEBUGOUT("Advertise 1000mb Full duplex\n");
- mii_1000t_ctrl_reg |= CR_1000T_FD_CAPS;
- }
-
- /* Check for a software override of the flow control settings, and
- * setup the PHY advertisement registers accordingly. If
- * auto-negotiation is enabled, then software will have to set the
- * "PAUSE" bits to the correct value in the Auto-Negotiation
- * Advertisement Register (PHY_AUTONEG_ADV) and re-start auto-negotiation.
- *
- * The possible values of the "fc" parameter are:
- * 0: Flow control is completely disabled
- * 1: Rx flow control is enabled (we can receive pause frames
- * but not send pause frames).
- * 2: Tx flow control is enabled (we can send pause frames
- * but we do not support receiving pause frames).
- * 3: Both Rx and TX flow control (symmetric) are enabled.
- * other: No software override. The flow control configuration
- * in the EEPROM is used.
- */
- switch (shared->fc) {
- case e1000_fc_none: /* 0 */
- /* Flow control (RX & TX) is completely disabled by a
- * software over-ride.
- */
- mii_autoneg_adv_reg &= ~(NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
- break;
- case e1000_fc_rx_pause: /* 1 */
- /* RX Flow control is enabled, and TX Flow control is
- * disabled, by a software over-ride.
- */
-
- /* Since there really isn't a way to advertise that we are
- * capable of RX Pause ONLY, we will advertise that we
- * support both symmetric and asymmetric RX PAUSE. Later
- * (in e1000_config_fc_after_link_up) we will disable the
- *shared's ability to send PAUSE frames.
- */
- mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
- break;
- case e1000_fc_tx_pause: /* 2 */
- /* TX Flow control is enabled, and RX Flow control is
- * disabled, by a software over-ride.
- */
- mii_autoneg_adv_reg |= NWAY_AR_ASM_DIR;
- mii_autoneg_adv_reg &= ~NWAY_AR_PAUSE;
- break;
- case e1000_fc_full: /* 3 */
- /* Flow control (both RX and TX) is enabled by a software
- * over-ride.
- */
- mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
- break;
- default:
- /* We should never get here. The value should be 0-3. */
- DEBUGOUT("Flow control param set incorrectly\n");
- ASSERT(0);
- break;
- }
-
- /* Write the MII Auto-Neg Advertisement Register (Address 4). */
- e1000_write_phy_reg(shared, PHY_AUTONEG_ADV, mii_autoneg_adv_reg);
-
- DEBUGOUT1("Auto-Neg Advertising %x\n", mii_autoneg_adv_reg);
-
- /* Write the MII 1000Base-T Control Register (Address 9). */
- e1000_write_phy_reg(shared, PHY_1000T_CTRL, mii_1000t_ctrl_reg);
- return (TRUE);
-}
-
-/******************************************************************************
-* Sets MAC speed and duplex settings to reflect the those in the PHY
-*
-* shared - Struct containing variables accessed by shared code
-* mii_reg - data to write to the MII control register
-*
-* The contents of the PHY register containing the needed information need to
-* be passed in.
-******************************************************************************/
-void
-e1000_config_mac_to_phy(struct e1000_shared_adapter *shared,
- uint16_t mii_reg)
-{
- uint32_t ctrl_reg;
- uint32_t tctl_reg;
- uint32_t shift;
-
- DEBUGFUNC("e1000_config_mac_to_phy");
-
- /* We need to read the Transmit Control register to configure the
- * collision distance.
- * Note: This must be done for both Half or Full Duplex.
- */
- tctl_reg = E1000_READ_REG(shared, TCTL);
- DEBUGOUT1("tctl_reg = %x\n", tctl_reg);
-
- /* Read the Device Control Register and set the bits to Force Speed
- * and Duplex.
- */
- ctrl_reg = E1000_READ_REG(shared, CTRL);
-
- ctrl_reg |= (E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
- ctrl_reg &= ~(DEVICE_SPEED_MASK);
-
- DEBUGOUT1("MII Register Data = %x\r\n", mii_reg);
-
- /* Clear the ILOS bit. */
- ctrl_reg &= ~E1000_CTRL_ILOS;
-
- /* Set up duplex in the Device Control and Transmit Control
- * registers depending on negotiated values.
- */
- if(mii_reg & M88E1000_PSSR_DPLX) {
- ctrl_reg |= E1000_CTRL_FD;
-
- /* We are in Full Duplex mode. We have the same collision
- * distance regardless of speed.
- */
- tctl_reg &= ~E1000_TCTL_COLD;
- shift = E1000_FDX_COLLISION_DISTANCE;
- shift <<= E1000_COLD_SHIFT;
- tctl_reg |= shift;
- } else {
- ctrl_reg &= ~E1000_CTRL_FD;
-
- /* We are in Half Duplex mode. Our Half Duplex collision
- * distance is different for Gigabit than for 10/100 so we will
- * set accordingly.
- */
- if((mii_reg & M88E1000_PSSR_SPEED) == M88E1000_PSSR_1000MBS) {
- /* 1000Mbs HDX */
- tctl_reg &= ~E1000_TCTL_COLD;
- shift = E1000_GB_HDX_COLLISION_DISTANCE;
- shift <<= E1000_COLD_SHIFT;
- tctl_reg |= shift;
- tctl_reg |= E1000_TCTL_PBE; /* Enable Packet Bursting */
- } else {
- /* 10/100Mbs HDX */
- tctl_reg &= ~E1000_TCTL_COLD;
- shift = E1000_HDX_COLLISION_DISTANCE;
- shift <<= E1000_COLD_SHIFT;
- tctl_reg |= shift;
- }
- }
-
- /* Set up speed in the Device Control register depending on
- * negotiated values.
- */
- if((mii_reg & M88E1000_PSSR_SPEED) == M88E1000_PSSR_1000MBS)
- ctrl_reg |= E1000_CTRL_SPD_1000;
- else if((mii_reg & M88E1000_PSSR_SPEED) == M88E1000_PSSR_100MBS)
- ctrl_reg |= E1000_CTRL_SPD_100;
- else
- ctrl_reg &= ~(E1000_CTRL_SPD_1000 | E1000_CTRL_SPD_100);
-
- /* Write the configured values back to the Transmit Control Reg. */
- E1000_WRITE_REG(shared, TCTL, tctl_reg);
-
- /* Write the configured values back to the Device Control Reg. */
- E1000_WRITE_REG(shared, CTRL, ctrl_reg);
-
- return;
-}
-
-/******************************************************************************
-* Sets the collision distance in the Transmit Control register
-*
-* shared - Struct containing variables accessed by shared code
-*
-* Link should have been established previously. Reads the speed and duplex
-* information from the Device Status register.
-******************************************************************************/
-void
-e1000_config_collision_dist(struct e1000_shared_adapter *shared)
-{
- uint32_t tctl_reg;
- uint16_t speed;
- uint16_t duplex;
- uint32_t shift;
-
- DEBUGFUNC("e1000_config_collision_dist");
-
- /* Get our current speed and duplex from the Device Status Register. */
- e1000_get_speed_and_duplex(shared, &speed, &duplex);
-
- /* We need to configure the Collision Distance for both Full or
- * Half Duplex.
- */
- tctl_reg = E1000_READ_REG(shared, TCTL);
- DEBUGOUT1("tctl_reg = %x\n", tctl_reg);
-
- /* mask the Collision Distance bits in the Transmit Control Reg. */
- tctl_reg &= ~E1000_TCTL_COLD;
-
- if(duplex == FULL_DUPLEX) {
- /* We are in Full Duplex mode. Therefore, the collision distance
- * is the same regardless of speed.
- */
- shift = E1000_FDX_COLLISION_DISTANCE;
- shift <<= E1000_COLD_SHIFT;
- tctl_reg |= shift;
- } else {
- /* We are in Half Duplex mode. Half Duplex collision distance is
- * different for Gigabit vs. 10/100, so we will set accordingly.
- */
- if(speed == SPEED_1000) { /* 1000Mbs HDX */
- shift = E1000_GB_HDX_COLLISION_DISTANCE;
- shift <<= E1000_COLD_SHIFT;
- tctl_reg |= shift;
- tctl_reg |= E1000_TCTL_PBE; /* Enable Packet Bursting */
- } else { /* 10/100Mbs HDX */
- shift = E1000_HDX_COLLISION_DISTANCE;
- shift <<= E1000_COLD_SHIFT;
- tctl_reg |= shift;
- }
- }
-
- /* Write the configured values back to the Transmit Control Reg. */
- E1000_WRITE_REG(shared, TCTL, tctl_reg);
-
- return;
-}
-
-/******************************************************************************
-* Probes the expected PHY address for known PHY IDs
-*
-* shared - Struct containing variables accessed by shared code
-******************************************************************************/
-boolean_t
-e1000_detect_gig_phy(struct e1000_shared_adapter *shared)
-{
- uint32_t phy_id_high;
- uint16_t phy_id_low;
-
- DEBUGFUNC("e1000_detect_gig_phy");
-
- /* Read the PHY ID Registers to identify which PHY is onboard. */
- shared->phy_addr = 1;
-
- phy_id_high = e1000_read_phy_reg(shared, PHY_ID1);
-
- usec_delay(2);
-
- phy_id_low = e1000_read_phy_reg(shared, PHY_ID2);
-
- shared->phy_id = (phy_id_low | (phy_id_high << 16)) & PHY_REVISION_MASK;
-
- if(shared->phy_id == M88E1000_12_PHY_ID ||
- shared->phy_id == M88E1000_14_PHY_ID ||
- shared->phy_id == M88E1000_I_PHY_ID) {
-
- DEBUGOUT2("phy_id 0x%x detected at address 0x%x\n",
- shared->phy_id, shared->phy_addr);
- return (TRUE);
- } else {
- DEBUGOUT("Could not auto-detect Phy!\n");
- return (FALSE);
- }
-}
-
-/******************************************************************************
-* Resets the PHY's DSP
-*
-* shared - Struct containing variables accessed by shared code
-******************************************************************************/
-void
-e1000_phy_reset_dsp(struct e1000_shared_adapter *shared)
-{
- e1000_write_phy_reg(shared, 29, 0x1d);
- e1000_write_phy_reg(shared, 30, 0xc1);
- e1000_write_phy_reg(shared, 30, 0x00);
- return;
-}
-
-/******************************************************************************
-* Blocks until autoneg completes or times out (~4.5 seconds)
-*
-* shared - Struct containing variables accessed by shared code
-******************************************************************************/
-boolean_t
-e1000_wait_autoneg(struct e1000_shared_adapter *shared)
-{
- uint16_t i;
- uint16_t mii_status_reg;
- boolean_t autoneg_complete = FALSE;
-
- DEBUGFUNC("e1000_wait_autoneg");
-
- /* We will wait for autoneg to complete. */
- DEBUGOUT("Waiting for Auto-Neg to complete.\n");
- mii_status_reg = 0;
-
- /* We will wait for autoneg to complete or 4.5 seconds to expire. */
-
- for(i = PHY_AUTO_NEG_TIME; i > 0; i--) {
- /* Read the MII Status Register and wait for Auto-Neg
- * Complete bit to be set.
- */
- mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS);
- mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS);
-
- if(mii_status_reg & MII_SR_AUTONEG_COMPLETE) {
- autoneg_complete = TRUE;
- break;
- }
-
- msec_delay(100);
- }
-
- return (autoneg_complete);
-}
-
-/******************************************************************************
-* Get PHY information from various PHY registers
-*
-* shared - Struct containing variables accessed by shared code
-* phy_status_info - PHY information structure
-******************************************************************************/
-boolean_t
-e1000_phy_get_info(struct e1000_shared_adapter *shared,
- struct e1000_phy_info *phy_status_info)
-{
- uint16_t phy_mii_status_reg;
- uint16_t phy_specific_ctrl_reg;
- uint16_t phy_specific_status_reg;
- uint16_t phy_specific_ext_ctrl_reg;
- uint16_t phy_1000t_stat_reg;
-
- phy_status_info->cable_length = e1000_cable_length_undefined;
- phy_status_info->extended_10bt_distance =
- e1000_10bt_ext_dist_enable_undefined;
- phy_status_info->cable_polarity = e1000_rev_polarity_undefined;
- phy_status_info->polarity_correction = e1000_polarity_reversal_undefined;
- phy_status_info->link_reset = e1000_down_no_idle_undefined;
- phy_status_info->mdix_mode = e1000_auto_x_mode_undefined;
- phy_status_info->local_rx = e1000_1000t_rx_status_undefined;
- phy_status_info->remote_rx = e1000_1000t_rx_status_undefined;
-
- /* PHY info only valid for copper media. */
- if(shared == NULL || shared->media_type != e1000_media_type_copper)
- return FALSE;
-
- /* PHY info only valid for LINK UP. Read MII status reg
- * back-to-back to get link status.
- */
- phy_mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS);
- phy_mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS);
- if((phy_mii_status_reg & MII_SR_LINK_STATUS) != MII_SR_LINK_STATUS)
- return FALSE;
-
- /* Read various PHY registers to get the PHY info. */
- phy_specific_ctrl_reg = e1000_read_phy_reg(shared, M88E1000_PHY_SPEC_CTRL);
- phy_specific_status_reg =
- e1000_read_phy_reg(shared, M88E1000_PHY_SPEC_STATUS);
- phy_specific_ext_ctrl_reg =
- e1000_read_phy_reg(shared, M88E1000_EXT_PHY_SPEC_CTRL);
- phy_1000t_stat_reg = e1000_read_phy_reg(shared, PHY_1000T_STATUS);
-
- phy_status_info->cable_length =
- ((phy_specific_status_reg & M88E1000_PSSR_CABLE_LENGTH) >>
- M88E1000_PSSR_CABLE_LENGTH_SHIFT);
-
- phy_status_info->extended_10bt_distance =
- (phy_specific_ctrl_reg & M88E1000_PSCR_10BT_EXT_DIST_ENABLE) >>
- M88E1000_PSCR_10BT_EXT_DIST_ENABLE_SHIFT;
-
- phy_status_info->cable_polarity =
- (phy_specific_status_reg & M88E1000_PSSR_REV_POLARITY) >>
- M88E1000_PSSR_REV_POLARITY_SHIFT;
-
- phy_status_info->polarity_correction =
- (phy_specific_ctrl_reg & M88E1000_PSCR_POLARITY_REVERSAL) >>
- M88E1000_PSCR_POLARITY_REVERSAL_SHIFT;
-
- phy_status_info->link_reset =
- (phy_specific_ext_ctrl_reg & M88E1000_EPSCR_DOWN_NO_IDLE) >>
- M88E1000_EPSCR_DOWN_NO_IDLE_SHIFT;
-
- phy_status_info->mdix_mode =
- (phy_specific_status_reg & M88E1000_PSSR_MDIX) >>
- M88E1000_PSSR_MDIX_SHIFT;
-
- phy_status_info->local_rx =
- (phy_1000t_stat_reg & SR_1000T_LOCAL_RX_STATUS) >>
- SR_1000T_LOCAL_RX_STATUS_SHIFT;
-
- phy_status_info->remote_rx =
- (phy_1000t_stat_reg & SR_1000T_REMOTE_RX_STATUS) >>
- SR_1000T_REMOTE_RX_STATUS_SHIFT;
-
- return TRUE;
-}
-
-boolean_t
-e1000_validate_mdi_setting(struct e1000_shared_adapter *shared)
-{
- if(!shared->autoneg && (shared->mdix == 0 || shared->mdix == 3)) {
- shared->mdix = 1;
- return FALSE;
- }
- return TRUE;
-}
diff --git a/drivers/net/e1000/e1000_phy.h b/drivers/net/e1000/e1000_phy.h
deleted file mode 100644
index 2232583cec043..0000000000000
--- a/drivers/net/e1000/e1000_phy.h
+++ /dev/null
@@ -1,422 +0,0 @@
-/*******************************************************************************
-
- This software program is available to you under a choice of one of two
- licenses. You may choose to be licensed under either the GNU General Public
- License (GPL) Version 2, June 1991, available at
- http://www.fsf.org/copyleft/gpl.html, or the Intel BSD + Patent License, the
- text of which follows:
-
- Recipient has requested a license and Intel Corporation ("Intel") is willing
- to grant a license for the software entitled Linux Base Driver for the
- Intel(R) PRO/1000 Family of Adapters (e1000) (the "Software") being provided
- by Intel Corporation. The following definitions apply to this license:
-
- "Licensed Patents" means patent claims licensable by Intel Corporation which
- are necessarily infringed by the use of sale of the Software alone or when
- combined with the operating system referred to below.
-
- "Recipient" means the party to whom Intel delivers this Software.
-
- "Licensee" means Recipient and those third parties that receive a license to
- any operating system available under the GNU Public License version 2.0 or
- later.
-
- Copyright (c) 1999 - 2002 Intel Corporation.
- All rights reserved.
-
- The license is provided to Recipient and Recipient's Licensees under the
- following terms.
-
- Redistribution and use in source and binary forms of the Software, with or
- without modification, are permitted provided that the following conditions
- are met:
-
- Redistributions of source code of the Software may retain the above
- copyright notice, this list of conditions and the following disclaimer.
-
- Redistributions in binary form of the Software may reproduce the above
- copyright notice, this list of conditions and the following disclaimer in
- the documentation and/or materials provided with the distribution.
-
- Neither the name of Intel Corporation nor the names of its contributors
- shall be used to endorse or promote products derived from this Software
- without specific prior written permission.
-
- Intel hereby grants Recipient and Licensees a non-exclusive, worldwide,
- royalty-free patent license under Licensed Patents to make, use, sell, offer
- to sell, import and otherwise transfer the Software, if any, in source code
- and object code form. This license shall include changes to the Software
- that are error corrections or other minor changes to the Software that do
- not add functionality or features when the Software is incorporated in any
- version of an operating system that has been distributed under the GNU
- General Public License 2.0 or later. This patent license shall apply to the
- combination of the Software and any operating system licensed under the GNU
- Public License version 2.0 or later if, at the time Intel provides the
- Software to Recipient, such addition of the Software to the then publicly
- available versions of such operating systems available under the GNU Public
- License version 2.0 or later (whether in gold, beta or alpha form) causes
- such combination to be covered by the Licensed Patents. The patent license
- shall not apply to any other combinations which include the Software. NO
- hardware per se is licensed hereunder.
-
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- IMPLIED WARRANTIES OF MECHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR IT CONTRIBUTORS BE LIABLE FOR ANY
- DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- (INCLUDING, BUT NOT LIMITED, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- ANY LOSS OF USE; DATA, OR PROFITS; OR BUSINESS INTERUPTION) HOWEVER CAUSED
- AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY OR
- TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*******************************************************************************/
-
-/* e1000_phy.h
- * Structures, enums, and macros for the PHY
- */
-
-#ifndef _E1000_PHY_H_
-#define _E1000_PHY_H_
-
-#include "e1000_osdep.h"
-
-/* PHY status info structure and supporting enums */
-typedef enum {
- e1000_cable_length_50 = 0,
- e1000_cable_length_50_80,
- e1000_cable_length_80_110,
- e1000_cable_length_110_140,
- e1000_cable_length_140,
- e1000_cable_length_undefined = 0xFF
-} e1000_cable_length;
-
-typedef enum {
- e1000_10bt_ext_dist_enable_normal = 0,
- e1000_10bt_ext_dist_enable_lower,
- e1000_10bt_ext_dist_enable_undefined = 0xFF
-} e1000_10bt_ext_dist_enable;
-
-typedef enum {
- e1000_rev_polarity_normal = 0,
- e1000_rev_polarity_reversed,
- e1000_rev_polarity_undefined = 0xFF
-} e1000_rev_polarity;
-
-typedef enum {
- e1000_polarity_reversal_enabled = 0,
- e1000_polarity_reversal_disabled,
- e1000_polarity_reversal_undefined = 0xFF
-} e1000_polarity_reversal;
-
-typedef enum {
- e1000_down_no_idle_no_detect = 0,
- e1000_down_no_idle_detect,
- e1000_down_no_idle_undefined = 0xFF
-} e1000_down_no_idle;
-
-typedef enum {
- e1000_auto_x_mode_manual_mdi = 0,
- e1000_auto_x_mode_manual_mdix,
- e1000_auto_x_mode_auto1,
- e1000_auto_x_mode_auto2,
- e1000_auto_x_mode_undefined = 0xFF
-} e1000_auto_x_mode;
-
-typedef enum {
- e1000_1000t_rx_status_not_ok = 0,
- e1000_1000t_rx_status_ok,
- e1000_1000t_rx_status_undefined = 0xFF
-} e1000_1000t_rx_status;
-
-struct e1000_phy_info {
- e1000_cable_length cable_length;
- e1000_10bt_ext_dist_enable extended_10bt_distance;
- e1000_rev_polarity cable_polarity;
- e1000_polarity_reversal polarity_correction;
- e1000_down_no_idle link_reset;
- e1000_auto_x_mode mdix_mode;
- e1000_1000t_rx_status local_rx;
- e1000_1000t_rx_status remote_rx;
-};
-
-struct e1000_phy_stats {
- uint32_t idle_errors;
- uint32_t receive_errors;
-};
-
-/* Function Prototypes */
-uint16_t e1000_read_phy_reg(struct e1000_shared_adapter *shared, uint32_t reg_addr);
-void e1000_write_phy_reg(struct e1000_shared_adapter *shared, uint32_t reg_addr, uint16_t data);
-void e1000_phy_hw_reset(struct e1000_shared_adapter *shared);
-boolean_t e1000_phy_reset(struct e1000_shared_adapter *shared);
-boolean_t e1000_phy_setup(struct e1000_shared_adapter *shared, uint32_t ctrl_reg);
-boolean_t e1000_phy_setup_autoneg(struct e1000_shared_adapter *shared);
-void e1000_config_mac_to_phy(struct e1000_shared_adapter *shared, uint16_t mii_reg);
-void e1000_config_collision_dist(struct e1000_shared_adapter *shared);
-boolean_t e1000_detect_gig_phy(struct e1000_shared_adapter *shared);
-void e1000_phy_reset_dsp(struct e1000_shared_adapter *shared);
-boolean_t e1000_wait_autoneg(struct e1000_shared_adapter *shared);
-boolean_t e1000_phy_get_info(struct e1000_shared_adapter *shared, struct e1000_phy_info *phy_status_info);
-boolean_t e1000_validate_mdi_setting(struct e1000_shared_adapter *shared);
-
-/* Bit definitions for the Management Data IO (MDIO) and Management Data
- * Clock (MDC) pins in the Device Control Register.
- */
-#define E1000_CTRL_PHY_RESET_DIR E1000_CTRL_SWDPIO0
-#define E1000_CTRL_PHY_RESET E1000_CTRL_SWDPIN0
-#define E1000_CTRL_MDIO_DIR E1000_CTRL_SWDPIO2
-#define E1000_CTRL_MDIO E1000_CTRL_SWDPIN2
-#define E1000_CTRL_MDC_DIR E1000_CTRL_SWDPIO3
-#define E1000_CTRL_MDC E1000_CTRL_SWDPIN3
-#define E1000_CTRL_PHY_RESET_DIR4 E1000_CTRL_EXT_SDP4_DIR
-#define E1000_CTRL_PHY_RESET4 E1000_CTRL_EXT_SDP4_DATA
-
-/* PHY 1000 MII Register/Bit Definitions */
-/* PHY Registers defined by IEEE */
-#define PHY_CTRL 0x00 /* Control Register */
-#define PHY_STATUS 0x01 /* Status Regiser */
-#define PHY_ID1 0x02 /* Phy Id Reg (word 1) */
-#define PHY_ID2 0x03 /* Phy Id Reg (word 2) */
-#define PHY_AUTONEG_ADV 0x04 /* Autoneg Advertisement */
-#define PHY_LP_ABILITY 0x05 /* Link Partner Ability (Base Page) */
-#define PHY_AUTONEG_EXP 0x06 /* Autoneg Expansion Reg */
-#define PHY_NEXT_PAGE_TX 0x07 /* Next Page TX */
-#define PHY_LP_NEXT_PAGE 0x08 /* Link Partner Next Page */
-#define PHY_1000T_CTRL 0x09 /* 1000Base-T Control Reg */
-#define PHY_1000T_STATUS 0x0A /* 1000Base-T Status Reg */
-#define PHY_EXT_STATUS 0x0F /* Extended Status Reg */
-
-/* M88E1000 Specific Registers */
-#define M88E1000_PHY_SPEC_CTRL 0x10 /* PHY Specific Control Register */
-#define M88E1000_PHY_SPEC_STATUS 0x11 /* PHY Specific Status Register */
-#define M88E1000_INT_ENABLE 0x12 /* Interrupt Enable Register */
-#define M88E1000_INT_STATUS 0x13 /* Interrupt Status Register */
-#define M88E1000_EXT_PHY_SPEC_CTRL 0x14 /* Extended PHY Specific Control */
-#define M88E1000_RX_ERR_CNTR 0x15 /* Receive Error Counter */
-
-#define MAX_PHY_REG_ADDRESS 0x1F /* 5 bit address bus (0-0x1F) */
-
-/* PHY Control Register */
-#define MII_CR_SPEED_SELECT_MSB 0x0040 /* bits 6,13: 10=1000, 01=100, 00=10 */
-#define MII_CR_COLL_TEST_ENABLE 0x0080 /* Collision test enable */
-#define MII_CR_FULL_DUPLEX 0x0100 /* FDX =1, half duplex =0 */
-#define MII_CR_RESTART_AUTO_NEG 0x0200 /* Restart auto negotiation */
-#define MII_CR_ISOLATE 0x0400 /* Isolate PHY from MII */
-#define MII_CR_POWER_DOWN 0x0800 /* Power down */
-#define MII_CR_AUTO_NEG_EN 0x1000 /* Auto Neg Enable */
-#define MII_CR_SPEED_SELECT_LSB 0x2000 /* bits 6,13: 10=1000, 01=100, 00=10 */
-#define MII_CR_LOOPBACK 0x4000 /* 0 = normal, 1 = loopback */
-#define MII_CR_RESET 0x8000 /* 0 = normal, 1 = PHY reset */
-
-/* PHY Status Register */
-#define MII_SR_EXTENDED_CAPS 0x0001 /* Extended register capabilities */
-#define MII_SR_JABBER_DETECT 0x0002 /* Jabber Detected */
-#define MII_SR_LINK_STATUS 0x0004 /* Link Status 1 = link */
-#define MII_SR_AUTONEG_CAPS 0x0008 /* Auto Neg Capable */
-#define MII_SR_REMOTE_FAULT 0x0010 /* Remote Fault Detect */
-#define MII_SR_AUTONEG_COMPLETE 0x0020 /* Auto Neg Complete */
-#define MII_SR_PREAMBLE_SUPPRESS 0x0040 /* Preamble may be suppressed */
-#define MII_SR_EXTENDED_STATUS 0x0100 /* Ext. status info in Reg 0x0F */
-#define MII_SR_100T2_HD_CAPS 0x0200 /* 100T2 Half Duplex Capable */
-#define MII_SR_100T2_FD_CAPS 0x0400 /* 100T2 Full Duplex Capable */
-#define MII_SR_10T_HD_CAPS 0x0800 /* 10T Half Duplex Capable */
-#define MII_SR_10T_FD_CAPS 0x1000 /* 10T Full Duplex Capable */
-#define MII_SR_100X_HD_CAPS 0x2000 /* 100X Half Duplex Capable */
-#define MII_SR_100X_FD_CAPS 0x4000 /* 100X Full Duplex Capable */
-#define MII_SR_100T4_CAPS 0x8000 /* 100T4 Capable */
-
-/* Autoneg Advertisement Register */
-#define NWAY_AR_SELECTOR_FIELD 0x0001 /* indicates IEEE 802.3 CSMA/CD */
-#define NWAY_AR_10T_HD_CAPS 0x0020 /* 10T Half Duplex Capable */
-#define NWAY_AR_10T_FD_CAPS 0x0040 /* 10T Full Duplex Capable */
-#define NWAY_AR_100TX_HD_CAPS 0x0080 /* 100TX Half Duplex Capable */
-#define NWAY_AR_100TX_FD_CAPS 0x0100 /* 100TX Full Duplex Capable */
-#define NWAY_AR_100T4_CAPS 0x0200 /* 100T4 Capable */
-#define NWAY_AR_PAUSE 0x0400 /* Pause operation desired */
-#define NWAY_AR_ASM_DIR 0x0800 /* Asymmetric Pause Direction bit */
-#define NWAY_AR_REMOTE_FAULT 0x2000 /* Remote Fault detected */
-#define NWAY_AR_NEXT_PAGE 0x8000 /* Next Page ability supported */
-
-/* Link Partner Ability Register (Base Page) */
-#define NWAY_LPAR_SELECTOR_FIELD 0x0000 /* LP protocol selector field */
-#define NWAY_LPAR_10T_HD_CAPS 0x0020 /* LP is 10T Half Duplex Capable */
-#define NWAY_LPAR_10T_FD_CAPS 0x0040 /* LP is 10T Full Duplex Capable */
-#define NWAY_LPAR_100TX_HD_CAPS 0x0080 /* LP is 100TX Half Duplex Capable */
-#define NWAY_LPAR_100TX_FD_CAPS 0x0100 /* LP is 100TX Full Duplex Capable */
-#define NWAY_LPAR_100T4_CAPS 0x0200 /* LP is 100T4 Capable */
-#define NWAY_LPAR_PAUSE 0x0400 /* LP Pause operation desired */
-#define NWAY_LPAR_ASM_DIR 0x0800 /* LP Asymmetric Pause Direction bit */
-#define NWAY_LPAR_REMOTE_FAULT 0x2000 /* LP has detected Remote Fault */
-#define NWAY_LPAR_ACKNOWLEDGE 0x4000 /* LP has rx'd link code word */
-#define NWAY_LPAR_NEXT_PAGE 0x8000 /* Next Page ability supported */
-
-/* Autoneg Expansion Register */
-#define NWAY_ER_LP_NWAY_CAPS 0x0001 /* LP has Auto Neg Capability */
-#define NWAY_ER_PAGE_RXD 0x0002 /* LP is 10T Half Duplex Capable */
-#define NWAY_ER_NEXT_PAGE_CAPS 0x0004 /* LP is 10T Full Duplex Capable */
-#define NWAY_ER_LP_NEXT_PAGE_CAPS 0x0008 /* LP is 100TX Half Duplex Capable */
-#define NWAY_ER_PAR_DETECT_FAULT 0x0100 /* LP is 100TX Full Duplex Capable */
-
-/* Next Page TX Register */
-#define NPTX_MSG_CODE_FIELD 0x0001 /* NP msg code or unformatted data */
-#define NPTX_TOGGLE 0x0800 /* Toggles between exchanges
- * of different NP
- */
-#define NPTX_ACKNOWLDGE2 0x1000 /* 1 = will comply with msg
- * 0 = cannot comply with msg
- */
-#define NPTX_MSG_PAGE 0x2000 /* formatted(1)/unformatted(0) pg */
-#define NPTX_NEXT_PAGE 0x8000 /* 1 = addition NP will follow
- * 0 = sending last NP
- */
-
-/* Link Partner Next Page Register */
-#define LP_RNPR_MSG_CODE_FIELD 0x0001 /* NP msg code or unformatted data */
-#define LP_RNPR_TOGGLE 0x0800 /* Toggles between exchanges
- * of different NP
- */
-#define LP_RNPR_ACKNOWLDGE2 0x1000 /* 1 = will comply with msg
- * 0 = cannot comply with msg
- */
-#define LP_RNPR_MSG_PAGE 0x2000 /* formatted(1)/unformatted(0) pg */
-#define LP_RNPR_ACKNOWLDGE 0x4000 /* 1 = ACK / 0 = NO ACK */
-#define LP_RNPR_NEXT_PAGE 0x8000 /* 1 = addition NP will follow
- * 0 = sending last NP
- */
-
-/* 1000BASE-T Control Register */
-#define CR_1000T_ASYM_PAUSE 0x0080 /* Advertise asymmetric pause bit */
-#define CR_1000T_HD_CAPS 0x0100 /* Advertise 1000T HD capability */
-#define CR_1000T_FD_CAPS 0x0200 /* Advertise 1000T FD capability */
-#define CR_1000T_REPEATER_DTE 0x0400 /* 1=Repeater/switch device port */
- /* 0=DTE device */
-#define CR_1000T_MS_VALUE 0x0800 /* 1=Configure PHY as Master */
- /* 0=Configure PHY as Slave */
-#define CR_1000T_MS_ENABLE 0x1000 /* 1=Master/Slave manual config value */
- /* 0=Automatic Master/Slave config */
-#define CR_1000T_TEST_MODE_NORMAL 0x0000 /* Normal Operation */
-#define CR_1000T_TEST_MODE_1 0x2000 /* Transmit Waveform test */
-#define CR_1000T_TEST_MODE_2 0x4000 /* Master Transmit Jitter test */
-#define CR_1000T_TEST_MODE_3 0x6000 /* Slave Transmit Jitter test */
-#define CR_1000T_TEST_MODE_4 0x8000 /* Transmitter Distortion test */
-
-/* 1000BASE-T Status Register */
-#define SR_1000T_IDLE_ERROR_CNT 0x00FF /* Num idle errors since last read */
-#define SR_1000T_ASYM_PAUSE_DIR 0x0100 /* LP asymmetric pause direction bit */
-#define SR_1000T_LP_HD_CAPS 0x0400 /* LP is 1000T HD capable */
-#define SR_1000T_LP_FD_CAPS 0x0800 /* LP is 1000T FD capable */
-#define SR_1000T_REMOTE_RX_STATUS 0x1000 /* Remote receiver OK */
-#define SR_1000T_LOCAL_RX_STATUS 0x2000 /* Local receiver OK */
-#define SR_1000T_MS_CONFIG_RES 0x4000 /* 1=Local TX is Master, 0=Slave */
-#define SR_1000T_MS_CONFIG_FAULT 0x8000 /* Master/Slave config fault */
-#define SR_1000T_REMOTE_RX_STATUS_SHIFT 12
-#define SR_1000T_LOCAL_RX_STATUS_SHIFT 13
-
-/* Extended Status Register */
-#define IEEE_ESR_1000T_HD_CAPS 0x1000 /* 1000T HD capable */
-#define IEEE_ESR_1000T_FD_CAPS 0x2000 /* 1000T FD capable */
-#define IEEE_ESR_1000X_HD_CAPS 0x4000 /* 1000X HD capable */
-#define IEEE_ESR_1000X_FD_CAPS 0x8000 /* 1000X FD capable */
-
-#define PHY_TX_POLARITY_MASK 0x0100 /* register 10h bit 8 (polarity bit) */
-#define PHY_TX_NORMAL_POLARITY 0 /* register 10h bit 8 (normal polarity) */
-
-#define AUTO_POLARITY_DISABLE 0x0010 /* register 11h bit 4 */
- /* (0=enable, 1=disable) */
-
-/* M88E1000 PHY Specific Control Register */
-#define M88E1000_PSCR_JABBER_DISABLE 0x0001 /* 1=Jabber Function disabled */
-#define M88E1000_PSCR_POLARITY_REVERSAL 0x0002 /* 1=Polarity Reversal enabled */
-#define M88E1000_PSCR_SQE_TEST 0x0004 /* 1=SQE Test enabled */
-#define M88E1000_PSCR_CLK125_DISABLE 0x0010 /* 1=CLK125 low,
- * 0=CLK125 toggling
- */
-#define M88E1000_PSCR_MDI_MANUAL_MODE 0x0000 /* MDI Crossover Mode bits 6:5 */
- /* Manual MDI configuration */
-#define M88E1000_PSCR_MDIX_MANUAL_MODE 0x0020 /* Manual MDIX configuration */
-#define M88E1000_PSCR_AUTO_X_1000T 0x0040 /* 1000BASE-T: Auto crossover,
- * 100BASE-TX/10BASE-T:
- * MDI Mode
- */
-#define M88E1000_PSCR_AUTO_X_MODE 0x0060 /* Auto crossover enabled
- * all speeds.
- */
-#define M88E1000_PSCR_10BT_EXT_DIST_ENABLE 0x0080
- /* 1=Enable Extended 10BASE-T distance
- * (Lower 10BASE-T RX Threshold)
- * 0=Normal 10BASE-T RX Threshold */
-#define M88E1000_PSCR_MII_5BIT_ENABLE 0x0100
- /* 1=5-Bit interface in 100BASE-TX
- * 0=MII interface in 100BASE-TX */
-#define M88E1000_PSCR_SCRAMBLER_DISABLE 0x0200 /* 1=Scrambler disable */
-#define M88E1000_PSCR_FORCE_LINK_GOOD 0x0400 /* 1=Force link good */
-#define M88E1000_PSCR_ASSERT_CRS_ON_TX 0x0800 /* 1=Assert CRS on Transmit */
-
-#define M88E1000_PSCR_POLARITY_REVERSAL_SHIFT 1
-#define M88E1000_PSCR_AUTO_X_MODE_SHIFT 5
-#define M88E1000_PSCR_10BT_EXT_DIST_ENABLE_SHIFT 7
-
-/* M88E1000 PHY Specific Status Register */
-#define M88E1000_PSSR_JABBER 0x0001 /* 1=Jabber */
-#define M88E1000_PSSR_REV_POLARITY 0x0002 /* 1=Polarity reversed */
-#define M88E1000_PSSR_MDIX 0x0040 /* 1=MDIX; 0=MDI */
-#define M88E1000_PSSR_CABLE_LENGTH 0x0380 /* 0=<50M;1=50-80M;2=80-110M;
- * 3=110-140M;4=>140M */
-#define M88E1000_PSSR_LINK 0x0400 /* 1=Link up, 0=Link down */
-#define M88E1000_PSSR_SPD_DPLX_RESOLVED 0x0800 /* 1=Speed & Duplex resolved */
-#define M88E1000_PSSR_PAGE_RCVD 0x1000 /* 1=Page received */
-#define M88E1000_PSSR_DPLX 0x2000 /* 1=Duplex 0=Half Duplex */
-#define M88E1000_PSSR_SPEED 0xC000 /* Speed, bits 14:15 */
-#define M88E1000_PSSR_10MBS 0x0000 /* 00=10Mbs */
-#define M88E1000_PSSR_100MBS 0x4000 /* 01=100Mbs */
-#define M88E1000_PSSR_1000MBS 0x8000 /* 10=1000Mbs */
-
-#define M88E1000_PSSR_REV_POLARITY_SHIFT 1
-#define M88E1000_PSSR_MDIX_SHIFT 6
-#define M88E1000_PSSR_CABLE_LENGTH_SHIFT 7
-
-/* M88E1000 Extended PHY Specific Control Register */
-#define M88E1000_EPSCR_FIBER_LOOPBACK 0x4000 /* 1=Fiber loopback */
-#define M88E1000_EPSCR_DOWN_NO_IDLE 0x8000 /* 1=Lost lock detect enabled.
- * Will assert lost lock and bring
- * link down if idle not seen
- * within 1ms in 1000BASE-T
- */
-#define M88E1000_EPSCR_TX_CLK_2_5 0x0060 /* 2.5 MHz TX_CLK */
-#define M88E1000_EPSCR_TX_CLK_25 0x0070 /* 25 MHz TX_CLK */
-#define M88E1000_EPSCR_TX_CLK_0 0x0000 /* NO TX_CLK */
-
-#define M88E1000_EPSCR_DOWN_NO_IDLE_SHIFT 15
-
-/* Bit definitions for valid PHY IDs. */
-#define M88E1000_12_PHY_ID 0x01410C50
-#define M88E1000_14_PHY_ID 0x01410C40
-#define M88E1000_I_PHY_ID 0x01410C30
-
-/* Miscellaneous PHY bit definitions. */
-#define PHY_PREAMBLE 0xFFFFFFFF
-#define PHY_SOF 0x01
-#define PHY_OP_READ 0x02
-#define PHY_OP_WRITE 0x01
-#define PHY_TURNAROUND 0x02
-#define PHY_PREAMBLE_SIZE 32
-#define MII_CR_SPEED_1000 0x0040
-#define MII_CR_SPEED_100 0x2000
-#define MII_CR_SPEED_10 0x0000
-#define E1000_PHY_ADDRESS 0x01
-#define PHY_AUTO_NEG_TIME 45 /* 4.5 Seconds */
-#define PHY_FORCE_TIME 20 /* 2.0 Seconds */
-#define PHY_REVISION_MASK 0xFFFFFFF0
-#define DEVICE_SPEED_MASK 0x00000300 /* Device Ctrl Reg Speed Mask */
-#define REG4_SPEED_MASK 0x01E0
-#define REG9_SPEED_MASK 0x0300
-#define ADVERTISE_10_HALF 0x0001
-#define ADVERTISE_10_FULL 0x0002
-#define ADVERTISE_100_HALF 0x0004
-#define ADVERTISE_100_FULL 0x0008
-#define ADVERTISE_1000_HALF 0x0010
-#define ADVERTISE_1000_FULL 0x0020
-#define AUTONEG_ADVERTISE_SPEED_DEFAULT 0x002F /* Everything but 1000-Half */
-
-#endif /* _E1000_PHY_H_ */
diff --git a/drivers/net/e1000/e1000_proc.c b/drivers/net/e1000/e1000_proc.c
index f497f0de1b6af..620638eb47c78 100644
--- a/drivers/net/e1000/e1000_proc.c
+++ b/drivers/net/e1000/e1000_proc.c
@@ -2,9 +2,8 @@
This software program is available to you under a choice of one of two
licenses. You may choose to be licensed under either the GNU General Public
- License (GPL) Version 2, June 1991, available at
- http://www.fsf.org/copyleft/gpl.html, or the Intel BSD + Patent License, the
- text of which follows:
+ License 2.0, June 1991, available at http://www.fsf.org/copyleft/gpl.html,
+ or the Intel BSD + Patent License, the text of which follows:
Recipient has requested a license and Intel Corporation ("Intel") is willing
to grant a license for the software entitled Linux Base Driver for the
@@ -18,7 +17,7 @@
"Recipient" means the party to whom Intel delivers this Software.
"Licensee" means Recipient and those third parties that receive a license to
- any operating system available under the GNU Public License version 2.0 or
+ any operating system available under the GNU General Public License 2.0 or
later.
Copyright (c) 1999 - 2002 Intel Corporation.
@@ -51,10 +50,10 @@
version of an operating system that has been distributed under the GNU
General Public License 2.0 or later. This patent license shall apply to the
combination of the Software and any operating system licensed under the GNU
- Public License version 2.0 or later if, at the time Intel provides the
+ General Public License 2.0 or later if, at the time Intel provides the
Software to Recipient, such addition of the Software to the then publicly
- available versions of such operating systems available under the GNU Public
- License version 2.0 or later (whether in gold, beta or alpha form) causes
+ available versions of such operating systems available under the GNU General
+ Public License 2.0 or later (whether in gold, beta or alpha form) causes
such combination to be covered by the Licensed Patents. The patent license
shall not apply to any other combinations which include the Software. NO
hardware per se is licensed hereunder.
@@ -96,7 +95,9 @@
#include <linux/proc_fs.h>
#define ADAPTERS_PROC_DIR "PRO_LAN_Adapters"
-#define TAG_MAX_LENGTH 36
+#define TAG_MAX_LENGTH 32
+#define LINE_MAX_LENGTH 80
+#define FIELD_MAX_LENGTH LINE_MAX_LENGTH - TAG_MAX_LENGTH - 3
extern char e1000_driver_name[];
extern char e1000_driver_version[];
@@ -110,7 +111,7 @@ extern char e1000_driver_version[];
struct proc_list {
struct list_head list; /* link list */
- char tag[TAG_MAX_LENGTH]; /* attribute name */
+ char tag[TAG_MAX_LENGTH + 1]; /* attribute name */
void *data; /* attribute data */
size_t len; /* sizeof data */
char *(*func)(void *, size_t, char *); /* format data func */
@@ -142,15 +143,20 @@ e1000_proc_info_read(char *page, char **start, off_t off,
struct list_head *proc_list_head = data, *curr;
struct proc_list *elem;
char *p = page;
- char buf[64];
+ char buf[FIELD_MAX_LENGTH + 1];
list_for_each(curr, proc_list_head) {
elem = list_entry(curr, struct proc_list, list);
- if(strlen(elem->tag) == 0)
+ if (p - page + LINE_MAX_LENGTH >= PAGE_SIZE)
+ break;
+
+ if(!strlen(elem->tag))
p += sprintf(p, "\n");
else
- p += sprintf(p, "%-32s %s\n", elem->tag,
+ p += sprintf(p, "%-*.*s %.*s\n",
+ TAG_MAX_LENGTH, TAG_MAX_LENGTH,
+ elem->tag, FIELD_MAX_LENGTH,
elem->func(elem->data, elem->len, buf));
}
@@ -165,7 +171,8 @@ e1000_proc_single_read(char *page, char **start, off_t off,
{
struct proc_list *elem = data;
- sprintf(page, "%s", elem->func(elem->data, elem->len, page));
+ sprintf(page, "%.*s", FIELD_MAX_LENGTH, elem->func(elem->data,
+ elem->len, page));
return e1000_proc_read(page, start, off, count, eof);
}
@@ -179,8 +186,7 @@ e1000_proc_dirs_free(char *name, struct list_head *proc_list_head)
for(intel_proc_dir = proc_net->subdir; intel_proc_dir;
intel_proc_dir = intel_proc_dir->next) {
if((intel_proc_dir->namelen == strlen(ADAPTERS_PROC_DIR)) &&
- (memcmp(intel_proc_dir->name,
- ADAPTERS_PROC_DIR, strlen(ADAPTERS_PROC_DIR)) == 0))
+ !memcmp(intel_proc_dir->name, ADAPTERS_PROC_DIR, strlen(ADAPTERS_PROC_DIR)))
break;
}
@@ -224,8 +230,6 @@ e1000_proc_dirs_free(char *name, struct list_head *proc_list_head)
if(!proc_dir)
remove_proc_entry(ADAPTERS_PROC_DIR, proc_net);
-
- return;
}
@@ -241,7 +245,7 @@ e1000_proc_singles_create(struct proc_dir_entry *parent,
elem = list_entry(curr, struct proc_list, list);
- if(strlen(elem->tag) == 0)
+ if(!strlen(elem->tag))
continue;
if(!(proc_entry =
@@ -256,8 +260,9 @@ e1000_proc_singles_create(struct proc_dir_entry *parent,
return 1;
}
-static int __devinit
-e1000_proc_dirs_create(char *name, struct list_head *proc_list_head)
+static void __devinit
+e1000_proc_dirs_create(void *data, char *name,
+ struct list_head *proc_list_head)
{
struct proc_dir_entry *intel_proc_dir, *proc_dir, *info_entry;
char info_name[strlen(name) + strlen(".info")];
@@ -265,8 +270,7 @@ e1000_proc_dirs_create(char *name, struct list_head *proc_list_head)
for(intel_proc_dir = proc_net->subdir; intel_proc_dir;
intel_proc_dir = intel_proc_dir->next) {
if((intel_proc_dir->namelen == strlen(ADAPTERS_PROC_DIR)) &&
- (memcmp(intel_proc_dir->name,
- ADAPTERS_PROC_DIR, strlen(ADAPTERS_PROC_DIR)) == 0))
+ !memcmp(intel_proc_dir->name, ADAPTERS_PROC_DIR, strlen(ADAPTERS_PROC_DIR)))
break;
}
@@ -274,28 +278,26 @@ e1000_proc_dirs_create(char *name, struct list_head *proc_list_head)
if(!(intel_proc_dir =
create_proc_entry(ADAPTERS_PROC_DIR,
S_IFDIR, proc_net)))
- return 0;
+ return;
if(!(proc_dir =
create_proc_entry(name, S_IFDIR, intel_proc_dir)))
- return 0;
+ return;
SET_MODULE_OWNER(proc_dir);
if(!e1000_proc_singles_create(proc_dir, proc_list_head))
- return 0;
+ return;
strcpy(info_name, name);
strcat(info_name, ".info");
if(!(info_entry =
create_proc_entry(info_name, S_IFREG, intel_proc_dir)))
- return 0;
+ return;
SET_MODULE_OWNER(info_entry);
info_entry->read_proc = e1000_proc_info_read;
info_entry->data = proc_list_head;
-
- return 1;
}
static void __devinit
@@ -315,8 +317,6 @@ e1000_proc_list_add(struct list_head *proc_list_head, char *tag,
new->func = func;
list_add_tail(&new->list, proc_list_head);
-
- return;
}
static void __devexit
@@ -329,8 +329,6 @@ e1000_proc_list_free(struct list_head *proc_list_head)
list_del(&elem->list);
kfree(elem);
}
-
- return;
}
/*
@@ -491,7 +489,7 @@ e1000_proc_media_type(void *data, size_t len, char *buf)
{
struct e1000_adapter *adapter = data;
sprintf(buf,
- adapter->shared.media_type == e1000_media_type_copper ?
+ adapter->hw.media_type == e1000_media_type_copper ?
"Copper" : "Fiber");
return buf;
}
@@ -547,18 +545,6 @@ e1000_proc_polarity_correction(void *data, size_t len, char *buf)
sprintf(buf,
correction == e1000_polarity_reversal_enabled ? "Disabled" :
correction == e1000_polarity_reversal_disabled ? "Enabled" :
- "Undefined");
- return buf;
-}
-
-static char *
-e1000_proc_link_reset_enabled(void *data, size_t len, char *buf)
-{
- struct e1000_adapter *adapter = data;
- e1000_down_no_idle link_reset = adapter->phy_info.link_reset;
- sprintf(buf,
- link_reset == e1000_down_no_idle_no_detect ? "Disabled" :
- link_reset == e1000_down_no_idle_detect ? "Enabled" :
"Unknown");
return buf;
}
@@ -568,7 +554,10 @@ e1000_proc_mdi_x_enabled(void *data, size_t len, char *buf)
{
struct e1000_adapter *adapter = data;
e1000_auto_x_mode mdix_mode = adapter->phy_info.mdix_mode;
- sprintf(buf, mdix_mode == 0 ? "MDI" : "MDI-X");
+ sprintf(buf,
+ mdix_mode == e1000_auto_x_mode_manual_mdi ? "MDI" :
+ mdix_mode == e1000_auto_x_mode_manual_mdix ? "MDI-X" :
+ "Unknown");
return buf;
}
@@ -601,7 +590,7 @@ e1000_proc_rx_status(void *data, size_t len, char *buf)
static void __devinit
e1000_proc_list_setup(struct e1000_adapter *adapter)
{
- struct e1000_shared_adapter *shared = &adapter->shared;
+ struct e1000_hw *hw = &adapter->hw;
struct list_head *proc_list_head = &adapter->proc_list_head;
INIT_LIST_HEAD(proc_list_head);
@@ -610,21 +599,21 @@ e1000_proc_list_setup(struct e1000_adapter *adapter)
LIST_ADD_F("Part_Number", &adapter->part_num, e1000_proc_part_number);
LIST_ADD_S("Driver_Name", e1000_driver_name);
LIST_ADD_S("Driver_Version", e1000_driver_version);
- LIST_ADD_H("PCI_Vendor", &shared->vendor_id);
- LIST_ADD_H("PCI_Device_ID", &shared->device_id);
- LIST_ADD_H("PCI_Subsystem_Vendor", &shared->subsystem_vendor_id);
- LIST_ADD_H("PCI_Subsystem_ID", &shared->subsystem_id);
- LIST_ADD_H("PCI_Revision_ID", &shared->revision_id);
+ LIST_ADD_H("PCI_Vendor", &hw->vendor_id);
+ LIST_ADD_H("PCI_Device_ID", &hw->device_id);
+ LIST_ADD_H("PCI_Subsystem_Vendor", &hw->subsystem_vendor_id);
+ LIST_ADD_H("PCI_Subsystem_ID", &hw->subsystem_id);
+ LIST_ADD_H("PCI_Revision_ID", &hw->revision_id);
LIST_ADD_U("PCI_Bus", &adapter->pdev->bus->number);
LIST_ADD_F("PCI_Slot", adapter, e1000_proc_slot);
- if(adapter->shared.mac_type >= e1000_82543) {
+ if(adapter->hw.mac_type >= e1000_82543) {
LIST_ADD_F("PCI_Bus_Type",
- &shared->bus_type, e1000_proc_bus_type);
+ &hw->bus_type, e1000_proc_bus_type);
LIST_ADD_F("PCI_Bus_Speed",
- &shared->bus_speed, e1000_proc_bus_speed);
+ &hw->bus_speed, e1000_proc_bus_speed);
LIST_ADD_F("PCI_Bus_Width",
- &shared->bus_width, e1000_proc_bus_width);
+ &hw->bus_width, e1000_proc_bus_width);
}
LIST_ADD_U("IRQ", &adapter->pdev->irq);
@@ -632,7 +621,7 @@ e1000_proc_list_setup(struct e1000_adapter *adapter)
LIST_ADD_F("Current_HWaddr",
adapter->netdev->dev_addr, e1000_proc_hwaddr);
LIST_ADD_F("Permanent_HWaddr",
- adapter->shared.perm_mac_addr, e1000_proc_hwaddr);
+ adapter->hw.perm_mac_addr, e1000_proc_hwaddr);
LIST_ADD_BLANK();
@@ -679,7 +668,7 @@ e1000_proc_list_setup(struct e1000_adapter *adapter)
LIST_ADD_U("Rx_Short_Length_Errors", &adapter->stats.ruc);
/* The 82542 does not have an alignment error count register */
- if(adapter->shared.mac_type >= e1000_82543)
+ if(adapter->hw.mac_type >= e1000_82543)
LIST_ADD_U("Rx_Align_Errors", &adapter->stats.algnerrc);
LIST_ADD_U("Rx_Flow_Control_XON", &adapter->stats.xonrxc);
@@ -693,7 +682,7 @@ e1000_proc_list_setup(struct e1000_adapter *adapter)
/* Cable diags */
LIST_ADD_F("PHY_Media_Type", adapter, e1000_proc_media_type);
- if(adapter->shared.media_type == e1000_media_type_copper) {
+ if(adapter->hw.media_type == e1000_media_type_copper) {
LIST_ADD_F("PHY_Cable_Length",
adapter, e1000_proc_cable_length);
LIST_ADD_F("PHY_Extended_10Base_T_Distance",
@@ -704,8 +693,6 @@ e1000_proc_list_setup(struct e1000_adapter *adapter)
adapter, e1000_proc_polarity_correction);
LIST_ADD_U("PHY_Idle_Errors",
&adapter->phy_stats.idle_errors);
- LIST_ADD_F("PHY_Link_Reset_Enabled",
- adapter, e1000_proc_link_reset_enabled);
LIST_ADD_U("PHY_Receive_Errors",
&adapter->phy_stats.receive_errors);
LIST_ADD_F("PHY_MDI_X_Enabled",
@@ -718,7 +705,6 @@ e1000_proc_list_setup(struct e1000_adapter *adapter)
e1000_proc_rx_status);
}
- return;
}
/*
@@ -731,9 +717,9 @@ e1000_proc_dev_setup(struct e1000_adapter *adapter)
{
e1000_proc_list_setup(adapter);
- e1000_proc_dirs_create(adapter->netdev->name,&adapter->proc_list_head);
-
- return;
+ e1000_proc_dirs_create(adapter,
+ adapter->netdev->name,
+ &adapter->proc_list_head);
}
/*
@@ -747,8 +733,6 @@ e1000_proc_dev_free(struct e1000_adapter *adapter)
e1000_proc_dirs_free(adapter->netdev->name, &adapter->proc_list_head);
e1000_proc_list_free(&adapter->proc_list_head);
-
- return;
}
#else /* CONFIG_PROC_FS */
diff --git a/drivers/net/e2100.c b/drivers/net/e2100.c
index bfed15fec8766..31493d863982f 100644
--- a/drivers/net/e2100.c
+++ b/drivers/net/e2100.c
@@ -72,7 +72,7 @@ static int e21_probe_list[] = {0x300, 0x280, 0x380, 0x220, 0};
#define E21_SAPROM 0x10 /* Offset to station address data. */
#define E21_IO_EXTENT 0x20
-extern inline void mem_on(short port, volatile char *mem_base,
+static inline void mem_on(short port, volatile char *mem_base,
unsigned char start_page )
{
/* This is a little weird: set the shared memory window by doing a
@@ -82,7 +82,7 @@ extern inline void mem_on(short port, volatile char *mem_base,
outb(E21_MEM_ON, port + E21_MEM_ENABLE + E21_MEM_ON);
}
-extern inline void mem_off(short port)
+static inline void mem_off(short port)
{
inb(port + E21_MEM_ENABLE);
outb(0x00, port + E21_MEM_ENABLE);
@@ -234,8 +234,8 @@ static int __init e21_probe1(struct net_device *dev, int ioaddr)
#ifdef notdef
/* These values are unused. The E2100 has a 2K window into the packet
buffer. The window can be set to start on any page boundary. */
- dev->rmem_start = dev->mem_start + TX_PAGES*256;
- dev->mem_end = dev->rmem_end = dev->mem_start + 2*1024;
+ ei_status.rmem_start = dev->mem_start + TX_PAGES*256;
+ dev->mem_end = ei_status.rmem_end = dev->mem_start + 2*1024;
#endif
printk(", IRQ %d, %s media, memory @ %#lx.\n", dev->irq,
diff --git a/drivers/net/eepro100.c b/drivers/net/eepro100.c
index bc61bd97f6ded..e455ac71d802b 100644
--- a/drivers/net/eepro100.c
+++ b/drivers/net/eepro100.c
@@ -1795,6 +1795,7 @@ speedo_rx(struct net_device *dev)
}
skb->protocol = eth_type_trans(skb, dev);
netif_rx(skb);
+ dev->last_rx = jiffies;
sp->stats.rx_packets++;
sp->stats.rx_bytes += pkt_len;
}
diff --git a/drivers/net/epic100.c b/drivers/net/epic100.c
index 4f9ad8cf88794..fe20646ddb5e6 100644
--- a/drivers/net/epic100.c
+++ b/drivers/net/epic100.c
@@ -60,11 +60,14 @@
LK1.1.12:
* fix power-up sequence
+ LK1.1.13:
+ * revert version 1.1.12, power-up sequence "fix"
+
*/
#define DRV_NAME "epic100"
-#define DRV_VERSION "1.11+LK1.1.12"
-#define DRV_RELDATE "Jan 18, 2002"
+#define DRV_VERSION "1.11+LK1.1.13"
+#define DRV_RELDATE "Mar 20, 2002"
/* The user-configurable values.
@@ -678,8 +681,9 @@ static int epic_open(struct net_device *dev)
required by the details of which bits are reset and the transceiver
wiring on the Ositech CardBus card.
*/
-
- outl(0x12, ioaddr + MIICfg);
+#if 0
+ outl(dev->if_port == 1 ? 0x13 : 0x12, ioaddr + MIICfg);
+#endif
if (ep->chip_flags & MII_PWRDWN)
outl((inl(ioaddr + NVCTL) & ~0x003C) | 0x4800, ioaddr + NVCTL);
diff --git a/drivers/net/es3210.c b/drivers/net/es3210.c
index 07ac2b091ee79..fa9ddc648790c 100644
--- a/drivers/net/es3210.c
+++ b/drivers/net/es3210.c
@@ -233,9 +233,9 @@ static int __init es_probe1(struct net_device *dev, int ioaddr)
printk(" assigning ");
}
- dev->mem_end = dev->rmem_end = dev->mem_start
+ dev->mem_end = ei_status.rmem_end = dev->mem_start
+ (ES_STOP_PG - ES_START_PG)*256;
- dev->rmem_start = dev->mem_start + TX_PAGES*256;
+ ei_status.rmem_start = dev->mem_start + TX_PAGES*256;
printk("mem %#lx-%#lx\n", dev->mem_start, dev->mem_end-1);
@@ -335,12 +335,12 @@ static void es_block_input(struct net_device *dev, int count, struct sk_buff *sk
{
unsigned long xfer_start = dev->mem_start + ring_offset - (ES_START_PG<<8);
- if (xfer_start + count > dev->rmem_end) {
+ if (xfer_start + count > ei_status.rmem_end) {
/* Packet wraps over end of ring buffer. */
- int semi_count = dev->rmem_end - xfer_start;
+ int semi_count = ei_status.rmem_end - xfer_start;
isa_memcpy_fromio(skb->data, xfer_start, semi_count);
count -= semi_count;
- isa_memcpy_fromio(skb->data + semi_count, dev->rmem_start, count);
+ isa_memcpy_fromio(skb->data + semi_count, ei_status.rmem_start, count);
} else {
/* Packet is in one chunk. */
isa_eth_io_copy_and_sum(skb, xfer_start, count, 0);
diff --git a/drivers/net/hamradio/6pack.c b/drivers/net/hamradio/6pack.c
index beafabd51e36b..26f08dce4b20a 100644
--- a/drivers/net/hamradio/6pack.c
+++ b/drivers/net/hamradio/6pack.c
@@ -256,7 +256,7 @@ static void sp_bump(struct sixpack *sp, char cmd)
skb->mac.raw = skb->data;
skb->protocol = htons(ETH_P_AX25);
netif_rx(skb);
- dev->last_rx = jiffies;
+ sp->dev->last_rx = jiffies;
sp->stats.rx_packets++;
}
@@ -701,7 +701,6 @@ static struct tty_ldisc sp_ldisc = {
/* Initialize 6pack control device -- register 6pack line discipline */
static char msg_banner[] __initdata = KERN_INFO "AX.25: 6pack driver, " SIXPACK_VERSION " (dynamic channels, max=%d)\n";
-static char msg_invparm[] __initdata = KERN_ERR "6pack: sixpack_maxdev parameter too large.\n";
static char msg_nomem[] __initdata = KERN_ERR "6pack: can't allocate sixpack_ctrls[] array! No 6pack available.\n";
static char msg_regfail[] __initdata = KERN_ERR "6pack: can't register line discipline (err = %d)\n";
diff --git a/drivers/net/hamradio/baycom_epp.c b/drivers/net/hamradio/baycom_epp.c
index e20dc463f6abf..30598d8418214 100644
--- a/drivers/net/hamradio/baycom_epp.c
+++ b/drivers/net/hamradio/baycom_epp.c
@@ -302,7 +302,7 @@ static const unsigned short crc_ccitt_table[] = {
/*---------------------------------------------------------------------------*/
#if 0
-extern inline void append_crc_ccitt(unsigned char *buffer, int len)
+static inline void append_crc_ccitt(unsigned char *buffer, int len)
{
unsigned int crc = 0xffff;
@@ -316,7 +316,7 @@ extern inline void append_crc_ccitt(unsigned char *buffer, int len)
/*---------------------------------------------------------------------------*/
-extern inline int check_crc_ccitt(const unsigned char *buf, int cnt)
+static inline int check_crc_ccitt(const unsigned char *buf, int cnt)
{
unsigned int crc = 0xffff;
@@ -327,7 +327,7 @@ extern inline int check_crc_ccitt(const unsigned char *buf, int cnt)
/*---------------------------------------------------------------------------*/
-extern inline int calc_crc_ccitt(const unsigned char *buf, int cnt)
+static inline int calc_crc_ccitt(const unsigned char *buf, int cnt)
{
unsigned int crc = 0xffff;
diff --git a/drivers/net/hamradio/baycom_ser_fdx.c b/drivers/net/hamradio/baycom_ser_fdx.c
index c1c3fc6ca0239..7fd2a1dc4e59a 100644
--- a/drivers/net/hamradio/baycom_ser_fdx.c
+++ b/drivers/net/hamradio/baycom_ser_fdx.c
@@ -201,12 +201,12 @@ static inline void ser12_set_divisor(struct net_device *dev,
/* --------------------------------------------------------------------- */
#if 0
-extern inline unsigned int hweight16(unsigned int w)
+static inline unsigned int hweight16(unsigned int w)
__attribute__ ((unused));
-extern inline unsigned int hweight8(unsigned int w)
+static inline unsigned int hweight8(unsigned int w)
__attribute__ ((unused));
-extern inline unsigned int hweight16(unsigned int w)
+static inline unsigned int hweight16(unsigned int w)
{
unsigned short res = (w & 0x5555) + ((w >> 1) & 0x5555);
res = (res & 0x3333) + ((res >> 2) & 0x3333);
@@ -214,7 +214,7 @@ extern inline unsigned int hweight16(unsigned int w)
return (res & 0x00FF) + ((res >> 8) & 0x00FF);
}
-extern inline unsigned int hweight8(unsigned int w)
+static inline unsigned int hweight8(unsigned int w)
{
unsigned short res = (w & 0x55) + ((w >> 1) & 0x55);
res = (res & 0x33) + ((res >> 2) & 0x33);
diff --git a/drivers/net/hamradio/dmascc.c b/drivers/net/hamradio/dmascc.c
index 2fcf1ff4af27f..9f237af5479b4 100644
--- a/drivers/net/hamradio/dmascc.c
+++ b/drivers/net/hamradio/dmascc.c
@@ -1121,6 +1121,7 @@ static void rx_bh(void *arg) {
skb->protocol = ntohs(ETH_P_AX25);
skb->mac.raw = skb->data;
netif_rx(skb);
+ priv->dev->last_rx = jiffies;
priv->stats.rx_packets++;
priv->stats.rx_bytes += cb;
}
diff --git a/drivers/net/hamradio/mkiss.c b/drivers/net/hamradio/mkiss.c
index d2e593db080f2..4f32863e7da8b 100644
--- a/drivers/net/hamradio/mkiss.c
+++ b/drivers/net/hamradio/mkiss.c
@@ -345,7 +345,7 @@ static void ax_bump(struct ax_disp *ax)
skb->mac.raw = skb->data;
skb->protocol = htons(ETH_P_AX25);
netif_rx(skb);
- dev->last_rx = jiffies;
+ tmp_ax->dev->last_rx = jiffies;
tmp_ax->rx_packets++;
}
diff --git a/drivers/net/hamradio/scc.c b/drivers/net/hamradio/scc.c
index 99c110a6561e8..fe404f3660221 100644
--- a/drivers/net/hamradio/scc.c
+++ b/drivers/net/hamradio/scc.c
@@ -1661,7 +1661,7 @@ static void scc_net_rx(struct scc_channel *scc, struct sk_buff *skb)
skb->pkt_type = PACKET_HOST;
netif_rx(skb);
- dev->last_rx = jiffies;
+ scc->dev->last_rx = jiffies;
return;
}
diff --git a/drivers/net/hamradio/soundmodem/sm.h b/drivers/net/hamradio/soundmodem/sm.h
index 367b045b80861..25c47f948ba7d 100644
--- a/drivers/net/hamradio/soundmodem/sm.h
+++ b/drivers/net/hamradio/soundmodem/sm.h
@@ -158,7 +158,7 @@ extern const char sm_drvinfo[];
* ===================== diagnostics stuff ===============================
*/
-extern inline void diag_trigger(struct sm_state *sm)
+static inline void diag_trigger(struct sm_state *sm)
{
if (sm->diag.ptr < 0)
if (!(sm->diag.flags & SM_DIAGFLAG_DCDGATE) || sm->hdrv.hdlcrx.dcd)
@@ -170,7 +170,7 @@ extern inline void diag_trigger(struct sm_state *sm)
#define SHRT_MAX ((short)(((unsigned short)(~0U))>>1))
#define SHRT_MIN (-SHRT_MAX-1)
-extern inline void diag_add(struct sm_state *sm, int valinp, int valdemod)
+static inline void diag_add(struct sm_state *sm, int valinp, int valdemod)
{
int val;
@@ -189,7 +189,7 @@ extern inline void diag_add(struct sm_state *sm, int valinp, int valdemod)
/* --------------------------------------------------------------------- */
-extern inline void diag_add_one(struct sm_state *sm, int val)
+static inline void diag_add_one(struct sm_state *sm, int val)
{
if ((sm->diag.mode != SM_DIAGMODE_INPUT &&
sm->diag.mode != SM_DIAGMODE_DEMOD) ||
@@ -229,14 +229,14 @@ static inline void diag_add_constellation(struct sm_state *sm, int vali, int val
*/
#if 0
-extern inline unsigned int hweight32(unsigned int w)
+static inline unsigned int hweight32(unsigned int w)
__attribute__ ((unused));
-extern inline unsigned int hweight16(unsigned short w)
+static inline unsigned int hweight16(unsigned short w)
__attribute__ ((unused));
-extern inline unsigned int hweight8(unsigned char w)
+static inline unsigned int hweight8(unsigned char w)
__attribute__ ((unused));
-extern inline unsigned int hweight32(unsigned int w)
+static inline unsigned int hweight32(unsigned int w)
{
unsigned int res = (w & 0x55555555) + ((w >> 1) & 0x55555555);
res = (res & 0x33333333) + ((res >> 2) & 0x33333333);
@@ -245,7 +245,7 @@ extern inline unsigned int hweight32(unsigned int w)
return (res & 0x0000FFFF) + ((res >> 16) & 0x0000FFFF);
}
-extern inline unsigned int hweight16(unsigned short w)
+static inline unsigned int hweight16(unsigned short w)
{
unsigned short res = (w & 0x5555) + ((w >> 1) & 0x5555);
res = (res & 0x3333) + ((res >> 2) & 0x3333);
@@ -253,7 +253,7 @@ extern inline unsigned int hweight16(unsigned short w)
return (res & 0x00FF) + ((res >> 8) & 0x00FF);
}
-extern inline unsigned int hweight8(unsigned char w)
+static inline unsigned int hweight8(unsigned char w)
{
unsigned short res = (w & 0x55) + ((w >> 1) & 0x55);
res = (res & 0x33) + ((res >> 2) & 0x33);
@@ -262,12 +262,12 @@ extern inline unsigned int hweight8(unsigned char w)
#endif
-extern inline unsigned int gcd(unsigned int x, unsigned int y)
+static inline unsigned int gcd(unsigned int x, unsigned int y)
__attribute__ ((unused));
-extern inline unsigned int lcm(unsigned int x, unsigned int y)
+static inline unsigned int lcm(unsigned int x, unsigned int y)
__attribute__ ((unused));
-extern inline unsigned int gcd(unsigned int x, unsigned int y)
+static inline unsigned int gcd(unsigned int x, unsigned int y)
{
for (;;) {
if (!x)
@@ -281,7 +281,7 @@ extern inline unsigned int gcd(unsigned int x, unsigned int y)
}
}
-extern inline unsigned int lcm(unsigned int x, unsigned int y)
+static inline unsigned int lcm(unsigned int x, unsigned int y)
{
return x * y / gcd(x, y);
}
diff --git a/drivers/net/hamradio/soundmodem/sm_afsk1200.c b/drivers/net/hamradio/soundmodem/sm_afsk1200.c
index 64b20a57c5912..1463d7fdd577c 100644
--- a/drivers/net/hamradio/soundmodem/sm_afsk1200.c
+++ b/drivers/net/hamradio/soundmodem/sm_afsk1200.c
@@ -94,7 +94,7 @@ static void modulator_1200_s16(struct sm_state *sm, short *buf, unsigned int buf
/* --------------------------------------------------------------------- */
-extern __inline__ int convolution8_u8(const unsigned char *st, const int *coeff, int csum)
+static __inline__ int convolution8_u8(const unsigned char *st, const int *coeff, int csum)
{
int sum = -0x80 * csum;
@@ -111,7 +111,7 @@ extern __inline__ int convolution8_u8(const unsigned char *st, const int *coeff,
return sum * sum;
}
-extern __inline__ int convolution8_s16(const short *st, const int *coeff, int csum)
+static __inline__ int convolution8_s16(const short *st, const int *coeff, int csum)
{
int sum = 0;
@@ -128,7 +128,7 @@ extern __inline__ int convolution8_s16(const short *st, const int *coeff, int cs
return sum * sum;
}
-extern __inline__ int do_filter_1200_u8(const unsigned char *buf)
+static __inline__ int do_filter_1200_u8(const unsigned char *buf)
{
int sum = convolution8_u8(buf, afsk12_tx_lo_i, SUM_AFSK12_TX_LO_I);
sum += convolution8_u8(buf, afsk12_tx_lo_q, SUM_AFSK12_TX_LO_Q);
@@ -137,7 +137,7 @@ extern __inline__ int do_filter_1200_u8(const unsigned char *buf)
return sum;
}
-extern __inline__ int do_filter_1200_s16(const short *buf)
+static __inline__ int do_filter_1200_s16(const short *buf)
{
int sum = convolution8_s16(buf, afsk12_tx_lo_i, SUM_AFSK12_TX_LO_I);
sum += convolution8_s16(buf, afsk12_tx_lo_q, SUM_AFSK12_TX_LO_Q);
diff --git a/drivers/net/hamradio/soundmodem/sm_afsk2400_7.c b/drivers/net/hamradio/soundmodem/sm_afsk2400_7.c
index d217936abdbd8..5d9f9ee9971a6 100644
--- a/drivers/net/hamradio/soundmodem/sm_afsk2400_7.c
+++ b/drivers/net/hamradio/soundmodem/sm_afsk2400_7.c
@@ -104,7 +104,7 @@ static void modulator_2400_s16(struct sm_state *sm, short *buf, unsigned int buf
/* --------------------------------------------------------------------- */
-extern __inline__ int convolution14_u8(const unsigned char *st, const int *coeff, int csum)
+static __inline__ int convolution14_u8(const unsigned char *st, const int *coeff, int csum)
{
int sum = -0x80 * csum;
@@ -127,7 +127,7 @@ extern __inline__ int convolution14_u8(const unsigned char *st, const int *coeff
return sum * sum;
}
-extern __inline__ int convolution14_s16(const short *st, const int *coeff, int csum)
+static __inline__ int convolution14_s16(const short *st, const int *coeff, int csum)
{
int sum = 0;
@@ -150,7 +150,7 @@ extern __inline__ int convolution14_s16(const short *st, const int *coeff, int c
return sum * sum;
}
-extern __inline__ int do_filter_2400_u8(const unsigned char *buf)
+static __inline__ int do_filter_2400_u8(const unsigned char *buf)
{
int sum = convolution14_u8(buf, afsk24_tx_lo_i, SUM_AFSK24_TX_LO_I);
sum += convolution14_u8(buf, afsk24_tx_lo_q, SUM_AFSK24_TX_LO_Q);
@@ -159,7 +159,7 @@ extern __inline__ int do_filter_2400_u8(const unsigned char *buf)
return sum;
}
-extern __inline__ int do_filter_2400_s16(const short *buf)
+static __inline__ int do_filter_2400_s16(const short *buf)
{
int sum = convolution14_s16(buf, afsk24_tx_lo_i, SUM_AFSK24_TX_LO_I);
sum += convolution14_s16(buf, afsk24_tx_lo_q, SUM_AFSK24_TX_LO_Q);
diff --git a/drivers/net/hamradio/soundmodem/sm_afsk2400_8.c b/drivers/net/hamradio/soundmodem/sm_afsk2400_8.c
index 23d2337464b3f..435afee2ecef7 100644
--- a/drivers/net/hamradio/soundmodem/sm_afsk2400_8.c
+++ b/drivers/net/hamradio/soundmodem/sm_afsk2400_8.c
@@ -104,7 +104,7 @@ static void modulator_2400_s16(struct sm_state *sm, short *buf, unsigned int buf
/* --------------------------------------------------------------------- */
-extern __inline__ int convolution14_u8(const unsigned char *st, const int *coeff, int csum)
+static __inline__ int convolution14_u8(const unsigned char *st, const int *coeff, int csum)
{
int sum = -0x80 * csum;
@@ -127,7 +127,7 @@ extern __inline__ int convolution14_u8(const unsigned char *st, const int *coeff
return sum * sum;
}
-extern __inline__ int convolution14_s16(const short *st, const int *coeff, int csum)
+static __inline__ int convolution14_s16(const short *st, const int *coeff, int csum)
{
int sum = 0;
@@ -150,7 +150,7 @@ extern __inline__ int convolution14_s16(const short *st, const int *coeff, int c
return sum * sum;
}
-extern __inline__ int do_filter_2400_u8(const unsigned char *buf)
+static __inline__ int do_filter_2400_u8(const unsigned char *buf)
{
int sum = convolution14_u8(buf, afsk24_tx_lo_i, SUM_AFSK24_TX_LO_I);
sum += convolution14_u8(buf, afsk24_tx_lo_q, SUM_AFSK24_TX_LO_Q);
@@ -159,7 +159,7 @@ extern __inline__ int do_filter_2400_u8(const unsigned char *buf)
return sum;
}
-extern __inline__ int do_filter_2400_s16(const short *buf)
+static __inline__ int do_filter_2400_s16(const short *buf)
{
int sum = convolution14_s16(buf, afsk24_tx_lo_i, SUM_AFSK24_TX_LO_I);
sum += convolution14_s16(buf, afsk24_tx_lo_q, SUM_AFSK24_TX_LO_Q);
diff --git a/drivers/net/hamradio/soundmodem/sm_afsk2666.c b/drivers/net/hamradio/soundmodem/sm_afsk2666.c
index 2aa2972e47d85..81d1fe27921e1 100644
--- a/drivers/net/hamradio/soundmodem/sm_afsk2666.c
+++ b/drivers/net/hamradio/soundmodem/sm_afsk2666.c
@@ -114,7 +114,7 @@ static void modulator_2666_s16(struct sm_state *sm, short *buf, unsigned int buf
/* --------------------------------------------------------------------- */
-extern __inline__ int convolution12_u8(const unsigned char *st, const int *coeff, int csum)
+static __inline__ int convolution12_u8(const unsigned char *st, const int *coeff, int csum)
{
int sum = -0x80 * csum;
@@ -134,7 +134,7 @@ extern __inline__ int convolution12_u8(const unsigned char *st, const int *coeff
return sum;
}
-extern __inline__ int convolution12_s16(const short *st, const int *coeff, int csum)
+static __inline__ int convolution12_s16(const short *st, const int *coeff, int csum)
{
int sum = 0;
diff --git a/drivers/net/hamradio/soundmodem/sm_sbc.c b/drivers/net/hamradio/soundmodem/sm_sbc.c
index 85ae47588ef4a..a73c74056f51e 100644
--- a/drivers/net/hamradio/soundmodem/sm_sbc.c
+++ b/drivers/net/hamradio/soundmodem/sm_sbc.c
@@ -59,7 +59,7 @@
#define put_user(x,ptr) ({ __put_user((unsigned long)(x),(ptr),sizeof(*(ptr))); 0; })
#define get_user(x,ptr) ({ x = ((__typeof__(*(ptr)))__get_user((ptr),sizeof(*(ptr)))); 0; })
-extern inline int copy_from_user(void *to, const void *from, unsigned long n)
+static inline int copy_from_user(void *to, const void *from, unsigned long n)
{
int i = verify_area(VERIFY_READ, from, n);
if (i)
@@ -68,7 +68,7 @@ extern inline int copy_from_user(void *to, const void *from, unsigned long n)
return 0;
}
-extern inline int copy_to_user(void *to, const void *from, unsigned long n)
+static inline int copy_to_user(void *to, const void *from, unsigned long n)
{
int i = verify_area(VERIFY_WRITE, to, n);
if (i)
diff --git a/drivers/net/hamradio/soundmodem/sm_wss.c b/drivers/net/hamradio/soundmodem/sm_wss.c
index 6d94d6da4a463..2fba58589f8dc 100644
--- a/drivers/net/hamradio/soundmodem/sm_wss.c
+++ b/drivers/net/hamradio/soundmodem/sm_wss.c
@@ -58,7 +58,7 @@
#define put_user(x,ptr) ({ __put_user((unsigned long)(x),(ptr),sizeof(*(ptr))); 0; })
#define get_user(x,ptr) ({ x = ((__typeof__(*(ptr)))__get_user((ptr),sizeof(*(ptr)))); 0; })
-extern inline int copy_from_user(void *to, const void *from, unsigned long n)
+static inline int copy_from_user(void *to, const void *from, unsigned long n)
{
int i = verify_area(VERIFY_READ, from, n);
if (i)
@@ -67,7 +67,7 @@ extern inline int copy_from_user(void *to, const void *from, unsigned long n)
return 0;
}
-extern inline int copy_to_user(void *to, const void *from, unsigned long n)
+static inline int copy_to_user(void *to, const void *from, unsigned long n)
{
int i = verify_area(VERIFY_WRITE, to, n);
if (i)
diff --git a/drivers/net/hamradio/soundmodem/smdma.h b/drivers/net/hamradio/soundmodem/smdma.h
index 44e457a7a1705..9e48713116ae4 100644
--- a/drivers/net/hamradio/soundmodem/smdma.h
+++ b/drivers/net/hamradio/soundmodem/smdma.h
@@ -52,7 +52,7 @@
/*
* returns the number of samples per fragment
*/
-extern __inline__ unsigned int dma_setup(struct sm_state *sm, int send, unsigned int dmanr)
+static __inline__ unsigned int dma_setup(struct sm_state *sm, int send, unsigned int dmanr)
{
if (send) {
disable_dma(dmanr);
@@ -79,7 +79,7 @@ extern __inline__ unsigned int dma_setup(struct sm_state *sm, int send, unsigned
/* --------------------------------------------------------------------- */
-extern __inline__ unsigned int dma_ptr(struct sm_state *sm, int send, unsigned int dmanr,
+static __inline__ unsigned int dma_ptr(struct sm_state *sm, int send, unsigned int dmanr,
unsigned int *curfrag)
{
unsigned int dmaptr, sz, frg, offs;
@@ -120,7 +120,7 @@ extern __inline__ unsigned int dma_ptr(struct sm_state *sm, int send, unsigned i
/* --------------------------------------------------------------------- */
-extern __inline__ int dma_end_transmit(struct sm_state *sm, unsigned int curfrag)
+static __inline__ int dma_end_transmit(struct sm_state *sm, unsigned int curfrag)
{
unsigned int diff = (NUM_FRAGMENTS + curfrag - sm->dma.ofragptr) % NUM_FRAGMENTS;
@@ -137,7 +137,7 @@ extern __inline__ int dma_end_transmit(struct sm_state *sm, unsigned int curfrag
return 0;
}
-extern __inline__ void dma_transmit(struct sm_state *sm)
+static __inline__ void dma_transmit(struct sm_state *sm)
{
void *p;
@@ -155,13 +155,13 @@ extern __inline__ void dma_transmit(struct sm_state *sm)
}
}
-extern __inline__ void dma_init_transmit(struct sm_state *sm)
+static __inline__ void dma_init_transmit(struct sm_state *sm)
{
sm->dma.ofragptr = 0;
sm->dma.ptt_cnt = 0;
}
-extern __inline__ void dma_start_transmit(struct sm_state *sm)
+static __inline__ void dma_start_transmit(struct sm_state *sm)
{
sm->dma.ofragptr = 0;
if (sm->dma.o16bit) {
@@ -174,7 +174,7 @@ extern __inline__ void dma_start_transmit(struct sm_state *sm)
sm->dma.ptt_cnt = 1;
}
-extern __inline__ void dma_clear_transmit(struct sm_state *sm)
+static __inline__ void dma_clear_transmit(struct sm_state *sm)
{
sm->dma.ptt_cnt = 0;
memset(sm->dma.obuf, (sm->dma.o16bit) ? 0 : 0x80, sm->dma.ofragsz * NUM_FRAGMENTS);
@@ -182,7 +182,7 @@ extern __inline__ void dma_clear_transmit(struct sm_state *sm)
/* --------------------------------------------------------------------- */
-extern __inline__ void dma_receive(struct sm_state *sm, unsigned int curfrag)
+static __inline__ void dma_receive(struct sm_state *sm, unsigned int curfrag)
{
void *p;
@@ -205,7 +205,7 @@ extern __inline__ void dma_receive(struct sm_state *sm, unsigned int curfrag)
}
}
-extern __inline__ void dma_init_receive(struct sm_state *sm)
+static __inline__ void dma_init_receive(struct sm_state *sm)
{
sm->dma.ifragptr = 0;
}
diff --git a/drivers/net/hamradio/yam.c b/drivers/net/hamradio/yam.c
index 7e175b3a51381..d74a43f3ce20f 100644
--- a/drivers/net/hamradio/yam.c
+++ b/drivers/net/hamradio/yam.c
@@ -308,7 +308,8 @@ static const unsigned char chktabh[256] =
static void delay(int ms)
{
unsigned long timeout = jiffies + ((ms * HZ) / 1000);
- while (jiffies < timeout);
+ while (time_before(jiffies, timeout))
+ cpu_relax();
}
/*
diff --git a/drivers/net/hp-plus.c b/drivers/net/hp-plus.c
index 330407a318399..0e05ee7803a4a 100644
--- a/drivers/net/hp-plus.c
+++ b/drivers/net/hp-plus.c
@@ -230,8 +230,8 @@ static int __init hpp_probe1(struct net_device *dev, int ioaddr)
ei_status.block_output = &hpp_mem_block_output;
ei_status.get_8390_hdr = &hpp_mem_get_8390_hdr;
dev->mem_start = mem_start;
- dev->rmem_start = dev->mem_start + TX_2X_PAGES*256;
- dev->mem_end = dev->rmem_end
+ ei_status.rmem_start = dev->mem_start + TX_2X_PAGES*256;
+ dev->mem_end = ei_status.rmem_end
= dev->mem_start + (HP_STOP_PG - HP_START_PG)*256;
}
diff --git a/drivers/net/irda/sa1100_ir.c b/drivers/net/irda/sa1100_ir.c
index ba201c9af1c1f..8b341fe6a33bf 100644
--- a/drivers/net/irda/sa1100_ir.c
+++ b/drivers/net/irda/sa1100_ir.c
@@ -597,6 +597,7 @@ static void sa1100_irda_fir_error(struct sa1100_irda *si, struct net_device *dev
sa1100_irda_rx_alloc(si);
netif_rx(skb);
+ dev->last_rx = jiffies;
} else {
/*
* Remap the buffer.
diff --git a/drivers/net/lance.c b/drivers/net/lance.c
index 771ab0c305339..03e504fa4b5b4 100644
--- a/drivers/net/lance.c
+++ b/drivers/net/lance.c
@@ -383,7 +383,7 @@ int __init lance_probe(struct net_device *dev)
return 0;
}
}
- release_resource(r);
+ release_region(ioaddr, LANCE_TOTAL_SIZE);
}
}
return -ENODEV;
diff --git a/drivers/net/lne390.c b/drivers/net/lne390.c
index 0866d905c37b6..c18997bbfcc7b 100644
--- a/drivers/net/lne390.c
+++ b/drivers/net/lne390.c
@@ -247,9 +247,9 @@ static int __init lne390_probe1(struct net_device *dev, int ioaddr)
LNE390_STOP_PG/4, dev->mem_start);
}
- dev->mem_end = dev->rmem_end = dev->mem_start
+ dev->mem_end = ei_status.rmem_end = dev->mem_start
+ (LNE390_STOP_PG - LNE390_START_PG)*256;
- dev->rmem_start = dev->mem_start + TX_PAGES*256;
+ ei_status.rmem_start = dev->mem_start + TX_PAGES*256;
/* The 8390 offset is zero for the LNE390 */
dev->base_addr = ioaddr;
@@ -334,12 +334,12 @@ static void lne390_block_input(struct net_device *dev, int count, struct sk_buff
{
unsigned long xfer_start = dev->mem_start + ring_offset - (LNE390_START_PG<<8);
- if (xfer_start + count > dev->rmem_end) {
+ if (xfer_start + count > ei_status.rmem_end) {
/* Packet wraps over end of ring buffer. */
- int semi_count = dev->rmem_end - xfer_start;
+ int semi_count = ei_status.rmem_end - xfer_start;
isa_memcpy_fromio(skb->data, xfer_start, semi_count);
count -= semi_count;
- isa_memcpy_fromio(skb->data + semi_count, dev->rmem_start, count);
+ isa_memcpy_fromio(skb->data + semi_count, ei_status.rmem_start, count);
} else {
/* Packet is in one chunk. */
isa_memcpy_fromio(skb->data, xfer_start, count);
diff --git a/drivers/net/ne3210.c b/drivers/net/ne3210.c
index 426530bbed93c..818527d9b3e7c 100644
--- a/drivers/net/ne3210.c
+++ b/drivers/net/ne3210.c
@@ -234,9 +234,9 @@ static int __init ne3210_probe1(struct net_device *dev, int ioaddr)
NE3210_STOP_PG/4, dev->mem_start);
}
- dev->mem_end = dev->rmem_end = dev->mem_start
+ dev->mem_end = ei_status.rmem_end = dev->mem_start
+ (NE3210_STOP_PG - NE3210_START_PG)*256;
- dev->rmem_start = dev->mem_start + TX_PAGES*256;
+ ei_status.rmem_start = dev->mem_start + TX_PAGES*256;
/* The 8390 offset is zero for the NE3210 */
dev->base_addr = ioaddr;
@@ -323,12 +323,12 @@ static void ne3210_block_input(struct net_device *dev, int count, struct sk_buff
{
unsigned long xfer_start = dev->mem_start + ring_offset - (NE3210_START_PG<<8);
- if (xfer_start + count > dev->rmem_end) {
+ if (xfer_start + count > ei_status.rmem_end) {
/* Packet wraps over end of ring buffer. */
- int semi_count = dev->rmem_end - xfer_start;
+ int semi_count = ei_status.rmem_end - xfer_start;
isa_memcpy_fromio(skb->data, xfer_start, semi_count);
count -= semi_count;
- isa_memcpy_fromio(skb->data + semi_count, dev->rmem_start, count);
+ isa_memcpy_fromio(skb->data + semi_count, ei_status.rmem_start, count);
} else {
/* Packet is in one chunk. */
isa_memcpy_fromio(skb->data, xfer_start, count);
diff --git a/drivers/net/ns83820.c b/drivers/net/ns83820.c
index d880da73b616b..e3378847e0a86 100644
--- a/drivers/net/ns83820.c
+++ b/drivers/net/ns83820.c
@@ -797,23 +797,6 @@ static void ns83820_cleanup_rx(struct ns83820 *dev)
}
}
-/* I hate the network stack sometimes */
-#ifdef __i386__
-#define skb_mangle_for_davem(skb,len) (skb)
-#else
-static inline struct sk_buff *skb_mangle_for_davem(struct sk_buff *skb, int len)
-{
- tmp = __dev_alloc_skb(len+2, GFP_ATOMIC);
- if (!tmp)
- goto done;
- tmp->dev = &dev->net_dev;
- skb_reserve(tmp, 2);
- memcpy(skb_put(tmp, len), skb->data, len);
- kfree_skb(skb);
- return tmp;
-}
-#endif
-
static void FASTCALL(ns83820_rx_kick(struct ns83820 *dev));
static void ns83820_rx_kick(struct ns83820 *dev)
{
@@ -883,7 +866,6 @@ static void rx_irq(struct ns83820 *dev)
if (likely(CMDSTS_OK & cmdsts)) {
int len = cmdsts & 0xffff;
skb_put(skb, len);
- skb = skb_mangle_for_davem(skb, len);
if (unlikely(!skb))
goto netdev_mangle_me_harder_failed;
if (cmdsts & CMDSTS_DEST_MULTI)
diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c
index ecf6ec9b94a42..66b5455f29c92 100644
--- a/drivers/net/pcnet32.c
+++ b/drivers/net/pcnet32.c
@@ -511,7 +511,6 @@ pcnet32_probe1(unsigned long ioaddr, unsigned int irq_line, int shared,
struct pci_dev *pdev)
{
struct pcnet32_private *lp;
- struct resource *res;
dma_addr_t lp_dma_addr;
int i, media;
int fdx, mii, fset, dxsuflo, ltint;
@@ -689,13 +688,12 @@ pcnet32_probe1(unsigned long ioaddr, unsigned int irq_line, int shared,
}
dev->base_addr = ioaddr;
- res = request_region(ioaddr, PCNET32_TOTAL_SIZE, chipname);
- if (!res)
+ if (request_region(ioaddr, PCNET32_TOTAL_SIZE, chipname) == NULL)
return -EBUSY;
/* pci_alloc_consistent returns page-aligned memory, so we do not have to check the alignment */
if ((lp = pci_alloc_consistent(pdev, sizeof(*lp), &lp_dma_addr)) == NULL) {
- release_resource(res);
+ release_region(ioaddr, PCNET32_TOTAL_SIZE);
return -ENOMEM;
}
@@ -727,7 +725,7 @@ pcnet32_probe1(unsigned long ioaddr, unsigned int irq_line, int shared,
if (!a) {
printk(KERN_ERR PFX "No access methods\n");
pci_free_consistent(lp->pci_dev, sizeof(*lp), lp, lp->dma_addr);
- release_resource(res);
+ release_region(ioaddr, PCNET32_TOTAL_SIZE);
return -ENODEV;
}
lp->a = *a;
@@ -775,7 +773,7 @@ pcnet32_probe1(unsigned long ioaddr, unsigned int irq_line, int shared,
else {
printk(", failed to detect IRQ line.\n");
pci_free_consistent(lp->pci_dev, sizeof(*lp), lp, lp->dma_addr);
- release_resource(res);
+ release_region(ioaddr, PCNET32_TOTAL_SIZE);
return -ENODEV;
}
}
diff --git a/drivers/net/sb1000.c b/drivers/net/sb1000.c
index 55dd5e283548b..184b2a4c2aae0 100644
--- a/drivers/net/sb1000.c
+++ b/drivers/net/sb1000.c
@@ -196,7 +196,7 @@ sb1000_probe(struct net_device *dev)
/* check I/O base and IRQ */
if (dev->base_addr != 0 && dev->base_addr != ioaddr[0])
continue;
- if (dev->rmem_end != 0 && dev->rmem_end != ioaddr[1])
+ if (dev->mem_start != 0 && dev->mem_start != ioaddr[1])
continue;
if (dev->irq != 0 && dev->irq != irq)
continue;
@@ -212,14 +212,14 @@ sb1000_probe(struct net_device *dev)
}
dev->base_addr = ioaddr[0];
- /* rmem_end holds the second I/O address - fv */
- dev->rmem_end = ioaddr[1];
+ /* mem_start holds the second I/O address */
+ dev->mem_start = ioaddr[1];
dev->irq = irq;
if (sb1000_debug > 0)
printk(KERN_NOTICE "%s: sb1000 at (%#3.3lx,%#3.3lx), "
"S/N %#8.8x, IRQ %d.\n", dev->name, dev->base_addr,
- dev->rmem_end, serial_number, dev->irq);
+ dev->mem_start, serial_number, dev->irq);
dev = init_etherdev(dev, 0);
if (!dev)
@@ -405,7 +405,7 @@ sb1000_wait_for_ready(const int ioaddr[], const char* name)
}
timeout = jiffies + Sb1000TimeOutJiffies;
while (!(inb(ioaddr[1] + 6) & 0x40)) {
- if (jiffies >= timeout) {
+ if (time_after_eq(jiffies, timeout)) {
printk(KERN_WARNING "%s: sb1000_wait_for_ready timeout\n",
name);
return -ETIME;
@@ -423,7 +423,7 @@ sb1000_wait_for_ready_clear(const int ioaddr[], const char* name)
timeout = jiffies + Sb1000TimeOutJiffies;
while (inb(ioaddr[1] + 6) & 0x80) {
- if (jiffies >= timeout) {
+ if (time_after_eq(jiffies, timeout)) {
printk(KERN_WARNING "%s: sb1000_wait_for_ready_clear timeout\n",
name);
return -ETIME;
@@ -431,7 +431,7 @@ sb1000_wait_for_ready_clear(const int ioaddr[], const char* name)
}
timeout = jiffies + Sb1000TimeOutJiffies;
while (inb(ioaddr[1] + 6) & 0x40) {
- if (jiffies >= timeout) {
+ if (time_after_eq(jiffies, timeout)) {
printk(KERN_WARNING "%s: sb1000_wait_for_ready_clear timeout\n",
name);
return -ETIME;
@@ -935,8 +935,8 @@ sb1000_error_dpc(struct net_device *dev)
const int ErrorDpcCounterInitialize = 200;
ioaddr[0] = dev->base_addr;
- /* rmem_end holds the second I/O address - fv */
- ioaddr[1] = dev->rmem_end;
+ /* mem_start holds the second I/O address */
+ ioaddr[1] = dev->mem_start;
name = dev->name;
sb1000_wait_for_ready_clear(ioaddr, name);
@@ -961,8 +961,8 @@ sb1000_open(struct net_device *dev)
const unsigned short FirmwareVersion[] = {0x01, 0x01};
ioaddr[0] = dev->base_addr;
- /* rmem_end holds the second I/O address - fv */
- ioaddr[1] = dev->rmem_end;
+ /* mem_start holds the second I/O address */
+ ioaddr[1] = dev->mem_start;
name = dev->name;
/* initialize sb1000 */
@@ -1029,8 +1029,8 @@ static int sb1000_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
return -ENODEV;
ioaddr[0] = dev->base_addr;
- /* rmem_end holds the second I/O address - fv */
- ioaddr[1] = dev->rmem_end;
+ /* mem_start holds the second I/O address */
+ ioaddr[1] = dev->mem_start;
name = dev->name;
switch (cmd) {
@@ -1130,8 +1130,8 @@ static void sb1000_interrupt(int irq, void *dev_id, struct pt_regs *regs)
}
ioaddr[0] = dev->base_addr;
- /* rmem_end holds the second I/O address - fv */
- ioaddr[1] = dev->rmem_end;
+ /* mem_start holds the second I/O address */
+ ioaddr[1] = dev->mem_start;
name = dev->name;
/* is it a good interrupt? */
@@ -1189,8 +1189,8 @@ static int sb1000_close(struct net_device *dev)
netif_stop_queue(dev);
ioaddr[0] = dev->base_addr;
- /* rmem_end holds the second I/O address - fv */
- ioaddr[1] = dev->rmem_end;
+ /* mem_start holds the second I/O address */
+ ioaddr[1] = dev->mem_start;
free_irq(dev->irq, dev);
/* If we don't do this, we can't re-insmod it later. */
@@ -1234,8 +1234,8 @@ init_module(void)
}
dev_sb1000.init = sb1000_probe;
dev_sb1000.base_addr = io[0];
- /* rmem_end holds the second I/O address - fv */
- dev_sb1000.rmem_end = io[1];
+ /* mem_start holds the second I/O address */
+ dev_sb1000.mem_start = io[1];
dev_sb1000.irq = irq;
if (register_netdev(&dev_sb1000) != 0) {
printk(KERN_ERR "sb1000: failed to register device (io: %03x,%03x "
@@ -1249,7 +1249,7 @@ void cleanup_module(void)
{
unregister_netdev(&dev_sb1000);
release_region(dev_sb1000.base_addr, 16);
- release_region(dev_sb1000.rmem_end, 16);
+ release_region(dev_sb1000.mem_start, 16);
kfree(dev_sb1000.priv);
dev_sb1000.priv = NULL;
}
diff --git a/drivers/net/sb1250-mac.c b/drivers/net/sb1250-mac.c
new file mode 100644
index 0000000000000..e0f35309bd79e
--- /dev/null
+++ b/drivers/net/sb1250-mac.c
@@ -0,0 +1,2673 @@
+/*
+ * Copyright (C) 2001 Broadcom Corporation
+ *
+ * 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.
+ */
+
+/*
+ This driver is designed for the Broadcom BCM12500 SOC chip's built-in
+ Ethernet controllers.
+
+ The author may be reached as mpl@broadcom.com
+*/
+
+
+/* A few user-configurable values.
+ These may be modified when a driver module is loaded. */
+
+static int debug = 1; /* 1 normal messages, 0 quiet .. 7 verbose. */
+
+/* Used to pass the media type, etc.
+ Both 'options[]' and 'full_duplex[]' should exist for driver
+ interoperability.
+ The media type is usually passed in 'options[]'.
+*/
+
+#define MAX_UNITS 3 /* More are supported, limit only on options */
+#ifdef MODULE
+static int options[MAX_UNITS] = {-1, -1, -1};
+static int full_duplex[MAX_UNITS] = {-1, -1, -1};
+#endif
+
+
+/* Operational parameters that usually are not changed. */
+
+/* Time in jiffies before concluding the transmitter is hung. */
+#define TX_TIMEOUT (2*HZ)
+
+#if !defined(__OPTIMIZE__) || !defined(__KERNEL__)
+#warning You must compile this file with the correct options!
+#warning See the last lines of the source file.
+#error You must compile this driver with "-O".
+#endif
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/config.h>
+#include <asm/processor.h> /* Processor type for cache alignment. */
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/sibyte/sb1250.h>
+#include <asm/sibyte/64bit.h>
+
+/* This is only here until the firmware is ready. In that case,
+ the firmware leaves the ethernet address in the register for us. */
+#ifdef CONFIG_SWARM_STANDALONE
+#define SBMAC_ETH0_HWADDR "40:00:00:00:01:00"
+#define SBMAC_ETH1_HWADDR "40:00:00:00:01:01"
+#define SBMAC_ETH2_HWADDR "40:00:00:00:01:02"
+#endif
+
+
+/* These identify the driver base version and may not be removed. */
+#if 0
+static char version1[] __devinitdata =
+"sb1250-mac.c:1.00 1/11/2001 Written by Mitch Lichtenberg (mpl@broadcom.com)\n";
+#endif
+
+
+
+MODULE_AUTHOR("Mitch Lichtenberg (mpl@broadcom.com)");
+MODULE_DESCRIPTION("Broadcom BCM12500 SOC GB Ethernet driver");
+MODULE_PARM(debug, "i");
+MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i");
+MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");
+
+
+#include <asm/sibyte/sb1250_defs.h>
+#include <asm/sibyte/sb1250_regs.h>
+#include <asm/sibyte/sb1250_mac.h>
+#include <asm/sibyte/sb1250_dma.h>
+#include <asm/sibyte/sb1250_int.h>
+
+
+/**********************************************************************
+ * Simple types
+ ********************************************************************* */
+
+
+typedef unsigned long sbmac_port_t;
+typedef uint64_t sbmac_physaddr_t;
+typedef uint64_t sbmac_enetaddr_t;
+
+typedef enum { sbmac_speed_auto, sbmac_speed_10,
+ sbmac_speed_100, sbmac_speed_1000 } sbmac_speed_t;
+
+typedef enum { sbmac_duplex_auto, sbmac_duplex_half,
+ sbmac_duplex_full } sbmac_duplex_t;
+
+typedef enum { sbmac_fc_auto, sbmac_fc_disabled, sbmac_fc_frame,
+ sbmac_fc_collision, sbmac_fc_carrier } sbmac_fc_t;
+
+typedef enum { sbmac_state_uninit, sbmac_state_off, sbmac_state_on,
+ sbmac_state_broken } sbmac_state_t;
+
+
+/**********************************************************************
+ * Macros
+ ********************************************************************* */
+
+
+#define SBDMA_NEXTBUF(d,f) ((((d)->f+1) == (d)->sbdma_dscrtable_end) ? \
+ (d)->sbdma_dscrtable : (d)->f+1)
+
+
+#define CACHELINESIZE 32
+#define NUMCACHEBLKS(x) (((x)+CACHELINESIZE-1)/CACHELINESIZE)
+#define KMALLOC(x) kmalloc((x),GFP_KERNEL)
+#define KFREE(x) kfree(x)
+#define KVTOPHYS(x) virt_to_bus((void *)(x))
+
+
+#define SBMAC_READCSR(t) (in64((unsigned long)(t)))
+#define SBMAC_WRITECSR(t,v) (out64(v, (unsigned long)(t)))
+
+#define PKSEG1(x) ((sbmac_port_t) KSEG1ADDR(x))
+
+#define SBMAC_MAX_TXDESCR 32
+#define SBMAC_MAX_RXDESCR 32
+
+#define ETHER_ALIGN 2
+#define ETHER_ADDR_LEN 6
+#define ENET_PACKET_SIZE 1518
+
+/**********************************************************************
+ * DMA Descriptor structure
+ ********************************************************************* */
+
+typedef struct sbdmadscr_s {
+ uint64_t dscr_a;
+ uint64_t dscr_b;
+} sbdmadscr_t;
+
+typedef unsigned long paddr_t;
+typedef unsigned long vaddr_t;
+
+/**********************************************************************
+ * DMA Controller structure
+ ********************************************************************* */
+
+typedef struct sbmacdma_s {
+
+ /*
+ * This stuff is used to identify the channel and the registers
+ * associated with it.
+ */
+
+ struct sbmac_softc *sbdma_eth; /* back pointer to associated MAC */
+ int sbdma_channel; /* channel number */
+ int sbdma_txdir; /* direction (1=transmit) */
+ int sbdma_maxdescr; /* total # of descriptors in ring */
+ sbmac_port_t sbdma_config0; /* DMA config register 0 */
+ sbmac_port_t sbdma_config1; /* DMA config register 1 */
+ sbmac_port_t sbdma_dscrbase; /* Descriptor base address */
+ sbmac_port_t sbdma_dscrcnt; /* Descriptor count register */
+ sbmac_port_t sbdma_curdscr; /* current descriptor address */
+
+ /*
+ * This stuff is for maintenance of the ring
+ */
+
+ sbdmadscr_t *sbdma_dscrtable; /* base of descriptor table */
+ sbdmadscr_t *sbdma_dscrtable_end; /* end of descriptor table */
+
+ struct sk_buff **sbdma_ctxtable; /* context table, one per descr */
+
+ paddr_t sbdma_dscrtable_phys; /* and also the phys addr */
+ sbdmadscr_t *sbdma_addptr; /* next dscr for sw to add */
+ sbdmadscr_t *sbdma_remptr; /* next dscr for sw to remove */
+
+} sbmacdma_t;
+
+
+/**********************************************************************
+ * Ethernet softc structure
+ ********************************************************************* */
+
+struct sbmac_softc {
+
+ /*
+ * Linux-specific things
+ */
+
+ struct net_device *sbm_dev; /* pointer to linux device */
+ spinlock_t sbm_lock; /* spin lock */
+ struct timer_list sbm_timer; /* for monitoring MII */
+ struct net_device_stats sbm_stats;
+ int sbm_devflags; /* current device flags */
+
+ int sbm_phy_oldbmsr;
+ int sbm_phy_oldanlpar;
+ int sbm_phy_oldk1stsr;
+ int sbm_phy_oldlinkstat;
+ int sbm_buffersize;
+
+ unsigned char sbm_phys[2];
+
+ /*
+ * Controller-specific things
+ */
+
+ sbmac_port_t sbm_base; /* MAC's base address */
+ sbmac_state_t sbm_state; /* current state */
+
+ sbmac_port_t sbm_macenable; /* MAC Enable Register */
+ sbmac_port_t sbm_maccfg; /* MAC Configuration Register */
+ sbmac_port_t sbm_fifocfg; /* FIFO configuration register */
+ sbmac_port_t sbm_framecfg; /* Frame configuration register */
+ sbmac_port_t sbm_rxfilter; /* receive filter register */
+ sbmac_port_t sbm_isr; /* Interrupt status register */
+ sbmac_port_t sbm_imr; /* Interrupt mask register */
+ sbmac_port_t sbm_mdio; /* MDIO register */
+
+ sbmac_speed_t sbm_speed; /* current speed */
+ sbmac_duplex_t sbm_duplex; /* current duplex */
+ sbmac_fc_t sbm_fc; /* current flow control setting */
+
+ u_char sbm_hwaddr[ETHER_ADDR_LEN];
+
+ sbmacdma_t sbm_txdma; /* for now, only use channel 0 */
+ sbmacdma_t sbm_rxdma;
+
+};
+
+
+/**********************************************************************
+ * Externs
+ ********************************************************************* */
+
+/**********************************************************************
+ * Prototypes
+ ********************************************************************* */
+
+static void sbdma_initctx(sbmacdma_t *d,
+ struct sbmac_softc *s,
+ int chan,
+ int txrx,
+ int maxdescr);
+static void sbdma_channel_start(sbmacdma_t *d);
+static int sbdma_add_rcvbuffer(sbmacdma_t *d,struct sk_buff *m);
+static int sbdma_add_txbuffer(sbmacdma_t *d,struct sk_buff *m);
+static void sbdma_emptyring(sbmacdma_t *d);
+static void sbdma_fillring(sbmacdma_t *d);
+static void sbdma_rx_process(struct sbmac_softc *sc,sbmacdma_t *d);
+static void sbdma_tx_process(struct sbmac_softc *sc,sbmacdma_t *d);
+static int sbmac_initctx(struct sbmac_softc *s);
+static void sbmac_channel_start(struct sbmac_softc *s);
+static void sbmac_channel_stop(struct sbmac_softc *s);
+static sbmac_state_t sbmac_set_channel_state(struct sbmac_softc *,sbmac_state_t);
+static void sbmac_promiscuous_mode(struct sbmac_softc *sc,int onoff);
+/*static void sbmac_init_and_start(struct sbmac_softc *sc);*/
+static uint64_t sbmac_addr2reg(unsigned char *ptr);
+static void sbmac_intr(int irq,void *dev_instance,struct pt_regs *rgs);
+static int sbmac_start_tx(struct sk_buff *skb, struct net_device *dev);
+static void sbmac_setmulti(struct sbmac_softc *sc);
+static int sbmac_init(struct net_device *dev);
+static int sbmac_set_speed(struct sbmac_softc *s,sbmac_speed_t speed);
+static int sbmac_set_duplex(struct sbmac_softc *s,sbmac_duplex_t duplex,sbmac_fc_t fc);
+
+static int sbmac_open(struct net_device *dev);
+static void sbmac_timer(unsigned long data);
+static void sbmac_tx_timeout (struct net_device *dev);
+static struct net_device_stats *sbmac_get_stats(struct net_device *dev);
+static void sbmac_set_rx_mode(struct net_device *dev);
+static int sbmac_mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
+static int sbmac_close(struct net_device *dev);
+static int sbmac_mii_poll(struct sbmac_softc *s,int noisy);
+
+static void sbmac_mii_sync(struct sbmac_softc *s);
+static void sbmac_mii_senddata(struct sbmac_softc *s,unsigned int data, int bitcnt);
+static unsigned int sbmac_mii_read(struct sbmac_softc *s,int phyaddr,int regidx);
+static void sbmac_mii_write(struct sbmac_softc *s,int phyaddr,int regidx,
+ unsigned int regval);
+
+
+/**********************************************************************
+ * Globals
+ ********************************************************************* */
+
+
+/**********************************************************************
+ * MDIO constants
+ ********************************************************************* */
+
+#define MII_COMMAND_START 0x01
+#define MII_COMMAND_READ 0x02
+#define MII_COMMAND_WRITE 0x01
+#define MII_COMMAND_ACK 0x02
+
+#define BMCR_RESET 0x8000
+#define BMCR_LOOPBACK 0x4000
+#define BMCR_SPEED0 0x2000
+#define BMCR_ANENABLE 0x1000
+#define BMCR_POWERDOWN 0x0800
+#define BMCR_ISOLATE 0x0400
+#define BMCR_RESTARTAN 0x0200
+#define BMCR_DUPLEX 0x0100
+#define BMCR_COLTEST 0x0080
+#define BMCR_SPEED1 0x0040
+#define BMCR_SPEED1000 (BMCR_SPEED1|BMCR_SPEED0)
+#define BMCR_SPEED100 (BMCR_SPEED0)
+#define BMCR_SPEED10 0
+
+#define BMSR_100BT4 0x8000
+#define BMSR_100BT_FDX 0x4000
+#define BMSR_100BT_HDX 0x2000
+#define BMSR_10BT_FDX 0x1000
+#define BMSR_10BT_HDX 0x0800
+#define BMSR_100BT2_FDX 0x0400
+#define BMSR_100BT2_HDX 0x0200
+#define BMSR_1000BT_XSR 0x0100
+#define BMSR_PRESUP 0x0040
+#define BMSR_ANCOMPLT 0x0020
+#define BMSR_REMFAULT 0x0010
+#define BMSR_AUTONEG 0x0008
+#define BMSR_LINKSTAT 0x0004
+#define BMSR_JABDETECT 0x0002
+#define BMSR_EXTCAPAB 0x0001
+
+#define PHYIDR1 0x2000
+#define PHYIDR2 0x5C60
+
+#define ANAR_NP 0x8000
+#define ANAR_RF 0x2000
+#define ANAR_ASYPAUSE 0x0800
+#define ANAR_PAUSE 0x0400
+#define ANAR_T4 0x0200
+#define ANAR_TXFD 0x0100
+#define ANAR_TXHD 0x0080
+#define ANAR_10FD 0x0040
+#define ANAR_10HD 0x0020
+#define ANAR_PSB 0x0001
+
+#define ANLPAR_NP 0x8000
+#define ANLPAR_ACK 0x4000
+#define ANLPAR_RF 0x2000
+#define ANLPAR_ASYPAUSE 0x0800
+#define ANLPAR_PAUSE 0x0400
+#define ANLPAR_T4 0x0200
+#define ANLPAR_TXFD 0x0100
+#define ANLPAR_TXHD 0x0080
+#define ANLPAR_10FD 0x0040
+#define ANLPAR_10HD 0x0020
+#define ANLPAR_PSB 0x0001 /* 802.3 */
+
+#define ANER_PDF 0x0010
+#define ANER_LPNPABLE 0x0008
+#define ANER_NPABLE 0x0004
+#define ANER_PAGERX 0x0002
+#define ANER_LPANABLE 0x0001
+
+#define ANNPTR_NP 0x8000
+#define ANNPTR_MP 0x2000
+#define ANNPTR_ACK2 0x1000
+#define ANNPTR_TOGTX 0x0800
+#define ANNPTR_CODE 0x0008
+
+#define ANNPRR_NP 0x8000
+#define ANNPRR_MP 0x2000
+#define ANNPRR_ACK3 0x1000
+#define ANNPRR_TOGTX 0x0800
+#define ANNPRR_CODE 0x0008
+
+#define K1TCR_TESTMODE 0x0000
+#define K1TCR_MSMCE 0x1000
+#define K1TCR_MSCV 0x0800
+#define K1TCR_RPTR 0x0400
+#define K1TCR_1000BT_FDX 0x200
+#define K1TCR_1000BT_HDX 0x100
+
+#define K1STSR_MSMCFLT 0x8000
+#define K1STSR_MSCFGRES 0x4000
+#define K1STSR_LRSTAT 0x2000
+#define K1STSR_RRSTAT 0x1000
+#define K1STSR_LP1KFD 0x0800
+#define K1STSR_LP1KHD 0x0400
+#define K1STSR_LPASMDIR 0x0200
+
+#define K1SCR_1KX_FDX 0x8000
+#define K1SCR_1KX_HDX 0x4000
+#define K1SCR_1KT_FDX 0x2000
+#define K1SCR_1KT_HDX 0x1000
+
+#define STRAP_PHY1 0x0800
+#define STRAP_NCMODE 0x0400
+#define STRAP_MANMSCFG 0x0200
+#define STRAP_ANENABLE 0x0100
+#define STRAP_MSVAL 0x0080
+#define STRAP_1KHDXADV 0x0010
+#define STRAP_1KFDXADV 0x0008
+#define STRAP_100ADV 0x0004
+#define STRAP_SPEEDSEL 0x0000
+#define STRAP_SPEED100 0x0001
+
+#define PHYSUP_SPEED1000 0x10
+#define PHYSUP_SPEED100 0x08
+#define PHYSUP_SPEED10 0x00
+#define PHYSUP_LINKUP 0x04
+#define PHYSUP_FDX 0x02
+
+#define MII_BMCR 0x00 /* Basic mode control register (rw) */
+#define MII_BMSR 0x01 /* Basic mode status register (ro) */
+#define MII_K1STSR 0x0A /* 1K Status Register (ro) */
+#define MII_ANLPAR 0x05 /* Autonegotiation lnk partner abilities (rw) */
+
+
+#define M_MAC_MDIO_DIR_OUTPUT 0 /* for clarity */
+
+
+/**********************************************************************
+ * SBMAC_MII_SYNC(s)
+ *
+ * Synchronize with the MII - send a pattern of bits to the MII
+ * that will guarantee that it is ready to accept a command.
+ *
+ * Input parameters:
+ * s - sbmac structure
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+static void sbmac_mii_sync(struct sbmac_softc *s)
+{
+ int cnt;
+ uint64_t bits;
+
+ bits = M_MAC_MDIO_DIR_OUTPUT | M_MAC_MDIO_OUT;
+
+ SBMAC_WRITECSR(s->sbm_mdio,bits);
+
+ for (cnt = 0; cnt < 32; cnt++) {
+ SBMAC_WRITECSR(s->sbm_mdio,bits | M_MAC_MDC);
+ SBMAC_WRITECSR(s->sbm_mdio,bits);
+ }
+}
+
+/**********************************************************************
+ * SBMAC_MII_SENDDATA(s,data,bitcnt)
+ *
+ * Send some bits to the MII. The bits to be sent are right-
+ * justified in the 'data' parameter.
+ *
+ * Input parameters:
+ * s - sbmac structure
+ * data - data to send
+ * bitcnt - number of bits to send
+ ********************************************************************* */
+
+static void sbmac_mii_senddata(struct sbmac_softc *s,unsigned int data, int bitcnt)
+{
+ int i;
+ uint64_t bits;
+ unsigned int curmask;
+
+ bits = M_MAC_MDIO_DIR_OUTPUT;
+ SBMAC_WRITECSR(s->sbm_mdio,bits);
+
+ curmask = 1 << (bitcnt - 1);
+
+ for (i = 0; i < bitcnt; i++) {
+ if (data & curmask) bits |= M_MAC_MDIO_OUT;
+ else bits &= ~M_MAC_MDIO_OUT;
+ SBMAC_WRITECSR(s->sbm_mdio,bits);
+ SBMAC_WRITECSR(s->sbm_mdio,bits | M_MAC_MDC);
+ SBMAC_WRITECSR(s->sbm_mdio,bits);
+ curmask >>= 1;
+ }
+}
+
+
+
+/**********************************************************************
+ * SBMAC_MII_READ(s,phyaddr,regidx)
+ *
+ * Read a PHY register.
+ *
+ * Input parameters:
+ * s - sbmac structure
+ * phyaddr - PHY's address
+ * regidx = index of register to read
+ *
+ * Return value:
+ * value read, or 0 if an error occured.
+ ********************************************************************* */
+
+static unsigned int sbmac_mii_read(struct sbmac_softc *s,int phyaddr,int regidx)
+{
+ int idx;
+ int error;
+ int regval;
+
+ /*
+ * Synchronize ourselves so that the PHY knows the next
+ * thing coming down is a command
+ */
+
+ sbmac_mii_sync(s);
+
+ /*
+ * Send the data to the PHY. The sequence is
+ * a "start" command (2 bits)
+ * a "read" command (2 bits)
+ * the PHY addr (5 bits)
+ * the register index (5 bits)
+ */
+
+ sbmac_mii_senddata(s,MII_COMMAND_START, 2);
+ sbmac_mii_senddata(s,MII_COMMAND_READ, 2);
+ sbmac_mii_senddata(s,phyaddr, 5);
+ sbmac_mii_senddata(s,regidx, 5);
+
+ /*
+ * Switch the port around without a clock transition.
+ */
+ SBMAC_WRITECSR(s->sbm_mdio,M_MAC_MDIO_DIR_INPUT);
+
+ /*
+ * Send out a clock pulse to signal we want the status
+ */
+
+ SBMAC_WRITECSR(s->sbm_mdio,M_MAC_MDIO_DIR_INPUT | M_MAC_MDC);
+ SBMAC_WRITECSR(s->sbm_mdio,M_MAC_MDIO_DIR_INPUT);
+
+ /*
+ * If an error occured, the PHY will signal '1' back
+ */
+ error = SBMAC_READCSR(s->sbm_mdio) & M_MAC_MDIO_IN;
+
+ /*
+ * Issue an 'idle' clock pulse, but keep the direction
+ * the same.
+ */
+ SBMAC_WRITECSR(s->sbm_mdio,M_MAC_MDIO_DIR_INPUT | M_MAC_MDC);
+ SBMAC_WRITECSR(s->sbm_mdio,M_MAC_MDIO_DIR_INPUT);
+
+ regval = 0;
+
+ for (idx = 0; idx < 16; idx++) {
+ regval <<= 1;
+
+ if (error == 0) {
+ if (SBMAC_READCSR(s->sbm_mdio) & M_MAC_MDIO_IN) regval |= 1;
+ }
+
+ SBMAC_WRITECSR(s->sbm_mdio,M_MAC_MDIO_DIR_INPUT | M_MAC_MDC);
+ SBMAC_WRITECSR(s->sbm_mdio,M_MAC_MDIO_DIR_INPUT);
+ }
+
+ /* Switch back to output */
+ SBMAC_WRITECSR(s->sbm_mdio,M_MAC_MDIO_DIR_OUTPUT);
+
+ if (error == 0) return regval;
+ return 0;
+}
+
+
+/**********************************************************************
+ * SBMAC_MII_WRITE(s,phyaddr,regidx,regval)
+ *
+ * Write a value to a PHY register.
+ *
+ * Input parameters:
+ * s - sbmac structure
+ * phyaddr - PHY to use
+ * regidx - register within the PHY
+ * regval - data to write to register
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+static void sbmac_mii_write(struct sbmac_softc *s,int phyaddr,int regidx,
+ unsigned int regval)
+{
+
+ sbmac_mii_sync(s);
+
+ sbmac_mii_senddata(s,MII_COMMAND_START,2);
+ sbmac_mii_senddata(s,MII_COMMAND_WRITE,2);
+ sbmac_mii_senddata(s,phyaddr, 5);
+ sbmac_mii_senddata(s,regidx, 5);
+ sbmac_mii_senddata(s,MII_COMMAND_ACK,2);
+ sbmac_mii_senddata(s,regval,16);
+
+ SBMAC_WRITECSR(s->sbm_mdio,M_MAC_MDIO_DIR_OUTPUT);
+}
+
+
+
+/**********************************************************************
+ * SBDMA_INITCTX(d,s,chan,txrx,maxdescr)
+ *
+ * Initialize a DMA channel context. Since there are potentially
+ * eight DMA channels per MAC, it's nice to do this in a standard
+ * way.
+ *
+ * Input parameters:
+ * d - sbmacdma_t structure (DMA channel context)
+ * s - sbmac_softc structure (pointer to a MAC)
+ * chan - channel number (0..1 right now)
+ * txrx - Identifies DMA_TX or DMA_RX for channel direction
+ * maxdescr - number of descriptors
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+static void sbdma_initctx(sbmacdma_t *d,
+ struct sbmac_softc *s,
+ int chan,
+ int txrx,
+ int maxdescr)
+{
+ /*
+ * Save away interesting stuff in the structure
+ */
+
+ d->sbdma_eth = s;
+ d->sbdma_channel = chan;
+ d->sbdma_txdir = txrx;
+
+ /*
+ * initialize register pointers
+ */
+
+ d->sbdma_config0 =
+ PKSEG1(s->sbm_base + R_MAC_DMA_REGISTER(txrx,chan,R_MAC_DMA_CONFIG0));
+ d->sbdma_config1 =
+ PKSEG1(s->sbm_base + R_MAC_DMA_REGISTER(txrx,chan,R_MAC_DMA_CONFIG0));
+ d->sbdma_dscrbase =
+ PKSEG1(s->sbm_base + R_MAC_DMA_REGISTER(txrx,chan,R_MAC_DMA_DSCR_BASE));
+ d->sbdma_dscrcnt =
+ PKSEG1(s->sbm_base + R_MAC_DMA_REGISTER(txrx,chan,R_MAC_DMA_DSCR_CNT));
+ d->sbdma_curdscr =
+ PKSEG1(s->sbm_base + R_MAC_DMA_REGISTER(txrx,chan,R_MAC_DMA_CUR_DSCRADDR));
+
+ /*
+ * Allocate memory for the ring
+ */
+
+ d->sbdma_maxdescr = maxdescr;
+
+ d->sbdma_dscrtable = (sbdmadscr_t *)
+ KMALLOC(d->sbdma_maxdescr*sizeof(sbdmadscr_t));
+
+ memset(d->sbdma_dscrtable,0,d->sbdma_maxdescr*sizeof(sbdmadscr_t));
+
+ d->sbdma_dscrtable_end = d->sbdma_dscrtable + d->sbdma_maxdescr;
+
+ d->sbdma_dscrtable_phys = KVTOPHYS(d->sbdma_dscrtable);
+
+ /*
+ * And context table
+ */
+
+ d->sbdma_ctxtable = (struct sk_buff **)
+ KMALLOC(d->sbdma_maxdescr*sizeof(struct sk_buff *));
+
+ memset(d->sbdma_ctxtable,0,d->sbdma_maxdescr*sizeof(struct sk_buff *));
+
+}
+
+/**********************************************************************
+ * SBDMA_CHANNEL_START(d)
+ *
+ * Initialize the hardware registers for a DMA channel.
+ *
+ * Input parameters:
+ * d - DMA channel to init (context must be previously init'd
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+static void sbdma_channel_start(sbmacdma_t *d)
+{
+ /*
+ * Turn on the DMA channel
+ */
+
+ SBMAC_WRITECSR(d->sbdma_config1,0);
+
+ SBMAC_WRITECSR(d->sbdma_dscrbase,d->sbdma_dscrtable_phys);
+
+ SBMAC_WRITECSR(d->sbdma_config0,
+ V_DMA_RINGSZ(d->sbdma_maxdescr) |
+ 0);
+
+ /*
+ * Initialize ring pointers
+ */
+
+ d->sbdma_addptr = d->sbdma_dscrtable;
+ d->sbdma_remptr = d->sbdma_dscrtable;
+}
+
+
+static void sbdma_align_skb(struct sk_buff *skb,int power2,int offset)
+{
+ unsigned long addr;
+ unsigned long newaddr;
+
+ addr = (unsigned long) skb->data;
+
+ newaddr = (addr + power2 - 1) & ~(power2 - 1);
+
+ skb_reserve(skb,newaddr-addr+offset);
+}
+
+
+/**********************************************************************
+ * SBDMA_ADD_RCVBUFFER(d,sb)
+ *
+ * Add a buffer to the specified DMA channel. For receive channels,
+ * this queues a buffer for inbound packets.
+ *
+ * Input parameters:
+ * d - DMA channel descriptor
+ * sb - sk_buff to add, or NULL if we should allocate one
+ *
+ * Return value:
+ * 0 if buffer could not be added (ring is full)
+ * 1 if buffer added successfully
+ ********************************************************************* */
+
+
+static int sbdma_add_rcvbuffer(sbmacdma_t *d,struct sk_buff *sb)
+{
+ sbdmadscr_t *dsc;
+ sbdmadscr_t *nextdsc;
+ struct sk_buff *sb_new = NULL;
+ int pktsize = ENET_PACKET_SIZE;
+
+ /* get pointer to our current place in the ring */
+
+ dsc = d->sbdma_addptr;
+ nextdsc = SBDMA_NEXTBUF(d,sbdma_addptr);
+
+ /*
+ * figure out if the ring is full - if the next descriptor
+ * is the same as the one that we're going to remove from
+ * the ring, the ring is full
+ */
+
+ if (nextdsc == d->sbdma_remptr) {
+ return -ENOSPC;
+ }
+
+ /*
+ * Allocate a sk_buff if we don't already have one.
+ * If we do have an sk_buff, reset it so that it's empty.
+ *
+ * Note: sk_buffs don't seem to be guaranteed to have any sort
+ * of alignment when they are allocated. Therefore, allocate enough
+ * extra space to make sure that:
+ *
+ * 1. the data does not start in the middle of a cache line.
+ * 2. The data does not end in the middle of a cache line
+ * 3. The buffer can be aligned such that the IP addresses are
+ * naturally aligned.
+ *
+ * Remember, the SB1250's MAC writes whole cache lines at a time,
+ * without reading the old contents first. So, if the sk_buff's
+ * data portion starts in the middle of a cache line, the SB1250
+ * DMA will trash the beginning (and ending) portions.
+ */
+
+ if (sb == NULL) {
+ sb_new = dev_alloc_skb(ENET_PACKET_SIZE + CACHELINESIZE*2 + ETHER_ALIGN);
+ if (sb_new == NULL) {
+ printk(KERN_INFO "%s: sk_buff allocation failed\n",
+ d->sbdma_eth->sbm_dev->name);
+ return -ENOBUFS;
+ }
+
+ sbdma_align_skb(sb_new,CACHELINESIZE,ETHER_ALIGN);
+
+ /* mark skbuff owned by our device */
+ sb_new->dev = d->sbdma_eth->sbm_dev;
+ }
+ else {
+ sb_new = sb;
+ /*
+ * nothing special to reinit buffer, it's already aligned
+ * and sb->tail already points to a good place.
+ */
+ }
+
+ /*
+ * fill in the descriptor
+ */
+
+ dsc->dscr_a = KVTOPHYS(sb_new->tail) |
+ V_DMA_DSCRA_A_SIZE(NUMCACHEBLKS(pktsize+ETHER_ALIGN)) |
+ M_DMA_DSCRA_INTERRUPT;
+
+ /* receiving: no options */
+ dsc->dscr_b = 0;
+
+ /*
+ * fill in the context
+ */
+
+ d->sbdma_ctxtable[dsc-d->sbdma_dscrtable] = sb_new;
+
+ /*
+ * point at next packet
+ */
+
+ d->sbdma_addptr = nextdsc;
+
+ /*
+ * Give the buffer to the DMA engine.
+ */
+
+ SBMAC_WRITECSR(d->sbdma_dscrcnt,1);
+
+ return 0; /* we did it */
+}
+
+/**********************************************************************
+ * SBDMA_ADD_TXBUFFER(d,sb)
+ *
+ * Add a transmit buffer to the specified DMA channel, causing a
+ * transmit to start.
+ *
+ * Input parameters:
+ * d - DMA channel descriptor
+ * sb - sk_buff to add
+ *
+ * Return value:
+ * 0 transmit queued successfully
+ * otherwise error code
+ ********************************************************************* */
+
+
+static int sbdma_add_txbuffer(sbmacdma_t *d,struct sk_buff *sb)
+{
+ sbdmadscr_t *dsc;
+ sbdmadscr_t *nextdsc;
+ uint64_t phys;
+ uint64_t ncb;
+ int length;
+
+ /* get pointer to our current place in the ring */
+
+ dsc = d->sbdma_addptr;
+ nextdsc = SBDMA_NEXTBUF(d,sbdma_addptr);
+
+ /*
+ * figure out if the ring is full - if the next descriptor
+ * is the same as the one that we're going to remove from
+ * the ring, the ring is full
+ */
+
+ if (nextdsc == d->sbdma_remptr) {
+ return -ENOSPC;
+ }
+
+ /*
+ * Under Linux, it's not necessary to copy/coalesce buffers
+ * like it is on NetBSD. We think they're all contiguous,
+ * but that may not be true for GBE.
+ */
+
+ length = sb->len;
+
+ /*
+ * fill in the descriptor. Note that the number of cache
+ * blocks in the descriptor is the number of blocks
+ * *spanned*, so we need to add in the offset (if any)
+ * while doing the calculation.
+ */
+
+ phys = KVTOPHYS(sb->data);
+ ncb = NUMCACHEBLKS(length+(phys & (CACHELINESIZE-1)));
+
+ dsc->dscr_a = phys |
+ V_DMA_DSCRA_A_SIZE(ncb) |
+ M_DMA_DSCRA_INTERRUPT |
+ M_DMA_ETHTX_SOP;
+
+ /* transmitting: set outbound options and length */
+
+ dsc->dscr_b = V_DMA_DSCRB_OPTIONS(K_DMA_ETHTX_APPENDCRC_APPENDPAD) |
+ V_DMA_DSCRB_PKT_SIZE(length);
+
+ /*
+ * fill in the context
+ */
+
+ d->sbdma_ctxtable[dsc-d->sbdma_dscrtable] = sb;
+
+ /*
+ * point at next packet
+ */
+
+ d->sbdma_addptr = nextdsc;
+
+ /*
+ * Give the buffer to the DMA engine.
+ */
+
+ SBMAC_WRITECSR(d->sbdma_dscrcnt,1);
+
+ return 0; /* we did it */
+}
+
+
+
+
+/**********************************************************************
+ * SBDMA_EMPTYRING(d)
+ *
+ * Free all allocated sk_buffs on the specified DMA channel;
+ *
+ * Input parameters:
+ * d - DMA channel
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+static void sbdma_emptyring(sbmacdma_t *d)
+{
+ int idx;
+ struct sk_buff *sb;
+
+ for (idx = 0; idx < d->sbdma_maxdescr; idx++) {
+ sb = d->sbdma_ctxtable[idx];
+ if (sb) {
+ dev_kfree_skb(sb);
+ d->sbdma_ctxtable[idx] = NULL;
+ }
+ }
+}
+
+
+/**********************************************************************
+ * SBDMA_FILLRING(d)
+ *
+ * Fill the specified DMA channel (must be receive channel)
+ * with sk_buffs
+ *
+ * Input parameters:
+ * d - DMA channel
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+static void sbdma_fillring(sbmacdma_t *d)
+{
+ int idx;
+
+ for (idx = 0; idx < SBMAC_MAX_RXDESCR-1; idx++) {
+ if (sbdma_add_rcvbuffer(d,NULL) != 0) break;
+ }
+}
+
+
+/**********************************************************************
+ * SBDMA_RX_PROCESS(sc,d)
+ *
+ * Process "completed" receive buffers on the specified DMA channel.
+ * Note that this isn't really ideal for priority channels, since
+ * it processes all of the packets on a given channel before
+ * returning.
+ *
+ * Input parameters:
+ * sc - softc structure
+ * d - DMA channel context
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+static void sbdma_rx_process(struct sbmac_softc *sc,sbmacdma_t *d)
+{
+ int curidx;
+ int hwidx;
+ sbdmadscr_t *dsc;
+ struct sk_buff *sb;
+ int len;
+
+ for (;;) {
+ /*
+ * figure out where we are (as an index) and where
+ * the hardware is (also as an index)
+ *
+ * This could be done faster if (for example) the
+ * descriptor table was page-aligned and contiguous in
+ * both virtual and physical memory -- you could then
+ * just compare the low-order bits of the virtual address
+ * (sbdma_remptr) and the physical address (sbdma_curdscr CSR)
+ */
+
+ curidx = d->sbdma_remptr - d->sbdma_dscrtable;
+ hwidx = (int) (((SBMAC_READCSR(d->sbdma_curdscr) & M_DMA_CURDSCR_ADDR) -
+ d->sbdma_dscrtable_phys) / sizeof(sbdmadscr_t));
+
+ /*
+ * If they're the same, that means we've processed all
+ * of the descriptors up to (but not including) the one that
+ * the hardware is working on right now.
+ */
+
+ if (curidx == hwidx) break;
+
+ /*
+ * Otherwise, get the packet's sk_buff ptr back
+ */
+
+ dsc = &(d->sbdma_dscrtable[curidx]);
+ sb = d->sbdma_ctxtable[curidx];
+ d->sbdma_ctxtable[curidx] = NULL;
+
+ len = (int)G_DMA_DSCRB_PKT_SIZE(dsc->dscr_b) - 4;
+
+ /*
+ * Check packet status. If good, process it.
+ * If not, silently drop it and put it back on the
+ * receive ring.
+ */
+
+ if (!(dsc->dscr_a & M_DMA_ETHRX_BAD)) {
+
+ /*
+ * Set length into the packet
+ */
+ skb_put(sb,len);
+
+ /*
+ * Add a new buffer to replace the old one. If we fail
+ * to allocate a buffer, we're going to drop this
+ * packet and put it right back on the receive ring.
+ */
+
+ if (sbdma_add_rcvbuffer(d,NULL) == -ENOBUFS) {
+ sbdma_add_rcvbuffer(d,sb); /* re-add old buffer */
+ }
+ else {
+ /*
+ * Buffer has been replaced on the receive ring.
+ * Pass the buffer to the kernel
+ */
+ sc->sbm_stats.rx_bytes += len;
+ sc->sbm_stats.rx_packets++;
+ sb->protocol = eth_type_trans(sb,d->sbdma_eth->sbm_dev);
+ netif_rx(sb);
+ }
+ }
+ else {
+ /*
+ * Packet was mangled somehow. Just drop it and
+ * put it back on the receive ring.
+ */
+ sbdma_add_rcvbuffer(d,sb);
+ }
+
+
+ /*
+ * .. and advance to the next buffer.
+ */
+
+ d->sbdma_remptr = SBDMA_NEXTBUF(d,sbdma_remptr);
+
+ }
+}
+
+
+
+/**********************************************************************
+ * SBDMA_TX_PROCESS(sc,d)
+ *
+ * Process "completed" transmit buffers on the specified DMA channel.
+ * This is normally called within the interrupt service routine.
+ * Note that this isn't really ideal for priority channels, since
+ * it processes all of the packets on a given channel before
+ * returning.
+ *
+ * Input parameters:
+ * sc - softc structure
+ * d - DMA channel context
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+static void sbdma_tx_process(struct sbmac_softc *sc,sbmacdma_t *d)
+{
+ int curidx;
+ int hwidx;
+ sbdmadscr_t *dsc;
+ struct sk_buff *sb;
+ unsigned long flags;
+
+ spin_lock_irqsave(&(sc->sbm_lock), flags);
+
+ for (;;) {
+ /*
+ * figure out where we are (as an index) and where
+ * the hardware is (also as an index)
+ *
+ * This could be done faster if (for example) the
+ * descriptor table was page-aligned and contiguous in
+ * both virtual and physical memory -- you could then
+ * just compare the low-order bits of the virtual address
+ * (sbdma_remptr) and the physical address (sbdma_curdscr CSR)
+ */
+
+ curidx = d->sbdma_remptr - d->sbdma_dscrtable;
+ {
+ /* XXX This is gross, ugly, and only here because justin hacked it
+ in to fix a problem without really understanding it.
+
+ It seems that, for whatever reason, this routine is invoked immediately upon the enabling of interrupts.
+ So then the Read below returns zero, making hwidx a negative number, and anti-hilarity
+ ensues.
+
+ I'm guessing there's a proper fix involving clearing out interrupt state from old packets
+ before enabling interrupts, but I'm not sure.
+
+ Anyways, this hack seems to work, and is Good Enough for 11 PM. :)
+
+ -Justin
+ */
+
+ uint64_t tmp = SBMAC_READCSR(d->sbdma_curdscr);
+ if (!tmp) {
+ break;
+ }
+ hwidx = (int) (((tmp & M_DMA_CURDSCR_ADDR) -
+ d->sbdma_dscrtable_phys) / sizeof(sbdmadscr_t));
+ }
+ /*
+ * If they're the same, that means we've processed all
+ * of the descriptors up to (but not including) the one that
+ * the hardware is working on right now.
+ */
+
+ if (curidx == hwidx) break;
+
+ /*
+ * Otherwise, get the packet's sk_buff ptr back
+ */
+
+ dsc = &(d->sbdma_dscrtable[curidx]);
+ sb = d->sbdma_ctxtable[curidx];
+ d->sbdma_ctxtable[curidx] = NULL;
+
+ /*
+ * Stats
+ */
+
+ sc->sbm_stats.tx_bytes += sb->len;
+ sc->sbm_stats.tx_packets++;
+
+ /*
+ * for transmits, we just free buffers.
+ */
+
+ dev_kfree_skb_irq(sb);
+
+ /*
+ * .. and advance to the next buffer.
+ */
+
+ d->sbdma_remptr = SBDMA_NEXTBUF(d,sbdma_remptr);
+
+ }
+
+ /*
+ * Decide if we should wake up the protocol or not.
+ * Other drivers seem to do this when we reach a low
+ * watermark on the transmit queue.
+ */
+
+ netif_wake_queue(d->sbdma_eth->sbm_dev);
+
+ spin_unlock_irqrestore(&(sc->sbm_lock), flags);
+
+}
+
+
+
+/**********************************************************************
+ * SBMAC_INITCTX(s)
+ *
+ * Initialize an Ethernet context structure - this is called
+ * once per MAC on the 1250. Memory is allocated here, so don't
+ * call it again from inside the ioctl routines that bring the
+ * interface up/down
+ *
+ * Input parameters:
+ * s - sbmac context structure
+ *
+ * Return value:
+ * 0
+ ********************************************************************* */
+
+static int sbmac_initctx(struct sbmac_softc *s)
+{
+
+ /*
+ * figure out the addresses of some ports
+ */
+
+ s->sbm_macenable = PKSEG1(s->sbm_base + R_MAC_ENABLE);
+ s->sbm_maccfg = PKSEG1(s->sbm_base + R_MAC_CFG);
+ s->sbm_fifocfg = PKSEG1(s->sbm_base + R_MAC_THRSH_CFG);
+ s->sbm_framecfg = PKSEG1(s->sbm_base + R_MAC_FRAMECFG);
+ s->sbm_rxfilter = PKSEG1(s->sbm_base + R_MAC_ADFILTER_CFG);
+ s->sbm_isr = PKSEG1(s->sbm_base + R_MAC_STATUS);
+ s->sbm_imr = PKSEG1(s->sbm_base + R_MAC_INT_MASK);
+ s->sbm_mdio = PKSEG1(s->sbm_base + R_MAC_MDIO);
+
+ s->sbm_phys[0] = 1;
+ s->sbm_phys[1] = 0;
+
+ s->sbm_phy_oldbmsr = 0;
+ s->sbm_phy_oldanlpar = 0;
+ s->sbm_phy_oldk1stsr = 0;
+ s->sbm_phy_oldlinkstat = 0;
+
+ /*
+ * Initialize the DMA channels. Right now, only one per MAC is used
+ * Note: Only do this _once_, as it allocates memory from the kernel!
+ */
+
+ sbdma_initctx(&(s->sbm_txdma),s,0,DMA_TX,SBMAC_MAX_TXDESCR);
+ sbdma_initctx(&(s->sbm_rxdma),s,0,DMA_RX,SBMAC_MAX_RXDESCR);
+
+ /*
+ * initial state is OFF
+ */
+
+ s->sbm_state = sbmac_state_off;
+
+ /*
+ * Initial speed is (XXX TEMP) 10MBit/s HDX no FC
+ */
+
+ s->sbm_speed = sbmac_speed_10;
+ s->sbm_duplex = sbmac_duplex_half;
+ s->sbm_fc = sbmac_fc_disabled;
+
+ return 0;
+}
+
+
+static void sbdma_uninitctx(struct sbmacdma_s *d)
+{
+ if (d->sbdma_dscrtable) {
+ KFREE(d->sbdma_dscrtable);
+ d->sbdma_dscrtable = NULL;
+ }
+
+ if (d->sbdma_ctxtable) {
+ KFREE(d->sbdma_ctxtable);
+ d->sbdma_ctxtable = NULL;
+ }
+}
+
+
+static void sbmac_uninitctx(struct sbmac_softc *sc)
+{
+ sbdma_uninitctx(&(sc->sbm_txdma));
+ sbdma_uninitctx(&(sc->sbm_rxdma));
+}
+
+
+/**********************************************************************
+ * SBMAC_CHANNEL_START(s)
+ *
+ * Start packet processing on this MAC.
+ *
+ * Input parameters:
+ * s - sbmac structure
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+static void sbmac_channel_start(struct sbmac_softc *s)
+{
+ uint64_t reg;
+ sbmac_port_t port;
+ uint64_t cfg,fifo,framecfg;
+ int idx;
+
+ /*
+ * Don't do this if running
+ */
+
+ if (s->sbm_state == sbmac_state_on) return;
+
+ /*
+ * Bring the controller out of reset, but leave it off.
+ */
+
+ SBMAC_WRITECSR(s->sbm_macenable,0);
+
+ /*
+ * Ignore all received packets
+ */
+
+ SBMAC_WRITECSR(s->sbm_rxfilter,0);
+
+ /*
+ * Calculate values for various control registers.
+ */
+
+ cfg = M_MAC_RETRY_EN |
+ M_MAC_TX_HOLD_SOP_EN |
+ V_MAC_TX_PAUSE_CNT_16K |
+ M_MAC_AP_STAT_EN |
+ M_MAC_FAST_SYNC |
+ M_MAC_SS_EN |
+ 0;
+
+ fifo = V_MAC_TX_WR_THRSH(4) | /* Must be '4' or '8' */
+ V_MAC_TX_RD_THRSH(4) |
+ V_MAC_TX_RL_THRSH(4) |
+ V_MAC_RX_PL_THRSH(4) |
+ V_MAC_RX_RD_THRSH(4) | /* Must be '4' */
+ V_MAC_RX_PL_THRSH(4) |
+ V_MAC_RX_RL_THRSH(8) |
+ 0;
+
+ framecfg = V_MAC_MIN_FRAMESZ_DEFAULT |
+ V_MAC_MAX_FRAMESZ_DEFAULT |
+ V_MAC_BACKOFF_SEL(1);
+
+
+ /*
+ * Clear out the hash address map
+ */
+
+ port = PKSEG1(s->sbm_base + R_MAC_HASH_BASE);
+ for (idx = 0; idx < MAC_HASH_COUNT; idx++) {
+ SBMAC_WRITECSR(port,0);
+ port += sizeof(uint64_t);
+ }
+
+ /*
+ * Clear out the exact-match table
+ */
+
+ port = PKSEG1(s->sbm_base + R_MAC_ADDR_BASE);
+ for (idx = 0; idx < MAC_ADDR_COUNT; idx++) {
+ SBMAC_WRITECSR(port,0);
+ port += sizeof(uint64_t);
+ }
+
+ /*
+ * Clear out the DMA Channel mapping table registers
+ */
+
+ port = PKSEG1(s->sbm_base + R_MAC_CHUP0_BASE);
+ for (idx = 0; idx < MAC_CHMAP_COUNT; idx++) {
+ SBMAC_WRITECSR(port,0);
+ port += sizeof(uint64_t);
+ }
+
+
+ port = PKSEG1(s->sbm_base + R_MAC_CHLO0_BASE);
+ for (idx = 0; idx < MAC_CHMAP_COUNT; idx++) {
+ SBMAC_WRITECSR(port,0);
+ port += sizeof(uint64_t);
+ }
+
+ /*
+ * Program the hardware address. It goes into the hardware-address
+ * register as well as the first filter register.
+ */
+
+ reg = sbmac_addr2reg(s->sbm_hwaddr);
+
+ port = PKSEG1(s->sbm_base + R_MAC_ADDR_BASE);
+ SBMAC_WRITECSR(port,reg);
+ port = PKSEG1(s->sbm_base + R_MAC_ETHERNET_ADDR);
+
+#ifdef CONFIG_SB1_PASS_1_WORKAROUNDS
+ /*
+ * Pass1 SB1250s do not receive packets addressed to the
+ * destination address in the R_MAC_ETHERNET_ADDR register.
+ * Set the value to zero.
+ */
+ SBMAC_WRITECSR(port,0);
+#else
+ SBMAC_WRITECSR(port,reg);
+#endif
+
+ /*
+ * Set the receive filter for no packets, and write values
+ * to the various config registers
+ */
+
+ SBMAC_WRITECSR(s->sbm_rxfilter,0);
+ SBMAC_WRITECSR(s->sbm_imr,0);
+ SBMAC_WRITECSR(s->sbm_framecfg,framecfg);
+ SBMAC_WRITECSR(s->sbm_fifocfg,fifo);
+ SBMAC_WRITECSR(s->sbm_maccfg,cfg);
+
+ /*
+ * Initialize DMA channels (rings should be ok now)
+ */
+
+ sbdma_channel_start(&(s->sbm_rxdma));
+ sbdma_channel_start(&(s->sbm_txdma));
+
+ /*
+ * Configure the speed, duplex, and flow control
+ */
+
+ sbmac_set_speed(s,s->sbm_speed);
+ sbmac_set_duplex(s,s->sbm_duplex,s->sbm_fc);
+
+ /*
+ * Fill the receive ring
+ */
+
+ sbdma_fillring(&(s->sbm_rxdma));
+
+ /*
+ * Turn on the rest of the bits in the enable register
+ */
+
+ SBMAC_WRITECSR(s->sbm_macenable,
+ M_MAC_RXDMA_EN0 |
+ M_MAC_TXDMA_EN0 |
+ M_MAC_RX_ENABLE |
+ M_MAC_TX_ENABLE);
+
+
+
+ /*
+ * Accept any kind of interrupt on TX and RX DMA channel 0
+ */
+ SBMAC_WRITECSR(s->sbm_imr,
+ (M_MAC_INT_CHANNEL << S_MAC_TX_CH0) |
+ (M_MAC_INT_CHANNEL << S_MAC_RX_CH0));
+
+ /*
+ * Enable receiving unicasts and broadcasts
+ */
+
+ SBMAC_WRITECSR(s->sbm_rxfilter,M_MAC_UCAST_EN | M_MAC_BCAST_EN);
+
+ /*
+ * we're running now.
+ */
+
+ s->sbm_state = sbmac_state_on;
+
+ /*
+ * Program multicast addresses
+ */
+
+ sbmac_setmulti(s);
+
+ /*
+ * If channel was in promiscuous mode before, turn that on
+ */
+
+ if (s->sbm_devflags & IFF_PROMISC) {
+ sbmac_promiscuous_mode(s,1);
+ }
+
+}
+
+
+/**********************************************************************
+ * SBMAC_CHANNEL_STOP(s)
+ *
+ * Stop packet processing on this MAC.
+ *
+ * Input parameters:
+ * s - sbmac structure
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+static void sbmac_channel_stop(struct sbmac_softc *s)
+{
+ uint64_t ctl;
+
+ /* don't do this if already stopped */
+
+ if (s->sbm_state == sbmac_state_off) return;
+
+ /* don't accept any packets, disable all interrupts */
+
+ SBMAC_WRITECSR(s->sbm_rxfilter,0);
+ SBMAC_WRITECSR(s->sbm_imr,0);
+
+ /* Turn off ticker */
+
+ /* XXX */
+
+ /* turn off receiver and transmitter */
+
+ ctl = SBMAC_READCSR(s->sbm_macenable);
+ ctl &= ~(M_MAC_RXDMA_EN0 | M_MAC_TXDMA_EN0);
+ SBMAC_WRITECSR(s->sbm_macenable,ctl);
+
+ /* We're stopped now. */
+
+ s->sbm_state = sbmac_state_off;
+
+
+ /* Empty the receive and transmit rings */
+
+ sbdma_emptyring(&(s->sbm_rxdma));
+ sbdma_emptyring(&(s->sbm_txdma));
+
+}
+
+/**********************************************************************
+ * SBMAC_SET_CHANNEL_STATE(state)
+ *
+ * Set the channel's state ON or OFF
+ *
+ * Input parameters:
+ * state - new state
+ *
+ * Return value:
+ * old state
+ ********************************************************************* */
+static sbmac_state_t sbmac_set_channel_state(struct sbmac_softc *sc,
+ sbmac_state_t state)
+{
+ sbmac_state_t oldstate = sc->sbm_state;
+
+ /*
+ * If same as previous state, return
+ */
+
+ if (state == oldstate) {
+ return oldstate;
+ }
+
+ /*
+ * If new state is ON, turn channel on
+ */
+
+ if (state == sbmac_state_on) {
+ sbmac_channel_start(sc);
+ }
+ else {
+ sbmac_channel_stop(sc);
+ }
+
+ /*
+ * Return previous state
+ */
+
+ return oldstate;
+}
+
+
+/**********************************************************************
+ * SBMAC_PROMISCUOUS_MODE(sc,onoff)
+ *
+ * Turn on or off promiscuous mode
+ *
+ * Input parameters:
+ * sc - softc
+ * onoff - 1 to turn on, 0 to turn off
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+static void sbmac_promiscuous_mode(struct sbmac_softc *sc,int onoff)
+{
+ uint64_t reg;
+
+ if (sc->sbm_state != sbmac_state_on) return;
+
+ if (onoff) {
+ reg = SBMAC_READCSR(sc->sbm_rxfilter);
+ reg |= M_MAC_ALLPKT_EN;
+ SBMAC_WRITECSR(sc->sbm_rxfilter,reg);
+ }
+ else {
+ reg = SBMAC_READCSR(sc->sbm_rxfilter);
+ reg &= ~M_MAC_ALLPKT_EN;
+ SBMAC_WRITECSR(sc->sbm_rxfilter,reg);
+ }
+}
+
+
+
+#if 0
+/**********************************************************************
+ * SBMAC_INIT_AND_START(sc)
+ *
+ * Stop the channel and restart it. This is generally used
+ * when we have to do something to the channel that requires
+ * a swift kick.
+ *
+ * Input parameters:
+ * sc - softc
+ ********************************************************************* */
+
+static void sbmac_init_and_start(struct sbmac_softc *sc)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&(sc->sbm_lock),flags);
+
+ sbmac_set_channel_state(sc,sbmac_state_on);
+
+ spin_unlock_irqrestore(&(sc->sbm_lock),flags);
+}
+#endif
+
+
+/**********************************************************************
+ * SBMAC_ADDR2REG(ptr)
+ *
+ * Convert six bytes into the 64-bit register value that
+ * we typically write into the SBMAC's address/mcast registers
+ *
+ * Input parameters:
+ * ptr - pointer to 6 bytes
+ *
+ * Return value:
+ * register value
+ ********************************************************************* */
+
+static uint64_t sbmac_addr2reg(unsigned char *ptr)
+{
+ uint64_t reg = 0;
+
+ ptr += 6;
+
+ reg |= (uint64_t) *(--ptr);
+ reg <<= 8;
+ reg |= (uint64_t) *(--ptr);
+ reg <<= 8;
+ reg |= (uint64_t) *(--ptr);
+ reg <<= 8;
+ reg |= (uint64_t) *(--ptr);
+ reg <<= 8;
+ reg |= (uint64_t) *(--ptr);
+ reg <<= 8;
+ reg |= (uint64_t) *(--ptr);
+
+ return reg;
+}
+
+
+/**********************************************************************
+ * SBMAC_SET_SPEED(s,speed)
+ *
+ * Configure LAN speed for the specified MAC.
+ * Warning: must be called when MAC is off!
+ *
+ * Input parameters:
+ * s - sbmac structure
+ * speed - speed to set MAC to (see sbmac_speed_t enum)
+ *
+ * Return value:
+ * 1 if successful
+ * 0 indicates invalid parameters
+ ********************************************************************* */
+
+static int sbmac_set_speed(struct sbmac_softc *s,sbmac_speed_t speed)
+{
+ uint64_t cfg;
+ uint64_t framecfg;
+
+ /*
+ * Save new current values
+ */
+
+ s->sbm_speed = speed;
+
+ if (s->sbm_state == sbmac_state_on) return 0; /* save for next restart */
+
+ /*
+ * Read current register values
+ */
+
+ cfg = SBMAC_READCSR(s->sbm_maccfg);
+ framecfg = SBMAC_READCSR(s->sbm_framecfg);
+
+ /*
+ * Mask out the stuff we want to change
+ */
+
+ cfg &= ~(M_MAC_BURST_EN | M_MAC_SPEED_SEL);
+ framecfg &= ~(M_MAC_IFG_RX | M_MAC_IFG_TX | M_MAC_IFG_THRSH |
+ M_MAC_SLOT_SIZE);
+
+ /*
+ * Now add in the new bits
+ */
+
+ switch (speed) {
+ case sbmac_speed_10:
+ framecfg |= V_MAC_IFG_RX_10 |
+ V_MAC_IFG_TX_10 |
+ K_MAC_IFG_THRSH_10 |
+ V_MAC_SLOT_SIZE_10;
+ cfg |= V_MAC_SPEED_SEL_10MBPS;
+ break;
+
+ case sbmac_speed_100:
+ framecfg |= V_MAC_IFG_RX_100 |
+ V_MAC_IFG_TX_100 |
+ V_MAC_IFG_THRSH_100 |
+ V_MAC_SLOT_SIZE_100;
+ cfg |= V_MAC_SPEED_SEL_100MBPS ;
+ break;
+
+ case sbmac_speed_1000:
+ framecfg |= V_MAC_IFG_RX_1000 |
+ V_MAC_IFG_TX_1000 |
+ V_MAC_IFG_THRSH_1000 |
+ V_MAC_SLOT_SIZE_1000;
+ cfg |= V_MAC_SPEED_SEL_1000MBPS | M_MAC_BURST_EN;
+ break;
+
+ case sbmac_speed_auto: /* XXX not implemented */
+ /* fall through */
+ default:
+ return 0;
+ }
+
+ /*
+ * Send the bits back to the hardware
+ */
+
+ SBMAC_WRITECSR(s->sbm_framecfg,framecfg);
+ SBMAC_WRITECSR(s->sbm_maccfg,cfg);
+
+ return 1;
+
+}
+
+/**********************************************************************
+ * SBMAC_SET_DUPLEX(s,duplex,fc)
+ *
+ * Set Ethernet duplex and flow control options for this MAC
+ * Warning: must be called when MAC is off!
+ *
+ * Input parameters:
+ * s - sbmac structure
+ * duplex - duplex setting (see sbmac_duplex_t)
+ * fc - flow control setting (see sbmac_fc_t)
+ *
+ * Return value:
+ * 1 if ok
+ * 0 if an invalid parameter combination was specified
+ ********************************************************************* */
+
+static int sbmac_set_duplex(struct sbmac_softc *s,sbmac_duplex_t duplex,sbmac_fc_t fc)
+{
+ uint64_t cfg;
+
+ /*
+ * Save new current values
+ */
+
+ s->sbm_duplex = duplex;
+ s->sbm_fc = fc;
+
+ if (s->sbm_state == sbmac_state_on) return 0; /* save for next restart */
+
+ /*
+ * Read current register values
+ */
+
+ cfg = SBMAC_READCSR(s->sbm_maccfg);
+
+ /*
+ * Mask off the stuff we're about to change
+ */
+
+ cfg &= ~(M_MAC_FC_SEL | M_MAC_FC_CMD | M_MAC_HDX_EN);
+
+
+ switch (duplex) {
+ case sbmac_duplex_half:
+ switch (fc) {
+ case sbmac_fc_disabled:
+ cfg |= M_MAC_HDX_EN | V_MAC_FC_CMD_DISABLED;
+ break;
+
+ case sbmac_fc_collision:
+ cfg |= M_MAC_HDX_EN | V_MAC_FC_CMD_ENABLED;
+ break;
+
+ case sbmac_fc_carrier:
+ cfg |= M_MAC_HDX_EN | V_MAC_FC_CMD_ENAB_FALSECARR;
+ break;
+
+ case sbmac_fc_auto: /* XXX not implemented */
+ /* fall through */
+ case sbmac_fc_frame: /* not valid in half duplex */
+ default: /* invalid selection */
+ return 0;
+ }
+ break;
+
+ case sbmac_duplex_full:
+ switch (fc) {
+ case sbmac_fc_disabled:
+ cfg |= V_MAC_FC_CMD_DISABLED;
+ break;
+
+ case sbmac_fc_frame:
+ cfg |= V_MAC_FC_CMD_ENABLED;
+ break;
+
+ case sbmac_fc_collision: /* not valid in full duplex */
+ case sbmac_fc_carrier: /* not valid in full duplex */
+ case sbmac_fc_auto: /* XXX not implemented */
+ /* fall through */
+ default:
+ return 0;
+ }
+ break;
+ case sbmac_duplex_auto:
+ /* XXX not implemented */
+ break;
+ }
+
+ /*
+ * Send the bits back to the hardware
+ */
+
+ SBMAC_WRITECSR(s->sbm_maccfg,cfg);
+
+ return 1;
+}
+
+
+
+
+/**********************************************************************
+ * SBMAC_INTR()
+ *
+ * Interrupt handler for MAC interrupts
+ *
+ * Input parameters:
+ * MAC structure
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+static void sbmac_intr(int irq,void *dev_instance,struct pt_regs *rgs)
+{
+ struct net_device *dev = (struct net_device *) dev_instance;
+ struct sbmac_softc *sc = (struct sbmac_softc *) (dev->priv);
+ uint64_t isr;
+
+ for (;;) {
+
+ /*
+ * Read the ISR (this clears the bits in the real register)
+ */
+
+ isr = SBMAC_READCSR(sc->sbm_isr);
+
+ if (isr == 0) break;
+
+ /*
+ * Transmits on channel 0
+ */
+
+ if (isr & (M_MAC_INT_CHANNEL << S_MAC_TX_CH0)) {
+ sbdma_tx_process(sc,&(sc->sbm_txdma));
+ }
+
+ /*
+ * Receives on channel 0
+ */
+
+ if (isr & (M_MAC_INT_CHANNEL << S_MAC_RX_CH0)) {
+ sbdma_rx_process(sc,&(sc->sbm_rxdma));
+ }
+ }
+
+}
+
+
+/**********************************************************************
+ * SBMAC_START_TX(skb,dev)
+ *
+ * Start output on the specified interface. Basically, we
+ * queue as many buffers as we can until the ring fills up, or
+ * we run off the end of the queue, whichever comes first.
+ *
+ * Input parameters:
+ *
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+static int sbmac_start_tx(struct sk_buff *skb, struct net_device *dev)
+{
+ struct sbmac_softc *sc = (struct sbmac_softc *)dev->priv;
+
+ /* lock eth irq */
+ spin_lock_irq (&sc->sbm_lock);
+
+ /*
+ * Put the buffer on the transmit ring. If we
+ * don't have room, stop the queue.
+ */
+
+ if (sbdma_add_txbuffer(&(sc->sbm_txdma),skb)) {
+ /* XXX save skb that we could not send */
+ netif_stop_queue(dev);
+ }
+
+ dev->trans_start = jiffies;
+
+ spin_unlock_irq (&sc->sbm_lock);
+
+ return 0;
+}
+
+/**********************************************************************
+ * SBMAC_SETMULTI(sc)
+ *
+ * Reprogram the multicast table into the hardware, given
+ * the list of multicasts associated with the interface
+ * structure.
+ *
+ * Input parameters:
+ * sc - softc
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+static void sbmac_setmulti(struct sbmac_softc *sc)
+{
+ uint64_t reg;
+ sbmac_port_t port;
+ int idx;
+ struct dev_mc_list *mclist;
+ struct net_device *dev = sc->sbm_dev;
+
+ /*
+ * Clear out entire multicast table. We do this by nuking
+ * the entire hash table and all the direct matches except
+ * the first one, which is used for our station address
+ */
+
+ for (idx = 1; idx < MAC_ADDR_COUNT; idx++) {
+ port = PKSEG1(sc->sbm_base + R_MAC_ADDR_BASE+(idx*sizeof(uint64_t)));
+ SBMAC_WRITECSR(port,0);
+ }
+
+ for (idx = 0; idx < MAC_HASH_COUNT; idx++) {
+ port = PKSEG1(sc->sbm_base + R_MAC_HASH_BASE+(idx*sizeof(uint64_t)));
+ SBMAC_WRITECSR(port,0);
+ }
+
+ /*
+ * Clear the filter to say we don't want any multicasts.
+ */
+
+ reg = SBMAC_READCSR(sc->sbm_rxfilter);
+ reg &= ~(M_MAC_MCAST_INV | M_MAC_MCAST_EN);
+ SBMAC_WRITECSR(sc->sbm_rxfilter,reg);
+
+ if (dev->flags & IFF_ALLMULTI) {
+ /*
+ * Enable ALL multicasts. Do this by inverting the
+ * multicast enable bit.
+ */
+ reg = SBMAC_READCSR(sc->sbm_rxfilter);
+ reg |= (M_MAC_MCAST_INV | M_MAC_MCAST_EN);
+ SBMAC_WRITECSR(sc->sbm_rxfilter,reg);
+ return;
+ }
+
+
+ /*
+ * Progam new multicast entries. For now, only use the
+ * perfect filter. In the future we'll need to use the
+ * hash filter if the perfect filter overflows
+ */
+
+ /* XXX only using perfect filter for now, need to use hash
+ * XXX if the table overflows */
+
+ idx = 1; /* skip station address */
+ mclist = dev->mc_list;
+ while (mclist && (idx < MAC_ADDR_COUNT)) {
+ reg = sbmac_addr2reg(mclist->dmi_addr);
+ port = PKSEG1(sc->sbm_base +
+ R_MAC_ADDR_BASE+(idx*sizeof(uint64_t)));
+ SBMAC_WRITECSR(port,reg);
+ idx++;
+ mclist = mclist->next;
+ }
+
+ /*
+ * Enable the "accept multicast bits" if we programmed at least one
+ * multicast.
+ */
+
+ if (idx > 1) {
+ reg = SBMAC_READCSR(sc->sbm_rxfilter);
+ reg |= M_MAC_MCAST_EN;
+ SBMAC_WRITECSR(sc->sbm_rxfilter,reg);
+ }
+}
+
+
+
+#if defined(SBMAC_ETH0_HWADDR) || defined(SBMAC_ETH1_HWADDR) || defined(SBMAC_ETH2_HWADDR)
+/**********************************************************************
+ * SBMAC_PARSE_XDIGIT(str)
+ *
+ * Parse a hex digit, returning its value
+ *
+ * Input parameters:
+ * str - character
+ *
+ * Return value:
+ * hex value, or -1 if invalid
+ ********************************************************************* */
+
+static int sbmac_parse_xdigit(char str)
+{
+ int digit;
+
+ if ((str >= '0') && (str <= '9')) digit = str - '0';
+ else if ((str >= 'a') && (str <= 'f')) digit = str - 'a' + 10;
+ else if ((str >= 'A') && (str <= 'F')) digit = str - 'A' + 10;
+ else return -1;
+
+ return digit;
+}
+
+/**********************************************************************
+ * SBMAC_PARSE_HWADDR(str,hwaddr)
+ *
+ * Convert a string in the form xx:xx:xx:xx:xx:xx into a 6-byte
+ * Ethernet address.
+ *
+ * Input parameters:
+ * str - string
+ * hwaddr - pointer to hardware address
+ *
+ * Return value:
+ * 0 if ok, else -1
+ ********************************************************************* */
+
+static int sbmac_parse_hwaddr(char *str,u_char *hwaddr)
+{
+ int digit1,digit2;
+ int idx = 6;
+
+ while (*str && (idx > 0)) {
+ digit1 = sbmac_parse_xdigit(*str);
+ if (digit1 < 0) return -1;
+ str++;
+ if (!*str) return -1;
+
+ if ((*str == ':') || (*str == '-')) {
+ digit2 = digit1;
+ digit1 = 0;
+ }
+ else {
+ digit2 = sbmac_parse_xdigit(*str);
+ if (digit2 < 0) return -1;
+ str++;
+ }
+
+ *hwaddr++ = (digit1 << 4) | digit2;
+ idx--;
+
+ if (*str == '-') str++;
+ if (*str == ':') str++;
+ }
+ return 0;
+}
+#endif
+
+/**********************************************************************
+ * SBMAC_INIT(dev)
+ *
+ * Attach routine - init hardware and hook ourselves into linux
+ *
+ * Input parameters:
+ * dev - net_device structure
+ *
+ * Return value:
+ * status
+ ********************************************************************* */
+
+static int sbmac_init(struct net_device *dev)
+{
+ struct sbmac_softc *sc;
+ u_char *eaddr;
+ uint64_t ea_reg;
+ int idx;
+
+ sc = (struct sbmac_softc *)dev->priv;
+
+ /* Determine controller base address */
+
+ sc->sbm_base = (sbmac_port_t) dev->base_addr;
+ sc->sbm_dev = dev;
+
+ eaddr = sc->sbm_hwaddr;
+
+ /*
+ * Read the ethernet address. The firwmare left this programmed
+ * for us in the ethernet address register for each mac.
+ */
+
+ ea_reg = SBMAC_READCSR(PKSEG1(sc->sbm_base + R_MAC_ETHERNET_ADDR));
+ SBMAC_WRITECSR(PKSEG1(sc->sbm_base + R_MAC_ETHERNET_ADDR), 0);
+ for (idx = 0; idx < 6; idx++) {
+ eaddr[idx] = (uint8_t) (ea_reg & 0xFF);
+ ea_reg >>= 8;
+ }
+
+
+ for (idx = 0; idx < 6; idx++) {
+ dev->dev_addr[idx] = eaddr[idx];
+ }
+
+
+ /*
+ * Init packet size
+ */
+
+ sc->sbm_buffersize = ENET_PACKET_SIZE + CACHELINESIZE*2 + ETHER_ALIGN;
+
+ /*
+ * Initialize context (get pointers to registers and stuff), then
+ * allocate the memory for the descriptor tables.
+ */
+
+ sbmac_initctx(sc);
+
+
+ /*
+ * Display Ethernet address (this is called during the config process
+ * so we need to finish off the config message that was being displayed)
+ */
+ printk(KERN_INFO
+ "%s: SB1250 Ethernet at 0x%08lX, address: %02X-%02X-%02X-%02X-%02X-%02X\n",
+ dev->name,
+ (unsigned long) sc->sbm_base,
+ eaddr[0],eaddr[1],eaddr[2],eaddr[3],eaddr[4],eaddr[5]);
+
+ /*
+ * Set up Linux device callins
+ */
+
+ spin_lock_init(&(sc->sbm_lock));
+
+ ether_setup(dev);
+ dev->open = sbmac_open;
+ dev->hard_start_xmit = sbmac_start_tx;
+ dev->stop = sbmac_close;
+ dev->get_stats = sbmac_get_stats;
+ dev->set_multicast_list = sbmac_set_rx_mode;
+ dev->do_ioctl = sbmac_mii_ioctl;
+ dev->tx_timeout = sbmac_tx_timeout;
+ dev->watchdog_timeo = TX_TIMEOUT;
+
+ return 0;
+
+}
+
+
+static int sbmac_open(struct net_device *dev)
+{
+ struct sbmac_softc *sc = (struct sbmac_softc *)dev->priv;
+
+ MOD_INC_USE_COUNT;
+
+ if (debug > 1) {
+ printk(KERN_DEBUG "%s: sbmac_open() irq %d.\n", dev->name, dev->irq);
+ }
+
+ /*
+ * map/route interrupt
+ */
+
+ if (request_irq(dev->irq, &sbmac_intr, SA_SHIRQ, dev->name, dev)) {
+ MOD_DEC_USE_COUNT;
+ return -EBUSY;
+ }
+
+ /*
+ * Configure default speed
+ */
+
+ sbmac_mii_poll(sc,1);
+
+ /*
+ * Turn on the channel
+ */
+
+ sbmac_set_channel_state(sc,sbmac_state_on);
+
+ /*
+ * XXX Station address is in dev->dev_addr
+ */
+
+ if (dev->if_port == 0)
+ dev->if_port = 0;
+
+ netif_start_queue(dev);
+
+ sbmac_set_rx_mode(dev);
+
+ /* Set the timer to check for link beat. */
+ init_timer(&sc->sbm_timer);
+ sc->sbm_timer.expires = jiffies + 2;
+ sc->sbm_timer.data = (unsigned long)dev;
+ sc->sbm_timer.function = &sbmac_timer;
+ add_timer(&sc->sbm_timer);
+
+ return 0;
+}
+
+
+
+static int sbmac_mii_poll(struct sbmac_softc *s,int noisy)
+{
+ int bmsr,bmcr,k1stsr,anlpar;
+ int chg;
+ char buffer[100];
+ char *p = buffer;
+
+ /* Read the mode status and mode control registers. */
+ bmsr = sbmac_mii_read(s,s->sbm_phys[0],MII_BMSR);
+ bmcr = sbmac_mii_read(s,s->sbm_phys[0],MII_BMCR);
+
+ /* get the link partner status */
+ anlpar = sbmac_mii_read(s,s->sbm_phys[0],MII_ANLPAR);
+
+ /* if supported, read the 1000baseT register */
+ if (bmsr & BMSR_1000BT_XSR) {
+ k1stsr = sbmac_mii_read(s,s->sbm_phys[0],MII_K1STSR);
+ }
+ else {
+ k1stsr = 0;
+ }
+
+ chg = 0;
+
+ if ((bmsr & BMSR_LINKSTAT) == 0) {
+ /*
+ * If link status is down, clear out old info so that when
+ * it comes back up it will force us to reconfigure speed
+ */
+ s->sbm_phy_oldbmsr = 0;
+ s->sbm_phy_oldanlpar = 0;
+ s->sbm_phy_oldk1stsr = 0;
+ return 0;
+ }
+
+ if ((s->sbm_phy_oldbmsr != bmsr) ||
+ (s->sbm_phy_oldanlpar != anlpar) ||
+ (s->sbm_phy_oldk1stsr != k1stsr)) {
+ if (debug > 1) {
+ printk(KERN_DEBUG "%s: bmsr:%x/%x anlpar:%x/%x k1stsr:%x/%x\n",
+ s->sbm_dev->name,
+ s->sbm_phy_oldbmsr,bmsr,
+ s->sbm_phy_oldanlpar,anlpar,
+ s->sbm_phy_oldk1stsr,k1stsr);
+ }
+ s->sbm_phy_oldbmsr = bmsr;
+ s->sbm_phy_oldanlpar = anlpar;
+ s->sbm_phy_oldk1stsr = k1stsr;
+ chg = 1;
+ }
+
+ if (chg == 0) return 0;
+
+ p += sprintf(p,"Link speed: ");
+
+ if (k1stsr & K1STSR_LP1KFD) {
+ s->sbm_speed = sbmac_speed_1000;
+ s->sbm_duplex = sbmac_duplex_full;
+ s->sbm_fc = sbmac_fc_frame;
+ p += sprintf(p,"1000BaseT FDX");
+ }
+ else if (k1stsr & K1STSR_LP1KHD) {
+ s->sbm_speed = sbmac_speed_1000;
+ s->sbm_duplex = sbmac_duplex_half;
+ s->sbm_fc = sbmac_fc_disabled;
+ p += sprintf(p,"1000BaseT HDX");
+ }
+ else if (anlpar & ANLPAR_TXFD) {
+ s->sbm_speed = sbmac_speed_100;
+ s->sbm_duplex = sbmac_duplex_full;
+ s->sbm_fc = (anlpar & ANLPAR_PAUSE) ? sbmac_fc_frame : sbmac_fc_disabled;
+ p += sprintf(p,"100BaseT FDX");
+ }
+ else if (anlpar & ANLPAR_TXHD) {
+ s->sbm_speed = sbmac_speed_100;
+ s->sbm_duplex = sbmac_duplex_half;
+ s->sbm_fc = sbmac_fc_disabled;
+ p += sprintf(p,"100BaseT HDX");
+ }
+ else if (anlpar & ANLPAR_10FD) {
+ s->sbm_speed = sbmac_speed_10;
+ s->sbm_duplex = sbmac_duplex_full;
+ s->sbm_fc = sbmac_fc_frame;
+ p += sprintf(p,"10BaseT FDX");
+ }
+ else if (anlpar & ANLPAR_10HD) {
+ s->sbm_speed = sbmac_speed_10;
+ s->sbm_duplex = sbmac_duplex_half;
+ s->sbm_fc = sbmac_fc_collision;
+ p += sprintf(p,"10BaseT HDX");
+ }
+ else {
+ p += sprintf(p,"Unknown");
+ }
+
+ if (noisy) {
+ printk(KERN_INFO "%s: %s\n",s->sbm_dev->name,buffer);
+ }
+
+ return 1;
+}
+
+
+
+
+static void sbmac_timer(unsigned long data)
+{
+ struct net_device *dev = (struct net_device *)data;
+ struct sbmac_softc *sc = (struct sbmac_softc *)dev->priv;
+ int next_tick = HZ;
+ int mii_status;
+
+ spin_lock_irq (&sc->sbm_lock);
+
+ /* make IFF_RUNNING follow the MII status bit "Link established" */
+ mii_status = sbmac_mii_read(sc, sc->sbm_phys[0], MII_BMSR);
+
+ if ( (mii_status & BMSR_LINKSTAT) != (sc->sbm_phy_oldlinkstat) ) {
+ sc->sbm_phy_oldlinkstat = mii_status & BMSR_LINKSTAT;
+ if (mii_status & BMSR_LINKSTAT) {
+ netif_carrier_on(dev);
+ }
+ else {
+ netif_carrier_off(dev);
+ }
+ }
+
+ /*
+ * Poll the PHY to see what speed we should be running at
+ */
+
+ if (sbmac_mii_poll(sc,1)) {
+ if (sc->sbm_state != sbmac_state_off) {
+ /*
+ * something changed, restart the channel
+ */
+ if (debug > 1) {
+ printk("%s: restarting channel because speed changed\n",
+ sc->sbm_dev->name);
+ }
+ sbmac_channel_stop(sc);
+ sbmac_channel_start(sc);
+ }
+ }
+
+ spin_unlock_irq (&sc->sbm_lock);
+
+ sc->sbm_timer.expires = jiffies + next_tick;
+ add_timer(&sc->sbm_timer);
+}
+
+
+static void sbmac_tx_timeout (struct net_device *dev)
+{
+ struct sbmac_softc *sc = (struct sbmac_softc *) dev->priv;
+
+ spin_lock_irq (&sc->sbm_lock);
+
+
+ dev->trans_start = jiffies;
+ sc->sbm_stats.tx_errors++;
+
+ spin_unlock_irq (&sc->sbm_lock);
+
+ printk (KERN_WARNING "%s: Transmit timed out\n",dev->name);
+}
+
+
+
+
+static struct net_device_stats *sbmac_get_stats(struct net_device *dev)
+{
+ struct sbmac_softc *sc = (struct sbmac_softc *)dev->priv;
+ unsigned long flags;
+
+ spin_lock_irqsave(&sc->sbm_lock, flags);
+
+ /* XXX update other stats here */
+
+ spin_unlock_irqrestore(&sc->sbm_lock, flags);
+
+ return &sc->sbm_stats;
+}
+
+
+
+static void sbmac_set_rx_mode(struct net_device *dev)
+{
+ unsigned long flags;
+ int msg_flag = 0;
+ struct sbmac_softc *sc = (struct sbmac_softc *)dev->priv;
+
+ spin_lock_irqsave(&sc->sbm_lock, flags);
+ if ((dev->flags ^ sc->sbm_devflags) & IFF_PROMISC) {
+ /*
+ * Promiscuous changed.
+ */
+
+ if (dev->flags & IFF_PROMISC) {
+ /* Unconditionally log net taps. */
+ msg_flag = 1;
+ sbmac_promiscuous_mode(sc,1);
+ }
+ else {
+ msg_flag = 2;
+ sbmac_promiscuous_mode(sc,0);
+ }
+ }
+ spin_unlock_irqrestore(&sc->sbm_lock, flags);
+
+ if (msg_flag) {
+ printk(KERN_NOTICE "%s: Promiscuous mode %sabled.\n", dev->name,(msg_flag==1)?"en":"dis");
+ }
+
+ /*
+ * Program the multicasts. Do this every time.
+ */
+
+ sbmac_setmulti(sc);
+
+}
+
+static int sbmac_mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+ struct sbmac_softc *sc = (struct sbmac_softc *)dev->priv;
+ u16 *data = (u16 *)&rq->ifr_data;
+ unsigned long flags;
+ int retval;
+
+ spin_lock_irqsave(&sc->sbm_lock, flags);
+ retval = 0;
+
+ switch(cmd) {
+ case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */
+ data[0] = sc->sbm_phys[0] & 0x1f;
+ /* Fall Through */
+ case SIOCDEVPRIVATE+1: /* Read the specified MII register. */
+ data[3] = sbmac_mii_read(sc, data[0] & 0x1f, data[1] & 0x1f);
+ break;
+ case SIOCDEVPRIVATE+2: /* Write the specified MII register */
+ if (!capable(CAP_NET_ADMIN)) {
+ retval = -EPERM;
+ break;
+ }
+ if (debug > 1) {
+ printk(KERN_DEBUG "%s: sbmac_mii_ioctl: write %02X %02X %02X\n",dev->name,
+ data[0],data[1],data[2]);
+ }
+ sbmac_mii_write(sc, data[0] & 0x1f, data[1] & 0x1f, data[2]);
+ break;
+ default:
+ retval = -EOPNOTSUPP;
+ }
+
+ spin_unlock_irqrestore(&sc->sbm_lock, flags);
+ return retval;
+}
+
+static int sbmac_close(struct net_device *dev)
+{
+ struct sbmac_softc *sc = (struct sbmac_softc *)dev->priv;
+ unsigned long flags;
+
+ sbmac_set_channel_state(sc,sbmac_state_off);
+
+ del_timer_sync(&sc->sbm_timer);
+
+ spin_lock_irqsave(&sc->sbm_lock, flags);
+
+ netif_stop_queue(dev);
+
+ if (debug > 1) {
+ printk(KERN_DEBUG "%s: Shutting down ethercard\n",dev->name);
+ }
+
+ spin_unlock_irqrestore(&sc->sbm_lock, flags);
+
+ /* Make sure there is no irq-handler running on a different CPU. */
+ synchronize_irq();
+
+ free_irq(dev->irq, dev);
+
+ sbdma_emptyring(&(sc->sbm_txdma));
+ sbdma_emptyring(&(sc->sbm_rxdma));
+
+ MOD_DEC_USE_COUNT;
+
+ return 0;
+}
+
+
+
+#if defined(SBMAC_ETH0_HWADDR) || defined(SBMAC_ETH1_HWADDR) || defined(SBMAC_ETH2_HWADDR)
+static void
+sbmac_setup_hwaddr(int chan,char *addr)
+{
+ uint8_t eaddr[6];
+ uint64_t val;
+ sbmac_port_t port;
+
+ port = A_MAC_CHANNEL_BASE(chan);
+ sbmac_parse_hwaddr(addr,eaddr);
+ val = sbmac_addr2reg(eaddr);
+ SBMAC_WRITECSR(PKSEG1(port+R_MAC_ETHERNET_ADDR),val);
+ val = SBMAC_READCSR(PKSEG1(port+R_MAC_ETHERNET_ADDR));
+}
+#endif
+
+static struct net_device *dev_sbmac[MAX_UNITS] = {0,0,0};
+
+static int __init
+sbmac_init_module(void)
+{
+ int idx;
+ int macidx = 0;
+ struct net_device *dev;
+ sbmac_port_t port;
+
+ /*
+ * For bringup when not using the firmware, we can pre-fill
+ * the MAC addresses using the environment variables
+ * specified in this file (or maybe from the config file?)
+ */
+#ifdef SBMAC_ETH0_HWADDR
+ sbmac_setup_hwaddr(0,SBMAC_ETH0_HWADDR);
+#endif
+#ifdef SBMAC_ETH1_HWADDR
+ sbmac_setup_hwaddr(1,SBMAC_ETH1_HWADDR);
+#endif
+#ifdef SBMAC_ETH2_HWADDR
+ sbmac_setup_hwaddr(2,SBMAC_ETH2_HWADDR);
+#endif
+
+ /*
+ * Walk through the Ethernet controllers and find
+ * those who have their MAC addresses set.
+ */
+
+ for (idx = 0; idx < MAX_UNITS; idx++) {
+
+ /*
+ * This is the base address of the MAC.
+ */
+
+ port = A_MAC_CHANNEL_BASE(idx);
+
+ /*
+ * The R_MAC_ETHERNET_ADDR register will be set to some nonzero
+ * value for us by the firmware if we're going to use this MAC.
+ * If we find a zero, skip this MAC.
+ */
+
+ if (SBMAC_READCSR(PKSEG1(port+R_MAC_ETHERNET_ADDR)) == 0) {
+ continue;
+ }
+
+ /*
+ * Okay, cool. Initialize this MAC.
+ */
+
+ dev = init_etherdev(NULL,sizeof(struct sbmac_softc));
+ if (!dev) break; /* problems, get out now. */
+ dev->irq = K_INT_MAC_0 + idx;
+ dev->base_addr = port;
+ dev->mem_end = 0;
+ /*dev->init = sbmac_init;*/
+ sbmac_init(dev);
+
+ dev_sbmac[macidx] = dev;
+ macidx++;
+
+ }
+
+ /*
+ * Should we care, 'macidx' is the total number of enabled MACs.
+ */
+
+ return 0;
+}
+
+
+static void __exit
+sbmac_cleanup_module(void)
+{
+ int idx;
+ struct net_device *dev;
+ for (idx = 0; idx < MAX_UNITS; idx++) {
+ dev = dev_sbmac[idx];
+ if (dev == NULL) continue;
+ if (dev->priv != NULL) {
+ struct sbmac_softc *sc = (struct sbmac_softc *) dev->priv;
+
+ unregister_netdev(dev);
+
+ sbmac_uninitctx(sc);
+
+ KFREE(sc);
+ }
+ KFREE(dev);
+ dev_sbmac[idx] = NULL;
+ }
+}
+
+module_init(sbmac_init_module);
+module_exit(sbmac_cleanup_module);
diff --git a/drivers/net/skfp/skfddi.c b/drivers/net/skfp/skfddi.c
index e748b5c9aa4c9..6b67bce267b87 100644
--- a/drivers/net/skfp/skfddi.c
+++ b/drivers/net/skfp/skfddi.c
@@ -520,8 +520,6 @@ static void init_dev(struct net_device *dev, u_long iobase)
{
/* Initialize new device structure */
- dev->rmem_end = 0; /* shared memory isn't used */
- dev->rmem_start = 0; /* shared memory isn't used */
dev->mem_end = 0; /* shared memory isn't used */
dev->mem_start = 0; /* shared memory isn't used */
dev->base_addr = iobase; /* save port (I/O) base address */
diff --git a/drivers/net/smc-mca.c b/drivers/net/smc-mca.c
index 50baaf26db693..7d947eaa40950 100644
--- a/drivers/net/smc-mca.c
+++ b/drivers/net/smc-mca.c
@@ -299,8 +299,8 @@ int __init ultramca_probe(struct net_device *dev)
ei_status.rx_start_page = START_PG + TX_PAGES;
ei_status.stop_page = num_pages;
- dev->rmem_start = dev->mem_start + TX_PAGES * 256;
- dev->mem_end = dev->rmem_end =
+ ei_status.rmem_start = dev->mem_start + TX_PAGES * 256;
+ dev->mem_end = ei_status.rmem_end =
dev->mem_start + (ei_status.stop_page - START_PG) * 256;
printk(KERN_INFO ", IRQ %d memory %#lx-%#lx.\n",
@@ -387,12 +387,12 @@ static void ultramca_block_input(struct net_device *dev, int count, struct sk_bu
{
unsigned long xfer_start = dev->mem_start + ring_offset - (START_PG << 8);
- if (xfer_start + count > dev->rmem_end) {
+ if (xfer_start + count > ei_status.rmem_end) {
/* We must wrap the input move. */
- int semi_count = dev->rmem_end - xfer_start;
+ int semi_count = ei_status.rmem_end - xfer_start;
isa_memcpy_fromio(skb->data, xfer_start, semi_count);
count -= semi_count;
- isa_memcpy_fromio(skb->data + semi_count, dev->rmem_start, count);
+ isa_memcpy_fromio(skb->data + semi_count, ei_status.rmem_start, count);
} else {
/* Packet is in one chunk -- we can copy + cksum. */
isa_eth_io_copy_and_sum(skb, xfer_start, count, 0);
diff --git a/drivers/net/smc-ultra.c b/drivers/net/smc-ultra.c
index c6ac05f774bbf..5dcb815b767fe 100644
--- a/drivers/net/smc-ultra.c
+++ b/drivers/net/smc-ultra.c
@@ -251,8 +251,8 @@ static int __init ultra_probe1(struct net_device *dev, int ioaddr)
ei_status.rx_start_page = START_PG + TX_PAGES;
ei_status.stop_page = num_pages;
- dev->rmem_start = dev->mem_start + TX_PAGES*256;
- dev->mem_end = dev->rmem_end
+ ei_status.rmem_start = dev->mem_start + TX_PAGES*256;
+ dev->mem_end = ei_status.rmem_end
= dev->mem_start + (ei_status.stop_page - START_PG)*256;
if (piomode) {
@@ -403,12 +403,12 @@ ultra_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ri
/* Enable shared memory. */
outb(ULTRA_MEMENB, dev->base_addr - ULTRA_NIC_OFFSET);
- if (xfer_start + count > dev->rmem_end) {
+ if (xfer_start + count > ei_status.rmem_end) {
/* We must wrap the input move. */
- int semi_count = dev->rmem_end - xfer_start;
+ int semi_count = ei_status.rmem_end - xfer_start;
isa_memcpy_fromio(skb->data, xfer_start, semi_count);
count -= semi_count;
- isa_memcpy_fromio(skb->data + semi_count, dev->rmem_start, count);
+ isa_memcpy_fromio(skb->data + semi_count, ei_status.rmem_start, count);
} else {
/* Packet is in one chunk -- we can copy + cksum. */
isa_eth_io_copy_and_sum(skb, xfer_start, count, 0);
diff --git a/drivers/net/smc-ultra32.c b/drivers/net/smc-ultra32.c
index b0c295b5593d3..52861584519c6 100644
--- a/drivers/net/smc-ultra32.c
+++ b/drivers/net/smc-ultra32.c
@@ -231,8 +231,8 @@ static int __init ultra32_probe1(struct net_device *dev, int ioaddr)
/* All Ultra32 cards have 32KB memory with an 8KB window. */
ei_status.stop_page = 128;
- dev->rmem_start = dev->mem_start + TX_PAGES*256;
- dev->mem_end = dev->rmem_end = dev->mem_start + 0x1fff;
+ ei_status.rmem_start = dev->mem_start + TX_PAGES*256;
+ dev->mem_end = ei_status.rmem_end = dev->mem_start + 0x1fff;
printk(", IRQ %d, 32KB memory, 8KB window at 0x%lx-0x%lx.\n",
dev->irq, dev->mem_start, dev->mem_end);
@@ -353,7 +353,7 @@ static void ultra32_block_input(struct net_device *dev,
} else {
/* Select first 8KB Window. */
outb(ei_status.reg0, RamReg);
- isa_memcpy_fromio(skb->data + semi_count, dev->rmem_start, count);
+ isa_memcpy_fromio(skb->data + semi_count, ei_status.rmem_start, count);
}
} else {
/* Packet is in one chunk -- we can copy + cksum. */
diff --git a/drivers/net/strip.c b/drivers/net/strip.c
index 1ae2fb3fb71f1..98577b85d1389 100644
--- a/drivers/net/strip.c
+++ b/drivers/net/strip.c
@@ -2080,6 +2080,7 @@ static void deliver_packet(struct strip *strip_info, STRIP_Header *header, __u16
#ifdef EXT_COUNTERS
strip_info->rx_bytes += packetlen;
#endif
+ skb->dev->last_rx = jiffies;
netif_rx(skb);
}
}
diff --git a/drivers/net/sun3_82586.c b/drivers/net/sun3_82586.c
new file mode 100644
index 0000000000000..0fad42a4021ca
--- /dev/null
+++ b/drivers/net/sun3_82586.c
@@ -0,0 +1,1206 @@
+/*
+ * Sun3 i82586 Ethernet driver
+ *
+ * Cloned from ni52.c for the Sun3 by Sam Creasey (sammy@sammy.net)
+ *
+ * Original copyright follows:
+ * --------------------------
+ *
+ * net-3-driver for the NI5210 card (i82586 Ethernet chip)
+ *
+ * This is an extension to the Linux operating system, and is covered by the
+ * same Gnu Public License that covers that work.
+ *
+ * Alphacode 0.82 (96/09/29) for Linux 2.0.0 (or later)
+ * Copyrights (c) 1994,1995,1996 by M.Hipp (hippm@informatik.uni-tuebingen.de)
+ * --------------------------
+ *
+ * Consult ni52.c for further notes from the original driver.
+ *
+ * This incarnation currently supports the OBIO version of the i82586 chip
+ * used in certain sun3 models. It should be fairly doable to expand this
+ * to support VME if I should every acquire such a board.
+ *
+ */
+
+static int debuglevel = 0; /* debug-printk 0: off 1: a few 2: more */
+static int automatic_resume = 0; /* experimental .. better should be zero */
+static int rfdadd = 0; /* rfdadd=1 may be better for 8K MEM cards */
+static int fifo=0x8; /* don't change */
+
+/* #define REALLY_SLOW_IO */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/idprom.h>
+#include <asm/machines.h>
+#include <asm/sun3mmu.h>
+#include <asm/dvma.h>
+#include <asm/byteorder.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+
+#include "sun3_82586.h"
+
+#define DEBUG /* debug on */
+#define SYSBUSVAL 0 /* 16 Bit */
+
+#define sun3_attn586() {*(volatile unsigned char *)(dev->base_addr) |= IEOB_ATTEN; *(volatile unsigned char *)(dev->base_addr) &= ~IEOB_ATTEN;}
+#define sun3_reset586() {*(volatile unsigned char *)(dev->base_addr) = 0; udelay(100); *(volatile unsigned char *)(dev->base_addr) = IEOB_NORSET;}
+#define sun3_disint() {*(volatile unsigned char *)(dev->base_addr) &= ~IEOB_IENAB;}
+#define sun3_enaint() {*(volatile unsigned char *)(dev->base_addr) |= IEOB_IENAB;}
+#define sun3_active() {*(volatile unsigned char *)(dev->base_addr) |= (IEOB_IENAB|IEOB_ONAIR|IEOB_NORSET);}
+
+#define make32(ptr16) (p->memtop + (swab16((unsigned short) (ptr16))) )
+#define make24(ptr32) (char *)swab32(( ((unsigned long) (ptr32)) - p->base))
+#define make16(ptr32) (swab16((unsigned short) ((unsigned long)(ptr32) - (unsigned long) p->memtop )))
+
+/******************* how to calculate the buffers *****************************
+
+ * IMPORTANT NOTE: if you configure only one NUM_XMIT_BUFFS, the driver works
+ * --------------- in a different (more stable?) mode. Only in this mode it's
+ * possible to configure the driver with 'NO_NOPCOMMANDS'
+
+sizeof(scp)=12; sizeof(scb)=16; sizeof(iscp)=8;
+sizeof(scp)+sizeof(iscp)+sizeof(scb) = 36 = INIT
+sizeof(rfd) = 24; sizeof(rbd) = 12;
+sizeof(tbd) = 8; sizeof(transmit_cmd) = 16;
+sizeof(nop_cmd) = 8;
+
+ * if you don't know the driver, better do not change these values: */
+
+#define RECV_BUFF_SIZE 1536 /* slightly oversized */
+#define XMIT_BUFF_SIZE 1536 /* slightly oversized */
+#define NUM_XMIT_BUFFS 1 /* config for 32K shmem */
+#define NUM_RECV_BUFFS_8 4 /* config for 32K shared mem */
+#define NUM_RECV_BUFFS_16 9 /* config for 32K shared mem */
+#define NUM_RECV_BUFFS_32 16 /* config for 32K shared mem */
+#define NO_NOPCOMMANDS /* only possible with NUM_XMIT_BUFFS=1 */
+
+/**************************************************************************/
+
+/* different DELAYs */
+#define DELAY(x) mdelay(32 * x);
+#define DELAY_16(); { udelay(16); }
+#define DELAY_18(); { udelay(4); }
+
+/* wait for command with timeout: */
+#define WAIT_4_SCB_CMD() \
+{ int i; \
+ for(i=0;i<16384;i++) { \
+ if(!p->scb->cmd_cuc) break; \
+ DELAY_18(); \
+ if(i == 16383) { \
+ printk("%s: scb_cmd timed out: %04x,%04x .. disabling i82586!!\n",dev->name,p->scb->cmd_cuc,p->scb->cus); \
+ if(!p->reseted) { p->reseted = 1; sun3_reset586(); } } } }
+
+#define WAIT_4_SCB_CMD_RUC() { int i; \
+ for(i=0;i<16384;i++) { \
+ if(!p->scb->cmd_ruc) break; \
+ DELAY_18(); \
+ if(i == 16383) { \
+ printk("%s: scb_cmd (ruc) timed out: %04x,%04x .. disabling i82586!!\n",dev->name,p->scb->cmd_ruc,p->scb->rus); \
+ if(!p->reseted) { p->reseted = 1; sun3_reset586(); } } } }
+
+#define WAIT_4_STAT_COMPL(addr) { int i; \
+ for(i=0;i<32767;i++) { \
+ if(swab16((addr)->cmd_status) & STAT_COMPL) break; \
+ DELAY_16(); DELAY_16(); } }
+
+static int sun3_82586_probe1(struct net_device *dev,int ioaddr);
+static void sun3_82586_interrupt(int irq,void *dev_id,struct pt_regs *reg_ptr);
+static int sun3_82586_open(struct net_device *dev);
+static int sun3_82586_close(struct net_device *dev);
+static int sun3_82586_send_packet(struct sk_buff *,struct net_device *);
+static struct net_device_stats *sun3_82586_get_stats(struct net_device *dev);
+static void set_multicast_list(struct net_device *dev);
+static void sun3_82586_timeout(struct net_device *dev);
+#if 0
+static void sun3_82586_dump(struct net_device *,void *);
+#endif
+
+/* helper-functions */
+static int init586(struct net_device *dev);
+static int check586(struct net_device *dev,char *where,unsigned size);
+static void alloc586(struct net_device *dev);
+static void startrecv586(struct net_device *dev);
+static void *alloc_rfa(struct net_device *dev,void *ptr);
+static void sun3_82586_rcv_int(struct net_device *dev);
+static void sun3_82586_xmt_int(struct net_device *dev);
+static void sun3_82586_rnr_int(struct net_device *dev);
+
+struct priv
+{
+ struct net_device_stats stats;
+ unsigned long base;
+ char *memtop;
+ long int lock;
+ int reseted;
+ volatile struct rfd_struct *rfd_last,*rfd_top,*rfd_first;
+ volatile struct scp_struct *scp; /* volatile is important */
+ volatile struct iscp_struct *iscp; /* volatile is important */
+ volatile struct scb_struct *scb; /* volatile is important */
+ volatile struct tbd_struct *xmit_buffs[NUM_XMIT_BUFFS];
+ volatile struct transmit_cmd_struct *xmit_cmds[NUM_XMIT_BUFFS];
+#if (NUM_XMIT_BUFFS == 1)
+ volatile struct nop_cmd_struct *nop_cmds[2];
+#else
+ volatile struct nop_cmd_struct *nop_cmds[NUM_XMIT_BUFFS];
+#endif
+ volatile int nop_point,num_recv_buffs;
+ volatile char *xmit_cbuffs[NUM_XMIT_BUFFS];
+ volatile int xmit_count,xmit_last;
+};
+
+/**********************************************
+ * close device
+ */
+static int sun3_82586_close(struct net_device *dev)
+{
+ free_irq(dev->irq, dev);
+
+ sun3_reset586(); /* the hard way to stop the receiver */
+
+ netif_stop_queue(dev);
+
+ return 0;
+}
+
+/**********************************************
+ * open device
+ */
+static int sun3_82586_open(struct net_device *dev)
+{
+ int ret;
+
+ sun3_disint();
+ alloc586(dev);
+ init586(dev);
+ startrecv586(dev);
+ sun3_enaint();
+
+ ret = request_irq(dev->irq, &sun3_82586_interrupt,0,dev->name,dev);
+ if (ret)
+ {
+ sun3_reset586();
+ return ret;
+ }
+
+ netif_start_queue(dev);
+
+ return 0; /* most done by init */
+}
+
+/**********************************************
+ * Check to see if there's an 82586 out there.
+ */
+static int check586(struct net_device *dev,char *where,unsigned size)
+{
+ struct priv pb;
+ struct priv *p = /* (struct priv *) dev->priv*/ &pb;
+ char *iscp_addr;
+ int i;
+
+ p->base = (unsigned long) dvma_btov(0);
+ p->memtop = (char *)dvma_btov((unsigned long)where);
+ p->scp = (struct scp_struct *)(p->base + SCP_DEFAULT_ADDRESS);
+ memset((char *)p->scp,0, sizeof(struct scp_struct));
+ for(i=0;i<sizeof(struct scp_struct);i++) /* memory was writeable? */
+ if(((char *)p->scp)[i])
+ return 0;
+ p->scp->sysbus = SYSBUSVAL; /* 1 = 8Bit-Bus, 0 = 16 Bit */
+ if(p->scp->sysbus != SYSBUSVAL)
+ return 0;
+
+ iscp_addr = (char *)dvma_btov((unsigned long)where);
+
+ p->iscp = (struct iscp_struct *) iscp_addr;
+ memset((char *)p->iscp,0, sizeof(struct iscp_struct));
+
+ p->scp->iscp = make24(p->iscp);
+ p->iscp->busy = 1;
+
+ sun3_reset586();
+ sun3_attn586();
+ DELAY(1); /* wait a while... */
+
+ if(p->iscp->busy) /* i82586 clears 'busy' after successful init */
+ return 0;
+
+ return 1;
+}
+
+/******************************************************************
+ * set iscp at the right place, called by sun3_82586_probe1 and open586.
+ */
+static void alloc586(struct net_device *dev)
+{
+ struct priv *p = (struct priv *) dev->priv;
+
+ sun3_reset586();
+ DELAY(1);
+
+ p->scp = (struct scp_struct *) (p->base + SCP_DEFAULT_ADDRESS);
+ p->iscp = (struct iscp_struct *) dvma_btov(dev->mem_start);
+ p->scb = (struct scb_struct *) ((char *)p->iscp + sizeof(struct iscp_struct));
+
+ memset((char *) p->iscp,0,sizeof(struct iscp_struct));
+ memset((char *) p->scp ,0,sizeof(struct scp_struct));
+
+ p->scp->iscp = make24(p->iscp);
+ p->scp->sysbus = SYSBUSVAL;
+ p->iscp->scb_offset = make16(p->scb);
+ p->iscp->scb_base = make24(dvma_btov(dev->mem_start));
+
+ p->iscp->busy = 1;
+ sun3_reset586();
+ sun3_attn586();
+
+ DELAY(1);
+
+ if(p->iscp->busy)
+ printk("%s: Init-Problems (alloc).\n",dev->name);
+
+ p->reseted = 0;
+
+ memset((char *)p->scb,0,sizeof(struct scb_struct));
+}
+
+int __init sun3_82586_probe(struct net_device *dev)
+{
+ unsigned long ioaddr, iopte;
+ static int found = 0;
+
+ /* check that this machine has an onboard lance */
+ switch(idprom->id_machtype) {
+ case SM_SUN3|SM_3_160:
+ case SM_SUN3|SM_3_260:
+ /* these machines have lance */
+ break;
+
+ default:
+ return(-ENODEV);
+ }
+
+ if(found)
+ return -ENODEV;
+
+ for(ioaddr = 0xfe00000; ioaddr < (0xfe00000 +
+ SUN3_PMEG_SIZE); ioaddr += SUN3_PTE_SIZE) {
+
+ iopte = sun3_get_pte(ioaddr);
+ if(!(iopte & SUN3_PAGE_TYPE_IO)) /* this an io page? */
+ continue;
+
+ if(((iopte & SUN3_PAGE_PGNUM_MASK) << PAGE_SHIFT) ==
+ IE_OBIO) {
+ found = 1;
+ break;
+ }
+ }
+
+ if(!found)
+ return 0;
+
+ SET_MODULE_OWNER(dev);
+
+ dev->irq = IE_IRQ;
+ dev->base_addr = ioaddr;
+ if(sun3_82586_probe1(dev, ioaddr) == 0)
+ return 0;
+
+ return -ENODEV;
+}
+
+static int __init sun3_82586_probe1(struct net_device *dev,int ioaddr)
+{
+ int i, size, retval;
+
+// if (!request_region(ioaddr, SUN3_82586_TOTAL_SIZE, dev->name))
+// return -EBUSY;
+
+ /* copy in the ethernet address from the prom */
+ for(i = 0; i < 6 ; i++)
+ dev->dev_addr[i] = idprom->id_ethaddr[i];
+
+ printk("%s: SUN3 Intel 82586 found at %lx, ",dev->name,dev->base_addr);
+
+ /*
+ * check (or search) IO-Memory, 32K
+ */
+ size = 0x8000;
+
+ dev->mem_start = (unsigned long)dvma_malloc_align(0x8000, 0x1000);
+ dev->mem_end = dev->mem_start + size;
+
+ if(size != 0x2000 && size != 0x4000 && size != 0x8000) {
+ printk("\n%s: Illegal memory size %d. Allowed is 0x2000 or 0x4000 or 0x8000 bytes.\n",dev->name,size);
+ retval = -ENODEV;
+ goto out;
+ }
+ if(!check586(dev,(char *) dev->mem_start,size)) {
+ printk("?memcheck, Can't find memory at 0x%lx with size %d!\n",dev->mem_start,size);
+ retval = -ENODEV;
+ goto out;
+ }
+
+ dev->priv = (void *) kmalloc(sizeof(struct priv),GFP_KERNEL);
+ if(dev->priv == NULL) {
+ printk("%s: Ooops .. can't allocate private driver memory.\n",dev->name);
+ retval = -ENOMEM;
+ goto out;
+ }
+
+ /* warning: we don't free it on errors */
+ memset((char *) dev->priv,0,sizeof(struct priv));
+
+ ((struct priv *) (dev->priv))->memtop = (char *)dvma_btov(dev->mem_start);
+ ((struct priv *) (dev->priv))->base = (unsigned long) dvma_btov(0);
+ alloc586(dev);
+
+ /* set number of receive-buffs according to memsize */
+ if(size == 0x2000)
+ ((struct priv *) dev->priv)->num_recv_buffs = NUM_RECV_BUFFS_8;
+ else if(size == 0x4000)
+ ((struct priv *) dev->priv)->num_recv_buffs = NUM_RECV_BUFFS_16;
+ else
+ ((struct priv *) dev->priv)->num_recv_buffs = NUM_RECV_BUFFS_32;
+
+ printk("Memaddr: 0x%lx, Memsize: %d, IRQ %d\n",dev->mem_start,size, dev->irq);
+
+ dev->open = sun3_82586_open;
+ dev->stop = sun3_82586_close;
+ dev->get_stats = sun3_82586_get_stats;
+ dev->tx_timeout = sun3_82586_timeout;
+ dev->watchdog_timeo = HZ/20;
+ dev->hard_start_xmit = sun3_82586_send_packet;
+ dev->set_multicast_list = set_multicast_list;
+
+ dev->if_port = 0;
+
+ ether_setup(dev);
+
+ return 0;
+out:
+ return retval;
+}
+
+
+static int init586(struct net_device *dev)
+{
+ void *ptr;
+ int i,result=0;
+ struct priv *p = (struct priv *) dev->priv;
+ volatile struct configure_cmd_struct *cfg_cmd;
+ volatile struct iasetup_cmd_struct *ias_cmd;
+ volatile struct tdr_cmd_struct *tdr_cmd;
+ volatile struct mcsetup_cmd_struct *mc_cmd;
+ struct dev_mc_list *dmi=dev->mc_list;
+ int num_addrs=dev->mc_count;
+
+ ptr = (void *) ((char *)p->scb + sizeof(struct scb_struct));
+
+ cfg_cmd = (struct configure_cmd_struct *)ptr; /* configure-command */
+ cfg_cmd->cmd_status = 0;
+ cfg_cmd->cmd_cmd = swab16(CMD_CONFIGURE | CMD_LAST);
+ cfg_cmd->cmd_link = 0xffff;
+
+ cfg_cmd->byte_cnt = 0x0a; /* number of cfg bytes */
+ cfg_cmd->fifo = fifo; /* fifo-limit (8=tx:32/rx:64) */
+ cfg_cmd->sav_bf = 0x40; /* hold or discard bad recv frames (bit 7) */
+ cfg_cmd->adr_len = 0x2e; /* addr_len |!src_insert |pre-len |loopback */
+ cfg_cmd->priority = 0x00;
+ cfg_cmd->ifs = 0x60;
+ cfg_cmd->time_low = 0x00;
+ cfg_cmd->time_high = 0xf2;
+ cfg_cmd->promisc = 0;
+ if(dev->flags & IFF_ALLMULTI) {
+ int len = ((char *) p->iscp - (char *) ptr - 8) / 6;
+ if(num_addrs > len) {
+ printk("%s: switching to promisc. mode\n",dev->name);
+ dev->flags|=IFF_PROMISC;
+ }
+ }
+ if(dev->flags&IFF_PROMISC)
+ {
+ cfg_cmd->promisc=1;
+ dev->flags|=IFF_PROMISC;
+ }
+ cfg_cmd->carr_coll = 0x00;
+
+ p->scb->cbl_offset = make16(cfg_cmd);
+ p->scb->cmd_ruc = 0;
+
+ p->scb->cmd_cuc = CUC_START; /* cmd.-unit start */
+ sun3_attn586();
+
+ WAIT_4_STAT_COMPL(cfg_cmd);
+
+ if((swab16(cfg_cmd->cmd_status) & (STAT_OK|STAT_COMPL)) != (STAT_COMPL|STAT_OK))
+ {
+ printk("%s: configure command failed: %x\n",dev->name,swab16(cfg_cmd->cmd_status));
+ return 1;
+ }
+
+ /*
+ * individual address setup
+ */
+
+ ias_cmd = (struct iasetup_cmd_struct *)ptr;
+
+ ias_cmd->cmd_status = 0;
+ ias_cmd->cmd_cmd = swab16(CMD_IASETUP | CMD_LAST);
+ ias_cmd->cmd_link = 0xffff;
+
+ memcpy((char *)&ias_cmd->iaddr,(char *) dev->dev_addr,ETH_ALEN);
+
+ p->scb->cbl_offset = make16(ias_cmd);
+
+ p->scb->cmd_cuc = CUC_START; /* cmd.-unit start */
+ sun3_attn586();
+
+ WAIT_4_STAT_COMPL(ias_cmd);
+
+ if((swab16(ias_cmd->cmd_status) & (STAT_OK|STAT_COMPL)) != (STAT_OK|STAT_COMPL)) {
+ printk("%s (82586): individual address setup command failed: %04x\n",dev->name,swab16(ias_cmd->cmd_status));
+ return 1;
+ }
+
+ /*
+ * TDR, wire check .. e.g. no resistor e.t.c
+ */
+
+ tdr_cmd = (struct tdr_cmd_struct *)ptr;
+
+ tdr_cmd->cmd_status = 0;
+ tdr_cmd->cmd_cmd = swab16(CMD_TDR | CMD_LAST);
+ tdr_cmd->cmd_link = 0xffff;
+ tdr_cmd->status = 0;
+
+ p->scb->cbl_offset = make16(tdr_cmd);
+ p->scb->cmd_cuc = CUC_START; /* cmd.-unit start */
+ sun3_attn586();
+
+ WAIT_4_STAT_COMPL(tdr_cmd);
+
+ if(!(swab16(tdr_cmd->cmd_status) & STAT_COMPL))
+ {
+ printk("%s: Problems while running the TDR.\n",dev->name);
+ }
+ else
+ {
+ DELAY_16(); /* wait for result */
+ result = swab16(tdr_cmd->status);
+
+ p->scb->cmd_cuc = p->scb->cus & STAT_MASK;
+ sun3_attn586(); /* ack the interrupts */
+
+ if(result & TDR_LNK_OK)
+ ;
+ else if(result & TDR_XCVR_PRB)
+ printk("%s: TDR: Transceiver problem. Check the cable(s)!\n",dev->name);
+ else if(result & TDR_ET_OPN)
+ printk("%s: TDR: No correct termination %d clocks away.\n",dev->name,result & TDR_TIMEMASK);
+ else if(result & TDR_ET_SRT)
+ {
+ if (result & TDR_TIMEMASK) /* time == 0 -> strange :-) */
+ printk("%s: TDR: Detected a short circuit %d clocks away.\n",dev->name,result & TDR_TIMEMASK);
+ }
+ else
+ printk("%s: TDR: Unknown status %04x\n",dev->name,result);
+ }
+
+ /*
+ * Multicast setup
+ */
+ if(num_addrs && !(dev->flags & IFF_PROMISC) )
+ {
+ mc_cmd = (struct mcsetup_cmd_struct *) ptr;
+ mc_cmd->cmd_status = 0;
+ mc_cmd->cmd_cmd = swab16(CMD_MCSETUP | CMD_LAST);
+ mc_cmd->cmd_link = 0xffff;
+ mc_cmd->mc_cnt = swab16(num_addrs * 6);
+
+ for(i=0;i<num_addrs;i++,dmi=dmi->next)
+ memcpy((char *) mc_cmd->mc_list[i], dmi->dmi_addr,6);
+
+ p->scb->cbl_offset = make16(mc_cmd);
+ p->scb->cmd_cuc = CUC_START;
+ sun3_attn586();
+
+ WAIT_4_STAT_COMPL(mc_cmd);
+
+ if( (swab16(mc_cmd->cmd_status) & (STAT_COMPL|STAT_OK)) != (STAT_COMPL|STAT_OK) )
+ printk("%s: Can't apply multicast-address-list.\n",dev->name);
+ }
+
+ /*
+ * alloc nop/xmit-cmds
+ */
+#if (NUM_XMIT_BUFFS == 1)
+ for(i=0;i<2;i++)
+ {
+ p->nop_cmds[i] = (struct nop_cmd_struct *)ptr;
+ p->nop_cmds[i]->cmd_cmd = swab16(CMD_NOP);
+ p->nop_cmds[i]->cmd_status = 0;
+ p->nop_cmds[i]->cmd_link = make16((p->nop_cmds[i]));
+ ptr = (char *) ptr + sizeof(struct nop_cmd_struct);
+ }
+#else
+ for(i=0;i<NUM_XMIT_BUFFS;i++)
+ {
+ p->nop_cmds[i] = (struct nop_cmd_struct *)ptr;
+ p->nop_cmds[i]->cmd_cmd = swab16(CMD_NOP);
+ p->nop_cmds[i]->cmd_status = 0;
+ p->nop_cmds[i]->cmd_link = make16((p->nop_cmds[i]));
+ ptr = (char *) ptr + sizeof(struct nop_cmd_struct);
+ }
+#endif
+
+ ptr = alloc_rfa(dev,(void *)ptr); /* init receive-frame-area */
+
+ /*
+ * alloc xmit-buffs / init xmit_cmds
+ */
+ for(i=0;i<NUM_XMIT_BUFFS;i++)
+ {
+ p->xmit_cmds[i] = (struct transmit_cmd_struct *)ptr; /*transmit cmd/buff 0*/
+ ptr = (char *) ptr + sizeof(struct transmit_cmd_struct);
+ p->xmit_cbuffs[i] = (char *)ptr; /* char-buffs */
+ ptr = (char *) ptr + XMIT_BUFF_SIZE;
+ p->xmit_buffs[i] = (struct tbd_struct *)ptr; /* TBD */
+ ptr = (char *) ptr + sizeof(struct tbd_struct);
+ if((void *)ptr > (void *)dev->mem_end)
+ {
+ printk("%s: not enough shared-mem for your configuration!\n",dev->name);
+ return 1;
+ }
+ memset((char *)(p->xmit_cmds[i]) ,0, sizeof(struct transmit_cmd_struct));
+ memset((char *)(p->xmit_buffs[i]),0, sizeof(struct tbd_struct));
+ p->xmit_cmds[i]->cmd_link = make16(p->nop_cmds[(i+1)%NUM_XMIT_BUFFS]);
+ p->xmit_cmds[i]->cmd_status = swab16(STAT_COMPL);
+ p->xmit_cmds[i]->cmd_cmd = swab16(CMD_XMIT | CMD_INT);
+ p->xmit_cmds[i]->tbd_offset = make16((p->xmit_buffs[i]));
+ p->xmit_buffs[i]->next = 0xffff;
+ p->xmit_buffs[i]->buffer = make24((p->xmit_cbuffs[i]));
+ }
+
+ p->xmit_count = 0;
+ p->xmit_last = 0;
+#ifndef NO_NOPCOMMANDS
+ p->nop_point = 0;
+#endif
+
+ /*
+ * 'start transmitter'
+ */
+#ifndef NO_NOPCOMMANDS
+ p->scb->cbl_offset = make16(p->nop_cmds[0]);
+ p->scb->cmd_cuc = CUC_START;
+ sun3_attn586();
+ WAIT_4_SCB_CMD();
+#else
+ p->xmit_cmds[0]->cmd_link = make16(p->xmit_cmds[0]);
+ p->xmit_cmds[0]->cmd_cmd = swab16(CMD_XMIT | CMD_SUSPEND | CMD_INT);
+#endif
+
+ /*
+ * ack. interrupts
+ */
+ p->scb->cmd_cuc = p->scb->cus & STAT_MASK;
+ sun3_attn586();
+ DELAY_16();
+
+ sun3_enaint();
+ sun3_active();
+
+ return 0;
+}
+
+/******************************************************
+ * This is a helper routine for sun3_82586_rnr_int() and init586().
+ * It sets up the Receive Frame Area (RFA).
+ */
+
+static void *alloc_rfa(struct net_device *dev,void *ptr)
+{
+ volatile struct rfd_struct *rfd = (struct rfd_struct *)ptr;
+ volatile struct rbd_struct *rbd;
+ int i;
+ struct priv *p = (struct priv *) dev->priv;
+
+ memset((char *) rfd,0,sizeof(struct rfd_struct)*(p->num_recv_buffs+rfdadd));
+ p->rfd_first = rfd;
+
+ for(i = 0; i < (p->num_recv_buffs+rfdadd); i++) {
+ rfd[i].next = make16(rfd + (i+1) % (p->num_recv_buffs+rfdadd) );
+ rfd[i].rbd_offset = 0xffff;
+ }
+ rfd[p->num_recv_buffs-1+rfdadd].last = RFD_SUSP; /* RU suspend */
+
+ ptr = (void *) (rfd + (p->num_recv_buffs + rfdadd) );
+
+ rbd = (struct rbd_struct *) ptr;
+ ptr = (void *) (rbd + p->num_recv_buffs);
+
+ /* clr descriptors */
+ memset((char *) rbd,0,sizeof(struct rbd_struct)*(p->num_recv_buffs));
+
+ for(i=0;i<p->num_recv_buffs;i++)
+ {
+ rbd[i].next = make16((rbd + (i+1) % p->num_recv_buffs));
+ rbd[i].size = swab16(RECV_BUFF_SIZE);
+ rbd[i].buffer = make24(ptr);
+ ptr = (char *) ptr + RECV_BUFF_SIZE;
+ }
+
+ p->rfd_top = p->rfd_first;
+ p->rfd_last = p->rfd_first + (p->num_recv_buffs - 1 + rfdadd);
+
+ p->scb->rfa_offset = make16(p->rfd_first);
+ p->rfd_first->rbd_offset = make16(rbd);
+
+ return ptr;
+}
+
+
+/**************************************************
+ * Interrupt Handler ...
+ */
+
+static void sun3_82586_interrupt(int irq,void *dev_id,struct pt_regs *reg_ptr)
+{
+ struct net_device *dev = dev_id;
+ unsigned short stat;
+ int cnt=0;
+ struct priv *p;
+
+ if (!dev) {
+ printk ("sun3_82586-interrupt: irq %d for unknown device.\n",irq);
+ return;
+ }
+ p = (struct priv *) dev->priv;
+
+ if(debuglevel > 1)
+ printk("I");
+
+ WAIT_4_SCB_CMD(); /* wait for last command */
+
+ while((stat=p->scb->cus & STAT_MASK))
+ {
+ p->scb->cmd_cuc = stat;
+ sun3_attn586();
+
+ if(stat & STAT_FR) /* received a frame */
+ sun3_82586_rcv_int(dev);
+
+ if(stat & STAT_RNR) /* RU went 'not ready' */
+ {
+ printk("(R)");
+ if(p->scb->rus & RU_SUSPEND) /* special case: RU_SUSPEND */
+ {
+ WAIT_4_SCB_CMD();
+ p->scb->cmd_ruc = RUC_RESUME;
+ sun3_attn586();
+ WAIT_4_SCB_CMD_RUC();
+ }
+ else
+ {
+ printk("%s: Receiver-Unit went 'NOT READY': %04x/%02x.\n",dev->name,(int) stat,(int) p->scb->rus);
+ sun3_82586_rnr_int(dev);
+ }
+ }
+
+ if(stat & STAT_CX) /* command with I-bit set complete */
+ sun3_82586_xmt_int(dev);
+
+#ifndef NO_NOPCOMMANDS
+ if(stat & STAT_CNA) /* CU went 'not ready' */
+ {
+ if(netif_running(dev))
+ printk("%s: oops! CU has left active state. stat: %04x/%02x.\n",dev->name,(int) stat,(int) p->scb->cus);
+ }
+#endif
+
+ if(debuglevel > 1)
+ printk("%d",cnt++);
+
+ WAIT_4_SCB_CMD(); /* wait for ack. (sun3_82586_xmt_int can be faster than ack!!) */
+ if(p->scb->cmd_cuc) /* timed out? */
+ {
+ printk("%s: Acknowledge timed out.\n",dev->name);
+ sun3_disint();
+ break;
+ }
+ }
+
+ if(debuglevel > 1)
+ printk("i");
+}
+
+/*******************************************************
+ * receive-interrupt
+ */
+
+static void sun3_82586_rcv_int(struct net_device *dev)
+{
+ int status,cnt=0;
+ unsigned short totlen;
+ struct sk_buff *skb;
+ struct rbd_struct *rbd;
+ struct priv *p = (struct priv *) dev->priv;
+
+ if(debuglevel > 0)
+ printk("R");
+
+ for(;(status = p->rfd_top->stat_high) & RFD_COMPL;)
+ {
+ rbd = (struct rbd_struct *) make32(p->rfd_top->rbd_offset);
+
+ if(status & RFD_OK) /* frame received without error? */
+ {
+ if( (totlen = swab16(rbd->status)) & RBD_LAST) /* the first and the last buffer? */
+ {
+ totlen &= RBD_MASK; /* length of this frame */
+ rbd->status = 0;
+ skb = (struct sk_buff *) dev_alloc_skb(totlen+2);
+ if(skb != NULL)
+ {
+ skb->dev = dev;
+ skb_reserve(skb,2);
+ skb_put(skb,totlen);
+ eth_copy_and_sum(skb,(char *) p->base+swab32((unsigned long) rbd->buffer),totlen,0);
+ skb->protocol=eth_type_trans(skb,dev);
+ netif_rx(skb);
+ p->stats.rx_packets++;
+ }
+ else
+ p->stats.rx_dropped++;
+ }
+ else
+ {
+ int rstat;
+ /* free all RBD's until RBD_LAST is set */
+ totlen = 0;
+ while(!((rstat=swab16(rbd->status)) & RBD_LAST))
+ {
+ totlen += rstat & RBD_MASK;
+ if(!rstat)
+ {
+ printk("%s: Whoops .. no end mark in RBD list\n",dev->name);
+ break;
+ }
+ rbd->status = 0;
+ rbd = (struct rbd_struct *) make32(rbd->next);
+ }
+ totlen += rstat & RBD_MASK;
+ rbd->status = 0;
+ printk("%s: received oversized frame! length: %d\n",dev->name,totlen);
+ p->stats.rx_dropped++;
+ }
+ }
+ else /* frame !(ok), only with 'save-bad-frames' */
+ {
+ printk("%s: oops! rfd-error-status: %04x\n",dev->name,status);
+ p->stats.rx_errors++;
+ }
+ p->rfd_top->stat_high = 0;
+ p->rfd_top->last = RFD_SUSP; /* maybe exchange by RFD_LAST */
+ p->rfd_top->rbd_offset = 0xffff;
+ p->rfd_last->last = 0; /* delete RFD_SUSP */
+ p->rfd_last = p->rfd_top;
+ p->rfd_top = (struct rfd_struct *) make32(p->rfd_top->next); /* step to next RFD */
+ p->scb->rfa_offset = make16(p->rfd_top);
+
+ if(debuglevel > 0)
+ printk("%d",cnt++);
+ }
+
+ if(automatic_resume)
+ {
+ WAIT_4_SCB_CMD();
+ p->scb->cmd_ruc = RUC_RESUME;
+ sun3_attn586();
+ WAIT_4_SCB_CMD_RUC();
+ }
+
+#ifdef WAIT_4_BUSY
+ {
+ int i;
+ for(i=0;i<1024;i++)
+ {
+ if(p->rfd_top->status)
+ break;
+ DELAY_16();
+ if(i == 1023)
+ printk("%s: RU hasn't fetched next RFD (not busy/complete)\n",dev->name);
+ }
+ }
+#endif
+
+#if 0
+ if(!at_least_one)
+ {
+ int i;
+ volatile struct rfd_struct *rfds=p->rfd_top;
+ volatile struct rbd_struct *rbds;
+ printk("%s: received a FC intr. without having a frame: %04x %d\n",dev->name,status,old_at_least);
+ for(i=0;i< (p->num_recv_buffs+4);i++)
+ {
+ rbds = (struct rbd_struct *) make32(rfds->rbd_offset);
+ printk("%04x:%04x ",rfds->status,rbds->status);
+ rfds = (struct rfd_struct *) make32(rfds->next);
+ }
+ printk("\nerrs: %04x %04x stat: %04x\n",(int)p->scb->rsc_errs,(int)p->scb->ovrn_errs,(int)p->scb->status);
+ printk("\nerrs: %04x %04x rus: %02x, cus: %02x\n",(int)p->scb->rsc_errs,(int)p->scb->ovrn_errs,(int)p->scb->rus,(int)p->scb->cus);
+ }
+ old_at_least = at_least_one;
+#endif
+
+ if(debuglevel > 0)
+ printk("r");
+}
+
+/**********************************************************
+ * handle 'Receiver went not ready'.
+ */
+
+static void sun3_82586_rnr_int(struct net_device *dev)
+{
+ struct priv *p = (struct priv *) dev->priv;
+
+ p->stats.rx_errors++;
+
+ WAIT_4_SCB_CMD(); /* wait for the last cmd, WAIT_4_FULLSTAT?? */
+ p->scb->cmd_ruc = RUC_ABORT; /* usually the RU is in the 'no resource'-state .. abort it now. */
+ sun3_attn586();
+ WAIT_4_SCB_CMD_RUC(); /* wait for accept cmd. */
+
+ alloc_rfa(dev,(char *)p->rfd_first);
+/* maybe add a check here, before restarting the RU */
+ startrecv586(dev); /* restart RU */
+
+ printk("%s: Receive-Unit restarted. Status: %04x\n",dev->name,p->scb->rus);
+
+}
+
+/**********************************************************
+ * handle xmit - interrupt
+ */
+
+static void sun3_82586_xmt_int(struct net_device *dev)
+{
+ int status;
+ struct priv *p = (struct priv *) dev->priv;
+
+ if(debuglevel > 0)
+ printk("X");
+
+ status = swab16(p->xmit_cmds[p->xmit_last]->cmd_status);
+ if(!(status & STAT_COMPL))
+ printk("%s: strange .. xmit-int without a 'COMPLETE'\n",dev->name);
+
+ if(status & STAT_OK)
+ {
+ p->stats.tx_packets++;
+ p->stats.collisions += (status & TCMD_MAXCOLLMASK);
+ }
+ else
+ {
+ p->stats.tx_errors++;
+ if(status & TCMD_LATECOLL) {
+ printk("%s: late collision detected.\n",dev->name);
+ p->stats.collisions++;
+ }
+ else if(status & TCMD_NOCARRIER) {
+ p->stats.tx_carrier_errors++;
+ printk("%s: no carrier detected.\n",dev->name);
+ }
+ else if(status & TCMD_LOSTCTS)
+ printk("%s: loss of CTS detected.\n",dev->name);
+ else if(status & TCMD_UNDERRUN) {
+ p->stats.tx_fifo_errors++;
+ printk("%s: DMA underrun detected.\n",dev->name);
+ }
+ else if(status & TCMD_MAXCOLL) {
+ printk("%s: Max. collisions exceeded.\n",dev->name);
+ p->stats.collisions += 16;
+ }
+ }
+
+#if (NUM_XMIT_BUFFS > 1)
+ if( (++p->xmit_last) == NUM_XMIT_BUFFS)
+ p->xmit_last = 0;
+#endif
+ netif_wake_queue(dev);
+}
+
+/***********************************************************
+ * (re)start the receiver
+ */
+
+static void startrecv586(struct net_device *dev)
+{
+ struct priv *p = (struct priv *) dev->priv;
+
+ WAIT_4_SCB_CMD();
+ WAIT_4_SCB_CMD_RUC();
+ p->scb->rfa_offset = make16(p->rfd_first);
+ p->scb->cmd_ruc = RUC_START;
+ sun3_attn586(); /* start cmd. */
+ WAIT_4_SCB_CMD_RUC(); /* wait for accept cmd. (no timeout!!) */
+}
+
+static void sun3_82586_timeout(struct net_device *dev)
+{
+ struct priv *p = (struct priv *) dev->priv;
+#ifndef NO_NOPCOMMANDS
+ if(p->scb->cus & CU_ACTIVE) /* COMMAND-UNIT active? */
+ {
+ netif_wake_queue(dev);
+#ifdef DEBUG
+ printk("%s: strange ... timeout with CU active?!?\n",dev->name);
+ printk("%s: X0: %04x N0: %04x N1: %04x %d\n",dev->name,(int)swab16(p->xmit_cmds[0]->cmd_status),(int)swab16(p->nop_cmds[0]->cmd_status),(int)swab16(p->nop_cmds[1]->cmd_status),(int)p->nop_point);
+#endif
+ p->scb->cmd_cuc = CUC_ABORT;
+ sun3_attn586();
+ WAIT_4_SCB_CMD();
+ p->scb->cbl_offset = make16(p->nop_cmds[p->nop_point]);
+ p->scb->cmd_cuc = CUC_START;
+ sun3_attn586();
+ WAIT_4_SCB_CMD();
+ dev->trans_start = jiffies;
+ return 0;
+ }
+#endif
+ {
+#ifdef DEBUG
+ printk("%s: xmitter timed out, try to restart! stat: %02x\n",dev->name,p->scb->cus);
+ printk("%s: command-stats: %04x %04x\n",dev->name,swab16(p->xmit_cmds[0]->cmd_status),swab16(p->xmit_cmds[1]->cmd_status));
+ printk("%s: check, whether you set the right interrupt number!\n",dev->name);
+#endif
+ sun3_82586_close(dev);
+ sun3_82586_open(dev);
+ }
+ dev->trans_start = jiffies;
+}
+
+/******************************************************
+ * send frame
+ */
+
+static int sun3_82586_send_packet(struct sk_buff *skb, struct net_device *dev)
+{
+ int len,i;
+#ifndef NO_NOPCOMMANDS
+ int next_nop;
+#endif
+ struct priv *p = (struct priv *) dev->priv;
+
+ if(skb->len > XMIT_BUFF_SIZE)
+ {
+ printk("%s: Sorry, max. framelength is %d bytes. The length of your frame is %d bytes.\n",dev->name,XMIT_BUFF_SIZE,skb->len);
+ return 0;
+ }
+
+ netif_stop_queue(dev);
+
+#if(NUM_XMIT_BUFFS > 1)
+ if(test_and_set_bit(0,(void *) &p->lock)) {
+ printk("%s: Queue was locked\n",dev->name);
+ return 1;
+ }
+ else
+#endif
+ {
+ memcpy((char *)p->xmit_cbuffs[p->xmit_count],(char *)(skb->data),skb->len);
+ len = (ETH_ZLEN < skb->len) ? skb->len : ETH_ZLEN;
+
+#if (NUM_XMIT_BUFFS == 1)
+# ifdef NO_NOPCOMMANDS
+
+#ifdef DEBUG
+ if(p->scb->cus & CU_ACTIVE)
+ {
+ printk("%s: Hmmm .. CU is still running and we wanna send a new packet.\n",dev->name);
+ printk("%s: stat: %04x %04x\n",dev->name,p->scb->cus,swab16(p->xmit_cmds[0]->cmd_status));
+ }
+#endif
+
+ p->xmit_buffs[0]->size = swab16(TBD_LAST | len);
+ for(i=0;i<16;i++)
+ {
+ p->xmit_cmds[0]->cmd_status = 0;
+ WAIT_4_SCB_CMD();
+ if( (p->scb->cus & CU_STATUS) == CU_SUSPEND)
+ p->scb->cmd_cuc = CUC_RESUME;
+ else
+ {
+ p->scb->cbl_offset = make16(p->xmit_cmds[0]);
+ p->scb->cmd_cuc = CUC_START;
+ }
+
+ sun3_attn586();
+ dev->trans_start = jiffies;
+ if(!i)
+ dev_kfree_skb(skb);
+ WAIT_4_SCB_CMD();
+ if( (p->scb->cus & CU_ACTIVE)) /* test it, because CU sometimes doesn't start immediately */
+ break;
+ if(p->xmit_cmds[0]->cmd_status)
+ break;
+ if(i==15)
+ printk("%s: Can't start transmit-command.\n",dev->name);
+ }
+# else
+ next_nop = (p->nop_point + 1) & 0x1;
+ p->xmit_buffs[0]->size = swab16(TBD_LAST | len);
+
+ p->xmit_cmds[0]->cmd_link = p->nop_cmds[next_nop]->cmd_link
+ = make16((p->nop_cmds[next_nop]));
+ p->xmit_cmds[0]->cmd_status = p->nop_cmds[next_nop]->cmd_status = 0;
+
+ p->nop_cmds[p->nop_point]->cmd_link = make16((p->xmit_cmds[0]));
+ dev->trans_start = jiffies;
+ p->nop_point = next_nop;
+ dev_kfree_skb(skb);
+# endif
+#else
+ p->xmit_buffs[p->xmit_count]->size = swab16(TBD_LAST | len);
+ if( (next_nop = p->xmit_count + 1) == NUM_XMIT_BUFFS )
+ next_nop = 0;
+
+ p->xmit_cmds[p->xmit_count]->cmd_status = 0;
+ /* linkpointer of xmit-command already points to next nop cmd */
+ p->nop_cmds[next_nop]->cmd_link = make16((p->nop_cmds[next_nop]));
+ p->nop_cmds[next_nop]->cmd_status = 0;
+
+ p->nop_cmds[p->xmit_count]->cmd_link = make16((p->xmit_cmds[p->xmit_count]));
+ dev->trans_start = jiffies;
+ p->xmit_count = next_nop;
+
+ {
+ unsigned long flags;
+ save_flags(flags);
+ cli();
+ if(p->xmit_count != p->xmit_last)
+ netif_wake_queue(dev);
+ p->lock = 0;
+ restore_flags(flags);
+ }
+ dev_kfree_skb(skb);
+#endif
+ }
+ return 0;
+}
+
+/*******************************************
+ * Someone wanna have the statistics
+ */
+
+static struct net_device_stats *sun3_82586_get_stats(struct net_device *dev)
+{
+ struct priv *p = (struct priv *) dev->priv;
+ unsigned short crc,aln,rsc,ovrn;
+
+ crc = swab16(p->scb->crc_errs); /* get error-statistic from the ni82586 */
+ p->scb->crc_errs = 0;
+ aln = swab16(p->scb->aln_errs);
+ p->scb->aln_errs = 0;
+ rsc = swab16(p->scb->rsc_errs);
+ p->scb->rsc_errs = 0;
+ ovrn = swab16(p->scb->ovrn_errs);
+ p->scb->ovrn_errs = 0;
+
+ p->stats.rx_crc_errors += crc;
+ p->stats.rx_fifo_errors += ovrn;
+ p->stats.rx_frame_errors += aln;
+ p->stats.rx_dropped += rsc;
+
+ return &p->stats;
+}
+
+/********************************************************
+ * Set MC list ..
+ */
+
+static void set_multicast_list(struct net_device *dev)
+{
+ netif_stop_queue(dev);
+ sun3_disint();
+ alloc586(dev);
+ init586(dev);
+ startrecv586(dev);
+ sun3_enaint();
+ netif_wake_queue(dev);
+}
+
+#ifdef MODULE
+#error This code is not currently supported as a module
+static struct net_device dev_sun3_82586;
+
+int init_module(void)
+{
+ dev_sun3_82586.init = sun3_82586_probe;
+ if (register_netdev(&dev_sun3_82586) != 0)
+ return -EIO;
+ return 0;
+}
+
+void cleanup_module(void)
+{
+ unregister_netdev(&dev_sun3_82586);
+ kfree(dev_sun3_82586.priv);
+ dev_sun3_82586.priv = NULL;
+}
+#endif /* MODULE */
+
+#if 0
+/*
+ * DUMP .. we expect a not running CMD unit and enough space
+ */
+void sun3_82586_dump(struct net_device *dev,void *ptr)
+{
+ struct priv *p = (struct priv *) dev->priv;
+ struct dump_cmd_struct *dump_cmd = (struct dump_cmd_struct *) ptr;
+ int i;
+
+ p->scb->cmd_cuc = CUC_ABORT;
+ sun3_attn586();
+ WAIT_4_SCB_CMD();
+ WAIT_4_SCB_CMD_RUC();
+
+ dump_cmd->cmd_status = 0;
+ dump_cmd->cmd_cmd = CMD_DUMP | CMD_LAST;
+ dump_cmd->dump_offset = make16((dump_cmd + 1));
+ dump_cmd->cmd_link = 0xffff;
+
+ p->scb->cbl_offset = make16(dump_cmd);
+ p->scb->cmd_cuc = CUC_START;
+ sun3_attn586();
+ WAIT_4_STAT_COMPL(dump_cmd);
+
+ if( (dump_cmd->cmd_status & (STAT_COMPL|STAT_OK)) != (STAT_COMPL|STAT_OK) )
+ printk("%s: Can't get dump information.\n",dev->name);
+
+ for(i=0;i<170;i++) {
+ printk("%02x ",(int) ((unsigned char *) (dump_cmd + 1))[i]);
+ if(i % 24 == 23)
+ printk("\n");
+ }
+ printk("\n");
+}
+#endif
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/sun3_82586.h b/drivers/net/sun3_82586.h
new file mode 100644
index 0000000000000..81cfb098bccaf
--- /dev/null
+++ b/drivers/net/sun3_82586.h
@@ -0,0 +1,318 @@
+/*
+ * Intel i82586 Ethernet definitions
+ *
+ * This is an extension to the Linux operating system, and is covered by the
+ * same Gnu Public License that covers that work.
+ *
+ * copyrights (c) 1994 by Michael Hipp (hippm@informatik.uni-tuebingen.de)
+ *
+ * I have done a look in the following sources:
+ * crynwr-packet-driver by Russ Nelson
+ * Garret A. Wollman's i82586-driver for BSD
+ */
+
+/*
+ * Cloned from ni52.h, copyright as above.
+ *
+ * Modified for Sun3 OBIO i82586 by Sam Creasey (sammy@sammy.net)
+ */
+
+
+/* defines for the obio chip (not vme) */
+#define IEOB_NORSET 0x80 /* don't reset the board */
+#define IEOB_ONAIR 0x40 /* put us on the air */
+#define IEOB_ATTEN 0x20 /* attention! */
+#define IEOB_IENAB 0x10 /* interrupt enable */
+#define IEOB_XXXXX 0x08 /* free bit */
+#define IEOB_XCVRL2 0x04 /* level 2 transceiver? */
+#define IEOB_BUSERR 0x02 /* bus error */
+#define IEOB_INT 0x01 /* interrupt */
+
+/* where the obio one lives */
+#define IE_OBIO 0xc0000
+#define IE_IRQ 3
+
+/*
+ * where to find the System Configuration Pointer (SCP)
+ */
+#define SCP_DEFAULT_ADDRESS 0xfffff4
+
+
+/*
+ * System Configuration Pointer Struct
+ */
+
+struct scp_struct
+{
+ unsigned short zero_dum0; /* has to be zero */
+ unsigned char sysbus; /* 0=16Bit,1=8Bit */
+ unsigned char zero_dum1; /* has to be zero for 586 */
+ unsigned short zero_dum2;
+ unsigned short zero_dum3;
+ char *iscp; /* pointer to the iscp-block */
+};
+
+
+/*
+ * Intermediate System Configuration Pointer (ISCP)
+ */
+struct iscp_struct
+{
+ unsigned char busy; /* 586 clears after successful init */
+ unsigned char zero_dummy; /* has to be zero */
+ unsigned short scb_offset; /* pointeroffset to the scb_base */
+ char *scb_base; /* base-address of all 16-bit offsets */
+};
+
+/*
+ * System Control Block (SCB)
+ */
+struct scb_struct
+{
+ unsigned char rus;
+ unsigned char cus;
+ unsigned char cmd_ruc; /* command word: RU part */
+ unsigned char cmd_cuc; /* command word: CU part & ACK */
+ unsigned short cbl_offset; /* pointeroffset, command block list */
+ unsigned short rfa_offset; /* pointeroffset, receive frame area */
+ unsigned short crc_errs; /* CRC-Error counter */
+ unsigned short aln_errs; /* allignmenterror counter */
+ unsigned short rsc_errs; /* Resourceerror counter */
+ unsigned short ovrn_errs; /* OVerrunerror counter */
+};
+
+/*
+ * possible command values for the command word
+ */
+#define RUC_MASK 0x0070 /* mask for RU commands */
+#define RUC_NOP 0x0000 /* NOP-command */
+#define RUC_START 0x0010 /* start RU */
+#define RUC_RESUME 0x0020 /* resume RU after suspend */
+#define RUC_SUSPEND 0x0030 /* suspend RU */
+#define RUC_ABORT 0x0040 /* abort receiver operation immediately */
+
+#define CUC_MASK 0x07 /* mask for CU command */
+#define CUC_NOP 0x00 /* NOP-command */
+#define CUC_START 0x01 /* start execution of 1. cmd on the CBL */
+#define CUC_RESUME 0x02 /* resume after suspend */
+#define CUC_SUSPEND 0x03 /* Suspend CU */
+#define CUC_ABORT 0x04 /* abort command operation immediately */
+
+#define ACK_MASK 0xf0 /* mask for ACK command */
+#define ACK_CX 0x80 /* acknowledges STAT_CX */
+#define ACK_FR 0x40 /* ack. STAT_FR */
+#define ACK_CNA 0x20 /* ack. STAT_CNA */
+#define ACK_RNR 0x10 /* ack. STAT_RNR */
+
+/*
+ * possible status values for the status word
+ */
+#define STAT_MASK 0xf0 /* mask for cause of interrupt */
+#define STAT_CX 0x80 /* CU finished cmd with its I bit set */
+#define STAT_FR 0x40 /* RU finished receiving a frame */
+#define STAT_CNA 0x20 /* CU left active state */
+#define STAT_RNR 0x10 /* RU left ready state */
+
+#define CU_STATUS 0x7 /* CU status, 0=idle */
+#define CU_SUSPEND 0x1 /* CU is suspended */
+#define CU_ACTIVE 0x2 /* CU is active */
+
+#define RU_STATUS 0x70 /* RU status, 0=idle */
+#define RU_SUSPEND 0x10 /* RU suspended */
+#define RU_NOSPACE 0x20 /* RU no resources */
+#define RU_READY 0x40 /* RU is ready */
+
+/*
+ * Receive Frame Descriptor (RFD)
+ */
+struct rfd_struct
+{
+ unsigned char stat_low; /* status word */
+ unsigned char stat_high; /* status word */
+ unsigned char rfd_sf; /* 82596 mode only */
+ unsigned char last; /* Bit15,Last Frame on List / Bit14,suspend */
+ unsigned short next; /* linkoffset to next RFD */
+ unsigned short rbd_offset; /* pointeroffset to RBD-buffer */
+ unsigned char dest[6]; /* ethernet-address, destination */
+ unsigned char source[6]; /* ethernet-address, source */
+ unsigned short length; /* 802.3 frame-length */
+ unsigned short zero_dummy; /* dummy */
+};
+
+#define RFD_LAST 0x80 /* last: last rfd in the list */
+#define RFD_SUSP 0x40 /* last: suspend RU after */
+#define RFD_COMPL 0x80
+#define RFD_OK 0x20
+#define RFD_BUSY 0x40
+#define RFD_ERR_LEN 0x10 /* Length error (if enabled length-checking */
+#define RFD_ERR_CRC 0x08 /* CRC error */
+#define RFD_ERR_ALGN 0x04 /* Alignment error */
+#define RFD_ERR_RNR 0x02 /* status: receiver out of resources */
+#define RFD_ERR_OVR 0x01 /* DMA Overrun! */
+
+#define RFD_ERR_FTS 0x0080 /* Frame to short */
+#define RFD_ERR_NEOP 0x0040 /* No EOP flag (for bitstuffing only) */
+#define RFD_ERR_TRUN 0x0020 /* (82596 only/SF mode) indicates truncated frame */
+#define RFD_MATCHADD 0x0002 /* status: Destinationaddress !matches IA (only 82596) */
+#define RFD_COLLDET 0x0001 /* Detected collision during reception */
+
+/*
+ * Receive Buffer Descriptor (RBD)
+ */
+struct rbd_struct
+{
+ unsigned short status; /* status word,number of used bytes in buff */
+ unsigned short next; /* pointeroffset to next RBD */
+ char *buffer; /* receive buffer address pointer */
+ unsigned short size; /* size of this buffer */
+ unsigned short zero_dummy; /* dummy */
+};
+
+#define RBD_LAST 0x8000 /* last buffer */
+#define RBD_USED 0x4000 /* this buffer has data */
+#define RBD_MASK 0x3fff /* size-mask for length */
+
+/*
+ * Statusvalues for Commands/RFD
+ */
+#define STAT_COMPL 0x8000 /* status: frame/command is complete */
+#define STAT_BUSY 0x4000 /* status: frame/command is busy */
+#define STAT_OK 0x2000 /* status: frame/command is ok */
+
+/*
+ * Action-Commands
+ */
+#define CMD_NOP 0x0000 /* NOP */
+#define CMD_IASETUP 0x0001 /* initial address setup command */
+#define CMD_CONFIGURE 0x0002 /* configure command */
+#define CMD_MCSETUP 0x0003 /* MC setup command */
+#define CMD_XMIT 0x0004 /* transmit command */
+#define CMD_TDR 0x0005 /* time domain reflectometer (TDR) command */
+#define CMD_DUMP 0x0006 /* dump command */
+#define CMD_DIAGNOSE 0x0007 /* diagnose command */
+
+/*
+ * Action command bits
+ */
+#define CMD_LAST 0x8000 /* indicates last command in the CBL */
+#define CMD_SUSPEND 0x4000 /* suspend CU after this CB */
+#define CMD_INT 0x2000 /* generate interrupt after execution */
+
+/*
+ * NOP - command
+ */
+struct nop_cmd_struct
+{
+ unsigned short cmd_status; /* status of this command */
+ unsigned short cmd_cmd; /* the command itself (+bits) */
+ unsigned short cmd_link; /* offsetpointer to next command */
+};
+
+/*
+ * IA Setup command
+ */
+struct iasetup_cmd_struct
+{
+ unsigned short cmd_status;
+ unsigned short cmd_cmd;
+ unsigned short cmd_link;
+ unsigned char iaddr[6];
+};
+
+/*
+ * Configure command
+ */
+struct configure_cmd_struct
+{
+ unsigned short cmd_status;
+ unsigned short cmd_cmd;
+ unsigned short cmd_link;
+ unsigned char byte_cnt; /* size of the config-cmd */
+ unsigned char fifo; /* fifo/recv monitor */
+ unsigned char sav_bf; /* save bad frames (bit7=1)*/
+ unsigned char adr_len; /* adr_len(0-2),al_loc(3),pream(4-5),loopbak(6-7)*/
+ unsigned char priority; /* lin_prio(0-2),exp_prio(4-6),bof_metd(7) */
+ unsigned char ifs; /* inter frame spacing */
+ unsigned char time_low; /* slot time low */
+ unsigned char time_high; /* slot time high(0-2) and max. retries(4-7) */
+ unsigned char promisc; /* promisc-mode(0) , et al (1-7) */
+ unsigned char carr_coll; /* carrier(0-3)/collision(4-7) stuff */
+ unsigned char fram_len; /* minimal frame len */
+ unsigned char dummy; /* dummy */
+};
+
+/*
+ * Multicast Setup command
+ */
+struct mcsetup_cmd_struct
+{
+ unsigned short cmd_status;
+ unsigned short cmd_cmd;
+ unsigned short cmd_link;
+ unsigned short mc_cnt; /* number of bytes in the MC-List */
+ unsigned char mc_list[0][6]; /* pointer to 6 bytes entries */
+};
+
+/*
+ * DUMP command
+ */
+struct dump_cmd_struct
+{
+ unsigned short cmd_status;
+ unsigned short cmd_cmd;
+ unsigned short cmd_link;
+ unsigned short dump_offset; /* pointeroffset to DUMP space */
+};
+
+/*
+ * transmit command
+ */
+struct transmit_cmd_struct
+{
+ unsigned short cmd_status;
+ unsigned short cmd_cmd;
+ unsigned short cmd_link;
+ unsigned short tbd_offset; /* pointeroffset to TBD */
+ unsigned char dest[6]; /* destination address of the frame */
+ unsigned short length; /* user defined: 802.3 length / Ether type */
+};
+
+#define TCMD_ERRMASK 0x0fa0
+#define TCMD_MAXCOLLMASK 0x000f
+#define TCMD_MAXCOLL 0x0020
+#define TCMD_HEARTBEAT 0x0040
+#define TCMD_DEFERRED 0x0080
+#define TCMD_UNDERRUN 0x0100
+#define TCMD_LOSTCTS 0x0200
+#define TCMD_NOCARRIER 0x0400
+#define TCMD_LATECOLL 0x0800
+
+struct tdr_cmd_struct
+{
+ unsigned short cmd_status;
+ unsigned short cmd_cmd;
+ unsigned short cmd_link;
+ unsigned short status;
+};
+
+#define TDR_LNK_OK 0x8000 /* No link problem identified */
+#define TDR_XCVR_PRB 0x4000 /* indicates a transceiver problem */
+#define TDR_ET_OPN 0x2000 /* open, no correct termination */
+#define TDR_ET_SRT 0x1000 /* TDR detected a short circuit */
+#define TDR_TIMEMASK 0x07ff /* mask for the time field */
+
+/*
+ * Transmit Buffer Descriptor (TBD)
+ */
+struct tbd_struct
+{
+ unsigned short size; /* size + EOF-Flag(15) */
+ unsigned short next; /* pointeroffset to next TBD */
+ char *buffer; /* pointer to buffer */
+};
+
+#define TBD_LAST 0x8000 /* EOF-Flag, indicates last buffer in list */
+
+
+
+
diff --git a/drivers/net/sungem.c b/drivers/net/sungem.c
index bbdc8ca9ae6fa..ff6f30e1404ce 100644
--- a/drivers/net/sungem.c
+++ b/drivers/net/sungem.c
@@ -1,7 +1,7 @@
/* $Id: sungem.c,v 1.49 2002/01/23 15:40:45 davem Exp $
* sungem.c: Sun GEM ethernet driver.
*
- * Copyright (C) 2000, 2001 David S. Miller (davem@redhat.com)
+ * Copyright (C) 2000, 2001, 2002 David S. Miller (davem@redhat.com)
*
* Support for Apple GMAC and assorted PHYs by
* Benjamin Herrenscmidt (benh@kernel.crashing.org)
@@ -16,6 +16,8 @@
* I can at least detect gigabit with autoneg.
*/
+#include <linux/config.h>
+
#include <linux/module.h>
#include <linux/kernel.h>
@@ -35,9 +37,10 @@
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
-#include <linux/crc32.h>
#include <linux/mii.h>
#include <linux/ethtool.h>
+#include <linux/crc32.h>
+#include <linux/random.h>
#include <asm/system.h>
#include <asm/bitops.h>
@@ -67,8 +70,8 @@
NETIF_MSG_LINK)
#define DRV_NAME "sungem"
-#define DRV_VERSION "0.96"
-#define DRV_RELDATE "11/17/01"
+#define DRV_VERSION "0.97"
+#define DRV_RELDATE "3/20/02"
#define DRV_AUTHOR "David S. Miller (davem@redhat.com)"
static char version[] __devinitdata =
@@ -293,19 +296,119 @@ static int gem_txmac_interrupt(struct net_device *dev, struct gem *gp, u32 gem_s
return 0;
}
+/* When we get a RX fifo overflow, the RX unit in GEM is probably hung
+ * so we do the following.
+ *
+ * If any part of the reset goes wrong, we return 1 and that causes the
+ * whole chip to be reset.
+ */
+static int gem_rxmac_reset(struct gem *gp)
+{
+ struct net_device *dev = gp->dev;
+ int limit, i;
+ u64 desc_dma;
+ u32 val;
+
+ /* First, reset MAC RX. */
+ writel(gp->mac_rx_cfg & ~MAC_RXCFG_ENAB,
+ gp->regs + MAC_RXCFG);
+ for (limit = 0; limit < 5000; limit++) {
+ if (!(readl(gp->regs + MAC_RXCFG) & MAC_RXCFG_ENAB))
+ break;
+ udelay(10);
+ }
+ if (limit == 5000) {
+ printk(KERN_ERR "%s: RX MAC will not disable, resetting whole "
+ "chip.\n", dev->name);
+ return 1;
+ }
+
+ /* Second, disable RX DMA. */
+ writel(0, gp->regs + RXDMA_CFG);
+ for (limit = 0; limit < 5000; limit++) {
+ if (!(readl(gp->regs + RXDMA_CFG) & RXDMA_CFG_ENABLE))
+ break;
+ udelay(10);
+ }
+ if (limit == 5000) {
+ printk(KERN_ERR "%s: RX DMA will not disable, resetting whole "
+ "chip.\n", dev->name);
+ return 1;
+ }
+
+ udelay(5000);
+
+ /* Execute RX reset command. */
+ writel(gp->swrst_base | GREG_SWRST_RXRST,
+ gp->regs + GREG_SWRST);
+ for (limit = 0; limit < 5000; limit++) {
+ if (!(readl(gp->regs + GREG_SWRST) & GREG_SWRST_RXRST))
+ break;
+ udelay(10);
+ }
+ if (limit == 5000) {
+ printk(KERN_ERR "%s: RX reset command will not execute, resetting "
+ "whole chip.\n", dev->name);
+ return 1;
+ }
+
+ /* Refresh the RX ring. */
+ for (i = 0; i < RX_RING_SIZE; i++) {
+ struct gem_rxd *rxd = &gp->init_block->rxd[i];
+
+ if (gp->rx_skbs[i] == NULL) {
+ printk(KERN_ERR "%s: Parts of RX ring empty, resetting "
+ "whole chip.\n", dev->name);
+ return 1;
+ }
+
+ rxd->status_word = cpu_to_le64(RXDCTRL_FRESH(gp));
+ }
+ gp->rx_new = gp->rx_old = 0;
+
+ /* Now we must reprogram the rest of RX unit. */
+ desc_dma = (u64) gp->gblock_dvma;
+ desc_dma += (INIT_BLOCK_TX_RING_SIZE * sizeof(struct gem_txd));
+ writel(desc_dma >> 32, gp->regs + RXDMA_DBHI);
+ writel(desc_dma & 0xffffffff, gp->regs + RXDMA_DBLOW);
+ writel(RX_RING_SIZE - 4, gp->regs + RXDMA_KICK);
+ val = (RXDMA_CFG_BASE | (RX_OFFSET << 10) |
+ ((14 / 2) << 13) | RXDMA_CFG_FTHRESH_128);
+ writel(val, gp->regs + RXDMA_CFG);
+ if (readl(gp->regs + GREG_BIFCFG) & GREG_BIFCFG_M66EN)
+ writel(((5 & RXDMA_BLANK_IPKTS) |
+ ((8 << 12) & RXDMA_BLANK_ITIME)),
+ gp->regs + RXDMA_BLANK);
+ else
+ writel(((5 & RXDMA_BLANK_IPKTS) |
+ ((4 << 12) & RXDMA_BLANK_ITIME)),
+ gp->regs + RXDMA_BLANK);
+ val = (((gp->rx_pause_off / 64) << 0) & RXDMA_PTHRESH_OFF);
+ val |= (((gp->rx_pause_on / 64) << 12) & RXDMA_PTHRESH_ON);
+ writel(val, gp->regs + RXDMA_PTHRESH);
+ val = readl(gp->regs + RXDMA_CFG);
+ writel(val | RXDMA_CFG_ENABLE, gp->regs + RXDMA_CFG);
+ writel(MAC_RXSTAT_RCV, gp->regs + MAC_RXMASK);
+ val = readl(gp->regs + MAC_RXCFG);
+ writel(val | MAC_RXCFG_ENAB, gp->regs + MAC_RXCFG);
+
+ return 0;
+}
+
static int gem_rxmac_interrupt(struct net_device *dev, struct gem *gp, u32 gem_status)
{
u32 rxmac_stat = readl(gp->regs + MAC_RXSTAT);
+ int ret = 0;
if (netif_msg_intr(gp))
printk(KERN_DEBUG "%s: rxmac interrupt, rxmac_stat: 0x%x\n",
gp->dev->name, rxmac_stat);
if (rxmac_stat & MAC_RXSTAT_OFLW) {
- printk(KERN_ERR "%s: RX MAC fifo overflow.\n",
- dev->name);
gp->net_stats.rx_over_errors++;
gp->net_stats.rx_fifo_errors++;
+
+ ret = gem_rxmac_reset(gp);
}
if (rxmac_stat & MAC_RXSTAT_ACE)
@@ -320,7 +423,7 @@ static int gem_rxmac_interrupt(struct net_device *dev, struct gem *gp, u32 gem_s
/* We do not track MAC_RXSTAT_FCE and MAC_RXSTAT_VCE
* events.
*/
- return 0;
+ return ret;
}
static int gem_mac_interrupt(struct net_device *dev, struct gem *gp, u32 gem_status)
@@ -480,7 +583,7 @@ static int gem_abnormal_irq(struct net_device *dev, struct gem *gp, u32 gem_stat
return 0;
do_reset:
- gp->reset_task_pending = 1;
+ gp->reset_task_pending = 2;
schedule_task(&gp->reset_task);
return 1;
@@ -542,7 +645,7 @@ static __inline__ void gem_tx(struct net_device *dev, struct gem *gp, u32 gem_st
gp->tx_old = entry;
if (netif_queue_stopped(dev) &&
- TX_BUFFS_AVAIL(gp) > 0)
+ TX_BUFFS_AVAIL(gp) > (MAX_SKB_FRAGS + 1))
netif_wake_queue(dev);
}
@@ -717,7 +820,7 @@ static void gem_tx_timeout(struct net_device *dev)
spin_lock_irq(&gp->lock);
- gp->reset_task_pending = 1;
+ gp->reset_task_pending = 2;
schedule_task(&gp->reset_task);
spin_unlock_irq(&gp->lock);
@@ -752,9 +855,12 @@ static int gem_start_xmit(struct sk_buff *skb, struct net_device *dev)
spin_lock_irq(&gp->lock);
+ /* This is a hard error, log it. */
if (TX_BUFFS_AVAIL(gp) <= (skb_shinfo(skb)->nr_frags + 1)) {
netif_stop_queue(dev);
spin_unlock_irq(&gp->lock);
+ printk(KERN_ERR PFX "%s: BUG! Tx Ring full when queue awake!\n",
+ dev->name);
return 1;
}
@@ -829,7 +935,7 @@ static int gem_start_xmit(struct sk_buff *skb, struct net_device *dev)
}
gp->tx_new = entry;
- if (TX_BUFFS_AVAIL(gp) <= 0)
+ if (TX_BUFFS_AVAIL(gp) <= (MAX_SKB_FRAGS + 1))
netif_stop_queue(dev);
if (netif_msg_tx_queued(gp))
@@ -844,19 +950,28 @@ static int gem_start_xmit(struct sk_buff *skb, struct net_device *dev)
}
/* Jumbo-grams don't seem to work :-( */
+#define GEM_MIN_MTU 68
#if 1
-#define MAX_MTU 1500
+#define GEM_MAX_MTU 1500
#else
-#define MAX_MTU 9000
+#define GEM_MAX_MTU 9000
#endif
static int gem_change_mtu(struct net_device *dev, int new_mtu)
{
struct gem *gp = dev->priv;
- if (new_mtu < 0 || new_mtu > MAX_MTU)
+ if (new_mtu < GEM_MIN_MTU || new_mtu > GEM_MAX_MTU)
return -EINVAL;
+ if (!netif_running(dev) || !netif_device_present(dev)) {
+ /* We'll just catch it later when the
+ * device is up'd or resumed.
+ */
+ dev->mtu = new_mtu;
+ return 0;
+ }
+
spin_lock_irq(&gp->lock);
dev->mtu = new_mtu;
gp->reset_task_pending = 1;
@@ -870,6 +985,7 @@ static int gem_change_mtu(struct net_device *dev, int new_mtu)
#define STOP_TRIES 32
+/* Must be invoked under gp->lock. */
static void gem_stop(struct gem *gp)
{
int limit;
@@ -879,7 +995,8 @@ static void gem_stop(struct gem *gp)
writel(0xffffffff, gp->regs + GREG_IMASK);
/* Reset the chip */
- writel(GREG_SWRST_TXRST | GREG_SWRST_RXRST, gp->regs + GREG_SWRST);
+ writel(gp->swrst_base | GREG_SWRST_TXRST | GREG_SWRST_RXRST,
+ gp->regs + GREG_SWRST);
limit = STOP_TRIES;
@@ -894,6 +1011,7 @@ static void gem_stop(struct gem *gp)
printk(KERN_ERR "gem: SW reset is ghetto.\n");
}
+/* Must be invoked under gp->lock. */
static void gem_start_dma(struct gem *gp)
{
unsigned long val;
@@ -929,6 +1047,7 @@ static int phy_BCM5400_link_table[8][3] = {
{ 1, 0, 1 }, /* 1000BT */
};
+/* Must be invoked under gp->lock. */
static void gem_begin_auto_negotiation(struct gem *gp, struct ethtool_cmd *ep)
{
u16 ctl;
@@ -954,11 +1073,8 @@ static void gem_begin_auto_negotiation(struct gem *gp, struct ethtool_cmd *ep)
}
start_aneg:
- spin_lock_irq(&gp->lock);
- if (!gp->hw_running) {
- spin_unlock_irq(&gp->lock);
+ if (!gp->hw_running)
return;
- }
/* Configure PHY & start aneg */
ctl = phy_read(gp, MII_BMCR);
@@ -973,11 +1089,10 @@ start_aneg:
phy_write(gp, MII_BMCR, ctl);
gp->timer_ticks = 0;
- gp->link_timer.expires = jiffies + ((12 * HZ) / 10);
- add_timer(&gp->link_timer);
- spin_unlock_irq(&gp->lock);
+ mod_timer(&gp->link_timer, jiffies + ((12 * HZ) / 10));
}
+/* Must be invoked under gp->lock. */
static void gem_read_mii_link_mode(struct gem *gp, int *fd, int *spd, int *pause)
{
u32 val;
@@ -1021,6 +1136,8 @@ static void gem_read_mii_link_mode(struct gem *gp, int *fd, int *spd, int *pause
/* A link-up condition has occurred, initialize and enable the
* rest of the chip.
+ *
+ * Must be invoked under gp->lock.
*/
static void gem_set_link_modes(struct gem *gp)
{
@@ -1101,6 +1218,20 @@ static void gem_set_link_modes(struct gem *gp)
pause = 1;
}
+ if (netif_msg_link(gp)) {
+ if (pause) {
+ printk(KERN_INFO "%s: Pause is enabled "
+ "(rxfifo: %d off: %d on: %d)\n",
+ gp->dev->name,
+ gp->rx_fifo_sz,
+ gp->rx_pause_off,
+ gp->rx_pause_on);
+ } else {
+ printk(KERN_INFO "%s: Pause is disabled\n",
+ gp->dev->name);
+ }
+ }
+
if (!full_duplex)
writel(512, gp->regs + MAC_STIME);
else
@@ -1115,6 +1246,7 @@ static void gem_set_link_modes(struct gem *gp)
gem_start_dma(gp);
}
+/* Must be invoked under gp->lock. */
static int gem_mdio_link_not_up(struct gem *gp)
{
u16 val;
@@ -1158,7 +1290,7 @@ static int gem_mdio_link_not_up(struct gem *gp)
return 0;
}
-static void gem_init_rings(struct gem *, int);
+static void gem_init_rings(struct gem *);
static void gem_init_hw(struct gem *, int);
static void gem_reset_task(void *data)
@@ -1169,24 +1301,27 @@ static void gem_reset_task(void *data)
* DMA stopped. Todo: Use this function for reset
* on error as well.
*/
+
+ spin_lock_irq(&gp->lock);
+
if (gp->hw_running && gp->opened) {
/* Make sure we don't get interrupts or tx packets */
- spin_lock_irq(&gp->lock);
-
netif_stop_queue(gp->dev);
writel(0xffffffff, gp->regs + GREG_IMASK);
- spin_unlock_irq(&gp->lock);
-
/* Reset the chip & rings */
gem_stop(gp);
- gem_init_rings(gp, 0);
- gem_init_hw(gp, 0);
+ gem_init_rings(gp);
+
+ gem_init_hw(gp,
+ (gp->reset_task_pending == 2));
netif_wake_queue(gp->dev);
}
gp->reset_task_pending = 0;
+
+ spin_unlock_irq(&gp->lock);
}
static void gem_link_timer(unsigned long data)
@@ -1196,13 +1331,14 @@ static void gem_link_timer(unsigned long data)
if (!gp->hw_running)
return;
+ spin_lock_irq(&gp->lock);
+
/* If the link of task is still pending, we just
* reschedule the link timer
*/
if (gp->reset_task_pending)
goto restart;
- spin_lock_irq(&gp->lock);
if (gp->phy_type == phy_mii_mdio0 ||
gp->phy_type == phy_mii_mdio1) {
u16 val = phy_read(gp, MII_BMSR);
@@ -1247,16 +1383,15 @@ static void gem_link_timer(unsigned long data)
if (netif_msg_link(gp))
printk(KERN_INFO "%s: Link down\n",
gp->dev->name);
- gp->reset_task_pending = 1;
+ gp->reset_task_pending = 2;
schedule_task(&gp->reset_task);
restart = 1;
} else if (++gp->timer_ticks > 10)
restart = gem_mdio_link_not_up(gp);
if (restart) {
- spin_unlock_irq(&gp->lock);
gem_begin_auto_negotiation(gp, NULL);
- return;
+ goto out_unlock;
}
}
} else {
@@ -1273,11 +1408,12 @@ static void gem_link_timer(unsigned long data)
}
restart:
- gp->link_timer.expires = jiffies + ((12 * HZ) / 10);
- add_timer(&gp->link_timer);
+ mod_timer(&gp->link_timer, jiffies + ((12 * HZ) / 10));
+out_unlock:
spin_unlock_irq(&gp->lock);
}
+/* Must be invoked under gp->lock. */
static void gem_clean_rings(struct gem *gp)
{
struct gem_init_block *gb = gp->init_block;
@@ -1311,7 +1447,9 @@ static void gem_clean_rings(struct gem *gp)
gp->tx_skbs[i] = NULL;
for (frag = 0; frag <= skb_shinfo(skb)->nr_frags; frag++) {
- txd = &gb->txd[i];
+ int ent = i & (TX_RING_SIZE - 1);
+
+ txd = &gb->txd[ent];
dma_addr = le64_to_cpu(txd->buffer);
pci_unmap_page(gp->pdev, dma_addr,
le64_to_cpu(txd->control_word) &
@@ -1325,16 +1463,14 @@ static void gem_clean_rings(struct gem *gp)
}
}
-static void gem_init_rings(struct gem *gp, int from_irq)
+/* Must be invoked under gp->lock. */
+static void gem_init_rings(struct gem *gp)
{
struct gem_init_block *gb = gp->init_block;
struct net_device *dev = gp->dev;
- int i, gfp_flags = GFP_KERNEL;
+ int i;
dma_addr_t dma_addr;
- if (from_irq)
- gfp_flags = GFP_ATOMIC;
-
gp->rx_new = gp->rx_old = gp->tx_new = gp->tx_old = 0;
gem_clean_rings(gp);
@@ -1343,7 +1479,7 @@ static void gem_init_rings(struct gem *gp, int from_irq)
struct sk_buff *skb;
struct gem_rxd *rxd = &gb->rxd[i];
- skb = gem_alloc_skb(RX_BUF_ALLOC_SIZE(gp), gfp_flags);
+ skb = gem_alloc_skb(RX_BUF_ALLOC_SIZE(gp), GFP_ATOMIC);
if (!skb) {
rxd->buffer = 0;
rxd->status_word = 0;
@@ -1372,6 +1508,7 @@ static void gem_init_rings(struct gem *gp, int from_irq)
}
}
+/* Must be invoked under gp->lock. */
static int gem_reset_one_mii_phy(struct gem *gp, int phy_addr)
{
u16 val;
@@ -1396,6 +1533,7 @@ static int gem_reset_one_mii_phy(struct gem *gp, int phy_addr)
return (limit <= 0);
}
+/* Must be invoked under gp->lock. */
static void gem_init_bcm5201_phy(struct gem *gp)
{
u16 data;
@@ -1405,6 +1543,7 @@ static void gem_init_bcm5201_phy(struct gem *gp)
phy_write(gp, MII_BCM5201_MULTIPHY, data);
}
+/* Must be invoked under gp->lock. */
static void gem_init_bcm5400_phy(struct gem *gp)
{
u16 data;
@@ -1432,6 +1571,7 @@ static void gem_init_bcm5400_phy(struct gem *gp)
phy_write(gp, MII_BCM5400_AUXCONTROL, data);
}
+/* Must be invoked under gp->lock. */
static void gem_init_bcm5401_phy(struct gem *gp)
{
u16 data;
@@ -1446,6 +1586,9 @@ static void gem_init_bcm5401_phy(struct gem *gp)
* WARNING ! OF and Darwin don't agree on the
* register addresses. OF seem to interpret the
* register numbers below as decimal
+ *
+ * Note: This should (and does) match tg3_init_5401phy_dsp
+ * in the tg3.c driver. -DaveM
*/
phy_write(gp, 0x18, 0x0c20);
phy_write(gp, 0x17, 0x0012);
@@ -1475,6 +1618,7 @@ static void gem_init_bcm5401_phy(struct gem *gp)
__phy_write(gp, MII_BCM5201_MULTIPHY, data, 0x1f);
}
+/* Must be invoked under gp->lock. */
static void gem_init_bcm5411_phy(struct gem *gp)
{
u16 data;
@@ -1501,6 +1645,7 @@ static void gem_init_bcm5411_phy(struct gem *gp)
phy_write(gp, MII_BCM5400_GB_CONTROL, data);
}
+/* Must be invoked under gp->lock. */
static void gem_init_phy(struct gem *gp)
{
u32 mifcfg;
@@ -1649,7 +1794,9 @@ static void gem_init_phy(struct gem *gp)
val &= ~(PCS_CFG_ENABLE | PCS_CFG_TO);
writel(val, gp->regs + PCS_CFG);
- /* Advertise all capabilities. */
+ /* Advertise all capabilities except assymetric
+ * pause.
+ */
val = readl(gp->regs + PCS_MIIADV);
val |= (PCS_MIIADV_FD | PCS_MIIADV_HD |
PCS_MIIADV_SP | PCS_MIIADV_AP);
@@ -1684,9 +1831,9 @@ static void gem_init_phy(struct gem *gp)
if (gp->phy_mod != phymod_bcm5400 && gp->phy_mod != phymod_bcm5401 &&
gp->phy_mod != phymod_bcm5411)
gp->link_cntl &= ~BMCR_SPD2;
-
}
+/* Must be invoked under gp->lock. */
static void gem_init_dma(struct gem *gp)
{
u64 desc_dma = (u64) gp->gblock_dvma;
@@ -1702,7 +1849,7 @@ static void gem_init_dma(struct gem *gp)
writel(0, gp->regs + TXDMA_KICK);
val = (RXDMA_CFG_BASE | (RX_OFFSET << 10) |
- ((14 / 2) << 13) | RXDMA_CFG_FTHRESH_512);
+ ((14 / 2) << 13) | RXDMA_CFG_FTHRESH_128);
writel(val, gp->regs + RXDMA_CFG);
writel(desc_dma >> 32, gp->regs + RXDMA_DBHI);
@@ -1724,6 +1871,7 @@ static void gem_init_dma(struct gem *gp)
gp->regs + RXDMA_BLANK);
}
+/* Must be invoked under gp->lock. */
static u32
gem_setup_multicast(struct gem *gp)
{
@@ -1766,10 +1914,10 @@ gem_setup_multicast(struct gem *gp)
return rxcfg;
}
+/* Must be invoked under gp->lock. */
static void gem_init_mac(struct gem *gp)
{
unsigned char *e = &gp->dev->dev_addr[0];
- u32 rxcfg;
if (gp->pdev->vendor == PCI_VENDOR_ID_SUN &&
gp->pdev->device == PCI_DEVICE_ID_SUN_GEM)
@@ -1780,7 +1928,10 @@ static void gem_init_mac(struct gem *gp)
writel(0x04, gp->regs + MAC_IPG2);
writel(0x40, gp->regs + MAC_STIME);
writel(0x40, gp->regs + MAC_MINFSZ);
- writel(0x20000000 | (gp->dev->mtu + 18), gp->regs + MAC_MAXFSZ);
+
+ /* Ethernet payload + header + FCS + optional VLAN tag. */
+ writel(0x20000000 | (gp->dev->mtu + ETH_HLEN + 4 + 4), gp->regs + MAC_MAXFSZ);
+
writel(0x07, gp->regs + MAC_PASIZE);
writel(0x04, gp->regs + MAC_JAMSIZE);
writel(0x10, gp->regs + MAC_ATTLIM);
@@ -1806,7 +1957,7 @@ static void gem_init_mac(struct gem *gp)
writel(0, gp->regs + MAC_AF21MSK);
writel(0, gp->regs + MAC_AF0MSK);
- rxcfg = gem_setup_multicast(gp);
+ gp->mac_rx_cfg = gem_setup_multicast(gp);
writel(0, gp->regs + MAC_NCOLL);
writel(0, gp->regs + MAC_FASUCC);
@@ -1824,7 +1975,7 @@ static void gem_init_mac(struct gem *gp)
* them once a link is established.
*/
writel(0, gp->regs + MAC_TXCFG);
- writel(rxcfg, gp->regs + MAC_RXCFG);
+ writel(gp->mac_rx_cfg, gp->regs + MAC_RXCFG);
writel(0, gp->regs + MAC_MCCFG);
writel(0, gp->regs + MAC_XIFCFG);
@@ -1841,6 +1992,7 @@ static void gem_init_mac(struct gem *gp)
writel(0xffffffff, gp->regs + MAC_MCMASK);
}
+/* Must be invoked under gp->lock. */
static void gem_init_pause_thresholds(struct gem *gp)
{
/* Calculate pause thresholds. Setting the OFF threshold to the
@@ -1851,8 +2003,9 @@ static void gem_init_pause_thresholds(struct gem *gp)
if (gp->rx_fifo_sz <= (2 * 1024)) {
gp->rx_pause_off = gp->rx_pause_on = gp->rx_fifo_sz;
} else {
- int off = (gp->rx_fifo_sz - (5 * 1024));
- int on = off - 1024;
+ int max_frame = (gp->dev->mtu + ETH_HLEN + 4 + 4 + 64) & ~63;
+ int off = (gp->rx_fifo_sz - (max_frame * 2));
+ int on = off - max_frame;
gp->rx_pause_off = off;
gp->rx_pause_on = on;
@@ -1861,7 +2014,10 @@ static void gem_init_pause_thresholds(struct gem *gp)
{
u32 cfg;
- cfg = GREG_CFG_IBURST;
+ cfg = 0;
+#if !defined(CONFIG_SPARC64) && !defined(CONFIG_ALPHA)
+ cfg |= GREG_CFG_IBURST;
+#endif
cfg |= ((31 << 1) & GREG_CFG_TXDMALIM);
cfg |= ((31 << 6) & GREG_CFG_RXDMALIM);
writel(cfg, gp->regs + GREG_CFG);
@@ -1881,6 +2037,7 @@ static int gem_check_invariants(struct gem *gp)
gp->phy_type = phy_mii_mdio0;
gp->tx_fifo_sz = readl(gp->regs + TXDMA_FSZ) * 64;
gp->rx_fifo_sz = readl(gp->regs + RXDMA_FSZ) * 64;
+ gp->swrst_base = 0;
return 0;
}
@@ -1943,6 +2100,7 @@ static int gem_check_invariants(struct gem *gp)
gp->tx_fifo_sz, gp->rx_fifo_sz);
return -1;
}
+ gp->swrst_base = 0;
} else {
if (gp->tx_fifo_sz != (2 * 1024) ||
gp->rx_fifo_sz != (2 * 1024)) {
@@ -1950,12 +2108,14 @@ static int gem_check_invariants(struct gem *gp)
gp->tx_fifo_sz, gp->rx_fifo_sz);
return -1;
}
+ gp->swrst_base = (64 / 4) << GREG_SWRST_CACHE_SHIFT;
}
}
return 0;
}
+/* Must be invoked under gp->lock. */
static void gem_init_hw(struct gem *gp, int restart_link)
{
/* On Apple's gmac, I initialize the PHY only after
@@ -1970,21 +2130,16 @@ static void gem_init_hw(struct gem *gp, int restart_link)
gem_init_mac(gp);
gem_init_pause_thresholds(gp);
- spin_lock_irq(&gp->lock);
if (restart_link) {
/* Default aneg parameters */
gp->timer_ticks = 0;
gp->lstate = link_down;
- spin_unlock_irq(&gp->lock);
-
/* Can I advertise gigabit here ? I'd need BCM PHY docs... */
gem_begin_auto_negotiation(gp, NULL);
} else {
if (gp->lstate == link_up)
gem_set_link_modes(gp);
-
- spin_unlock_irq(&gp->lock);
}
}
@@ -2029,6 +2184,7 @@ static void gem_apple_powerdown(struct gem *gp)
#endif /* CONFIG_ALL_PPC */
+/* Must be invoked under gp->lock. */
static void gem_stop_phy(struct gem *gp)
{
u32 mifcfg;
@@ -2100,14 +2256,21 @@ static void gem_shutdown(struct gem *gp)
schedule();
/* Actually stop the chip */
+ spin_lock_irq(&gp->lock);
if (gp->pdev->vendor == PCI_VENDOR_ID_APPLE) {
gem_stop_phy(gp);
+
+ spin_unlock_irq(&gp->lock);
+
#ifdef CONFIG_ALL_PPC
/* Power down the chip */
gem_apple_powerdown(gp);
#endif /* CONFIG_ALL_PPC */
- } else
+ } else {
gem_stop(gp);
+
+ spin_unlock_irq(&gp->lock);
+ }
}
static void gem_pm_task(void *data)
@@ -2142,14 +2305,19 @@ static void gem_pm_timer(unsigned long data)
static int gem_open(struct net_device *dev)
{
struct gem *gp = dev->priv;
- int hw_was_up = gp->hw_running;
+ int hw_was_up;
down(&gp->pm_sem);
+ hw_was_up = gp->hw_running;
+
/* Stop the PM timer/task */
del_timer(&gp->pm_timer);
flush_scheduled_tasks();
+ /* The power-management semaphore protects the hw_running
+ * etc. state so it is safe to do this bit without gp->lock
+ */
if (!gp->hw_running) {
#ifdef CONFIG_ALL_PPC
/* First, we need to bring up the chip */
@@ -2158,18 +2326,26 @@ static int gem_open(struct net_device *dev)
gem_check_invariants(gp);
}
#endif /* CONFIG_ALL_PPC */
+
/* Reset the chip */
+ spin_lock_irq(&gp->lock);
gem_stop(gp);
+ spin_unlock_irq(&gp->lock);
gp->hw_running = 1;
}
+ spin_lock_irq(&gp->lock);
+
/* We can now request the interrupt as we know it's masked
* on the controller
*/
if (request_irq(gp->pdev->irq, gem_interrupt,
SA_SHIRQ, dev->name, (void *)dev)) {
+ spin_unlock_irq(&gp->lock);
+
printk(KERN_ERR "%s: failed to request irq !\n", gp->dev->name);
+
#ifdef CONFIG_ALL_PPC
if (!hw_was_up && gp->pdev->vendor == PCI_VENDOR_ID_APPLE)
gem_apple_powerdown(gp);
@@ -2183,13 +2359,15 @@ static int gem_open(struct net_device *dev)
}
/* Allocate & setup ring buffers */
- gem_init_rings(gp, 0);
+ gem_init_rings(gp);
/* Init & setup chip hardware */
gem_init_hw(gp, !hw_was_up);
gp->opened = 1;
+ spin_unlock_irq(&gp->lock);
+
up(&gp->pm_sem);
return 0;
@@ -2209,8 +2387,6 @@ static int gem_close(struct net_device *dev)
writel(0xffffffff, gp->regs + GREG_IMASK);
netif_stop_queue(dev);
- spin_unlock_irq(&gp->lock);
-
/* Stop chip */
gem_stop(gp);
@@ -2220,6 +2396,8 @@ static int gem_close(struct net_device *dev)
/* Bye, the pm timer will finish the job */
free_irq(gp->pdev->irq, (void *) dev);
+ spin_unlock_irq(&gp->lock);
+
/* Fire the PM timer that will shut us down in about 10 seconds */
gp->pm_timer.expires = jiffies + 10*HZ;
add_timer(&gp->pm_timer);
@@ -2245,21 +2423,21 @@ static int gem_suspend(struct pci_dev *pdev, u32 state)
/* If the driver is opened, we stop the DMA */
if (gp->opened) {
+ spin_lock_irq(&gp->lock);
+
/* Stop traffic, mark us closed */
netif_device_detach(dev);
- spin_lock_irq(&gp->lock);
-
writel(0xffffffff, gp->regs + GREG_IMASK);
- spin_unlock_irq(&gp->lock);
-
/* Stop chip */
gem_stop(gp);
/* Get rid of ring buffers */
gem_clean_rings(gp);
+ spin_unlock_irq(&gp->lock);
+
if (gp->pdev->vendor == PCI_VENDOR_ID_APPLE)
disable_irq(gp->pdev->irq);
}
@@ -2290,10 +2468,15 @@ static int gem_resume(struct pci_dev *pdev)
gem_check_invariants(gp);
}
#endif /* CONFIG_ALL_PPC */
+ spin_lock_irq(&gp->lock);
+
gem_stop(gp);
gp->hw_running = 1;
- gem_init_rings(gp, 0);
+ gem_init_rings(gp);
gem_init_hw(gp, 1);
+
+ spin_unlock_irq(&gp->lock);
+
netif_device_attach(dev);
if (gp->pdev->vendor == PCI_VENDOR_ID_APPLE)
enable_irq(gp->pdev->irq);
@@ -2309,6 +2492,8 @@ static struct net_device_stats *gem_get_stats(struct net_device *dev)
struct gem *gp = dev->priv;
struct net_device_stats *stats = &gp->net_stats;
+ spin_lock_irq(&gp->lock);
+
if (gp->hw_running) {
stats->rx_crc_errors += readl(gp->regs + MAC_FCSERR);
writel(0, gp->regs + MAC_FCSERR);
@@ -2326,6 +2511,9 @@ static struct net_device_stats *gem_get_stats(struct net_device *dev)
writel(0, gp->regs + MAC_ECOLL);
writel(0, gp->regs + MAC_LCOLL);
}
+
+ spin_unlock_irq(&gp->lock);
+
return &gp->net_stats;
}
@@ -2338,10 +2526,12 @@ static void gem_set_multicast(struct net_device *dev)
if (!gp->hw_running)
return;
+ spin_lock_irq(&gp->lock);
+
netif_stop_queue(dev);
rxcfg = readl(gp->regs + MAC_RXCFG);
- rxcfg_new = gem_setup_multicast(gp);
+ gp->mac_rx_cfg = rxcfg_new = gem_setup_multicast(gp);
writel(rxcfg & ~MAC_RXCFG_ENAB, gp->regs + MAC_RXCFG);
while (readl(gp->regs + MAC_RXCFG) & MAC_RXCFG_ENAB) {
@@ -2355,8 +2545,9 @@ static void gem_set_multicast(struct net_device *dev)
writel(rxcfg, gp->regs + MAC_RXCFG);
- /* Hrm... we may walk on the reset task here... */
netif_wake_queue(dev);
+
+ spin_unlock_irq(&gp->lock);
}
/* Eventually add support for changing the advertisement
@@ -2405,11 +2596,13 @@ static int gem_ethtool_ioctl(struct net_device *dev, void *ep_user)
ecmd.phy_address = 0; /* XXX fixed PHYAD */
/* Record PHY settings if HW is on. */
+ spin_lock_irq(&gp->lock);
if (gp->hw_running) {
bmcr = phy_read(gp, MII_BMCR);
gem_read_mii_link_mode(gp, &full_duplex, &speed, &pause);
} else
bmcr = 0;
+ spin_unlock_irq(&gp->lock);
if (bmcr & BMCR_ANENABLE) {
ecmd.autoneg = AUTONEG_ENABLE;
ecmd.speed = speed == 10 ? SPEED_10 : (speed == 1000 ? SPEED_1000 : SPEED_100);
@@ -2443,18 +2636,22 @@ static int gem_ethtool_ioctl(struct net_device *dev, void *ep_user)
ecmd.duplex != DUPLEX_FULL)))
return -EINVAL;
- /* Apply settings and restart link process */
- if (gp->hw_running)
- del_timer(&gp->link_timer);
+ /* Apply settings and restart link process. */
+ spin_lock_irq(&gp->lock);
gem_begin_auto_negotiation(gp, &ecmd);
+ spin_unlock_irq(&gp->lock);
+
return 0;
case ETHTOOL_NWAY_RST:
if ((gp->link_cntl & BMCR_ANENABLE) == 0)
return -EINVAL;
- if (gp->hw_running)
- del_timer(&gp->link_timer);
+
+ /* Restart link process. */
+ spin_lock_irq(&gp->lock);
gem_begin_auto_negotiation(gp, NULL);
+ spin_unlock_irq(&gp->lock);
+
return 0;
case ETHTOOL_GWOL:
@@ -2570,13 +2767,74 @@ static int gem_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
return rc;
}
+#if (!defined(__sparc__) && !defined(CONFIG_ALL_PPC))
+/* Fetch MAC address from vital product data of PCI ROM. */
+static void find_eth_addr_in_vpd(void *rom_base, int len, unsigned char *dev_addr)
+{
+ int this_offset;
+
+ for (this_offset = 0x20; this_offset < len; this_offset++) {
+ void *p = rom_base + this_offset;
+ int i;
+
+ if (readb(p + 0) != 0x90 ||
+ readb(p + 1) != 0x00 ||
+ readb(p + 2) != 0x09 ||
+ readb(p + 3) != 0x4e ||
+ readb(p + 4) != 0x41 ||
+ readb(p + 5) != 0x06)
+ continue;
+
+ this_offset += 6;
+ p += 6;
+
+ for (i = 0; i < 6; i++)
+ dev_addr[i] = readb(p + i);
+ break;
+ }
+}
+
+static void get_gem_mac_nonobp(struct pci_dev *pdev, unsigned char *dev_addr)
+{
+ u32 rom_reg_orig;
+ void *p;
+
+ if (pdev->resource[PCI_ROM_RESOURCE].parent == NULL) {
+ if (pci_assign_resource(pdev, PCI_ROM_RESOURCE) < 0)
+ goto use_random;
+ }
+
+ pci_read_config_dword(pdev, pdev->rom_base_reg, &rom_reg_orig);
+ pci_write_config_dword(pdev, pdev->rom_base_reg,
+ rom_reg_orig | PCI_ROM_ADDRESS_ENABLE);
+
+ p = ioremap(pci_resource_start(pdev, PCI_ROM_RESOURCE), (64 * 1024));
+ if (p != NULL && readb(p) == 0x55 && readb(p + 1) == 0xaa)
+ find_eth_addr_in_vpd(p, (64 * 1024), dev_addr);
+
+ if (p != NULL)
+ iounmap(p);
+
+ pci_write_config_dword(pdev, pdev->rom_base_reg, rom_reg_orig);
+ return;
+
+use_random:
+ /* Sun MAC prefix then 3 random bytes. */
+ dev_addr[0] = 0x08;
+ dev_addr[1] = 0x00;
+ dev_addr[2] = 0x20;
+ get_random_bytes(dev_addr, 3);
+ return;
+}
+#endif /* not Sparc and not PPC */
+
static int __devinit gem_get_device_address(struct gem *gp)
{
#if defined(__sparc__) || defined(CONFIG_ALL_PPC)
struct net_device *dev = gp->dev;
#endif
-#ifdef __sparc__
+#if defined(__sparc__)
struct pci_dev *pdev = gp->pdev;
struct pcidev_cookie *pcp = pdev->sysdata;
int node = -1;
@@ -2591,8 +2849,7 @@ static int __devinit gem_get_device_address(struct gem *gp)
}
if (node == -1)
memcpy(dev->dev_addr, idprom->id_ethaddr, 6);
-#endif
-#ifdef CONFIG_ALL_PPC
+#elif defined(CONFIG_ALL_PPC)
unsigned char *addr;
addr = get_property(gp->of_node, "local-mac-address", NULL);
@@ -2602,6 +2859,8 @@ static int __devinit gem_get_device_address(struct gem *gp)
return -1;
}
memcpy(dev->dev_addr, addr, MAX_ADDR_LEN);
+#else
+ get_gem_mac_nonobp(gp->pdev, gp->dev->dev_addr);
#endif
return 0;
}
@@ -2664,21 +2923,21 @@ static int __devinit gem_init_one(struct pci_dev *pdev,
return -ENODEV;
}
- dev = init_etherdev(NULL, sizeof(*gp));
+ dev = alloc_etherdev(sizeof(*gp));
if (!dev) {
- printk(KERN_ERR PFX "Etherdev init failed, aborting.\n");
+ printk(KERN_ERR PFX "Etherdev alloc failed, aborting.\n");
return -ENOMEM;
}
SET_MODULE_OWNER(dev);
- if (!request_mem_region(gemreg_base, gemreg_len, dev->name)) {
- printk(KERN_ERR PFX "MMIO resource (0x%lx@0x%lx) unavailable, "
- "aborting.\n", gemreg_base, gemreg_len);
+ gp = dev->priv;
+
+ if (pci_request_regions(pdev, dev->name)) {
+ printk(KERN_ERR PFX "Cannot obtain PCI resources, "
+ "aborting.\n");
goto err_out_free_netdev;
}
- gp = dev->priv;
-
gp->pdev = pdev;
dev->base_addr = (long) pdev;
gp->dev = dev;
@@ -2711,7 +2970,7 @@ static int __devinit gem_init_one(struct pci_dev *pdev,
if (gp->regs == 0UL) {
printk(KERN_ERR PFX "Cannot map device registers, "
"aborting.\n");
- goto err_out_free_mmio_res;
+ goto err_out_free_res;
}
/* On Apple, we power the chip up now in order for check
@@ -2722,12 +2981,18 @@ static int __devinit gem_init_one(struct pci_dev *pdev,
if (pdev->vendor == PCI_VENDOR_ID_APPLE)
gem_apple_powerup(gp);
#endif
+ spin_lock_irq(&gp->lock);
gem_stop(gp);
+ spin_unlock_irq(&gp->lock);
+
if (gem_check_invariants(gp))
goto err_out_iounmap;
+
+ spin_lock_irq(&gp->lock);
gp->hw_running = 1;
gem_init_phy(gp);
gem_begin_auto_negotiation(gp, NULL);
+ spin_unlock_irq(&gp->lock);
/* It is guarenteed that the returned buffer will be at least
* PAGE_SIZE aligned.
@@ -2741,22 +3006,28 @@ static int __devinit gem_init_one(struct pci_dev *pdev,
goto err_out_iounmap;
}
- pci_set_drvdata(pdev, dev);
-
- printk(KERN_INFO "%s: Sun GEM (PCI) 10/100/1000BaseT Ethernet ",
- dev->name);
-
#ifdef CONFIG_ALL_PPC
gp->of_node = pci_device_to_OF_node(pdev);
#endif
if (gem_get_device_address(gp))
- goto err_out_iounmap;
+ goto err_out_free_consistent;
+
+ if (register_netdev(dev)) {
+ printk(KERN_ERR PFX "Cannot register net device, "
+ "aborting.\n");
+ goto err_out_free_consistent;
+ }
+
+ printk(KERN_INFO "%s: Sun GEM (PCI) 10/100/1000BaseT Ethernet ",
+ dev->name);
for (i = 0; i < 6; i++)
printk("%2.2x%c", dev->dev_addr[i],
i == 5 ? ' ' : ':');
printk("\n");
+ pci_set_drvdata(pdev, dev);
+
dev->open = gem_open;
dev->stop = gem_close;
dev->hard_start_xmit = gem_start_xmit;
@@ -2780,6 +3051,12 @@ static int __devinit gem_init_one(struct pci_dev *pdev,
return 0;
+err_out_free_consistent:
+ pci_free_consistent(pdev,
+ sizeof(struct gem_init_block),
+ gp->init_block,
+ gp->gblock_dvma);
+
err_out_iounmap:
down(&gp->pm_sem);
/* Stop the PM timer & task */
@@ -2788,13 +3065,13 @@ err_out_iounmap:
if (gp->hw_running)
gem_shutdown(gp);
up(&gp->pm_sem);
+
iounmap((void *) gp->regs);
-err_out_free_mmio_res:
- release_mem_region(gemreg_base, gemreg_len);
+err_out_free_res:
+ pci_release_regions(pdev);
err_out_free_netdev:
- unregister_netdev(dev);
kfree(dev);
return -ENODEV;
@@ -2823,8 +3100,7 @@ static void __devexit gem_remove_one(struct pci_dev *pdev)
gp->init_block,
gp->gblock_dvma);
iounmap((void *) gp->regs);
- release_mem_region(pci_resource_start(pdev, 0),
- pci_resource_len(pdev, 0));
+ pci_release_regions(pdev);
kfree(dev);
pci_set_drvdata(pdev, NULL);
diff --git a/drivers/net/sungem.h b/drivers/net/sungem.h
index 971db64a446a9..d26652f9d64ef 100644
--- a/drivers/net/sungem.h
+++ b/drivers/net/sungem.h
@@ -94,6 +94,8 @@
#define GREG_SWRST_TXRST 0x00000001 /* TX Software Reset */
#define GREG_SWRST_RXRST 0x00000002 /* RX Software Reset */
#define GREG_SWRST_RSTOUT 0x00000004 /* Force RST# pin active */
+#define GREG_SWRST_CACHESIZE 0x00ff0000 /* RIO only: cache line size */
+#define GREG_SWRST_CACHE_SHIFT 16
/* TX DMA Registers */
#define TXDMA_KICK 0x2000UL /* TX Kick Register */
@@ -986,6 +988,9 @@ struct gem {
int mii_phy_addr;
int gigabit_capable;
+ u32 mac_rx_cfg;
+ u32 swrst_base;
+
/* Autoneg & PHY control */
int link_cntl;
int link_advertise;
diff --git a/drivers/net/sunhme.c b/drivers/net/sunhme.c
index 14c3e26652a8d..0a8aba5d08ab2 100644
--- a/drivers/net/sunhme.c
+++ b/drivers/net/sunhme.c
@@ -3,7 +3,7 @@
* auto carrier detecting ethernet driver. Also known as the
* "Happy Meal Ethernet" found on SunSwift SBUS cards.
*
- * Copyright (C) 1996, 1998, 1999 David S. Miller (davem@redhat.com)
+ * Copyright (C) 1996, 1998, 1999, 2002 David S. Miller (davem@redhat.com)
*
* Changes :
* 2000/11/11 Willy Tarreau <willy AT meta-x.org>
@@ -14,7 +14,7 @@
*/
static char version[] =
- "sunhme.c:v1.99 12/Sep/99 David S. Miller (davem@redhat.com)\n";
+ "sunhme.c:v2.01 26/Mar/2002 David S. Miller (davem@redhat.com)\n";
#include <linux/module.h>
@@ -34,6 +34,7 @@ static char version[] =
#include <linux/ethtool.h>
#include <linux/mii.h>
#include <linux/crc32.h>
+#include <linux/random.h>
#include <asm/system.h>
#include <asm/bitops.h>
#include <asm/io.h>
@@ -696,7 +697,7 @@ no_response:
return 1;
}
-static int happy_meal_init(struct happy_meal *hp, int from_irq);
+static int happy_meal_init(struct happy_meal *hp);
static int is_lucent_phy(struct happy_meal *hp)
{
@@ -707,12 +708,8 @@ static int is_lucent_phy(struct happy_meal *hp)
mr2 = happy_meal_tcvr_read(hp, tregs, 2);
mr3 = happy_meal_tcvr_read(hp, tregs, 3);
if ((mr2 & 0xffff) == 0x0180 &&
- ((mr3 & 0xffff) >> 10) == 0x1d) {
-#if 0
- printk("HMEDEBUG: Lucent PHY detected.\n");
-#endif
+ ((mr3 & 0xffff) >> 10) == 0x1d)
ret = 1;
- }
return ret;
}
@@ -723,6 +720,8 @@ static void happy_meal_timer(unsigned long data)
unsigned long tregs = hp->tcvregs;
int restart_timer = 0;
+ spin_lock_irq(&hp->happy_lock);
+
hp->timer_ticks++;
switch(hp->timer_state) {
case arbwait:
@@ -852,13 +851,13 @@ static void happy_meal_timer(unsigned long data)
printk(KERN_NOTICE "%s: Link down, cable problem?\n",
hp->dev->name);
- ret = happy_meal_init(hp, 0);
+ ret = happy_meal_init(hp);
if (ret) {
/* ho hum... */
printk(KERN_ERR "%s: Error, cannot re-init the "
"Happy Meal.\n", hp->dev->name);
}
- return;
+ goto out;
}
if (!is_lucent_phy(hp)) {
hp->sw_csconfig = happy_meal_tcvr_read(hp, tregs,
@@ -890,11 +889,15 @@ static void happy_meal_timer(unsigned long data)
hp->happy_timer.expires = jiffies + ((12 * HZ)/10); /* 1.2 sec. */
add_timer(&hp->happy_timer);
}
+
+out:
+ spin_unlock_irq(&hp->happy_lock);
}
#define TX_RESET_TRIES 32
#define RX_RESET_TRIES 32
+/* hp->happy_lock must be held */
static void happy_meal_tx_reset(struct happy_meal *hp, unsigned long bregs)
{
int tries = TX_RESET_TRIES;
@@ -914,6 +917,7 @@ static void happy_meal_tx_reset(struct happy_meal *hp, unsigned long bregs)
HMD(("done\n"));
}
+/* hp->happy_lock must be held */
static void happy_meal_rx_reset(struct happy_meal *hp, unsigned long bregs)
{
int tries = RX_RESET_TRIES;
@@ -935,6 +939,7 @@ static void happy_meal_rx_reset(struct happy_meal *hp, unsigned long bregs)
#define STOP_TRIES 16
+/* hp->happy_lock must be held */
static void happy_meal_stop(struct happy_meal *hp, unsigned long gregs)
{
int tries = STOP_TRIES;
@@ -954,6 +959,7 @@ static void happy_meal_stop(struct happy_meal *hp, unsigned long gregs)
HMD(("done\n"));
}
+/* hp->happy_lock must be held */
static void happy_meal_get_counters(struct happy_meal *hp, unsigned long bregs)
{
struct net_device_stats *stats = &hp->net_stats;
@@ -976,53 +982,7 @@ static void happy_meal_get_counters(struct happy_meal *hp, unsigned long bregs)
hme_write32(hp, bregs + BMAC_LTCTR, 0);
}
-#if 0
-static void happy_meal_poll_start(struct happy_meal *hp, unsigned long tregs)
-{
- u32 tmp;
- int speed;
-
- ASD(("happy_meal_poll_start: "));
- if (!(hp->happy_flags & HFLAG_POLLENABLE)) {
- HMD(("polling disabled, return\n"));
- return;
- }
-
- /* Start the MIF polling on the external transceiver. */
- ASD(("polling on, "));
- tmp = hme_read32(hp, tregs + TCVR_CFG);
- tmp &= ~(TCV_CFG_PDADDR | TCV_CFG_PREGADDR);
- tmp |= ((hp->paddr & 0x1f) << 10);
- tmp |= (TCV_PADDR_ETX << 3);
- tmp |= TCV_CFG_PENABLE;
- hme_write32(hp, tregs + TCVR_CFG, tmp);
-
- /* Let the bits set. */
- udelay(200);
-
- /* We are polling now. */
- ASD(("now polling, "));
- hp->happy_flags |= HFLAG_POLL;
-
- /* Clear the poll flags, get the basic status as of now. */
- hp->poll_flag = 0;
- hp->poll_data = hme_read32(hp, tregs + TCVR_STATUS) >> 16;
-
- if (hp->happy_flags & HFLAG_AUTO)
- speed = hp->auto_speed;
- else
- speed = hp->forced_speed;
-
- /* Listen only for the MIF interrupts we want to hear. */
- ASD(("mif ints on, "));
- if (speed == 100)
- hme_write32(hp, tregs + TCVR_IMASK, 0xfffb);
- else
- hme_write32(hp, tregs + TCVR_IMASK, 0xfff9);
- ASD(("done\n"));
-}
-#endif
-
+/* hp->happy_lock must be held */
static void happy_meal_poll_stop(struct happy_meal *hp, unsigned long tregs)
{
ASD(("happy_meal_poll_stop: "));
@@ -1057,6 +1017,7 @@ static void happy_meal_poll_stop(struct happy_meal *hp, unsigned long tregs)
#define TCVR_RESET_TRIES 16 /* It should reset quickly */
#define TCVR_UNISOLATE_TRIES 32 /* Dis-isolation can take longer. */
+/* hp->happy_lock must be held */
static int happy_meal_tcvr_reset(struct happy_meal *hp, unsigned long tregs)
{
u32 tconfig;
@@ -1151,7 +1112,10 @@ static int happy_meal_tcvr_reset(struct happy_meal *hp, unsigned long tregs)
return 0;
}
-/* Figure out whether we have an internal or external transceiver. */
+/* Figure out whether we have an internal or external transceiver.
+ *
+ * hp->happy_lock must be held
+ */
static void happy_meal_transceiver_check(struct happy_meal *hp, unsigned long tregs)
{
unsigned long tconfig = hme_read32(hp, tregs + TCVR_CFG);
@@ -1303,14 +1267,12 @@ static void happy_meal_clean_rings(struct happy_meal *hp)
}
}
-static void happy_meal_init_rings(struct happy_meal *hp, int from_irq)
+/* hp->happy_lock must be held */
+static void happy_meal_init_rings(struct happy_meal *hp)
{
struct hmeal_init_block *hb = hp->happy_block;
struct net_device *dev = hp->dev;
- int i, gfp_flags = GFP_KERNEL;
-
- if (from_irq || in_interrupt())
- gfp_flags = GFP_ATOMIC;
+ int i;
HMD(("happy_meal_init_rings: counters to zero, "));
hp->rx_new = hp->rx_old = hp->tx_new = hp->tx_old = 0;
@@ -1324,7 +1286,7 @@ static void happy_meal_init_rings(struct happy_meal *hp, int from_irq)
for (i = 0; i < RX_RING_SIZE; i++) {
struct sk_buff *skb;
- skb = happy_meal_alloc_skb(RX_BUF_ALLOC_SIZE, gfp_flags);
+ skb = happy_meal_alloc_skb(RX_BUF_ALLOC_SIZE, GFP_ATOMIC);
if (!skb) {
hme_write_rxd(hp, &hb->happy_meal_rxd[i], 0, 0);
continue;
@@ -1347,6 +1309,7 @@ static void happy_meal_init_rings(struct happy_meal *hp, int from_irq)
HMD(("done\n"));
}
+/* hp->happy_lock must be held */
static void happy_meal_begin_auto_negotiation(struct happy_meal *hp,
unsigned long tregs,
struct ethtool_cmd *ep)
@@ -1470,7 +1433,8 @@ force_link:
add_timer(&hp->happy_timer);
}
-static int happy_meal_init(struct happy_meal *hp, int from_irq)
+/* hp->happy_lock must be held */
+static int happy_meal_init(struct happy_meal *hp)
{
unsigned long gregs = hp->gregs;
unsigned long etxregs = hp->etxregs;
@@ -1501,7 +1465,7 @@ static int happy_meal_init(struct happy_meal *hp, int from_irq)
/* Alloc and reset the tx/rx descriptor chains. */
HMD(("happy_meal_init: to happy_meal_init_rings\n"));
- happy_meal_init_rings(hp, from_irq);
+ happy_meal_init_rings(hp);
/* Shut up the MIF. */
HMD(("happy_meal_init: Disable all MIF irqs (old[%08x]), ",
@@ -1618,6 +1582,17 @@ static int happy_meal_init(struct happy_meal *hp, int from_irq)
hme_write32(hp, etxregs + ETX_RING,
((__u32)hp->hblock_dvma + hblock_offset(happy_meal_txd, 0)));
+ /* Parity issues in the ERX unit of some HME revisions can cause some
+ * registers to not be written unless their parity is even. Detect such
+ * lost writes and simply rewrite with a low bit set (which will be ignored
+ * since the rxring needs to be 2K aligned).
+ */
+ if (hme_read32(hp, erxregs + ERX_RING) !=
+ ((__u32)hp->hblock_dvma + hblock_offset(happy_meal_rxd, 0)))
+ hme_write32(hp, erxregs + ERX_RING,
+ ((__u32)hp->hblock_dvma + hblock_offset(happy_meal_rxd, 0))
+ | 0x4);
+
/* Set the supported burst sizes. */
HMD(("happy_meal_init: old[%08x] bursts<",
hme_read32(hp, gregs + GREG_CFG)));
@@ -1698,7 +1673,7 @@ static int happy_meal_init(struct happy_meal *hp, int from_irq)
/* Enable Big Mac hash table filter. */
HMD(("happy_meal_init: enable hash rx_cfg_old[%08x], ",
hme_read32(hp, bregs + BMAC_RXCFG)));
- rxcfg = BIGMAC_RXCFG_HENABLE;
+ rxcfg = BIGMAC_RXCFG_HENABLE | BIGMAC_RXCFG_REJME;
if (hp->dev->flags & IFF_PROMISC)
rxcfg |= BIGMAC_RXCFG_PMISC;
hme_write32(hp, bregs + BMAC_RXCFG, rxcfg);
@@ -1711,7 +1686,14 @@ static int happy_meal_init(struct happy_meal *hp, int from_irq)
regtmp = 0;
if (hp->happy_flags & HFLAG_FULL)
regtmp |= BIGMAC_TXCFG_FULLDPLX;
- hme_write32(hp, bregs + BMAC_TXCFG, regtmp | BIGMAC_TXCFG_DGIVEUP);
+
+ /* Don't turn on the "don't give up" bit for now. It could cause hme
+ * to deadlock with the PHY if a Jabber occurs.
+ */
+ hme_write32(hp, bregs + BMAC_TXCFG, regtmp /*| BIGMAC_TXCFG_DGIVEUP*/);
+
+ /* Give up after 16 TX attempts. */
+ hme_write32(hp, bregs + BMAC_ALIMIT, 16);
/* Enable the output drivers no matter what. */
regtmp = BIGMAC_XCFG_ODENABLE;
@@ -1744,6 +1726,7 @@ static int happy_meal_init(struct happy_meal *hp, int from_irq)
return 0;
}
+/* hp->happy_lock must be held */
static void happy_meal_set_initial_advertisement(struct happy_meal *hp)
{
unsigned long tregs = hp->tcvregs;
@@ -1801,6 +1784,8 @@ static void happy_meal_set_initial_advertisement(struct happy_meal *hp)
/* Once status is latched (by happy_meal_interrupt) it is cleared by
* the hardware, so we cannot re-read it and get a correct value.
+ *
+ * hp->happy_lock must be held
*/
static int happy_meal_is_not_so_happy(struct happy_meal *hp, u32 status)
{
@@ -1909,12 +1894,13 @@ static int happy_meal_is_not_so_happy(struct happy_meal *hp, u32 status)
if (reset) {
printk(KERN_NOTICE "%s: Resetting...\n", hp->dev->name);
- happy_meal_init(hp, 1);
+ happy_meal_init(hp);
return 1;
}
return 0;
}
+/* hp->happy_lock must be held */
static void happy_meal_mif_interrupt(struct happy_meal *hp)
{
unsigned long tregs = hp->tcvregs;
@@ -1948,6 +1934,7 @@ static void happy_meal_mif_interrupt(struct happy_meal *hp)
#define TXD(x)
#endif
+/* hp->happy_lock must be held */
static void happy_meal_tx(struct happy_meal *hp)
{
struct happy_meal_txd *txbase = &hp->happy_block->happy_meal_txd[0];
@@ -1955,8 +1942,6 @@ static void happy_meal_tx(struct happy_meal *hp)
struct net_device *dev = hp->dev;
int elem;
- spin_lock(&hp->happy_lock);
-
elem = hp->tx_old;
TXD(("TX<"));
while (elem != hp->tx_new) {
@@ -2000,10 +1985,8 @@ static void happy_meal_tx(struct happy_meal *hp)
TXD((">"));
if (netif_queue_stopped(dev) &&
- TX_BUFFS_AVAIL(hp) > 0)
+ TX_BUFFS_AVAIL(hp) > (MAX_SKB_FRAGS + 1))
netif_wake_queue(dev);
-
- spin_unlock(&hp->happy_lock);
}
#ifdef RXDEBUG
@@ -2018,6 +2001,8 @@ static void happy_meal_tx(struct happy_meal *hp)
* with all of the packets it has DMA'd in. So now I just drop the entire
* ring when we cannot get a new skb and give them all back to the happy meal,
* maybe things will be "happier" now.
+ *
+ * hp->happy_lock must be held
*/
static void happy_meal_rx(struct happy_meal *hp, struct net_device *dev)
{
@@ -2127,10 +2112,12 @@ static void happy_meal_interrupt(int irq, void *dev_id, struct pt_regs *regs)
HMD(("happy_meal_interrupt: status=%08x ", happy_status));
+ spin_lock(&hp->happy_lock);
+
if (happy_status & GREG_STAT_ERRORS) {
HMD(("ERRORS "));
if (happy_meal_is_not_so_happy(hp, /* un- */ happy_status))
- return;
+ goto out;
}
if (happy_status & GREG_STAT_MIFIRQ) {
@@ -2149,6 +2136,8 @@ static void happy_meal_interrupt(int irq, void *dev_id, struct pt_regs *regs)
}
HMD(("done\n"));
+out:
+ spin_unlock(&hp->happy_lock);
}
#ifdef CONFIG_SBUS
@@ -2170,10 +2159,12 @@ static void quattro_sbus_interrupt(int irq, void *cookie, struct pt_regs *ptregs
GREG_STAT_RXTOHOST)))
continue;
+ spin_lock(&hp->happy_lock);
+
if (happy_status & GREG_STAT_ERRORS) {
HMD(("ERRORS "));
if (happy_meal_is_not_so_happy(hp, happy_status))
- break;
+ goto next;
}
if (happy_status & GREG_STAT_MIFIRQ) {
@@ -2190,6 +2181,9 @@ static void quattro_sbus_interrupt(int irq, void *cookie, struct pt_regs *ptregs
HMD(("RXTOHOST "));
happy_meal_rx(hp, dev);
}
+
+ next:
+ spin_unlock(&hp->happy_lock);
}
HMD(("done\n"));
}
@@ -2222,7 +2216,11 @@ static int happy_meal_open(struct net_device *dev)
}
HMD(("to happy_meal_init\n"));
- res = happy_meal_init(hp, 0);
+
+ spin_lock_irq(&hp->happy_lock);
+ res = happy_meal_init(hp);
+ spin_unlock_irq(&hp->happy_lock);
+
if (res && ((hp->happy_flags & (HFLAG_QUATTRO|HFLAG_PCI)) != HFLAG_QUATTRO))
free_irq(dev->irq, dev);
return res;
@@ -2232,12 +2230,15 @@ static int happy_meal_close(struct net_device *dev)
{
struct happy_meal *hp = dev->priv;
+ spin_lock_irq(&hp->happy_lock);
happy_meal_stop(hp, hp->gregs);
happy_meal_clean_rings(hp);
/* If auto-negotiation timer is running, kill it. */
del_timer(&hp->happy_timer);
+ spin_unlock_irq(&hp->happy_lock);
+
/* On Quattro QFE cards, all hme interrupts are concentrated
* into a single source which we register handling at probe
* time and never unregister.
@@ -2254,7 +2255,6 @@ static int happy_meal_close(struct net_device *dev)
#define SXD(x)
#endif
-#ifdef CONFIG_SBUS
static void happy_meal_tx_timeout(struct net_device *dev)
{
struct happy_meal *hp = dev->priv;
@@ -2265,10 +2265,13 @@ static void happy_meal_tx_timeout(struct net_device *dev)
hme_read32(hp, hp->gregs + GREG_STAT),
hme_read32(hp, hp->etxregs + ETX_CFG),
hme_read32(hp, hp->bigmacregs + BMAC_TXCFG));
- happy_meal_init(hp, 0);
+
+ spin_lock_irq(&hp->happy_lock);
+ happy_meal_init(hp);
+ spin_unlock_irq(&hp->happy_lock);
+
netif_wake_queue(dev);
}
-#endif
static int happy_meal_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
@@ -2293,6 +2296,8 @@ static int happy_meal_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (TX_BUFFS_AVAIL(hp) <= (skb_shinfo(skb)->nr_frags + 1)) {
netif_stop_queue(dev);
spin_unlock_irq(&hp->happy_lock);
+ printk(KERN_ERR "%s: BUG! Tx Ring full when queue awake!\n",
+ dev->name);
return 1;
}
@@ -2345,7 +2350,7 @@ static int happy_meal_start_xmit(struct sk_buff *skb, struct net_device *dev)
hp->tx_new = entry;
- if (TX_BUFFS_AVAIL(hp) <= 0)
+ if (TX_BUFFS_AVAIL(hp) <= (MAX_SKB_FRAGS + 1))
netif_stop_queue(dev);
/* Get it going. */
@@ -2363,7 +2368,10 @@ static struct net_device_stats *happy_meal_get_stats(struct net_device *dev)
{
struct happy_meal *hp = dev->priv;
+ spin_lock_irq(&hp->happy_lock);
happy_meal_get_counters(hp, hp->bigmacregs);
+ spin_unlock_irq(&hp->happy_lock);
+
return &hp->net_stats;
}
@@ -2376,7 +2384,8 @@ static void happy_meal_set_multicast(struct net_device *dev)
int i;
u32 crc;
- /* Lock out others. */
+ spin_lock_irq(&hp->happy_lock);
+
netif_stop_queue(dev);
if ((dev->flags & IFF_ALLMULTI) || (dev->mc_count > 64)) {
@@ -2410,8 +2419,9 @@ static void happy_meal_set_multicast(struct net_device *dev)
hme_write32(hp, bregs + BMAC_HTABLE3, hash_table[3]);
}
- /* Let us get going again. */
netif_wake_queue(dev);
+
+ spin_unlock_irq(&hp->happy_lock);
}
/* Ethtool support... */
@@ -2439,8 +2449,11 @@ static int happy_meal_ioctl(struct net_device *dev,
ecmd.phy_address = 0; /* XXX fixed PHYAD */
/* Record PHY settings. */
+ spin_lock_irq(&hp->happy_lock);
hp->sw_bmcr = happy_meal_tcvr_read(hp, hp->tcvregs, MII_BMCR);
hp->sw_lpa = happy_meal_tcvr_read(hp, hp->tcvregs, MII_LPA);
+ spin_unlock_irq(&hp->happy_lock);
+
if (hp->sw_bmcr & BMCR_ANENABLE) {
ecmd.autoneg = AUTONEG_ENABLE;
ecmd.speed =
@@ -2482,10 +2495,12 @@ static int happy_meal_ioctl(struct net_device *dev,
return -EINVAL;
/* Ok, do it to it. */
+ spin_lock_irq(&hp->happy_lock);
del_timer(&hp->happy_timer);
happy_meal_begin_auto_negotiation(hp,
hp->tcvregs,
&ecmd);
+ spin_unlock_irq(&hp->happy_lock);
return 0;
} else
@@ -2657,7 +2672,7 @@ static int __init happy_meal_sbus_init(struct sbus_dev *sdev, int is_qfe)
}
err = -ENOMEM;
- dev = init_etherdev(NULL, sizeof(struct happy_meal));
+ dev = alloc_etherdev(sizeof(struct happy_meal));
if (!dev)
goto err_out;
SET_MODULE_OWNER(dev);
@@ -2665,13 +2680,6 @@ static int __init happy_meal_sbus_init(struct sbus_dev *sdev, int is_qfe)
if (hme_version_printed++ == 0)
printk(KERN_INFO "%s", version);
- if (qfe_slot != -1)
- printk(KERN_INFO "%s: Quattro HME slot %d (SBUS) 10/100baseT Ethernet ",
- dev->name, qfe_slot);
- else
- printk(KERN_INFO "%s: HAPPY MEAL (SBUS) 10/100baseT Ethernet ",
- dev->name);
-
/* If user did not specify a MAC address specifically, use
* the Quattro local-mac-address property...
*/
@@ -2682,6 +2690,7 @@ static int __init happy_meal_sbus_init(struct sbus_dev *sdev, int is_qfe)
if (i < 6) { /* a mac address was given */
for (i = 0; i < 6; i++)
dev->dev_addr[i] = macaddr[i];
+ macaddr[5]++;
} else if (qfe_slot != -1 &&
prom_getproplen(sdev->prom_node,
"local-mac-address") == 6) {
@@ -2691,11 +2700,6 @@ static int __init happy_meal_sbus_init(struct sbus_dev *sdev, int is_qfe)
memcpy(dev->dev_addr, idprom->id_ethaddr, 6);
}
- for (i = 0; i < 6; i++)
- printk("%2.2x%c",
- dev->dev_addr[i], i == 5 ? ' ' : ':');
- printk("\n");
-
hp = dev->priv;
memset(hp, 0, sizeof(*hp));
@@ -2818,19 +2822,42 @@ static int __init happy_meal_sbus_init(struct sbus_dev *sdev, int is_qfe)
/* Grrr, Happy Meal comes up by default not advertising
* full duplex 100baseT capabilities, fix this.
*/
+ spin_lock_irq(&hp->happy_lock);
happy_meal_set_initial_advertisement(hp);
+ spin_unlock_irq(&hp->happy_lock);
- ether_setup(dev);
+ if (register_netdev(hp->dev)) {
+ printk(KERN_ERR "happymeal: Cannot register net device, "
+ "aborting.\n");
+ goto err_out_free_consistent;
+ }
+
+ if (qfe_slot != -1)
+ printk(KERN_INFO "%s: Quattro HME slot %d (SBUS) 10/100baseT Ethernet ",
+ dev->name, qfe_slot);
+ else
+ printk(KERN_INFO "%s: HAPPY MEAL (SBUS) 10/100baseT Ethernet ",
+ dev->name);
+
+ for (i = 0; i < 6; i++)
+ printk("%2.2x%c",
+ dev->dev_addr[i], i == 5 ? ' ' : ':');
+ printk("\n");
/* We are home free at this point, link us in to the happy
* device list.
*/
- dev->ifindex = dev_new_index();
hp->next_module = root_happy_dev;
root_happy_dev = hp;
return 0;
+err_out_free_consistent:
+ sbus_free_consistent(hp->happy_dev,
+ PAGE_SIZE,
+ hp->happy_block,
+ hp->hblock_dvma);
+
err_out_iounmap:
if (hp->gregs)
sbus_iounmap(hp->gregs, GREG_REG_SIZE);
@@ -2844,7 +2871,6 @@ err_out_iounmap:
sbus_iounmap(hp->tcvregs, TCVR_REG_SIZE);
err_out_free_netdev:
- unregister_netdev(dev);
kfree(dev);
err_out:
@@ -2853,6 +2879,104 @@ err_out:
#endif
#ifdef CONFIG_PCI
+#ifndef __sparc__
+static int is_quattro_p(struct pci_dev *pdev)
+{
+ struct pci_dev *busdev = pdev->bus->self;
+ struct list_head *tmp;
+ int n_hmes;
+
+ if (busdev->vendor != PCI_VENDOR_ID_DEC ||
+ busdev->device != PCI_DEVICE_ID_DEC_21153)
+ return 0;
+
+ n_hmes = 0;
+ tmp = pdev->bus->devices.next;
+ while (tmp != &pdev->bus->devices) {
+ struct pci_dev *this_pdev = pci_dev_b(tmp);
+
+ if (this_pdev->vendor == PCI_VENDOR_ID_SUN &&
+ this_pdev->device == PCI_DEVICE_ID_SUN_HAPPYMEAL)
+ n_hmes++;
+
+ tmp = tmp->next;
+ }
+
+ if (n_hmes != 4)
+ return 0;
+
+ return 1;
+}
+
+/* Fetch MAC address from vital product data of PCI ROM. */
+static void find_eth_addr_in_vpd(void *rom_base, int len, int index, unsigned char *dev_addr)
+{
+ int this_offset;
+
+ for (this_offset = 0x20; this_offset < len; this_offset++) {
+ void *p = rom_base + this_offset;
+
+ if (readb(p + 0) != 0x90 ||
+ readb(p + 1) != 0x00 ||
+ readb(p + 2) != 0x09 ||
+ readb(p + 3) != 0x4e ||
+ readb(p + 4) != 0x41 ||
+ readb(p + 5) != 0x06)
+ continue;
+
+ this_offset += 6;
+ p += 6;
+
+ if (index == 0) {
+ int i;
+
+ for (i = 0; i < 6; i++)
+ dev_addr[i] = readb(p + i);
+ break;
+ }
+ index--;
+ }
+}
+
+static void get_hme_mac_nonsparc(struct pci_dev *pdev, unsigned char *dev_addr)
+{
+ u32 rom_reg_orig;
+ void *p;
+ int index;
+
+ index = 0;
+ if (is_quattro_p(pdev))
+ index = PCI_SLOT(pdev->devfn);
+
+ if (pdev->resource[PCI_ROM_RESOURCE].parent == NULL) {
+ if (pci_assign_resource(pdev, PCI_ROM_RESOURCE) < 0)
+ goto use_random;
+ }
+
+ pci_read_config_dword(pdev, pdev->rom_base_reg, &rom_reg_orig);
+ pci_write_config_dword(pdev, pdev->rom_base_reg,
+ rom_reg_orig | PCI_ROM_ADDRESS_ENABLE);
+
+ p = ioremap(pci_resource_start(pdev, PCI_ROM_RESOURCE), (64 * 1024));
+ if (p != NULL && readb(p) == 0x55 && readb(p + 1) == 0xaa)
+ find_eth_addr_in_vpd(p, (64 * 1024), index, dev_addr);
+
+ if (p != NULL)
+ iounmap(p);
+
+ pci_write_config_dword(pdev, pdev->rom_base_reg, rom_reg_orig);
+ return;
+
+use_random:
+ /* Sun MAC prefix then 3 random bytes. */
+ dev_addr[0] = 0x08;
+ dev_addr[1] = 0x00;
+ dev_addr[2] = 0x20;
+ get_random_bytes(dev_addr, 3);
+ return;
+}
+#endif /* !(__sparc__) */
+
static int __init happy_meal_pci_init(struct pci_dev *pdev)
{
struct quattro *qp = NULL;
@@ -2878,8 +3002,10 @@ static int __init happy_meal_pci_init(struct pci_dev *pdev)
prom_getstring(node, "name", prom_name, sizeof(prom_name));
#else
-/* This needs to be corrected... -DaveM */
- strcpy(prom_name, "qfe");
+ if (is_quattro_p(pdev))
+ strcpy(prom_name, "SUNW,qfe");
+ else
+ strcpy(prom_name, "SUNW,hme");
#endif
err = -ENODEV;
@@ -2894,7 +3020,7 @@ static int __init happy_meal_pci_init(struct pci_dev *pdev)
goto err_out;
}
- dev = init_etherdev(NULL, sizeof(struct happy_meal));
+ dev = alloc_etherdev(sizeof(struct happy_meal));
err = -ENOMEM;
if (!dev)
goto err_out;
@@ -2903,29 +3029,6 @@ static int __init happy_meal_pci_init(struct pci_dev *pdev)
if (hme_version_printed++ == 0)
printk(KERN_INFO "%s", version);
- if (!qfe_slot) {
- struct pci_dev *qpdev = qp->quattro_dev;
-
- prom_name[0] = 0;
- if (!strncmp(dev->name, "eth", 3)) {
- int i = simple_strtoul(dev->name + 3, NULL, 10);
- sprintf(prom_name, "-%d", i + 3);
- }
- printk(KERN_INFO "%s%s: Quattro HME (PCI/CheerIO) 10/100baseT Ethernet ", dev->name, prom_name);
- if (qpdev->vendor == PCI_VENDOR_ID_DEC &&
- qpdev->device == PCI_DEVICE_ID_DEC_21153)
- printk("DEC 21153 PCI Bridge\n");
- else
- printk("unknown bridge %04x.%04x\n",
- qpdev->vendor, qpdev->device);
- }
- if (qfe_slot != -1)
- printk(KERN_INFO "%s: Quattro HME slot %d (PCI/CheerIO) 10/100baseT Ethernet ",
- dev->name, qfe_slot);
- else
- printk(KERN_INFO "%s: HAPPY MEAL (PCI/CheerIO) 10/100BaseT Ethernet ",
- dev->name);
-
dev->base_addr = (long) pdev;
hp = (struct happy_meal *)dev->priv;
@@ -2947,9 +3050,15 @@ static int __init happy_meal_pci_init(struct pci_dev *pdev)
printk(KERN_ERR "happymeal(PCI): Cannot find proper PCI device base address.\n");
goto err_out_clear_quattro;
}
+ if (pci_request_regions(pdev, dev->name)) {
+ printk(KERN_ERR "happymeal(PCI): Cannot obtain PCI resources, "
+ "aborting.\n");
+ goto err_out_clear_quattro;
+ }
+
if ((hpreg_base = (unsigned long) ioremap(hpreg_base, 0x8000)) == 0) {
printk(KERN_ERR "happymeal(PCI): Unable to remap card memory.\n");
- return -ENODEV;
+ goto err_out_free_res;
}
for (i = 0; i < 6; i++) {
@@ -2959,6 +3068,7 @@ static int __init happy_meal_pci_init(struct pci_dev *pdev)
if (i < 6) { /* a mac address was given */
for (i = 0; i < 6; i++)
dev->dev_addr[i] = macaddr[i];
+ macaddr[5]++;
} else {
#ifdef __sparc__
if (qfe_slot != -1 &&
@@ -2969,15 +3079,10 @@ static int __init happy_meal_pci_init(struct pci_dev *pdev)
memcpy(dev->dev_addr, idprom->id_ethaddr, 6);
}
#else
- memset(dev->dev_addr, 0, 6);
+ get_hme_mac_nonsparc(pdev, &dev->dev_addr[0]);
#endif
}
- for (i = 0; i < 6; i++)
- printk("%2.2x%c", dev->dev_addr[i], i == 5 ? ' ' : ':');
-
- printk("\n");
-
/* Layout registers. */
hp->gregs = (hpreg_base + 0x0000UL);
hp->etxregs = (hpreg_base + 0x2000UL);
@@ -3032,6 +3137,8 @@ static int __init happy_meal_pci_init(struct pci_dev *pdev)
dev->hard_start_xmit = &happy_meal_start_xmit;
dev->get_stats = &happy_meal_get_stats;
dev->set_multicast_list = &happy_meal_set_multicast;
+ dev->tx_timeout = &happy_meal_tx_timeout;
+ dev->watchdog_timeo = 5*HZ;
dev->do_ioctl = &happy_meal_ioctl;
dev->irq = pdev->irq;
dev->dma = 0;
@@ -3054,14 +3161,48 @@ static int __init happy_meal_pci_init(struct pci_dev *pdev)
/* Grrr, Happy Meal comes up by default not advertising
* full duplex 100baseT capabilities, fix this.
*/
+ spin_lock_irq(&hp->happy_lock);
happy_meal_set_initial_advertisement(hp);
+ spin_unlock_irq(&hp->happy_lock);
+
+ if (register_netdev(hp->dev)) {
+ printk(KERN_ERR "happymeal(PCI): Cannot register net device, "
+ "aborting.\n");
+ goto err_out_iounmap;
+ }
+
+ if (!qfe_slot) {
+ struct pci_dev *qpdev = qp->quattro_dev;
- ether_setup(dev);
+ prom_name[0] = 0;
+ if (!strncmp(dev->name, "eth", 3)) {
+ int i = simple_strtoul(dev->name + 3, NULL, 10);
+ sprintf(prom_name, "-%d", i + 3);
+ }
+ printk(KERN_INFO "%s%s: Quattro HME (PCI/CheerIO) 10/100baseT Ethernet ", dev->name, prom_name);
+ if (qpdev->vendor == PCI_VENDOR_ID_DEC &&
+ qpdev->device == PCI_DEVICE_ID_DEC_21153)
+ printk("DEC 21153 PCI Bridge\n");
+ else
+ printk("unknown bridge %04x.%04x\n",
+ qpdev->vendor, qpdev->device);
+ }
+
+ if (qfe_slot != -1)
+ printk(KERN_INFO "%s: Quattro HME slot %d (PCI/CheerIO) 10/100baseT Ethernet ",
+ dev->name, qfe_slot);
+ else
+ printk(KERN_INFO "%s: HAPPY MEAL (PCI/CheerIO) 10/100BaseT Ethernet ",
+ dev->name);
+
+ for (i = 0; i < 6; i++)
+ printk("%2.2x%c", dev->dev_addr[i], i == 5 ? ' ' : ':');
+
+ printk("\n");
/* We are home free at this point, link us in to the happy
* device list.
*/
- dev->ifindex = dev_new_index();
hp->next_module = root_happy_dev;
root_happy_dev = hp;
@@ -3070,11 +3211,13 @@ static int __init happy_meal_pci_init(struct pci_dev *pdev)
err_out_iounmap:
iounmap((void *)hp->gregs);
+err_out_free_res:
+ pci_release_regions(pdev);
+
err_out_clear_quattro:
if (qp != NULL)
qp->happy_meals[qfe_slot] = NULL;
- unregister_netdev(dev);
kfree(dev);
err_out:
@@ -3125,6 +3268,7 @@ static int __init happy_meal_pci_probe(void)
PCI_DEVICE_ID_SUN_HAPPYMEAL, pdev)) != NULL) {
if (pci_enable_device(pdev))
continue;
+ pci_set_master(pdev);
cards++;
happy_meal_pci_init(pdev);
}
@@ -3165,12 +3309,18 @@ static void __exit happy_meal_cleanup_module(void)
while (root_happy_dev) {
struct happy_meal *hp = root_happy_dev;
struct happy_meal *next = root_happy_dev->next_module;
+ struct net_device *dev = hp->dev;
+
+ /* Unregister netdev before unmapping registers as this
+ * call can end up trying to access those registers.
+ */
+ unregister_netdev(dev);
#ifdef CONFIG_SBUS
if (!(hp->happy_flags & HFLAG_PCI)) {
if (hp->happy_flags & HFLAG_QUATTRO) {
if (hp->qfe_parent != last_seen_qfe) {
- free_irq(hp->dev->irq, hp->qfe_parent);
+ free_irq(dev->irq, hp->qfe_parent);
last_seen_qfe = hp->qfe_parent;
}
}
@@ -3193,12 +3343,35 @@ static void __exit happy_meal_cleanup_module(void)
hp->happy_block,
hp->hblock_dvma);
iounmap((void *)hp->gregs);
+ pci_release_regions(hp->happy_dev);
}
#endif
- unregister_netdev(hp->dev);
- kfree(hp->dev);
+ kfree(dev);
+
root_happy_dev = next;
}
+
+ /* Now cleanup the quattro lists. */
+#ifdef CONFIG_SBUS
+ while (qfe_sbus_list) {
+ struct quattro *qfe = qfe_sbus_list;
+ struct quattro *next = qfe->next;
+
+ kfree(qfe);
+
+ qfe_sbus_list = next;
+ }
+#endif
+#ifdef CONFIG_PCI
+ while (qfe_pci_list) {
+ struct quattro *qfe = qfe_pci_list;
+ struct quattro *next = qfe->next;
+
+ kfree(qfe);
+
+ qfe_pci_list = next;
+ }
+#endif
}
module_init(happy_meal_probe);
diff --git a/drivers/net/sunhme.h b/drivers/net/sunhme.h
index 8c177c1999045..efa319e0ed1ae 100644
--- a/drivers/net/sunhme.h
+++ b/drivers/net/sunhme.h
@@ -227,7 +227,7 @@
#define BIGMAC_RXCFG_PMISC 0x00000040 /* Enable promiscous mode */
#define BIGMAC_RXCFG_DERR 0x00000080 /* Disable error checking */
#define BIGMAC_RXCFG_DCRCS 0x00000100 /* Disable CRC stripping */
-#define BIGMAC_RXCFG_ME 0x00000200 /* Receive packets addressed to me */
+#define BIGMAC_RXCFG_REJME 0x00000200 /* Reject packets addressed to me */
#define BIGMAC_RXCFG_PGRP 0x00000400 /* Enable promisc group mode */
#define BIGMAC_RXCFG_HENABLE 0x00000800 /* Enable the hash filter */
#define BIGMAC_RXCFG_AENABLE 0x00001000 /* Enable the address filter */
diff --git a/drivers/net/tc35815.c b/drivers/net/tc35815.c
new file mode 100644
index 0000000000000..51235569651ab
--- /dev/null
+++ b/drivers/net/tc35815.c
@@ -0,0 +1,1779 @@
+/* tc35815.c: A TOSHIBA TC35815CF PCI 10/100Mbps ethernet driver for linux.
+ *
+ * Copyright 2001 MontaVista Software Inc.
+ * Author: MontaVista Software, Inc.
+ * ahennessy@mvista.com
+ *
+ * Based on skelton.c by Donald Becker.
+ * Copyright (C) 2000-2001 Toshiba Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+static const char *version =
+ "tc35815.c:v0.00 26/07/2000 by Toshiba Corporation\n";
+
+#include <linux/module.h>
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/interrupt.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/in.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/proc_fs.h>
+#include <asm/byteorder.h>
+
+
+/*
+ * The name of the card. Is used for messages and in the requests for
+ * io regions, irqs and dma channels
+ */
+static const char* cardname = "TC35815CF";
+#define TC35815_PROC_ENTRY "net/tc35815"
+
+#define TC35815_MODULE_NAME "TC35815CF"
+#define TX_TIMEOUT (4*HZ)
+
+/* First, a few definitions that the brave might change. */
+
+/* use 0 for production, 1 for verification, >2 for debug */
+#ifndef TC35815_DEBUG
+#define TC35815_DEBUG 1
+#endif
+static unsigned int tc35815_debug = TC35815_DEBUG;
+
+#define GATHER_TXINT /* On-Demand Tx Interrupt */
+
+#define vtonocache(p) KSEG1ADDR(virt_to_phys(p))
+
+/*
+ * Registers
+ */
+struct tc35815_regs {
+ volatile __u32 DMA_Ctl; /* 0x00 */
+ volatile __u32 TxFrmPtr;
+ volatile __u32 TxThrsh;
+ volatile __u32 TxPollCtr;
+ volatile __u32 BLFrmPtr;
+ volatile __u32 RxFragSize;
+ volatile __u32 Int_En;
+ volatile __u32 FDA_Bas;
+ volatile __u32 FDA_Lim; /* 0x20 */
+ volatile __u32 Int_Src;
+ volatile __u32 unused0[2];
+ volatile __u32 PauseCnt;
+ volatile __u32 RemPauCnt;
+ volatile __u32 TxCtlFrmStat;
+ volatile __u32 unused1;
+ volatile __u32 MAC_Ctl; /* 0x40 */
+ volatile __u32 CAM_Ctl;
+ volatile __u32 Tx_Ctl;
+ volatile __u32 Tx_Stat;
+ volatile __u32 Rx_Ctl;
+ volatile __u32 Rx_Stat;
+ volatile __u32 MD_Data;
+ volatile __u32 MD_CA;
+ volatile __u32 CAM_Adr; /* 0x60 */
+ volatile __u32 CAM_Data;
+ volatile __u32 CAM_Ena;
+ volatile __u32 PROM_Ctl;
+ volatile __u32 PROM_Data;
+ volatile __u32 Algn_Cnt;
+ volatile __u32 CRC_Cnt;
+ volatile __u32 Miss_Cnt;
+};
+
+/*
+ * Bit assignments
+ */
+/* DMA_Ctl bit asign ------------------------------------------------------- */
+#define DMA_IntMask 0x00040000 /* 1:Interupt mask */
+#define DMA_SWIntReq 0x00020000 /* 1:Software Interrupt request */
+#define DMA_TxWakeUp 0x00010000 /* 1:Transmit Wake Up */
+#define DMA_RxBigE 0x00008000 /* 1:Receive Big Endian */
+#define DMA_TxBigE 0x00004000 /* 1:Transmit Big Endian */
+#define DMA_TestMode 0x00002000 /* 1:Test Mode */
+#define DMA_PowrMgmnt 0x00001000 /* 1:Power Management */
+#define DMA_DmBurst_Mask 0x000001fc /* DMA Burst size */
+
+/* RxFragSize bit asign ---------------------------------------------------- */
+#define RxFrag_EnPack 0x00008000 /* 1:Enable Packing */
+#define RxFrag_MinFragMask 0x00000ffc /* Minimum Fragment */
+
+/* MAC_Ctl bit asign ------------------------------------------------------- */
+#define MAC_Link10 0x00008000 /* 1:Link Status 10Mbits */
+#define MAC_EnMissRoll 0x00002000 /* 1:Enable Missed Roll */
+#define MAC_MissRoll 0x00000400 /* 1:Missed Roll */
+#define MAC_Loop10 0x00000080 /* 1:Loop 10 Mbps */
+#define MAC_Conn_Auto 0x00000000 /*00:Connection mode (Automatic) */
+#define MAC_Conn_10M 0x00000020 /*01: (10Mbps endec)*/
+#define MAC_Conn_Mll 0x00000040 /*10: (Mll clock) */
+#define MAC_MacLoop 0x00000010 /* 1:MAC Loopback */
+#define MAC_FullDup 0x00000008 /* 1:Full Duplex 0:Half Duplex */
+#define MAC_Reset 0x00000004 /* 1:Software Reset */
+#define MAC_HaltImm 0x00000002 /* 1:Halt Immediate */
+#define MAC_HaltReq 0x00000001 /* 1:Halt request */
+
+/* PROM_Ctl bit asign ------------------------------------------------------ */
+#define PROM_Busy 0x00008000 /* 1:Busy (Start Operation) */
+#define PROM_Read 0x00004000 /*10:Read operation */
+#define PROM_Write 0x00002000 /*01:Write operation */
+#define PROM_Erase 0x00006000 /*11:Erase operation */
+ /*00:Enable or Disable Writting, */
+ /* as specified in PROM_Addr. */
+#define PROM_Addr_Ena 0x00000030 /*11xxxx:PROM Write enable */
+ /*00xxxx: disable */
+
+/* CAM_Ctl bit asign ------------------------------------------------------- */
+#define CAM_CompEn 0x00000010 /* 1:CAM Compare Enable */
+#define CAM_NegCAM 0x00000008 /* 1:Reject packets CAM recognizes,*/
+ /* accept other */
+#define CAM_BroadAcc 0x00000004 /* 1:Broadcast assept */
+#define CAM_GroupAcc 0x00000002 /* 1:Multicast assept */
+#define CAM_StationAcc 0x00000001 /* 1:unicast accept */
+
+/* CAM_Ena bit asign ------------------------------------------------------- */
+#define CAM_ENTRY_MAX 21 /* CAM Data entry max count */
+#define CAM_Ena_Mask ((1<<CAM_ENTRY_MAX)-1) /* CAM Enable bits (Max 21bits) */
+#define CAM_Ena_Bit(index) (1<<(index))
+#define CAM_ENTRY_DESTINATION 0
+#define CAM_ENTRY_SOURCE 1
+#define CAM_ENTRY_MACCTL 20
+
+/* Tx_Ctl bit asign -------------------------------------------------------- */
+#define Tx_En 0x00000001 /* 1:Transmit enable */
+#define Tx_TxHalt 0x00000002 /* 1:Transmit Halt Request */
+#define Tx_NoPad 0x00000004 /* 1:Suppress Padding */
+#define Tx_NoCRC 0x00000008 /* 1:Suppress Padding */
+#define Tx_FBack 0x00000010 /* 1:Fast Back-off */
+#define Tx_EnUnder 0x00000100 /* 1:Enable Underrun */
+#define Tx_EnExDefer 0x00000200 /* 1:Enable Excessive Deferral */
+#define Tx_EnLCarr 0x00000400 /* 1:Enable Lost Carrier */
+#define Tx_EnExColl 0x00000800 /* 1:Enable Excessive Collision */
+#define Tx_EnLateColl 0x00001000 /* 1:Enable Late Collision */
+#define Tx_EnTxPar 0x00002000 /* 1:Enable Transmit Parity */
+#define Tx_EnComp 0x00004000 /* 1:Enable Completion */
+
+/* Tx_Stat bit asign ------------------------------------------------------- */
+#define Tx_TxColl_MASK 0x0000000F /* Tx Collision Count */
+#define Tx_ExColl 0x00000010 /* Excessive Collision */
+#define Tx_TXDefer 0x00000020 /* Transmit Defered */
+#define Tx_Paused 0x00000040 /* Transmit Paused */
+#define Tx_IntTx 0x00000080 /* Interrupt on Tx */
+#define Tx_Under 0x00000100 /* Underrun */
+#define Tx_Defer 0x00000200 /* Deferral */
+#define Tx_NCarr 0x00000400 /* No Carrier */
+#define Tx_10Stat 0x00000800 /* 10Mbps Status */
+#define Tx_LateColl 0x00001000 /* Late Collision */
+#define Tx_TxPar 0x00002000 /* Tx Parity Error */
+#define Tx_Comp 0x00004000 /* Completion */
+#define Tx_Halted 0x00008000 /* Tx Halted */
+#define Tx_SQErr 0x00010000 /* Signal Quality Error(SQE) */
+
+/* Rx_Ctl bit asign -------------------------------------------------------- */
+#define Rx_EnGood 0x00004000 /* 1:Enable Good */
+#define Rx_EnRxPar 0x00002000 /* 1:Enable Receive Parity */
+#define Rx_EnLongErr 0x00000800 /* 1:Enable Long Error */
+#define Rx_EnOver 0x00000400 /* 1:Enable OverFlow */
+#define Rx_EnCRCErr 0x00000200 /* 1:Enable CRC Error */
+#define Rx_EnAlign 0x00000100 /* 1:Enable Alignment */
+#define Rx_IgnoreCRC 0x00000040 /* 1:Ignore CRC Value */
+#define Rx_StripCRC 0x00000010 /* 1:Strip CRC Value */
+#define Rx_ShortEn 0x00000008 /* 1:Short Enable */
+#define Rx_LongEn 0x00000004 /* 1:Long Enable */
+#define Rx_RxHalt 0x00000002 /* 1:Receive Halt Request */
+#define Rx_RxEn 0x00000001 /* 1:Receive Intrrupt Enable */
+
+/* Rx_Stat bit asign ------------------------------------------------------- */
+#define Rx_Halted 0x00008000 /* Rx Halted */
+#define Rx_Good 0x00004000 /* Rx Good */
+#define Rx_RxPar 0x00002000 /* Rx Parity Error */
+ /* 0x00001000 not use */
+#define Rx_LongErr 0x00000800 /* Rx Long Error */
+#define Rx_Over 0x00000400 /* Rx Overflow */
+#define Rx_CRCErr 0x00000200 /* Rx CRC Error */
+#define Rx_Align 0x00000100 /* Rx Alignment Error */
+#define Rx_10Stat 0x00000080 /* Rx 10Mbps Status */
+#define Rx_IntRx 0x00000040 /* Rx Interrupt */
+#define Rx_CtlRecd 0x00000020 /* Rx Control Receive */
+
+#define Rx_Stat_Mask 0x0000EFC0 /* Rx All Status Mask */
+
+/* Int_En bit asign -------------------------------------------------------- */
+#define Int_NRAbtEn 0x00000800 /* 1:Non-recoverable Abort Enable */
+#define Int_TxCtlCmpEn 0x00000400 /* 1:Transmit Control Complete Enable */
+#define Int_DmParErrEn 0x00000200 /* 1:DMA Parity Error Enable */
+#define Int_DParDEn 0x00000100 /* 1:Data Parity Error Enable */
+#define Int_EarNotEn 0x00000080 /* 1:Early Notify Enable */
+#define Int_DParErrEn 0x00000040 /* 1:Detected Parity Error Enable */
+#define Int_SSysErrEn 0x00000020 /* 1:Signalled System Error Enable */
+#define Int_RMasAbtEn 0x00000010 /* 1:Received Master Abort Enable */
+#define Int_RTargAbtEn 0x00000008 /* 1:Received Target Abort Enable */
+#define Int_STargAbtEn 0x00000004 /* 1:Signalled Target Abort Enable */
+#define Int_BLExEn 0x00000002 /* 1:Buffer List Exhausted Enable */
+#define Int_FDAExEn 0x00000001 /* 1:Free Descriptor Area */
+ /* Exhausted Enable */
+
+/* Int_Src bit asign ------------------------------------------------------- */
+#define Int_NRabt 0x00004000 /* 1:Non Recoverable error */
+#define Int_DmParErrStat 0x00002000 /* 1:DMA Parity Error & Clear */
+#define Int_BLEx 0x00001000 /* 1:Buffer List Empty & Clear */
+#define Int_FDAEx 0x00000800 /* 1:FDA Empty & Clear */
+#define Int_IntNRAbt 0x00000400 /* 1:Non Recoverable Abort */
+#define Int_IntCmp 0x00000200 /* 1:MAC control packet complete */
+#define Int_IntExBD 0x00000100 /* 1:Interrupt Extra BD & Clear */
+#define Int_DmParErr 0x00000080 /* 1:DMA Parity Error & Clear */
+#define Int_IntEarNot 0x00000040 /* 1:Receive Data write & Clear */
+#define Int_SWInt 0x00000020 /* 1:Software request & Clear */
+#define Int_IntBLEx 0x00000010 /* 1:Buffer List Empty & Clear */
+#define Int_IntFDAEx 0x00000008 /* 1:FDA Empty & Clear */
+#define Int_IntPCI 0x00000004 /* 1:PCI controller & Clear */
+#define Int_IntMacRx 0x00000002 /* 1:Rx controller & Clear */
+#define Int_IntMacTx 0x00000001 /* 1:Tx controller & Clear */
+
+/* MD_CA bit asign --------------------------------------------------------- */
+#define MD_CA_PreSup 0x00001000 /* 1:Preamble Supress */
+#define MD_CA_Busy 0x00000800 /* 1:Busy (Start Operation) */
+#define MD_CA_Wr 0x00000400 /* 1:Write 0:Read */
+
+
+/* MII register offsets */
+#define MII_CONTROL 0x0000
+#define MII_STATUS 0x0001
+#define MII_PHY_ID0 0x0002
+#define MII_PHY_ID1 0x0003
+#define MII_ANAR 0x0004
+#define MII_ANLPAR 0x0005
+#define MII_ANER 0x0006
+/* MII Control register bit definitions. */
+#define MIICNTL_FDX 0x0100
+#define MIICNTL_RST_AUTO 0x0200
+#define MIICNTL_ISOLATE 0x0400
+#define MIICNTL_PWRDWN 0x0800
+#define MIICNTL_AUTO 0x1000
+#define MIICNTL_SPEED 0x2000
+#define MIICNTL_LPBK 0x4000
+#define MIICNTL_RESET 0x8000
+/* MII Status register bit significance. */
+#define MIISTAT_EXT 0x0001
+#define MIISTAT_JAB 0x0002
+#define MIISTAT_LINK 0x0004
+#define MIISTAT_CAN_AUTO 0x0008
+#define MIISTAT_FAULT 0x0010
+#define MIISTAT_AUTO_DONE 0x0020
+#define MIISTAT_CAN_T 0x0800
+#define MIISTAT_CAN_T_FDX 0x1000
+#define MIISTAT_CAN_TX 0x2000
+#define MIISTAT_CAN_TX_FDX 0x4000
+#define MIISTAT_CAN_T4 0x8000
+/* MII Auto-Negotiation Expansion/RemoteEnd Register Bits */
+#define MII_AN_TX_FDX 0x0100
+#define MII_AN_TX_HDX 0x0080
+#define MII_AN_10_FDX 0x0040
+#define MII_AN_10_HDX 0x0020
+
+
+/*
+ * Descriptors
+ */
+
+/* Frame descripter */
+struct FDesc {
+ volatile __u32 FDNext;
+ volatile __u32 FDSystem;
+ volatile __u32 FDStat;
+ volatile __u32 FDCtl;
+};
+
+/* Buffer descripter */
+struct BDesc {
+ volatile __u32 BuffData;
+ volatile __u32 BDCtl;
+};
+
+#define FD_ALIGN 16
+
+/* Frame Descripter bit asign ---------------------------------------------- */
+#define FD_FDLength_MASK 0x0000FFFF /* Length MASK */
+#define FD_BDCnt_MASK 0x001F0000 /* BD count MASK in FD */
+#define FD_FrmOpt_MASK 0x7C000000 /* Frame option MASK */
+#define FD_FrmOpt_BigEndian 0x40000000 /* Tx/Rx */
+#define FD_FrmOpt_IntTx 0x20000000 /* Tx only */
+#define FD_FrmOpt_NoCRC 0x10000000 /* Tx only */
+#define FD_FrmOpt_NoPadding 0x08000000 /* Tx only */
+#define FD_FrmOpt_Packing 0x04000000 /* Rx only */
+#define FD_CownsFD 0x80000000 /* FD Controller owner bit */
+#define FD_Next_EOL 0x00000001 /* FD EOL indicator */
+#define FD_BDCnt_SHIFT 16
+
+/* Buffer Descripter bit asign --------------------------------------------- */
+#define BD_BuffLength_MASK 0x0000FFFF /* Recieve Data Size */
+#define BD_RxBDID_MASK 0x00FF0000 /* BD ID Number MASK */
+#define BD_RxBDSeqN_MASK 0x7F000000 /* Rx BD Sequence Number */
+#define BD_CownsBD 0x80000000 /* BD Controller owner bit */
+#define BD_RxBDID_SHIFT 16
+#define BD_RxBDSeqN_SHIFT 24
+
+
+/* Some useful constants. */
+#undef NO_CHECK_CARRIER /* Does not check No-Carrier with TP */
+
+#ifdef NO_CHECK_CARRIER
+#define TX_CTL_CMD (Tx_EnComp | Tx_EnTxPar | Tx_EnLateColl | \
+ Tx_EnExColl | Tx_EnLCarr | Tx_EnExDefer | Tx_EnUnder | \
+ Tx_En) /* maybe 0x7d01 */
+#else
+#define TX_CTL_CMD (Tx_EnComp | Tx_EnTxPar | Tx_EnLateColl | \
+ Tx_EnExColl | Tx_EnExDefer | Tx_EnUnder | \
+ Tx_En) /* maybe 0x7f01 */
+#endif
+#define RX_CTL_CMD (Rx_EnGood | Rx_EnRxPar | Rx_EnLongErr | Rx_EnOver \
+ | Rx_EnCRCErr | Rx_EnAlign | Rx_RxEn) /* maybe 0x6f01 */
+
+#define INT_EN_CMD (Int_NRAbtEn | \
+ Int_DParDEn | Int_DParErrEn | \
+ Int_SSysErrEn | Int_RMasAbtEn | Int_RTargAbtEn | \
+ Int_STargAbtEn | \
+ Int_BLExEn | Int_FDAExEn) /* maybe 0xb7f*/
+
+/* Tuning parameters */
+#define DMA_BURST_SIZE 32
+#define TX_THRESHOLD 1024
+
+#define FD_PAGE_NUM 2
+#define FD_PAGE_ORDER 1
+/* 16 + RX_BUF_PAGES * 8 + RX_FD_NUM * 16 + TX_FD_NUM * 32 <= PAGE_SIZE*2 */
+#define RX_BUF_PAGES 8 /* >= 2 */
+#define RX_FD_NUM 250 /* >= 32 */
+#define TX_FD_NUM 128
+
+struct TxFD {
+ struct FDesc fd;
+ struct BDesc bd;
+ struct BDesc unused;
+};
+
+struct RxFD {
+ struct FDesc fd;
+ struct BDesc bd[0]; /* variable length */
+};
+
+struct FrFD {
+ struct FDesc fd;
+ struct BDesc bd[RX_BUF_PAGES];
+};
+
+
+extern unsigned long tc_readl(volatile __u32 *addr);
+extern void tc_writel(unsigned long data, volatile __u32 *addr);
+
+dma_addr_t priv_dma_handle;
+
+/* Information that need to be kept for each board. */
+struct tc35815_local {
+ struct net_device *next_module;
+
+ /* statistics */
+ struct net_device_stats stats;
+ struct {
+ int max_tx_qlen;
+ int tx_ints;
+ int rx_ints;
+ } lstats;
+
+ int tbusy;
+ int option;
+#define TC35815_OPT_AUTO 0x00
+#define TC35815_OPT_10M 0x01
+#define TC35815_OPT_100M 0x02
+#define TC35815_OPT_FULLDUP 0x04
+ int linkspeed; /* 10 or 100 */
+ int fullduplex;
+
+ /*
+ * Transmitting: Batch Mode.
+ * 1 BD in 1 TxFD.
+ * Receiving: Packing Mode.
+ * 1 circular FD for Free Buffer List.
+ * RX_BUG_PAGES BD in Free Buffer FD.
+ * One Free Buffer BD has PAGE_SIZE data buffer.
+ */
+ struct pci_dev *pdev;
+ dma_addr_t fd_buf_dma_handle;
+ void * fd_buf; /* for TxFD, TxFD, FrFD */
+ struct TxFD *tfd_base;
+ int tfd_start;
+ int tfd_end;
+ struct RxFD *rfd_base;
+ struct RxFD *rfd_limit;
+ struct RxFD *rfd_cur;
+ struct FrFD *fbl_ptr;
+ unsigned char fbl_curid;
+ dma_addr_t data_buf_dma_handle[RX_BUF_PAGES];
+ void * data_buf[RX_BUF_PAGES]; /* packing */
+};
+
+/* Index to functions, as function prototypes. */
+
+static int __init tc35815_probe1(struct pci_dev *pdev, unsigned int base_addr, unsigned int irq);
+
+static int tc35815_open(struct net_device *dev);
+static int tc35815_send_packet(struct sk_buff *skb, struct net_device *dev);
+static void tc35815_tx_timeout(struct net_device *dev);
+static void tc35815_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static void tc35815_rx(struct net_device *dev);
+static void tc35815_txdone(struct net_device *dev);
+static int tc35815_close(struct net_device *dev);
+static struct net_device_stats *tc35815_get_stats(struct net_device *dev);
+static void tc35815_set_multicast_list(struct net_device *dev);
+
+static void tc35815_chip_reset(struct net_device *dev);
+static void tc35815_chip_init(struct net_device *dev);
+static void tc35815_phy_chip_init(struct net_device *dev);
+static int tc35815_proc_info(char *buffer, char **start, off_t offset, int length, int *eof, void *data);
+
+/* A list of all installed tc35815 devices. */
+static struct net_device *root_tc35815_dev = NULL;
+
+/*
+ * PCI device identifiers for "new style" Linux PCI Device Drivers
+ */
+static struct pci_device_id tc35815_pci_tbl[] __devinitdata = {
+ { PCI_VENDOR_ID_TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_TC35815CF, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+ { 0, }
+};
+
+MODULE_DEVICE_TABLE (pci, tc35815_pci_tbl);
+
+int
+tc35815_probe(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+{
+ static int called = 0;
+ int err = 0;
+ int ret;
+
+ if (called)
+ return -ENODEV;
+ called++;
+
+ if (!pci_present())
+ return -ENODEV;
+
+ if (pdev) {
+ unsigned int pci_memaddr;
+ unsigned int pci_irq_line;
+
+ printk(KERN_INFO "tc35815_probe: found device %#08x.%#08x\n", ent->vendor, ent->device);
+
+ pci_memaddr = pci_resource_start (pdev, 1);
+
+ printk(KERN_INFO " pci_memaddr=%#08lx resource_flags=%#08lx\n", pci_memaddr, pci_resource_flags (pdev, 0));
+
+ if (!pci_memaddr) {
+ printk(KERN_WARNING "no PCI MEM resources, aborting\n");
+ return -ENODEV;
+ }
+ pci_irq_line = pdev->irq;
+ /* irq disabled. */
+ if (pci_irq_line == 0) {
+ printk(KERN_WARNING "no PCI irq, aborting\n");
+ return -ENODEV;
+ }
+
+ ret = tc35815_probe1(pdev, pci_memaddr, pci_irq_line);
+
+ if (!ret) {
+ if ((err = pci_enable_device(pdev)) < 0) {
+ printk(KERN_ERR "tc35815_probe: failed to enable device -- err=%d\n", err);
+ return err;
+ }
+ pci_set_master(pdev);
+ }
+
+ return ret;
+ }
+ return -ENODEV;
+}
+
+static int __init tc35815_probe1(struct pci_dev *pdev, unsigned int base_addr, unsigned int irq)
+{
+ static unsigned version_printed = 0;
+ int i;
+ struct tc35815_local *lp;
+ struct tc35815_regs *tr;
+ struct net_device *dev;
+
+ /* Allocate a new 'dev' if needed. */
+ dev = init_etherdev(NULL, 0);
+ if (dev == NULL)
+ return -ENOMEM;
+
+ if (tc35815_debug && version_printed++ == 0)
+ printk(KERN_DEBUG "%s", version);
+
+ printk(KERN_INFO "%s: %s found at %#x, irq %d\n",
+ dev->name, cardname, base_addr, irq);
+
+ /* Fill in the 'dev' fields. */
+ dev->irq = irq;
+ dev->base_addr = (unsigned long)ioremap(base_addr,
+ sizeof(struct tc35815_regs));
+ tr = (struct tc35815_regs*)dev->base_addr;
+
+ tc35815_chip_reset(dev);
+
+ /* Retrieve and print the ethernet address. */
+ while (tc_readl(&tr->PROM_Ctl) & PROM_Busy)
+ ;
+ for (i = 0; i < 6; i += 2) {
+ unsigned short data;
+ tc_writel(PROM_Busy | PROM_Read | (i / 2 + 2), &tr->PROM_Ctl);
+ while (tc_readl(&tr->PROM_Ctl) & PROM_Busy)
+ ;
+ data = tc_readl(&tr->PROM_Data);
+ dev->dev_addr[i] = data & 0xff;
+ dev->dev_addr[i+1] = data >> 8;
+ }
+ for (i = 0; i < 6; i++)
+ printk(" %2.2x", dev->dev_addr[i]);
+ printk("\n");
+
+ /* Initialize the device structure. */
+ if (dev->priv == NULL) {
+ dev->priv = kmalloc(sizeof(struct tc35815_local), GFP_KERNEL);
+ if (dev->priv == NULL)
+ return -ENODEV;
+ }
+ lp = dev->priv;
+
+ lp->pdev = pdev;
+
+ memset(lp, 0, sizeof(struct tc35815_local));
+
+ lp->next_module = root_tc35815_dev;
+ root_tc35815_dev = dev;
+
+ if (dev->mem_start > 0) {
+ lp->option = dev->mem_start;
+ if ((lp->option & TC35815_OPT_10M) &&
+ (lp->option & TC35815_OPT_100M)) {
+ /* if both speed speficied, auto select. */
+ lp->option &= ~(TC35815_OPT_10M | TC35815_OPT_100M);
+ }
+ }
+ //XXX fixme
+ lp->option |= TC35815_OPT_10M;
+
+ /* do auto negotiation */
+ tc35815_phy_chip_init(dev);
+ printk(KERN_INFO "%s: linkspeed %dMbps, %s Duplex\n",
+ dev->name, lp->linkspeed, lp->fullduplex ? "Full" : "Half");
+
+ dev->open = tc35815_open;
+ dev->stop = tc35815_close;
+ dev->tx_timeout = tc35815_tx_timeout;
+ dev->watchdog_timeo = TX_TIMEOUT;
+ dev->hard_start_xmit = tc35815_send_packet;
+ dev->get_stats = tc35815_get_stats;
+ dev->set_multicast_list = tc35815_set_multicast_list;
+
+#if 0 /* XXX called in init_etherdev */
+ /* Fill in the fields of the device structure with ethernet values. */
+ ether_setup(dev);
+#endif
+
+ return 0;
+}
+
+
+static int
+tc35815_init_queues(struct net_device *dev)
+{
+ struct tc35815_local *lp = (struct tc35815_local *)dev->priv;
+ int i;
+ unsigned long fd_addr;
+
+ if (!lp->fd_buf) {
+ if (sizeof(struct FDesc) +
+ sizeof(struct BDesc) * RX_BUF_PAGES +
+ sizeof(struct FDesc) * RX_FD_NUM +
+ sizeof(struct TxFD) * TX_FD_NUM > PAGE_SIZE * FD_PAGE_NUM) {
+ printk(KERN_WARNING "%s: Invalid Queue Size.\n", dev->name);
+ return -ENOMEM;
+ }
+
+ if ((lp->fd_buf = (void *)__get_free_pages(GFP_KERNEL, FD_PAGE_ORDER)) == 0)
+ return -ENOMEM;
+ for (i = 0; i < RX_BUF_PAGES; i++) {
+ if ((lp->data_buf[i] = (void *)get_free_page(GFP_KERNEL)) == 0) {
+ while (--i >= 0) {
+ free_page((unsigned long)lp->data_buf[i]);
+ lp->data_buf[i] = 0;
+ }
+ free_page((unsigned long)lp->fd_buf);
+ lp->fd_buf = 0;
+ return -ENOMEM;
+ }
+#ifdef __mips__
+ dma_cache_wback_inv((unsigned long)lp->data_buf[i], PAGE_SIZE * FD_PAGE_NUM);
+#endif
+ }
+#ifdef __mips__
+ dma_cache_wback_inv((unsigned long)lp->fd_buf, PAGE_SIZE * FD_PAGE_NUM);
+#endif
+ } else {
+ clear_page(lp->fd_buf);
+#ifdef __mips__
+ dma_cache_wback_inv((unsigned long)lp->fd_buf, PAGE_SIZE * FD_PAGE_NUM);
+#endif
+ }
+#ifdef __mips__
+ fd_addr = (unsigned long)vtonocache(lp->fd_buf);
+#else
+ fd_addr = (unsigned long)lp->fd_buf;
+#endif
+
+ /* Free Descriptors (for Receive) */
+ lp->rfd_base = (struct RxFD *)fd_addr;
+ fd_addr += sizeof(struct RxFD) * RX_FD_NUM;
+ for (i = 0; i < RX_FD_NUM; i++) {
+ lp->rfd_base[i].fd.FDCtl = cpu_to_le32(FD_CownsFD);
+ }
+ lp->rfd_cur = lp->rfd_base;
+ lp->rfd_limit = (struct RxFD *)(fd_addr -
+ sizeof(struct FDesc) -
+ sizeof(struct BDesc) * 30);
+
+ /* Transmit Descriptors */
+ lp->tfd_base = (struct TxFD *)fd_addr;
+ fd_addr += sizeof(struct TxFD) * TX_FD_NUM;
+ for (i = 0; i < TX_FD_NUM; i++) {
+ lp->tfd_base[i].fd.FDNext = cpu_to_le32(virt_to_bus(&lp->tfd_base[i+1]));
+ lp->tfd_base[i].fd.FDSystem = cpu_to_le32(0);
+ lp->tfd_base[i].fd.FDCtl = cpu_to_le32(0);
+ }
+ lp->tfd_base[TX_FD_NUM-1].fd.FDNext = cpu_to_le32(virt_to_bus(&lp->tfd_base[0]));
+ lp->tfd_start = 0;
+ lp->tfd_end = 0;
+
+ /* Buffer List (for Receive) */
+ lp->fbl_ptr = (struct FrFD *)fd_addr;
+ lp->fbl_ptr->fd.FDNext = cpu_to_le32(virt_to_bus(lp->fbl_ptr));
+ lp->fbl_ptr->fd.FDCtl = cpu_to_le32(RX_BUF_PAGES | FD_CownsFD);
+ for (i = 0; i < RX_BUF_PAGES; i++) {
+ lp->fbl_ptr->bd[i].BuffData = cpu_to_le32(virt_to_bus(lp->data_buf[i]));
+ /* BDID is index of FrFD.bd[] */
+ lp->fbl_ptr->bd[i].BDCtl =
+ cpu_to_le32(BD_CownsBD | (i << BD_RxBDID_SHIFT) | PAGE_SIZE);
+ }
+ lp->fbl_curid = 0;
+
+ return 0;
+}
+
+static void
+tc35815_clear_queues(struct net_device *dev)
+{
+ struct tc35815_local *lp = (struct tc35815_local *)dev->priv;
+ int i;
+
+ for (i = 0; i < TX_FD_NUM; i++) {
+ struct sk_buff *skb = (struct sk_buff *)
+ le32_to_cpu(lp->tfd_base[i].fd.FDSystem);
+ if (skb)
+ dev_kfree_skb_any(skb);
+ lp->tfd_base[i].fd.FDSystem = cpu_to_le32(0);
+ }
+
+ tc35815_init_queues(dev);
+}
+
+static void
+tc35815_free_queues(struct net_device *dev)
+{
+ struct tc35815_local *lp = (struct tc35815_local *)dev->priv;
+ int i;
+
+ if (lp->tfd_base) {
+ for (i = 0; i < TX_FD_NUM; i++) {
+ struct sk_buff *skb = (struct sk_buff *)
+ le32_to_cpu(lp->tfd_base[i].fd.FDSystem);
+ if (skb)
+ dev_kfree_skb_any(skb);
+ lp->tfd_base[i].fd.FDSystem = cpu_to_le32(0);
+ }
+ }
+
+ lp->rfd_base = NULL;
+ lp->rfd_base = NULL;
+ lp->rfd_limit = NULL;
+ lp->rfd_cur = NULL;
+ lp->fbl_ptr = NULL;
+
+ for (i = 0; i < RX_BUF_PAGES; i++) {
+ if (lp->data_buf[i])
+ free_page((unsigned long)lp->data_buf[i]);
+ lp->data_buf[i] = 0;
+ }
+ if (lp->fd_buf)
+ __free_pages(lp->fd_buf, FD_PAGE_ORDER);
+ lp->fd_buf = NULL;
+}
+
+static void
+dump_txfd(struct TxFD *fd)
+{
+ printk("TxFD(%p): %08x %08x %08x %08x\n", fd,
+ le32_to_cpu(fd->fd.FDNext),
+ le32_to_cpu(fd->fd.FDSystem),
+ le32_to_cpu(fd->fd.FDStat),
+ le32_to_cpu(fd->fd.FDCtl));
+ printk("BD: ");
+ printk(" %08x %08x",
+ le32_to_cpu(fd->bd.BuffData),
+ le32_to_cpu(fd->bd.BDCtl));
+ printk("\n");
+}
+
+static int
+dump_rxfd(struct RxFD *fd)
+{
+ int i, bd_count = (le32_to_cpu(fd->fd.FDCtl) & FD_BDCnt_MASK) >> FD_BDCnt_SHIFT;
+ if (bd_count > 8)
+ bd_count = 8;
+ printk("RxFD(%p): %08x %08x %08x %08x\n", fd,
+ le32_to_cpu(fd->fd.FDNext),
+ le32_to_cpu(fd->fd.FDSystem),
+ le32_to_cpu(fd->fd.FDStat),
+ le32_to_cpu(fd->fd.FDCtl));
+ if (le32_to_cpu(fd->fd.FDCtl) & FD_CownsFD)
+ return 0;
+ printk("BD: ");
+ for (i = 0; i < bd_count; i++)
+ printk(" %08x %08x",
+ le32_to_cpu(fd->bd[i].BuffData),
+ le32_to_cpu(fd->bd[i].BDCtl));
+ printk("\n");
+ return bd_count;
+}
+
+static void
+dump_frfd(struct FrFD *fd)
+{
+ int i;
+ printk("FrFD(%p): %08x %08x %08x %08x\n", fd,
+ le32_to_cpu(fd->fd.FDNext),
+ le32_to_cpu(fd->fd.FDSystem),
+ le32_to_cpu(fd->fd.FDStat),
+ le32_to_cpu(fd->fd.FDCtl));
+ printk("BD: ");
+ for (i = 0; i < RX_BUF_PAGES; i++)
+ printk(" %08x %08x",
+ le32_to_cpu(fd->bd[i].BuffData),
+ le32_to_cpu(fd->bd[i].BDCtl));
+ printk("\n");
+}
+
+static void
+panic_queues(struct net_device *dev)
+{
+ struct tc35815_local *lp = (struct tc35815_local *)dev->priv;
+ int i;
+
+ printk("TxFD base %p, start %d, end %d\n",
+ lp->tfd_base, lp->tfd_start, lp->tfd_end);
+ printk("RxFD base %p limit %p cur %p\n",
+ lp->rfd_base, lp->rfd_limit, lp->rfd_cur);
+ printk("FrFD %p\n", lp->fbl_ptr);
+ for (i = 0; i < TX_FD_NUM; i++)
+ dump_txfd(&lp->tfd_base[i]);
+ for (i = 0; i < RX_FD_NUM; i++) {
+ int bd_count = dump_rxfd(&lp->rfd_base[i]);
+ i += (bd_count + 1) / 2; /* skip BDs */
+ }
+ dump_frfd(lp->fbl_ptr);
+ panic("%s: Illegal queue state.", dev->name);
+}
+
+static void print_buf(char *add, int length)
+{
+ int i;
+ int len = length;
+
+ printk("print_buf(%08x)(%x)\n", (unsigned int) add,length);
+
+ if (len > 100)
+ len = 100;
+ for (i = 0; i < len; i++) {
+ printk(" %2.2X", (unsigned char) add[i]);
+ if (!(i % 16))
+ printk("\n");
+ }
+ printk("\n");
+}
+
+static void print_eth(char *add)
+{
+ int i;
+
+ printk("print_eth(%08x)\n", (unsigned int) add);
+ for (i = 0; i < 6; i++)
+ printk(" %2.2X", (unsigned char) add[i + 6]);
+ printk(" =>");
+ for (i = 0; i < 6; i++)
+ printk(" %2.2X", (unsigned char) add[i]);
+ printk(" : %2.2X%2.2X\n", (unsigned char) add[12], (unsigned char) add[13]);
+}
+
+/*
+ * Open/initialize the board. This is called (in the current kernel)
+ * sometime after booting when the 'ifconfig' program is run.
+ *
+ * This routine should set everything up anew at each open, even
+ * registers that "should" only need to be set once at boot, so that
+ * there is non-reboot way to recover if something goes wrong.
+ */
+static int
+tc35815_open(struct net_device *dev)
+{
+ struct tc35815_local *lp = (struct tc35815_local *)dev->priv;
+ /*
+ * This is used if the interrupt line can turned off (shared).
+ * See 3c503.c for an example of selecting the IRQ at config-time.
+ */
+
+ if (dev->irq == 0 ||
+ request_irq(dev->irq, &tc35815_interrupt, SA_SHIRQ, cardname, dev)) {
+ return -EAGAIN;
+ }
+
+ tc35815_chip_reset(dev);
+
+ if (tc35815_init_queues(dev) != 0) {
+ free_irq(dev->irq, dev);
+ return -EAGAIN;
+ }
+
+ /* Reset the hardware here. Don't forget to set the station address. */
+ tc35815_chip_init(dev);
+
+ lp->tbusy = 0;
+ netif_start_queue(dev);
+
+ MOD_INC_USE_COUNT;
+
+ return 0;
+}
+
+static void tc35815_tx_timeout(struct net_device *dev)
+{
+ struct tc35815_local *lp = (struct tc35815_local *)dev->priv;
+ struct tc35815_regs *tr = (struct tc35815_regs *)dev->base_addr;
+ int flags;
+
+ save_and_cli(flags);
+ printk(KERN_WARNING "%s: transmit timed out, status %#x\n",
+ dev->name, tc_readl(&tr->Tx_Stat));
+ /* Try to restart the adaptor. */
+ tc35815_chip_reset(dev);
+ tc35815_clear_queues(dev);
+ tc35815_chip_init(dev);
+ lp->tbusy=0;
+ restore_flags(flags);
+ dev->trans_start = jiffies;
+ netif_wake_queue(dev);
+}
+
+static int tc35815_send_packet(struct sk_buff *skb, struct net_device *dev)
+{
+ struct tc35815_local *lp = (struct tc35815_local *)dev->priv;
+ struct tc35815_regs *tr = (struct tc35815_regs *)dev->base_addr;
+
+ if (netif_queue_stopped(dev)) {
+ /*
+ * If we get here, some higher level has decided we are broken.
+ * There should really be a "kick me" function call instead.
+ */
+ int tickssofar = jiffies - dev->trans_start;
+ if (tickssofar < 5)
+ return 1;
+ printk(KERN_WARNING "%s: transmit timed out, status %#x\n",
+ dev->name, tc_readl(&tr->Tx_Stat));
+ /* Try to restart the adaptor. */
+ tc35815_chip_reset(dev);
+ tc35815_clear_queues(dev);
+ tc35815_chip_init(dev);
+ lp->tbusy=0;
+ dev->trans_start = jiffies;
+ netif_wake_queue(dev);
+ }
+
+ /*
+ * Block a timer-based transmit from overlapping. This could better be
+ * done with atomic_swap(1, lp->tbusy), but set_bit() works as well.
+ */
+ if (test_and_set_bit(0, (void*)&lp->tbusy) != 0) {
+ printk(KERN_WARNING "%s: Transmitter access conflict.\n", dev->name);
+ dev_kfree_skb_any(skb);
+ } else {
+ short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
+ unsigned char *buf = skb->data;
+ struct TxFD *txfd = &lp->tfd_base[lp->tfd_start];
+ int flags;
+ lp->stats.tx_bytes += skb->len;
+
+
+#ifdef __mips__
+ dma_cache_wback_inv((unsigned long)buf, length);
+#endif
+
+ save_and_cli(flags);
+
+ /* failsafe... */
+ if (lp->tfd_start != lp->tfd_end)
+ tc35815_txdone(dev);
+
+
+ txfd->bd.BuffData = cpu_to_le32(virt_to_bus(buf));
+
+ txfd->bd.BDCtl = cpu_to_le32(length);
+ txfd->fd.FDSystem = cpu_to_le32((__u32)skb);
+ txfd->fd.FDCtl = cpu_to_le32(FD_CownsFD | (1 << FD_BDCnt_SHIFT));
+
+ if (lp->tfd_start == lp->tfd_end) {
+ /* Start DMA Transmitter. */
+ txfd->fd.FDNext |= cpu_to_le32(FD_Next_EOL);
+#ifdef GATHER_TXINT
+ txfd->fd.FDCtl |= cpu_to_le32(FD_FrmOpt_IntTx);
+#endif
+ if (tc35815_debug > 2) {
+ printk("%s: starting TxFD.\n", dev->name);
+ dump_txfd(txfd);
+ if (tc35815_debug > 3)
+ print_eth(buf);
+ }
+ tc_writel(virt_to_bus(txfd), &tr->TxFrmPtr);
+ } else {
+ txfd->fd.FDNext &= cpu_to_le32(~FD_Next_EOL);
+ if (tc35815_debug > 2) {
+ printk("%s: queueing TxFD.\n", dev->name);
+ dump_txfd(txfd);
+ if (tc35815_debug > 3)
+ print_eth(buf);
+ }
+ }
+ lp->tfd_start = (lp->tfd_start + 1) % TX_FD_NUM;
+
+ dev->trans_start = jiffies;
+
+ if ((lp->tfd_start + 1) % TX_FD_NUM != lp->tfd_end) {
+ /* we can send another packet */
+ lp->tbusy = 0;
+ netif_start_queue(dev);
+ } else {
+ netif_stop_queue(dev);
+ if (tc35815_debug > 1)
+ printk(KERN_WARNING "%s: TxFD Exhausted.\n", dev->name);
+ }
+ restore_flags(flags);
+ }
+
+ return 0;
+}
+
+#define FATAL_ERROR_INT \
+ (Int_IntPCI | Int_DmParErr | Int_IntNRAbt)
+static void tc35815_fatal_error_interrupt(struct net_device *dev, int status)
+{
+ static int count;
+ printk(KERN_WARNING "%s: Fatal Error Intterrupt (%#x):",
+ dev->name, status);
+
+ if (status & Int_IntPCI)
+ printk(" IntPCI");
+ if (status & Int_DmParErr)
+ printk(" DmParErr");
+ if (status & Int_IntNRAbt)
+ printk(" IntNRAbt");
+ printk("\n");
+ if (count++ > 100)
+ panic("%s: Too many fatal errors.", dev->name);
+ printk(KERN_WARNING "%s: Resetting %s...\n", dev->name, cardname);
+ /* Try to restart the adaptor. */
+ tc35815_chip_reset(dev);
+ tc35815_clear_queues(dev);
+ tc35815_chip_init(dev);
+}
+
+/*
+ * The typical workload of the driver:
+ * Handle the network interface interrupts.
+ */
+static void tc35815_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+{
+ struct net_device *dev = dev_id;
+ struct tc35815_regs *tr;
+ struct tc35815_local *lp;
+ int status, boguscount = 0;
+
+ if (dev == NULL) {
+ printk(KERN_WARNING "%s: irq %d for unknown device.\n", cardname, irq);
+ return;
+ }
+
+ tr = (struct tc35815_regs*)dev->base_addr;
+ lp = (struct tc35815_local *)dev->priv;
+
+ do {
+ status = tc_readl(&tr->Int_Src);
+ if (status == 0)
+ break;
+ tc_writel(status, &tr->Int_Src); /* write to clear */
+
+ /* Fatal errors... */
+ if (status & FATAL_ERROR_INT) {
+ tc35815_fatal_error_interrupt(dev, status);
+ break;
+ }
+ /* recoverable errors */
+ if (status & Int_IntFDAEx) {
+ /* disable FDAEx int. (until we make rooms...) */
+ tc_writel(tc_readl(&tr->Int_En) & ~Int_FDAExEn, &tr->Int_En);
+ printk(KERN_WARNING
+ "%s: Free Descriptor Area Exhausted (%#x).\n",
+ dev->name, status);
+ lp->stats.rx_dropped++;
+ }
+ if (status & Int_IntBLEx) {
+ /* disable BLEx int. (until we make rooms...) */
+ tc_writel(tc_readl(&tr->Int_En) & ~Int_BLExEn, &tr->Int_En);
+ printk(KERN_WARNING
+ "%s: Buffer List Exhausted (%#x).\n",
+ dev->name, status);
+ lp->stats.rx_dropped++;
+ }
+ if (status & Int_IntExBD) {
+ printk(KERN_WARNING
+ "%s: Excessive Buffer Descriptiors (%#x).\n",
+ dev->name, status);
+ lp->stats.rx_length_errors++;
+ }
+ /* normal notification */
+ if (status & Int_IntMacRx) {
+ /* Got a packet(s). */
+ lp->lstats.rx_ints++;
+ tc35815_rx(dev);
+ }
+ if (status & Int_IntMacTx) {
+ lp->lstats.tx_ints++;
+ tc35815_txdone(dev);
+ }
+ } while (++boguscount < 20) ;
+
+ return;
+}
+
+/* We have a good packet(s), get it/them out of the buffers. */
+static void
+tc35815_rx(struct net_device *dev)
+{
+ struct tc35815_local *lp = (struct tc35815_local *)dev->priv;
+ struct tc35815_regs *tr = (struct tc35815_regs*)dev->base_addr;
+ unsigned int fdctl;
+ int i;
+ int buf_free_count = 0;
+ int fd_free_count = 0;
+
+ while (!((fdctl = le32_to_cpu(lp->rfd_cur->fd.FDCtl)) & FD_CownsFD)) {
+ int status = le32_to_cpu(lp->rfd_cur->fd.FDStat);
+ int pkt_len = fdctl & FD_FDLength_MASK;
+ struct RxFD *next_rfd;
+ int bd_count = (fdctl & FD_BDCnt_MASK) >> FD_BDCnt_SHIFT;
+
+ if (tc35815_debug > 2)
+ dump_rxfd(lp->rfd_cur);
+ if (status & Rx_Good) {
+ /* Malloc up new buffer. */
+ struct sk_buff *skb;
+ unsigned char *data;
+ int cur_bd, offset;
+
+ lp->stats.rx_bytes += pkt_len;
+
+ skb = dev_alloc_skb(pkt_len + 2); /* +2: for reserve */
+ if (skb == NULL) {
+ printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n",
+ dev->name);
+ lp->stats.rx_dropped++;
+ break;
+ }
+ skb_reserve(skb, 2); /* 16 bit alignment */
+ skb->dev = dev;
+
+ data = skb_put(skb, pkt_len);
+
+ /* copy from receive buffer */
+ cur_bd = 0;
+ offset = 0;
+ while (offset < pkt_len && cur_bd < bd_count) {
+ int len = le32_to_cpu(lp->rfd_cur->bd[cur_bd].BDCtl) &
+ BD_BuffLength_MASK;
+ void *rxbuf =
+ bus_to_virt(le32_to_cpu(lp->rfd_cur->bd[cur_bd].BuffData));
+#ifdef __mips__
+ dma_cache_inv((unsigned long)rxbuf, len);
+#endif
+ memcpy(data + offset, rxbuf, len);
+ offset += len;
+ cur_bd++;
+ }
+ // print_buf(data,pkt_len);
+ if (tc35815_debug > 3)
+ print_eth(data);
+ skb->protocol = eth_type_trans(skb, dev);
+ netif_rx(skb);
+ lp->stats.rx_packets++;
+ } else {
+ lp->stats.rx_errors++;
+ /* WORKAROUND: LongErr and CRCErr means Overflow. */
+ if ((status & Rx_LongErr) && (status & Rx_CRCErr)) {
+ status &= ~(Rx_LongErr|Rx_CRCErr);
+ status |= Rx_Over;
+ }
+ if (status & Rx_LongErr) lp->stats.rx_length_errors++;
+ if (status & Rx_Over) lp->stats.rx_fifo_errors++;
+ if (status & Rx_CRCErr) lp->stats.rx_crc_errors++;
+ if (status & Rx_Align) lp->stats.rx_frame_errors++;
+ }
+
+ if (bd_count > 0) {
+ /* put Free Buffer back to controller */
+ int bdctl = le32_to_cpu(lp->rfd_cur->bd[bd_count - 1].BDCtl);
+ unsigned char id =
+ (bdctl & BD_RxBDID_MASK) >> BD_RxBDID_SHIFT;
+ if (id >= RX_BUF_PAGES) {
+ printk("%s: invalid BDID.\n", dev->name);
+ panic_queues(dev);
+ }
+ /* free old buffers */
+ while (lp->fbl_curid != id) {
+ bdctl = le32_to_cpu(lp->fbl_ptr->bd[lp->fbl_curid].BDCtl);
+ if (bdctl & BD_CownsBD) {
+ printk("%s: Freeing invalid BD.\n",
+ dev->name);
+ panic_queues(dev);
+ }
+ /* pass BD to controler */
+ /* Note: BDLength was modified by chip. */
+ lp->fbl_ptr->bd[lp->fbl_curid].BDCtl =
+ cpu_to_le32(BD_CownsBD |
+ (lp->fbl_curid << BD_RxBDID_SHIFT) |
+ PAGE_SIZE);
+ lp->fbl_curid =
+ (lp->fbl_curid + 1) % RX_BUF_PAGES;
+ if (tc35815_debug > 2) {
+ printk("%s: Entering new FBD %d\n",
+ dev->name, lp->fbl_curid);
+ dump_frfd(lp->fbl_ptr);
+ }
+ buf_free_count++;
+ }
+ }
+
+ /* put RxFD back to controller */
+ next_rfd = bus_to_virt(le32_to_cpu(lp->rfd_cur->fd.FDNext));
+#ifdef __mips__
+ next_rfd = (struct RxFD *)vtonocache(next_rfd);
+#endif
+ if (next_rfd < lp->rfd_base || next_rfd > lp->rfd_limit) {
+ printk("%s: RxFD FDNext invalid.\n", dev->name);
+ panic_queues(dev);
+ }
+ for (i = 0; i < (bd_count + 1) / 2 + 1; i++) {
+ /* pass FD to controler */
+ lp->rfd_cur->fd.FDNext = cpu_to_le32(0xdeaddead); /* for debug */
+ lp->rfd_cur->fd.FDCtl = cpu_to_le32(FD_CownsFD);
+ lp->rfd_cur++;
+ fd_free_count++;
+ }
+
+ lp->rfd_cur = next_rfd;
+ }
+
+ /* re-enable BL/FDA Exhaust interupts. */
+ if (fd_free_count) {
+ tc_writel(tc_readl(&tr->Int_En) | Int_FDAExEn, &tr->Int_En);
+ if (buf_free_count)
+ tc_writel(tc_readl(&tr->Int_En) | Int_BLExEn, &tr->Int_En);
+ }
+}
+
+#ifdef NO_CHECK_CARRIER
+#define TX_STA_ERR (Tx_ExColl|Tx_Under|Tx_Defer|Tx_LateColl|Tx_TxPar|Tx_SQErr)
+#else
+#define TX_STA_ERR (Tx_ExColl|Tx_Under|Tx_Defer|Tx_NCarr|Tx_LateColl|Tx_TxPar|Tx_SQErr)
+#endif
+
+static void
+tc35815_check_tx_stat(struct net_device *dev, int status)
+{
+ struct tc35815_local *lp = (struct tc35815_local *)dev->priv;
+ const char *msg = NULL;
+
+ /* count collisions */
+ if (status & Tx_ExColl)
+ lp->stats.collisions += 16;
+ if (status & Tx_TxColl_MASK)
+ lp->stats.collisions += status & Tx_TxColl_MASK;
+
+ /* WORKAROUND: ignore LostCrS in full duplex operation */
+ if (lp->fullduplex)
+ status &= ~Tx_NCarr;
+
+ if (!(status & TX_STA_ERR)) {
+ /* no error. */
+ lp->stats.tx_packets++;
+ return;
+ }
+
+ lp->stats.tx_errors++;
+ if (status & Tx_ExColl) {
+ lp->stats.tx_aborted_errors++;
+ msg = "Excessive Collision.";
+ }
+ if (status & Tx_Under) {
+ lp->stats.tx_fifo_errors++;
+ msg = "Tx FIFO Underrun.";
+ }
+ if (status & Tx_Defer) {
+ lp->stats.tx_fifo_errors++;
+ msg = "Excessive Deferral.";
+ }
+#ifndef NO_CHECK_CARRIER
+ if (status & Tx_NCarr) {
+ lp->stats.tx_carrier_errors++;
+ msg = "Lost Carrier Sense.";
+ }
+#endif
+ if (status & Tx_LateColl) {
+ lp->stats.tx_aborted_errors++;
+ msg = "Late Collision.";
+ }
+ if (status & Tx_TxPar) {
+ lp->stats.tx_fifo_errors++;
+ msg = "Transmit Parity Error.";
+ }
+ if (status & Tx_SQErr) {
+ lp->stats.tx_heartbeat_errors++;
+ msg = "Signal Quality Error.";
+ }
+ if (msg)
+ printk(KERN_WARNING "%s: %s (%#x)\n", dev->name, msg, status);
+}
+
+static void
+tc35815_txdone(struct net_device *dev)
+{
+ struct tc35815_local *lp = (struct tc35815_local *)dev->priv;
+ struct tc35815_regs *tr = (struct tc35815_regs*)dev->base_addr;
+ struct TxFD *txfd;
+ unsigned int fdctl;
+ int num_done = 0;
+
+ txfd = &lp->tfd_base[lp->tfd_end];
+ while (lp->tfd_start != lp->tfd_end &&
+ !((fdctl = le32_to_cpu(txfd->fd.FDCtl)) & FD_CownsFD)) {
+ int status = le32_to_cpu(txfd->fd.FDStat);
+ struct sk_buff *skb;
+ unsigned long fdnext = le32_to_cpu(txfd->fd.FDNext);
+
+ if (tc35815_debug > 2) {
+ printk("%s: complete TxFD.\n", dev->name);
+ dump_txfd(txfd);
+ }
+ tc35815_check_tx_stat(dev, status);
+
+ skb = (struct sk_buff *)le32_to_cpu(txfd->fd.FDSystem);
+ if (skb) {
+ dev_kfree_skb_any(skb);
+ }
+ txfd->fd.FDSystem = cpu_to_le32(0);
+
+ num_done++;
+ lp->tfd_end = (lp->tfd_end + 1) % TX_FD_NUM;
+ txfd = &lp->tfd_base[lp->tfd_end];
+ if ((fdnext & ~FD_Next_EOL) != virt_to_bus(txfd)) {
+ printk("%s: TxFD FDNext invalid.\n", dev->name);
+ panic_queues(dev);
+ }
+ if (fdnext & FD_Next_EOL) {
+ /* DMA Transmitter has been stopping... */
+ if (lp->tfd_end != lp->tfd_start) {
+ int head = (lp->tfd_start + TX_FD_NUM - 1) % TX_FD_NUM;
+ struct TxFD* txhead = &lp->tfd_base[head];
+ int qlen = (lp->tfd_start + TX_FD_NUM
+ - lp->tfd_end) % TX_FD_NUM;
+
+ if (!(le32_to_cpu(txfd->fd.FDCtl) & FD_CownsFD)) {
+ printk("%s: TxFD FDCtl invalid.\n", dev->name);
+ panic_queues(dev);
+ }
+ /* log max queue length */
+ if (lp->lstats.max_tx_qlen < qlen)
+ lp->lstats.max_tx_qlen = qlen;
+
+
+ /* start DMA Transmitter again */
+ txhead->fd.FDNext |= cpu_to_le32(FD_Next_EOL);
+#ifdef GATHER_TXINT
+ txhead->fd.FDCtl |= cpu_to_le32(FD_FrmOpt_IntTx);
+#endif
+ if (tc35815_debug > 2) {
+ printk("%s: start TxFD on queue.\n",
+ dev->name);
+ dump_txfd(txfd);
+ }
+ tc_writel(virt_to_bus(txfd), &tr->TxFrmPtr);
+ }
+ break;
+ }
+ }
+
+ if (num_done > 0 && lp->tbusy) {
+ lp->tbusy = 0;
+ netif_start_queue(dev);
+ }
+}
+
+/* The inverse routine to tc35815_open(). */
+static int
+tc35815_close(struct net_device *dev)
+{
+ struct tc35815_local *lp = (struct tc35815_local *)dev->priv;
+
+ lp->tbusy = 1;
+ netif_stop_queue(dev);
+
+ /* Flush the Tx and disable Rx here. */
+
+ tc35815_chip_reset(dev);
+ free_irq(dev->irq, dev);
+
+ tc35815_free_queues(dev);
+
+ MOD_DEC_USE_COUNT;
+
+ return 0;
+}
+
+/*
+ * Get the current statistics.
+ * This may be called with the card open or closed.
+ */
+static struct net_device_stats *tc35815_get_stats(struct net_device *dev)
+{
+ struct tc35815_local *lp = (struct tc35815_local *)dev->priv;
+ struct tc35815_regs *tr = (struct tc35815_regs*)dev->base_addr;
+ unsigned long flags;
+
+ if (netif_running(dev)) {
+ save_and_cli(flags);
+ /* Update the statistics from the device registers. */
+ lp->stats.rx_missed_errors = tc_readl(&tr->Miss_Cnt);
+ restore_flags(flags);
+ }
+
+ return &lp->stats;
+}
+
+static void tc35815_set_cam_entry(struct tc35815_regs *tr, int index, unsigned char *addr)
+{
+ int cam_index = index * 6;
+ unsigned long cam_data;
+ unsigned long saved_addr;
+ saved_addr = tc_readl(&tr->CAM_Adr);
+
+ if (tc35815_debug > 1) {
+ int i;
+ printk(KERN_DEBUG "%s: CAM %d:", cardname, index);
+ for (i = 0; i < 6; i++)
+ printk(" %02x", addr[i]);
+ printk("\n");
+ }
+ if (index & 1) {
+ /* read modify write */
+ tc_writel(cam_index - 2, &tr->CAM_Adr);
+ cam_data = tc_readl(&tr->CAM_Data) & 0xffff0000;
+ cam_data |= addr[0] << 8 | addr[1];
+ tc_writel(cam_data, &tr->CAM_Data);
+ /* write whole word */
+ tc_writel(cam_index + 2, &tr->CAM_Adr);
+ cam_data = (addr[2] << 24) | (addr[3] << 16) | (addr[4] << 8) | addr[5];
+ tc_writel(cam_data, &tr->CAM_Data);
+ } else {
+ /* write whole word */
+ tc_writel(cam_index, &tr->CAM_Adr);
+ cam_data = (addr[0] << 24) | (addr[1] << 16) | (addr[2] << 8) | addr[3];
+ tc_writel(cam_data, &tr->CAM_Data);
+ /* read modify write */
+ tc_writel(cam_index + 4, &tr->CAM_Adr);
+ cam_data = tc_readl(&tr->CAM_Data) & 0x0000ffff;
+ cam_data |= addr[4] << 24 | (addr[5] << 16);
+ tc_writel(cam_data, &tr->CAM_Data);
+ }
+
+ if (tc35815_debug > 2) {
+ int i;
+ for (i = cam_index / 4; i < cam_index / 4 + 2; i++) {
+ tc_writel(i * 4, &tr->CAM_Adr);
+ printk("CAM 0x%x: %08x",
+ i * 4, tc_readl(&tr->CAM_Data));
+ }
+ }
+ tc_writel(saved_addr, &tr->CAM_Adr);
+}
+
+
+/*
+ * Set or clear the multicast filter for this adaptor.
+ * num_addrs == -1 Promiscuous mode, receive all packets
+ * num_addrs == 0 Normal mode, clear multicast list
+ * num_addrs > 0 Multicast mode, receive normal and MC packets,
+ * and do best-effort filtering.
+ */
+static void
+tc35815_set_multicast_list(struct net_device *dev)
+{
+ struct tc35815_regs *tr = (struct tc35815_regs*)dev->base_addr;
+
+ if (dev->flags&IFF_PROMISC)
+ {
+ /* Enable promiscuous mode */
+ tc_writel(CAM_CompEn | CAM_BroadAcc | CAM_GroupAcc | CAM_StationAcc, &tr->CAM_Ctl);
+ }
+ else if((dev->flags&IFF_ALLMULTI) || dev->mc_count > CAM_ENTRY_MAX - 3)
+ {
+ /* CAM 0, 1, 20 are reserved. */
+ /* Disable promiscuous mode, use normal mode. */
+ tc_writel(CAM_CompEn | CAM_BroadAcc | CAM_GroupAcc, &tr->CAM_Ctl);
+ }
+ else if(dev->mc_count)
+ {
+ struct dev_mc_list* cur_addr = dev->mc_list;
+ int i;
+ int ena_bits = CAM_Ena_Bit(CAM_ENTRY_SOURCE);
+
+ tc_writel(0, &tr->CAM_Ctl);
+ /* Walk the address list, and load the filter */
+ for (i = 0; i < dev->mc_count; i++, cur_addr = cur_addr->next) {
+ if (!cur_addr)
+ break;
+ /* entry 0,1 is reserved. */
+ tc35815_set_cam_entry(tr, i + 2, cur_addr->dmi_addr);
+ ena_bits |= CAM_Ena_Bit(i + 2);
+ }
+ tc_writel(ena_bits, &tr->CAM_Ena);
+ tc_writel(CAM_CompEn | CAM_BroadAcc, &tr->CAM_Ctl);
+ }
+ else {
+ tc_writel(CAM_Ena_Bit(CAM_ENTRY_SOURCE), &tr->CAM_Ena);
+ tc_writel(CAM_CompEn | CAM_BroadAcc, &tr->CAM_Ctl);
+ }
+}
+
+static unsigned long tc_phy_read(struct tc35815_regs *tr, int phy, int phy_reg)
+{
+ unsigned long data;
+ int flags;
+ save_and_cli(flags);
+ tc_writel(MD_CA_Busy | (phy << 5) | phy_reg, &tr->MD_CA);
+ while (tc_readl(&tr->MD_CA) & MD_CA_Busy)
+ ;
+ data = tc_readl(&tr->MD_Data);
+ restore_flags(flags);
+ return data;
+}
+
+static void tc_phy_write(unsigned long d, struct tc35815_regs *tr, int phy, int phy_reg)
+{
+ int flags;
+ save_and_cli(flags);
+ tc_writel(d, &tr->MD_Data);
+ tc_writel(MD_CA_Busy | MD_CA_Wr | (phy << 5) | phy_reg, &tr->MD_CA);
+ while (tc_readl(&tr->MD_CA) & MD_CA_Busy)
+ ;
+ restore_flags(flags);
+}
+
+static void tc35815_phy_chip_init(struct net_device *dev)
+{
+ struct tc35815_local *lp = (struct tc35815_local *)dev->priv;
+ struct tc35815_regs *tr = (struct tc35815_regs*)dev->base_addr;
+ static int first = 1;
+ unsigned short ctl;
+
+ if (first) {
+ unsigned short id0, id1;
+ int count;
+ first = 0;
+
+ /* first data written to the PHY will be an ID number */
+ tc_phy_write(0, tr, 0, MII_CONTROL); /* ID:0 */
+#if 0
+ tc_phy_write(MIICNTL_RESET, tr, 0, MII_CONTROL);
+ printk(KERN_INFO "%s: Resetting PHY...", dev->name);
+ while (tc_phy_read(tr, 0, MII_CONTROL) & MIICNTL_RESET)
+ ;
+ printk("\n");
+ tc_phy_write(MIICNTL_AUTO|MIICNTL_SPEED|MIICNTL_FDX, tr, 0,
+ MII_CONTROL);
+#endif
+ id0 = tc_phy_read(tr, 0, MII_PHY_ID0);
+ id1 = tc_phy_read(tr, 0, MII_PHY_ID1);
+ printk(KERN_DEBUG "%s: PHY ID %04x %04x\n", dev->name,
+ id0, id1);
+ if (lp->option & TC35815_OPT_10M) {
+ lp->linkspeed = 10;
+ lp->fullduplex = (lp->option & TC35815_OPT_FULLDUP) != 0;
+ } else if (lp->option & TC35815_OPT_100M) {
+ lp->linkspeed = 100;
+ lp->fullduplex = (lp->option & TC35815_OPT_FULLDUP) != 0;
+ } else {
+ /* auto negotiation */
+ unsigned long neg_result;
+ tc_phy_write(MIICNTL_AUTO | MIICNTL_RST_AUTO, tr, 0, MII_CONTROL);
+ printk(KERN_INFO "%s: Auto Negotiation...", dev->name);
+ count = 0;
+ while (!(tc_phy_read(tr, 0, MII_STATUS) & MIISTAT_AUTO_DONE)) {
+ if (count++ > 5000) {
+ printk(" failed. Assume 10Mbps\n");
+ lp->linkspeed = 10;
+ lp->fullduplex = 0;
+ goto done;
+ }
+ if (count % 512 == 0)
+ printk(".");
+ mdelay(1);
+ }
+ printk(" done.\n");
+ neg_result = tc_phy_read(tr, 0, MII_ANLPAR);
+ if (neg_result & (MII_AN_TX_FDX | MII_AN_TX_HDX))
+ lp->linkspeed = 100;
+ else
+ lp->linkspeed = 10;
+ if (neg_result & (MII_AN_TX_FDX | MII_AN_10_FDX))
+ lp->fullduplex = 1;
+ else
+ lp->fullduplex = 0;
+ done:
+ ;
+ }
+ }
+
+ ctl = 0;
+ if (lp->linkspeed == 100)
+ ctl |= MIICNTL_SPEED;
+ if (lp->fullduplex)
+ ctl |= MIICNTL_FDX;
+ tc_phy_write(ctl, tr, 0, MII_CONTROL);
+
+ if (lp->fullduplex) {
+ tc_writel(tc_readl(&tr->MAC_Ctl) | MAC_FullDup, &tr->MAC_Ctl);
+ }
+}
+
+static void tc35815_chip_reset(struct net_device *dev)
+{
+ struct tc35815_regs *tr = (struct tc35815_regs*)dev->base_addr;
+
+ /* reset the controller */
+ tc_writel(MAC_Reset, &tr->MAC_Ctl);
+ while (tc_readl(&tr->MAC_Ctl) & MAC_Reset)
+ ;
+
+ tc_writel(0, &tr->MAC_Ctl);
+
+ /* initialize registers to default value */
+ tc_writel(0, &tr->DMA_Ctl);
+ tc_writel(0, &tr->TxThrsh);
+ tc_writel(0, &tr->TxPollCtr);
+ tc_writel(0, &tr->RxFragSize);
+ tc_writel(0, &tr->Int_En);
+ tc_writel(0, &tr->FDA_Bas);
+ tc_writel(0, &tr->FDA_Lim);
+ tc_writel(0xffffffff, &tr->Int_Src); /* Write 1 to clear */
+ tc_writel(0, &tr->CAM_Ctl);
+ tc_writel(0, &tr->Tx_Ctl);
+ tc_writel(0, &tr->Rx_Ctl);
+ tc_writel(0, &tr->CAM_Ena);
+ (void)tc_readl(&tr->Miss_Cnt); /* Read to clear */
+
+}
+
+static void tc35815_chip_init(struct net_device *dev)
+{
+ struct tc35815_local *lp = (struct tc35815_local *)dev->priv;
+ struct tc35815_regs *tr = (struct tc35815_regs*)dev->base_addr;
+ int flags;
+ unsigned long txctl = TX_CTL_CMD;
+
+ tc35815_phy_chip_init(dev);
+
+ /* load station address to CAM */
+ tc35815_set_cam_entry(tr, CAM_ENTRY_SOURCE, dev->dev_addr);
+
+ /* Enable CAM (broadcast and unicast) */
+ tc_writel(CAM_Ena_Bit(CAM_ENTRY_SOURCE), &tr->CAM_Ena);
+ tc_writel(CAM_CompEn | CAM_BroadAcc, &tr->CAM_Ctl);
+
+ save_and_cli(flags);
+
+ tc_writel(DMA_BURST_SIZE, &tr->DMA_Ctl);
+
+ tc_writel(RxFrag_EnPack | ETH_ZLEN, &tr->RxFragSize); /* Packing */
+ tc_writel(0, &tr->TxPollCtr); /* Batch mode */
+ tc_writel(TX_THRESHOLD, &tr->TxThrsh);
+ tc_writel(INT_EN_CMD, &tr->Int_En);
+
+ /* set queues */
+ tc_writel(virt_to_bus(lp->rfd_base), &tr->FDA_Bas);
+ tc_writel((unsigned long)lp->rfd_limit - (unsigned long)lp->rfd_base,
+ &tr->FDA_Lim);
+ /*
+ * Activation method:
+ * First, enable eht MAC Transmitter and the DMA Receive circuits.
+ * Then enable the DMA Transmitter and the MAC Receive circuits.
+ */
+ tc_writel(virt_to_bus(lp->fbl_ptr), &tr->BLFrmPtr); /* start DMA receiver */
+ tc_writel(RX_CTL_CMD, &tr->Rx_Ctl); /* start MAC receiver */
+ /* start MAC transmitter */
+ /* WORKAROUND: ignore LostCrS in full duplex operation */
+ if (lp->fullduplex)
+ txctl = TX_CTL_CMD & ~Tx_EnLCarr;
+#ifdef GATHER_TXINT
+ txctl &= ~Tx_EnComp; /* disable global tx completion int. */
+#endif
+ tc_writel(txctl, &tr->Tx_Ctl);
+#if 0 /* No need to polling */
+ tc_writel(virt_to_bus(lp->tfd_base), &tr->TxFrmPtr); /* start DMA transmitter */
+#endif
+ restore_flags(flags);
+}
+
+static int tc35815_proc_info(char *buffer, char **start, off_t offset, int length, int *eof, void *data)
+{
+ int len = 0;
+ off_t pos = 0;
+ off_t begin = 0;
+ struct net_device *dev;
+
+ len += sprintf(buffer, "TC35815 statistics:\n");
+ for (dev = root_tc35815_dev; dev; dev = ((struct tc35815_local *)dev->priv)->next_module) {
+ struct tc35815_local *lp = (struct tc35815_local *)dev->priv;
+ len += sprintf(buffer + len,
+ "%s: tx_ints %d, rx_ints %d, max_tx_qlen %d\n",
+ dev->name,
+ lp->lstats.tx_ints,
+ lp->lstats.rx_ints,
+ lp->lstats.max_tx_qlen);
+ pos = begin + len;
+
+ if (pos < offset) {
+ len = 0;
+ begin = pos;
+ }
+
+ if (pos > offset+length) break;
+ }
+
+ *start = buffer + (offset - begin);
+ len -= (offset - begin);
+
+ if (len > length) len = length;
+
+ return len;
+}
+
+/* XXX */
+void
+tc35815_killall(void)
+{
+ struct net_device *dev;
+
+ for (dev = root_tc35815_dev; dev; dev = ((struct tc35815_local *)dev->priv)->next_module) {
+ if (dev->flags&IFF_UP){
+ dev->stop(dev);
+ }
+ }
+}
+
+static struct pci_driver tc35815_driver = {
+ name: TC35815_MODULE_NAME,
+ probe: tc35815_probe,
+ remove: NULL,
+ id_table: tc35815_pci_tbl,
+};
+
+static int __init tc35815_init_module(void)
+{
+ int err;
+
+ if ((err = pci_module_init(&tc35815_driver)) < 0 )
+ return err;
+ else
+ return 0;
+}
+
+static void __exit tc35815_cleanup_module(void)
+{
+ struct net_device *next_dev;
+
+ /* No need to check MOD_IN_USE, as sys_delete_module() checks. */
+ while (root_tc35815_dev) {
+ struct net_device *dev = root_tc35815_dev;
+ next_dev = ((struct tc35815_local *)dev->priv)->next_module;
+ kfree(dev->priv);
+ iounmap((void *)(dev->base_addr));
+ unregister_netdev(dev);
+ kfree(dev);
+ root_tc35815_dev = next_dev;
+ }
+}
+module_init(tc35815_init_module);
+module_exit(tc35815_cleanup_module);
diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c
index 7261252d24011..1235fc86fd9ef 100644
--- a/drivers/net/tg3.c
+++ b/drivers/net/tg3.c
@@ -1509,7 +1509,8 @@ static void tg3_tx(struct tg3 *tp)
if (unlikely(skb == NULL))
BUG();
- pci_unmap_single(tp->pdev, ri->mapping,
+ pci_unmap_single(tp->pdev,
+ pci_unmap_addr(ri, mapping),
(skb->len - skb->data_len),
PCI_DMA_TODEVICE);
@@ -1526,7 +1527,7 @@ static void tg3_tx(struct tg3 *tp)
BUG();
pci_unmap_page(tp->pdev,
- ri->mapping,
+ pci_unmap_addr(ri, mapping),
skb_shinfo(skb)->frags[i].size,
PCI_DMA_TODEVICE);
@@ -1614,7 +1615,7 @@ static int tg3_alloc_rx_skb(struct tg3 *tp, u32 opaque_key,
PCI_DMA_FROMDEVICE);
map->skb = skb;
- map->mapping = mapping;
+ pci_unmap_addr_set(map, mapping, mapping);
if (src_map != NULL)
src_map->skb = NULL;
@@ -1666,7 +1667,8 @@ static void tg3_recycle_rx(struct tg3 *tp, u32 opaque_key,
};
dest_map->skb = src_map->skb;
- dest_map->mapping = src_map->mapping;
+ pci_unmap_addr_set(dest_map, mapping,
+ pci_unmap_addr(src_map, mapping));
dest_desc->addr_hi = src_desc->addr_hi;
dest_desc->addr_lo = src_desc->addr_lo;
@@ -1723,17 +1725,20 @@ static void tg3_rx(struct tg3 *tp)
desc_idx = desc->opaque & RXD_OPAQUE_INDEX_MASK;
opaque_key = desc->opaque & RXD_OPAQUE_RING_MASK;
if (opaque_key == RXD_OPAQUE_RING_STD) {
- dma_addr = tp->rx_std_buffers[desc_idx].mapping;
+ dma_addr = pci_unmap_addr(&tp->rx_std_buffers[desc_idx],
+ mapping);
skb = tp->rx_std_buffers[desc_idx].skb;
post_ptr = &tp->rx_std_ptr;
} else if (opaque_key == RXD_OPAQUE_RING_JUMBO) {
- dma_addr = tp->rx_jumbo_buffers[desc_idx].mapping;
+ dma_addr = pci_unmap_addr(&tp->rx_jumbo_buffers[desc_idx],
+ mapping);
skb = tp->rx_jumbo_buffers[desc_idx].skb;
post_ptr = &tp->rx_jumbo_ptr;
}
#if TG3_MINI_RING_WORKS
else if (opaque_key == RXD_OPAQUE_RING_MINI) {
- dma_addr = tp->rx_mini_buffers[desc_idx].mapping;
+ dma_addr = pci_unmap_addr(&tp->rx_mini_buffers[desc_idx],
+ mapping);
skb = tp->rx_mini_buffers[desc_idx].skb;
post_ptr = &tp->rx_mini_ptr;
}
@@ -2072,8 +2077,9 @@ static void tg3_set_txd_addr(struct tg3 *tp, int entry, dma_addr_t mapping)
NIC_SRAM_TX_BUFFER_DESC);
txd += (entry * TXD_SIZE);
- writel(((u64) mapping >> 32),
- txd + TXD_ADDR + TG3_64BIT_REG_HIGH);
+ if (sizeof(dma_addr_t) != sizeof(u32))
+ writel(((u64) mapping >> 32),
+ txd + TXD_ADDR + TG3_64BIT_REG_HIGH);
writel(((u64) mapping & 0xffffffff),
txd + TXD_ADDR + TG3_64BIT_REG_LOW);
@@ -2111,10 +2117,12 @@ static int tigon3_4gb_hwbug_workaround(struct tg3 *tp, struct sk_buff *skb,
frag->page, frag->page_offset,
guilty_len, PCI_DMA_TODEVICE);
}
- pci_unmap_single(tp->pdev, tp->tx_buffers[guilty_entry].mapping,
+ pci_unmap_single(tp->pdev, pci_unmap_addr(&tp->tx_buffers[guilty_entry],
+ mapping),
guilty_len, PCI_DMA_TODEVICE);
tg3_set_txd_addr(tp, guilty_entry, new_addr);
- tp->tx_buffers[guilty_entry].mapping = new_addr;
+ pci_unmap_addr_set(&tp->tx_buffers[guilty_entry], mapping,
+ new_addr);
*start = last_plus_one;
#else
/* Oh well, no IOMMU, have to allocate a whole new SKB. */
@@ -2148,11 +2156,12 @@ static int tigon3_4gb_hwbug_workaround(struct tg3 *tp, struct sk_buff *skb,
len = skb->len - skb->data_len;
else
len = skb_shinfo(skb)->frags[i-1].size;
- pci_unmap_single(tp->pdev, tp->tx_buffers[entry].mapping,
+ pci_unmap_single(tp->pdev,
+ pci_unmap_addr(&tp->tx_buffers[entry], mapping),
len, PCI_DMA_TODEVICE);
if (i == 0) {
tp->tx_buffers[entry].skb = new_skb;
- tp->tx_buffers[entry].mapping = new_addr;
+ pci_unmap_addr_set(&tp->tx_buffers[entry], mapping, new_addr);
} else {
tp->tx_buffers[entry].skb = NULL;
}
@@ -2199,8 +2208,7 @@ static void tg3_set_txd(struct tg3 *tp, int entry,
txd += (entry * TXD_SIZE);
/* Save some PIOs */
- if (((u64) tp->tx_buffers[entry].mapping >> 32) !=
- ((u64) mapping >> 32))
+ if (sizeof(dma_addr_t) != sizeof(u32))
writel(((u64) mapping >> 32),
txd + TXD_ADDR + TG3_64BIT_REG_HIGH);
@@ -2257,9 +2265,12 @@ static int tg3_start_xmit_4gbug(struct sk_buff *skb, struct net_device *dev)
mapping = pci_map_single(tp->pdev, skb->data, len, PCI_DMA_TODEVICE);
tp->tx_buffers[entry].skb = skb;
- tp->tx_buffers[entry].mapping = mapping;
+ pci_unmap_addr_set(&tp->tx_buffers[entry], mapping, mapping);
- would_hit_hwbug = tg3_4g_overflow_test(mapping, len);
+ would_hit_hwbug = 0;
+
+ if (tg3_4g_overflow_test(mapping, len))
+ would_hit_hwbug = entry + 1;
tg3_set_txd(tp, entry, mapping, len, base_flags,
(skb_shinfo(skb)->nr_frags == 0));
@@ -2281,10 +2292,14 @@ static int tg3_start_xmit_4gbug(struct sk_buff *skb, struct net_device *dev)
len, PCI_DMA_TODEVICE);
tp->tx_buffers[entry].skb = NULL;
- tp->tx_buffers[entry].mapping = mapping;
+ pci_unmap_addr_set(&tp->tx_buffers[entry], mapping, mapping);
- would_hit_hwbug |=
- tg3_4g_overflow_test(mapping, len);
+ if (tg3_4g_overflow_test(mapping, len)) {
+ /* Only one should match. */
+ if (would_hit_hwbug)
+ BUG();
+ would_hit_hwbug = entry + 1;
+ }
tg3_set_txd(tp, entry, mapping, len,
base_flags, (i == last));
@@ -2298,19 +2313,18 @@ static int tg3_start_xmit_4gbug(struct sk_buff *skb, struct net_device *dev)
u32 start;
unsigned int len = 0;
+ would_hit_hwbug -= 1;
entry = entry - 1 - skb_shinfo(skb)->nr_frags;
entry &= (TG3_TX_RING_SIZE - 1);
start = entry;
i = 0;
while (entry != last_plus_one) {
- dma_addr_t mapping = tp->tx_buffers[entry].mapping;
-
if (i == 0)
len = skb->len - skb->data_len;
else
len = skb_shinfo(skb)->frags[i-1].size;
- if (tg3_4g_overflow_test(mapping, len))
+ if (entry == would_hit_hwbug)
break;
i++;
@@ -2390,7 +2404,7 @@ static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev)
mapping = pci_map_single(tp->pdev, skb->data, len, PCI_DMA_TODEVICE);
tp->tx_buffers[entry].skb = skb;
- tp->tx_buffers[entry].mapping = mapping;
+ pci_unmap_addr_set(&tp->tx_buffers[entry], mapping, mapping);
tg3_set_txd(tp, entry, mapping, len, base_flags,
(skb_shinfo(skb)->nr_frags == 0));
@@ -2413,7 +2427,7 @@ static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev)
len, PCI_DMA_TODEVICE);
tp->tx_buffers[entry].skb = NULL;
- tp->tx_buffers[entry].mapping = mapping;
+ pci_unmap_addr_set(&tp->tx_buffers[entry], mapping, mapping);
tg3_set_txd(tp, entry, mapping, len,
base_flags, (i == last));
@@ -2497,7 +2511,8 @@ static void tg3_free_rings(struct tg3 *tp)
if (rxp->skb == NULL)
continue;
- pci_unmap_single(tp->pdev, rxp->mapping,
+ pci_unmap_single(tp->pdev,
+ pci_unmap_addr(rxp, mapping),
RX_PKT_BUF_SZ - tp->rx_offset,
PCI_DMA_FROMDEVICE);
dev_kfree_skb(rxp->skb);
@@ -2509,7 +2524,8 @@ static void tg3_free_rings(struct tg3 *tp)
if (rxp->skb == NULL)
continue;
- pci_unmap_single(tp->pdev, rxp->mapping,
+ pci_unmap_single(tp->pdev,
+ pci_unmap_addr(rxp, mapping),
RX_MINI_PKT_BUF_SZ - tp->rx_offset,
PCI_DMA_FROMDEVICE);
dev_kfree_skb(rxp->skb);
@@ -2521,7 +2537,8 @@ static void tg3_free_rings(struct tg3 *tp)
if (rxp->skb == NULL)
continue;
- pci_unmap_single(tp->pdev, rxp->mapping,
+ pci_unmap_single(tp->pdev,
+ pci_unmap_addr(rxp, mapping),
RX_JUMBO_PKT_BUF_SZ - tp->rx_offset,
PCI_DMA_FROMDEVICE);
dev_kfree_skb(rxp->skb);
@@ -2541,7 +2558,8 @@ static void tg3_free_rings(struct tg3 *tp)
continue;
}
- pci_unmap_single(tp->pdev, txp->mapping,
+ pci_unmap_single(tp->pdev,
+ pci_unmap_addr(txp, mapping),
(skb->len - skb->data_len),
PCI_DMA_TODEVICE);
txp->skb = NULL;
@@ -2550,7 +2568,8 @@ static void tg3_free_rings(struct tg3 *tp)
for (j = 0; j < skb_shinfo(skb)->nr_frags; j++) {
txp = &tp->tx_buffers[i & (TG3_TX_RING_SIZE - 1)];
- pci_unmap_page(tp->pdev, txp->mapping,
+ pci_unmap_page(tp->pdev,
+ pci_unmap_addr(txp, mapping),
skb_shinfo(skb)->frags[j].size,
PCI_DMA_TODEVICE);
i++;
@@ -4770,6 +4789,7 @@ static int tg3_ethtool_ioctl (struct net_device *dev, void *useraddr)
edata.data = netif_carrier_ok(tp->dev) ? 1 : 0;
if (copy_to_user(useraddr, &edata, sizeof(edata)))
return -EFAULT;
+ return 0;
}
case ETHTOOL_GCOALESCE: {
struct ethtool_coalesce ecoal = { ETHTOOL_GCOALESCE };
@@ -5441,10 +5461,23 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
pci_read_config_dword(tp->pdev, TG3PCI_CACHELINESZ,
&cacheline_sz_reg);
- tp->pci_cacheline_sz = (cacheline_sz_reg >> 24) & 0xff;
- tp->pci_lat_timer = (cacheline_sz_reg >> 16) & 0xff;
- tp->pci_hdr_type = (cacheline_sz_reg >> 8) & 0xff;
- tp->pci_bist = (cacheline_sz_reg >> 0) & 0xff;
+ tp->pci_cacheline_sz = (cacheline_sz_reg >> 0) & 0xff;
+ tp->pci_lat_timer = (cacheline_sz_reg >> 8) & 0xff;
+ tp->pci_hdr_type = (cacheline_sz_reg >> 16) & 0xff;
+ tp->pci_bist = (cacheline_sz_reg >> 24) & 0xff;
+
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703 &&
+ tp->pci_lat_timer < 64) {
+ tp->pci_lat_timer = 64;
+
+ cacheline_sz_reg = ((tp->pci_cacheline_sz & 0xff) << 0);
+ cacheline_sz_reg |= ((tp->pci_lat_timer & 0xff) << 8);
+ cacheline_sz_reg |= ((tp->pci_hdr_type & 0xff) << 16);
+ cacheline_sz_reg |= ((tp->pci_bist & 0xff) << 24);
+
+ pci_write_config_dword(tp->pdev, TG3PCI_CACHELINESZ,
+ cacheline_sz_reg);
+ }
pci_read_config_dword(tp->pdev, TG3PCI_PCISTATE,
&pci_state_reg);
@@ -5924,6 +5957,10 @@ static int __devinit tg3_test_dma(struct tg3 *tp)
tw32(TG3PCI_DMA_RW_CTRL, tp->dma_rwctrl);
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5700 &&
+ GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5701)
+ return 0;
+
ret = 0;
while (1) {
u32 *p, i;
diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h
index 5beda44b61c1c..1ad86220d9aa8 100644
--- a/drivers/net/tg3.h
+++ b/drivers/net/tg3.h
@@ -1654,7 +1654,7 @@ enum phy_led_mode {
*/
struct ring_info {
struct sk_buff *skb;
- dma_addr_t mapping;
+ DECLARE_PCI_UNMAP_ADDR(mapping)
};
struct tg3_config_info {
diff --git a/drivers/net/tokenring/smctr.c b/drivers/net/tokenring/smctr.c
index bbc7fd183399a..c3a33e3858640 100644
--- a/drivers/net/tokenring/smctr.c
+++ b/drivers/net/tokenring/smctr.c
@@ -3718,8 +3718,8 @@ static int __init smctr_probe1(struct net_device *dev, int ioaddr)
}
tp = (struct net_local *)dev->priv;
- dev->rmem_start = dev->mem_start = tp->ram_base;
- dev->rmem_end = dev->mem_end = dev->mem_start + 0x10000;
+ dev->mem_start = tp->ram_base;
+ dev->mem_end = dev->mem_start + 0x10000;
ram = (__u32 *)phys_to_virt(dev->mem_start);
tp->ram_access = *(__u32 *)&ram;
tp->status = NOT_INITIALIZED;
diff --git a/drivers/net/wan/comx-hw-locomx.c b/drivers/net/wan/comx-hw-locomx.c
index 4f73023d6cd69..76e41b5109ad3 100644
--- a/drivers/net/wan/comx-hw-locomx.c
+++ b/drivers/net/wan/comx-hw-locomx.c
@@ -154,12 +154,10 @@ static int LOCOMX_open(struct net_device *dev)
return -ENODEV;
}
- if (check_region(dev->base_addr, hw->io_extent)) {
+ if (!request_region(dev->base_addr, hw->io_extent, dev->name)) {
return -EAGAIN;
}
- request_region(dev->base_addr, hw->io_extent, dev->name);
-
hw->board.chanA.ctrlio=dev->base_addr + 5;
hw->board.chanA.dataio=dev->base_addr + 7;
diff --git a/drivers/net/wan/comx-hw-mixcom.c b/drivers/net/wan/comx-hw-mixcom.c
index 3936d97163e0f..59b3927483388 100644
--- a/drivers/net/wan/comx-hw-mixcom.c
+++ b/drivers/net/wan/comx-hw-mixcom.c
@@ -566,8 +566,6 @@ static int MIXCOM_open(struct net_device *dev)
return 0;
-err_restore_flags:
- restore_flags(flags);
err_release_region:
release_region(dev->base_addr, MIXCOM_IO_EXTENT);
err_ret:
diff --git a/drivers/net/wan/comx-hw-munich.c b/drivers/net/wan/comx-hw-munich.c
index 87b92433b7308..b69c983bcbb8a 100644
--- a/drivers/net/wan/comx-hw-munich.c
+++ b/drivers/net/wan/comx-hw-munich.c
@@ -1397,15 +1397,6 @@ udelay(10000);
return;
}
-void free_stuff(munich_board_t *board, struct comx_channel *ch)
-{
-/* Free CCB and the interrupt queues */
- if (board->ccb) kfree((void *)board->ccb);
- if (board->tiq) kfree((void *)board->tiq);
- if (board->riq) kfree((void *)board->riq);
- if (board->piq) kfree((void *)board->piq);
-}
-
/*
* Hardware open routine.
* Called by comx (upper) layer when the user wants to bring up the interface
@@ -1488,7 +1479,6 @@ static int MUNICH_open(struct net_device *dev)
if (board->tiq == NULL)
{
spin_unlock_irqrestore(&mister_lock, flags);
- free_stuff(board, ch);
return -ENOMEM;
}
memset((void *)board->tiq, 0, MUNICH_INTQSIZE);
@@ -1497,7 +1487,6 @@ static int MUNICH_open(struct net_device *dev)
if (board->riq == NULL)
{
spin_unlock_irqrestore(&mister_lock, flags);
- free_stuff(board, ch);
return -ENOMEM;
}
memset((void *)board->riq, 0, MUNICH_INTQSIZE);
@@ -1506,7 +1495,6 @@ static int MUNICH_open(struct net_device *dev)
if (board->piq == NULL)
{
spin_unlock_irqrestore(&mister_lock, flags);
- free_stuff(board, ch);
return -ENOMEM;
}
memset((void *)board->piq, 0, MUNICH_PIQSIZE);
@@ -1527,7 +1515,6 @@ static int MUNICH_open(struct net_device *dev)
board->pci->irq);
/* TOD: free other resources (a sok malloc feljebb) */
spin_unlock_irqrestore(&mister_lock, flags);
- free_stuff(board, ch);
return -EAGAIN;
}
board->irq = board->pci->irq; /* csak akkor legyen != 0, ha tenyleg le van foglalva nekunk */
@@ -1597,7 +1584,6 @@ static int MUNICH_open(struct net_device *dev)
free_irq(board->irq, (void *)board); /* TOD: free other resources too *//* maybe shut down hw? */
board->irq = 0;
spin_unlock_irqrestore(&mister_lock, flags);
- free_stuff(board, ch);
return -EAGAIN;
}
else if (!(stat & STAT_PCMA))
@@ -1608,7 +1594,6 @@ static int MUNICH_open(struct net_device *dev)
free_irq(board->irq, (void *)board); /* TOD: free other resources too *//* maybe shut off the hw? */
board->irq = 0;
spin_unlock_irqrestore(&mister_lock, flags);
- free_stuff(board, ch);
return -EIO;
}
@@ -1670,7 +1655,7 @@ static int MUNICH_open(struct net_device *dev)
spin_unlock_irqrestore(&mister_lock, flags);
dev->irq = board->irq; /* hogy szep legyen az ifconfig outputja */
- ccb = board->ccb; /* TOD: ez igy csunya egy kicsit hogy benn is meg kinn is beletoltom :( */
+ ccb = board->ccb; /* TODO: ez igy csunya egy kicsit hogy benn is meg kinn is beletoltom :( */
spin_lock_irqsave(&mister_lock, flags);
@@ -1680,13 +1665,12 @@ static int MUNICH_open(struct net_device *dev)
/* Check if the selected timeslots aren't used already */
for (i = 0; i < 32; i++)
- if (((1 << i) & timeslots) && ccb->timeslot_spec[i].tti == 0)
+ if (((1 << i) & timeslots) && !ccb->timeslot_spec[i].tti)
{
printk("MUNICH_open: %s: timeslot %d already used by %s\n",
dev->name, i, board->twins[ccb->timeslot_spec[i].txchannel]->name);
spin_unlock_irqrestore(&mister_lock, flags);
- free_stuff(board, ch);
- return -EBUSY; /* TOD: lehet hogy valami mas errno kellene? */
+ return -EBUSY; /* TODO: lehet hogy valami mas errno kellene? */
}
/* find a free channel: */
@@ -1700,7 +1684,6 @@ static int MUNICH_open(struct net_device *dev)
("MUNICH_open: %s: FATAL: can not find a free channel - this should not happen!\n",
dev->name);
spin_unlock_irqrestore(&mister_lock, flags);
- free_stuff(board, ch);
return -ENODEV;
}
if (board->twins[channel] == NULL)
@@ -1998,7 +1981,7 @@ static int MUNICH_close(struct net_device *dev)
spin_lock_irqsave(&mister_lock, flags);
- board->use_count--;
+ if (board->use_count) board->use_count--;
if (!board->use_count) /* we were the last user of the board */
{
@@ -2020,7 +2003,12 @@ static int MUNICH_close(struct net_device *dev)
free_irq(board->irq, (void *)board); /* Ha nem inicializalta magat, akkor meg nincs irq */
board->irq = 0;
- free_stuff(board, ch);
+ /* Free CCB and the interrupt queues */
+ if (board->ccb) kfree((void *)board->ccb);
+ if (board->tiq) kfree((void *)board->tiq);
+ if (board->riq) kfree((void *)board->riq);
+ if (board->piq) kfree((void *)board->piq);
+ board->ccb = board->tiq = board->riq = board->piq = NULL;
}
/* Enable setting of hw parameters */
diff --git a/drivers/net/wan/cosa.c b/drivers/net/wan/cosa.c
index 883d064de3ec3..30af146bb9724 100644
--- a/drivers/net/wan/cosa.c
+++ b/drivers/net/wan/cosa.c
@@ -105,13 +105,6 @@
#include <net/syncppp.h>
#include "cosa.h"
-/* Linux version stuff */
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,1)
-typedef struct wait_queue *wait_queue_head_t;
-#define DECLARE_WAITQUEUE(wait, current) \
- struct wait_queue wait = { current, NULL }
-#endif
-
/* Maximum length of the identification string. */
#define COSA_MAX_ID_STRING 128
diff --git a/drivers/net/wan/dscc4.c b/drivers/net/wan/dscc4.c
index 991996da0fb14..da81e5390439d 100644
--- a/drivers/net/wan/dscc4.c
+++ b/drivers/net/wan/dscc4.c
@@ -515,8 +515,9 @@ static inline void dscc4_rx_skb(struct dscc4_dev_priv *dpriv, int cur,
stats->rx_bytes += pkt_len;
skb->tail += pkt_len;
skb->len = pkt_len;
- if (netif_running(dev))
+ if (netif_running(dev))
skb->protocol = htons(ETH_P_HDLC);
+ skb->dev->last_rx = jiffies;
netif_rx(skb);
try_get_rx_skb(dpriv, cur, dev);
} else {
diff --git a/drivers/net/wan/hd6457x.c b/drivers/net/wan/hd6457x.c
index 7f8677c62a04e..cd2645791d1ea 100644
--- a/drivers/net/wan/hd6457x.c
+++ b/drivers/net/wan/hd6457x.c
@@ -291,6 +291,7 @@ static inline void sca_rx(card_t *card, port_t *port, pkt_desc *desc, u8 rxin)
#endif
port->hdlc.stats.rx_packets++;
port->hdlc.stats.rx_bytes += skb->len;
+ skb->dev->last_rx = jiffies;
skb->mac.raw = skb->data;
skb->dev = hdlc_to_dev(&port->hdlc);
skb->protocol = htons(ETH_P_HDLC);
diff --git a/drivers/net/wan/sdla_ppp.c b/drivers/net/wan/sdla_ppp.c
index 73a9d033e8c65..f3badbcdf3f68 100644
--- a/drivers/net/wan/sdla_ppp.c
+++ b/drivers/net/wan/sdla_ppp.c
@@ -1463,11 +1463,11 @@ static int tokenize (char *str, char **tokens)
{
int cnt = 0;
- tokens[0] = strtok(str, "/");
+ tokens[0] = strsep(&str, "/");
while (tokens[cnt] && (cnt < 32 - 1))
{
tokens[cnt] = strstrip(tokens[cnt], " \t");
- tokens[++cnt] = strtok(NULL, "/");
+ tokens[++cnt] = strsep(&str, "/");
}
return cnt;
}
diff --git a/drivers/net/wd.c b/drivers/net/wd.c
index b6c5f8701bbee..3f244b70ed394 100644
--- a/drivers/net/wd.c
+++ b/drivers/net/wd.c
@@ -97,7 +97,7 @@ int __init wd_probe(struct net_device *dev)
return -EBUSY;
i = wd_probe1(dev, base_addr);
if (i != 0)
- release_resource(r);
+ release_region(base_addr, WD_IO_EXTENT);
else
r->name = dev->name;
return i;
@@ -114,7 +114,7 @@ int __init wd_probe(struct net_device *dev)
r->name = dev->name;
return 0;
}
- release_resource(r);
+ release_region(ioaddr, WD_IO_EXTENT);
}
return -ENODEV;
@@ -281,7 +281,7 @@ static int __init wd_probe1(struct net_device *dev, int ioaddr)
ei_status.rx_start_page = WD_START_PG + TX_PAGES;
/* Don't map in the shared memory until the board is actually opened. */
- dev->rmem_start = dev->mem_start + TX_PAGES*256;
+ ei_status.rmem_start = dev->mem_start + TX_PAGES*256;
/* Some cards (eg WD8003EBT) can be jumpered for more (32k!) memory. */
if (dev->mem_end != 0) {
@@ -290,7 +290,7 @@ static int __init wd_probe1(struct net_device *dev, int ioaddr)
ei_status.stop_page = word16 ? WD13_STOP_PG : WD03_STOP_PG;
dev->mem_end = dev->mem_start + (ei_status.stop_page - WD_START_PG)*256;
}
- dev->rmem_end = dev->mem_end;
+ ei_status.rmem_end = dev->mem_end;
printk(" %s, IRQ %d, shared memory at %#lx-%#lx.\n",
model_name, dev->irq, dev->mem_start, dev->mem_end-1);
@@ -384,12 +384,12 @@ wd_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_
int wd_cmdreg = dev->base_addr - WD_NIC_OFFSET; /* WD_CMDREG */
unsigned long xfer_start = dev->mem_start + ring_offset - (WD_START_PG<<8);
- if (xfer_start + count > dev->rmem_end) {
+ if (xfer_start + count > ei_status.rmem_end) {
/* We must wrap the input move. */
- int semi_count = dev->rmem_end - xfer_start;
+ int semi_count = ei_status.rmem_end - xfer_start;
isa_memcpy_fromio(skb->data, xfer_start, semi_count);
count -= semi_count;
- isa_memcpy_fromio(skb->data + semi_count, dev->rmem_start, count);
+ isa_memcpy_fromio(skb->data + semi_count, ei_status.rmem_start, count);
} else {
/* Packet is in one chunk -- we can copy + cksum. */
isa_eth_io_copy_and_sum(skb, xfer_start, count, 0);
diff --git a/drivers/net/wireless/orinoco_plx.c b/drivers/net/wireless/orinoco_plx.c
index 9c84936c43adb..0bdd8a952cf71 100644
--- a/drivers/net/wireless/orinoco_plx.c
+++ b/drivers/net/wireless/orinoco_plx.c
@@ -267,21 +267,28 @@ static void __devexit orinoco_plx_remove_one(struct pci_dev *pdev)
pci_set_drvdata(pdev, NULL);
}
-
static struct pci_device_id orinoco_plx_pci_id_table[] __devinitdata = {
- {0x1638, 0x1100, PCI_ANY_ID, PCI_ANY_ID,},
+ {0x1385, 0x4100, PCI_ANY_ID, PCI_ANY_ID,}, /* Netgear MA301 */
+#if 0
+ {0x15e8, 0x0130, PCI_ANY_ID, PCI_ANY_ID,}, /* Correga */
+#endif
+ {0x1638, 0x1100, PCI_ANY_ID, PCI_ANY_ID,}, /* SMC EZConnect SMC2602W,
+ Eumitcom PCI WL11000,
+ Addtron AWA-100*/
+ {0x16ab, 0x1100, PCI_ANY_ID, PCI_ANY_ID,}, /* Global Sun Tech GL24110P */
+ {0x16ab, 0x1101, PCI_ANY_ID, PCI_ANY_ID,}, /* Reported working, but unknown */
+ {0x16ab, 0x1102, PCI_ANY_ID, PCI_ANY_ID,}, /* Linksys WDT11 */
+ {0x16ec, 0x3685, PCI_ANY_ID, PCI_ANY_ID,}, /* USR 2415 */
+ {0xec80, 0xec00, PCI_ANY_ID, PCI_ANY_ID,}, /* Belkin F5D6000 */
{0,},
};
-
MODULE_DEVICE_TABLE(pci, orinoco_plx_pci_id_table);
static struct pci_driver orinoco_plx_driver = {
- name:"orinoco_plx",
- id_table:orinoco_plx_pci_id_table,
- probe:orinoco_plx_init_one,
- remove:__devexit_p(orinoco_plx_remove_one),
- suspend:0,
- resume:0
+ name: "orinoco_plx",
+ id_table: orinoco_plx_pci_id_table,
+ probe: orinoco_plx_init_one,
+ remove: __devexit_p(orinoco_plx_remove_one),
};
static int __init orinoco_plx_init(void)
diff --git a/drivers/parport/parport_mfc3.c b/drivers/parport/parport_mfc3.c
index 41cc106ba7ef2..200a5f378ef45 100644
--- a/drivers/parport/parport_mfc3.c
+++ b/drivers/parport/parport_mfc3.c
@@ -408,6 +408,7 @@ void __exit parport_mfc3_exit(void)
MODULE_AUTHOR("Joerg Dorchain <joerg@dorchain.net>");
MODULE_DESCRIPTION("Parport Driver for Multiface 3 expansion cards Paralllel Port");
MODULE_SUPPORTED_DEVICE("Multiface 3 Parallel Port");
+MODULE_LICENSE("GPL");
module_init(parport_mfc3_init)
module_exit(parport_mfc3_exit)
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index a8fa051737f8d..b9b10a1b4f7a4 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -893,7 +893,7 @@ pci_generic_prep_mwi(struct pci_dev *dev)
#endif /* !HAVE_ARCH_PCI_MWI */
/**
- * pci_set_mwi - enables memory-write-validate PCI transaction
+ * pci_set_mwi - enables memory-write-invalidate PCI transaction
* @dev: the PCI device for which MWI is enabled
*
* Enables the Memory-Write-Invalidate transaction in %PCI_COMMAND,
diff --git a/drivers/pci/pci.ids b/drivers/pci/pci.ids
index 29a97f2b8138c..4d8e32e5b1c42 100644
--- a/drivers/pci/pci.ids
+++ b/drivers/pci/pci.ids
@@ -824,6 +824,7 @@
0074 56k Voice Modem
1033 8014 RCV56ACF 56k Voice Modem
009b Vrc5476
+ 00a6 VRC5477 AC97
00e0 USB 2.0
1034 Framatome Connectors USA Inc.
1035 Comp. & Comm. Research Lab
@@ -1108,12 +1109,14 @@
1059 Teknor Industrial Computers Inc
105a Promise Technology, Inc.
0d30 20265
+ 1275 20275
4d30 20267
4d33 20246
4d38 20262
4d68 20268
6268 20268R
4d69 20269
+ 5275 20276
5300 DC5300
105b Foxconn International, Inc.
105c Wipro Infotech Limited
@@ -1192,11 +1195,21 @@
0017 Paddington Mac I/O
0018 UniNorth FireWire
0019 KeyLargo USB
- 001e UniNorth PCI
+ 001e UniNorth Internal PCI
001f UniNorth PCI
0020 UniNorth AGP
- 0021 UniNorth GMAC
+ 0021 UniNorth GMAC (Sun GEM)
0022 KeyLargo Mac I/O
+ 0024 UniNorth/Pangea GMAC (Sun GEM)
+ 0025 KeyLargo/Pangea Mac I/O
+ 0026 KeyLargo/Pangea USB
+ 0027 UniNorth/Pangea AGP
+ 0028 UniNorth/Pangea PCI
+ 0029 UniNorth/Pangea Internal PCI
+ 002d UniNorth 1.5 AGP
+ 002e UniNorth 1.5 PCI
+ 002f UniNorth 1.5 Internal PCI
+ 0030 UniNorth/Pangea FireWire
106c Hyundai Electronics America
8801 Dual Pentium ISA/PCI Motherboard
8802 PowerPC ISA/PCI Motherboard
@@ -2620,6 +2633,8 @@
0005 ATP850UF
0006 ATP860 NO-BIOS
0007 ATP860
+ 0008 ATP865 NO-ROM
+ 0009 ATP865
8002 AEC6710 SCSI-2 Host Adapter
8010 AEC6712UW SCSI
8020 AEC6712U SCSI
@@ -3965,7 +3980,7 @@
9511 16PCI954 Function 1
15ed 2000 Macrolink MCCR Serial p4-7 of 8
15ed 2001 Macrolink MCCR Serial p4-15 of 16
- 9521 Oxford Semi OX16PCI952 PCI/dual 16950 UART
+ 9521 16PCI952 PCI/dual 16950 UART
1416 Multiwave Innovation pte Ltd
1417 Convergenet Technologies Inc
1418 Kyushu electronics systems Inc
diff --git a/drivers/pcmcia/Config.in b/drivers/pcmcia/Config.in
index ae5294fa23dbb..adb380b855119 100644
--- a/drivers/pcmcia/Config.in
+++ b/drivers/pcmcia/Config.in
@@ -24,6 +24,8 @@ if [ "$CONFIG_PCMCIA" != "n" ]; then
dep_tristate ' HD64465 host bridge support' CONFIG_HD64465_PCMCIA $CONFIG_PCMCIA
fi
fi
-dep_tristate ' SA1100 support' CONFIG_PCMCIA_SA1100 $CONFIG_ARCH_SA1100 $CONFIG_PCMCIA
+if [ "$CONFIG_ARM" = "y" ]; then
+ dep_tristate ' SA1100 support' CONFIG_PCMCIA_SA1100 $CONFIG_ARCH_SA1100 $CONFIG_PCMCIA
+fi
endmenu
diff --git a/drivers/pcmcia/i82092.c b/drivers/pcmcia/i82092.c
index 6f921871df334..2bd40cd6d57a9 100644
--- a/drivers/pcmcia/i82092.c
+++ b/drivers/pcmcia/i82092.c
@@ -43,7 +43,7 @@ static struct pci_driver i82092aa_pci_drv = {
name: "i82092aa",
id_table: i82092aa_pci_ids,
probe: i82092aa_pci_probe,
- remove: i82092aa_pci_remove,
+ remove: __devexit_p(i82092aa_pci_remove),
suspend: NULL,
resume: NULL
};
@@ -168,7 +168,7 @@ err_out_disable:
return ret;
}
-static void __exit i82092aa_pci_remove(struct pci_dev *dev)
+static void __devexit i82092aa_pci_remove(struct pci_dev *dev)
{
enter("i82092aa_pci_remove");
diff --git a/drivers/pnp/pnpbios_core.c b/drivers/pnp/pnpbios_core.c
index 6f2eda9cb3f68..5c39209bb52ba 100644
--- a/drivers/pnp/pnpbios_core.c
+++ b/drivers/pnp/pnpbios_core.c
@@ -4,7 +4,7 @@
* Originally (C) 1998 Christian Schmidt <schmidt@digadd.de>
* Modifications (c) 1998 Tom Lees <tom@lpsg.demon.co.uk>
* Minor reorganizations by David Hinds <dahinds@users.sourceforge.net>
- * Modifications (c) 2001 by Thomas Hood <jdthood@mail.com>
+ * Modifications (c) 2001,2002 by Thomas Hood <jdthood@mail.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
@@ -190,8 +190,8 @@ static inline u16 call_pnp_bios(u16 func, u16 arg1, u16 arg2, u16 arg3,
/* If we get here and this is set then the PnP BIOS faulted on us. */
if(pnp_bios_is_utter_crap)
{
- printk(KERN_ERR "PnPBIOS: Warning! Your PnP BIOS caused a fatal error. Attempting to continue.\n");
- printk(KERN_ERR "PnPBIOS: You may need to reboot with the \"nobiospnp\" option to operate stably.\n");
+ printk(KERN_ERR "PnPBIOS: Warning! Your PnP BIOS caused a fatal error. Attempting to continue\n");
+ printk(KERN_ERR "PnPBIOS: You may need to reboot with the \"nobiospnp\" option to operate stably\n");
printk(KERN_ERR "PnPBIOS: Check with your vendor for an updated BIOS\n");
}
@@ -205,11 +205,16 @@ static inline u16 call_pnp_bios(u16 func, u16 arg1, u16 arg2, u16 arg3,
*
*/
+static void pnpbios_warn_unexpected_status(const char * module, u16 status)
+{
+ printk(KERN_ERR "PnPBIOS: %s: Unexpected status 0x%x\n", module, status);
+}
+
void *pnpbios_kmalloc(size_t size, int f)
{
void *p = kmalloc( size, f );
if ( p == NULL )
- printk(KERN_ERR "PnPBIOS: kmalloc() failed.\n");
+ printk(KERN_ERR "PnPBIOS: kmalloc() failed\n");
return p;
}
@@ -251,7 +256,7 @@ static void update_devlist( u8 nodenum, struct pnp_bios_node *data );
static int __pnp_bios_dev_node_info(struct pnp_dev_node_info *data)
{
u16 status;
- if (!pnp_bios_present ())
+ if (!pnp_bios_present())
return PNP_FUNCTION_NOT_SUPPORTED;
Q2_SET_SEL(PNP_TS1, data, sizeof(struct pnp_dev_node_info));
status = call_pnp_bios(PNP_GET_NUM_SYS_DEV_NODES, 0, PNP_TS1, 2, PNP_TS1, PNP_DS, 0, 0);
@@ -263,7 +268,7 @@ int pnp_bios_dev_node_info(struct pnp_dev_node_info *data)
{
int status = __pnp_bios_dev_node_info( data );
if ( status )
- printk(KERN_WARNING "PnPBIOS: dev_node_info: Unexpected status 0x%x\n", status);
+ pnpbios_warn_unexpected_status( "dev_node_info", status );
return status;
}
@@ -284,7 +289,7 @@ int pnp_bios_dev_node_info(struct pnp_dev_node_info *data)
static int __pnp_bios_get_dev_node(u8 *nodenum, char boot, struct pnp_bios_node *data)
{
u16 status;
- if (!pnp_bios_present ())
+ if (!pnp_bios_present())
return PNP_FUNCTION_NOT_SUPPORTED;
if ( !boot & pnpbios_dont_use_current_config )
return PNP_FUNCTION_NOT_SUPPORTED;
@@ -299,7 +304,7 @@ int pnp_bios_get_dev_node(u8 *nodenum, char boot, struct pnp_bios_node *data)
int status;
status = __pnp_bios_get_dev_node( nodenum, boot, data );
if ( status )
- printk(KERN_WARNING "PnPBIOS: get_dev_node: Unexpected 0x%x\n", status);
+ pnpbios_warn_unexpected_status( "get_dev_node", status );
return status;
}
@@ -313,7 +318,7 @@ int pnp_bios_get_dev_node(u8 *nodenum, char boot, struct pnp_bios_node *data)
static int __pnp_bios_set_dev_node(u8 nodenum, char boot, struct pnp_bios_node *data)
{
u16 status;
- if (!pnp_bios_present ())
+ if (!pnp_bios_present())
return PNP_FUNCTION_NOT_SUPPORTED;
if ( !boot & pnpbios_dont_use_current_config )
return PNP_FUNCTION_NOT_SUPPORTED;
@@ -327,17 +332,14 @@ int pnp_bios_set_dev_node(u8 nodenum, char boot, struct pnp_bios_node *data)
int status;
status = __pnp_bios_set_dev_node( nodenum, boot, data );
if ( status ) {
- printk(KERN_WARNING "PnPBIOS: set_dev_node: Unexpected set_dev_node status 0x%x\n", status);
+ pnpbios_warn_unexpected_status( "set_dev_node", status );
return status;
}
- if ( !boot ) {
- /* Update devlist */
+ if ( !boot ) { /* Update devlist */
u8 thisnodenum = nodenum;
- status = __pnp_bios_get_dev_node( &nodenum, boot, data );
- if ( status ) {
- printk(KERN_WARNING "PnPBIOS: set_dev_node: Unexpected get_dev_node status 0x%x\n", status);
+ status = pnp_bios_get_dev_node( &nodenum, boot, data );
+ if ( status )
return status;
- }
update_devlist( thisnodenum, data );
}
return status;
@@ -350,7 +352,7 @@ int pnp_bios_set_dev_node(u8 nodenum, char boot, struct pnp_bios_node *data)
static int pnp_bios_get_event(u16 *event)
{
u16 status;
- if (!pnp_bios_present ())
+ if (!pnp_bios_present())
return PNP_FUNCTION_NOT_SUPPORTED;
Q2_SET_SEL(PNP_TS1, event, sizeof(u16));
status = call_pnp_bios(PNP_GET_EVENT, 0, PNP_TS1, PNP_DS, 0, 0 ,0 ,0);
@@ -365,7 +367,7 @@ static int pnp_bios_get_event(u16 *event)
static int pnp_bios_send_message(u16 message)
{
u16 status;
- if (!pnp_bios_present ())
+ if (!pnp_bios_present())
return PNP_FUNCTION_NOT_SUPPORTED;
status = call_pnp_bios(PNP_SEND_MESSAGE, message, PNP_DS, 0, 0, 0, 0, 0);
return status;
@@ -379,7 +381,7 @@ static int pnp_bios_send_message(u16 message)
static int pnp_bios_dock_station_info(struct pnp_docking_station_info *data)
{
u16 status;
- if (!pnp_bios_present ())
+ if (!pnp_bios_present())
return PNP_FUNCTION_NOT_SUPPORTED;
Q2_SET_SEL(PNP_TS1, data, sizeof(struct pnp_docking_station_info));
status = call_pnp_bios(PNP_GET_DOCKING_STATION_INFORMATION, 0, PNP_TS1, PNP_DS, 0, 0, 0, 0);
@@ -395,7 +397,7 @@ static int pnp_bios_dock_station_info(struct pnp_docking_station_info *data)
static int pnp_bios_set_stat_res(char *info)
{
u16 status;
- if (!pnp_bios_present ())
+ if (!pnp_bios_present())
return PNP_FUNCTION_NOT_SUPPORTED;
Q2_SET_SEL(PNP_TS1, info, *((u16 *) info));
status = call_pnp_bios(PNP_SET_STATIC_ALLOCED_RES_INFO, 0, PNP_TS1, PNP_DS, 0, 0, 0, 0);
@@ -403,21 +405,28 @@ static int pnp_bios_set_stat_res(char *info)
}
#endif
-#if needed
/*
* Call PnP BIOS with function 0x0a, "get statically allocated resource
* information"
*/
-static int pnp_bios_get_stat_res(char *info)
+static int __pnp_bios_get_stat_res(char *info)
{
u16 status;
- if (!pnp_bios_present ())
+ if (!pnp_bios_present())
return PNP_FUNCTION_NOT_SUPPORTED;
Q2_SET_SEL(PNP_TS1, info, 64 * 1024);
status = call_pnp_bios(PNP_GET_STATIC_ALLOCED_RES_INFO, 0, PNP_TS1, PNP_DS, 0, 0, 0, 0);
return status;
}
-#endif
+
+int pnp_bios_get_stat_res(char *info)
+{
+ int status;
+ status = __pnp_bios_get_stat_res( info );
+ if ( status )
+ pnpbios_warn_unexpected_status( "get_stat_res", status );
+ return status;
+}
#if needed
/*
@@ -426,7 +435,7 @@ static int pnp_bios_get_stat_res(char *info)
static int pnp_bios_apm_id_table(char *table, u16 *size)
{
u16 status;
- if (!pnp_bios_present ())
+ if (!pnp_bios_present())
return PNP_FUNCTION_NOT_SUPPORTED;
Q2_SET_SEL(PNP_TS1, table, *size);
Q2_SET_SEL(PNP_TS2, size, sizeof(u16));
@@ -435,45 +444,58 @@ static int pnp_bios_apm_id_table(char *table, u16 *size)
}
#endif
-#if needed
/*
* Call PnP BIOS with function 0x40, "get isa pnp configuration structure"
*/
-static int pnp_bios_isapnp_config(struct pnp_isa_config_struc *data)
+static int __pnp_bios_isapnp_config(struct pnp_isa_config_struc *data)
{
u16 status;
- if (!pnp_bios_present ())
+ if (!pnp_bios_present())
return PNP_FUNCTION_NOT_SUPPORTED;
Q2_SET_SEL(PNP_TS1, data, sizeof(struct pnp_isa_config_struc));
status = call_pnp_bios(PNP_GET_PNP_ISA_CONFIG_STRUC, 0, PNP_TS1, PNP_DS, 0, 0, 0, 0);
return status;
}
-#endif
-#if needed
+int pnp_bios_isapnp_config(struct pnp_isa_config_struc *data)
+{
+ int status;
+ status = __pnp_bios_isapnp_config( data );
+ if ( status )
+ pnpbios_warn_unexpected_status( "isapnp_config", status );
+ return status;
+}
+
/*
* Call PnP BIOS with function 0x41, "get ESCD info"
*/
-static int pnp_bios_escd_info(struct escd_info_struc *data)
+static int __pnp_bios_escd_info(struct escd_info_struc *data)
{
u16 status;
- if (!pnp_bios_present ())
+ if (!pnp_bios_present())
return ESCD_FUNCTION_NOT_SUPPORTED;
Q2_SET_SEL(PNP_TS1, data, sizeof(struct escd_info_struc));
status = call_pnp_bios(PNP_GET_ESCD_INFO, 0, PNP_TS1, 2, PNP_TS1, 4, PNP_TS1, PNP_DS);
return status;
}
-#endif
-#if needed
+int pnp_bios_escd_info(struct escd_info_struc *data)
+{
+ int status;
+ status = __pnp_bios_escd_info( data );
+ if ( status )
+ pnpbios_warn_unexpected_status( "escd_info", status );
+ return status;
+}
+
/*
* Call PnP BIOS function 0x42, "read ESCD"
* nvram_base is determined by calling escd_info
*/
-static int pnp_bios_read_escd(char *data, u32 nvram_base)
+static int __pnp_bios_read_escd(char *data, u32 nvram_base)
{
u16 status;
- if (!pnp_bios_present ())
+ if (!pnp_bios_present())
return ESCD_FUNCTION_NOT_SUPPORTED;
Q2_SET_SEL(PNP_TS1, data, 64 * 1024);
set_base(gdt[PNP_TS2 >> 3], nvram_base);
@@ -481,7 +503,15 @@ static int pnp_bios_read_escd(char *data, u32 nvram_base)
status = call_pnp_bios(PNP_READ_ESCD, 0, PNP_TS1, PNP_TS2, PNP_DS, 0, 0, 0);
return status;
}
-#endif
+
+int pnp_bios_read_escd(char *data, u32 nvram_base)
+{
+ int status;
+ status = __pnp_bios_read_escd( data, nvram_base );
+ if ( status )
+ pnpbios_warn_unexpected_status( "read_escd", status );
+ return status;
+}
#if needed
/*
@@ -490,7 +520,7 @@ static int pnp_bios_read_escd(char *data, u32 nvram_base)
static int pnp_bios_write_escd(char *data, u32 nvram_base)
{
u16 status;
- if (!pnp_bios_present ())
+ if (!pnp_bios_present())
return ESCD_FUNCTION_NOT_SUPPORTED;
Q2_SET_SEL(PNP_TS1, data, 64 * 1024);
set_base(gdt[PNP_TS2 >> 3], nvram_base);
@@ -574,13 +604,13 @@ static int pnp_dock_event(int dock, struct pnp_docking_station_info *info)
static int pnp_dock_thread(void * unused)
{
static struct pnp_docking_station_info now;
- int docked = -1, d;
+ int docked = -1, d = 0;
daemonize();
reparent_to_init();
- strcpy(current->comm, "kpnpbios");
+ strcpy(current->comm, "kpnpbiosd");
while(!unloading && !signal_pending(current))
{
- int err;
+ int status;
/*
* Poll every 2 seconds
@@ -590,9 +620,9 @@ static int pnp_dock_thread(void * unused)
if(signal_pending(current))
break;
- err = pnp_bios_dock_station_info(&now);
+ status = pnp_bios_dock_station_info(&now);
- switch(err)
+ switch(status)
{
/*
* No dock to manage
@@ -606,7 +636,7 @@ static int pnp_dock_thread(void * unused)
d = 1;
break;
default:
- printk(KERN_WARNING "PnPBIOS: pnp_dock_thread: Unexpected status 0x%x returned by BIOS.\n", err);
+ pnpbios_warn_unexpected_status( "pnp_dock_thread", status );
continue;
}
if(d != docked)
@@ -615,7 +645,7 @@ static int pnp_dock_thread(void * unused)
{
docked = d;
#if 0
- printk(KERN_INFO "PnPBIOS: Docking station %stached.\n", docked?"at":"de");
+ printk(KERN_INFO "PnPBIOS: Docking station %stached\n", docked?"at":"de");
#endif
}
}
@@ -848,15 +878,14 @@ static void inline pnpid32_to_pnpid(u32 id, char *str)
*/
static void __init build_devlist(void)
{
- int i;
- int nodenum;
- int nodes_got = 0;
- int devs = 0;
+ u8 nodenum;
+ unsigned int nodes_got = 0;
+ unsigned int devs = 0;
struct pnp_bios_node *node;
struct pnp_dev_node_info node_info;
struct pci_dev *dev;
- if (!pnp_bios_present ())
+ if (!pnp_bios_present())
return;
if (pnp_bios_dev_node_info(&node_info) != 0)
@@ -866,26 +895,20 @@ static void __init build_devlist(void)
if (!node)
return;
- for(i=0,nodenum=0; i<0xff && nodenum!=0xff; i++) {
- int thisnodenum = nodenum;
- /* For now we build the list from the "boot" config
- * because asking for the "current" config causes
- * some BIOSes to crash. */
- if (pnp_bios_get_dev_node((u8 *)&nodenum, (char )1 , node)) {
- printk(KERN_WARNING "PnPBIOS: PnP BIOS reported error on attempt to get dev node.\n");
- break;
- }
- /* The BIOS returns with nodenum = the next node number */
- if (nodenum < thisnodenum) {
- printk(KERN_WARNING "PnPBIOS: Node number is out of sequence. Naughty BIOS!\n");
+ for(nodenum=0; nodenum<0xff; ) {
+ u8 thisnodenum = nodenum;
+ /* We build the list from the "boot" config because
+ * asking for the "current" config causes some
+ * BIOSes to crash.
+ */
+ if (pnp_bios_get_dev_node(&nodenum, (char )1 , node))
break;
- }
nodes_got++;
dev = pnpbios_kmalloc(sizeof (struct pci_dev), GFP_KERNEL);
if (!dev)
break;
memset(dev,0,sizeof(struct pci_dev));
- dev->devfn=thisnodenum;
+ dev->devfn = thisnodenum;
memcpy(dev->name,"PNPBIOS",8);
pnpid32_to_pnpid(node->eisa_id,dev->slot_name);
node_resource_data_to_dev(node,dev);
@@ -893,10 +916,14 @@ static void __init build_devlist(void)
kfree(dev);
else
devs++;
+ if (nodenum <= thisnodenum) {
+ printk(KERN_ERR "PnPBIOS: build_devlist: Node number 0x%x is out of sequence following node 0x%x. Aborting.\n", (unsigned int)nodenum, (unsigned int)thisnodenum);
+ break;
+ }
}
kfree(node);
- printk(KERN_INFO "PnPBIOS: %i node%s reported by PnP BIOS; %i recorded by driver.\n",
+ printk(KERN_INFO "PnPBIOS: %i node%s reported by PnP BIOS; %i recorded by driver\n",
nodes_got, nodes_got != 1 ? "s" : "", devs);
}
@@ -1062,7 +1089,7 @@ static void __init reserve_ioport_range(char *pnpid, int start, int end)
regionid = pnpbios_kmalloc(16, GFP_KERNEL);
if ( regionid == NULL )
return;
- sprintf(regionid, "PnPBIOS %s", pnpid);
+ snprintf(regionid, 16, "PnPBIOS %s", pnpid);
res = request_region(start,end-start+1,regionid);
if ( res == NULL )
kfree( regionid );
@@ -1074,7 +1101,7 @@ static void __init reserve_ioport_range(char *pnpid, int start, int end)
* have double reservations.
*/
printk(KERN_INFO
- "PnPBIOS: %s: ioport range 0x%x-0x%x %s reserved.\n",
+ "PnPBIOS: %s: ioport range 0x%x-0x%x %s reserved\n",
pnpid, start, end,
NULL != res ? "has been" : "could not be"
);
@@ -1193,14 +1220,14 @@ int __init pnpbios_init(void)
{
union pnp_bios_expansion_header *check;
u8 sum;
- int i, length;
+ int i, length, r;
spin_lock_init(&pnp_bios_lock);
spin_lock_init(&pnpbios_devices_lock);
if(pnpbios_disabled) {
- printk(KERN_INFO "PnPBIOS: Disabled.\n");
- return 0;
+ printk(KERN_INFO "PnPBIOS: Disabled\n");
+ return -ENODEV;
}
if ( is_sony_vaio_laptop )
@@ -1224,13 +1251,13 @@ int __init pnpbios_init(void)
if (sum)
continue;
if (check->fields.version < 0x10) {
- printk(KERN_WARNING "PnPBIOS: PnP BIOS version %d.%d is not supported.\n",
+ printk(KERN_WARNING "PnPBIOS: PnP BIOS version %d.%d is not supported\n",
check->fields.version >> 4,
check->fields.version & 15);
continue;
}
- printk(KERN_INFO "PnPBIOS: Found PnP BIOS installation structure at 0x%p.\n", check);
- printk(KERN_INFO "PnPBIOS: PnP BIOS version %d.%d, entry 0x%x:0x%x, dseg 0x%x.\n",
+ printk(KERN_INFO "PnPBIOS: Found PnP BIOS installation structure at 0x%p\n", check);
+ printk(KERN_INFO "PnPBIOS: PnP BIOS version %d.%d, entry 0x%x:0x%x, dseg 0x%x\n",
check->fields.version >> 4, check->fields.version & 15,
check->fields.pm16cseg, check->fields.pm16offset,
check->fields.pm16dseg);
@@ -1242,12 +1269,21 @@ int __init pnpbios_init(void)
pnp_bios_hdr = check;
break;
}
+ if (!pnp_bios_present())
+ return -ENODEV;
build_devlist();
if ( ! dont_reserve_resources )
reserve_resources();
#ifdef CONFIG_PROC_FS
- pnpbios_proc_init();
+ r = pnpbios_proc_init();
+ if (r)
+ return r;
#endif
+ return 0;
+}
+
+static int __init pnpbios_thread_init(void)
+{
#ifdef CONFIG_HOTPLUG
init_completion(&unload_sem);
if(kernel_thread(pnp_dock_thread, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGNAL)>0)
@@ -1256,23 +1292,46 @@ int __init pnpbios_init(void)
return 0;
}
-#ifdef MODULE
+#ifndef MODULE
+
+/* init/main.c calls pnpbios_init early */
+
+/* Start the kernel thread later: */
+module_init(pnpbios_thread_init);
+
+#else
+
+/*
+ * N.B.: Building pnpbios as a module hasn't been fully implemented
+ */
MODULE_LICENSE("GPL");
-/* We have to run it early and not as a module. */
-module_init(pnpbios_init);
+static int __init pnpbios_init_all(void)
+{
+ int r;
+
+ r = pnpbios_init();
+ if (r)
+ return r;
+ r = pnpbios_thread_init();
+ if (r)
+ return r;
+ return 0;
+}
-#ifdef CONFIG_HOTPLUG
-static void pnpbios_exit(void)
+static void __exit pnpbios_exit(void)
{
- /* free_resources() ought to go here */
- /* pnpbios_proc_done() */
+#ifdef CONFIG_HOTPLUG
unloading = 1;
wait_for_completion(&unload_sem);
+#endif
+ pnpbios_proc_exit();
+ /* We ought to free resources here */
+ return;
}
+module_init(pnpbios_init_all);
module_exit(pnpbios_exit);
#endif
-#endif
diff --git a/drivers/pnp/pnpbios_proc.c b/drivers/pnp/pnpbios_proc.c
index efa39987dc92f..6321c32ed1a38 100644
--- a/drivers/pnp/pnpbios_proc.c
+++ b/drivers/pnp/pnpbios_proc.c
@@ -1,7 +1,21 @@
/*
- * pnp_proc.c: /proc/bus/pnp interface for Plug and Play devices
+ * /proc/bus/pnp interface for Plug and Play devices
*
* Written by David Hinds, dahinds@users.sourceforge.net
+ * Modified by Thomas Hood, jdthood@mail.com
+ *
+ * The .../devices and .../<node> and .../boot/<node> files are
+ * utilized by the lspnp and setpnp utilities, supplied with the
+ * pcmcia-cs package.
+ * http://pcmcia-cs.sourceforge.net
+ *
+ * The .../escd file is utilized by the lsescd utility written by
+ * Gunther Mayer.
+ * http://home.t-online.de/home/gunther.mayer/lsescd
+ *
+ * The .../legacy_device_resources file is not used yet.
+ *
+ * The other files are human-readable.
*/
//#include <pcmcia/config.h>
@@ -19,30 +33,118 @@ static struct proc_dir_entry *proc_pnp = NULL;
static struct proc_dir_entry *proc_pnp_boot = NULL;
static struct pnp_dev_node_info node_info;
+static int proc_read_pnpconfig(char *buf, char **start, off_t pos,
+ int count, int *eof, void *data)
+{
+ struct pnp_isa_config_struc pnps;
+
+ if (pnp_bios_isapnp_config(&pnps))
+ return -EIO;
+ return snprintf(buf, count,
+ "structure_revision %d\n"
+ "number_of_CSNs %d\n"
+ "ISA_read_data_port 0x%x\n",
+ pnps.revision,
+ pnps.no_csns,
+ pnps.isa_rd_data_port
+ );
+}
+
+static int proc_read_escdinfo(char *buf, char **start, off_t pos,
+ int count, int *eof, void *data)
+{
+ struct escd_info_struc escd;
+
+ if (pnp_bios_escd_info(&escd))
+ return -EIO;
+ return snprintf(buf, count,
+ "min_ESCD_write_size %d\n"
+ "ESCD_size %d\n"
+ "NVRAM_base 0x%x\n",
+ escd.min_escd_write_size,
+ escd.escd_size,
+ escd.nv_storage_base
+ );
+}
+
+static int proc_read_escd(char *buf, char **start, off_t pos,
+ int count, int *eof, void *data)
+{
+ struct escd_info_struc escd;
+ char *tmpbuf;
+ int escd_size, escd_left_to_read, n;
+
+ if (pnp_bios_escd_info(&escd))
+ return -EIO;
+
+ /* sanity check */
+ if (escd.escd_size > (32*1024)) {
+ printk(KERN_ERR "PnPBIOS: proc_read_escd: ESCD size is too great\n");
+ return -EFBIG;
+ }
+
+ tmpbuf = pnpbios_kmalloc(escd.escd_size, GFP_KERNEL);
+ if (!tmpbuf) return -ENOMEM;
+
+ if (pnp_bios_read_escd(tmpbuf, escd.nv_storage_base))
+ return -EIO;
+
+ escd_size = (unsigned char)(buf[0]) + (unsigned char)(buf[1])*256;
+ escd_left_to_read = escd_size - pos;
+ if (escd_left_to_read < 0) escd_left_to_read = 0;
+ if (escd_left_to_read == 0) *eof = 1;
+ n = min(count,escd_left_to_read);
+ memcpy(buf, tmpbuf + pos, n);
+ kfree(tmpbuf);
+ *start = buf;
+ return n;
+}
+
+static int proc_read_legacyres(char *buf, char **start, off_t pos,
+ int count, int *eof, void *data)
+{
+ /* Assume that the following won't overflow the buffer */
+ if (pnp_bios_get_stat_res(buf))
+ return -EIO;
+
+ return count; // FIXME: Return actual length
+}
+
static int proc_read_devices(char *buf, char **start, off_t pos,
int count, int *eof, void *data)
{
struct pnp_bios_node *node;
- int i;
u8 nodenum;
char *p = buf;
- if (pos != 0) {
- *eof = 1;
- return 0;
- }
+ if (pos >= 0xff)
+ return 0;
+
node = pnpbios_kmalloc(node_info.max_node_size, GFP_KERNEL);
if (!node) return -ENOMEM;
- for (i=0,nodenum=0;i<0xff && nodenum!=0xff; i++) {
- if ( pnp_bios_get_dev_node(&nodenum, 1, node) )
+
+ for (nodenum=pos; nodenum<0xff; ) {
+ u8 thisnodenum = nodenum;
+ /* 26 = the number of characters per line sprintf'ed */
+ if ((p - buf + 26) > count)
+ break;
+ if (pnp_bios_get_dev_node(&nodenum, 1, node))
break;
p += sprintf(p, "%02x\t%08x\t%02x:%02x:%02x\t%04x\n",
node->handle, node->eisa_id,
node->type_code[0], node->type_code[1],
node->type_code[2], node->flags);
+ if (nodenum <= thisnodenum) {
+ printk(KERN_ERR "%s Node number 0x%x is out of sequence following node 0x%x. Aborting.\n", "PnPBIOS: proc_read_devices:", (unsigned int)nodenum, (unsigned int)thisnodenum);
+ *eof = 1;
+ break;
+ }
}
kfree(node);
- return (p-buf);
+ if (nodenum == 0xff)
+ *eof = 1;
+ *start = (char *)((off_t)nodenum - pos);
+ return p - buf;
}
static int proc_read_node(char *buf, char **start, off_t pos,
@@ -53,13 +155,9 @@ static int proc_read_node(char *buf, char **start, off_t pos,
u8 nodenum = (long)data;
int len;
- if (pos != 0) {
- *eof = 1;
- return 0;
- }
node = pnpbios_kmalloc(node_info.max_node_size, GFP_KERNEL);
if (!node) return -ENOMEM;
- if ( pnp_bios_get_dev_node(&nodenum, boot, node) )
+ if (pnp_bios_get_dev_node(&nodenum, boot, node))
return -EIO;
len = node->size - sizeof(struct pnp_bios_node);
memcpy(buf, node->data, len);
@@ -92,25 +190,34 @@ static int proc_write_node(struct file *file, const char *buf,
* work and the pnpbios_dont_use_current_config flag
* should already have been set to the appropriate value
*/
-void pnpbios_proc_init( void )
+int __init pnpbios_proc_init( void )
{
struct pnp_bios_node *node;
struct proc_dir_entry *ent;
char name[3];
- int i;
u8 nodenum;
- if (pnp_bios_dev_node_info(&node_info) != 0) return;
+ if (pnp_bios_dev_node_info(&node_info))
+ return -EIO;
proc_pnp = proc_mkdir("pnp", proc_bus);
- if (!proc_pnp) return;
+ if (!proc_pnp)
+ return -EIO;
proc_pnp_boot = proc_mkdir("boot", proc_pnp);
- if (!proc_pnp_boot) return;
+ if (!proc_pnp_boot)
+ return -EIO;
create_proc_read_entry("devices", 0, proc_pnp, proc_read_devices, NULL);
+ create_proc_read_entry("configuration_info", 0, proc_pnp, proc_read_pnpconfig, NULL);
+ create_proc_read_entry("escd_info", 0, proc_pnp, proc_read_escdinfo, NULL);
+ create_proc_read_entry("escd", 0, proc_pnp, proc_read_escd, NULL);
+ create_proc_read_entry("legacy_device_resources", 0, proc_pnp, proc_read_legacyres, NULL);
node = pnpbios_kmalloc(node_info.max_node_size, GFP_KERNEL);
- if (!node) return;
- for (i=0,nodenum = 0; i<0xff && nodenum != 0xff; i++) {
+ if (!node)
+ return -ENOMEM;
+
+ for (nodenum=0; nodenum<0xff; ) {
+ u8 thisnodenum = nodenum;
if (pnp_bios_get_dev_node(&nodenum, 1, node) != 0)
break;
sprintf(name, "%02x", node->handle);
@@ -128,11 +235,17 @@ void pnpbios_proc_init( void )
ent->write_proc = proc_write_node;
ent->data = (void *)(long)(node->handle+0x100);
}
+ if (nodenum <= thisnodenum) {
+ printk(KERN_ERR "%s Node number 0x%x is out of sequence following node 0x%x. Aborting.\n", "PnPBIOS: proc_init:", (unsigned int)nodenum, (unsigned int)thisnodenum);
+ break;
+ }
}
kfree(node);
+
+ return 0;
}
-void pnpbios_proc_done(void)
+void __exit pnpbios_proc_exit(void)
{
int i;
char name[3];
@@ -145,7 +258,13 @@ void pnpbios_proc_done(void)
remove_proc_entry(name, proc_pnp);
remove_proc_entry(name, proc_pnp_boot);
}
- remove_proc_entry("boot", proc_pnp);
+ remove_proc_entry("legacy_device_resources", proc_pnp);
+ remove_proc_entry("escd", proc_pnp);
+ remove_proc_entry("escd_info", proc_pnp);
+ remove_proc_entry("configuration_info", proc_pnp);
remove_proc_entry("devices", proc_pnp);
+ remove_proc_entry("boot", proc_pnp);
remove_proc_entry("pnp", proc_bus);
+
+ return;
}
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c
index 1f5259ff728c0..f3b8482517252 100644
--- a/drivers/s390/block/dasd.c
+++ b/drivers/s390/block/dasd.c
@@ -2618,7 +2618,7 @@ dasd_release (struct inode *inp, struct file *filp)
}
count = atomic_dec_return (&device->open_count);
if ( count == 0) {
- invalidate_buffers (inp->i_rdev);
+ invalidate_bdev (inp->i_bdev, 0);
if ( device->discipline->owner )
__MOD_DEC_USE_COUNT(device->discipline->owner);
MOD_DEC_USE_COUNT;
diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h
index bb14996daf661..c0278e300cd8d 100644
--- a/drivers/s390/block/dasd_int.h
+++ b/drivers/s390/block/dasd_int.h
@@ -201,14 +201,14 @@ do {\
debug_sprintf_event(d_device->debug_area,d_level,\
DASD_DEVICE_FORMAT_STRING d_str "\n",\
d_device, d_data);\
-} while(0);
+} while(0)
#define DASD_DEVICE_DEBUG_EXCEPTION(d_level, d_device, d_str, d_data...)\
do {\
if ( d_device->debug_area != NULL )\
debug_sprintf_exception(d_device->debug_area,d_level,\
DASD_DEVICE_FORMAT_STRING d_str "\n",\
d_device, d_data);\
-} while(0);
+} while(0)
#define DASD_DRIVER_FORMAT_STRING "Driver: <[%p]>"
#define DASD_DRIVER_DEBUG_EVENT(d_level, d_fn, d_str, d_data...)\
@@ -217,14 +217,14 @@ do {\
debug_sprintf_event(dasd_debug_area, d_level,\
DASD_DRIVER_FORMAT_STRING #d_fn ":" d_str "\n",\
d_fn, d_data);\
-} while(0);
+} while(0)
#define DASD_DRIVER_DEBUG_EXCEPTION(d_level, d_fn, d_str, d_data...)\
do {\
if ( dasd_debug_area != NULL )\
debug_sprintf_exception(dasd_debug_area, d_level,\
DASD_DRIVER_FORMAT_STRING #d_fn ":" d_str "\n",\
d_fn, d_data);\
-} while(0);
+} while(0)
struct dasd_device_t;
struct request;
diff --git a/drivers/s390/block/xpram.c b/drivers/s390/block/xpram.c
index 7e91ea6b2035a..f494eff5a34de 100644
--- a/drivers/s390/block/xpram.c
+++ b/drivers/s390/block/xpram.c
@@ -655,7 +655,7 @@ int xpram_ioctl (struct inode *inode, struct file *filp,
case BLKFLSBUF: /* flush, 0x1261 */
fsync_bdev(inode->i_bdev);
- if ( capable(CAP_SYS_ADMIN) )invalidate_buffers(inode->i_rdev);
+ if ( capable(CAP_SYS_ADMIN) )invalidate_bdev(inode->i_bdev, 0);
return 0;
case BLKRRPART: /* re-read partition table: can't do it, 0x1259 */
diff --git a/drivers/s390/char/tapeblock.c b/drivers/s390/char/tapeblock.c
index fd186360aa4b0..5053228602e6e 100644
--- a/drivers/s390/char/tapeblock.c
+++ b/drivers/s390/char/tapeblock.c
@@ -217,7 +217,7 @@ tapeblock_release(struct inode *inode, struct file *filp) {
s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
tapestate_set (ti, TS_UNUSED);
s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
- invalidate_buffers(inode->i_rdev);
+ invalidate_bdev(inode->i_bdev, 0);
return 0;
}
diff --git a/drivers/sbus/audio/amd7930.c b/drivers/sbus/audio/amd7930.c
index e2eece1727a17..3f37e962d216c 100644
--- a/drivers/sbus/audio/amd7930.c
+++ b/drivers/sbus/audio/amd7930.c
@@ -1619,7 +1619,6 @@ static int amd7930_attach(struct sparcaudio_driver *drv, int node,
info->irq = irq.pri;
request_irq(info->irq, amd7930_interrupt,
SA_INTERRUPT, "amd7930", drv);
- enable_irq(info->irq);
amd7930_enable_ints(info);
/* Initalize the local copy of the MAP registers. */
@@ -1644,7 +1643,6 @@ static int amd7930_attach(struct sparcaudio_driver *drv, int node,
err = register_sparcaudio_driver(drv, 1);
if (err < 0) {
printk(KERN_ERR "amd7930: unable to register\n");
- disable_irq(info->irq);
free_irq(info->irq, drv);
sbus_iounmap(info->regs, info->regs_size);
kfree(drv->private);
@@ -1666,7 +1664,6 @@ static void __exit amd7930_detach(struct sparcaudio_driver *drv)
unregister_sparcaudio_driver(drv, 1);
amd7930_idle(info);
- disable_irq(info->irq);
free_irq(info->irq, drv);
sbus_iounmap(info->regs, info->regs_size);
kfree(drv->private);
diff --git a/drivers/sbus/audio/cs4231.c b/drivers/sbus/audio/cs4231.c
index 1ec3880f5da85..75d9260582789 100644
--- a/drivers/sbus/audio/cs4231.c
+++ b/drivers/sbus/audio/cs4231.c
@@ -2210,7 +2210,6 @@ static int cs4231_attach(struct sparcaudio_driver *drv,
/* Attach the interrupt handler to the audio interrupt. */
cs4231_chip->irq = sdev->irqs[0];
request_irq(cs4231_chip->irq, cs4231_interrupt, SA_SHIRQ, "cs4231", drv);
- enable_irq(cs4231_chip->irq);
cs4231_chip->nirqs = 1;
cs4231_enable_interrupts(drv);
@@ -2224,7 +2223,6 @@ static int cs4231_attach(struct sparcaudio_driver *drv,
if (err < 0) {
printk(KERN_ERR "cs4231: unable to register\n");
cs4231_disable_interrupts(drv);
- disable_irq(cs4231_chip->irq);
free_irq(cs4231_chip->irq, drv);
sbus_iounmap(cs4231_chip->regs, cs4231_chip->regs_size);
kfree(drv->private);
@@ -2312,9 +2310,7 @@ static int eb4231_attach(struct sparcaudio_driver *drv,
bail:
printk(KERN_ERR "cs4231: unable to register\n");
cs4231_disable_interrupts(drv);
- disable_irq(cs4231_chip->irq);
free_irq(cs4231_chip->irq, drv);
- disable_irq(cs4231_chip->irq2);
free_irq(cs4231_chip->irq2, drv);
kfree(drv->private);
return -EIO;
@@ -2371,7 +2367,6 @@ static void __exit cs4231_detach(struct sparcaudio_driver *drv)
cs4231_disable_interrupts(drv);
unregister_sparcaudio_driver(drv, 1);
- disable_irq(cs4231_chip->irq);
free_irq(cs4231_chip->irq, drv);
if (!(cs4231_chip->status & CS_STATUS_IS_EBUS)) {
sbus_iounmap(cs4231_chip->regs, cs4231_chip->regs_size);
@@ -2380,7 +2375,6 @@ static void __exit cs4231_detach(struct sparcaudio_driver *drv)
iounmap(cs4231_chip->regs);
iounmap(cs4231_chip->eb2p);
iounmap(cs4231_chip->eb2c);
- disable_irq(cs4231_chip->irq2);
free_irq(cs4231_chip->irq2, drv);
#endif
}
diff --git a/drivers/sbus/char/aurora.c b/drivers/sbus/char/aurora.c
index 86b08d5cb8272..cc89c4c54c38d 100644
--- a/drivers/sbus/char/aurora.c
+++ b/drivers/sbus/char/aurora.c
@@ -179,7 +179,7 @@ extern inline void aurora_long_delay(unsigned long delay)
#ifdef AURORA_DEBUG
printk("aurora_long_delay: start\n");
#endif
- for (i = jiffies + delay; i > jiffies; ) ;
+ for (i = jiffies + delay; time_before(jiffies, i); ) ;
#ifdef AURORA_DEBUG
printk("aurora_long_delay: end\n");
#endif
diff --git a/drivers/sbus/char/uctrl.c b/drivers/sbus/char/uctrl.c
index f3a2713d8fa1b..b1571efa47ce0 100644
--- a/drivers/sbus/char/uctrl.c
+++ b/drivers/sbus/char/uctrl.c
@@ -389,15 +389,11 @@ static int __init ts102_uctrl_init(void)
if(!driver->irq)
driver->irq = tmp_irq[0].pri;
- request_irq(driver->irq, uctrl_interrupt, 0,
- "uctrl", driver);
-
- enable_irq(driver->irq);
+ request_irq(driver->irq, uctrl_interrupt, 0, "uctrl", driver);
if (misc_register(&uctrl_dev)) {
printk("%s: unable to get misc minor %d\n",
__FUNCTION__, uctrl_dev.minor);
- disable_irq(driver->irq);
free_irq(driver->irq, driver);
return -ENODEV;
}
@@ -414,10 +410,8 @@ static void __exit ts102_uctrl_cleanup(void)
struct uctrl_driver *driver = &drv;
misc_deregister(&uctrl_dev);
- if (driver->irq) {
- disable_irq(driver->irq);
+ if (driver->irq)
free_irq(driver->irq, driver);
- }
if (driver->regs)
driver->regs = 0;
}
diff --git a/drivers/sbus/sbus.c b/drivers/sbus/sbus.c
index 89a4cc2f9a7e7..8fd7d45522abf 100644
--- a/drivers/sbus/sbus.c
+++ b/drivers/sbus/sbus.c
@@ -392,6 +392,10 @@ static int __init sbus_init(void)
sbus_bus_ranges_init(iommund, sbus);
sbus_devs = prom_getchild(this_sbus);
+ if (!sbus_devs) {
+ sbus->devices = NULL;
+ goto next_bus;
+ }
sbus->devices = kmalloc(sizeof(struct sbus_dev), GFP_ATOMIC);
@@ -455,7 +459,7 @@ static int __init sbus_init(void)
sbus_fixup_all_regs(sbus->devices);
dvma_init(sbus);
-
+ next_bus:
num_sbus++;
if(sparc_cpu_model == sun4u) {
this_sbus = prom_getsibling(this_sbus);
diff --git a/drivers/scsi/3w-xxxx.c b/drivers/scsi/3w-xxxx.c
index 4b02451d2877a..c7ccb6c0ad21b 100644
--- a/drivers/scsi/3w-xxxx.c
+++ b/drivers/scsi/3w-xxxx.c
@@ -133,6 +133,14 @@
some SMP systems.
1.02.00.020 - Add pci_set_dma_mask(), rewrite kmalloc()/virt_to_bus() to
pci_alloc/free_consistent().
+ Better alignment checking in tw_allocate_memory().
+ Cleanup tw_initialize_device_extension().
+ 1.02.00.021 - Bump cmd_per_lun in SHT to 255 for better jbod performance.
+ Improve handling of errors in tw_interrupt().
+ Add handling/clearing of controller queue error.
+ Empty stale responses before draining aen queue.
+ Fix tw_scsi_eh_abort() to not reset on every io abort.
+ Set can_queue in SHT to 255 to prevent hang from AEN.
*/
#include <linux/module.h>
@@ -182,7 +190,7 @@ static struct notifier_block tw_notifier = {
};
/* Globals */
-char *tw_driver_version="1.02.00.020";
+char *tw_driver_version="1.02.00.021";
TW_Device_Extension *tw_device_extension_list[TW_MAX_SLOT];
int tw_device_extension_count = 0;
@@ -284,6 +292,9 @@ int tw_aen_drain_queue(TW_Device_Extension *tw_dev)
}
tw_clear_attention_interrupt(tw_dev);
+ /* Empty response queue */
+ tw_empty_response_que(tw_dev);
+
/* Initialize command packet */
if (tw_dev->command_packet_virtual_address[request_id] == NULL) {
printk(KERN_WARNING "3w-xxxx: tw_aen_drain_queue(): Bad command packet virtual address.\n");
@@ -337,7 +348,7 @@ int tw_aen_drain_queue(TW_Device_Extension *tw_dev)
status_reg_value = inl(status_reg_addr);
if (tw_check_bits(status_reg_value)) {
dprintk(KERN_WARNING "3w-xxxx: tw_aen_drain_queue(): Unexpected bits.\n");
- tw_decode_bits(tw_dev, status_reg_value);
+ tw_decode_bits(tw_dev, status_reg_value, 0);
return 1;
}
if ((status_reg_value & TW_STATUS_RESPONSE_QUEUE_EMPTY) == 0) {
@@ -451,7 +462,7 @@ int tw_aen_read_queue(TW_Device_Extension *tw_dev, int request_id)
status_reg_value = inl(status_reg_addr);
if (tw_check_bits(status_reg_value)) {
dprintk(KERN_WARNING "3w-xxxx: tw_aen_read_queue(): Unexpected bits.\n");
- tw_decode_bits(tw_dev, status_reg_value);
+ tw_decode_bits(tw_dev, status_reg_value, 1);
return 1;
}
if (tw_dev->command_packet_virtual_address[request_id] == NULL) {
@@ -571,13 +582,23 @@ int tw_check_errors(TW_Device_Extension *tw_dev)
status_reg_value = inl(status_reg_addr);
if (TW_STATUS_ERRORS(status_reg_value) || tw_check_bits(status_reg_value)) {
- tw_decode_bits(tw_dev, status_reg_value);
+ tw_decode_bits(tw_dev, status_reg_value, 0);
return 1;
}
return 0;
} /* End tw_check_errors() */
+/* This function will clear all interrupts on the controller */
+void tw_clear_all_interrupts(TW_Device_Extension *tw_dev)
+{
+ u32 control_reg_addr, control_reg_value;
+
+ control_reg_addr = tw_dev->registers.control_reg_addr;
+ control_reg_value = TW_STATUS_VALID_INTERRUPT;
+ outl(control_reg_value, control_reg_addr);
+} /* End tw_clear_all_interrupts() */
+
/* This function will clear the attention interrupt */
void tw_clear_attention_interrupt(TW_Device_Extension *tw_dev)
{
@@ -632,30 +653,51 @@ static void tw_copy_mem_info(TW_Info *info, char *data, int len)
}
} /* End tw_copy_mem_info() */
-/* This function will print readable messages from statsu register errors */
-void tw_decode_bits(TW_Device_Extension *tw_dev, u32 status_reg_value)
+/* This function will print readable messages from status register errors */
+int tw_decode_bits(TW_Device_Extension *tw_dev, u32 status_reg_value, int print_host)
{
+ char host[16];
+
dprintk(KERN_WARNING "3w-xxxx: tw_decode_bits()\n");
+
+ if (print_host)
+ sprintf(host, " scsi%d:", tw_dev->host->host_no);
+ else
+ host[0] = '\0';
+
switch (status_reg_value & TW_STATUS_UNEXPECTED_BITS) {
case TW_STATUS_PCI_PARITY_ERROR:
- printk(KERN_WARNING "3w-xxxx: PCI Parity Error: clearing.\n");
+ printk(KERN_WARNING "3w-xxxx:%s PCI Parity Error: clearing.\n", host);
outl(TW_CONTROL_CLEAR_PARITY_ERROR, tw_dev->registers.control_reg_addr);
break;
case TW_STATUS_MICROCONTROLLER_ERROR:
- printk(KERN_WARNING "3w-xxxx: Microcontroller Error.\n");
- break;
+ if (tw_dev->reset_print == 0) {
+ printk(KERN_WARNING "3w-xxxx:%s Microcontroller Error: clearing.\n", host);
+ tw_dev->reset_print = 1;
+ }
+ return 1;
case TW_STATUS_PCI_ABORT:
- printk(KERN_WARNING "3w-xxxx: PCI Abort: clearing.\n");
+ printk(KERN_WARNING "3w-xxxx:%s PCI Abort: clearing.\n", host);
outl(TW_CONTROL_CLEAR_PCI_ABORT, tw_dev->registers.control_reg_addr);
pci_write_config_word(tw_dev->tw_pci_dev, PCI_STATUS, TW_PCI_CLEAR_PCI_ABORT);
break;
- }
+ case TW_STATUS_QUEUE_ERROR:
+ printk(KERN_WARNING "3w-xxxx:%s Controller Queue Error: clearing.\n", host);
+ outl(TW_CONTROL_CLEAR_QUEUE_ERROR, tw_dev->registers.control_reg_addr);
+ break;
+ case TW_STATUS_SBUF_WRITE_ERROR:
+ printk(KERN_WARNING "3w-xxxx:%s SBUF Write Error: clearing.\n", host);
+ outl(TW_CONTROL_CLEAR_SBUF_WRITE_ERROR, tw_dev->registers.control_reg_addr);
+ break;
+ }
+
+ return 0;
} /* End tw_decode_bits() */
/* This function will return valid sense buffer information for failed cmds */
-void tw_decode_sense(TW_Device_Extension *tw_dev, int request_id, int fill_sense)
+int tw_decode_sense(TW_Device_Extension *tw_dev, int request_id, int fill_sense)
{
- int i, found=0;
+ int i;
TW_Command *command;
dprintk(KERN_WARNING "3w-xxxx: tw_decode_sense()\n");
@@ -668,7 +710,6 @@ void tw_decode_sense(TW_Device_Extension *tw_dev, int request_id, int fill_sense
if ((command->status == 0xc7) || (command->status == 0xcb)) {
for (i=0;i<(sizeof(tw_sense_table)/sizeof(tw_sense_table[0]));i++) {
if (command->flags == tw_sense_table[i][0]) {
- found=1;
/* Valid bit and 'current errors' */
tw_dev->srb[request_id]->sense_buffer[0] = (0x1 << 7 | 0x70);
@@ -686,13 +727,16 @@ void tw_decode_sense(TW_Device_Extension *tw_dev, int request_id, int fill_sense
tw_dev->srb[request_id]->sense_buffer[13] = tw_sense_table[i][3];
tw_dev->srb[request_id]->result = (DID_OK << 16) | (CHECK_CONDITION << 1);
+ return TW_ISR_DONT_RESULT; /* Special case for isr to not over-write result */
}
}
}
+
/* If no table match, error so we get a reset */
- if (found == 0)
- tw_dev->srb[request_id]->result = (DID_RESET << 16);
+ return 1;
}
+
+ return 0;
} /* End tw_decode_sense() */
/* This function will disable interrupts on the controller */
@@ -706,7 +750,7 @@ void tw_disable_interrupts(TW_Device_Extension *tw_dev)
} /* End tw_disable_interrupts() */
/* This function will empty the response que */
-int tw_empty_response_que(TW_Device_Extension *tw_dev)
+void tw_empty_response_que(TW_Device_Extension *tw_dev)
{
u32 status_reg_addr, status_reg_value;
u32 response_que_addr, response_que_value;
@@ -716,22 +760,10 @@ int tw_empty_response_que(TW_Device_Extension *tw_dev)
status_reg_value = inl(status_reg_addr);
- if (tw_check_bits(status_reg_value)) {
- dprintk(KERN_WARNING "3w-xxxx: tw_empty_response_queue(): Unexpected bits 1.\n");
- tw_decode_bits(tw_dev, status_reg_value);
- return 1;
- }
-
while ((status_reg_value & TW_STATUS_RESPONSE_QUEUE_EMPTY) == 0) {
response_que_value = inl(response_que_addr);
status_reg_value = inl(status_reg_addr);
- if (tw_check_bits(status_reg_value)) {
- dprintk(KERN_WARNING "3w-xxxx: tw_empty_response_queue(): Unexpected bits 2.\n");
- tw_decode_bits(tw_dev, status_reg_value);
- return 1;
- }
}
- return 0;
} /* End tw_empty_response_que() */
/* This function will enable interrupts on the controller */
@@ -811,8 +843,8 @@ int tw_findcards(Scsi_Host_Template *tw_host)
/* Check for errors and clear them */
status_reg_value = inl(tw_dev->registers.status_reg_addr);
- if (TW_STATUS_ERRORS(status_reg_value))
- tw_decode_bits(tw_dev, status_reg_value);
+ if (TW_STATUS_ERRORS(status_reg_value))
+ tw_decode_bits(tw_dev, status_reg_value, 0);
/* Poll status register for 60 secs for 'Controller Ready' flag */
if (tw_poll_status(tw_dev, TW_STATUS_MICROCONTROLLER_READY, 60)) {
@@ -843,14 +875,6 @@ int tw_findcards(Scsi_Host_Template *tw_host)
continue;
}
- /* Empty the response queue */
- error = tw_empty_response_que(tw_dev);
- if (error) {
- printk(KERN_WARNING "3w-xxxx: Couldn't empty response queue, retrying for card %d.\n", numcards);
- tries++;
- continue;
- }
-
/* Now the controller is in a good state */
break;
}
@@ -877,7 +901,7 @@ int tw_findcards(Scsi_Host_Template *tw_host)
request_region((tw_dev->tw_pci_dev->resource[0].start), TW_IO_ADDRESS_RANGE, TW_DEVICE_NAME);
error = tw_initialize_units(tw_dev);
if (error) {
- printk(KERN_WARNING "3w-xxxx: tw_findcards(): Couldn't initialize units for card %d.\n", numcards);
+ printk(KERN_WARNING "3w-xxxx: No valid units for for card %d.\n", numcards);
release_region((tw_dev->tw_pci_dev->resource[0].start), TW_IO_ADDRESS_RANGE);
tw_free_device_extension(tw_dev);
kfree(tw_dev);
@@ -895,7 +919,7 @@ int tw_findcards(Scsi_Host_Template *tw_host)
/* Calculate max cmds per lun, and setup queues */
if (tw_dev->num_units > 0) {
- tw_host->cmd_per_lun = (TW_Q_LENGTH-1)/tw_dev->num_units;
+ /* Use SHT cmd_per_lun here */
tw_dev->free_head = TW_Q_START;
tw_dev->free_tail = TW_Q_LENGTH - 1;
tw_dev->free_wrap = TW_Q_LENGTH - 1;
@@ -1064,7 +1088,7 @@ int tw_initconnection(TW_Device_Extension *tw_dev, int message_credits)
status_reg_value = inl(status_reg_addr);
if (tw_check_bits(status_reg_value)) {
dprintk(KERN_WARNING "3w-xxxx: tw_initconnection(): Unexpected bits.\n");
- tw_decode_bits(tw_dev, status_reg_value);
+ tw_decode_bits(tw_dev, status_reg_value, 0);
return 1;
}
if ((status_reg_value & TW_STATUS_RESPONSE_QUEUE_EMPTY) == 0) {
@@ -1191,7 +1215,7 @@ int tw_initialize_units(TW_Device_Extension *tw_dev)
status_reg_value = inl(status_reg_addr);
if (tw_check_bits(status_reg_value)) {
dprintk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Unexpected bits.\n");
- tw_decode_bits(tw_dev, status_reg_value);
+ tw_decode_bits(tw_dev, status_reg_value, 0);
return 1;
}
if ((status_reg_value & TW_STATUS_RESPONSE_QUEUE_EMPTY) == 0) {
@@ -1251,51 +1275,52 @@ static void tw_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
u32 response_que_addr;
TW_Device_Extension *tw_dev = (TW_Device_Extension *)dev_instance;
TW_Response_Queue response_que;
- int error = 0;
- int do_response_interrupt=0;
- int do_attention_interrupt=0;
- int do_host_interrupt=0;
- int do_command_interrupt=0;
+ int error = 0, retval = 0;
unsigned long flags = 0;
TW_Command *command_packet;
+
+ dprintk(KERN_WARNING "3w-xxxx: tw_interrupt()\n");
+
+ /* See if we are already running on another processor */
if (test_and_set_bit(TW_IN_INTR, &tw_dev->flags))
return;
+
+ /* Get the host lock for io completions */
spin_lock_irqsave(tw_dev->host->host_lock, flags);
+ /* See if the interrupt matches this instance */
if (tw_dev->tw_pci_dev->irq == irq) {
+
+ /* Make sure io isn't queueing */
spin_lock(&tw_dev->tw_lock);
- dprintk(KERN_WARNING "3w-xxxx: tw_interrupt()\n");
/* Read the registers */
status_reg_addr = tw_dev->registers.status_reg_addr;
response_que_addr = tw_dev->registers.response_que_addr;
status_reg_value = inl(status_reg_addr);
+ /* Check if this is our interrupt, otherwise bail */
+ if (!(status_reg_value & TW_STATUS_VALID_INTERRUPT))
+ goto tw_interrupt_bail;
+
+ /* Check controller for errors */
if (tw_check_bits(status_reg_value)) {
dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Unexpected bits.\n");
- tw_decode_bits(tw_dev, status_reg_value);
+ if (tw_decode_bits(tw_dev, status_reg_value, 1)) {
+ tw_clear_all_interrupts(tw_dev);
+ goto tw_interrupt_bail;
+ }
}
- /* Check which interrupt */
- if (status_reg_value & TW_STATUS_HOST_INTERRUPT)
- do_host_interrupt=1;
- if (status_reg_value & TW_STATUS_ATTENTION_INTERRUPT)
- do_attention_interrupt=1;
- if (status_reg_value & TW_STATUS_COMMAND_INTERRUPT)
- do_command_interrupt=1;
- if (status_reg_value & TW_STATUS_RESPONSE_INTERRUPT)
- do_response_interrupt=1;
-
/* Handle host interrupt */
- if (do_host_interrupt) {
+ if (status_reg_value & TW_STATUS_HOST_INTERRUPT) {
dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): Received host interrupt.\n");
tw_clear_host_interrupt(tw_dev);
}
/* Handle attention interrupt */
- if (do_attention_interrupt) {
+ if (status_reg_value & TW_STATUS_ATTENTION_INTERRUPT) {
dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): Received attention interrupt.\n");
- dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Clearing attention interrupt.\n");
tw_clear_attention_interrupt(tw_dev);
tw_state_request_start(tw_dev, &request_id);
error = tw_aen_read_queue(tw_dev, request_id);
@@ -1307,7 +1332,7 @@ static void tw_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
}
/* Handle command interrupt */
- if (do_command_interrupt) {
+ if (status_reg_value & TW_STATUS_COMMAND_INTERRUPT) {
/* Drain as many pending commands as we can */
while (tw_dev->pending_request_count > 0) {
request_id = tw_dev->pending_queue[tw_dev->pending_head];
@@ -1323,6 +1348,7 @@ static void tw_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
}
tw_dev->pending_request_count--;
} else {
+ printk(KERN_WARNING "3w-xxxx: scsi%d: Error posting pending commands.\n", tw_dev->host->host_no);
break;
}
}
@@ -1332,40 +1358,40 @@ static void tw_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
}
/* Handle response interrupt */
- if (do_response_interrupt) {
+ if (status_reg_value & TW_STATUS_RESPONSE_INTERRUPT) {
/* Drain the response queue from the board */
while ((status_reg_value & TW_STATUS_RESPONSE_QUEUE_EMPTY) == 0) {
+ /* Read response queue register */
response_que.value = inl(response_que_addr);
request_id = response_que.u.response_id;
command_packet = (TW_Command *)tw_dev->command_packet_virtual_address[request_id];
error = 0;
+
+ /* Check for bad response */
if (command_packet->status != 0) {
- /* Bad response */
- if (tw_dev->srb[request_id] != 0)
- tw_decode_sense(tw_dev, request_id, 1);
- error = 3;
+ /* If internal command, don't error, don't fill sense */
+ if (tw_dev->srb[request_id] == 0) {
+ tw_decode_sense(tw_dev, request_id, 0);
+ } else {
+ error = tw_decode_sense(tw_dev, request_id, 1);
+ }
}
+
+ /* Check for correct state */
if (tw_dev->state[request_id] != TW_S_POSTED) {
printk(KERN_WARNING "3w-xxxx: scsi%d: Received a request id (%d) (opcode = 0x%x) that wasn't posted.\n", tw_dev->host->host_no, request_id, command_packet->byte0.opcode);
error = 1;
}
- if (TW_STATUS_ERRORS(status_reg_value)) {
- tw_decode_bits(tw_dev, status_reg_value);
- error = 1;
- }
+
dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): Response queue request id: %d.\n", request_id);
- /* Check for internal command */
+
+ /* Check for internal command completion */
if (tw_dev->srb[request_id] == 0) {
dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Found internally posted command.\n");
- error = tw_aen_complete(tw_dev, request_id);
- if (error) {
+ retval = tw_aen_complete(tw_dev, request_id);
+ if (retval) {
printk(KERN_WARNING "3w-xxxx: scsi%d: Error completing aen.\n", tw_dev->host->host_no);
}
- status_reg_value = inl(status_reg_addr);
- if (tw_check_bits(status_reg_value)) {
- dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Unexpected bits.\n");
- tw_decode_bits(tw_dev, status_reg_value);
- }
} else {
switch (tw_dev->srb[request_id]->cmnd[0]) {
case READ_10:
@@ -1389,20 +1415,22 @@ static void tw_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
error = tw_ioctl_complete(tw_dev, request_id);
break;
default:
- printk(KERN_WARNING "3w-xxxx: scsi%d: Unknown scsi opcode: 0x%x.\n", tw_dev->host->host_no, tw_dev->srb[request_id]->cmnd[0]);
- tw_dev->srb[request_id]->result = (DID_BAD_TARGET << 16);
- tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]);
- }
- if (error == 1) {
- /* Tell scsi layer there was an error */
- dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Scsi Error.\n");
- tw_dev->srb[request_id]->result = (DID_RESET << 16);
+ printk(KERN_WARNING "3w-xxxx: case slip in tw_interrupt()\n");
+ error = 1;
}
+
+ /* If no error command was a success */
if (error == 0) {
- /* Tell scsi layer command was a success */
tw_dev->srb[request_id]->result = (DID_OK << 16);
}
- if (error != 2) {
+
+ /* If error, command failed */
+ if (error == 1) {
+ tw_dev->srb[request_id]->result = (DID_RESET << 16);
+ }
+
+ /* Now complete the io */
+ if ((error != TW_ISR_DONT_COMPLETE)) {
tw_dev->state[request_id] = TW_S_COMPLETED;
tw_state_request_finish(tw_dev, request_id);
tw_dev->posted_request_count--;
@@ -1410,16 +1438,24 @@ static void tw_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
tw_unmap_scsi_data(tw_dev->tw_pci_dev, tw_dev->srb[request_id]);
}
- status_reg_value = inl(status_reg_addr);
- if (tw_check_bits(status_reg_value)) {
- dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Unexpected bits.\n");
- tw_decode_bits(tw_dev, status_reg_value);
+ }
+
+ /* Check for valid status after each drain */
+ status_reg_value = inl(status_reg_addr);
+ if (tw_check_bits(status_reg_value)) {
+ dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Unexpected bits.\n");
+ if (tw_decode_bits(tw_dev, status_reg_value, 1)) {
+ tw_clear_all_interrupts(tw_dev);
+ goto tw_interrupt_bail;
}
}
}
}
+tw_interrupt_bail:
spin_unlock(&tw_dev->tw_lock);
- }
+ } else
+ dprintk(KERN_WARNING "3w-xxxx: tw_interrupt() called for wrong instance.\n");
+
spin_unlock_irqrestore(tw_dev->host->host_lock, flags);
clear_bit(TW_IN_INTR, &tw_dev->flags);
} /* End tw_interrupt() */
@@ -1782,7 +1818,7 @@ int tw_ioctl_complete(TW_Device_Extension *tw_dev, int request_id)
break;
case TW_CMD_PACKET_WITH_DATA:
dprintk(KERN_WARNING "3w-xxxx: tw_ioctl_complete(): caught TW_CMD_PACKET_WITH_DATA.\n");
- return 2; /* Special case for isr to not complete io */
+ return TW_ISR_DONT_COMPLETE; /* Special case for isr to not complete io */
default:
memset(buff, 0, tw_dev->srb[request_id]->request_bufflen);
param = (TW_Param *)tw_dev->alignment_virtual_address[request_id];
@@ -1852,7 +1888,7 @@ int tw_poll_status(TW_Device_Extension *tw_dev, u32 flag, int seconds)
if (tw_check_bits(status_reg_value)) {
dprintk(KERN_WARNING "3w-xxxx: tw_poll_status(): Unexpected bits.\n");
- tw_decode_bits(tw_dev, status_reg_value);
+ tw_decode_bits(tw_dev, status_reg_value, 0);
}
while ((status_reg_value & flag) != flag) {
@@ -1860,7 +1896,7 @@ int tw_poll_status(TW_Device_Extension *tw_dev, u32 flag, int seconds)
if (tw_check_bits(status_reg_value)) {
dprintk(KERN_WARNING "3w-xxxx: tw_poll_status(): Unexpected bits.\n");
- tw_decode_bits(tw_dev, status_reg_value);
+ tw_decode_bits(tw_dev, status_reg_value, 0);
}
do_gettimeofday(&timeout);
@@ -1887,7 +1923,7 @@ int tw_post_command_packet(TW_Device_Extension *tw_dev, int request_id)
if (tw_check_bits(status_reg_value)) {
dprintk(KERN_WARNING "3w-xxxx: tw_post_command_packet(): Unexpected bits.\n");
- tw_decode_bits(tw_dev, status_reg_value);
+ tw_decode_bits(tw_dev, status_reg_value, 1);
}
if ((status_reg_value & TW_STATUS_COMMAND_QUEUE_FULL) == 0) {
@@ -1941,7 +1977,6 @@ int tw_reset_device_extension(TW_Device_Extension *tw_dev)
(tw_dev->state[i] != TW_S_COMPLETED)) {
srb = tw_dev->srb[i];
if (srb != NULL) {
- srb = tw_dev->srb[i];
srb->result = (DID_RESET << 16);
tw_dev->srb[i]->scsi_done(tw_dev->srb[i]);
tw_unmap_scsi_data(tw_dev->tw_pci_dev, tw_dev->srb[i]);
@@ -1960,6 +1995,7 @@ int tw_reset_device_extension(TW_Device_Extension *tw_dev)
tw_dev->pending_request_count = 0;
tw_dev->pending_head = TW_Q_START;
tw_dev->pending_tail = TW_Q_START;
+ tw_dev->reset_print = 0;
return 0;
} /* End tw_reset_device_extension() */
@@ -1991,14 +2027,6 @@ int tw_reset_sequence(TW_Device_Extension *tw_dev)
continue;
}
- /* Empty the response queue again */
- error = tw_empty_response_que(tw_dev);
- if (error) {
- printk(KERN_WARNING "3w-xxxx: scsi%d: Couldn't empty response queue, retrying.\n", tw_dev->host->host_no);
- tries++;
- continue;
- }
-
/* Now the controller is in a good state */
break;
}
@@ -2086,11 +2114,6 @@ int tw_scsi_eh_abort(Scsi_Cmnd *SCpnt)
return (FAILED);
}
- /* We have to let AEN requests through before the reset */
- spin_unlock_irq(tw_dev->host->host_lock);
- mdelay(TW_AEN_WAIT_TIME);
- spin_lock_irq(tw_dev->host->host_lock);
-
spin_lock(&tw_dev->tw_lock);
tw_dev->num_aborts++;
@@ -2117,18 +2140,26 @@ int tw_scsi_eh_abort(Scsi_Cmnd *SCpnt)
spin_unlock(&tw_dev->tw_lock);
return (SUCCESS);
}
+ if (tw_dev->state[i] == TW_S_POSTED) {
+ /* If the command has already been posted, we have to reset the card */
+ printk(KERN_WARNING "3w-xxxx: scsi%d: Command (0x%x) timed out, resetting card.\n", tw_dev->host->host_no, (u32)SCpnt);
+ /* We have to let AEN requests through before the reset */
+ spin_unlock(&tw_dev->tw_lock);
+ spin_unlock_irq(tw_dev->host->host_lock);
+ mdelay(TW_AEN_WAIT_TIME);
+ spin_lock_irq(tw_dev->host->host_lock);
+ spin_lock(&tw_dev->tw_lock);
+
+ if (tw_reset_device_extension(tw_dev)) {
+ dprintk(KERN_WARNING "3w-xxxx: tw_scsi_eh_abort(): Reset failed for card %d.\n", tw_dev->host->host_no);
+ spin_unlock(&tw_dev->tw_lock);
+ return (FAILED);
+ }
+ }
}
}
- /* If the command has already been posted, we have to reset the card */
- printk(KERN_WARNING "3w-xxxx: scsi%d: Command (0x%x) timed out, resetting card.\n", tw_dev->host->host_no, (u32)SCpnt);
- if (tw_reset_device_extension(tw_dev)) {
- dprintk(KERN_WARNING "3w-xxxx: tw_scsi_eh_abort(): Reset failed for card %d.\n", tw_dev->host->host_no);
- spin_unlock(&tw_dev->tw_lock);
- return (FAILED);
- }
spin_unlock(&tw_dev->tw_lock);
-
return (SUCCESS);
} /* End tw_scsi_eh_abort() */
@@ -2593,7 +2624,7 @@ int tw_scsiop_read_write(TW_Device_Extension *tw_dev, int request_id)
}
command_packet->byte0.sgl_offset = 3;
- command_packet->size = 5;
+ command_packet->size = 3;
command_packet->request_id = request_id;
command_packet->byte3.unit = srb->target;
command_packet->byte3.host_id = 0;
@@ -2628,6 +2659,7 @@ int tw_scsiop_read_write(TW_Device_Extension *tw_dev, int request_id)
buffaddr = tw_map_scsi_single_data(tw_dev->tw_pci_dev, tw_dev->srb[request_id]);
command_packet->byte8.io.sgl[0].address = buffaddr;
command_packet->byte8.io.sgl[0].length = tw_dev->srb[request_id]->request_bufflen;
+ command_packet->size+=2;
}
/* Do this if we have multiple sg list entries */
@@ -2638,8 +2670,6 @@ int tw_scsiop_read_write(TW_Device_Extension *tw_dev, int request_id)
command_packet->byte8.io.sgl[i].length = sg_dma_len(&sglist[i]);
command_packet->size+=2;
}
- if (tw_dev->srb[request_id]->use_sg >= 1)
- command_packet->size-=2;
}
/* Update SG statistics */
@@ -2754,7 +2784,7 @@ int tw_setfeature(TW_Device_Extension *tw_dev, int parm, int param_size,
status_reg_value = inl(status_reg_addr);
if (tw_check_bits(status_reg_value)) {
dprintk(KERN_WARNING "3w-xxxx: tw_setfeature(): Unexpected bits.\n");
- tw_decode_bits(tw_dev, status_reg_value);
+ tw_decode_bits(tw_dev, status_reg_value, 1);
return 1;
}
if ((status_reg_value & TW_STATUS_RESPONSE_QUEUE_EMPTY) == 0) {
diff --git a/drivers/scsi/3w-xxxx.h b/drivers/scsi/3w-xxxx.h
index 5ab618c7168be..37ae5521d0d9e 100644
--- a/drivers/scsi/3w-xxxx.h
+++ b/drivers/scsi/3w-xxxx.h
@@ -92,10 +92,11 @@ static char *tw_aen_string[] = {
"Verify failed: Port #", // 0x02A
"Verify complete: Unit #", // 0x02B
"Overwrote bad sector during rebuild: Port #", //0x2C
- "Encountered bad sector during rebuild: Port #" //0x2D
+ "Encountered bad sector during rebuild: Port #", //0x2D
+ "Replacement drive is too small: Port #" //0x2E
};
-#define TW_AEN_STRING_MAX 0x02E
+#define TW_AEN_STRING_MAX 0x02F
/*
Sense key lookup table
@@ -134,7 +135,9 @@ static unsigned char tw_sense_table[][4] =
#define TW_CONTROL_DISABLE_INTERRUPTS 0x00000040
#define TW_CONTROL_ISSUE_HOST_INTERRUPT 0x00000020
#define TW_CONTROL_CLEAR_PARITY_ERROR 0x00800000
+#define TW_CONTROL_CLEAR_QUEUE_ERROR 0x00400000
#define TW_CONTROL_CLEAR_PCI_ABORT 0x00100000
+#define TW_CONTROL_CLEAR_SBUF_WRITE_ERROR 0x00000008
/* Status register bit definitions */
#define TW_STATUS_MAJOR_VERSION_MASK 0xF0000000
@@ -154,7 +157,9 @@ static unsigned char tw_sense_table[][4] =
#define TW_STATUS_ALL_INTERRUPTS 0x000F0000
#define TW_STATUS_CLEARABLE_BITS 0x00D00000
#define TW_STATUS_EXPECTED_BITS 0x00002000
-#define TW_STATUS_UNEXPECTED_BITS 0x00F80000
+#define TW_STATUS_UNEXPECTED_BITS 0x00F00008
+#define TW_STATUS_SBUF_WRITE_ERROR 0x00000008
+#define TW_STATUS_VALID_INTERRUPT 0x00DF0008
/* RESPONSE QUEUE BIT DEFINITIONS */
#define TW_RESPONSE_ID_MASK 0x00000FF0
@@ -214,7 +219,7 @@ static unsigned char tw_sense_table[][4] =
#define TW_MAX_PCI_BUSES 255
#define TW_MAX_RESET_TRIES 3
#define TW_UNIT_INFORMATION_TABLE_BASE 0x300
-#define TW_MAX_CMDS_PER_LUN (TW_Q_LENGTH-2)/TW_MAX_UNITS
+#define TW_MAX_CMDS_PER_LUN 255
#define TW_BLOCK_SIZE 0x200 /* 512-byte blocks */
#define TW_IOCTL 0x80
#define TW_MAX_AEN_TRIES 100
@@ -223,6 +228,8 @@ static unsigned char tw_sense_table[][4] =
#define TW_MAX_SECTORS 256
#define TW_AEN_WAIT_TIME 1000
#define TW_IOCTL_WAIT_TIME (1 * HZ) /* 1 second */
+#define TW_ISR_DONT_COMPLETE 2
+#define TW_ISR_DONT_RESULT 3
/* Macros */
#define TW_STATUS_ERRORS(x) \
@@ -235,7 +242,7 @@ static unsigned char tw_sense_table[][4] =
#ifdef TW_DEBUG
#define dprintk(msg...) printk(msg)
#else
-#define dprintk(msg...) do { } while(0);
+#define dprintk(msg...) do { } while(0)
#endif
/* Scatter Gather List Entry */
@@ -402,8 +409,9 @@ typedef struct TAG_TW_Device_Extension {
unsigned short aen_queue[TW_Q_LENGTH];
unsigned char aen_head;
unsigned char aen_tail;
- long flags; /* long req'd for set_bit --RR */
+ volatile long flags; /* long req'd for set_bit --RR */
char *ioctl_data[TW_Q_LENGTH];
+ int reset_print;
} TW_Device_Extension;
/* Function prototypes */
@@ -413,12 +421,13 @@ int tw_aen_read_queue(TW_Device_Extension *tw_dev, int request_id);
int tw_allocate_memory(TW_Device_Extension *tw_dev, int size, int which);
int tw_check_bits(u32 status_reg_value);
int tw_check_errors(TW_Device_Extension *tw_dev);
+void tw_clear_all_interrupts(TW_Device_Extension *tw_dev);
void tw_clear_attention_interrupt(TW_Device_Extension *tw_dev);
void tw_clear_host_interrupt(TW_Device_Extension *tw_dev);
-void tw_decode_bits(TW_Device_Extension *tw_dev, u32 status_reg_value);
-void tw_decode_sense(TW_Device_Extension *tw_dev, int request_id, int fill_sense);
+int tw_decode_bits(TW_Device_Extension *tw_dev, u32 status_reg_value, int print_host);
+int tw_decode_sense(TW_Device_Extension *tw_dev, int request_id, int fill_sense);
void tw_disable_interrupts(TW_Device_Extension *tw_dev);
-int tw_empty_response_que(TW_Device_Extension *tw_dev);
+void tw_empty_response_que(TW_Device_Extension *tw_dev);
void tw_enable_interrupts(TW_Device_Extension *tw_dev);
void tw_enable_and_clear_interrupts(TW_Device_Extension *tw_dev);
int tw_findcards(Scsi_Host_Template *tw_host);
@@ -478,7 +487,7 @@ void tw_unmask_command_interrupt(TW_Device_Extension *tw_dev);
reset : NULL, \
slave_attach : NULL, \
bios_param : tw_scsi_biosparam, \
- can_queue : TW_Q_LENGTH, \
+ can_queue : TW_Q_LENGTH-1, \
this_id: -1, \
sg_tablesize : TW_MAX_SGL_LENGTH, \
cmd_per_lun: TW_MAX_CMDS_PER_LUN, \
diff --git a/drivers/scsi/53c7,8xx.c b/drivers/scsi/53c7,8xx.c
index a944ae49708e3..3dd98eab9650a 100644
--- a/drivers/scsi/53c7,8xx.c
+++ b/drivers/scsi/53c7,8xx.c
@@ -1869,7 +1869,7 @@ NCR53c8xx_run_tests (struct Scsi_Host *host) {
*/
timeout = jiffies + 5 * HZ / 10;
- while ((hostdata->test_completed == -1) && jiffies < timeout) {
+ while ((hostdata->test_completed == -1) && time_before(jiffies, timeout)) {
barrier();
cpu_relax();
}
@@ -1955,7 +1955,7 @@ NCR53c8xx_run_tests (struct Scsi_Host *host) {
restore_flags(flags);
timeout = jiffies + 5 * HZ; /* arbitrary */
- while ((hostdata->test_completed == -1) && jiffies < timeout) {
+ while ((hostdata->test_completed == -1) && time_before(jiffies, timeout)) {
barrier();
cpu_relax();
}
diff --git a/drivers/scsi/53c7xx.c b/drivers/scsi/53c7xx.c
index ee9e02d955221..686231ba083ca 100644
--- a/drivers/scsi/53c7xx.c
+++ b/drivers/scsi/53c7xx.c
@@ -1627,7 +1627,7 @@ NCR53c7xx_run_tests (struct Scsi_Host *host) {
*/
timeout = jiffies + 5 * HZ / 10;
- while ((hostdata->test_completed == -1) && jiffies < timeout)
+ while ((hostdata->test_completed == -1) && time_before(jiffies, timeout))
barrier();
failed = 1;
@@ -1713,7 +1713,7 @@ NCR53c7xx_run_tests (struct Scsi_Host *host) {
restore_flags(flags);
timeout = jiffies + 5 * HZ; /* arbitrary */
- while ((hostdata->test_completed == -1) && jiffies < timeout)
+ while ((hostdata->test_completed == -1) && time_before(jiffies, timeout))
barrier();
NCR53c7x0_write32 (DSA_REG, 0);
diff --git a/drivers/scsi/NCR53C9x.c b/drivers/scsi/NCR53C9x.c
index 1aa7cfc855f5b..6d40aa0cbff5c 100644
--- a/drivers/scsi/NCR53C9x.c
+++ b/drivers/scsi/NCR53C9x.c
@@ -3615,3 +3615,5 @@ void esp_release(void)
esps_running = esps_in_use;
}
#endif
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/scsi/a2091.c b/drivers/scsi/a2091.c
index 08cafe0f88b5d..6aba3e11c6528 100644
--- a/drivers/scsi/a2091.c
+++ b/drivers/scsi/a2091.c
@@ -248,3 +248,5 @@ int a2091_release(struct Scsi_Host *instance)
#endif
return 1;
}
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/scsi/aic7xxx/aic7xxx_linux.c b/drivers/scsi/aic7xxx/aic7xxx_linux.c
index 5e0029feecc8d..2edba37b5aa15 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_linux.c
+++ b/drivers/scsi/aic7xxx/aic7xxx_linux.c
@@ -906,7 +906,7 @@ ahc_softc_comp(struct ahc_softc *lahc, struct ahc_softc *rahc)
}
static void
-ahc_linux_setup_tag_info(char *p, char *end)
+ahc_linux_setup_tag_info(char *p, char *end, char *s)
{
char *base;
char *tok;
@@ -986,7 +986,7 @@ ahc_linux_setup_tag_info(char *p, char *end)
}
}
while ((p != base) && (p != NULL))
- p = strtok(NULL, ",.");
+ p = strsep(&s, ",.");
}
/*
@@ -1018,7 +1018,8 @@ aic7xxx_setup(char *s)
end = strchr(s, '\0');
- for (p = strtok(s, ",."); p; p = strtok(NULL, ",.")) {
+ while ((p = strsep(&s, ",.")) != NULL) {
+ if (!*p) continue;
for (i = 0; i < NUM_ELEMENTS(options); i++) {
n = strlen(options[i].name);
@@ -1026,7 +1027,7 @@ aic7xxx_setup(char *s)
continue;
if (strncmp(p, "tag_info", n) == 0) {
- ahc_linux_setup_tag_info(p + n, end);
+ ahc_linux_setup_tag_info(p + n, end, s);
} else if (p[n] == ':') {
*(options[i].flag) =
simple_strtoul(p + n + 1, NULL, 0);
diff --git a/drivers/scsi/aic7xxx_old.c b/drivers/scsi/aic7xxx_old.c
index 0c64cd55f048c..86c41aae013f6 100644
--- a/drivers/scsi/aic7xxx_old.c
+++ b/drivers/scsi/aic7xxx_old.c
@@ -1443,7 +1443,7 @@ aic7xxx_setup(char *s)
end = strchr(s, '\0');
- for (p = strtok(s, ",."); p; p = strtok(NULL, ",."))
+ while ((p = strsep(&s, ",.")) != NULL)
{
for (i = 0; i < NUMBER(options); i++)
{
@@ -1525,7 +1525,7 @@ aic7xxx_setup(char *s)
}
}
while((p != base) && (p != NULL))
- p = strtok(NULL, ",.");
+ p = strsep(&s, ",.");
}
}
else if (p[n] == ':')
diff --git a/drivers/scsi/eata.c b/drivers/scsi/eata.c
index 27cda3b515f67..5a84221d5d5c8 100644
--- a/drivers/scsi/eata.c
+++ b/drivers/scsi/eata.c
@@ -311,7 +311,7 @@
* include in the list of i/o ports to be probed all the PCI SCSI controllers.
*
* Due to a DPT BIOS "feature", it might not be possible to force an EISA
- * address on more then a single DPT PCI board, so in this case you have to
+ * address on more than a single DPT PCI board, so in this case you have to
* let the PCI BIOS assign the addresses.
*
* The sequence of detection probes is:
diff --git a/drivers/scsi/fdomain.c b/drivers/scsi/fdomain.c
index f11acf771c1c8..c853eabf386fd 100644
--- a/drivers/scsi/fdomain.c
+++ b/drivers/scsi/fdomain.c
@@ -78,7 +78,7 @@
Please note that the drive ordering that Future Domain implemented in BIOS
versions 3.4 and 3.5 is the opposite of the order (currently) used by the
rest of the SCSI industry. If you have BIOS version 3.4 or 3.5, and have
- more then one drive, then the drive ordering will be the reverse of that
+ more than one drive, then the drive ordering will be the reverse of that
which you see under DOS. For example, under DOS SCSI ID 0 will be D: and
SCSI ID 1 will be C: (the boot device). Under Linux, SCSI ID 0 will be
/dev/sda and SCSI ID 1 will be /dev/sdb. The Linux ordering is consistent
diff --git a/drivers/scsi/ide-scsi.c b/drivers/scsi/ide-scsi.c
index 80554c4b69467..c076125c87e95 100644
--- a/drivers/scsi/ide-scsi.c
+++ b/drivers/scsi/ide-scsi.c
@@ -331,7 +331,7 @@ static ide_startstop_t idescsi_pc_intr (ide_drive_t *drive)
printk ("ide-scsi: %s: DMA complete\n", drive->name);
#endif /* IDESCSI_DEBUG_LOG */
pc->actually_transferred=pc->request_transfer;
- (void) (HWIF(drive)->dmaproc(ide_dma_end, drive));
+ (void) drive->channel->dmaproc(ide_dma_end, drive);
}
status = GET_STAT(); /* Clear the interrupt */
@@ -434,9 +434,9 @@ static ide_startstop_t idescsi_issue_pc (ide_drive_t *drive, idescsi_pc_t *pc)
bcount = min(pc->request_transfer, 63 * 1024); /* Request to transfer the entire buffer at once */
if (drive->using_dma && rq->bio)
- dma_ok=!HWIF(drive)->dmaproc(test_bit (PC_WRITING, &pc->flags) ? ide_dma_write : ide_dma_read, drive);
+ dma_ok = !drive->channel->dmaproc(test_bit (PC_WRITING, &pc->flags) ? ide_dma_write : ide_dma_read, drive);
- SELECT_DRIVE(HWIF(drive), drive);
+ SELECT_DRIVE(drive->channel, drive);
if (IDE_CONTROL_REG)
OUT_BYTE (drive->ctl,IDE_CONTROL_REG);
OUT_BYTE (dma_ok,IDE_FEATURE_REG);
@@ -444,8 +444,8 @@ static ide_startstop_t idescsi_issue_pc (ide_drive_t *drive, idescsi_pc_t *pc)
OUT_BYTE (bcount & 0xff,IDE_BCOUNTL_REG);
if (dma_ok) {
- set_bit (PC_DMA_IN_PROGRESS, &pc->flags);
- (void) (HWIF(drive)->dmaproc(ide_dma_begin, drive));
+ set_bit(PC_DMA_IN_PROGRESS, &pc->flags);
+ (void) drive->channel->dmaproc(ide_dma_begin, drive);
}
if (test_bit (IDESCSI_DRQ_INTERRUPT, &scsi->flags)) {
ide_set_handler (drive, &idescsi_transfer_pc, get_timeout(pc), NULL);
@@ -508,7 +508,7 @@ static void idescsi_add_settings(ide_drive_t *drive)
*/
static void idescsi_setup (ide_drive_t *drive, idescsi_scsi_t *scsi, int id)
{
- ata_ops(drive)->busy++;
+ MOD_INC_USE_COUNT;
idescsi_drives[id] = drive;
drive->driver_data = scsi;
@@ -629,8 +629,9 @@ int idescsi_release (struct Scsi_Host *host)
for (id = 0; id < MAX_HWIFS * MAX_DRIVES; id++) {
drive = idescsi_drives[id];
- if (drive)
- ata_ops(drive)->busy--;
+ if (drive) {
+ MOD_DEC_USE_COUNT;
+ }
}
return 0;
}
diff --git a/drivers/scsi/ppa.c b/drivers/scsi/ppa.c
index fdcbca13cf530..f0618cd93f6b5 100644
--- a/drivers/scsi/ppa.c
+++ b/drivers/scsi/ppa.c
@@ -702,7 +702,7 @@ static int ppa_completion(Scsi_Cmnd * cmd)
* change things for "normal" hardware since generally
* the 6th bit is always high.
* This makes the CPU load higher on some hardware
- * but otherwise we can not get more then 50K/secs
+ * but otherwise we can not get more than 50K/secs
* on this problem hardware.
*/
if ((r & 0xc0) != 0xc0) {
diff --git a/drivers/scsi/sun3x_esp.c b/drivers/scsi/sun3x_esp.c
index 7afe0407e245b..0aea0993fa106 100644
--- a/drivers/scsi/sun3x_esp.c
+++ b/drivers/scsi/sun3x_esp.c
@@ -376,3 +376,5 @@ static void dma_advance_sg (Scsi_Cmnd *sp)
static Scsi_Host_Template driver_template = SCSI_SUN3X_ESP;
#include "scsi_module.c"
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/scsi/tmscsim.c b/drivers/scsi/tmscsim.c
index 24ab220113888..ea61de3cacb63 100644
--- a/drivers/scsi/tmscsim.c
+++ b/drivers/scsi/tmscsim.c
@@ -2468,68 +2468,68 @@ void dc390_sendstart (PACB pACB, PDCB pDCB)
* '-' means no change
*******************************************************************/
-static int dc390_scanf (char** p1, char** p2, int* var)
+static int dc390_scanf (char** buffer, char** pos, char** p0, int* var)
{
- *p2 = *p1;
- *var = simple_strtoul (*p2, p1, 10);
- if (*p2 == *p1) return -1;
- *p1 = strtok (0, " \t\n:=,;.");
+ *p0 = *pos;
+ *var = simple_strtoul (*p0, pos, 10);
+ if (*p0 == *pos) return -1;
+ *pos = strsep (buffer, " \t\n:=,;.");
return 0;
};
-#define SCANF(p1, p2, var, min, max) \
-if (dc390_scanf (&p1, &p2, &var)) goto einv; \
+#define SCANF(buffer, pos, p0, var, min, max) \
+if (dc390_scanf (&buffer, &pos, &p0, &var)) goto einv; \
else if (var<min || var>max) goto einv2
-static int dc390_yesno (char** p, char* var, char bmask)
+static int dc390_yesno (char** buffer, char** pos, char* var, char bmask)
{
- switch (**p)
+ switch (**pos)
{
case 'Y': *var |= bmask; break;
case 'N': *var &= ~bmask; break;
case '-': break;
default: return -1;
}
- *p = strtok (0, " \t\n:=,;");
+ *pos = strsep (buffer, " \t\n:=,;");
return 0;
};
-#define YESNO(p, var, bmask) \
-if (dc390_yesno (&p, &var, bmask)) goto einv; \
+#define YESNO(buffer, pos, var, bmask) \
+if (dc390_yesno (&buffer, &pos, &var, bmask)) goto einv; \
else dc390_updateDCB (pACB, pDCB); \
if (!p) goto ok
-static int dc390_search (char **p1, char **p2, char *var, char* txt, int max, int scale, char* ign)
+static int dc390_search (char** buffer, char** pos, char** p0, char* var, char* txt, int max, int scale, char* ign)
{
int dum;
- if (! memcmp (*p1, txt, strlen(txt)))
+ if (! memcmp (*pos, txt, strlen(txt)))
{
- *p2 = strtok (0, " \t\n:=,;");
- if (!*p2) return -1;
- dum = simple_strtoul (*p2, p1, 10);
- if (*p2 == *p1) return -1;
+ *p0 = strsep (buffer, " \t\n:=,;");
+ if (!*p0) return -1;
+ dum = simple_strtoul (*p0, pos, 10);
+ if (*p0 == *pos) return -1;
if (dum >= 0 && dum <= max)
{ *var = (dum * 100) / scale; }
else return -2;
- *p1 = strtok (0, " \t\n:=,;");
- if (*ign && *p1 && strlen(*p1) >= strlen(ign) &&
- !(memcmp (*p1, ign, strlen(ign))))
- *p1 = strtok (0, " \t\n:=,;");
+ *pos = strsep (buffer, " \t\n:=,;");
+ if (*ign && *pos && strlen(*pos) >= strlen(ign) &&
+ !(memcmp (*pos, ign, strlen(ign))))
+ *pos = strsep (buffer, " \t\n:=,;");
}
return 0;
};
-#define SEARCH(p1, p2, var, txt, max) \
-if (dc390_search (&p1, &p2, (PUCHAR)(&var), txt, max, 100, "")) goto einv2; \
+#define SEARCH(buffer, pos, p0, var, txt, max) \
+if (dc390_search (&buffer, &pos, &p0, (PUCHAR)(&var), txt, max, 100, "")) goto einv2; \
else if (!p1) goto ok2
-#define SEARCH2(p1, p2, var, txt, max, scale) \
-if (dc390_search (&p1, &p2, &var, txt, max, scale, "")) goto einv2; \
+#define SEARCH2(buffer, pos, p0, var, txt, max, scale) \
+if (dc390_search (&buffer, &pos, &p0, &var, txt, max, scale, "")) goto einv2; \
else if (!p1) goto ok2
-#define SEARCH3(p1, p2, var, txt, max, scale, ign) \
-if (dc390_search (&p1, &p2, &var, txt, max, scale, ign)) goto einv2; \
+#define SEARCH3(buffer, pos, &p0, var, txt, max, scale, ign) \
+if (dc390_search (&buffer, &pos, p0, &var, txt, max, scale, ign)) goto einv2; \
else if (!p1) goto ok2
@@ -2565,12 +2565,9 @@ int dc390_set_info (char *buffer, int length, PACB pACB)
while (*pos)
{ if (*pos >='a' && *pos <= 'z') *pos = *pos + 'A' - 'a'; pos++; };
- /* We should protect __strtok ! */
- /* spin_lock (strtok_lock); */
-
/* Remove WS */
- pos = strtok (buffer, " \t:\n=,;");
- if (!pos) goto ok;
+ pos = strsep (&buffer, " \t:\n=,;");
+ if (!*pos) goto ok;
next:
if (!memcmp (pos, "RESET", 5)) goto reset;
@@ -2586,10 +2583,10 @@ int dc390_set_info (char *buffer, int length, PACB pACB)
int dev, id, lun; char* pdec;
char olddevmode;
- SCANF (pos, p0, dev, 0, pACB->DCBCnt-1);
- if (pos) { SCANF (pos, p0, id, 0, 7); } else goto einv;
- if (pos) { SCANF (pos, p0, lun, 0, 7); } else goto einv;
- if (!pos) goto einv;
+ SCANF (buffer, pos, p0, dev, 0, pACB->DCBCnt-1);
+ if (*pos) { SCANF (buffer, pos, p0, id, 0, 7); } else goto einv;
+ if (*pos) { SCANF (buffer, pos, p0, lun, 0, 7); } else goto einv;
+ if (!*pos) goto einv;
PARSEDEBUG(printk (KERN_INFO "DC390: config line %i %i %i:\"%s\"\n", dev, id, lun, prstr (pos, &buffer[length]));)
pDCB = pACB->pLinkDCB;
@@ -2610,20 +2607,20 @@ int dc390_set_info (char *buffer, int length, PACB pACB)
};
olddevmode = pDCB->DevMode;
- YESNO (pos, pDCB->DevMode, PARITY_CHK_);
+ YESNO (buffer, pos, pDCB->DevMode, PARITY_CHK_);
needs_inquiry++;
- YESNO (pos, pDCB->DevMode, SYNC_NEGO_);
+ YESNO (buffer, pos, pDCB->DevMode, SYNC_NEGO_);
if ((olddevmode & SYNC_NEGO_) == (pDCB->DevMode & SYNC_NEGO_)) needs_inquiry--;
needs_inquiry++;
- YESNO (pos, pDCB->DevMode, EN_DISCONNECT_);
+ YESNO (buffer, pos, pDCB->DevMode, EN_DISCONNECT_);
if ((olddevmode & EN_DISCONNECT_) == (pDCB->DevMode & EN_DISCONNECT_)) needs_inquiry--;
- YESNO (pos, pDCB->DevMode, SEND_START_);
+ YESNO (buffer, pos, pDCB->DevMode, SEND_START_);
needs_inquiry++;
- YESNO (pos, pDCB->DevMode, TAG_QUEUEING_);
+ YESNO (buffer, pos, pDCB->DevMode, TAG_QUEUEING_);
if ((olddevmode & TAG_QUEUEING_) == (pDCB->DevMode & TAG_QUEUEING_)) needs_inquiry--;
dc390_updateDCB (pACB, pDCB);
- if (!pos) goto ok;
+ if (!*pos) goto ok;
olddevmode = pDCB->NegoPeriod;
/* Look for decimal point (Speed) */
@@ -2632,22 +2629,22 @@ int dc390_set_info (char *buffer, int length, PACB pACB)
/* NegoPeriod */
if (*pos != '-')
{
- SCANF (pos, p0, dum, 72, 800);
+ SCANF (buffer, pos, p0, dum, 72, 800);
pDCB->NegoPeriod = dum >> 2;
if (pDCB->NegoPeriod != olddevmode) needs_inquiry++;
if (!pos) goto ok;
- if (memcmp (pos, "NS", 2) == 0) pos = strtok (0, " \t\n:=,;.");
+ if (memcmp (pos, "NS", 2) == 0) pos = strsep (*pos, " \t\n:=,;.");
}
- else pos = strtok (0, " \t\n:=,;.");
- if (!pos) goto ok;
+ else pos = strsep (*pos, " \t\n:=,;.");
+ if (!*pos) goto ok;
/* Sync Speed in MHz */
if (*pos != '-')
{
- SCANF (pos, p0, dum, 1, 13);
+ SCANF (buffer, pos, p0, dum, 1, 13);
pDCB->NegoPeriod = (1000/dum) >> 2;
if (pDCB->NegoPeriod != olddevmode && !pos) needs_inquiry++;
- if (!pos) goto ok;
+ if (!*pos) goto ok;
/* decimal */
if (pos-1 == pdec)
{
@@ -2656,38 +2653,38 @@ int dc390_set_info (char *buffer, int length, PACB pACB)
for (; p0-pos > 1; p0--) dum /= 10;
pDCB->NegoPeriod = (100000/(100*dumold + dum)) >> 2;
if (pDCB->NegoPeriod < 19) pDCB->NegoPeriod = 19;
- pos = strtok (0, " \t\n:=,;");
- if (!pos) goto ok;
+ pos = strsep (*pos, " \t\n:=,;");
+ if (!*pos) goto ok;
};
- if (*pos == 'M') pos = strtok (0, " \t\n:=,;");
+ if (*pos == 'M') pos = strsep (*pos, " \t\n:=,;");
if (pDCB->NegoPeriod != olddevmode) needs_inquiry++;
}
- else pos = strtok (0, " \t\n:=,;");
+ else pos = strsep (*pos, " \t\n:=,;");
/* dc390_updateDCB (pACB, pDCB); */
- if (!pos) goto ok;
+ if (!*pos) goto ok;
olddevmode = pDCB->SyncOffset;
/* SyncOffs */
if (*pos != '-')
{
- SCANF (pos, p0, dum, 0, 0x0f);
+ SCANF (buffer, pos, p0, dum, 0, 0x0f);
pDCB->SyncOffset = dum;
if (pDCB->SyncOffset > olddevmode) needs_inquiry++;
}
- else pos = strtok (0, " \t\n:=,;");
- if (!pos) goto ok;
+ else pos = strsep (*pos, " \t\n:=,;");
+ if (!*pos) goto ok;
dc390_updateDCB (pACB, pDCB);
//olddevmode = pDCB->MaxCommand;
/* MaxCommand (Tags) */
if (*pos != '-')
{
- SCANF (pos, p0, dum, 1, 32 /*pACB->TagMaxNum*/);
+ SCANF (buffer, pos, p0, dum, 1, 32 /*pACB->TagMaxNum*/);
if (pDCB->SyncMode & EN_TAG_QUEUEING)
pDCB->MaxCommand = dum;
else printk (KERN_INFO "DC390: Can't set MaxCmd larger than one without Tag Queueing!\n");
}
- else pos = strtok (0, " \t\n:=,;");
+ else pos = strsep (*pos, " \t\n:=,;");
}
else
@@ -2696,14 +2693,14 @@ int dc390_set_info (char *buffer, int length, PACB pACB)
PARSEDEBUG(printk (KERN_INFO "DC390: chg adapt cfg \"%s\"\n", prstr (pos, &buffer[length]));)
dum = GLITCH_TO_NS (pACB->glitch_cfg);
/* Adapter setting */
- SEARCH (pos, p0, pACB->pScsiHost->max_id, "MAXID", 8);
- SEARCH (pos, p0, pACB->pScsiHost->max_lun, "MAXLUN", 8);
- SEARCH (pos, p0, newadaptid, "ADAPTERID", 7);
- SEARCH (pos, p0, pACB->TagMaxNum, "TAGMAXNUM", 32);
- SEARCH (pos, p0, pACB->ACBFlag, "ACBFLAG", 255);
- SEARCH3 (pos, p0, dum, "GLITCHEATER", 40, 1000, "NS");
- SEARCH3 (pos, p0, pACB->sel_timeout, "SELTIMEOUT", 400, 163, "MS");
- SEARCH3 (pos, p0, dc390_eepromBuf[pACB->AdapterIndex][EE_DELAY], "DELAYRESET", 180, 100, "S");
+ SEARCH (buffer, pos, p0, pACB->pScsiHost->max_id, "MAXID", 8);
+ SEARCH (buffer, pos, p0, pACB->pScsiHost->max_lun, "MAXLUN", 8);
+ SEARCH (buffer, pos, p0, newadaptid, "ADAPTERID", 7);
+ SEARCH (buffer, pos, p0, pACB->TagMaxNum, "TAGMAXNUM", 32);
+ SEARCH (buffer, pos, p0, pACB->ACBFlag, "ACBFLAG", 255);
+ SEARCH3 (buffer, pos, p0, dum, "GLITCHEATER", 40, 1000, "NS");
+ SEARCH3 (buffer, pos, p0, pACB->sel_timeout, "SELTIMEOUT", 400, 163, "MS");
+ SEARCH3 (buffer, pos, p0, dc390_eepromBuf[pACB->AdapterIndex][EE_DELAY], "DELAYRESET", 180, 100, "S");
ok2:
pACB->glitch_cfg = NS_TO_GLITCH (dum);
if (pACB->sel_timeout < 60) pACB->sel_timeout = 60;
@@ -2719,10 +2716,9 @@ int dc390_set_info (char *buffer, int length, PACB pACB)
// All devs should be INQUIRED now
if (pos == p1) goto einv;
}
- if (pos) goto next;
+ if (*pos) goto next;
ok:
- /* spin_unlock (strtok_lock); */
DC390_UNLOCK_ACB;
if (needs_inquiry)
{ dc390_updateDCB (pACB, pDCB); dc390_inquiry (pACB, pDCB); };
@@ -2732,7 +2728,6 @@ int dc390_set_info (char *buffer, int length, PACB pACB)
einv2:
pos = p0;
einv:
- /* spin_unlock (strtok_lock); */
DC390_UNLOCK_ACB;
DC390_UNLOCK_IO(pACB.pScsiHost);
printk (KERN_WARNING "DC390: parse error near \"%s\"\n", (pos? pos: "NULL"));
@@ -2758,7 +2753,7 @@ int dc390_set_info (char *buffer, int length, PACB pACB)
inquiry:
{
- pos = strtok (0, " \t\n.:;="); if (!pos) goto einv;
+ pos = strsep (*pos, " \t\n.:;="); if (!*pos) goto einv;
dev = simple_strtoul (pos, &p0, 10);
if (dev >= pACB->DCBCnt) goto einv_dev;
for (dum = 0; dum < dev; dum++) pDCB = pDCB->pNextDCB;
@@ -2772,7 +2767,7 @@ int dc390_set_info (char *buffer, int length, PACB pACB)
remove:
{
- pos = strtok (0, " \t\n.:;="); if (!pos) goto einv;
+ pos = strsep (*pos, " \t\n.:;="); if (!*pos) goto einv;
dev = simple_strtoul (pos, &p0, 10);
if (dev >= pACB->DCBCnt) goto einv_dev;
for (dum = 0; dum < dev; dum++) pDCB = pDCB->pNextDCB;
@@ -2788,9 +2783,9 @@ int dc390_set_info (char *buffer, int length, PACB pACB)
add:
{
int id, lun;
- pos = strtok (0, " \t\n.:;=");
- if (pos) { SCANF (pos, p0, id, 0, 7); } else goto einv;
- if (pos) { SCANF (pos, p0, lun, 0, 7); } else goto einv;
+ pos = strsep (*pos, " \t\n.:;=");
+ if (*pos) { SCANF (buffer, pos, p0, id, 0, 7); } else goto einv;
+ if (*pos) { SCANF (buffer, pos, p0, lun, 0, 7); } else goto einv;
pDCB = dc390_findDCB (pACB, id, lun);
if (pDCB) { printk ("DC390: ADD: Device already existing\n"); goto einv; };
dc390_initDCB (pACB, &pDCB, id, lun);
@@ -2803,9 +2798,9 @@ int dc390_set_info (char *buffer, int length, PACB pACB)
start:
{
int id, lun;
- pos = strtok (0, " \t\n.:;=");
- if (pos) { SCANF (pos, p0, id, 0, 7); } else goto einv;
- if (pos) { SCANF (pos, p0, lun, 0, 7); } else goto einv;
+ pos = strsep (*pos, " \t\n.:;=");
+ if (*pos) { SCANF (buffer, pos, p0, id, 0, 7); } else goto einv;
+ if (*pos) { SCANF (buffer, pos, p0, lun, 0, 7); } else goto einv;
pDCB = dc390_findDCB (pACB, id, lun);
if (pDCB) printk ("DC390: SendStart: Device already existing ...\n");
else dc390_initDCB (pACB, &pDCB, id, lun);
diff --git a/drivers/scsi/u14-34f.c b/drivers/scsi/u14-34f.c
index 0948ed4664318..5ae088c865478 100644
--- a/drivers/scsi/u14-34f.c
+++ b/drivers/scsi/u14-34f.c
@@ -171,7 +171,7 @@
* Auto detects if U14F boards have an old firmware revision.
* Max number of scatter/gather lists set to 16 for all boards
* (most installation run fine using 33 sglists, while other
- * has problems when using more then 16).
+ * has problems when using more than 16).
*
* 16 Jan 1995 rev. 1.13 for linux 1.1.81
* Display a message if check_region detects a port address
@@ -279,7 +279,7 @@
*
* For U34F boards the latest bios prom is 38008-002 (BIOS rev. 2.01),
* the latest firmware prom is 28008-006. Older firmware 28008-005 has
- * problems when using more then 16 scatter/gather lists.
+ * problems when using more than 16 scatter/gather lists.
*
* The list of i/o ports to be probed can be totally replaced by the
* boot command line option: "u14-34f=port0,port1,port2,...", where the
diff --git a/drivers/tc/zs.c b/drivers/tc/zs.c
index 6239675f8b9ab..b54b103655196 100644
--- a/drivers/tc/zs.c
+++ b/drivers/tc/zs.c
@@ -1472,7 +1472,7 @@ static void rs_wait_until_sent(struct tty_struct *tty, int timeout)
schedule_timeout(char_time);
if (signal_pending(current))
break;
- if (timeout && ((orig_jiffies + timeout) < jiffies))
+ if (timeout && time_after(jiffies, orig_jiffies + timeout))
break;
}
current->state = TASK_RUNNING;
diff --git a/drivers/usb/inode.c b/drivers/usb/inode.c
index 329462ed7ee59..73527b766d81d 100644
--- a/drivers/usb/inode.c
+++ b/drivers/usb/inode.c
@@ -64,9 +64,9 @@ static int parse_options(struct super_block *s, char *data)
{
char *curopt = NULL, *value;
- if (data)
- curopt = strtok(data, ",");
- for (; curopt; curopt = strtok(NULL, ",")) {
+ while ((curopt = strsep(&data, ",")) != NULL) {
+ if (!*curopt)
+ continue;
if ((value = strchr(curopt, '=')) != NULL)
*value++ = 0;
if (!strcmp(curopt, "devuid")) {
diff --git a/drivers/usb/storage/transport.h b/drivers/usb/storage/transport.h
index a991bd2d9240a..2dc2ac1a3e0a5 100644
--- a/drivers/usb/storage/transport.h
+++ b/drivers/usb/storage/transport.h
@@ -112,7 +112,7 @@ struct bulk_cs_wrap {
#define US_BULK_GET_MAX_LUN 0xfe
/*
- * us_bulk_transfer() return codes
+ * usb_stor_transfer() return codes
*/
#define US_BULK_TRANSFER_GOOD 0 /* good transfer */
#define US_BULK_TRANSFER_SHORT 1 /* transfered less than expected */
diff --git a/drivers/usb/usbvideo.c b/drivers/usb/usbvideo.c
index b0d4eb5e0cdec..c04a67e6c45c5 100644
--- a/drivers/usb/usbvideo.c
+++ b/drivers/usb/usbvideo.c
@@ -1020,7 +1020,7 @@ static struct file_operations usbvideo_fops = {
release: usbvideo_v4l_close,
read: usbvideo_v4l_read,
mmap: usbvideo_v4l_mmap,
- ioctl: video_generic_ioctl,
+ ioctl: usbvideo_v4l_ioctl,
llseek: no_llseek,
};
static struct video_device usbvideo_template = {
@@ -1028,7 +1028,6 @@ static struct video_device usbvideo_template = {
type: VID_TYPE_CAPTURE,
hardware: VID_HARDWARE_CPIA,
fops: &usbvideo_fops,
- kernel_ioctl: usbvideo_v4l_ioctl,
};
uvd_t *usbvideo_AllocateDevice(usbvideo_t *cams)
@@ -1349,8 +1348,8 @@ int usbvideo_v4l_close(struct inode *inode, struct file *file)
* History:
* 22-Jan-2000 Corrected VIDIOCSPICT to reject unsupported settings.
*/
-int usbvideo_v4l_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, void *arg)
+static int usbvideo_v4l_do_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, void *arg)
{
uvd_t *uvd = file->private_data;
@@ -1555,6 +1554,12 @@ int usbvideo_v4l_ioctl(struct inode *inode, struct file *file,
return 0;
}
+int usbvideo_v4l_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ return video_usercopy(inode, file, cmd, arg, usbvideo_v4l_do_ioctl);
+}
+
/*
* usbvideo_v4l_read()
*
diff --git a/drivers/usb/usbvideo.h b/drivers/usb/usbvideo.h
index 006fd267a4260..211249c340db4 100644
--- a/drivers/usb/usbvideo.h
+++ b/drivers/usb/usbvideo.h
@@ -350,7 +350,7 @@ void usbvideo_CameraRelease(uvd_t *uvd);
int usbvideo_v4l_close(struct inode *inode, struct file *file);
int usbvideo_v4l_initialize(struct video_device *dev);
int usbvideo_v4l_ioctl(struct inode *inode, struct file *file,
- unsigned int ioctlnr, void *arg);
+ unsigned int cmd, unsigned long arg);
int usbvideo_v4l_mmap(struct file *file, struct vm_area_struct *vma);
int usbvideo_v4l_open(struct inode *inode, struct file *file);
int usbvideo_v4l_read(struct file *file, char *buf,
diff --git a/drivers/video/amifb.c b/drivers/video/amifb.c
index fadb7f0a8719d..30de86c25712b 100644
--- a/drivers/video/amifb.c
+++ b/drivers/video/amifb.c
@@ -1132,7 +1132,6 @@ static int flash_cursor(void);
static void amifb_interrupt(int irq, void *dev_id, struct pt_regs *fp);
static u_long chipalloc(u_long size);
static void chipfree(void);
-static char *strtoke(char *s,const char *ct);
/*
* Hardware routines
@@ -1224,22 +1223,22 @@ int __init amifb_setup(char *options)
* <H*> horizontal freq. in kHz
*/
- if (!(p = strtoke(mcap_spec, ";")) || !*p)
+ if (!(p = strsep(&mcap_spec, ";")) || !*p)
goto cap_invalid;
vmin = simple_strtoul(p, NULL, 10);
if (vmin <= 0)
goto cap_invalid;
- if (!(p = strtoke(NULL, ";")) || !*p)
+ if (!(p = strsep(&mcap_spec, ";")) || !*p)
goto cap_invalid;
vmax = simple_strtoul(p, NULL, 10);
if (vmax <= 0 || vmax <= vmin)
goto cap_invalid;
- if (!(p = strtoke(NULL, ";")) || !*p)
+ if (!(p = strsep(&mcap_spec, ";")) || !*p)
goto cap_invalid;
hmin = 1000 * simple_strtoul(p, NULL, 10);
if (hmin <= 0)
goto cap_invalid;
- if (!(p = strtoke(NULL, "")) || !*p)
+ if (!(p = strsep(&mcap_spec, "")) || !*p)
goto cap_invalid;
hmax = 1000 * simple_strtoul(p, NULL, 10);
if (hmax <= 0 || hmax <= hmin)
@@ -1915,29 +1914,6 @@ static void amifb_interrupt(int irq, void *dev_id, struct pt_regs *fp)
}
}
- /*
- * A strtok which returns empty strings, too
- */
-
-static char __init *strtoke(char *s,const char *ct)
-{
- char *sbegin, *send;
- static char *ssave = NULL;
-
- sbegin = s ? s : ssave;
- if (!sbegin)
- return NULL;
- if (*sbegin == '\0') {
- ssave = NULL;
- return NULL;
- }
- send = strpbrk(sbegin, ct);
- if (send && *send != '\0')
- *send++ = '\0';
- ssave = send;
- return sbegin;
-}
-
/* --------------------------- Hardware routines --------------------------- */
/*
diff --git a/drivers/video/atafb.c b/drivers/video/atafb.c
index 73339ab4cba0d..64e8d4a239310 100644
--- a/drivers/video/atafb.c
+++ b/drivers/video/atafb.c
@@ -2860,28 +2860,6 @@ int __init atafb_init(void)
return 0;
}
-/* a strtok which returns empty strings, too */
-
-static char * strtoke(char * s,const char * ct)
-{
- char *sbegin, *send;
- static char *ssave = NULL;
-
- sbegin = s ? s : ssave;
- if (!sbegin) {
- return NULL;
- }
- if (*sbegin == '\0') {
- ssave = NULL;
- return NULL;
- }
- send = strpbrk(sbegin, ct);
- if (send && *send != '\0')
- *send++ = '\0';
- ssave = send;
- return sbegin;
-}
-
int __init atafb_setup( char *options )
{
char *this_opt;
@@ -2956,18 +2934,18 @@ int __init atafb_setup( char *options )
int xres;
char *p;
- if (!(p = strtoke(int_str, ";")) ||!*p) goto int_invalid;
+ if (!(p = strsep(&int_str, ";")) || !*p) goto int_invalid;
xres = simple_strtoul(p, NULL, 10);
- if (!(p = strtoke(NULL, ";")) || !*p) goto int_invalid;
+ if (!(p = strsep(&int_str, ";")) || !*p) goto int_invalid;
sttt_xres=xres;
tt_yres=st_yres=simple_strtoul(p, NULL, 10);
- if ((p=strtoke(NULL, ";")) && *p) {
+ if ((p=strsep(&int_str, ";")) && *p) {
sttt_xres_virtual=simple_strtoul(p, NULL, 10);
}
- if ((p=strtoke(NULL, ";")) && *p) {
+ if ((p=strsep(&int_str, ";")) && *p) {
sttt_yres_virtual=simple_strtoul(p, NULL, 0);
}
- if ((p=strtoke(NULL, ";")) && *p) {
+ if ((p=strsep(&int_str, ";")) && *p) {
ovsc_offset=simple_strtoul(p, NULL, 0);
}
@@ -2993,20 +2971,20 @@ int __init atafb_setup( char *options )
*
* Even xres_virtual is available, we neither support panning nor hw-scrolling!
*/
- if (!(p = strtoke(ext_str, ";")) ||!*p) goto ext_invalid;
+ if (!(p = strsep(&ext_str, ";")) || !*p) goto ext_invalid;
xres_virtual = xres = simple_strtoul(p, NULL, 10);
if (xres <= 0) goto ext_invalid;
- if (!(p = strtoke(NULL, ";")) ||!*p) goto ext_invalid;
+ if (!(p = strsep(&ext_str, ";")) || !*p) goto ext_invalid;
yres = simple_strtoul(p, NULL, 10);
if (yres <= 0) goto ext_invalid;
- if (!(p = strtoke(NULL, ";")) ||!*p) goto ext_invalid;
+ if (!(p = strsep(&ext_str, ";")) || !*p) goto ext_invalid;
depth = simple_strtoul(p, NULL, 10);
if (depth != 1 && depth != 2 && depth != 4 && depth != 8 &&
depth != 16 && depth != 24) goto ext_invalid;
- if (!(p = strtoke(NULL, ";")) ||!*p) goto ext_invalid;
+ if (!(p = strsep(&ext_str, ";")) || !*p) goto ext_invalid;
if (*p == 'i')
planes = FB_TYPE_INTERLEAVED_PLANES;
else if (*p == 'p')
@@ -3019,19 +2997,19 @@ int __init atafb_setup( char *options )
goto ext_invalid;
- if (!(p = strtoke(NULL, ";")) ||!*p) goto ext_invalid;
+ if (!(p = strsep(&ext_str, ";")) || !*p) goto ext_invalid;
addr = simple_strtoul(p, NULL, 0);
- if (!(p = strtoke(NULL, ";")) ||!*p)
+ if (!(p = strsep(&ext_str, ";")) || !*p)
len = xres*yres*depth/8;
else
len = simple_strtoul(p, NULL, 0);
- if ((p = strtoke(NULL, ";")) && *p) {
+ if ((p = strsep(&ext_str, ";")) && *p) {
external_vgaiobase=simple_strtoul(p, NULL, 0);
}
- if ((p = strtoke(NULL, ";")) && *p) {
+ if ((p = strsep(&ext_str, ";")) && *p) {
external_bitspercol = simple_strtoul(p, NULL, 0);
if (external_bitspercol > 8)
external_bitspercol = 8;
@@ -3039,14 +3017,14 @@ int __init atafb_setup( char *options )
external_bitspercol = 1;
}
- if ((p = strtoke(NULL, ";")) && *p) {
+ if ((p = strsep(&ext_str, ";")) && *p) {
if (!strcmp(p, "vga"))
external_card_type = IS_VGA;
if (!strcmp(p, "mv300"))
external_card_type = IS_MV300;
}
- if ((p = strtoke(NULL, ";")) && *p) {
+ if ((p = strsep(&ext_str, ";")) && *p) {
xres_virtual = simple_strtoul(p, NULL, 10);
if (xres_virtual < xres)
xres_virtual = xres;
@@ -3089,16 +3067,16 @@ int __init atafb_setup( char *options )
* <V*> vertical freq. in Hz
* <H*> horizontal freq. in kHz
*/
- if (!(p = strtoke(mcap_spec, ";")) || !*p) goto cap_invalid;
+ if (!(p = strsep(&mcap_spec, ";")) || !*p) goto cap_invalid;
vmin = simple_strtoul(p, NULL, 10);
if (vmin <= 0) goto cap_invalid;
- if (!(p = strtoke(NULL, ";")) || !*p) goto cap_invalid;
+ if (!(p = strsep(&mcap_spec, ";")) || !*p) goto cap_invalid;
vmax = simple_strtoul(p, NULL, 10);
if (vmax <= 0 || vmax <= vmin) goto cap_invalid;
- if (!(p = strtoke(NULL, ";")) || !*p) goto cap_invalid;
+ if (!(p = strsep(&mcap_spec, ";")) || !*p) goto cap_invalid;
hmin = 1000 * simple_strtoul(p, NULL, 10);
if (hmin <= 0) goto cap_invalid;
- if (!(p = strtoke(NULL, "")) || !*p) goto cap_invalid;
+ if (!(p = strsep(&mcap_spec, "")) || !*p) goto cap_invalid;
hmax = 1000 * simple_strtoul(p, NULL, 10);
if (hmax <= 0 || hmax <= hmin) goto cap_invalid;
@@ -3117,11 +3095,11 @@ int __init atafb_setup( char *options )
char *p;
int xres, yres, depth, temp;
- if (!(p = strtoke(user_mode, ";")) || !*p) goto user_invalid;
+ if (!(p = strsep(&user_mode, ";")) || !*p) goto user_invalid;
xres = simple_strtoul(p, NULL, 10);
- if (!(p = strtoke(NULL, ";")) || !*p) goto user_invalid;
+ if (!(p = strsep(&user_mode, ";")) || !*p) goto user_invalid;
yres = simple_strtoul(p, NULL, 10);
- if (!(p = strtoke(NULL, "")) || !*p) goto user_invalid;
+ if (!(p = strsep(&user_mode, "")) || !*p) goto user_invalid;
depth = simple_strtoul(p, NULL, 10);
if ((temp=get_video_mode("user0"))) {
default_par=temp;
diff --git a/drivers/video/aty/atyfb_base.c b/drivers/video/aty/atyfb_base.c
index da3e1ea3cac9b..f18527020c7b5 100644
--- a/drivers/video/aty/atyfb_base.c
+++ b/drivers/video/aty/atyfb_base.c
@@ -178,7 +178,6 @@ static void atyfbcon_blank(int blank, struct fb_info *fb);
static int aty_init(struct fb_info_aty *info, const char *name);
#ifdef CONFIG_ATARI
static int store_video_par(char *videopar, unsigned char m64_num);
-static char *strtoke(char *s, const char *ct);
#endif
static void aty_set_crtc(const struct fb_info_aty *info,
@@ -2595,13 +2594,13 @@ static int __init store_video_par(char *video_str, unsigned char m64_num)
printk("store_video_par() '%s' \n", video_str);
- if (!(p = strtoke(video_str, ";")) || !*p)
+ if (!(p = strsep(&video_str, ";")) || !*p)
goto mach64_invalid;
vmembase = simple_strtoul(p, NULL, 0);
- if (!(p = strtoke(NULL, ";")) || !*p)
+ if (!(p = strsep(&video_str, ";")) || !*p)
goto mach64_invalid;
size = simple_strtoul(p, NULL, 0);
- if (!(p = strtoke(NULL, ";")) || !*p)
+ if (!(p = strsep(&video_str, ";")) || !*p)
goto mach64_invalid;
guiregbase = simple_strtoul(p, NULL, 0);
@@ -2616,25 +2615,6 @@ mach64_invalid:
phys_vmembase[m64_num] = 0;
return -1;
}
-
-static char __init *strtoke(char *s, const char *ct)
-{
- static char *ssave = NULL;
- char *sbegin, *send;
-
- sbegin = s ? s : ssave;
- if (!sbegin)
- return NULL;
- if (*sbegin == '\0') {
- ssave = NULL;
- return NULL;
- }
- send = strpbrk(sbegin, ct);
- if (send && *send != '\0')
- *send++ = '\0';
- ssave = send;
- return sbegin;
-}
#endif /* CONFIG_ATARI */
static int atyfbcon_switch(int con, struct fb_info *fb)
diff --git a/fs/Makefile b/fs/Makefile
index 331ec687a6a4a..43a3d6ffbacfd 100644
--- a/fs/Makefile
+++ b/fs/Makefile
@@ -16,12 +16,6 @@ obj-y := open.o read_write.o devices.o file_table.o buffer.o \
dcache.o inode.o attr.o bad_inode.o file.o iobuf.o dnotify.o \
filesystems.o namespace.o seq_file.o xattr.o libfs.o
-ifeq ($(CONFIG_QUOTA),y)
-obj-y += dquot.o
-else
-obj-y += noquot.o
-endif
-
ifneq ($(CONFIG_NFSD),n)
ifneq ($(CONFIG_NFSD),)
obj-y += nfsctl.o
@@ -85,6 +79,8 @@ obj-y += binfmt_script.o
obj-$(CONFIG_BINFMT_ELF) += binfmt_elf.o
+obj-$(CONFIG_QUOTA) += dquot.o
+
# persistent filesystems
obj-y += $(join $(subdir-y),$(subdir-y:%=/%.o))
diff --git a/fs/adfs/super.c b/fs/adfs/super.c
index 67886233c5380..1164ce6d11d02 100644
--- a/fs/adfs/super.c
+++ b/fs/adfs/super.c
@@ -171,7 +171,9 @@ static int parse_options(struct super_block *sb, char *options)
if (!options)
return 0;
- for (opt = strtok(options, ","); opt != NULL; opt = strtok(NULL, ",")) {
+ while ((opt = strsep(&options, ",")) != NULL) {
+ if (!*opt)
+ continue;
value = strchr(opt, '=');
if (value)
*value++ = '\0';
diff --git a/fs/affs/super.c b/fs/affs/super.c
index adfefd10ff905..2a7e4c9a7c87f 100644
--- a/fs/affs/super.c
+++ b/fs/affs/super.c
@@ -161,7 +161,9 @@ parse_options(char *options, uid_t *uid, gid_t *gid, int *mode, int *reserved, s
*mount_opts = 0;
if (!options)
return 1;
- for (this_char = strtok(options,","); this_char; this_char = strtok(NULL,",")) {
+ while ((this_char = strsep(&options, ",")) != NULL) {
+ if (!*this_char)
+ continue;
f = 0;
if ((value = strchr(this_char,'=')) != NULL)
*value++ = 0;
@@ -291,7 +293,7 @@ static int affs_fill_super(struct super_block *sb, void *data, int silent)
sb->s_magic = AFFS_SUPER_MAGIC;
sb->s_op = &affs_sops;
-
+
sbi = kmalloc(sizeof(struct affs_sb_info), GFP_KERNEL);
if (!sbi)
return -ENOMEM;
diff --git a/fs/autofs/inode.c b/fs/autofs/inode.c
index cc9c70c158fe2..4e846d5224503 100644
--- a/fs/autofs/inode.c
+++ b/fs/autofs/inode.c
@@ -60,7 +60,9 @@ static int parse_options(char *options, int *pipefd, uid_t *uid, gid_t *gid, pid
*pipefd = -1;
if ( !options ) return 1;
- for (this_char = strtok(options,","); this_char; this_char = strtok(NULL,",")) {
+ while ((this_char = strsep(&options,",")) != NULL) {
+ if (!*value)
+ continue;
if ((value = strchr(this_char,'=')) != NULL)
*value++ = 0;
if (!strcmp(this_char,"fd")) {
@@ -119,9 +121,10 @@ int autofs_fill_super(struct super_block *s, void *data, int silent)
struct autofs_sb_info *sbi;
int minproto, maxproto;
- sbi = (struct autofs_sb_info *) kmalloc(sizeof(struct autofs_sb_info), GFP_KERNEL);
+ sbi = kmalloc(sizeof(*sbi), GFP_KERNEL);
if ( !sbi )
goto fail_unlock;
+ memset(sbi, 0, sizeof(*sbi));
DPRINTK(("autofs: starting up, sbi = %p\n",sbi));
s->u.generic_sbp = sbi;
diff --git a/fs/autofs4/inode.c b/fs/autofs4/inode.c
index 77b826010828b..86f73230fa298 100644
--- a/fs/autofs4/inode.c
+++ b/fs/autofs4/inode.c
@@ -110,7 +110,9 @@ static int parse_options(char *options, int *pipefd, uid_t *uid, gid_t *gid,
*pipefd = -1;
if ( !options ) return 1;
- for (this_char = strtok(options,","); this_char; this_char = strtok(NULL,",")) {
+ while ((this_char = strsep(&options,",")) != NULL) {
+ if (!*this_char)
+ continue;
if ((value = strchr(this_char,'=')) != NULL)
*value++ = 0;
if (!strcmp(this_char,"fd")) {
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c
index a52245622b5ba..4432c7562fe78 100644
--- a/fs/binfmt_elf.c
+++ b/fs/binfmt_elf.c
@@ -138,6 +138,21 @@ create_elf_tables(char *p, int argc, int envc,
} else
u_platform = p;
+#if defined(__i386__) && defined(CONFIG_SMP)
+ /*
+ * In some cases (e.g. Hyper-Threading), we want to avoid L1 evictions
+ * by the processes running on the same package. One thing we can do
+ * is to shuffle the initial stack for them.
+ *
+ * The conditionals here are unneeded, but kept in to make the
+ * code behaviour the same as pre change unless we have hyperthreaded
+ * processors. This should be cleaned up before 2.6
+ */
+
+ if(smp_num_siblings > 1)
+ u_platform = u_platform - ((current->pid % 64) << 7);
+#endif
+
/*
* Force 16 byte _final_ alignment here for generality.
*/
@@ -553,7 +568,6 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
SET_PERSONALITY(elf_ex, ibcs2_interpreter);
}
-
/* OK, we are done with that, now set up the arg stuff,
and then start this sucker up */
diff --git a/fs/bio.c b/fs/bio.c
index a83b018c227fa..4a3dde467b9a8 100644
--- a/fs/bio.c
+++ b/fs/bio.c
@@ -328,7 +328,7 @@ static void bio_end_io_kio(struct bio *bio)
* ll_rw_kio - submit a &struct kiobuf for I/O
* @rw: %READ or %WRITE
* @kio: the kiobuf to do I/O on
- * @dev: target device
+ * @bdev: target device
* @sector: start location on disk
*
* Description:
@@ -336,11 +336,12 @@ static void bio_end_io_kio(struct bio *bio)
* &struct bio and queue them for I/O. The kiobuf given must describe
* a continous range of data, and must be fully prepared for I/O.
**/
-void ll_rw_kio(int rw, struct kiobuf *kio, kdev_t dev, sector_t sector)
+void ll_rw_kio(int rw, struct kiobuf *kio, struct block_device *bdev, sector_t sector)
{
int i, offset, size, err, map_i, total_nr_pages, nr_pages;
struct bio_vec *bvec;
struct bio *bio;
+ kdev_t dev = to_kdev_t(bdev->bd_dev);
err = 0;
if ((rw & WRITE) && is_read_only(dev)) {
diff --git a/fs/buffer.c b/fs/buffer.c
index a27c47330b21b..784ae1957aca5 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -795,8 +795,11 @@ static void end_buffer_io_async(struct buffer_head * bh, int uptodate)
unlock_buffer(bh);
tmp = bh->b_this_page;
while (tmp != bh) {
- if (buffer_async(tmp) && buffer_locked(tmp))
- goto still_busy;
+ if (buffer_locked(tmp)) {
+ if (buffer_async(tmp))
+ goto still_busy;
+ } else if (!buffer_uptodate(tmp))
+ SetPageError(page);
tmp = tmp->b_this_page;
}
@@ -1716,7 +1719,7 @@ int block_read_full_page(struct page *page, get_block_t *get_block)
if (!buffer_mapped(bh)) {
if (iblock < lblock) {
if (get_block(inode, iblock, bh, 0))
- continue;
+ SetPageError(page);
}
if (!buffer_mapped(bh)) {
memset(kmap(page) + i*blocksize, 0, blocksize);
@@ -1736,10 +1739,11 @@ int block_read_full_page(struct page *page, get_block_t *get_block)
if (!nr) {
/*
- * all buffers are uptodate - we can set the page
- * uptodate as well.
+ * All buffers are uptodate - we can set the page uptodate
+ * as well. But not if get_block() returned an error.
*/
- SetPageUptodate(page);
+ if (!PageError(page))
+ SetPageUptodate(page);
UnlockPage(page);
return 0;
}
@@ -2122,7 +2126,7 @@ int generic_direct_IO(int rw, struct inode * inode, struct kiobuf * iobuf, unsig
}
/* This does not understand multi-device filesystems currently */
- retval = brw_kiovec(rw, 1, &iobuf, inode->i_dev, blocks, blocksize);
+ retval = brw_kiovec(rw, 1, &iobuf, inode->i_sb->s_bdev, blocks, blocksize);
out:
return retval;
@@ -2138,8 +2142,8 @@ int generic_direct_IO(int rw, struct inode * inode, struct kiobuf * iobuf, unsig
* It is up to the caller to make sure that there are enough blocks
* passed in to completely map the iobufs to disk.
*/
-int brw_kiovec(int rw, int nr, struct kiobuf *iovec[], kdev_t dev, sector_t b[],
- int size)
+int brw_kiovec(int rw, int nr, struct kiobuf *iovec[],
+ struct block_device *bdev, sector_t b[], int size)
{
int transferred;
int i;
@@ -2167,7 +2171,7 @@ int brw_kiovec(int rw, int nr, struct kiobuf *iovec[], kdev_t dev, sector_t b[],
iobuf = iovec[i];
iobuf->errno = 0;
- ll_rw_kio(rw, iobuf, dev, b[i] * (size >> 9));
+ ll_rw_kio(rw, iobuf, bdev, b[i] * (size >> 9));
}
/*
diff --git a/fs/devpts/inode.c b/fs/devpts/inode.c
index 742a42d8a519d..231bc91cd79d5 100644
--- a/fs/devpts/inode.c
+++ b/fs/devpts/inode.c
@@ -66,9 +66,9 @@ static int devpts_parse_options(char *options, struct devpts_sb_info *sbi)
char *this_char, *value;
this_char = NULL;
- if ( options )
- this_char = strtok(options,",");
- for ( ; this_char; this_char = strtok(NULL,",")) {
+ while ((this_char = strsep(&options, ",")) != NULL) {
+ if (!*this_char)
+ continue;
if ((value = strchr(this_char,'=')) != NULL)
*value++ = 0;
if (!strcmp(this_char,"uid")) {
@@ -123,9 +123,10 @@ static int devpts_fill_super(struct super_block *s, void *data, int silent)
struct inode * inode;
struct devpts_sb_info *sbi;
- sbi = (struct devpts_sb_info *) kmalloc(sizeof(struct devpts_sb_info), GFP_KERNEL);
+ sbi = kmalloc(sizeof(*sbi), GFP_KERNEL);
if ( !sbi )
goto fail;
+ memset(sbi, 0, sizeof(*sbi));
sbi->magic = DEVPTS_SBI_MAGIC;
sbi->max_ptys = unix98_max_ptys;
diff --git a/fs/dquot.c b/fs/dquot.c
index bfe793b6669ad..1aaed4771fa38 100644
--- a/fs/dquot.c
+++ b/fs/dquot.c
@@ -59,6 +59,7 @@
#include <linux/tty.h>
#include <linux/file.h>
#include <linux/slab.h>
+#include <linux/sysctl.h>
#include <linux/smp_lock.h>
#include <linux/init.h>
@@ -1240,10 +1241,23 @@ warn_put_all:
return ret;
}
+static ctl_table fs_table[] = {
+ {FS_NRDQUOT, "dquot-nr", &nr_dquots, 2*sizeof(int),
+ 0444, NULL, &proc_dointvec},
+ {},
+};
+
+static ctl_table dquot_table[] = {
+ {CTL_FS, "fs", NULL, 0, 0555, fs_table},
+ {},
+};
+
static int __init dquot_init(void)
{
int i;
+ register_sysctl_table(dquot_table, 0);
+
for (i = 0; i < NR_DQHASH; i++)
INIT_LIST_HEAD(dquot_hash + i);
printk(KERN_NOTICE "VFS: Diskquotas version %s initialized\n", __DQUOT_VERSION__);
diff --git a/fs/ext2/super.c b/fs/ext2/super.c
index c11c360401672..d4fcb94cac458 100644
--- a/fs/ext2/super.c
+++ b/fs/ext2/super.c
@@ -221,9 +221,9 @@ static int parse_options (char * options, unsigned long * sb_block,
if (!options)
return 1;
- for (this_char = strtok (options, ",");
- this_char != NULL;
- this_char = strtok (NULL, ",")) {
+ while ((this_char = strsep (&options, ",")) != NULL) {
+ if (!*this_char)
+ continue;
if ((value = strchr (this_char, '=')) != NULL)
*value++ = 0;
if (!strcmp (this_char, "bsddf"))
@@ -465,11 +465,11 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent)
int db_count;
int i, j;
- sbi = kmalloc(sizeof(struct ext2_super_block), GFP_KERNEL);
+ sbi = kmalloc(sizeof(*sbi), GFP_KERNEL);
if (!sbi)
return -ENOMEM;
sb->u.generic_sbp = sbi;
- memset(sbi, 0, sizeof(struct ext2_super_block));
+ memset(sbi, 0, sizeof(*sbi));
/*
* See what the current blocksize for the device is, and
diff --git a/fs/ext3/super.c b/fs/ext3/super.c
index 7b5d962906859..8f1f16623b0a5 100644
--- a/fs/ext3/super.c
+++ b/fs/ext3/super.c
@@ -554,9 +554,9 @@ static int parse_options (char * options, unsigned long * sb_block,
if (!options)
return 1;
- for (this_char = strtok (options, ",");
- this_char != NULL;
- this_char = strtok (NULL, ",")) {
+ while ((this_char = strsep (&options, ",")) != NULL) {
+ if (!*this_char)
+ continue;
if ((value = strchr (this_char, '=')) != NULL)
*value++ = 0;
if (!strcmp (this_char, "bsddf"))
diff --git a/fs/fat/inode.c b/fs/fat/inode.c
index b2e6f985e5abc..b5f9f42273958 100644
--- a/fs/fat/inode.c
+++ b/fs/fat/inode.c
@@ -177,7 +177,6 @@ void fat_put_super(struct super_block *sb)
fat_clusters_flush(sb);
}
fat_cache_inval_dev(sb);
- set_blocksize (sb->s_dev,BLOCK_SIZE);
if (sbi->nls_disk) {
unload_nls(sbi->nls_disk);
sbi->nls_disk = NULL;
@@ -225,8 +224,9 @@ static int parse_options(char *options, int *debug,
goto out;
save = 0;
savep = NULL;
- for (this_char = strtok(options,","); this_char;
- this_char = strtok(NULL,",")) {
+ while ((this_char = strsep(&options,",")) != NULL) {
+ if (!*this_char)
+ continue;
if ((value = strchr(this_char,'=')) != NULL) {
save = *value;
savep = value;
diff --git a/fs/filesystems.c b/fs/filesystems.c
index 9d924215e12c3..996dd9fd73353 100644
--- a/fs/filesystems.c
+++ b/fs/filesystems.c
@@ -6,10 +6,9 @@
* table of configured filesystems
*/
-#include <linux/config.h>
+#include <linux/fs.h>
#include <linux/slab.h>
#include <linux/kmod.h>
-#define __NO_VERSION__
#include <linux/module.h>
#include <asm/uaccess.h>
diff --git a/fs/hfs/super.c b/fs/hfs/super.c
index 934310f4f35ca..56024b013ddb9 100644
--- a/fs/hfs/super.c
+++ b/fs/hfs/super.c
@@ -32,6 +32,8 @@
#include <linux/module.h>
#include <linux/init.h>
+MODULE_LICENSE("GPL");
+
/*================ Forward declarations ================*/
static void hfs_read_inode(struct inode *);
@@ -176,9 +178,6 @@ static void hfs_put_super(struct super_block *sb)
/* release the MDB's resources */
hfs_mdb_put(mdb, sb->s_flags & MS_RDONLY);
- /* restore default blocksize for the device */
- set_blocksize(sb->s_dev, BLOCK_SIZE);
-
kfree(sb->u.generic_sbp);
sb->u.generic_sbp = NULL;
}
@@ -240,8 +239,9 @@ static int parse_options(char *options, struct hfs_sb_info *hsb, int *part)
if (!options) {
goto done;
}
- for (this_char = strtok(options,","); this_char;
- this_char = strtok(NULL,",")) {
+ while ((this_char = strsep(&options,",")) != NULL) {
+ if (!*this_char)
+ continue;
if ((value = strchr(this_char,'=')) != NULL) {
*value++ = 0;
}
@@ -449,7 +449,6 @@ int hfs_fill_super(struct super_block *s, void *data, int silent)
struct hfs_sb_info *sbi;
struct hfs_mdb *mdb;
struct hfs_cat_key key;
- kdev_t dev = s->s_dev;
hfs_s32 part_size, part_start;
struct inode *root_inode;
int part;
@@ -462,7 +461,7 @@ int hfs_fill_super(struct super_block *s, void *data, int silent)
if (!parse_options((char *)data, sbi, &part)) {
hfs_warn("hfs_fs: unable to parse mount options.\n");
- goto bail3;
+ goto bail2;
}
/* set the device driver to 512-byte blocks */
@@ -530,10 +529,8 @@ bail_no_root:
bail1:
hfs_mdb_put(mdb, s->s_flags & MS_RDONLY);
bail2:
- set_blocksize(dev, BLOCK_SIZE);
-bail3:
kfree(sbi);
- sb->u.generic_sbp = NULL;
+ s->u.generic_sbp = NULL;
return -EINVAL;
}
diff --git a/fs/hpfs/super.c b/fs/hpfs/super.c
index 3fc140ea1c18e..09aa44db499a8 100644
--- a/fs/hpfs/super.c
+++ b/fs/hpfs/super.c
@@ -3,7 +3,7 @@
*
* Mikulas Patocka (mikulas@artax.karlin.mff.cuni.cz), 1998-1999
*
- * mouning, unmounting, error handling
+ * mounting, unmounting, error handling
*/
#include <linux/string.h>
@@ -222,7 +222,9 @@ int parse_opts(char *opts, uid_t *uid, gid_t *gid, umode_t *umask,
/*printk("Parsing opts: '%s'\n",opts);*/
- for (p = strtok(opts, ","); p != 0; p = strtok(0, ",")) {
+ while ((p = strsep(&opts, ",")) != NULL) {
+ if (!*p)
+ continue;
if ((rhs = strchr(p, '=')) != 0)
*rhs++ = '\0';
if (!strcmp(p, "help")) return 2;
diff --git a/fs/inode.c b/fs/inode.c
index c8a205f2df78c..cbe7d2eeb3498 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -657,10 +657,14 @@ int invalidate_inodes(struct super_block * sb)
int invalidate_device(kdev_t dev, int do_sync)
{
struct super_block *sb;
+ struct block_device *bdev = bdget(kdev_t_to_nr(dev));
int res;
+ if (!bdev)
+ return 0;
+
if (do_sync)
- fsync_dev(dev);
+ fsync_bdev(bdev);
res = 0;
sb = get_super(dev);
@@ -675,7 +679,8 @@ int invalidate_device(kdev_t dev, int do_sync)
res = invalidate_inodes(sb);
drop_super(sb);
}
- invalidate_buffers(dev);
+ invalidate_bdev(bdev, 0);
+ bdput(bdev);
return res;
}
@@ -1191,6 +1196,8 @@ static inline void do_atime_update(struct inode *inode)
void update_atime (struct inode *inode)
{
+ if (inode->i_atime == CURRENT_TIME)
+ return;
if ( IS_NOATIME (inode) ) return;
if ( IS_NODIRATIME (inode) && S_ISDIR (inode->i_mode) ) return;
if ( IS_RDONLY (inode) ) return;
diff --git a/fs/intermezzo/super.c b/fs/intermezzo/super.c
index de9d181359dcf..4a9358f82c07a 100644
--- a/fs/intermezzo/super.c
+++ b/fs/intermezzo/super.c
@@ -120,12 +120,12 @@ static char *presto_options(char *options, char *cache_data,
store_opt(prestodev, NULL, PRESTO_PSDEV_NAME "0");
CDEBUG(D_SUPER, "parsing options\n");
- for (this_char = strtok (options, ",");
- this_char != NULL;
- this_char = strtok (NULL, ",")) {
+ while ((this_char = strsep (&options, ",")) != NULL) {
char *opt;
CDEBUG(D_SUPER, "this_char %s\n", this_char);
+ if (!*this_char)
+ continue;
if ( (opt = read_opt("fileset", this_char)) ) {
store_opt(fileset, opt, NULL);
continue;
diff --git a/fs/iobuf.c b/fs/iobuf.c
index 3f9e5642faafd..ab2188fc3e7a1 100644
--- a/fs/iobuf.c
+++ b/fs/iobuf.c
@@ -28,11 +28,14 @@ int end_kio_request(struct kiobuf *kiobuf, int uptodate)
static void kiobuf_init(struct kiobuf *iobuf)
{
- memset(iobuf, 0, sizeof(*iobuf));
init_waitqueue_head(&iobuf->wait_queue);
atomic_set(&iobuf->io_count, 0);
iobuf->array_len = KIO_STATIC_PAGES;
iobuf->maplist = iobuf->map_array;
+ iobuf->nr_pages = 0;
+ iobuf->locked = 0;
+ iobuf->io_count.counter = 0;
+ iobuf->end_io = NULL;
}
int alloc_kiovec(int nr, struct kiobuf **bufp)
diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c
index 31174ae2bedee..d4e9ad9a6dd3c 100644
--- a/fs/isofs/inode.c
+++ b/fs/isofs/inode.c
@@ -341,7 +341,9 @@ static int parse_options(char *options, struct iso9660_options * popt)
popt->session=-1;
popt->sbsector=-1;
if (!options) return 1;
- for (this_char = strtok(options,","); this_char; this_char = strtok(NULL,",")) {
+ while ((this_char = strsep(&options,",")) != NULL) {
+ if (!*this_char)
+ continue;
if (strncmp(this_char,"norock",6) == 0) {
popt->rock = 'n';
continue;
diff --git a/fs/jbd/journal.c b/fs/jbd/journal.c
index 169b8f4f3c22c..7f0e69be25ed8 100644
--- a/fs/jbd/journal.c
+++ b/fs/jbd/journal.c
@@ -894,7 +894,7 @@ int journal_create (journal_t *journal)
__brelse(bh);
}
- fsync_dev(to_kdev_t(journal->j_dev->bd_dev));
+ fsync_bdev(journal->j_dev);
jbd_debug(1, "JBD: journal cleared.\n");
/* OK, fill in the initial static fields in the new superblock */
diff --git a/fs/jfs/jfs_logmgr.c b/fs/jfs/jfs_logmgr.c
index 0d243fba0f828..2f7c1e8fa43d8 100644
--- a/fs/jfs/jfs_logmgr.c
+++ b/fs/jfs/jfs_logmgr.c
@@ -66,6 +66,7 @@
#include <linux/blkdev.h>
#include <linux/interrupt.h>
#include <linux/smp_lock.h>
+#include <linux/completion.h>
#include "jfs_incore.h"
#include "jfs_filsys.h"
#include "jfs_metapage.h"
@@ -1594,7 +1595,7 @@ static int lmLogFileSystem(log_t * log, dev_t fsdev, int activate)
return rc;
logsuper = (logsuper_t *) bpsuper->l_ldata;
- bit = MINOR(fsdev);
+ bit = minor(fsdev);
word = bit / 32;
bit -= 32 * word;
if (activate)
diff --git a/fs/jfs/jfs_txnmgr.c b/fs/jfs/jfs_txnmgr.c
index 6c5a6312819a8..893dbf26aae38 100644
--- a/fs/jfs/jfs_txnmgr.c
+++ b/fs/jfs/jfs_txnmgr.c
@@ -47,6 +47,7 @@
#include <linux/locks.h>
#include <linux/vmalloc.h>
#include <linux/smp_lock.h>
+#include <linux/completion.h>
#include "jfs_incore.h"
#include "jfs_filsys.h"
#include "jfs_metapage.h"
@@ -2777,6 +2778,7 @@ int jfs_lazycommit(void)
complete(&jfsIOwait);
do {
+ LAZY_LOCK(flags);
restart:
WorkDone = 0;
while ((tblk = TxAnchor.unlock_queue)) {
@@ -2788,7 +2790,6 @@ restart:
*/
WorkDone = 1;
- LAZY_LOCK(flags);
/*
* Remove first transaction from queue
*/
@@ -2808,11 +2809,13 @@ restart:
current->state = TASK_RUNNING;
schedule();
}
+ LAZY_LOCK(flags);
}
if (WorkDone)
goto restart;
-
+
+ LAZY_UNLOCK(flags);
set_current_state(TASK_INTERRUPTIBLE);
schedule();
} while (!jfs_thread_stopped());
diff --git a/fs/jfs/super.c b/fs/jfs/super.c
index c0900217f422d..dec4af2fac465 100644
--- a/fs/jfs/super.c
+++ b/fs/jfs/super.c
@@ -22,6 +22,7 @@
#include <linux/config.h>
#include <linux/module.h>
#include <linux/slab.h>
+#include <linux/completion.h>
#include <asm/uaccess.h>
#include "jfs_incore.h"
#include "jfs_filsys.h"
@@ -170,9 +171,9 @@ static int parse_options (char * options, struct jfs_sb_info *sbi)
if (!options)
return 1;
- for (this_char = strtok (options, ",");
- this_char != NULL;
- this_char = strtok (NULL, ",")) {
+ while ((this_char = strsep (&options, ",")) != NULL) {
+ if (!*this_char)
+ continue;
if ((value = strchr (this_char, '=')) != NULL)
*value++ = 0;
if (!strcmp (this_char, "iocharset")) {
@@ -268,10 +269,7 @@ static int jfs_fill_super(struct super_block *sb, void *data, int silent)
/*
* Initialize blocksize to 4K.
*/
- sb->s_blocksize = PSIZE;
- sb->s_blocksize_bits = L2PSIZE;
- set_blocksize(sb->s_dev, PSIZE);
-
+ sb_set_blocksize(sb, PSIZE);
sb->s_op = &jfs_sops;
/*
* Initialize direct-mapping inode/address-space
diff --git a/fs/minix/bitmap.c b/fs/minix/bitmap.c
index dbfe98f395058..5725962dbb0a7 100644
--- a/fs/minix/bitmap.c
+++ b/fs/minix/bitmap.c
@@ -11,10 +11,8 @@
/* bitmap.c contains the code that handles the inode and block bitmaps */
-#include <linux/fs.h>
-#include <linux/minix_fs.h>
-#include <linux/locks.h>
-
+#include "minix.h"
+#include <linux/smp_lock.h>
#include <asm/bitops.h>
static int nibblemap[] = { 4,3,3,2,3,2,2,1,3,2,2,1,2,1,1,0 };
@@ -56,12 +54,7 @@ void minix_free_block(struct inode * inode, int block)
struct buffer_head * bh;
unsigned int bit,zone;
- if (!sb) {
- printk("trying to free block on nonexistent device\n");
- return;
- }
- if (block < sbi->s_firstdatazone ||
- block >= sbi->s_nzones) {
+ if (block < sbi->s_firstdatazone || block >= sbi->s_nzones) {
printk("trying to free block not in datazone\n");
return;
}
@@ -73,49 +66,41 @@ void minix_free_block(struct inode * inode, int block)
return;
}
bh = sbi->s_zmap[zone];
+ lock_kernel();
if (!minix_test_and_clear_bit(bit,bh->b_data))
printk("free_block (%s:%d): bit already cleared\n",
sb->s_id, block);
+ unlock_kernel();
mark_buffer_dirty(bh);
return;
}
int minix_new_block(struct inode * inode)
{
- struct super_block * sb = inode->i_sb;
- struct minix_sb_info * sbi = minix_sb(sb);
- struct buffer_head * bh;
- int i,j;
+ struct minix_sb_info *sbi = minix_sb(inode->i_sb);
+ int i;
- if (!sb) {
- printk("trying to get new block from nonexistent device\n");
- return 0;
- }
-repeat:
- j = 8192;
- bh = NULL;
for (i = 0; i < sbi->s_zmap_blocks; i++) {
- bh = sbi->s_zmap[i];
- if ((j = minix_find_first_zero_bit(bh->b_data, 8192)) < 8192)
- break;
- }
- if (!bh || j >= 8192)
- return 0;
- if (minix_test_and_set_bit(j,bh->b_data)) {
- printk("new_block: bit already set");
- goto repeat;
+ struct buffer_head *bh = sbi->s_zmap[i];
+ int j;
+
+ lock_kernel();
+ if ((j = minix_find_first_zero_bit(bh->b_data, 8192)) < 8192) {
+ minix_set_bit(j,bh->b_data);
+ unlock_kernel();
+ mark_buffer_dirty(bh);
+ j += i*8192 + sbi->s_firstdatazone-1;
+ if (j < sbi->s_firstdatazone || j >= sbi->s_nzones)
+ break;
+ return j;
+ }
+ unlock_kernel();
}
- mark_buffer_dirty(bh);
- j += i*8192 + sbi->s_firstdatazone-1;
- if (j < sbi->s_firstdatazone ||
- j >= sbi->s_nzones)
- return 0;
- return j;
+ return 0;
}
-unsigned long minix_count_free_blocks(struct super_block *sb)
+unsigned long minix_count_free_blocks(struct minix_sb_info *sbi)
{
- struct minix_sb_info *sbi = minix_sb(sb);
return (count_free(sbi->s_zmap, sbi->s_zmap_blocks,
sbi->s_nzones - sbi->s_firstdatazone + 1)
<< sbi->s_log_zone_size);
@@ -198,36 +183,38 @@ static void minix_clear_inode(struct inode *inode)
void minix_free_inode(struct inode * inode)
{
+ struct minix_sb_info *sbi = minix_sb(inode->i_sb);
struct buffer_head * bh;
unsigned long ino;
- if (inode->i_ino < 1 || inode->i_ino > minix_sb(inode->i_sb)->s_ninodes) {
+ if (inode->i_ino < 1 || inode->i_ino > sbi->s_ninodes) {
printk("free_inode: inode 0 or nonexistent inode\n");
return;
}
ino = inode->i_ino;
- if ((ino >> 13) >= minix_sb(inode->i_sb)->s_imap_blocks) {
+ if ((ino >> 13) >= sbi->s_imap_blocks) {
printk("free_inode: nonexistent imap in superblock\n");
return;
}
- bh = minix_sb(inode->i_sb)->s_imap[ino >> 13];
+ bh = sbi->s_imap[ino >> 13];
minix_clear_inode(inode);
clear_inode(inode);
+ lock_kernel();
if (!minix_test_and_clear_bit(ino & 8191, bh->b_data))
printk("free_inode: bit %lu already cleared.\n",ino);
+ unlock_kernel();
mark_buffer_dirty(bh);
}
struct inode * minix_new_inode(const struct inode * dir, int * error)
{
- struct super_block * sb;
- struct inode * inode;
+ struct super_block *sb = dir->i_sb;
+ struct minix_sb_info *sbi = minix_sb(sb);
+ struct inode *inode = new_inode(sb);
struct buffer_head * bh;
int i,j;
- sb = dir->i_sb;
- inode = new_inode(sb);
if (!inode) {
*error = -ENOMEM;
return NULL;
@@ -235,28 +222,28 @@ struct inode * minix_new_inode(const struct inode * dir, int * error)
j = 8192;
bh = NULL;
*error = -ENOSPC;
- lock_super(sb);
- for (i = 0; i < minix_sb(sb)->s_imap_blocks; i++) {
- bh = minix_sb(inode->i_sb)->s_imap[i];
+ lock_kernel();
+ for (i = 0; i < sbi->s_imap_blocks; i++) {
+ bh = sbi->s_imap[i];
if ((j = minix_find_first_zero_bit(bh->b_data, 8192)) < 8192)
break;
}
if (!bh || j >= 8192) {
+ unlock_kernel();
iput(inode);
- unlock_super(sb);
return NULL;
}
if (minix_test_and_set_bit(j,bh->b_data)) { /* shouldn't happen */
printk("new_inode: bit already set");
+ unlock_kernel();
iput(inode);
- unlock_super(sb);
return NULL;
}
+ unlock_kernel();
mark_buffer_dirty(bh);
j += i*8192;
- if (!j || j > minix_sb(inode->i_sb)->s_ninodes) {
+ if (!j || j > sbi->s_ninodes) {
iput(inode);
- unlock_super(sb);
return NULL;
}
inode->i_uid = current->fsuid;
@@ -268,13 +255,11 @@ struct inode * minix_new_inode(const struct inode * dir, int * error)
insert_inode_hash(inode);
mark_inode_dirty(inode);
- unlock_super(sb);
*error = 0;
return inode;
}
-unsigned long minix_count_free_inodes(struct super_block *sb)
+unsigned long minix_count_free_inodes(struct minix_sb_info *sbi)
{
- return count_free(minix_sb(sb)->s_imap, minix_sb(sb)->s_imap_blocks,
- minix_sb(sb)->s_ninodes + 1);
+ return count_free(sbi->s_imap, sbi->s_imap_blocks, sbi->s_ninodes + 1);
}
diff --git a/fs/minix/dir.c b/fs/minix/dir.c
index 88b11f7ffaee2..18022e977903a 100644
--- a/fs/minix/dir.c
+++ b/fs/minix/dir.c
@@ -6,9 +6,7 @@
* minix directory handling functions
*/
-#include <linux/fs.h>
-#include <linux/minix_fs.h>
-#include <linux/pagemap.h>
+#include "minix.h"
typedef struct minix_dir_entry minix_dirent;
diff --git a/fs/minix/file.c b/fs/minix/file.c
index ab8682902b267..63352bb8cc3e0 100644
--- a/fs/minix/file.c
+++ b/fs/minix/file.c
@@ -6,8 +6,7 @@
* minix regular file handling primitives
*/
-#include <linux/fs.h>
-#include <linux/minix_fs.h>
+#include "minix.h"
/*
* We have mostly NULLs here: the current defaults are OK for
diff --git a/fs/minix/inode.c b/fs/minix/inode.c
index 5659fea7a54c9..10fdf3f6973e4 100644
--- a/fs/minix/inode.c
+++ b/fs/minix/inode.c
@@ -10,15 +10,11 @@
*/
#include <linux/module.h>
-
-#include <linux/fs.h>
-#include <linux/minix_fs.h>
+#include "minix.h"
#include <linux/slab.h>
#include <linux/locks.h>
#include <linux/init.h>
-#include <linux/smp_lock.h>
#include <linux/highuid.h>
-#include <linux/blkdev.h>
static void minix_read_inode(struct inode * inode);
static void minix_write_inode(struct inode * inode, int wait);
@@ -29,32 +25,9 @@ static void minix_delete_inode(struct inode *inode)
{
inode->i_size = 0;
minix_truncate(inode);
- lock_kernel();
minix_free_inode(inode);
- unlock_kernel();
-}
-
-static void minix_commit_super(struct super_block * sb)
-{
- mark_buffer_dirty(minix_sb(sb)->s_sbh);
- sb->s_dirt = 0;
-}
-
-static void minix_write_super(struct super_block * sb)
-{
- struct minix_super_block * ms;
-
- if (!(sb->s_flags & MS_RDONLY)) {
- ms = minix_sb(sb)->s_ms;
-
- if (ms->s_state & MINIX_VALID_FS)
- ms->s_state &= ~MINIX_VALID_FS;
- minix_commit_super(sb);
- }
- sb->s_dirt = 0;
}
-
static void minix_put_super(struct super_block *sb)
{
int i;
@@ -125,7 +98,6 @@ static struct super_operations minix_sops = {
write_inode: minix_write_inode,
delete_inode: minix_delete_inode,
put_super: minix_put_super,
- write_super: minix_write_super,
statfs: minix_statfs,
remount_fs: minix_remount,
};
@@ -145,15 +117,11 @@ static int minix_remount (struct super_block * sb, int * flags, char * data)
/* Mounting a rw partition read-only. */
ms->s_state = sbi->s_mount_state;
mark_buffer_dirty(sbi->s_sbh);
- sb->s_dirt = 1;
- minix_commit_super(sb);
- }
- else {
+ } else {
/* Mount a partition which is read-only, read-write. */
sbi->s_mount_state = ms->s_state;
ms->s_state &= ~MINIX_VALID_FS;
mark_buffer_dirty(sbi->s_sbh);
- sb->s_dirt = 1;
if (!(sbi->s_mount_state & MINIX_VALID_FS))
printk ("MINIX-fs warning: remounting unchecked fs, "
@@ -272,7 +240,6 @@ static int minix_fill_super(struct super_block *s, void *data, int silent)
if (!(s->s_flags & MS_RDONLY)) {
ms->s_state &= ~MINIX_VALID_FS;
mark_buffer_dirty(bh);
- s->s_dirt = 1;
}
if (!(sbi->s_mount_state & MINIX_VALID_FS))
printk ("MINIX-fs: mounting unchecked file system, "
@@ -332,10 +299,10 @@ static int minix_statfs(struct super_block *sb, struct statfs *buf)
buf->f_type = sb->s_magic;
buf->f_bsize = sb->s_blocksize;
buf->f_blocks = (sbi->s_nzones - sbi->s_firstdatazone) << sbi->s_log_zone_size;
- buf->f_bfree = minix_count_free_blocks(sb);
+ buf->f_bfree = minix_count_free_blocks(sbi);
buf->f_bavail = buf->f_bfree;
buf->f_files = sbi->s_ninodes;
- buf->f_ffree = minix_count_free_inodes(sb);
+ buf->f_ffree = minix_count_free_inodes(sbi);
buf->f_namelen = sbi->s_namelen;
return 0;
}
@@ -526,12 +493,7 @@ static struct buffer_head *minix_update_inode(struct inode *inode)
static void minix_write_inode(struct inode * inode, int wait)
{
- struct buffer_head *bh;
-
- lock_kernel();
- bh = minix_update_inode(inode);
- unlock_kernel();
- brelse(bh);
+ brelse(minix_update_inode(inode));
}
int minix_sync_inode(struct inode * inode)
@@ -562,12 +524,10 @@ int minix_sync_inode(struct inode * inode)
*/
void minix_truncate(struct inode * inode)
{
- lock_kernel();
if (INODE_VERSION(inode) == MINIX_V1)
V1_minix_truncate(inode);
else
V2_minix_truncate(inode);
- unlock_kernel();
}
static struct super_block *minix_get_sb(struct file_system_type *fs_type,
diff --git a/fs/minix/itree_common.c b/fs/minix/itree_common.c
index 41c0acb30a297..692f3043090a9 100644
--- a/fs/minix/itree_common.c
+++ b/fs/minix/itree_common.c
@@ -6,6 +6,8 @@ typedef struct {
struct buffer_head *bh;
} Indirect;
+static rwlock_t pointers_lock = RW_LOCK_UNLOCKED;
+
static inline void add_chain(Indirect *p, struct buffer_head *bh, block_t *v)
{
p->key = *(p->p = v);
@@ -43,17 +45,18 @@ static inline Indirect *get_branch(struct inode *inode,
bh = sb_bread(sb, block_to_cpu(p->key));
if (!bh)
goto failure;
- /* Reader: pointers */
+ read_lock(&pointers_lock);
if (!verify_chain(chain, p))
goto changed;
add_chain(++p, bh, (block_t *)bh->b_data + *++offsets);
- /* Reader: end */
+ read_unlock(&pointers_lock);
if (!p->key)
goto no_block;
}
return NULL;
changed:
+ read_unlock(&pointers_lock);
*err = -EAGAIN;
goto no_block;
failure:
@@ -108,18 +111,15 @@ static inline int splice_branch(struct inode *inode,
{
int i;
- /* Verify that place we are splicing to is still there and vacant */
+ write_lock(&pointers_lock);
- /* Writer: pointers */
+ /* Verify that place we are splicing to is still there and vacant */
if (!verify_chain(chain, where-1) || *where->p)
- /* Writer: end */
goto changed;
- /* That's it */
-
*where->p = where->key;
- /* Writer: end */
+ write_unlock(&pointers_lock);
/* We are done with atomic stuff, now do the rest of housekeeping */
@@ -133,6 +133,7 @@ static inline int splice_branch(struct inode *inode,
return 0;
changed:
+ write_unlock(&pointers_lock);
for (i = 1; i < num; i++)
bforget(where[i].bh);
for (i = 0; i < num; i++)
@@ -153,7 +154,6 @@ static inline int get_block(struct inode * inode, sector_t block,
if (depth == 0)
goto out;
- lock_kernel();
reread:
partial = get_branch(inode, depth, offsets, chain, &err);
@@ -173,7 +173,6 @@ cleanup:
brelse(partial->bh);
partial--;
}
- unlock_kernel();
out:
return err;
}
@@ -226,12 +225,14 @@ static Indirect *find_shared(struct inode *inode,
for (k = depth; k > 1 && !offsets[k-1]; k--)
;
partial = get_branch(inode, k, offsets, chain, &err);
- /* Writer: pointers */
+
+ write_lock(&pointers_lock);
if (!partial)
partial = chain + k-1;
- if (!partial->key && *partial->p)
- /* Writer: end */
+ if (!partial->key && *partial->p) {
+ write_unlock(&pointers_lock);
goto no_top;
+ }
for (p=partial;p>chain && all_zeroes((block_t*)p->bh->b_data,p->p);p--)
;
if (p == chain + k - 1 && p > chain) {
@@ -240,7 +241,7 @@ static Indirect *find_shared(struct inode *inode,
*top = *p->p;
*p->p = 0;
}
- /* Writer: end */
+ write_unlock(&pointers_lock);
while(partial > p)
{
diff --git a/fs/minix/itree_v1.c b/fs/minix/itree_v1.c
index a6826ed6de821..83064f69675fd 100644
--- a/fs/minix/itree_v1.c
+++ b/fs/minix/itree_v1.c
@@ -1,7 +1,5 @@
-#include <linux/fs.h>
-#include <linux/minix_fs.h>
+#include "minix.h"
#include <linux/locks.h>
-#include <linux/smp_lock.h>
enum {DEPTH = 3, DIRECT = 7}; /* Only double indirect */
diff --git a/fs/minix/itree_v2.c b/fs/minix/itree_v2.c
index c438457af392d..80885cc9b437e 100644
--- a/fs/minix/itree_v2.c
+++ b/fs/minix/itree_v2.c
@@ -1,7 +1,5 @@
-#include <linux/fs.h>
-#include <linux/minix_fs.h>
+#include "minix.h"
#include <linux/locks.h>
-#include <linux/smp_lock.h>
enum {DIRECT = 7, DEPTH = 4}; /* Have triple indirect */
diff --git a/fs/minix/minix.h b/fs/minix/minix.h
new file mode 100644
index 0000000000000..653fc977c31b5
--- /dev/null
+++ b/fs/minix/minix.h
@@ -0,0 +1,91 @@
+#include <linux/fs.h>
+#include <linux/pagemap.h>
+#include <linux/minix_fs.h>
+
+/*
+ * change the define below to 0 if you want names > info->s_namelen chars to be
+ * truncated. Else they will be disallowed (ENAMETOOLONG).
+ */
+#define NO_TRUNCATE 1
+
+#define INODE_VERSION(inode) minix_sb(inode->i_sb)->s_version
+
+#define MINIX_V1 0x0001 /* original minix fs */
+#define MINIX_V2 0x0002 /* minix V2 fs */
+
+/*
+ * minix fs inode data in memory
+ */
+struct minix_inode_info {
+ union {
+ __u16 i1_data[16];
+ __u32 i2_data[16];
+ } u;
+ struct inode vfs_inode;
+};
+
+/*
+ * minix super-block data in memory
+ */
+struct minix_sb_info {
+ unsigned long s_ninodes;
+ unsigned long s_nzones;
+ unsigned long s_imap_blocks;
+ unsigned long s_zmap_blocks;
+ unsigned long s_firstdatazone;
+ unsigned long s_log_zone_size;
+ unsigned long s_max_size;
+ int s_dirsize;
+ int s_namelen;
+ int s_link_max;
+ struct buffer_head ** s_imap;
+ struct buffer_head ** s_zmap;
+ struct buffer_head * s_sbh;
+ struct minix_super_block * s_ms;
+ unsigned short s_mount_state;
+ unsigned short s_version;
+};
+
+extern struct minix_inode * minix_V1_raw_inode(struct super_block *, ino_t, struct buffer_head **);
+extern struct minix2_inode * minix_V2_raw_inode(struct super_block *, ino_t, struct buffer_head **);
+extern struct inode * minix_new_inode(const struct inode * dir, int * error);
+extern void minix_free_inode(struct inode * inode);
+extern unsigned long minix_count_free_inodes(struct minix_sb_info *sbi);
+extern int minix_new_block(struct inode * inode);
+extern void minix_free_block(struct inode * inode, int block);
+extern unsigned long minix_count_free_blocks(struct minix_sb_info *sbi);
+
+extern void V1_minix_truncate(struct inode *);
+extern void V2_minix_truncate(struct inode *);
+extern void minix_truncate(struct inode *);
+extern int minix_sync_inode(struct inode *);
+extern void minix_set_inode(struct inode *, dev_t);
+extern int V1_minix_get_block(struct inode *, long, struct buffer_head *, int);
+extern int V2_minix_get_block(struct inode *, long, struct buffer_head *, int);
+
+extern struct minix_dir_entry *minix_find_entry(struct dentry*, struct page**);
+extern int minix_add_link(struct dentry*, struct inode*);
+extern int minix_delete_entry(struct minix_dir_entry*, struct page*);
+extern int minix_make_empty(struct inode*, struct inode*);
+extern int minix_empty_dir(struct inode*);
+extern void minix_set_link(struct minix_dir_entry*, struct page*, struct inode*);
+extern struct minix_dir_entry *minix_dotdot(struct inode*, struct page**);
+extern ino_t minix_inode_by_name(struct dentry*);
+
+extern int minix_sync_file(struct file *, struct dentry *, int);
+
+extern struct inode_operations minix_file_inode_operations;
+extern struct inode_operations minix_dir_inode_operations;
+extern struct file_operations minix_file_operations;
+extern struct file_operations minix_dir_operations;
+extern struct dentry_operations minix_dentry_operations;
+
+static inline struct minix_sb_info *minix_sb(struct super_block *sb)
+{
+ return sb->u.generic_sbp;
+}
+
+static inline struct minix_inode_info *minix_i(struct inode *inode)
+{
+ return list_entry(inode, struct minix_inode_info, vfs_inode);
+}
diff --git a/fs/minix/namei.c b/fs/minix/namei.c
index 6663b0681dcd3..a98fc9414cb53 100644
--- a/fs/minix/namei.c
+++ b/fs/minix/namei.c
@@ -4,9 +4,7 @@
* Copyright (C) 1991, 1992 Linus Torvalds
*/
-#include <linux/fs.h>
-#include <linux/minix_fs.h>
-#include <linux/pagemap.h>
+#include "minix.h"
static inline void inc_count(struct inode *inode)
{
diff --git a/fs/nfs/nfsroot.c b/fs/nfs/nfsroot.c
index 5541efe6ee2a1..0bd4a72ed9b69 100644
--- a/fs/nfs/nfsroot.c
+++ b/fs/nfs/nfsroot.c
@@ -202,8 +202,9 @@ static void __init root_nfs_parse(char *name, char *buf)
if ((options = strchr(name, ','))) {
*options++ = 0;
- cp = strtok(options, ",");
- while (cp) {
+ while ((cp = strsep(&options, ",")) != NULL) {
+ if (!*cp)
+ continue;
if ((val = strchr(cp, '='))) {
struct nfs_int_opts *opts = root_int_opts;
*val++ = '\0';
@@ -220,7 +221,6 @@ static void __init root_nfs_parse(char *name, char *buf)
nfs_data.flags |= opts->or_mask;
}
}
- cp = strtok(NULL, ",");
}
}
if (name[0] && strcmp(name, "default")) {
diff --git a/fs/nls/Config.help b/fs/nls/Config.help
index 7fad1861af540..d84b758063c5e 100644
--- a/fs/nls/Config.help
+++ b/fs/nls/Config.help
@@ -224,6 +224,15 @@ CONFIG_NLS_CODEPAGE_950
say Y here if you want to include the DOS codepage for Traditional
Chinese(Big5).
+CONFIG_NLS_CODEPAGE_1250
+ If you want to display filenames with native language characters
+ from the Microsoft FAT file system family or from JOLIET CDROMs
+ correctly on the screen, you need to include the appropriate
+ input/output character sets. Say Y here for the Windows CP-1250
+ character set, which works for most Latin-written Slavic and Central
+ European languages: Czech, German, Hungarian, Polish, Rumanian, Croatian,
+ Slovak, Slovene.
+
CONFIG_NLS_ISO8859_1
If you want to display filenames with native language characters
from the Microsoft FAT file system family or from JOLIET CD-ROMs
diff --git a/fs/nls/Config.in b/fs/nls/Config.in
index 3f59db4bcf911..b14f587b4a2b6 100644
--- a/fs/nls/Config.in
+++ b/fs/nls/Config.in
@@ -43,6 +43,7 @@ if [ "$CONFIG_NLS" = "y" ]; then
tristate 'Korean charset (CP949, EUC-KR)' CONFIG_NLS_CODEPAGE_949
tristate 'Thai charset (CP874, TIS-620)' CONFIG_NLS_CODEPAGE_874
tristate 'Hebrew charsets (ISO-8859-8, CP1255)' CONFIG_NLS_ISO8859_8
+ tristate 'Windows CP1250 (Slavic/Central European Languages)' CONFIG_NLS_CODEPAGE_1250
tristate 'Windows CP1251 (Bulgarian, Belarusian)' CONFIG_NLS_CODEPAGE_1251
tristate 'NLS ISO 8859-1 (Latin 1; Western European Languages)' CONFIG_NLS_ISO8859_1
tristate 'NLS ISO 8859-2 (Latin 2; Slavic/Central European Languages)' CONFIG_NLS_ISO8859_2
diff --git a/fs/nls/nls_cp1250.c b/fs/nls/nls_cp1250.c
new file mode 100644
index 0000000000000..4055dbc7167f8
--- /dev/null
+++ b/fs/nls/nls_cp1250.c
@@ -0,0 +1,365 @@
+/*
+ * linux/fs/nls_cp1250.c
+ *
+ * Charset cp1250 translation tables.
+ * Generated automatically from the Unicode and charset
+ * tables from the Unicode Organization (www.unicode.org).
+ * The Unicode to charset table has only exact mappings.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/nls.h>
+#include <linux/errno.h>
+
+static wchar_t charset2uni[256] = {
+ /* 0x00*/
+ 0x0000, 0x0001, 0x0002, 0x0003,
+ 0x0004, 0x0005, 0x0006, 0x0007,
+ 0x0008, 0x0009, 0x000a, 0x000b,
+ 0x000c, 0x000d, 0x000e, 0x000f,
+ /* 0x10*/
+ 0x0010, 0x0011, 0x0012, 0x0013,
+ 0x0014, 0x0015, 0x0016, 0x0017,
+ 0x0018, 0x0019, 0x001a, 0x001b,
+ 0x001c, 0x001d, 0x001e, 0x001f,
+ /* 0x20*/
+ 0x0020, 0x0021, 0x0022, 0x0023,
+ 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002a, 0x002b,
+ 0x002c, 0x002d, 0x002e, 0x002f,
+ /* 0x30*/
+ 0x0030, 0x0031, 0x0032, 0x0033,
+ 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003a, 0x003b,
+ 0x003c, 0x003d, 0x003e, 0x003f,
+ /* 0x40*/
+ 0x0040, 0x0041, 0x0042, 0x0043,
+ 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004a, 0x004b,
+ 0x004c, 0x004d, 0x004e, 0x004f,
+ /* 0x50*/
+ 0x0050, 0x0051, 0x0052, 0x0053,
+ 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005a, 0x005b,
+ 0x005c, 0x005d, 0x005e, 0x005f,
+ /* 0x60*/
+ 0x0060, 0x0061, 0x0062, 0x0063,
+ 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006a, 0x006b,
+ 0x006c, 0x006d, 0x006e, 0x006f,
+ /* 0x70*/
+ 0x0070, 0x0071, 0x0072, 0x0073,
+ 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007a, 0x007b,
+ 0x007c, 0x007d, 0x007e, 0x007f,
+ /* 0x80*/
+ 0x20ac, 0x0000, 0x201a, 0x0000,
+ 0x201e, 0x2026, 0x2020, 0x2021,
+ 0x0000, 0x2030, 0x0160, 0x2039,
+ 0x015a, 0x0164, 0x017d, 0x0179,
+ /* 0x90*/
+ 0x0000, 0x2018, 0x2019, 0x201c,
+ 0x201d, 0x2022, 0x2013, 0x2014,
+ 0x0000, 0x2122, 0x0161, 0x203a,
+ 0x015b, 0x0165, 0x017e, 0x017a,
+ /* 0xa0*/
+ 0x00a0, 0x02c7, 0x02d8, 0x0141,
+ 0x00a4, 0x0104, 0x00a6, 0x00a7,
+ 0x00a8, 0x00a9, 0x015e, 0x00ab,
+ 0x00ac, 0x00ad, 0x00ae, 0x017b,
+ /* 0xb0*/
+ 0x00b0, 0x00b1, 0x02db, 0x0142,
+ 0x00b4, 0x00b5, 0x00b6, 0x00b7,
+ 0x00b8, 0x0105, 0x015f, 0x00bb,
+ 0x013d, 0x02dd, 0x013e, 0x017c,
+ /* 0xc0*/
+ 0x0154, 0x00c1, 0x00c2, 0x0102,
+ 0x00c4, 0x0139, 0x0106, 0x00c7,
+ 0x010c, 0x00c9, 0x0118, 0x00cb,
+ 0x011a, 0x00cd, 0x00ce, 0x010e,
+ /* 0xd0*/
+ 0x0110, 0x0143, 0x0147, 0x00d3,
+ 0x00d4, 0x0150, 0x00d6, 0x00d7,
+ 0x0158, 0x016e, 0x00da, 0x0170,
+ 0x00dc, 0x00dd, 0x0162, 0x00df,
+ /* 0xe0*/
+ 0x0155, 0x00e1, 0x00e2, 0x0103,
+ 0x00e4, 0x013a, 0x0107, 0x00e7,
+ 0x010d, 0x00e9, 0x0119, 0x00eb,
+ 0x011b, 0x00ed, 0x00ee, 0x010f,
+ /* 0xf0*/
+ 0x0111, 0x0144, 0x0148, 0x00f3,
+ 0x00f4, 0x0151, 0x00f6, 0x00f7,
+ 0x0159, 0x016f, 0x00fa, 0x0171,
+ 0x00fc, 0x00fd, 0x0163, 0x02d9,
+ };
+
+static unsigned char page00[256] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
+ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
+ 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
+ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */
+ 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */
+ 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
+
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0xa0, 0x00, 0x00, 0x00, 0xa4, 0x00, 0xa6, 0xa7, /* 0xa0-0xa7 */
+ 0xa8, 0xa9, 0x00, 0xab, 0xac, 0xad, 0xae, 0x00, /* 0xa8-0xaf */
+ 0xb0, 0xb1, 0x00, 0x00, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */
+ 0xb8, 0x00, 0x00, 0xbb, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+ 0x00, 0xc1, 0xc2, 0x00, 0xc4, 0x00, 0x00, 0xc7, /* 0xc0-0xc7 */
+ 0x00, 0xc9, 0x00, 0xcb, 0x00, 0xcd, 0xce, 0x00, /* 0xc8-0xcf */
+ 0x00, 0x00, 0x00, 0xd3, 0xd4, 0x00, 0xd6, 0xd7, /* 0xd0-0xd7 */
+ 0x00, 0x00, 0xda, 0x00, 0xdc, 0xdd, 0x00, 0xdf, /* 0xd8-0xdf */
+ 0x00, 0xe1, 0xe2, 0x00, 0xe4, 0x00, 0x00, 0xe7, /* 0xe0-0xe7 */
+ 0x00, 0xe9, 0x00, 0xeb, 0x00, 0xed, 0xee, 0x00, /* 0xe8-0xef */
+ 0x00, 0x00, 0x00, 0xf3, 0xf4, 0x00, 0xf6, 0xf7, /* 0xf0-0xf7 */
+ 0x00, 0x00, 0xfa, 0x00, 0xfc, 0xfd, 0x00, 0x00, /* 0xf8-0xff */
+ };
+
+static unsigned char page01[256] = {
+ 0x00, 0x00, 0xc3, 0xe3, 0xa5, 0xb9, 0xc6, 0xe6, /* 0x00-0x07 */
+ 0x00, 0x00, 0x00, 0x00, 0xc8, 0xe8, 0xcf, 0xef, /* 0x08-0x0f */
+ 0xd0, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+ 0xca, 0xea, 0xcc, 0xec, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+ 0x00, 0xc5, 0xe5, 0x00, 0x00, 0xbc, 0xbe, 0x00, /* 0x38-0x3f */
+ 0x00, 0xa3, 0xb3, 0xd1, 0xf1, 0x00, 0x00, 0xd2, /* 0x40-0x47 */
+ 0xf2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+ 0xd5, 0xf5, 0x00, 0x00, 0xc0, 0xe0, 0x00, 0x00, /* 0x50-0x57 */
+ 0xd8, 0xf8, 0x8c, 0x9c, 0x00, 0x00, 0xaa, 0xba, /* 0x58-0x5f */
+ 0x8a, 0x9a, 0xde, 0xfe, 0x8d, 0x9d, 0x00, 0x00, /* 0x60-0x67 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd9, 0xf9, /* 0x68-0x6f */
+ 0xdb, 0xfb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0x8f, 0x9f, 0xaf, 0xbf, 0x8e, 0x9e, 0x00, /* 0x78-0x7f */
+
+ };
+
+static unsigned char page02[256] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa1, /* 0xc0-0xc7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+ 0xa2, 0xff, 0x00, 0xb2, 0x00, 0xbd, 0x00, 0x00, /* 0xd8-0xdf */
+ };
+
+static unsigned char page20[256] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+ 0x00, 0x00, 0x00, 0x96, 0x97, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+ 0x91, 0x92, 0x82, 0x00, 0x93, 0x94, 0x84, 0x00, /* 0x18-0x1f */
+ 0x86, 0x87, 0x95, 0x00, 0x00, 0x00, 0x85, 0x00, /* 0x20-0x27 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+ 0x89, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+ 0x00, 0x8b, 0x9b, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+ 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+ };
+
+static unsigned char page21[256] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+ 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+ };
+
+static unsigned char *page_uni2charset[256] = {
+ page00, page01, page02, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ page20, page21, NULL, NULL, NULL, NULL, NULL, NULL,
+ };
+
+static unsigned char charset2lower[256] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
+ 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x40-0x47 */
+ 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x48-0x4f */
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x50-0x57 */
+ 0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
+ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */
+ 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */
+ 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
+
+ 0x80, 0x00, 0x82, 0x00, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */
+ 0x00, 0x89, 0x9a, 0x8b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x88-0x8f */
+ 0x00, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */
+ 0x00, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */
+ 0xa0, 0xa1, 0xa2, 0xb3, 0xa4, 0xb9, 0xa6, 0xa7, /* 0xa0-0xa7 */
+ 0xa8, 0xa9, 0xba, 0xab, 0xac, 0xad, 0xae, 0xbf, /* 0xa8-0xaf */
+ 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */
+ 0xb8, 0xb9, 0xba, 0xbb, 0xbe, 0xbd, 0xbe, 0xbf, /* 0xb8-0xbf */
+ 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xc0-0xc7 */
+ 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xc8-0xcf */
+ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xd7, /* 0xd0-0xd7 */
+ 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xdf, /* 0xd8-0xdf */
+ 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xe0-0xe7 */
+ 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xe8-0xef */
+ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */
+ 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */
+ };
+
+static unsigned char charset2upper[256] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
+ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
+ 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
+ 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x60-0x67 */
+ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x68-0x6f */
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x70-0x77 */
+ 0x58, 0x59, 0x5a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
+
+ 0x80, 0x00, 0x82, 0x00, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */
+ 0x00, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */
+ 0x00, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */
+ 0x00, 0x99, 0x8a, 0x9b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x98-0x9f */
+ 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */
+ 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */
+ 0xb0, 0xb1, 0xb2, 0xa3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */
+ 0xb8, 0xa5, 0xaa, 0xbb, 0xbc, 0xbd, 0xbc, 0xaf, /* 0xb8-0xbf */
+ 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0-0xc7 */
+ 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */
+ 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xd0-0xd7 */
+ 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0x00, /* 0xd8-0xdf */
+ 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xe0-0xe7 */
+ 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xe8-0xef */
+ 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xf7, /* 0xf0-0xf7 */
+ 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xff, /* 0xf8-0xff */
+ };
+
+static int uni2char(wchar_t uni, unsigned char *out, int boundlen)
+{
+ unsigned char *uni2charset;
+ unsigned char cl = uni & 0x00ff;
+ unsigned char ch = (uni & 0xff00) >> 8;
+
+ if (boundlen <= 0)
+ return -ENAMETOOLONG;
+
+ uni2charset = page_uni2charset[ch];
+ if (uni2charset && uni2charset[cl])
+ out[0] = uni2charset[cl];
+ else
+ return -EINVAL;
+ return 1;
+}
+
+static int char2uni(const unsigned char *rawstring, int boundlen, wchar_t *uni)
+{
+ *uni = charset2uni[*rawstring];
+ if (*uni == 0x0000)
+ return -EINVAL;
+ return 1;
+}
+
+static struct nls_table table = {
+ charset: "cp1250",
+ uni2char: uni2char,
+ char2uni: char2uni,
+ charset2lower: charset2lower,
+ charset2upper: charset2upper,
+ owner: THIS_MODULE,
+};
+
+static int __init init_nls_cp1250(void)
+{
+ return register_nls(&table);
+}
+static void __exit exit_nls_cp1250(void)
+{
+ unregister_nls(&table);
+}
+
+module_init(init_nls_cp1250)
+module_exit(exit_nls_cp1250)
+
+MODULE_LICENSE("BSD without advertising clause");
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only. This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-indent-level: 8
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -8
+ * c-argdecl-indent: 8
+ * c-label-offset: -8
+ * c-continued-statement-offset: 8
+ * c-continued-brace-offset: 0
+ * End:
+ */
+
diff --git a/fs/noquot.c b/fs/noquot.c
deleted file mode 100644
index 231aab4957ca1..0000000000000
--- a/fs/noquot.c
+++ /dev/null
@@ -1,15 +0,0 @@
-/* noquot.c: Quota stubs necessary for when quotas are not
- * compiled into the kernel.
- */
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/errno.h>
-
-int nr_dquots, nr_free_dquots;
-int max_dquots;
-
-asmlinkage long sys_quotactl(int cmd, const char *special, int id, caddr_t addr)
-{
- return(-ENOSYS);
-}
diff --git a/fs/ntfs/fs.c b/fs/ntfs/fs.c
index 9bcc2335caab3..fbc6bf66eda9c 100644
--- a/fs/ntfs/fs.c
+++ b/fs/ntfs/fs.c
@@ -360,10 +360,13 @@ static int parse_options(ntfs_volume *vol, char *opt)
int use_utf8 = -1; /* If no NLS specified and loading the default
NLS failed use utf8. */
int mft_zone_mul = -1; /* 1 */
+ char *opts = opt;
if (!opt)
goto done;
- for (opt = strtok(opt, ","); opt; opt = strtok(NULL, ",")) {
+ while ((opt = strsep(&opts, ",")) != NULL) {
+ if (!*opt)
+ continue;
if ((value = strchr(opt, '=')) != NULL)
*value ++= '\0';
if (strcmp(opt, "uid") == 0) {
diff --git a/fs/partitions/Config.help b/fs/partitions/Config.help
index e90aa4acf828e..6cea3ac42ba53 100644
--- a/fs/partitions/Config.help
+++ b/fs/partitions/Config.help
@@ -115,6 +115,11 @@ CONFIG_SGI_PARTITION
Say Y here if you would like to be able to read the hard disk
partition table format used by SGI machines.
+CONFIG_EFI_PARTITION
+ Say Y here if you would like to use hard disks under Linux which
+ were partitioned using EFI GPT. Presently only useful on the
+ IA-64 platform.
+
CONFIG_ULTRIX_PARTITION
Say Y here if you would like to be able to read the hard disk
partition table format used by DEC (now Compaq) Ultrix machines.
diff --git a/fs/partitions/Config.in b/fs/partitions/Config.in
index 83b3a60a65dba..785ba377bf8c3 100644
--- a/fs/partitions/Config.in
+++ b/fs/partitions/Config.in
@@ -32,6 +32,7 @@ if [ "$CONFIG_PARTITION_ADVANCED" = "y" ]; then
bool ' SGI partition support' CONFIG_SGI_PARTITION
bool ' Ultrix partition table support' CONFIG_ULTRIX_PARTITION
bool ' Sun partition tables support' CONFIG_SUN_PARTITION
+ bool ' EFI GUID Partition support' CONFIG_EFI_PARTITION
else
if [ "$ARCH" = "alpha" ]; then
define_bool CONFIG_OSF_PARTITION y
diff --git a/fs/partitions/Makefile b/fs/partitions/Makefile
index e4cda505301d0..b000fada1b0f6 100644
--- a/fs/partitions/Makefile
+++ b/fs/partitions/Makefile
@@ -24,6 +24,7 @@ obj-$(CONFIG_SGI_PARTITION) += sgi.o
obj-$(CONFIG_SUN_PARTITION) += sun.o
obj-$(CONFIG_ULTRIX_PARTITION) += ultrix.o
obj-$(CONFIG_IBM_PARTITION) += ibm.o
+obj-$(CONFIG_EFI_PARTITION) += efi.o
include $(TOPDIR)/Rules.make
diff --git a/fs/partitions/check.c b/fs/partitions/check.c
index 48c25baf58f46..e7e8579dfbbd2 100644
--- a/fs/partitions/check.c
+++ b/fs/partitions/check.c
@@ -35,6 +35,7 @@
#include "sun.h"
#include "ibm.h"
#include "ultrix.h"
+#include "efi.h"
int warn_no_part = 1; /*This is ugly: should make genhd removable media aware*/
@@ -43,6 +44,9 @@ static int (*check_part[])(struct gendisk *hd, struct block_device *bdev,
#ifdef CONFIG_ACORN_PARTITION
acorn_partition,
#endif
+#ifdef CONFIG_EFI_PARTITION
+ efi_partition, /* this must come before msdos */
+#endif
#ifdef CONFIG_LDM_PARTITION
ldm_partition, /* this must come before msdos */
#endif
diff --git a/fs/partitions/efi.c b/fs/partitions/efi.c
new file mode 100644
index 0000000000000..6fab6c5e6b7a0
--- /dev/null
+++ b/fs/partitions/efi.c
@@ -0,0 +1,828 @@
+/************************************************************
+ * EFI GUID Partition Table handling
+ * Per Intel EFI Specification v1.02
+ * http://developer.intel.com/technology/efi/efi.htm
+ * efi.[ch] by Matt Domsch <Matt_Domsch@dell.com>
+ * Copyright 2000,2001,2002 Dell Computer Corporation
+ *
+ * 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
+ *
+ *
+ * TODO:
+ *
+ * Changelog:
+ * Mon Jan 14 2002 Matt Domsch <Matt_Domsch@dell.com>
+ * - Ported to 2.5.2-pre11 + library crc32 patch Linus applied
+ *
+ * Thu Dec 6 2001 Matt Domsch <Matt_Domsch@dell.com>
+ * - Added compare_gpts().
+ * - moved le_efi_guid_to_cpus() back into this file. GPT is the only
+ * thing that keeps EFI GUIDs on disk.
+ * - Changed gpt structure names and members to be simpler and more Linux-like.
+ *
+ * Wed Oct 17 2001 Matt Domsch <Matt_Domsch@dell.com>
+ * - Removed CONFIG_DEVFS_VOLUMES_UUID code entirely per Martin Wilck
+ *
+ * Wed Oct 10 2001 Matt Domsch <Matt_Domsch@dell.com>
+ * - Changed function comments to DocBook style per Andreas Dilger suggestion.
+ *
+ * Mon Oct 08 2001 Matt Domsch <Matt_Domsch@dell.com>
+ * - Change read_lba() to use the page cache per Al Viro's work.
+ * - print u64s properly on all architectures
+ * - fixed debug_printk(), now Dprintk()
+ *
+ * Mon Oct 01 2001 Matt Domsch <Matt_Domsch@dell.com>
+ * - Style cleanups
+ * - made most functions static
+ * - Endianness addition
+ * - remove test for second alternate header, as it's not per spec,
+ * and is unnecessary. There's now a method to read/write the last
+ * sector of an odd-sized disk from user space. No tools have ever
+ * been released which used this code, so it's effectively dead.
+ * - Per Asit Mallick of Intel, added a test for a valid PMBR.
+ * - Added kernel command line option 'gpt' to override valid PMBR test.
+ *
+ * Wed Jun 6 2001 Martin Wilck <Martin.Wilck@Fujitsu-Siemens.com>
+ * - added devfs volume UUID support (/dev/volumes/uuids) for
+ * mounting file systems by the partition GUID.
+ *
+ * Tue Dec 5 2000 Matt Domsch <Matt_Domsch@dell.com>
+ * - Moved crc32() to linux/lib, added efi_crc32().
+ *
+ * Thu Nov 30 2000 Matt Domsch <Matt_Domsch@dell.com>
+ * - Replaced Intel's CRC32 function with an equivalent
+ * non-license-restricted version.
+ *
+ * Wed Oct 25 2000 Matt Domsch <Matt_Domsch@dell.com>
+ * - Fixed the last_lba() call to return the proper last block
+ *
+ * Thu Oct 12 2000 Matt Domsch <Matt_Domsch@dell.com>
+ * - Thanks to Andries Brouwer for his debugging assistance.
+ * - Code works, detects all the partitions.
+ *
+ ************************************************************/
+#include <linux/config.h>
+#include <linux/fs.h>
+#include <linux/genhd.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/string.h>
+#include <linux/blk.h>
+#include <linux/blkpg.h>
+#include <linux/slab.h>
+#include <linux/smp_lock.h>
+#include <linux/init.h>
+#include <linux/crc32.h>
+#include <asm/system.h>
+#include <asm/byteorder.h>
+#include "check.h"
+#include "efi.h"
+
+#if CONFIG_BLK_DEV_MD
+extern void md_autodetect_dev(kdev_t dev);
+#endif
+
+/* Handle printing of 64-bit values */
+/* Borrowed from /usr/include/inttypes.h */
+# if BITS_PER_LONG == 64
+# define __PRI64_PREFIX "l"
+# define __PRIPTR_PREFIX "l"
+# else
+# define __PRI64_PREFIX "ll"
+# define __PRIPTR_PREFIX
+# endif
+# define PRIx64 __PRI64_PREFIX "x"
+
+
+#undef EFI_DEBUG
+#ifdef EFI_DEBUG
+#define Dprintk(x...) printk(KERN_DEBUG x)
+#else
+#define Dprintk(x...)
+#endif
+
+/* This allows a kernel command line option 'gpt' to override
+ * the test for invalid PMBR. Not __initdata because reloading
+ * the partition tables happens after init too.
+ */
+static int forcegpt;
+static int __init
+force_gpt(char *str)
+{
+ forcegpt = 1;
+ return 1;
+}
+
+__setup("gpt", force_gpt);
+
+/**
+ * le_efi_guid_to_cpus()
+ * @guid
+ *
+ * Description: modifies @guid in situ
+ *
+ * This function converts a little endian efi_guid_t to the
+ * native cpu representation. The EFI Spec. declares that all
+ * on-disk structures are stored in little endian format.
+ */
+static void
+le_efi_guid_to_cpus(efi_guid_t *guid)
+{
+ le32_to_cpus(guid->data1);
+ le16_to_cpus(guid->data2);
+ le16_to_cpus(guid->data3);
+ /* no need to change the rest. It's already an array of chars */
+ return;
+}
+
+/**
+ * efi_crc32() - EFI version of crc32 function
+ * @buf: buffer to calculate crc32 of
+ * @len - length of buf
+ *
+ * Description: Returns EFI-style CRC32 value for @buf
+ *
+ * This function uses the little endian Ethernet polynomial
+ * but seeds the function with ~0, and xor's with ~0 at the end.
+ * Note, the EFI Specification, v1.02, has a reference to
+ * Dr. Dobbs Journal, May 1994 (actually it's in May 1992).
+ */
+static inline u32
+efi_crc32(const void *buf, unsigned long len)
+{
+ return (crc32(~0L, buf, len) ^ ~0L);
+}
+
+/**
+ * le_part_attributes_to_cpus(): converts LE attributes to CPU type in situ
+ * @attributes - ptr to partition attributes
+ *
+ * Description: modifies attributes in situ, returns nothing.
+ * Converts a little endian partition attributes struct to the
+ * native cpu representation. Good for reading attributes off of a disk.
+ */
+static void
+le_part_attributes_to_cpus(gpt_entry_attributes * a)
+{
+ u64 *b = (u64 *) a;
+ *b = le64_to_cpu(*b);
+}
+
+/**
+ * is_pmbr_valid(): test Protective MBR for validity
+ * @mbr: pointer to a legacy mbr structure
+ *
+ * Description: Returns 1 if PMBR is valid, 0 otherwise.
+ * Validity depends on two things:
+ * 1) MSDOS signature is in the last two bytes of the MBR
+ * 2) One partition of type 0xEE is found
+ */
+static int
+is_pmbr_valid(legacy_mbr *mbr)
+{
+ int i, found = 0, signature = 0;
+ if (!mbr)
+ return 0;
+ signature = (le16_to_cpu(mbr->signature) == MSDOS_MBR_SIGNATURE);
+ for (i = 0; signature && i < 4; i++) {
+ if (mbr->partition_record[i].sys_ind == EFI_PMBR_OSTYPE_EFI_GPT) {
+ found = 1;
+ break;
+ }
+ }
+ return (signature && found);
+}
+
+/**
+ * last_lba(): return number of last logical block of device
+ * @hd: gendisk with partition list
+ * @bdev: block device
+ *
+ * Description: Returns last LBA value on success, 0 on error.
+ * This is stored (by sd and ide-geometry) in
+ * the part[0] entry for this disk, and is the number of
+ * physical sectors available on the disk.
+ */
+static u64
+last_lba(struct gendisk *hd, struct block_device *bdev)
+{
+ if (!hd || !hd->part || !bdev)
+ return 0;
+ return hd->part[minor(to_kdev_t(bdev->bd_dev))].nr_sects - 1;
+}
+
+/**
+ * read_lba(): Read bytes from disk, starting at given LBA
+ * @hd
+ * @bdev
+ * @lba
+ * @buffer
+ * @size_t
+ *
+ * Description: Reads @count bytes from @bdev into @buffer.
+ * Returns number of bytes read on success, 0 on error.
+ */
+static size_t
+read_lba(struct gendisk *hd, struct block_device *bdev, u64 lba,
+ u8 * buffer, size_t count)
+{
+
+ size_t totalreadcount = 0, bytesread = 0;
+ unsigned long blocksize;
+ int i;
+ Sector sect;
+ unsigned char *data = NULL;
+
+ if (!hd || !bdev || !buffer || !count)
+ return 0;
+
+ blocksize = get_hardsect_size(to_kdev_t(bdev->bd_dev));
+ if (!blocksize)
+ blocksize = 512;
+
+ for (i = 0; count > 0; i++) {
+ data = read_dev_sector(bdev, lba, &sect);
+ if (!data)
+ return totalreadcount;
+
+ bytesread =
+ PAGE_CACHE_SIZE - (data -
+ (unsigned char *) page_address(sect.v));
+ bytesread = min(bytesread, count);
+ memcpy(buffer, data, bytesread);
+ put_dev_sector(sect);
+
+ buffer += bytesread;
+ totalreadcount += bytesread;
+ count -= bytesread;
+ lba += (bytesread / blocksize);
+ }
+ return totalreadcount;
+}
+
+/**
+ * print_gpt_header(): unparses gpt header to console
+ * @gpt: gpt header
+ */
+static void
+print_gpt_header(gpt_header *gpt)
+{
+ Dprintk("GUID Partition Table Header\n");
+ if (!gpt)
+ return;
+ Dprintk("signature : %" PRIx64 "\n", gpt->signature);
+ Dprintk("revision : %x\n", gpt->revision);
+ Dprintk("header_size : %x\n", gpt->header_size);
+ Dprintk("header_crc32 : %x\n", gpt->header_crc32);
+ Dprintk("my_lba : %" PRIx64 "\n", gpt->my_lba);
+ Dprintk("alternate_lba : %" PRIx64 "\n",
+ gpt->alternate_lba);
+ Dprintk("first_usable_lba : %" PRIx64 "\n",
+ gpt->first_usable_lba);
+ Dprintk("last_usable_lba : %" PRIx64 "\n",
+ gpt->last_usable_lba);
+ Dprintk("partition_entry_lba : %" PRIx64 "\n",
+ gpt->partition_entry_lba);
+ Dprintk("num_partition_entries : %x\n",
+ gpt->num_partition_entries);
+ Dprintk("sizeof_partition_entry : %x\n",
+ gpt->sizeof_partition_entry);
+ Dprintk("partition_entry_array_crc32 : %x\n",
+ gpt->partition_entry_array_crc32);
+ return;
+}
+
+/**
+ * alloc_read_gpt_entries(): reads partition entries from disk
+ * @hd
+ * @bdev
+ * @gpt - GPT header
+ *
+ * Description: Returns ptes on success, NULL on error.
+ * Allocates space for PTEs based on information found in @gpt.
+ * Notes: remember to free pte when you're done!
+ */
+static gpt_entry *
+alloc_read_gpt_entries(struct gendisk *hd,
+ struct block_device *bdev, gpt_header *gpt)
+{
+ u32 i, j;
+ size_t count;
+ gpt_entry *pte;
+ if (!hd || !bdev || !gpt)
+ return NULL;
+
+ count = gpt->num_partition_entries * gpt->sizeof_partition_entry;
+ if (!count)
+ return NULL;
+ pte = kmalloc(count, GFP_KERNEL);
+ if (!pte)
+ return NULL;
+ memset(pte, 0, count);
+
+ if (read_lba(hd, bdev, gpt->partition_entry_lba, (u8 *) pte,
+ count) < count) {
+ kfree(pte);
+ return NULL;
+ }
+ /* Fixup endianness */
+ for (i = 0; i < gpt->num_partition_entries; i++) {
+ le_efi_guid_to_cpus(&pte[i].partition_type_guid);
+ le_efi_guid_to_cpus(&pte[i].unique_partition_guid);
+ le64_to_cpus(pte[i].starting_lba);
+ le64_to_cpus(pte[i].ending_lba);
+ le_part_attributes_to_cpus(&pte[i].attributes);
+ for (j = 0; j < (72 / sizeof (efi_char16_t)); j++) {
+ le16_to_cpus((u16) (pte[i].partition_name[j]));
+ }
+ }
+
+ return pte;
+}
+
+/**
+ * alloc_read_gpt_header(): Allocates GPT header, reads into it from disk
+ * @hd
+ * @bdev
+ * @lba is the Logical Block Address of the partition table
+ *
+ * Description: returns GPT header on success, NULL on error. Allocates
+ * and fills a GPT header starting at @ from @bdev.
+ * Note: remember to free gpt when finished with it.
+ */
+static gpt_header *
+alloc_read_gpt_header(struct gendisk *hd, struct block_device *bdev, u64 lba)
+{
+ gpt_header *gpt;
+ if (!hd || !bdev)
+ return NULL;
+
+ gpt = kmalloc(sizeof (gpt_header), GFP_KERNEL);
+ if (!gpt)
+ return NULL;
+ memset(gpt, 0, sizeof (gpt_header));
+
+ if (read_lba(hd, bdev, lba, (u8 *) gpt,
+ sizeof (gpt_header)) < sizeof (gpt_header)) {
+ kfree(gpt);
+ return NULL;
+ }
+
+ /* Fixup endianness */
+ le64_to_cpus(gpt->signature);
+ le32_to_cpus(gpt->revision);
+ le32_to_cpus(gpt->header_size);
+ le32_to_cpus(gpt->header_crc32);
+ le32_to_cpus(gpt->reserved1);
+ le64_to_cpus(gpt->my_lba);
+ le64_to_cpus(gpt->alternate_lba);
+ le64_to_cpus(gpt->first_usable_lba);
+ le64_to_cpus(gpt->last_usable_lba);
+ le_efi_guid_to_cpus(&gpt->disk_guid);
+ le64_to_cpus(gpt->partition_entry_lba);
+ le32_to_cpus(gpt->num_partition_entries);
+ le32_to_cpus(gpt->sizeof_partition_entry);
+ le32_to_cpus(gpt->partition_entry_array_crc32);
+
+ print_gpt_header(gpt);
+
+ return gpt;
+}
+
+/**
+ * is_gpt_valid() - tests one GPT header and PTEs for validity
+ * @hd
+ * @bdev
+ * @lba is the logical block address of the GPT header to test
+ * @gpt is a GPT header ptr, filled on return.
+ * @ptes is a PTEs ptr, filled on return.
+ *
+ * Description: returns 1 if valid, 0 on error.
+ * If valid, returns pointers to newly allocated GPT header and PTEs.
+ */
+static int
+is_gpt_valid(struct gendisk *hd, struct block_device *bdev, u64 lba,
+ gpt_header **gpt, gpt_entry **ptes)
+{
+ u32 crc, origcrc;
+
+ if (!hd || !bdev || !gpt || !ptes)
+ return 0;
+ if (!(*gpt = alloc_read_gpt_header(hd, bdev, lba)))
+ return 0;
+
+ /* Check the GUID Partition Table signature */
+ if ((*gpt)->signature != GPT_HEADER_SIGNATURE) {
+ Dprintk("GUID Partition Table Header signature is wrong: %"
+ PRIx64 " != %" PRIx64 "\n", (*gpt)->signature,
+ GPT_HEADER_SIGNATURE);
+ kfree(*gpt);
+ *gpt = NULL;
+ return 0;
+ }
+
+ /* Check the GUID Partition Table CRC */
+ origcrc = (*gpt)->header_crc32;
+ (*gpt)->header_crc32 = 0;
+ crc = efi_crc32((const unsigned char *) (*gpt), (*gpt)->header_size);
+
+ if (crc != origcrc) {
+ Dprintk
+ ("GUID Partition Table Header CRC is wrong: %x != %x\n",
+ (*gpt)->header_crc32, origcrc);
+ kfree(*gpt);
+ *gpt = NULL;
+ return 0;
+ }
+ (*gpt)->header_crc32 = origcrc;
+
+ /* Check that the my_lba entry points to the LBA that contains
+ * the GUID Partition Table */
+ if ((*gpt)->my_lba != lba) {
+ Dprintk("GPT my_lba incorrect: %" PRIx64 " != %" PRIx64 "\n",
+ (*gpt)->my_lba, lba);
+ kfree(*gpt);
+ *gpt = NULL;
+ return 0;
+ }
+
+ if (!(*ptes = alloc_read_gpt_entries(hd, bdev, *gpt))) {
+ kfree(*gpt);
+ *gpt = NULL;
+ return 0;
+ }
+
+ /* Check the GUID Partition Entry Array CRC */
+ crc = efi_crc32((const unsigned char *) (*ptes),
+ (*gpt)->num_partition_entries *
+ (*gpt)->sizeof_partition_entry);
+
+ if (crc != (*gpt)->partition_entry_array_crc32) {
+ Dprintk("GUID Partitition Entry Array CRC check failed.\n");
+ kfree(*gpt);
+ *gpt = NULL;
+ kfree(*ptes);
+ *ptes = NULL;
+ return 0;
+ }
+
+ /* We're done, all's well */
+ return 1;
+}
+
+/**
+ * compare_gpts() - Search disk for valid GPT headers and PTEs
+ * @pgpt is the primary GPT header
+ * @agpt is the alternate GPT header
+ * @lastlba is the last LBA number
+ * Description: Returns nothing. Sanity checks pgpt and agpt fields
+ * and prints warnings on discrepancies.
+ *
+ */
+static void
+compare_gpts(gpt_header *pgpt, gpt_header *agpt, u64 lastlba)
+{
+ int error_found = 0;
+ if (!pgpt || !agpt)
+ return;
+ if (pgpt->my_lba != agpt->alternate_lba) {
+ printk(KERN_WARNING
+ "GPT:Primary header LBA != Alt. header alternate_lba\n");
+ printk(KERN_WARNING "GPT:%" PRIx64 " != %" PRIx64 "\n",
+ pgpt->my_lba, agpt->alternate_lba);
+ error_found++;
+ }
+ if (pgpt->alternate_lba != agpt->my_lba) {
+ printk(KERN_WARNING
+ "GPT:Primary header alternate_lba != Alt. header my_lba\n");
+ printk(KERN_WARNING "GPT:%" PRIx64 " != %" PRIx64 "\n",
+ pgpt->alternate_lba, agpt->my_lba);
+ error_found++;
+ }
+ if (pgpt->first_usable_lba != agpt->first_usable_lba) {
+ printk(KERN_WARNING "GPT:first_usable_lbas don't match.\n");
+ printk(KERN_WARNING "GPT:%" PRIx64 " != %" PRIx64 "\n",
+ pgpt->first_usable_lba, agpt->first_usable_lba);
+ error_found++;
+ }
+ if (pgpt->last_usable_lba != agpt->last_usable_lba) {
+ printk(KERN_WARNING "GPT:last_usable_lbas don't match.\n");
+ printk(KERN_WARNING "GPT:%" PRIx64 " != %" PRIx64 "\n",
+ pgpt->last_usable_lba, agpt->last_usable_lba);
+ error_found++;
+ }
+ if (efi_guidcmp(pgpt->disk_guid, agpt->disk_guid)) {
+ printk(KERN_WARNING "GPT:disk_guids don't match.\n");
+ error_found++;
+ }
+ if (pgpt->num_partition_entries != agpt->num_partition_entries) {
+ printk(KERN_WARNING "GPT:num_partition_entries don't match: "
+ "0x%x != 0x%x\n",
+ pgpt->num_partition_entries,
+ agpt->num_partition_entries);
+ error_found++;
+ }
+ if (pgpt->sizeof_partition_entry != agpt->sizeof_partition_entry) {
+ printk(KERN_WARNING
+ "GPT:sizeof_partition_entry values don't match: "
+ "0x%x != 0x%x\n", pgpt->sizeof_partition_entry,
+ agpt->sizeof_partition_entry);
+ error_found++;
+ }
+ if (pgpt->partition_entry_array_crc32 !=
+ agpt->partition_entry_array_crc32) {
+ printk(KERN_WARNING
+ "GPT:partition_entry_array_crc32 values don't match: "
+ "0x%x != 0x%x\n", pgpt->partition_entry_array_crc32,
+ agpt->partition_entry_array_crc32);
+ error_found++;
+ }
+ if (pgpt->alternate_lba != lastlba) {
+ printk(KERN_WARNING
+ "GPT:Primary header thinks Alt. header is not at the end of the disk.\n");
+ printk(KERN_WARNING "GPT:%" PRIx64 " != %" PRIx64 "\n",
+ pgpt->alternate_lba, lastlba);
+ error_found++;
+ }
+
+ if (agpt->my_lba != lastlba) {
+ printk(KERN_WARNING
+ "GPT:Alternate GPT header not at the end of the disk.\n");
+ printk(KERN_WARNING "GPT:%" PRIx64 " != %" PRIx64 "\n",
+ agpt->my_lba, lastlba);
+ error_found++;
+ }
+
+ if (error_found)
+ printk(KERN_WARNING
+ "GPT: Use GNU Parted to correct GPT errors.\n");
+ return;
+}
+
+/**
+ * find_valid_gpt() - Search disk for valid GPT headers and PTEs
+ * @hd
+ * @bdev
+ * @gpt is a GPT header ptr, filled on return.
+ * @ptes is a PTEs ptr, filled on return.
+ * Description: Returns 1 if valid, 0 on error.
+ * If valid, returns pointers to newly allocated GPT header and PTEs.
+ * Validity depends on finding either the Primary GPT header and PTEs valid,
+ * or the Alternate GPT header and PTEs valid, and the PMBR valid.
+ */
+static int
+find_valid_gpt(struct gendisk *hd, struct block_device *bdev,
+ gpt_header **gpt, gpt_entry **ptes)
+{
+ int good_pgpt = 0, good_agpt = 0, good_pmbr = 0;
+ gpt_header *pgpt = NULL, *agpt = NULL;
+ gpt_entry *pptes = NULL, *aptes = NULL;
+ legacy_mbr *legacymbr = NULL;
+ u64 lastlba;
+ if (!hd || !bdev || !gpt || !ptes)
+ return 0;
+
+ lastlba = last_lba(hd, bdev);
+ /* Check the Primary GPT */
+ good_pgpt = is_gpt_valid(hd, bdev, GPT_PRIMARY_PARTITION_TABLE_LBA,
+ &pgpt, &pptes);
+ if (good_pgpt) {
+ /* Primary GPT is OK, check the alternate and warn if bad */
+ good_agpt = is_gpt_valid(hd, bdev, pgpt->alternate_lba,
+ &agpt, &aptes);
+ if (!good_agpt) {
+ printk(KERN_WARNING
+ "Alternate GPT is invalid, using primary GPT.\n");
+ }
+
+ compare_gpts(pgpt, agpt, lastlba);
+
+ *gpt = pgpt;
+ *ptes = pptes;
+ if (agpt) {
+ kfree(agpt);
+ agpt = NULL;
+ }
+ if (aptes) {
+ kfree(aptes);
+ aptes = NULL;
+ }
+ } /* if primary is valid */
+ else {
+ /* Primary GPT is bad, check the Alternate GPT */
+ good_agpt = is_gpt_valid(hd, bdev, lastlba, &agpt, &aptes);
+ if (good_agpt) {
+ /* Primary is bad, alternate is good.
+ Return values from the alternate and warn.
+ */
+ printk(KERN_WARNING
+ "Primary GPT is invalid, using alternate GPT.\n");
+ *gpt = agpt;
+ *ptes = aptes;
+ }
+ }
+
+ /* Now test for valid PMBR */
+ /* This will be added to the EFI Spec. per Intel after v1.02. */
+ if (good_pgpt || good_agpt) {
+ legacymbr = kmalloc(sizeof (*legacymbr), GFP_KERNEL);
+ if (legacymbr) {
+ memset(legacymbr, 0, sizeof (*legacymbr));
+ read_lba(hd, bdev, 0, (u8 *) legacymbr,
+ sizeof (*legacymbr));
+ good_pmbr = is_pmbr_valid(legacymbr);
+ kfree(legacymbr);
+ }
+ if (good_pmbr)
+ return 1;
+ if (!forcegpt) {
+ printk
+ (" Warning: Disk has a valid GPT signature but invalid PMBR.\n");
+ printk(KERN_WARNING
+ " Assuming this disk is *not* a GPT disk anymore.\n");
+ printk(KERN_WARNING
+ " Use gpt kernel option to override. Use GNU Parted to correct disk.\n");
+ } else {
+ printk(KERN_WARNING
+ " Warning: Disk has a valid GPT signature but invalid PMBR.\n");
+ printk(KERN_WARNING
+ " Use GNU Parted to correct disk.\n");
+ printk(KERN_WARNING
+ " gpt option taken, disk treated as GPT.\n");
+ return 1;
+ }
+ }
+
+ /* Both primary and alternate GPTs are bad, and/or PMBR is invalid.
+ * This isn't our disk, return 0.
+ */
+ if (pgpt) {
+ kfree(pgpt);
+ pgpt = NULL;
+ }
+ if (agpt) {
+ kfree(agpt);
+ agpt = NULL;
+ }
+ if (pptes) {
+ kfree(pptes);
+ pptes = NULL;
+ }
+ if (aptes) {
+ kfree(aptes);
+ aptes = NULL;
+ }
+ *gpt = NULL;
+ *ptes = NULL;
+ return 0;
+}
+
+/**
+ * add_gpt_partitions(struct gendisk *hd, struct block_device *bdev,
+ * @hd
+ * @bdev
+ *
+ * Description: Create devices for each entry in the GUID Partition Table
+ * Entries.
+ *
+ * We do not create a Linux partition for GPT, but
+ * only for the actual data partitions.
+ * Returns:
+ * -1 if unable to read the partition table
+ * 0 if this isn't our partition table
+ * 1 if successful
+ *
+ */
+static int
+add_gpt_partitions(struct gendisk *hd, struct block_device *bdev, int nextminor)
+{
+ gpt_header *gpt = NULL;
+ gpt_entry *ptes = NULL;
+ u32 i, nummade = 0;
+ int max_p;
+
+ efi_guid_t unusedGuid = UNUSED_ENTRY_GUID;
+#if CONFIG_BLK_DEV_MD
+ efi_guid_t raidGuid = PARTITION_LINUX_RAID_GUID;
+#endif
+
+ if (!hd || !bdev)
+ return -1;
+
+ if (!find_valid_gpt(hd, bdev, &gpt, &ptes) || !gpt || !ptes) {
+ if (gpt)
+ kfree(gpt);
+ if (ptes)
+ kfree(ptes);
+ return 0;
+ }
+
+ Dprintk("GUID Partition Table is valid! Yea!\n");
+
+ max_p = (1 << hd->minor_shift) - 1;
+ for (i = 0; i < gpt->num_partition_entries && nummade < max_p; i++) {
+ if (!efi_guidcmp(unusedGuid, ptes[i].partition_type_guid))
+ continue;
+
+ add_gd_partition(hd, nextminor, ptes[i].starting_lba,
+ (ptes[i].ending_lba - ptes[i].starting_lba +
+ 1));
+
+ /* If there's this is a RAID volume, tell md */
+#if CONFIG_BLK_DEV_MD
+ if (!efi_guidcmp(raidGuid, ptes[i].partition_type_guid)) {
+ md_autodetect_dev(mk_kdev(hd->major,
+ nextminor));
+ }
+#endif
+ nummade++;
+ nextminor++;
+
+ }
+ kfree(ptes);
+ kfree(gpt);
+ printk("\n");
+ return 1;
+}
+
+/**
+ * efi_partition(): EFI GPT partition handling entry function
+ * @hd
+ * @bdev
+ * @first_sector: unused
+ * @first_part_minor: minor number assigned to first GPT partition found
+ *
+ * Description: called from check.c, if the disk contains GPT
+ * partitions, sets up partition entries in the kernel.
+ *
+ * If the first block on the disk is a legacy MBR,
+ * it will get handled by msdos_partition().
+ * If it's a Protective MBR, we'll handle it here.
+ *
+ * set_blocksize() calls are necessary to be able to read
+ * a disk with an odd number of 512-byte sectors, as the
+ * default BLOCK_SIZE of 1024 bytes won't let that last
+ * sector be read otherwise.
+ *
+ * Returns:
+ * -1 if unable to read the partition table
+ * 0 if this isn't our partitoin table
+ * 1 if successful
+ */
+int
+efi_partition(struct gendisk *hd, struct block_device *bdev,
+ unsigned long first_sector, int first_part_minor)
+{
+
+ kdev_t dev = to_kdev_t(bdev->bd_dev);
+ int hardblocksize = get_hardsect_size(dev);
+ int orig_blksize_size = BLOCK_SIZE;
+ int rc = 0;
+
+ /* Need to change the block size that the block layer uses */
+ if (blksize_size[major(dev)]) {
+ orig_blksize_size = blksize_size[major(dev)][minor(dev)];
+ }
+
+ if (orig_blksize_size != hardblocksize)
+ set_blocksize(dev, hardblocksize);
+
+ rc = add_gpt_partitions(hd, bdev, first_part_minor);
+
+ /* change back */
+ if (orig_blksize_size != hardblocksize)
+ set_blocksize(dev, orig_blksize_size);
+
+ return rc;
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only. This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-indent-level: 4
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -4
+ * c-argdecl-indent: 4
+ * c-label-offset: -4
+ * c-continued-statement-offset: 4
+ * c-continued-brace-offset: 0
+ * indent-tabs-mode: nil
+ * tab-width: 8
+ * End:
+ */
diff --git a/fs/partitions/efi.h b/fs/partitions/efi.h
new file mode 100644
index 0000000000000..1af5359d24dc9
--- /dev/null
+++ b/fs/partitions/efi.h
@@ -0,0 +1,133 @@
+/************************************************************
+ * EFI GUID Partition Table
+ * Per Intel EFI Specification v1.02
+ * http://developer.intel.com/technology/efi/efi.htm
+ *
+ * By Matt Domsch <Matt_Domsch@dell.com> Fri Sep 22 22:15:56 CDT 2000
+ * Copyright 2000,2001 Dell Computer Corporation
+ *
+ * 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
+ *
+ ************************************************************/
+
+#ifndef FS_PART_EFI_H_INCLUDED
+#define FS_PART_EFI_H_INCLUDED
+
+#include <linux/types.h>
+#include <linux/config.h>
+#include <linux/fs.h>
+#include <linux/genhd.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/string.h>
+#include <linux/blk.h>
+/*
+ * Yes, specifying asm-ia64 is ugly, but this lets it build on
+ * other platforms too, until efi.h moves to include/linux.
+ */
+#include <asm-ia64/efi.h>
+
+#define MSDOS_MBR_SIGNATURE 0xaa55
+#define EFI_PMBR_OSTYPE_EFI 0xEF
+#define EFI_PMBR_OSTYPE_EFI_GPT 0xEE
+
+#define GPT_BLOCK_SIZE 512
+#define GPT_HEADER_SIGNATURE 0x5452415020494645L
+#define GPT_HEADER_REVISION_V1 0x00010000
+#define GPT_PRIMARY_PARTITION_TABLE_LBA 1
+
+#define UNUSED_ENTRY_GUID \
+ ((efi_guid_t) { 0x00000000, 0x0000, 0x0000, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }})
+#define PARTITION_SYSTEM_GUID \
+((efi_guid_t) { 0xC12A7328, 0xF81F, 0x11d2, { 0xBA, 0x4B, 0x00, 0xA0, 0xC9, 0x3E, 0xC9, 0x3B }})
+#define LEGACY_MBR_PARTITION_GUID \
+ ((efi_guid_t) { 0x024DEE41, 0x33E7, 0x11d3, { 0x9D, 0x69, 0x00, 0x08, 0xC7, 0x81, 0xF3, 0x9F }})
+#define PARTITION_MSFT_RESERVED_GUID \
+ ((efi_guid_t) { 0xE3C9E316, 0x0B5C, 0x4DB8, { 0x81, 0x7D, 0xF9, 0x2D, 0xF0, 0x02, 0x15, 0xAE }})
+#define PARTITION_BASIC_DATA_GUID \
+ ((efi_guid_t) { 0xEBD0A0A2, 0xB9E5, 0x4433, { 0x87, 0xC0, 0x68, 0xB6, 0xB7, 0x26, 0x99, 0xC7 }})
+#define PARTITION_LINUX_RAID_GUID \
+ ((efi_guid_t) { 0xa19d880f, 0x05fc, 0x4d3b, { 0xa0, 0x06, 0x74, 0x3f, 0x0f, 0x84, 0x91, 0x1e }})
+#define PARTITION_LINUX_SWAP_GUID \
+ ((efi_guid_t) { 0x0657fd6d, 0xa4ab, 0x43c4, { 0x84, 0xe5, 0x09, 0x33, 0xc8, 0x4b, 0x4f, 0x4f }})
+#define PARTITION_LINUX_LVM_GUID \
+ ((efi_guid_t) { 0xe6d6d379, 0xf507, 0x44c2, { 0xa2, 0x3c, 0x23, 0x8f, 0x2a, 0x3d, 0xf9, 0x28 }})
+
+typedef struct _gpt_header {
+ u64 signature;
+ u32 revision;
+ u32 header_size;
+ u32 header_crc32;
+ u32 reserved1;
+ u64 my_lba;
+ u64 alternate_lba;
+ u64 first_usable_lba;
+ u64 last_usable_lba;
+ efi_guid_t disk_guid;
+ u64 partition_entry_lba;
+ u32 num_partition_entries;
+ u32 sizeof_partition_entry;
+ u32 partition_entry_array_crc32;
+ u8 reserved2[GPT_BLOCK_SIZE - 92];
+} __attribute__ ((packed)) gpt_header;
+
+typedef struct _gpt_entry_attributes {
+ u64 required_to_function:1;
+ u64 reserved:47;
+ u64 type_guid_specific:16;
+} __attribute__ ((packed)) gpt_entry_attributes;
+
+typedef struct _gpt_entry {
+ efi_guid_t partition_type_guid;
+ efi_guid_t unique_partition_guid;
+ u64 starting_lba;
+ u64 ending_lba;
+ gpt_entry_attributes attributes;
+ efi_char16_t partition_name[72 / sizeof (efi_char16_t)];
+} __attribute__ ((packed)) gpt_entry;
+
+typedef struct _legacy_mbr {
+ u8 boot_code[440];
+ u32 unique_mbr_signature;
+ u16 unknown;
+ struct partition partition_record[4];
+ u16 signature;
+} __attribute__ ((packed)) legacy_mbr;
+
+/* Functions */
+extern int
+ efi_partition(struct gendisk *hd, struct block_device *bdev,
+ unsigned long first_sector, int first_part_minor);
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only. This must remain at the end
+ * of the file.
+ * --------------------------------------------------------------------------
+ * Local variables:
+ * c-indent-level: 4
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -4
+ * c-argdecl-indent: 4
+ * c-label-offset: -4
+ * c-continued-statement-offset: 4
+ * c-continued-brace-offset: 0
+ * indent-tabs-mode: nil
+ * tab-width: 8
+ * End:
+ */
diff --git a/fs/partitions/msdos.c b/fs/partitions/msdos.c
index 43c6ab1e7ce7f..ee85285e9fe18 100644
--- a/fs/partitions/msdos.c
+++ b/fs/partitions/msdos.c
@@ -41,6 +41,7 @@ EXPORT_SYMBOL(ide_xlate_1024_hook);
#include "check.h"
#include "msdos.h"
+#include "efi.h"
#if CONFIG_BLK_DEV_MD
extern void md_autodetect_dev(kdev_t dev);
@@ -536,6 +537,16 @@ int msdos_partition(struct gendisk *hd, struct block_device *bdev,
return 0;
}
p = (struct partition *) (data + 0x1be);
+#ifdef CONFIG_EFI_PARTITION
+ for (i=1 ; i<=4 ; i++,p++) {
+ /* If this is an EFI GPT disk, msdos should ignore it. */
+ if (SYS_IND(p) == EFI_PMBR_OSTYPE_EFI_GPT) {
+ put_dev_sector(sect);
+ return 0;
+ }
+ }
+ p = (struct partition *) (data + 0x1be);
+#endif
/*
* Look for partitions in two passes:
diff --git a/fs/proc/array.c b/fs/proc/array.c
index d216d47ddcdc5..28c6a3d4a3ef0 100644
--- a/fs/proc/array.c
+++ b/fs/proc/array.c
@@ -227,6 +227,7 @@ static void collect_sigign_sigcatch(struct task_struct *p, sigset_t *ign,
sigemptyset(ign);
sigemptyset(catch);
+ spin_lock_irq(&p->sigmask_lock);
if (p->sig) {
k = p->sig->action;
for (i = 1; i <= _NSIG; ++i, ++k) {
@@ -236,6 +237,7 @@ static void collect_sigign_sigcatch(struct task_struct *p, sigset_t *ign,
sigaddset(catch, i);
}
}
+ spin_unlock_irq(&p->sigmask_lock);
}
static inline char * task_sig(struct task_struct *p, char *buffer)
diff --git a/fs/proc/inode.c b/fs/proc/inode.c
index 4ae60bfb88fb4..638d218a7f15d 100644
--- a/fs/proc/inode.c
+++ b/fs/proc/inode.c
@@ -133,8 +133,11 @@ static int parse_options(char *options,uid_t *uid,gid_t *gid)
*uid = current->uid;
*gid = current->gid;
- if (!options) return 1;
- for (this_char = strtok(options,","); this_char; this_char = strtok(NULL,",")) {
+ if (!options)
+ return 1;
+ while ((this_char = strsep(&options,",")) != NULL) {
+ if (!*this_char)
+ continue;
if ((value = strchr(this_char,'=')) != NULL)
*value++ = 0;
if (!strcmp(this_char,"uid")) {
diff --git a/fs/proc/proc_misc.c b/fs/proc/proc_misc.c
index b176467ff7659..7cabf182edf5e 100644
--- a/fs/proc/proc_misc.c
+++ b/fs/proc/proc_misc.c
@@ -51,7 +51,6 @@
* wrappers, but this needs further analysis wrt potential overflows.
*/
extern int get_device_list(char *);
-extern int get_partition_list(char *, char **, off_t, int);
extern int get_filesystem_list(char *);
extern int get_exec_domain_list(char *);
extern int get_dma_list(char *);
@@ -199,6 +198,18 @@ static struct file_operations proc_cpuinfo_operations = {
release: seq_release,
};
+extern struct seq_operations partitions_op;
+static int partitions_open(struct inode *inode, struct file *file)
+{
+ return seq_open(file, &partitions_op);
+}
+static struct file_operations proc_partitions_operations = {
+ open: partitions_open,
+ read: seq_read,
+ llseek: seq_lseek,
+ release: seq_release,
+};
+
#ifdef CONFIG_MODULES
extern struct seq_operations modules_op;
static int modules_open(struct inode *inode, struct file *file)
@@ -323,14 +334,6 @@ static int devices_read_proc(char *page, char **start, off_t off,
return proc_calc_metrics(page, start, off, count, eof, len);
}
-static int partitions_read_proc(char *page, char **start, off_t off,
- int count, int *eof, void *data)
-{
- int len = get_partition_list(page, start, off, count);
- if (len < count) *eof = 1;
- return len;
-}
-
static void *single_start(struct seq_file *p, loff_t *pos)
{
return NULL + (*pos == 0);
@@ -538,7 +541,6 @@ void __init proc_misc_init(void)
{"version", version_read_proc},
{"stat", kstat_read_proc},
{"devices", devices_read_proc},
- {"partitions", partitions_read_proc},
{"filesystems", filesystems_read_proc},
{"dma", dma_read_proc},
{"ioports", ioports_read_proc},
@@ -562,6 +564,7 @@ void __init proc_misc_init(void)
if (entry)
entry->proc_fops = &proc_kmsg_operations;
create_seq_entry("cpuinfo", 0, &proc_cpuinfo_operations);
+ create_seq_entry("partitions", 0, &proc_partitions_operations);
create_seq_entry("interrupts", 0, &proc_interrupts_operations);
create_seq_entry("slabinfo",S_IWUSR|S_IRUGO,&proc_slabinfo_operations);
#ifdef CONFIG_MODULES
diff --git a/fs/reiserfs/journal.c b/fs/reiserfs/journal.c
index 6f404024b8835..bf28a245c6589 100644
--- a/fs/reiserfs/journal.c
+++ b/fs/reiserfs/journal.c
@@ -1958,8 +1958,7 @@ static int journal_init_dev( struct super_block *super,
SB_ONDISK_JOURNAL_DEVICE( super ) ?
to_kdev_t(SB_ONDISK_JOURNAL_DEVICE( super )) : super -> s_dev;
/* there is no "jdev" option and journal is on separate device */
- if( ( !jdev_name || !jdev_name[ 0 ] ) &&
- SB_ONDISK_JOURNAL_DEVICE( super ) ) {
+ if( ( !jdev_name || !jdev_name[ 0 ] ) ) {
journal -> j_dev_bd = bdget( kdev_t_to_nr( jdev ) );
if( journal -> j_dev_bd )
result = blkdev_get( journal -> j_dev_bd,
@@ -1974,9 +1973,6 @@ static int journal_init_dev( struct super_block *super,
return result;
}
- /* no "jdev" option and journal is on the host device */
- if( !jdev_name || !jdev_name[ 0 ] )
- return 0;
journal -> j_dev_file = filp_open( jdev_name, 0, 0 );
if( !IS_ERR( journal -> j_dev_file ) ) {
struct inode *jdev_inode;
diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c
index cf59e892c0206..4698081c8d342 100644
--- a/fs/reiserfs/super.c
+++ b/fs/reiserfs/super.c
@@ -508,7 +508,9 @@ static int parse_options (char * options, unsigned long * mount_options, unsigne
/* use default configuration: create tails, journaling on, no
conversion to newest format */
return 1;
- for (this_char = strtok (options, ","); this_char != NULL; this_char = strtok (NULL, ",")) {
+ while ((this_char = strsep (&options, ",")) != NULL) {
+ if (!*this_char)
+ continue;
if ((value = strchr (this_char, '=')) != NULL)
*value++ = 0;
if (!strcmp (this_char, "notail")) {
@@ -991,7 +993,6 @@ int function2code (hashf_t func)
//
static int reiserfs_fill_super(struct super_block *s, void *data, int silent)
{
- int size;
struct inode *root_inode;
int j;
struct reiserfs_transaction_handle th ;
@@ -1013,9 +1014,6 @@ static int reiserfs_fill_super(struct super_block *s, void *data, int silent)
return -EINVAL;
}
- size = block_size(s->s_dev);
- sb_set_blocksize(s, size);
-
/* try old format (undistributed bitmap, super block in 8-th 1k block of a device) */
if (!read_super_block (s, REISERFS_OLD_DISK_OFFSET_IN_BYTES))
old_format = 1;
diff --git a/fs/romfs/inode.c b/fs/romfs/inode.c
index 7ed521adcc8e6..b833c85321635 100644
--- a/fs/romfs/inode.c
+++ b/fs/romfs/inode.c
@@ -536,7 +536,51 @@ romfs_read_inode(struct inode *i)
}
}
+static kmem_cache_t * romfs_inode_cachep;
+
+static struct inode *romfs_alloc_inode(struct super_block *sb)
+{
+ struct romfs_inode_info *ei;
+ ei = (struct romfs_inode_info *)kmem_cache_alloc(romfs_inode_cachep, SLAB_KERNEL);
+ if (!ei)
+ return NULL;
+ return &ei->vfs_inode;
+}
+
+static void romfs_destroy_inode(struct inode *inode)
+{
+ kmem_cache_free(romfs_inode_cachep, ROMFS_I(inode));
+}
+
+static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
+{
+ struct romfs_inode_info *ei = (struct romfs_inode_info *) foo;
+
+ if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
+ SLAB_CTOR_CONSTRUCTOR)
+ inode_init_once(&ei->vfs_inode);
+}
+
+static int init_inodecache(void)
+{
+ romfs_inode_cachep = kmem_cache_create("romfs_inode_cache",
+ sizeof(struct romfs_inode_info),
+ 0, SLAB_HWCACHE_ALIGN,
+ init_once, NULL);
+ if (romfs_inode_cachep == NULL)
+ return -ENOMEM;
+ return 0;
+}
+
+static void destroy_inodecache(void)
+{
+ if (kmem_cache_destroy(romfs_inode_cachep))
+ printk(KERN_INFO "romfs_inode_cache: not all structures were freed\n");
+}
+
static struct super_operations romfs_ops = {
+ alloc_inode: romfs_alloc_inode,
+ destroy_inode: romfs_destroy_inode,
read_inode: romfs_read_inode,
statfs: romfs_statfs,
};
@@ -557,12 +601,23 @@ static struct file_system_type romfs_fs_type = {
static int __init init_romfs_fs(void)
{
- return register_filesystem(&romfs_fs_type);
+ int err = init_inodecache();
+ if (err)
+ goto out1;
+ err = register_filesystem(&romfs_fs_type);
+ if (err)
+ goto out;
+ return 0;
+out:
+ destroy_inodecache();
+out1:
+ return err;
}
static void __exit exit_romfs_fs(void)
{
unregister_filesystem(&romfs_fs_type);
+ destroy_inodecache();
}
/* Yes, works even as a module... :) */
diff --git a/fs/super.c b/fs/super.c
index 1a2d66737e087..7c259fb46b8e1 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -26,6 +26,7 @@
#include <linux/smp_lock.h>
#include <linux/devfs_fs_kernel.h>
#include <linux/acct.h>
+#include <linux/blkdev.h>
#include <asm/uaccess.h>
void get_filesystem(struct file_system_type *fs);
@@ -513,6 +514,8 @@ struct super_block *get_sb_bdev(struct file_system_type *fs_type,
} else {
s->s_flags = flags;
strncpy(s->s_id, bdevname(dev), sizeof(s->s_id));
+ s->s_old_blocksize = block_size(dev);
+ sb_set_blocksize(s, s->s_old_blocksize);
error = fill_super(s, data, flags & MS_VERBOSE ? 1 : 0);
if (error) {
up_write(&s->s_umount);
@@ -535,6 +538,7 @@ void kill_block_super(struct super_block *sb)
{
struct block_device *bdev = sb->s_bdev;
generic_shutdown_super(sb);
+ set_blocksize(to_kdev_t(bdev->bd_dev), sb->s_old_blocksize);
bd_release(bdev);
blkdev_put(bdev, BDEV_FS);
}
diff --git a/fs/udf/super.c b/fs/udf/super.c
index 2edd4015fb61c..43b13b6ebe5bd 100644
--- a/fs/udf/super.c
+++ b/fs/udf/super.c
@@ -286,8 +286,9 @@ udf_parse_options(char *options, struct udf_options *uopt)
if (!options)
return 1;
- for (opt = strtok(options, ","); opt; opt = strtok(NULL, ","))
- {
+ while ((opt = strsep(&options, ",")) != NULL) {
+ if (!*opt)
+ continue;
/* Make "opt=val" into two strings */
val = strchr(opt, '=');
if (val)
diff --git a/fs/ufs/super.c b/fs/ufs/super.c
index c2cd329064b37..e13ce227d0bf1 100644
--- a/fs/ufs/super.c
+++ b/fs/ufs/super.c
@@ -257,11 +257,10 @@ static int ufs_parse_options (char * options, unsigned * mount_options)
if (!options)
return 1;
-
- for (this_char = strtok (options, ",");
- this_char != NULL;
- this_char = strtok (NULL, ",")) {
-
+
+ while ((this_char = strsep (&options, ",")) != NULL) {
+ if (!*this_char)
+ continue;
if ((value = strchr (this_char, '=')) != NULL)
*value++ = 0;
if (!strcmp (this_char, "ufstype")) {
diff --git a/fs/vfat/namei.c b/fs/vfat/namei.c
index e44b87116be1e..c71cf4971f46b 100644
--- a/fs/vfat/namei.c
+++ b/fs/vfat/namei.c
@@ -115,7 +115,9 @@ static int parse_options(char *options, struct fat_mount_options *opts)
save = 0;
savep = NULL;
ret = 1;
- for (this_char = strtok(options,","); this_char; this_char = strtok(NULL,",")) {
+ while ((this_char = strsep(&options,",")) != NULL) {
+ if (!*this_char)
+ continue;
if ((value = strchr(this_char,'=')) != NULL) {
save = *value;
savep = value;
diff --git a/include/asm-arm/arch-cl7500/system.h b/include/asm-arm/arch-cl7500/system.h
index 6cb0021948345..fee569dd0303b 100644
--- a/include/asm-arm/arch-cl7500/system.h
+++ b/include/asm-arm/arch-cl7500/system.h
@@ -18,6 +18,6 @@ static void arch_idle(void)
do { \
iomd_writeb(0, IOMD_ROMCR0); \
cpu_reset(0); \
- } while (0);
+ } while (0)
#endif
diff --git a/include/asm-arm/arch-sa1100/keyboard.h b/include/asm-arm/arch-sa1100/keyboard.h
index 0207ba65ed6e2..aa7f317092e52 100644
--- a/include/asm-arm/arch-sa1100/keyboard.h
+++ b/include/asm-arm/arch-sa1100/keyboard.h
@@ -10,8 +10,8 @@
#include <asm/mach-types.h>
#include <asm/arch/assabet.h>
-#define kbd_disable_irq() do { } while(0);
-#define kbd_enable_irq() do { } while(0);
+#define kbd_disable_irq() do { } while(0)
+#define kbd_enable_irq() do { } while(0)
extern int sa1111_kbd_init_hw(void);
extern void gc_kbd_init_hw(void);
diff --git a/include/asm-i386/apic.h b/include/asm-i386/apic.h
index 89921f9d78438..d36b2f10f7310 100644
--- a/include/asm-i386/apic.h
+++ b/include/asm-i386/apic.h
@@ -3,6 +3,7 @@
#include <linux/config.h>
#include <linux/pm.h>
+#include <asm/fixmap.h>
#include <asm/apicdef.h>
#include <asm/system.h>
diff --git a/include/asm-i386/apicdef.h b/include/asm-i386/apicdef.h
index f855a7d88d828..a91e6ede6b0af 100644
--- a/include/asm-i386/apicdef.h
+++ b/include/asm-i386/apicdef.h
@@ -71,6 +71,7 @@
#define GET_APIC_DEST_FIELD(x) (((x)>>24)&0xFF)
#define SET_APIC_DEST_FIELD(x) ((x)<<24)
#define APIC_LVTT 0x320
+#define APIC_LVTTHMR 0x330
#define APIC_LVTPC 0x340
#define APIC_LVT0 0x350
#define APIC_LVT_TIMER_BASE_MASK (0x3<<18)
@@ -280,7 +281,16 @@ struct local_apic {
u32 __reserved_4[3];
} lvt_timer;
-/*330*/ struct { u32 __reserved[4]; } __reserved_15;
+/*330*/ struct { /* LVT - Thermal Sensor */
+ u32 vector : 8,
+ delivery_mode : 3,
+ __reserved_1 : 1,
+ delivery_status : 1,
+ __reserved_2 : 3,
+ mask : 1,
+ __reserved_3 : 15;
+ u32 __reserved_4[3];
+ } lvt_thermal;
/*340*/ struct { /* LVT - Performance Counter */
u32 vector : 8,
diff --git a/include/asm-i386/checksum.h b/include/asm-i386/checksum.h
index 6b9761aa8f372..7c0527f9256b5 100644
--- a/include/asm-i386/checksum.h
+++ b/include/asm-i386/checksum.h
@@ -1,6 +1,7 @@
#ifndef _I386_CHECKSUM_H
#define _I386_CHECKSUM_H
+#include <linux/in6.h>
/*
* computes the checksum of a memory block at buff, length len,
diff --git a/include/asm-i386/hw_irq.h b/include/asm-i386/hw_irq.h
index 1461dab08d90a..bf447a1b97b2d 100644
--- a/include/asm-i386/hw_irq.h
+++ b/include/asm-i386/hw_irq.h
@@ -43,6 +43,7 @@
#define RESCHEDULE_VECTOR 0xfc
#define CALL_FUNCTION_VECTOR 0xfb
+#define THERMAL_APIC_VECTOR 0xf0
/*
* Local APIC timer IRQ vector is on a different priority level,
* to work around the 'lost local interrupt if more than 2 IRQ
diff --git a/include/asm-i386/io.h b/include/asm-i386/io.h
index f578b76c40cf8..a54484360fa95 100644
--- a/include/asm-i386/io.h
+++ b/include/asm-i386/io.h
@@ -57,15 +57,37 @@
#define __io_virt(x) ((void *)(x))
#endif
-/*
- * Change virtual addresses to physical addresses and vv.
- * These are pretty trivial
+/**
+ * virt_to_phys - map virtual addresses to physical
+ * @address: address to remap
+ *
+ * The returned physical address is the physical (CPU) mapping for
+ * the memory address given. It is only valid to use this function on
+ * addresses directly mapped or allocated via kmalloc.
+ *
+ * This function does not give bus mappings for DMA transfers. In
+ * almost all conceivable cases a device driver should not be using
+ * this function
*/
+
static inline unsigned long virt_to_phys(volatile void * address)
{
return __pa(address);
}
+/**
+ * phys_to_virt - map physical address to virtual
+ * @address: address to remap
+ *
+ * The returned virtual address is a current CPU mapping for
+ * the memory address given. It is only valid to use this function on
+ * addresses that have a kernel mapping
+ *
+ * This function does not handle bus mappings for DMA transfers. In
+ * almost all conceivable cases a device driver should not be using
+ * this function
+ */
+
static inline void * phys_to_virt(unsigned long address)
{
return __va(address);
@@ -74,20 +96,51 @@ static inline void * phys_to_virt(unsigned long address)
/*
* Change "struct page" to physical address.
*/
+#ifdef CONFIG_HIGHMEM64G
+#define page_to_phys(page) ((u64)(page - mem_map) << PAGE_SHIFT)
+#else
#define page_to_phys(page) ((page - mem_map) << PAGE_SHIFT)
+#endif
extern void * __ioremap(unsigned long offset, unsigned long size, unsigned long flags);
+/**
+ * ioremap - map bus memory into CPU space
+ * @offset: bus address of the memory
+ * @size: size of the resource to map
+ *
+ * ioremap performs a platform specific sequence of operations to
+ * make bus memory CPU accessible via the readb/readw/readl/writeb/
+ * writew/writel functions and the other mmio helpers. The returned
+ * address is not guaranteed to be usable directly as a virtual
+ * address.
+ */
+
static inline void * ioremap (unsigned long offset, unsigned long size)
{
return __ioremap(offset, size, 0);
}
-/*
- * This one maps high address device memory and turns off caching for that area.
- * it's useful if some control registers are in such an area and write combining
- * or read caching is not desirable:
+/**
+ * ioremap_nocache - map bus memory into CPU space
+ * @offset: bus address of the memory
+ * @size: size of the resource to map
+ *
+ * ioremap_nocache performs a platform specific sequence of operations to
+ * make bus memory CPU accessible via the readb/readw/readl/writeb/
+ * writew/writel functions and the other mmio helpers. The returned
+ * address is not guaranteed to be usable directly as a virtual
+ * address.
+ *
+ * This version of ioremap ensures that the memory is marked uncachable
+ * on the CPU as well as honouring existing caching rules from things like
+ * the PCI bus. Note that there are other caches and buffers on many
+ * busses. In paticular driver authors should read up on PCI writes
+ *
+ * It's useful if some control registers are in such an area and
+ * write combining or read caching is not desirable:
*/
+
static inline void * ioremap_nocache (unsigned long offset, unsigned long size)
{
return __ioremap(offset, size, _PAGE_PCD);
@@ -172,6 +225,17 @@ extern unsigned long bus_to_virt_not_defined_use_pci_map(volatile void *addr);
#define eth_io_copy_and_sum(a,b,c,d) eth_copy_and_sum((a),__io_virt(b),(c),(d))
#define isa_eth_io_copy_and_sum(a,b,c,d) eth_copy_and_sum((a),__io_virt(__ISA_IO_base + (b)),(c),(d))
+/**
+ * check_signature - find BIOS signatures
+ * @io_addr: mmio address to check
+ * @signature: signature block
+ * @length: length of signature
+ *
+ * Perform a signature comparison with the mmio address io_addr. This
+ * address should have been obtained by ioremap.
+ * Returns 1 on a match.
+ */
+
static inline int check_signature(unsigned long io_addr,
const unsigned char *signature, int length)
{
@@ -188,6 +252,20 @@ out:
return retval;
}
+/**
+ * isa_check_signature - find BIOS signatures
+ * @io_addr: mmio address to check
+ * @signature: signature block
+ * @length: length of signature
+ *
+ * Perform a signature comparison with the ISA mmio address io_addr.
+ * Returns 1 on a match.
+ *
+ * This function is deprecated. New drivers should use ioremap and
+ * check_signature.
+ */
+
+
static inline int isa_check_signature(unsigned long io_addr,
const unsigned char *signature, int length)
{
diff --git a/include/asm-i386/irq.h b/include/asm-i386/irq.h
index c1bcd739bc7bb..269bf3e1aa8bb 100644
--- a/include/asm-i386/irq.h
+++ b/include/asm-i386/irq.h
@@ -11,6 +11,7 @@
*/
#include <linux/config.h>
+#include <linux/sched.h>
#define TIMER_IRQ 0
diff --git a/include/asm-i386/msr.h b/include/asm-i386/msr.h
index d3f23faa638a0..2a57654f0d0f3 100644
--- a/include/asm-i386/msr.h
+++ b/include/asm-i386/msr.h
@@ -48,8 +48,8 @@
#define MSR_IA32_UCODE_WRITE 0x79
#define MSR_IA32_UCODE_REV 0x8b
-#define MSR_IA32_PERFCTR0 0xc1
-#define MSR_IA32_PERFCTR1 0xc2
+#define MSR_P6_PERFCTR0 0xc1
+#define MSR_P6_PERFCTR1 0xc2
#define MSR_IA32_BBL_CR_CTL 0x119
@@ -57,8 +57,13 @@
#define MSR_IA32_MCG_STATUS 0x17a
#define MSR_IA32_MCG_CTL 0x17b
-#define MSR_IA32_EVNTSEL0 0x186
-#define MSR_IA32_EVNTSEL1 0x187
+#define MSR_P6_EVNTSEL0 0x186
+#define MSR_P6_EVNTSEL1 0x187
+
+#define MSR_IA32_THERM_CONTROL 0x19a
+#define MSR_IA32_THERM_INTERRUPT 0x19b
+#define MSR_IA32_THERM_STATUS 0x19c
+#define MSR_IA32_MISC_ENABLE 0x1a0
#define MSR_IA32_DEBUGCTLMSR 0x1d9
#define MSR_IA32_LASTBRANCHFROMIP 0x1db
diff --git a/include/asm-i386/processor.h b/include/asm-i386/processor.h
index 573dac8f51ab0..13eec87ba8fdd 100644
--- a/include/asm-i386/processor.h
+++ b/include/asm-i386/processor.h
@@ -59,6 +59,7 @@ struct cpuinfo_x86 {
#define X86_VENDOR_CENTAUR 5
#define X86_VENDOR_RISE 6
#define X86_VENDOR_TRANSMETA 7
+#define X86_VENDOR_NSC 8
#define X86_VENDOR_UNKNOWN 0xff
/*
@@ -216,7 +217,7 @@ static inline void clear_in_cr4 (unsigned long mask)
}
/*
- * Cyrix CPU configuration register indexes
+ * NSC/Cyrix CPU configuration register indexes
*/
#define CX86_CCR0 0xc0
#define CX86_CCR1 0xc1
@@ -232,7 +233,7 @@ static inline void clear_in_cr4 (unsigned long mask)
#define CX86_RCR_BASE 0xdc
/*
- * Cyrix CPU indexed register access macros
+ * NSC/Cyrix CPU indexed register access macros
*/
#define getCx86(reg) ({ outb((reg), 0x22); inb(0x23); })
diff --git a/include/asm-i386/rwsem.h b/include/asm-i386/rwsem.h
index 3cac142723806..9caff19cfd2e2 100644
--- a/include/asm-i386/rwsem.h
+++ b/include/asm-i386/rwsem.h
@@ -164,7 +164,7 @@ LOCK_PREFIX " xadd %%edx,(%%eax)\n\t" /* subtracts 1, returns the old valu
" jmp 1b\n"
LOCK_SECTION_END
"# ending __up_read\n"
- : "+m"(sem->count), "+d"(tmp)
+ : /*"+m"(sem->count),*/ "+d"(tmp)
: "a"(sem)
: "memory", "cc");
}
diff --git a/include/asm-i386/string-486.h b/include/asm-i386/string-486.h
index 51bfd051bc003..4104ab9bc9f9b 100644
--- a/include/asm-i386/string-486.h
+++ b/include/asm-i386/string-486.h
@@ -5,7 +5,7 @@
* This string-include defines all string functions as inline
* functions. Use gcc. It also assumes ds=es=data space, this should be
* normal. Most of the string-functions are rather heavily hand-optimized,
- * see especially strtok,strstr,str[c]spn. They should work, but are not
+ * see especially strsep,strstr,str[c]spn. They should work, but are not
* very easy to understand. Everything is done entirely within the register
* set, making the functions fast and clean.
*
diff --git a/include/asm-i386/string.h b/include/asm-i386/string.h
index d4d7899dc1aa9..96f4e52fc7f78 100644
--- a/include/asm-i386/string.h
+++ b/include/asm-i386/string.h
@@ -20,7 +20,7 @@
* This string-include defines all string functions as inline
* functions. Use gcc. It also assumes ds=es=data space, this should be
* normal. Most of the string-functions are rather heavily hand-optimized,
- * see especially strtok,strstr,str[c]spn. They should work, but are not
+ * see especially strsep,strstr,str[c]spn. They should work, but are not
* very easy to understand. Everything is done entirely within the register
* set, making the functions fast and clean. String instructions have been
* used through-out, making for "slightly" unclear code :-)
diff --git a/include/asm-i386/timex.h b/include/asm-i386/timex.h
index 97099dd0d4148..6cfc7c9a08fc6 100644
--- a/include/asm-i386/timex.h
+++ b/include/asm-i386/timex.h
@@ -9,7 +9,12 @@
#include <linux/config.h>
#include <asm/msr.h>
-#define CLOCK_TICK_RATE 1193180 /* Underlying HZ */
+#ifdef CONFIG_MELAN
+# define CLOCK_TICK_RATE 1189200 /* AMD Elan has different frequency! */
+#else
+# define CLOCK_TICK_RATE 1193180 /* Underlying HZ */
+#endif
+
#define CLOCK_TICK_FACTOR 20 /* Factor of both 1000000 and CLOCK_TICK_RATE */
#define FINETUNE ((((((long)LATCH * HZ - CLOCK_TICK_RATE) << SHIFT_HZ) * \
(1000000/CLOCK_TICK_FACTOR) / (CLOCK_TICK_RATE/CLOCK_TICK_FACTOR)) \
diff --git a/include/asm-m68k/string.h b/include/asm-m68k/string.h
index 5183aa0096d86..5604739225b34 100644
--- a/include/asm-m68k/string.h
+++ b/include/asm-m68k/string.h
@@ -117,29 +117,6 @@ static inline size_t strspn(const char *s, const char *accept)
}
#endif
-#if 0
-#define __HAVE_ARCH_STRTOK
-extern inline char * strtok(char * s,const char * ct)
-{
- char *sbegin, *send;
-
- sbegin = s ? s : ___strtok;
- if (!sbegin) {
- return NULL;
- }
- sbegin += strspn(sbegin,ct);
- if (*sbegin == '\0') {
- ___strtok = NULL;
- return( NULL );
- }
- send = strpbrk( sbegin, ct);
- if (send && *send != '\0')
- *send++ = '\0';
- ___strtok = send;
- return (sbegin);
-}
-#endif
-
/* strstr !! */
#define __HAVE_ARCH_STRLEN
diff --git a/include/asm-mips/spinlock.h b/include/asm-mips/spinlock.h
index 61ebfa6603eb9..fb02686f78964 100644
--- a/include/asm-mips/spinlock.h
+++ b/include/asm-mips/spinlock.h
@@ -19,10 +19,10 @@ typedef struct {
#define SPIN_LOCK_UNLOCKED (spinlock_t) { 0 }
-#define spin_lock_init(x) do { (x)->lock = 0; } while(0);
+#define spin_lock_init(x) do { (x)->lock = 0; } while(0)
#define spin_is_locked(x) ((x)->lock != 0)
-#define spin_unlock_wait(x) ({ do { barrier(); } while ((x)->lock); })
+#define spin_unlock_wait(x) do { barrier(); } while ((x)->lock)
/*
* Simple spin lock operations. There are two variants, one clears IRQ's
diff --git a/include/asm-mips64/spinlock.h b/include/asm-mips64/spinlock.h
index 7e560d4c05a46..9ce6c6c2e13cb 100644
--- a/include/asm-mips64/spinlock.h
+++ b/include/asm-mips64/spinlock.h
@@ -19,10 +19,10 @@ typedef struct {
#define SPIN_LOCK_UNLOCKED (spinlock_t) { 0 }
-#define spin_lock_init(x) do { (x)->lock = 0; } while(0);
+#define spin_lock_init(x) do { (x)->lock = 0; } while(0)
#define spin_is_locked(x) ((x)->lock != 0)
-#define spin_unlock_wait(x) ({ do { barrier(); } while ((x)->lock); })
+#define spin_unlock_wait(x) do { barrier(); } while ((x)->lock)
/*
* Simple spin lock operations. There are two variants, one clears IRQ's
diff --git a/include/asm-parisc/pgalloc.h b/include/asm-parisc/pgalloc.h
index b29fa8aef9be4..37e7511bedd7a 100644
--- a/include/asm-parisc/pgalloc.h
+++ b/include/asm-parisc/pgalloc.h
@@ -123,7 +123,7 @@ extern void flush_instruction_tlb(void);
#define flush_tlb() do { \
flush_data_tlb(); \
flush_instruction_tlb(); \
-} while(0);
+} while(0)
#define flush_tlb_all() flush_tlb() /* XXX p[id]tlb */
diff --git a/include/asm-sparc/elf.h b/include/asm-sparc/elf.h
index 436d1a9ad56b7..d6e8a340495d4 100644
--- a/include/asm-sparc/elf.h
+++ b/include/asm-sparc/elf.h
@@ -41,7 +41,7 @@ do { unsigned long *dest = &(__elf_regs[0]); \
dest[34] = src->npc; \
dest[35] = src->y; \
dest[36] = dest[37] = 0; /* XXX */ \
-} while(0);
+} while(0)
typedef struct {
union {
diff --git a/include/asm-sparc/pgtable.h b/include/asm-sparc/pgtable.h
index 518f153793946..b73aaa20847e0 100644
--- a/include/asm-sparc/pgtable.h
+++ b/include/asm-sparc/pgtable.h
@@ -293,6 +293,9 @@ BTFIXUPDEF_CALL_CONST(pte_t, pte_mkyoung, pte_t)
#define page_pte_prot(page, prot) mk_pte(page, prot)
#define page_pte(page) page_pte_prot(page, __pgprot(0))
+/* Permanent address of a page. */
+#define page_address(page) ((page)->virtual)
+
BTFIXUPDEF_CALL(struct page *, pte_page, pte_t)
#define pte_page(pte) BTFIXUP_CALL(pte_page)(pte)
diff --git a/include/asm-sparc/sbus.h b/include/asm-sparc/sbus.h
index 6a687a465c214..d26fd0326a038 100644
--- a/include/asm-sparc/sbus.h
+++ b/include/asm-sparc/sbus.h
@@ -94,7 +94,8 @@ sbus_is_slave(struct sbus_dev *dev)
for((device) = (bus)->devices; (device); (device)=(device)->next)
#define for_all_sbusdev(device, bus) \
- for((bus) = sbus_root, ((device) = (bus) ? (bus)->devices : 0); (bus); (device)=((device)->next ? (device)->next : ((bus) = (bus)->next, (bus) ? (bus)->devices : 0)))
+ for ((bus) = sbus_root; (bus); (bus) = (bus)->next) \
+ for ((device) = (bus)->devices; (device); (device) = (device)->next)
/* Driver DVMA interfaces. */
#define sbus_can_dma_64bit(sdev) (0) /* actually, sparc_cpu_model==sun4d */
diff --git a/include/asm-sparc64/pgalloc.h b/include/asm-sparc64/pgalloc.h
index d2909390fc6d2..7f3f59461552c 100644
--- a/include/asm-sparc64/pgalloc.h
+++ b/include/asm-sparc64/pgalloc.h
@@ -10,13 +10,6 @@
#include <asm/spitfire.h>
#include <asm/pgtable.h>
-#define VPTE_BASE_SPITFIRE 0xfffffffe00000000
-#if 1
-#define VPTE_BASE_CHEETAH VPTE_BASE_SPITFIRE
-#else
-#define VPTE_BASE_CHEETAH 0xffe0000000000000
-#endif
-
static __inline__ void flush_tlb_pgtables(struct mm_struct *mm, unsigned long start,
unsigned long end)
{
@@ -42,8 +35,6 @@ static __inline__ void flush_tlb_pgtables(struct mm_struct *mm, unsigned long st
vpte_base + (e >> (PAGE_SHIFT - 3)));
}
}
-#undef VPTE_BASE_SPITFIRE
-#undef VPTE_BASE_CHEETAH
/* Page table allocation/freeing. */
#ifdef CONFIG_SMP
diff --git a/include/asm-sparc64/processor.h b/include/asm-sparc64/processor.h
index 1815502bf7003..2f9061f38856d 100644
--- a/include/asm-sparc64/processor.h
+++ b/include/asm-sparc64/processor.h
@@ -39,9 +39,25 @@
* address that the kernel will allocate out.
*/
#define VA_BITS 44
+#ifndef __ASSEMBLY__
#define VPTE_SIZE (1UL << (VA_BITS - PAGE_SHIFT + 3))
+#else
+#define VPTE_SIZE (1 << (VA_BITS - PAGE_SHIFT + 3))
+#endif
#define TASK_SIZE ((unsigned long)-VPTE_SIZE)
+/*
+ * The vpte base must be able to hold the entire vpte, half
+ * of which lives above, and half below, the base. And it
+ * is placed as close to the highest address range as possible.
+ */
+#define VPTE_BASE_SPITFIRE (-(VPTE_SIZE/2))
+#if 1
+#define VPTE_BASE_CHEETAH VPTE_BASE_SPITFIRE
+#else
+#define VPTE_BASE_CHEETAH 0xffe0000000000000
+#endif
+
#ifndef __ASSEMBLY__
typedef struct {
diff --git a/include/asm-sparc64/sbus.h b/include/asm-sparc64/sbus.h
index e9f7344b47cff..5970645950ab1 100644
--- a/include/asm-sparc64/sbus.h
+++ b/include/asm-sparc64/sbus.h
@@ -87,7 +87,8 @@ extern struct sbus_bus *sbus_root;
for((device) = (bus)->devices; (device); (device)=(device)->next)
#define for_all_sbusdev(device, bus) \
- for((bus) = sbus_root, ((device) = (bus) ? (bus)->devices : 0); (bus); (device)=((device)->next ? (device)->next : ((bus) = (bus)->next, (bus) ? (bus)->devices : 0)))
+ for ((bus) = sbus_root; (bus); (bus) = (bus)->next) \
+ for ((device) = (bus)->devices; (device); (device) = (device)->next)
/* Driver DVMA interfaces. */
#define sbus_can_dma_64bit(sdev) (1)
diff --git a/include/linux/device.h b/include/linux/device.h
index f8234fdff19fc..585dd1e57f8b2 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -83,7 +83,7 @@ struct device {
device */
void *driver_data; /* data private to the driver */
void *platform_data; /* Platform specific data (e.g. ACPI,
- BIOS data relevant to device */
+ BIOS data relevant to device) */
u32 current_state; /* Current operating state. In
ACPI-speak, this is D0-D3, D0
diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h
index 192959f7477d1..6f8ebf32d7445 100644
--- a/include/linux/ethtool.h
+++ b/include/linux/ethtool.h
@@ -36,7 +36,8 @@ struct ethtool_drvinfo {
char bus_info[ETHTOOL_BUSINFO_LEN]; /* Bus info for this IF. */
/* For PCI devices, use pci_dev->slot_name. */
char reserved1[32];
- char reserved2[24];
+ char reserved2[20];
+ u32 testinfo_len;
u32 eedump_len; /* Size of data from ETHTOOL_GEEPROM (bytes) */
u32 regdump_len; /* Size of data from ETHTOOL_GREGS (bytes) */
};
@@ -210,6 +211,34 @@ struct ethtool_pauseparam {
u32 tx_pause;
};
+#define ETH_GSTRING_LEN 32
+enum ethtool_stringset {
+ ETH_SS_TEST = 0,
+ ETH_SS_STATS,
+};
+
+/* for passing string sets for data tagging */
+struct ethtool_gstrings {
+ u32 cmd; /* ETHTOOL_GSTRINGS */
+ u32 string_set; /* string set id e.c. ETH_SS_TEST, etc*/
+ u32 len; /* number of strings in the string set */
+ u8 data[0];
+};
+
+enum ethtool_test_flags {
+ ETH_TEST_FL_OFFLINE = (1 << 0), /* online / offline */
+ ETH_TEST_FL_FAILED = (1 << 1), /* test passed / failed */
+};
+
+/* for requesting NIC test and getting results*/
+struct ethtool_test {
+ u32 cmd; /* ETHTOOL_TEST */
+ u32 flags; /* ETH_TEST_FL_xxx */
+ u32 reserved;
+ u32 len; /* result length, in number of u64 elements */
+ u64 data[0];
+};
+
/* CMDs currently supported */
#define ETHTOOL_GSET 0x00000001 /* Get settings. */
#define ETHTOOL_SSET 0x00000002 /* Set settings, privileged. */
@@ -222,13 +251,13 @@ struct ethtool_pauseparam {
#define ETHTOOL_NWAY_RST 0x00000009 /* Restart autonegotiation, priv. */
#define ETHTOOL_GLINK 0x0000000a /* Get link status (ethtool_value) */
#define ETHTOOL_GEEPROM 0x0000000b /* Get EEPROM data */
-#define ETHTOOL_SEEPROM 0x0000000c /* Set EEPROM data */
+#define ETHTOOL_SEEPROM 0x0000000c /* Set EEPROM data, priv. */
#define ETHTOOL_GCOALESCE 0x0000000e /* Get coalesce config */
-#define ETHTOOL_SCOALESCE 0x0000000f /* Set coalesce config */
+#define ETHTOOL_SCOALESCE 0x0000000f /* Set coalesce config, priv. */
#define ETHTOOL_GRINGPARAM 0x00000010 /* Get ring parameters */
-#define ETHTOOL_SRINGPARAM 0x00000011 /* Set ring parameters */
+#define ETHTOOL_SRINGPARAM 0x00000011 /* Set ring parameters, priv. */
#define ETHTOOL_GPAUSEPARAM 0x00000012 /* Get pause parameters */
-#define ETHTOOL_SPAUSEPARAM 0x00000013 /* Set pause parameters */
+#define ETHTOOL_SPAUSEPARAM 0x00000013 /* Set pause parameters, priv. */
#define ETHTOOL_GRXCSUM 0x00000014 /* Get RX hw csum enable (ethtool_value) */
#define ETHTOOL_SRXCSUM 0x00000015 /* Set RX hw csum enable (ethtool_value) */
#define ETHTOOL_GTXCSUM 0x00000016 /* Get TX hw csum enable (ethtool_value) */
@@ -236,7 +265,9 @@ struct ethtool_pauseparam {
#define ETHTOOL_GSG 0x00000018 /* Get scatter-gather enable
* (ethtool_value) */
#define ETHTOOL_SSG 0x00000019 /* Set scatter-gather enable
- * (ethtool_value) */
+ * (ethtool_value), priv. */
+#define ETHTOOL_TEST 0x0000001a /* execute NIC self-test, priv. */
+#define ETHTOOL_GSTRINGS 0x0000001b /* get specified string set */
/* compatibility with older code */
#define SPARC_ETH_GSET ETHTOOL_GSET
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 85ae3dcb64964..cac7a59f64627 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -664,6 +664,7 @@ struct super_block {
kdev_t s_dev;
unsigned long s_blocksize;
unsigned char s_blocksize_bits;
+ unsigned long s_old_blocksize;
unsigned char s_dirt;
unsigned long long s_maxbytes; /* Max file size */
struct file_system_type *s_type;
diff --git a/include/linux/hdreg.h b/include/linux/hdreg.h
index 8c847b5726010..73de808b4749d 100644
--- a/include/linux/hdreg.h
+++ b/include/linux/hdreg.h
@@ -54,16 +54,9 @@
* HDIO_DRIVE_CMD and HDIO_DRIVE_TASK
*/
-#if 0
-#include <asm/hdreg.h>
-typedef ide_ioreg_t task_ioreg_t;
-#else
-typedef unsigned char task_ioreg_t;
-#endif
-
-#define HDIO_DRIVE_CMD_HDR_SIZE 4*sizeof(task_ioreg_t)
-#define HDIO_DRIVE_TASK_HDR_SIZE 8*sizeof(task_ioreg_t)
-#define HDIO_DRIVE_HOB_HDR_SIZE 8*sizeof(task_ioreg_t)
+#define HDIO_DRIVE_CMD_HDR_SIZE (4 * sizeof(u8))
+#define HDIO_DRIVE_TASK_HDR_SIZE (8 * sizeof(u8))
+#define HDIO_DRIVE_HOB_HDR_SIZE (8 * sizeof(u8))
#define IDE_DRIVE_TASK_INVALID -1
#define IDE_DRIVE_TASK_NO_DATA 0
@@ -74,57 +67,27 @@ typedef unsigned char task_ioreg_t;
#define IDE_DRIVE_TASK_OUT 3
#define IDE_DRIVE_TASK_RAW_WRITE 4
-struct hd_drive_cmd_hdr {
- task_ioreg_t command;
- task_ioreg_t sector_number;
- task_ioreg_t feature;
- task_ioreg_t sector_count;
-};
-
-typedef struct hd_drive_task_hdr {
- task_ioreg_t data;
- task_ioreg_t feature;
- task_ioreg_t sector_count;
- task_ioreg_t sector_number;
- task_ioreg_t low_cylinder;
- task_ioreg_t high_cylinder;
- task_ioreg_t device_head;
- task_ioreg_t command;
-} task_struct_t;
-
-typedef struct hd_drive_hob_hdr {
- task_ioreg_t data;
- task_ioreg_t feature;
- task_ioreg_t sector_count;
- task_ioreg_t sector_number;
- task_ioreg_t low_cylinder;
- task_ioreg_t high_cylinder;
- task_ioreg_t device_head;
- task_ioreg_t control;
-} hob_struct_t;
-
-typedef union ide_reg_valid_s {
- unsigned all : 16;
- struct {
- unsigned data : 1;
- unsigned error_feature : 1;
- unsigned sector : 1;
- unsigned nsector : 1;
- unsigned lcyl : 1;
- unsigned hcyl : 1;
- unsigned select : 1;
- unsigned status_command : 1;
-
- unsigned data_hob : 1;
- unsigned error_feature_hob : 1;
- unsigned sector_hob : 1;
- unsigned nsector_hob : 1;
- unsigned lcyl_hob : 1;
- unsigned hcyl_hob : 1;
- unsigned select_hob : 1;
- unsigned control_hob : 1;
- } b;
-} ide_reg_valid_t;
+struct hd_drive_task_hdr {
+ u8 data;
+ u8 feature;
+ u8 sector_count;
+ u8 sector_number;
+ u8 low_cylinder;
+ u8 high_cylinder;
+ u8 device_head;
+ u8 command;
+} __attribute__((packed));
+
+struct hd_drive_hob_hdr {
+ u8 data;
+ u8 feature;
+ u8 sector_count;
+ u8 sector_number;
+ u8 low_cylinder;
+ u8 high_cylinder;
+ u8 device_head;
+ u8 control;
+} __attribute__((packed));
/*
* Define standard taskfile in/out register
@@ -134,23 +97,6 @@ typedef union ide_reg_valid_s {
#define IDE_HOB_STD_OUT_FLAGS 0xC0
#define IDE_HOB_STD_IN_FLAGS 0xC0
-typedef struct ide_task_request_s {
- task_ioreg_t io_ports[8];
- task_ioreg_t hob_ports[8];
- ide_reg_valid_t out_flags;
- ide_reg_valid_t in_flags;
- int data_phase;
- int req_cmd;
- unsigned long out_size;
- unsigned long in_size;
-} ide_task_request_t;
-
-typedef struct ide_ioctl_request_s {
- ide_task_request_t *task_request;
- unsigned char *out_buffer;
- unsigned char *in_buffer;
-} ide_ioctl_request_t;
-
#define TASKFILE_INVALID 0x7fff
#define TASKFILE_48 0x8000
@@ -212,7 +158,7 @@ typedef struct ide_ioctl_request_s {
#define WIN_PIDENTIFY 0xA1 /* identify ATAPI device */
#define WIN_QUEUED_SERVICE 0xA2
#define WIN_SMART 0xB0 /* self-monitoring and reporting */
-#define CFA_ERASE_SECTORS 0xC0
+#define CFA_ERASE_SECTORS 0xC0
#define WIN_MULTREAD 0xC4 /* read sectors using multiple mode*/
#define WIN_MULTWRITE 0xC5 /* write sectors using multiple mode */
#define WIN_SETMULT 0xC6 /* enable/disable multiple mode */
@@ -221,12 +167,12 @@ typedef struct ide_ioctl_request_s {
#define WIN_WRITEDMA 0xCA /* write sectors using DMA transfers */
#define WIN_WRITEDMA_QUEUED 0xCC /* write sectors using Queued DMA transfers */
#define CFA_WRITE_MULTI_WO_ERASE 0xCD /* CFA Write multiple without erase */
-#define WIN_GETMEDIASTATUS 0xDA
+#define WIN_GETMEDIASTATUS 0xDA
#define WIN_DOORLOCK 0xDE /* lock door on removable drives */
#define WIN_DOORUNLOCK 0xDF /* unlock door on removable drives */
#define WIN_STANDBYNOW1 0xE0
#define WIN_IDLEIMMEDIATE 0xE1 /* force drive to become "ready" */
-#define WIN_STANDBY 0xE2 /* Set device in Standby Mode */
+#define WIN_STANDBY 0xE2 /* Set device in Standby Mode */
#define WIN_SETIDLE1 0xE3
#define WIN_READ_BUFFER 0xE4 /* force read only 1 sector */
#define WIN_CHECKPOWERMODE1 0xE5
@@ -268,7 +214,7 @@ typedef struct ide_ioctl_request_s {
#define SMART_LCYL_PASS 0x4F
#define SMART_HCYL_PASS 0xC2
-
+
/* WIN_SETFEATURES sub-commands */
#define SETFEATURES_EN_WCACHE 0x02 /* Enable write cache */
@@ -638,8 +584,5 @@ struct hd_driveid {
*/
#define IDE_NICE_DSC_OVERLAP (0) /* per the DSC overlap protocol */
#define IDE_NICE_ATAPI_OVERLAP (1) /* not supported yet */
-#define IDE_NICE_0 (2) /* when sure that it won't affect us */
-#define IDE_NICE_1 (3) /* when probably won't affect us much */
-#define IDE_NICE_2 (4) /* when we know it's on our expense */
#endif /* _LINUX_HDREG_H */
diff --git a/include/linux/ide.h b/include/linux/ide.h
index 6dafc47697ffe..6d80160690b28 100644
--- a/include/linux/ide.h
+++ b/include/linux/ide.h
@@ -68,8 +68,8 @@ typedef unsigned char byte; /* used everywhere */
*/
#define DMA_PIO_RETRY 1 /* retrying in PIO */
-#define HWIF(drive) ((drive)->hwif)
-#define HWGROUP(drive) (HWIF(drive)->hwgroup)
+#define HWIF(drive) ((drive)->channel)
+#define HWGROUP(drive) (drive->channel->hwgroup)
/*
* Definitions for accessing IDE controller registers
@@ -90,37 +90,16 @@ typedef unsigned char byte; /* used everywhere */
#define IDE_FEATURE_OFFSET IDE_ERROR_OFFSET
#define IDE_COMMAND_OFFSET IDE_STATUS_OFFSET
-#define IDE_DATA_OFFSET_HOB (0)
-#define IDE_ERROR_OFFSET_HOB (1)
-#define IDE_NSECTOR_OFFSET_HOB (2)
-#define IDE_SECTOR_OFFSET_HOB (3)
-#define IDE_LCYL_OFFSET_HOB (4)
-#define IDE_HCYL_OFFSET_HOB (5)
-#define IDE_SELECT_OFFSET_HOB (6)
-#define IDE_CONTROL_OFFSET_HOB (7)
-
-#define IDE_FEATURE_OFFSET_HOB IDE_ERROR_OFFSET_HOB
-
-#define IDE_DATA_REG (HWIF(drive)->io_ports[IDE_DATA_OFFSET])
-#define IDE_ERROR_REG (HWIF(drive)->io_ports[IDE_ERROR_OFFSET])
-#define IDE_NSECTOR_REG (HWIF(drive)->io_ports[IDE_NSECTOR_OFFSET])
-#define IDE_SECTOR_REG (HWIF(drive)->io_ports[IDE_SECTOR_OFFSET])
-#define IDE_LCYL_REG (HWIF(drive)->io_ports[IDE_LCYL_OFFSET])
-#define IDE_HCYL_REG (HWIF(drive)->io_ports[IDE_HCYL_OFFSET])
-#define IDE_SELECT_REG (HWIF(drive)->io_ports[IDE_SELECT_OFFSET])
-#define IDE_STATUS_REG (HWIF(drive)->io_ports[IDE_STATUS_OFFSET])
-#define IDE_CONTROL_REG (HWIF(drive)->io_ports[IDE_CONTROL_OFFSET])
-#define IDE_IRQ_REG (HWIF(drive)->io_ports[IDE_IRQ_OFFSET])
-
-#define IDE_DATA_REG_HOB (HWIF(drive)->io_ports[IDE_DATA_OFFSET])
-#define IDE_ERROR_REG_HOB (HWIF(drive)->io_ports[IDE_ERROR_OFFSET])
-#define IDE_NSECTOR_REG_HOB (HWIF(drive)->io_ports[IDE_NSECTOR_OFFSET])
-#define IDE_SECTOR_REG_HOB (HWIF(drive)->io_ports[IDE_SECTOR_OFFSET])
-#define IDE_LCYL_REG_HOB (HWIF(drive)->io_ports[IDE_LCYL_OFFSET])
-#define IDE_HCYL_REG_HOB (HWIF(drive)->io_ports[IDE_HCYL_OFFSET])
-#define IDE_SELECT_REG_HOB (HWIF(drive)->io_ports[IDE_SELECT_OFFSET])
-#define IDE_STATUS_REG_HOB (HWIF(drive)->io_ports[IDE_STATUS_OFFSET])
-#define IDE_CONTROL_REG_HOB (HWIF(drive)->io_ports[IDE_CONTROL_OFFSET])
+#define IDE_DATA_REG (drive->channel->io_ports[IDE_DATA_OFFSET])
+#define IDE_ERROR_REG (drive->channel->io_ports[IDE_ERROR_OFFSET])
+#define IDE_NSECTOR_REG (drive->channel->io_ports[IDE_NSECTOR_OFFSET])
+#define IDE_SECTOR_REG (drive->channel->io_ports[IDE_SECTOR_OFFSET])
+#define IDE_LCYL_REG (drive->channel->io_ports[IDE_LCYL_OFFSET])
+#define IDE_HCYL_REG (drive->channel->io_ports[IDE_HCYL_OFFSET])
+#define IDE_SELECT_REG (drive->channel->io_ports[IDE_SELECT_OFFSET])
+#define IDE_STATUS_REG (drive->channel->io_ports[IDE_STATUS_OFFSET])
+#define IDE_CONTROL_REG (drive->channel->io_ports[IDE_CONTROL_OFFSET])
+#define IDE_IRQ_REG (drive->channel->io_ports[IDE_IRQ_OFFSET])
#define IDE_FEATURE_REG IDE_ERROR_REG
#define IDE_COMMAND_REG IDE_STATUS_REG
@@ -175,24 +154,24 @@ typedef unsigned char byte; /* used everywhere */
#define WAIT_CMD (10*HZ) /* 10sec - maximum wait for an IRQ to happen */
#define WAIT_MIN_SLEEP (2*HZ/100) /* 20msec - minimum sleep time */
-#define SELECT_DRIVE(hwif,drive) \
+#define SELECT_DRIVE(channel, drive) \
{ \
- if (hwif->selectproc) \
- hwif->selectproc(drive); \
- OUT_BYTE((drive)->select.all, hwif->io_ports[IDE_SELECT_OFFSET]); \
+ if (channel->selectproc) \
+ channel->selectproc(drive); \
+ OUT_BYTE((drive)->select.all, channel->io_ports[IDE_SELECT_OFFSET]); \
}
-#define SELECT_MASK(hwif,drive,mask) \
+#define SELECT_MASK(channel, drive, mask) \
{ \
- if (hwif->maskproc) \
- hwif->maskproc(drive,mask); \
+ if (channel->maskproc) \
+ channel->maskproc(drive,mask); \
}
/*
* Check for an interrupt and acknowledge the interrupt status
*/
-struct hwif_s;
-typedef int (ide_ack_intr_t)(struct hwif_s *);
+struct ata_channel;
+typedef int (ide_ack_intr_t)(struct ata_channel *);
#ifndef NO_DMA
# define NO_DMA 255
@@ -235,7 +214,6 @@ typedef struct hw_regs_s {
int irq; /* our irq number */
int dma; /* our dma entry */
ide_ack_intr_t *ack_intr; /* acknowledge interrupt */
- void *priv; /* interface specific data */
hwif_chipset_t chipset;
} hw_regs_t;
@@ -291,20 +269,28 @@ typedef union {
struct ide_settings_s;
typedef struct ide_drive_s {
- unsigned int usage; /* current "open()" count for drive */
+ struct ata_channel *channel; /* parent pointer to the channel we are attached to */
+
+ unsigned int usage; /* current "open()" count for drive */
char type; /* distingiush different devices: disk, cdrom, tape, floppy, ... */
/* NOTE: If we had proper separation between channel and host chip, we
* could move this to the chanell and many sync problems would
* magically just go away.
*/
- request_queue_t queue; /* per device request queue */
+ request_queue_t queue; /* per device request queue */
struct ide_drive_s *next; /* circular list of hwgroup drives */
- unsigned long sleep; /* sleep until this time */
- unsigned long service_start; /* time we started last request */
- unsigned long service_time; /* service time of last request */
- unsigned long timeout; /* max time to wait for irq */
+
+ /* Those are directly injected jiffie values. They should go away and
+ * we should use generic timers instead!!!
+ */
+
+ unsigned long PADAM_sleep; /* sleep until this time */
+ unsigned long PADAM_service_start; /* time we started last request */
+ unsigned long PADAM_service_time; /* service time of last request */
+ unsigned long PADAM_timeout; /* max time to wait for irq */
+
special_t special; /* special action flags */
byte keep_settings; /* restore settings after drive reset */
byte using_dma; /* disk is using dma for read/write */
@@ -314,11 +300,13 @@ typedef struct ide_drive_s {
byte slow; /* flag: slow data port */
byte bswap; /* flag: byte swap data */
byte dsc_overlap; /* flag: DSC overlap */
- byte nice1; /* flag: give potential excess bandwidth */
+
unsigned waiting_for_dma: 1; /* dma currently in progress */
+ unsigned busy : 1; /* currently doing revalidate_disk() */
+ unsigned blocked : 1; /* 1=powermanagment told us not to do anything, so sleep nicely */
+
unsigned present : 1; /* drive is physically present */
unsigned noprobe : 1; /* from: hdx=noprobe */
- unsigned busy : 1; /* currently doing revalidate_disk() */
unsigned removable : 1; /* 1 if need to do check_media_change */
unsigned forced_geom : 1; /* 1 if hdx=c,h,s was given at boot */
unsigned no_unmask : 1; /* disallow setting unmask bit */
@@ -326,21 +314,18 @@ typedef struct ide_drive_s {
unsigned nobios : 1; /* flag: do not probe bios for drive */
unsigned revalidate : 1; /* request revalidation */
unsigned atapi_overlap : 1; /* flag: ATAPI overlap (not supported) */
- unsigned nice0 : 1; /* flag: give obvious excess bandwidth */
- unsigned nice2 : 1; /* flag: give a share in our own bandwidth */
unsigned doorlocking : 1; /* flag: for removable only: door lock/unlock works */
unsigned autotune : 2; /* 1=autotune, 2=noautotune, 0=default */
unsigned remap_0_to_1 : 2; /* 0=remap if ezdrive, 1=remap, 2=noremap */
unsigned ata_flash : 1; /* 1=present, 0=default */
- unsigned blocked : 1; /* 1=powermanagment told us not to do anything, so sleep nicely */
unsigned addressing; /* : 2; 0=28-bit, 1=48-bit, 2=64-bit */
byte scsi; /* 0=default, 1=skip current ide-subdriver for ide-scsi emulation */
select_t select; /* basic drive/head select reg value */
byte ctl; /* "normal" value for IDE_CONTROL_REG */
byte ready_stat; /* min status value for drive ready */
byte mult_count; /* current multiple sector setting */
- byte mult_req; /* requested multiple sector setting */
- byte tune_req; /* requested drive tuning setting */
+ byte mult_req; /* requested multiple sector setting */
+ byte tune_req; /* requested drive tuning setting */
byte io_32bit; /* 0=16-bit, 1=32-bit, 2/3=32bit+sync */
byte bad_wstat; /* used for ignoring WRERR_STAT */
byte nowerr; /* used for ignoring WRERR_STAT */
@@ -354,20 +339,25 @@ typedef struct ide_drive_s {
unsigned long capacity; /* total number of sectors */
unsigned long long capacity48; /* total number of sectors */
unsigned int drive_data; /* for use by tuneproc/selectproc as needed */
- struct hwif_s *hwif; /* parent pointer to the interface we are attached to */
+
wait_queue_head_t wqueue; /* used to wait for drive in open() */
+
struct hd_driveid *id; /* drive model identification info */
struct hd_struct *part; /* drive partition table */
+
char name[4]; /* drive name, such as "hda" */
struct ata_operations *driver;
+
void *driver_data; /* extra driver data */
devfs_handle_t de; /* directory for device */
struct proc_dir_entry *proc; /* /proc/ide/ directory entry */
struct ide_settings_s *settings; /* /proc/ide/ drive settings */
char driver_req[10]; /* requests specific driver */
+
int last_lun; /* last logical unit */
int forced_lun; /* if hdxlun was given at boot */
int lun; /* logical unit */
+
int crc_count; /* crc counter to reduce drive speed */
byte quirk_list; /* drive is considered quirky if set for a specific host */
byte suspend_reset; /* drive suspend mode flag, soft-reset recovers */
@@ -409,7 +399,7 @@ typedef int (ide_dmaproc_t)(ide_dma_action_t, ide_drive_t *);
*
* If it is not defined for a controller, standard-code is used from ide.c.
*
- * Controllers which are not memory-mapped in the standard way need to
+ * Controllers which are not memory-mapped in the standard way need to
* override that mechanism using this function to work.
*
*/
@@ -448,11 +438,18 @@ typedef void (ide_rw_proc_t) (ide_drive_t *, ide_dma_action_t);
*/
typedef int (ide_busproc_t) (ide_drive_t *, int);
-typedef struct hwif_s {
- struct hwif_s *next; /* for linked-list in ide_hwgroup_t */
+struct ata_channel {
+ struct device dev; /* device handle */
+ int unit; /* channel number */
+
+ struct ata_channel *next; /* for linked-list in ide_hwgroup_t */
struct hwgroup_s *hwgroup; /* actually (ide_hwgroup_t *) */
+
ide_ioreg_t io_ports[IDE_NR_PORTS]; /* task file registers */
hw_regs_t hw; /* Hardware info */
+#ifdef CONFIG_BLK_DEV_IDEPCI
+ struct pci_dev *pci_dev; /* for pci chipsets */
+#endif
ide_drive_t drives[MAX_DRIVES]; /* drive info */
struct gendisk *gd; /* gendisk structure */
ide_tuneproc_t *tuneproc; /* routine to tune PIO mode for drives */
@@ -470,7 +467,7 @@ typedef struct hwif_s {
struct scatterlist *sg_table; /* Scatter-gather list used to build the above */
int sg_nents; /* Current number of entries in it */
int sg_dma_direction; /* dma transfer direction */
- struct hwif_s *mate; /* other hwif from same PCI chip */
+ struct ata_channel *mate; /* other hwif from same PCI chip */
unsigned long dma_base; /* base addr for dma ports */
unsigned dma_extra; /* extra addr for dma ports */
unsigned long config_data; /* for use by chipset-specific code */
@@ -478,7 +475,7 @@ typedef struct hwif_s {
struct proc_dir_entry *proc; /* /proc/ide/ directory entry */
int irq; /* our irq number */
int major; /* our major number */
- char name[80]; /* name of interface */
+ char name[8]; /* name of interface */
int index; /* 0 for ide0; 1 for ide1; ... */
hwif_chipset_t chipset; /* sub-module for tuning.. */
unsigned noprobe : 1; /* don't probe for this interface */
@@ -489,24 +486,19 @@ typedef struct hwif_s {
unsigned autodma : 1; /* automatically try to enable DMA at boot */
unsigned udma_four : 1; /* 1=ATA-66 capable, 0=default */
unsigned highmem : 1; /* can do full 32-bit dma */
- byte channel; /* for dual-port chips: 0=primary, 1=secondary */
-#ifdef CONFIG_BLK_DEV_IDEPCI
- struct pci_dev *pci_dev; /* for pci chipsets */
-#endif
#if (DISK_RECOVERY_TIME > 0)
unsigned long last_time; /* time when previous rq was done */
#endif
byte straight8; /* Alan's straight 8 check */
ide_busproc_t *busproc; /* driver soft-power interface */
byte bus_state; /* power state of the IDE bus */
- struct device device; /* global device tree handle */
-} ide_hwif_t;
+};
/*
* Register new hardware with ide
*/
-extern int ide_register_hw(hw_regs_t *hw, struct hwif_s **hwifp);
-extern void ide_unregister(ide_hwif_t *hwif);
+extern int ide_register_hw(hw_regs_t *hw, struct ata_channel **hwifp);
+extern void ide_unregister(struct ata_channel *hwif);
/*
* Status returned from various ide_ functions
@@ -536,7 +528,7 @@ typedef struct hwgroup_s {
ide_handler_t *handler;/* irq handler, if active */
unsigned long flags; /* BUSY, SLEEPING */
ide_drive_t *drive; /* current drive */
- ide_hwif_t *hwif; /* ptr to current hwif in linked-list */
+ struct ata_channel *hwif; /* ptr to current hwif in linked-list */
struct request *rq; /* current request */
struct timer_list timer; /* failsafe timer */
struct request wrq; /* local copy of current write rq */
@@ -595,7 +587,7 @@ typedef struct {
#ifdef CONFIG_PROC_FS
void proc_ide_create(void);
void proc_ide_destroy(void);
-void destroy_proc_ide_drives(ide_hwif_t *);
+void destroy_proc_ide_drives(struct ata_channel *);
void create_proc_ide_interfaces(void);
void ide_add_proc_entries(struct proc_dir_entry *dir, ide_proc_entry_t *p, void *data);
void ide_remove_proc_entries(struct proc_dir_entry *dir, ide_proc_entry_t *p);
@@ -630,7 +622,6 @@ read_proc_t proc_ide_read_geometry;
struct ata_operations {
struct module *owner;
- unsigned busy: 1; /* FIXME: this will go soon away... */
int (*cleanup)(ide_drive_t *);
int (*standby)(ide_drive_t *);
ide_startstop_t (*do_request)(ide_drive_t *, struct request *, unsigned long);
@@ -645,6 +636,7 @@ struct ata_operations {
void (*pre_reset)(ide_drive_t *);
unsigned long (*capacity)(ide_drive_t *);
ide_startstop_t (*special)(ide_drive_t *);
+
ide_proc_entry_t *proc;
};
@@ -670,15 +662,7 @@ extern int register_ata_driver(unsigned int type, struct ata_operations *driver)
#define ata_ops(drive) ((drive)->driver)
-/*
- * ide_hwifs[] is the master data structure used to keep track
- * of just about everything in ide.c. Whenever possible, routines
- * should be using pointers to a drive (ide_drive_t *) or
- * pointers to a hwif (ide_hwif_t *), rather than indexing this
- * structure directly (the allocation/layout may change!).
- *
- */
-extern struct hwif_s ide_hwifs[]; /* master data repository */
+extern struct ata_channel ide_hwifs[]; /* master data repository */
extern int noautodma;
/*
@@ -771,35 +755,7 @@ typedef enum {
*/
#define ide_rq_offset(rq) (((rq)->hard_cur_sectors - (rq)->current_nr_sectors) << 9)
-#define task_rq_offset(rq) \
- (((rq)->nr_sectors - (rq)->current_nr_sectors) * SECTOR_SIZE)
-
-/*
- * This function issues a special IDE device request
- * onto the request queue.
- *
- * If action is ide_wait, then the rq is queued at the end of the
- * request queue, and the function sleeps until it has been processed.
- * This is for use when invoked from an ioctl handler.
- *
- * If action is ide_preempt, then the rq is queued at the head of
- * the request queue, displacing the currently-being-processed
- * request and this function returns immediately without waiting
- * for the new rq to be completed. This is VERY DANGEROUS, and is
- * intended for careful use by the ATAPI tape/cdrom driver code.
- *
- * If action is ide_next, then the rq is queued immediately after
- * the currently-being-processed-request (if any), and the function
- * returns without waiting for the new rq to be completed. As above,
- * This is VERY DANGEROUS, and is intended for careful use by the
- * ATAPI tape/cdrom driver code.
- *
- * If action is ide_end, then the rq is queued at the end of the
- * request queue, and the function returns immediately without waiting
- * for the new rq to be completed. This is again intended for careful
- * use by the ATAPI tape/cdrom driver code.
- */
-int ide_do_drive_cmd (ide_drive_t *drive, struct request *rq, ide_action_t action);
+extern int ide_do_drive_cmd(ide_drive_t *drive, struct request *rq, ide_action_t action);
/*
* Clean up after success/failure of an explicit drive cmd.
@@ -807,17 +763,11 @@ int ide_do_drive_cmd (ide_drive_t *drive, struct request *rq, ide_action_t actio
void ide_end_drive_cmd (ide_drive_t *drive, byte stat, byte err);
typedef struct ide_task_s {
- task_ioreg_t tfRegister[8];
- task_ioreg_t hobRegister[8];
- ide_reg_valid_t tf_out_flags;
- ide_reg_valid_t tf_in_flags;
- int data_phase;
+ struct hd_drive_task_hdr taskfile;
+ struct hd_drive_hob_hdr hobfile;
int command_type;
ide_pre_handler_t *prehandler;
ide_handler_t *handler;
- void *special; /* valid_t generally */
- struct request *rq; /* copy of request */
- unsigned long block; /* copy of block */
} ide_task_t;
void ata_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount);
@@ -827,15 +777,12 @@ void atapi_output_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecoun
void taskfile_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount);
void taskfile_output_data (ide_drive_t *drive, void *buffer, unsigned int wcount);
-/*
- * taskfile io for disks for now...
- */
-ide_startstop_t do_rw_taskfile (ide_drive_t *drive, ide_task_t *task);
-
-/*
- * Builds request from ide_ioctl
- */
-void do_taskfile (ide_drive_t *drive, struct hd_drive_task_hdr *taskfile, struct hd_drive_hob_hdr *hobfile, ide_handler_t *handler);
+extern ide_startstop_t ata_taskfile(ide_drive_t *drive,
+ struct hd_drive_task_hdr *taskfile,
+ struct hd_drive_hob_hdr *hobfile,
+ ide_handler_t *handler,
+ ide_pre_handler_t *prehandler,
+ struct request *rq);
/*
* Special Flagged Register Validation Caller
@@ -871,7 +818,7 @@ extern int system_bus_speed;
* idedisk_input_data() is a wrapper around ide_input_data() which copes
* with byte-swapping the input data if required.
*/
-inline void idedisk_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount);
+extern void idedisk_input_data(ide_drive_t *drive, void *buffer, unsigned int wcount);
/*
* ide_stall_queue() can be used by a drive to give excess bandwidth back
@@ -939,15 +886,14 @@ extern int ide_unregister_subdriver(ide_drive_t *drive);
void __init ide_scan_pcibus(int scan_direction);
#endif
#ifdef CONFIG_BLK_DEV_IDEDMA
-# define BAD_DMA_DRIVE 0
-# define GOOD_DMA_DRIVE 1
int ide_build_dmatable (ide_drive_t *drive, ide_dma_action_t func);
void ide_destroy_dmatable (ide_drive_t *drive);
ide_startstop_t ide_dma_intr (ide_drive_t *drive);
int check_drive_lists (ide_drive_t *drive, int good_bad);
int ide_dmaproc (ide_dma_action_t func, ide_drive_t *drive);
-extern void ide_release_dma(ide_hwif_t *hwif);
-void ide_setup_dma (ide_hwif_t *hwif, unsigned long dmabase, unsigned int num_ports) __init;
+extern void ide_release_dma(struct ata_channel *hwif);
+extern void ide_setup_dma(struct ata_channel *hwif,
+ unsigned long dmabase, unsigned int num_ports) __init;
#endif
extern spinlock_t ide_lock;
diff --git a/include/linux/inetdevice.h b/include/linux/inetdevice.h
index 47ee810f813c3..ddd8e23c1ca5f 100644
--- a/include/linux/inetdevice.h
+++ b/include/linux/inetdevice.h
@@ -18,6 +18,7 @@ struct ipv4_devconf
int mc_forwarding;
int tag;
int arp_filter;
+ int medium_id;
void *sysctl;
};
@@ -48,6 +49,7 @@ struct in_device
#define IN_DEV_TX_REDIRECTS(in_dev) (ipv4_devconf.send_redirects || (in_dev)->cnf.send_redirects)
#define IN_DEV_SEC_REDIRECTS(in_dev) (ipv4_devconf.secure_redirects || (in_dev)->cnf.secure_redirects)
#define IN_DEV_IDTAG(in_dev) ((in_dev)->cnf.tag)
+#define IN_DEV_MEDIUM_ID(in_dev) ((in_dev)->cnf.medium_id)
#define IN_DEV_RX_REDIRECTS(in_dev) \
((IN_DEV_FORWARD(in_dev) && \
diff --git a/include/linux/iobuf.h b/include/linux/iobuf.h
index 869b05dc6b801..fb147b5c48a79 100644
--- a/include/linux/iobuf.h
+++ b/include/linux/iobuf.h
@@ -80,9 +80,9 @@ extern void free_kiobuf_bhs(struct kiobuf *);
/* fs/buffer.c */
int brw_kiovec(int rw, int nr, struct kiobuf *iovec[],
- kdev_t dev, sector_t [], int size);
+ struct block_device *bdev, sector_t [], int size);
/* fs/bio.c */
-void ll_rw_kio(int rw, struct kiobuf *kio, kdev_t dev, sector_t block);
+void ll_rw_kio(int rw, struct kiobuf *kio, struct block_device *bdev, sector_t block);
#endif /* __LINUX_IOBUF_H */
diff --git a/include/linux/minix_fs.h b/include/linux/minix_fs.h
index 586b49bb61bd6..1ecc3cc8cef53 100644
--- a/include/linux/minix_fs.h
+++ b/include/linux/minix_fs.h
@@ -29,11 +29,6 @@
#define MINIX_INODES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct minix_inode)))
#define MINIX2_INODES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct minix2_inode)))
-#define MINIX_V1 0x0001 /* original minix fs */
-#define MINIX_V2 0x0002 /* minix V2 fs */
-
-#define INODE_VERSION(inode) minix_sb(inode->i_sb)->s_version
-
/*
* This is the original minix inode layout on disk.
* Note the 8-bit gid and atime and ctime.
@@ -87,61 +82,4 @@ struct minix_dir_entry {
char name[0];
};
-#ifdef __KERNEL__
-
-#include <linux/minix_fs_i.h>
-#include <linux/minix_fs_sb.h>
-
-/*
- * change the define below to 0 if you want names > info->s_namelen chars to be
- * truncated. Else they will be disallowed (ENAMETOOLONG).
- */
-#define NO_TRUNCATE 1
-
-extern struct minix_inode * minix_V1_raw_inode(struct super_block *, ino_t, struct buffer_head **);
-extern struct minix2_inode * minix_V2_raw_inode(struct super_block *, ino_t, struct buffer_head **);
-extern struct inode * minix_new_inode(const struct inode * dir, int * error);
-extern void minix_free_inode(struct inode * inode);
-extern unsigned long minix_count_free_inodes(struct super_block *sb);
-extern int minix_new_block(struct inode * inode);
-extern void minix_free_block(struct inode * inode, int block);
-extern unsigned long minix_count_free_blocks(struct super_block *sb);
-
-extern void V1_minix_truncate(struct inode *);
-extern void V2_minix_truncate(struct inode *);
-extern void minix_truncate(struct inode *);
-extern int minix_sync_inode(struct inode *);
-extern void minix_set_inode(struct inode *, dev_t);
-extern int V1_minix_get_block(struct inode *, long, struct buffer_head *, int);
-extern int V2_minix_get_block(struct inode *, long, struct buffer_head *, int);
-
-extern struct minix_dir_entry *minix_find_entry(struct dentry*, struct page**);
-extern int minix_add_link(struct dentry*, struct inode*);
-extern int minix_delete_entry(struct minix_dir_entry*, struct page*);
-extern int minix_make_empty(struct inode*, struct inode*);
-extern int minix_empty_dir(struct inode*);
-extern void minix_set_link(struct minix_dir_entry*, struct page*, struct inode*);
-extern struct minix_dir_entry *minix_dotdot(struct inode*, struct page**);
-extern ino_t minix_inode_by_name(struct dentry*);
-
-extern int minix_sync_file(struct file *, struct dentry *, int);
-
-extern struct inode_operations minix_file_inode_operations;
-extern struct inode_operations minix_dir_inode_operations;
-extern struct file_operations minix_file_operations;
-extern struct file_operations minix_dir_operations;
-extern struct dentry_operations minix_dentry_operations;
-
-static inline struct minix_sb_info *minix_sb(struct super_block *sb)
-{
- return sb->u.generic_sbp;
-}
-
-static inline struct minix_inode_info *minix_i(struct inode *inode)
-{
- return list_entry(inode, struct minix_inode_info, vfs_inode);
-}
-
-#endif /* __KERNEL__ */
-
#endif
diff --git a/include/linux/minix_fs_i.h b/include/linux/minix_fs_i.h
deleted file mode 100644
index 1ffd85ed4070d..0000000000000
--- a/include/linux/minix_fs_i.h
+++ /dev/null
@@ -1,15 +0,0 @@
-#ifndef _MINIX_FS_I
-#define _MINIX_FS_I
-
-/*
- * minix fs inode data in memory
- */
-struct minix_inode_info {
- union {
- __u16 i1_data[16];
- __u32 i2_data[16];
- } u;
- struct inode vfs_inode;
-};
-
-#endif
diff --git a/include/linux/minix_fs_sb.h b/include/linux/minix_fs_sb.h
deleted file mode 100644
index 54c82af99a8f1..0000000000000
--- a/include/linux/minix_fs_sb.h
+++ /dev/null
@@ -1,26 +0,0 @@
-#ifndef _MINIX_FS_SB
-#define _MINIX_FS_SB
-
-/*
- * minix super-block data in memory
- */
-struct minix_sb_info {
- unsigned long s_ninodes;
- unsigned long s_nzones;
- unsigned long s_imap_blocks;
- unsigned long s_zmap_blocks;
- unsigned long s_firstdatazone;
- unsigned long s_log_zone_size;
- unsigned long s_max_size;
- int s_dirsize;
- int s_namelen;
- int s_link_max;
- struct buffer_head ** s_imap;
- struct buffer_head ** s_zmap;
- struct buffer_head * s_sbh;
- struct minix_super_block * s_ms;
- unsigned short s_mount_state;
- unsigned short s_version;
-};
-
-#endif
diff --git a/include/linux/mtd/compatmac.h b/include/linux/mtd/compatmac.h
index e6844448c327b..9c9a2276f57e4 100644
--- a/include/linux/mtd/compatmac.h
+++ b/include/linux/mtd/compatmac.h
@@ -190,8 +190,8 @@ static inline int try_inc_mod_count(struct module *mod)
#if LINUX_VERSION_CODE < 0x20300
#include <linux/interrupt.h>
-#define spin_lock_bh(lock) do {start_bh_atomic();spin_lock(lock);}while(0);
-#define spin_unlock_bh(lock) do {spin_unlock(lock);end_bh_atomic();}while(0);
+#define spin_lock_bh(lock) do {start_bh_atomic();spin_lock(lock);} while(0)
+#define spin_unlock_bh(lock) do {spin_unlock(lock);end_bh_atomic();} while(0)
#else
#include <asm/softirq.h>
#include <linux/spinlock.h>
diff --git a/include/linux/nbd.h b/include/linux/nbd.h
index f1b5135d288e1..b6120317731d0 100644
--- a/include/linux/nbd.h
+++ b/include/linux/nbd.h
@@ -70,7 +70,7 @@ struct nbd_device {
struct file * file; /* If == NULL, device is not ready, yet */
int magic; /* FIXME: not if debugging is off */
struct list_head queue_head; /* Requests are added here... */
- struct semaphore queue_lock;
+ struct semaphore tx_lock;
};
#endif
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 32b6db3c7a2c4..706c6240eccab 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -246,8 +246,6 @@ struct net_device
* I/O specific fields
* FIXME: Merge these and struct ifmap into one
*/
- unsigned long rmem_end; /* shmem "recv" end */
- unsigned long rmem_start; /* shmem "recv" start */
unsigned long mem_end; /* shared mem end */
unsigned long mem_start; /* shared mem start */
unsigned long base_addr; /* device I/O address */
diff --git a/include/linux/netfilter_ipv4/ip_conntrack.h b/include/linux/netfilter_ipv4/ip_conntrack.h
index 107cce0c67a3d..de76fd298762e 100644
--- a/include/linux/netfilter_ipv4/ip_conntrack.h
+++ b/include/linux/netfilter_ipv4/ip_conntrack.h
@@ -6,6 +6,7 @@
#include <linux/config.h>
#include <linux/netfilter_ipv4/ip_conntrack_tuple.h>
+#include <asm/atomic.h>
enum ip_conntrack_info
{
@@ -62,27 +63,58 @@ do { \
#define IP_NF_ASSERT(x)
#endif
+#ifdef CONFIG_IP_NF_NAT_NEEDED
+#include <linux/netfilter_ipv4/ip_nat.h>
+#endif
+
+/* Add protocol helper include file here */
+#include <linux/netfilter_ipv4/ip_conntrack_ftp.h>
+#include <linux/netfilter_ipv4/ip_conntrack_irc.h>
+
struct ip_conntrack_expect
{
- /* Internal linked list */
+ /* Internal linked list (global expectation list) */
struct list_head list;
+ /* expectation list for this master */
+ struct list_head expected_list;
+
+ /* The conntrack of the master connection */
+ struct ip_conntrack *expectant;
+
+ /* The conntrack of the sibling connection, set after
+ * expectation arrived */
+ struct ip_conntrack *sibling;
+
+ /* Tuple saved for conntrack */
+ struct ip_conntrack_tuple ct_tuple;
+
+ /* Timer function; deletes the expectation. */
+ struct timer_list timeout;
+
+ /* Data filled out by the conntrack helpers follow: */
+
/* We expect this tuple, with the following mask */
struct ip_conntrack_tuple tuple, mask;
/* Function to call after setup and insertion */
int (*expectfn)(struct ip_conntrack *new);
- /* The conntrack we are part of (set iff we're live) */
- struct ip_conntrack *expectant;
-};
-
+ /* At which sequence number did this expectation occur */
+ u_int32_t seq;
+
+ union {
+ /* insert conntrack helper private data (expect) here */
+ struct ip_ct_ftp_expect exp_ftp_info;
+ struct ip_ct_irc_expect exp_irc_info;
+
#ifdef CONFIG_IP_NF_NAT_NEEDED
-#include <linux/netfilter_ipv4/ip_nat.h>
+ union {
+ /* insert nat helper private data (expect) here */
+ } nat;
#endif
-
-#include <linux/netfilter_ipv4/ip_conntrack_ftp.h>
-#include <linux/netfilter_ipv4/ip_conntrack_irc.h>
+ } help;
+};
struct ip_conntrack
{
@@ -101,10 +133,13 @@ struct ip_conntrack
/* If we're expecting another related connection, this will be
in expected linked list */
- struct ip_conntrack_expect expected;
+ struct list_head sibling_list;
+
+ /* Current number of expected connections */
+ unsigned int expecting;
- /* If we were expected by another connection, this will be it */
- struct nf_ct_info master;
+ /* If we were expected by an expectation, this will be it */
+ struct ip_conntrack_expect *master;
/* Helper, if any. */
struct ip_conntrack_helper *helper;
@@ -121,8 +156,9 @@ struct ip_conntrack
} proto;
union {
- struct ip_ct_ftp ct_ftp_info;
- struct ip_ct_irc ct_irc_info;
+ /* insert conntrack helper private data (master) here */
+ struct ip_ct_ftp_master ct_ftp_info;
+ struct ip_ct_irc_master ct_irc_info;
} help;
#ifdef CONFIG_IP_NF_NAT_NEEDED
@@ -140,6 +176,9 @@ struct ip_conntrack
};
+/* get master conntrack via master expectation */
+#define master_ct(conntr) (conntr->master ? conntr->master->expectant : NULL)
+
/* Alter reply tuple (maybe alter helper). If it's already taken,
return 0 and don't do alteration. */
extern int
diff --git a/include/linux/netfilter_ipv4/ip_conntrack_core.h b/include/linux/netfilter_ipv4/ip_conntrack_core.h
index 6ed40793af6a9..49f26c463e856 100644
--- a/include/linux/netfilter_ipv4/ip_conntrack_core.h
+++ b/include/linux/netfilter_ipv4/ip_conntrack_core.h
@@ -15,7 +15,7 @@ extern int ip_conntrack_init(void);
extern void ip_conntrack_cleanup(void);
struct ip_conntrack_protocol;
-extern struct ip_conntrack_protocol *find_proto(u_int8_t protocol);
+extern struct ip_conntrack_protocol *ip_ct_find_proto(u_int8_t protocol);
/* Like above, but you already have conntrack read lock. */
extern struct ip_conntrack_protocol *__find_proto(u_int8_t protocol);
extern struct list_head protocol_list;
diff --git a/include/linux/netfilter_ipv4/ip_conntrack_ftp.h b/include/linux/netfilter_ipv4/ip_conntrack_ftp.h
index 4b560e237ba3d..06f6f588ce37d 100644
--- a/include/linux/netfilter_ipv4/ip_conntrack_ftp.h
+++ b/include/linux/netfilter_ipv4/ip_conntrack_ftp.h
@@ -11,6 +11,8 @@
/* Protects ftp part of conntracks */
DECLARE_LOCK_EXTERN(ip_ftp_lock);
+#define FTP_PORT 21
+
enum ip_ct_ftp_type
{
/* PORT command from client */
@@ -23,18 +25,20 @@ enum ip_ct_ftp_type
IP_CT_FTP_EPSV,
};
-/* We record seq number and length of ftp ip/port text here: all in
- host order. */
-struct ip_ct_ftp
+/* This structure is per expected connection */
+struct ip_ct_ftp_expect
{
- /* This tells NAT that this is an ftp connection */
- int is_ftp;
- u_int32_t seq;
- /* 0 means not found yet */
- u_int32_t len;
- enum ip_ct_ftp_type ftptype;
- /* Port that was to be used */
- u_int16_t port;
+ /* We record seq number and length of ftp ip/port text here: all in
+ * host order. */
+
+ /* sequence number of IP address in packet is in ip_conntrack_expect */
+ u_int32_t len; /* length of IP address */
+ enum ip_ct_ftp_type ftptype; /* PORT or PASV ? */
+ u_int16_t port; /* TCP port that was to be used */
+};
+
+/* This structure exists only once per master */
+struct ip_ct_ftp_master {
/* Next valid seq position for cmd matching after newline */
u_int32_t seq_aft_nl[IP_CT_DIR_MAX];
/* 0 means seq_match_aft_nl not set */
diff --git a/include/linux/netfilter_ipv4/ip_conntrack_helper.h b/include/linux/netfilter_ipv4/ip_conntrack_helper.h
index 728e7bde6b3f1..d092a4fcb33b0 100644
--- a/include/linux/netfilter_ipv4/ip_conntrack_helper.h
+++ b/include/linux/netfilter_ipv4/ip_conntrack_helper.h
@@ -5,10 +5,19 @@
struct module;
+/* Reuse expectation when max_expected reached */
+#define IP_CT_HELPER_F_REUSE_EXPECT 0x01
+
struct ip_conntrack_helper
{
- /* Internal use. */
- struct list_head list;
+ struct list_head list; /* Internal use. */
+
+ const char *name; /* name of the module */
+ unsigned char flags; /* Flags (see above) */
+ struct module *me; /* pointer to self */
+ unsigned int max_expected; /* Maximum number of concurrent
+ * expected connections */
+ unsigned int timeout; /* timeout for expecteds */
/* Mask of things we will help (compared against server response) */
struct ip_conntrack_tuple tuple;
@@ -24,11 +33,13 @@ struct ip_conntrack_helper
extern int ip_conntrack_helper_register(struct ip_conntrack_helper *);
extern void ip_conntrack_helper_unregister(struct ip_conntrack_helper *);
-/* Add an expected connection: can only have one per connection */
+extern struct ip_conntrack_helper *ip_ct_find_helper(const struct ip_conntrack_tuple *tuple);
+
+/* Add an expected connection: can have more than one per connection */
extern int ip_conntrack_expect_related(struct ip_conntrack *related_to,
- const struct ip_conntrack_tuple *tuple,
- const struct ip_conntrack_tuple *mask,
- int (*expectfn)(struct ip_conntrack *));
-extern void ip_conntrack_unexpect_related(struct ip_conntrack *related_to);
+ struct ip_conntrack_expect *exp);
+extern int ip_conntrack_change_expect(struct ip_conntrack_expect *expect,
+ struct ip_conntrack_tuple *newtuple);
+extern void ip_conntrack_unexpect_related(struct ip_conntrack_expect *exp);
#endif /*_IP_CONNTRACK_HELPER_H*/
diff --git a/include/linux/netfilter_ipv4/ip_conntrack_irc.h b/include/linux/netfilter_ipv4/ip_conntrack_irc.h
index 8069814530eaa..bc96a5df6a4bd 100644
--- a/include/linux/netfilter_ipv4/ip_conntrack_irc.h
+++ b/include/linux/netfilter_ipv4/ip_conntrack_irc.h
@@ -20,7 +20,7 @@
#include <linux/netfilter_ipv4/lockhelp.h>
-#define IP_CONNTR_IRC 2
+#define IRC_PORT 6667
struct dccproto {
char* match;
@@ -32,16 +32,18 @@ DECLARE_LOCK_EXTERN(ip_irc_lock);
/* We record seq number and length of irc ip/port text here: all in
host order. */
-struct ip_ct_irc
+
+/* This structure is per expected connection */
+struct ip_ct_irc_expect
{
- /* This tells NAT that this is an IRC connection */
- int is_irc;
- /* sequence number where address part of DCC command begins */
- u_int32_t seq;
- /* 0 means not found yet */
+ /* length of IP address */
u_int32_t len;
/* Port that was to be used */
u_int16_t port;
};
+/* This structure exists only once per master */
+struct ip_ct_irc_master {
+};
+
#endif /* _IP_CONNTRACK_IRC_H */
diff --git a/include/linux/netfilter_ipv4/ip_conntrack_protocol.h b/include/linux/netfilter_ipv4/ip_conntrack_protocol.h
index 83076c3c5f250..e99cd7ded26f4 100644
--- a/include/linux/netfilter_ipv4/ip_conntrack_protocol.h
+++ b/include/linux/netfilter_ipv4/ip_conntrack_protocol.h
@@ -42,6 +42,13 @@ struct ip_conntrack_protocol
int (*new)(struct ip_conntrack *conntrack, struct iphdr *iph,
size_t len);
+ /* Called when a conntrack entry is destroyed */
+ void (*destroy)(struct ip_conntrack *conntrack);
+
+ /* Has to decide if a expectation matches one packet or not */
+ int (*exp_matches_pkt)(struct ip_conntrack_expect *exp,
+ struct sk_buff **pskb);
+
/* Module (if any) which this is connected to. */
struct module *me;
};
diff --git a/include/linux/netfilter_ipv4/ip_nat_helper.h b/include/linux/netfilter_ipv4/ip_nat_helper.h
index d85cd06698267..2c1fb8d9bb54e 100644
--- a/include/linux/netfilter_ipv4/ip_nat_helper.h
+++ b/include/linux/netfilter_ipv4/ip_nat_helper.h
@@ -6,23 +6,37 @@
struct sk_buff;
+/* Flags */
+/* NAT helper must be called on every packet (for TCP) */
+#define IP_NAT_HELPER_F_ALWAYS 0x01
+/* Standalone NAT helper, without a conntrack part */
+#define IP_NAT_HELPER_F_STANDALONE 0x02
+
struct ip_nat_helper
{
- /* Internal use */
- struct list_head list;
+ struct list_head list; /* Internal use */
+ const char *name; /* name of the module */
+ unsigned char flags; /* Flags (see above) */
+ struct module *me; /* pointer to self */
+
/* Mask of things we will help: vs. tuple from server */
struct ip_conntrack_tuple tuple;
struct ip_conntrack_tuple mask;
/* Helper function: returns verdict */
unsigned int (*help)(struct ip_conntrack *ct,
+ struct ip_conntrack_expect *exp,
struct ip_nat_info *info,
enum ip_conntrack_info ctinfo,
unsigned int hooknum,
struct sk_buff **pskb);
- const char *name;
+ /* Returns verdict and sets up NAT for this connection */
+ unsigned int (*expect)(struct sk_buff **pskb,
+ unsigned int hooknum,
+ struct ip_conntrack *ct,
+ struct ip_nat_info *info);
};
extern struct list_head helpers;
@@ -39,5 +53,5 @@ extern int ip_nat_mangle_tcp_packet(struct sk_buff **skb,
extern int ip_nat_seq_adjust(struct sk_buff *skb,
struct ip_conntrack *ct,
enum ip_conntrack_info ctinfo);
-extern void ip_nat_delete_sack(struct sk_buff *skb, struct tcphdr *tcph);
+extern void ip_nat_delete_sack(struct sk_buff *skb);
#endif
diff --git a/include/linux/netfilter_ipv4/ip_nat_rule.h b/include/linux/netfilter_ipv4/ip_nat_rule.h
index 6c92b285d1847..488efcee2f3ce 100644
--- a/include/linux/netfilter_ipv4/ip_nat_rule.h
+++ b/include/linux/netfilter_ipv4/ip_nat_rule.h
@@ -5,24 +5,7 @@
#include <linux/netfilter_ipv4/ip_nat.h>
#ifdef __KERNEL__
-/* Want to be told when we first NAT an expected packet for a conntrack? */
-struct ip_nat_expect
-{
- struct list_head list;
- /* Returns 1 (and sets verdict) if it has setup NAT for this
- connection */
- int (*expect)(struct sk_buff **pskb,
- unsigned int hooknum,
- struct ip_conntrack *ct,
- struct ip_nat_info *info,
- struct ip_conntrack *master,
- struct ip_nat_info *masterinfo,
- unsigned int *verdict);
-};
-
-extern int ip_nat_expect_register(struct ip_nat_expect *expect);
-extern void ip_nat_expect_unregister(struct ip_nat_expect *expect);
extern int ip_nat_rule_init(void) __init;
extern void ip_nat_rule_cleanup(void);
extern int ip_nat_rule_find(struct sk_buff **pskb,
diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
index 41eed9cd438e5..13ab68e4c0d55 100644
--- a/include/linux/pci_ids.h
+++ b/include/linux/pci_ids.h
@@ -355,6 +355,7 @@
#define PCI_VENDOR_ID_WD 0x101c
#define PCI_DEVICE_ID_WD_7197 0x3296
+#define PCI_DEVICE_ID_WD_90C 0xc24a
#define PCI_VENDOR_ID_AMI 0x101e
#define PCI_DEVICE_ID_AMI_MEGARAID3 0x1960
@@ -445,6 +446,7 @@
#define PCI_DEVICE_ID_NEC_PCX2 0x0046
#define PCI_DEVICE_ID_NEC_NILE4 0x005a
#define PCI_DEVICE_ID_NEC_VRC5476 0x009b
+#define PCI_DEVICE_ID_NEC_VRC5477_AC97 0x00a6
#define PCI_VENDOR_ID_FD 0x1036
#define PCI_DEVICE_ID_FD_36C70 0x0000
@@ -537,10 +539,6 @@
#define PCI_DEVICE_ID_ELSA_MICROLINK 0x1000
#define PCI_DEVICE_ID_ELSA_QS3000 0x3000
-#define PCI_VENDOR_ID_ELSA 0x1048
-#define PCI_DEVICE_ID_ELSA_MICROLINK 0x1000
-#define PCI_DEVICE_ID_ELSA_QS3000 0x3000
-
#define PCI_VENDOR_ID_SGS 0x104a
#define PCI_DEVICE_ID_SGS_2000 0x0008
#define PCI_DEVICE_ID_SGS_1764 0x0009
@@ -597,6 +595,7 @@
#define PCI_DEVICE_ID_MOTOROLA_MPC106 0x0002
#define PCI_DEVICE_ID_MOTOROLA_RAVEN 0x4801
#define PCI_DEVICE_ID_MOTOROLA_FALCON 0x4802
+#define PCI_DEVICE_ID_MOTOROLA_HAWK 0x4803
#define PCI_DEVICE_ID_MOTOROLA_CPX8216 0x4806
#define PCI_VENDOR_ID_PROMISE 0x105a
@@ -608,6 +607,7 @@
#define PCI_DEVICE_ID_PROMISE_20268R 0x6268
#define PCI_DEVICE_ID_PROMISE_20269 0x4d69
#define PCI_DEVICE_ID_PROMISE_20275 0x1275
+#define PCI_DEVICE_ID_PROMISE_20276 0x5275
#define PCI_DEVICE_ID_PROMISE_5300 0x5300
#define PCI_VENDOR_ID_N9 0x105d
@@ -649,6 +649,12 @@
#define PCI_DEVICE_ID_APPLE_KL_USB 0x0019
#define PCI_DEVICE_ID_APPLE_UNI_N_AGP 0x0020
#define PCI_DEVICE_ID_APPLE_UNI_N_GMAC 0x0021
+#define PCI_DEVICE_ID_APPLE_KEYLARGO 0x0022
+#define PCI_DEVICE_ID_APPLE_UNI_N_GMACP 0x0024
+#define PCI_DEVICE_ID_APPLE_KEYLARGO_P 0x0025
+#define PCI_DEVICE_ID_APPLE_KL_USB_P 0x0026
+#define PCI_DEVICE_ID_APPLE_UNI_N_AGP_P 0x0027
+#define PCI_DEVICE_ID_APPLE_UNI_N_AGP15 0x002d
#define PCI_DEVICE_ID_APPLE_UNI_N_FW2 0x0030
#define PCI_VENDOR_ID_YAMAHA 0x1073
@@ -860,12 +866,18 @@
#define PCI_DEVICE_ID_NVIDIA_QUADRO 0x0103
#define PCI_DEVICE_ID_NVIDIA_GEFORCE2_MX 0x0110
#define PCI_DEVICE_ID_NVIDIA_GEFORCE2_MX2 0x0111
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE2_GO 0x0112
#define PCI_DEVICE_ID_NVIDIA_QUADRO2_MXR 0x0113
#define PCI_DEVICE_ID_NVIDIA_GEFORCE2_GTS 0x0150
#define PCI_DEVICE_ID_NVIDIA_GEFORCE2_GTS2 0x0151
#define PCI_DEVICE_ID_NVIDIA_GEFORCE2_ULTRA 0x0152
#define PCI_DEVICE_ID_NVIDIA_QUADRO2_PRO 0x0153
+#define PCI_DEVICE_ID_NVIDIA_IGEFORCE2 0x01a0
#define PCI_DEVICE_ID_NVIDIA_NFORCE_IDE 0x01bc
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE3 0x0200
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE3_1 0x0201
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE3_2 0x0202
+#define PCI_DEVICE_ID_NVIDIA_QUADRO_DDC 0x0203
#define PCI_VENDOR_ID_IMS 0x10e0
#define PCI_DEVICE_ID_IMS_8849 0x8849
@@ -1106,6 +1118,11 @@
#define PCI_DEVICE_ID_TOSHIBA_TOPIC95 0x060a
#define PCI_DEVICE_ID_TOSHIBA_TOPIC97 0x060f
+#define PCI_VENDOR_ID_TOSHIBA_2 0x102f
+#define PCI_DEVICE_ID_TOSHIBA_TX3927 0x000a
+#define PCI_DEVICE_ID_TOSHIBA_TC35815CF 0x0030
+#define PCI_DEVICE_ID_TOSHIBA_TX4927 0x0180
+
#define PCI_VENDOR_ID_RICOH 0x1180
#define PCI_DEVICE_ID_RICOH_RL5C465 0x0465
#define PCI_DEVICE_ID_RICOH_RL5C466 0x0466
@@ -1118,6 +1135,8 @@
#define PCI_DEVICE_ID_ARTOP_ATP850UF 0x0005
#define PCI_DEVICE_ID_ARTOP_ATP860 0x0006
#define PCI_DEVICE_ID_ARTOP_ATP860R 0x0007
+#define PCI_DEVICE_ID_ARTOP_ATP865 0x0008
+#define PCI_DEVICE_ID_ARTOP_ATP865R 0x0009
#define PCI_DEVICE_ID_ARTOP_AEC7610 0x8002
#define PCI_DEVICE_ID_ARTOP_AEC7612UW 0x8010
#define PCI_DEVICE_ID_ARTOP_AEC7612U 0x8020
@@ -1279,13 +1298,8 @@
#define PCI_VENDOR_ID_ITE 0x1283
#define PCI_DEVICE_ID_ITE_IT8172G 0x8172
#define PCI_DEVICE_ID_ITE_IT8172G_AUDIO 0x0801
-
-#define PCI_VENDOR_ID_ITE 0x1283
-#define PCI_DEVICE_ID_ITE_IT8172G 0x8172
-
-#define PCI_VENDOR_ID_ITE 0x1283
#define PCI_DEVICE_ID_ITE_8872 0x8872
-
+#define PCI_DEVICE_ID_ITE_IT8330G_0 0xe886
/* formerly Platform Tech */
#define PCI_VENDOR_ID_ESS_OLD 0x1285
@@ -1450,6 +1464,8 @@
#define PCI_DEVICE_ID_LAVA_DSERIAL 0x0100 /* 2x 16550 */
#define PCI_DEVICE_ID_LAVA_QUATRO_A 0x0101 /* 2x 16550, half of 4 port */
#define PCI_DEVICE_ID_LAVA_QUATRO_B 0x0102 /* 2x 16550, half of 4 port */
+#define PCI_DEVICE_ID_LAVA_OCTO_A 0x0180 /* 4x 16550A, half of 8 port */
+#define PCI_DEVICE_ID_LAVA_OCTO_B 0x0181 /* 4x 16550A, half of 8 port */
#define PCI_DEVICE_ID_LAVA_PORT_PLUS 0x0200 /* 2x 16650 */
#define PCI_DEVICE_ID_LAVA_QUAD_A 0x0201 /* 2x 16650, half of 4 port */
#define PCI_DEVICE_ID_LAVA_QUAD_B 0x0202 /* 2x 16650, half of 4 port */
@@ -1639,16 +1655,6 @@
#define PCI_DEVICE_ID_INTEL_82801BA_2 0x2443
#define PCI_DEVICE_ID_INTEL_82801BA_3 0x2444
#define PCI_DEVICE_ID_INTEL_82801BA_4 0x2445
-#define PCI_DEVICE_ID_INTEL_82801CA_0 0x2480
-#define PCI_DEVICE_ID_INTEL_82801CA_2 0x2482
-#define PCI_DEVICE_ID_INTEL_82801CA_3 0x2483
-#define PCI_DEVICE_ID_INTEL_82801CA_4 0x2484
-#define PCI_DEVICE_ID_INTEL_82801CA_5 0x2485
-#define PCI_DEVICE_ID_INTEL_82801CA_6 0x2486
-#define PCI_DEVICE_ID_INTEL_82801CA_7 0x2487
-#define PCI_DEVICE_ID_INTEL_82801CA_10 0x248a
-#define PCI_DEVICE_ID_INTEL_82801CA_11 0x248b
-#define PCI_DEVICE_ID_INTEL_82801CA_12 0x248c
#define PCI_DEVICE_ID_INTEL_82801BA_5 0x2446
#define PCI_DEVICE_ID_INTEL_82801BA_6 0x2448
#define PCI_DEVICE_ID_INTEL_82801BA_7 0x2449
diff --git a/include/linux/pnpbios.h b/include/linux/pnpbios.h
index b1b2b6f9e5e66..e1e8542bda0a4 100644
--- a/include/linux/pnpbios.h
+++ b/include/linux/pnpbios.h
@@ -143,20 +143,21 @@ static __inline struct pnpbios_driver *pnpbios_dev_driver(const struct pci_dev *
extern int pnpbios_dont_use_current_config;
extern void *pnpbios_kmalloc(size_t size, int f);
extern int pnpbios_init (void);
-extern void pnpbios_proc_init (void);
+extern int pnpbios_proc_init (void);
+extern void pnpbios_proc_exit (void);
extern int pnp_bios_dev_node_info (struct pnp_dev_node_info *data);
extern int pnp_bios_get_dev_node (u8 *nodenum, char config, struct pnp_bios_node *data);
extern int pnp_bios_set_dev_node (u8 nodenum, char config, struct pnp_bios_node *data);
+extern int pnp_bios_get_stat_res (char *info);
+extern int pnp_bios_isapnp_config (struct pnp_isa_config_struc *data);
+extern int pnp_bios_escd_info (struct escd_info_struc *data);
+extern int pnp_bios_read_escd (char *data, u32 nvram_base);
#if needed
extern int pnp_bios_get_event (u16 *message);
extern int pnp_bios_send_message (u16 message);
extern int pnp_bios_set_stat_res (char *info);
-extern int pnp_bios_get_stat_res (char *info);
extern int pnp_bios_apm_id_table (char *table, u16 *size);
-extern int pnp_bios_isapnp_config (struct pnp_isa_config_struc *data);
-extern int pnp_bios_escd_info (struct escd_info_struc *data);
-extern int pnp_bios_read_escd (char *data, u32 nvram_base);
extern int pnp_bios_write_escd (char *data, u32 nvram_base);
#endif
diff --git a/include/linux/quota.h b/include/linux/quota.h
index d155eb2bd51ac..b2d5de7368f6b 100644
--- a/include/linux/quota.h
+++ b/include/linux/quota.h
@@ -144,7 +144,6 @@ struct dqstats {
#ifdef __KERNEL__
-extern int nr_dquots, nr_free_dquots;
extern int dquot_root_squash;
#define NR_DQHASH 43 /* Just an arbitrary number */
diff --git a/include/linux/raid/md.h b/include/linux/raid/md.h
index 233163eb28728..07e24c4dc71ef 100644
--- a/include/linux/raid/md.h
+++ b/include/linux/raid/md.h
@@ -18,8 +18,6 @@
#ifndef _MD_H
#define _MD_H
-#include <linux/mm.h>
-#include <linux/fs.h>
#include <linux/blkdev.h>
#include <asm/semaphore.h>
#include <linux/major.h>
diff --git a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h
index b0778a2d45e77..3854002c7eec3 100644
--- a/include/linux/rtnetlink.h
+++ b/include/linux/rtnetlink.h
@@ -589,7 +589,7 @@ extern void rtnetlink_init(void);
#define ASSERT_RTNL() do { if (down_trylock(&rtnl_sem) == 0) { up(&rtnl_sem); \
printk("RTNL: assertion failed at " __FILE__ "(%d)\n", __LINE__); } \
- } while(0);
+ } while(0)
#define BUG_TRAP(x) if (!(x)) { printk("KERNEL: assertion (" #x ") failed at " __FILE__ "(%d)\n", __LINE__); }
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 205c801bea22a..024e34706cc95 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -79,7 +79,6 @@ extern int nr_threads;
extern int last_pid;
extern unsigned long nr_running(void);
-#include <linux/fs.h>
#include <linux/time.h>
#include <linux/param.h>
#include <linux/resource.h>
diff --git a/include/linux/securebits.h b/include/linux/securebits.h
index 1e10badcbdba3..5b0617840fa46 100644
--- a/include/linux/securebits.h
+++ b/include/linux/securebits.h
@@ -6,7 +6,7 @@
extern unsigned securebits;
/* When set UID 0 has no special privileges. When unset, we support
- inheritance of root-permissions and suid-root executablew under
+ inheritance of root-permissions and suid-root executable under
compatibility mode. We raise the effective and inheritable bitmasks
*of the executable file* if the effective uid of the new process is
0. If the real uid is 0, we raise the inheritable bitmask of the
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index 2bec5fabc4dc1..372d30d0cd55b 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -16,7 +16,6 @@
#include <linux/config.h>
#include <linux/kernel.h>
-#include <linux/sched.h>
#include <linux/time.h>
#include <linux/cache.h>
diff --git a/include/linux/smb_fs.h b/include/linux/smb_fs.h
index f554cf9057a8e..e049feae8dea4 100644
--- a/include/linux/smb_fs.h
+++ b/include/linux/smb_fs.h
@@ -12,6 +12,7 @@
#include <linux/smb.h>
#include <linux/smb_fs_i.h>
#include <linux/smb_fs_sb.h>
+#include <linux/fs.h>
/*
* ioctl commands
diff --git a/include/linux/sonypi.h b/include/linux/sonypi.h
index 48aab6f712a33..4a53f5b8852a0 100644
--- a/include/linux/sonypi.h
+++ b/include/linux/sonypi.h
@@ -73,11 +73,28 @@
#define SONYPI_EVENT_BACK_PRESSED 35
#define SONYPI_EVENT_LID_CLOSED 36
#define SONYPI_EVENT_LID_OPENED 37
+#define SONYPI_EVENT_BLUETOOTH_ON 38
+#define SONYPI_EVENT_BLUETOOTH_OFF 39
+/* get/set brightness */
+#define SONYPI_IOCGBRT _IOR('v', 0, __u8)
+#define SONYPI_IOCSBRT _IOW('v', 0, __u8)
-/* brightness etc. ioctls */
-#define SONYPI_IOCGBRT _IOR('v', 0, __u8)
-#define SONYPI_IOCSBRT _IOW('v', 0, __u8)
+/* get battery full capacity/remaining capacity */
+#define SONYPI_IOCGBAT1CAP _IOR('v', 2, __u16)
+#define SONYPI_IOCGBAT1REM _IOR('v', 3, __u16)
+#define SONYPI_IOCGBAT2CAP _IOR('v', 4, __u16)
+#define SONYPI_IOCGBAT2REM _IOR('v', 5, __u16)
+
+/* get battery flags: battery1/battery2/ac adapter present */
+#define SONYPI_BFLAGS_B1 0x01
+#define SONYPI_BFLAGS_B2 0x02
+#define SONYPI_BFLAGS_AC 0x04
+#define SONYPI_IOCGBATFLAGS _IOR('v', 7, __u8)
+
+/* get/set bluetooth subsystem state on/off */
+#define SONYPI_IOCGBLUE _IOR('v', 8, __u8)
+#define SONYPI_IOCSBLUE _IOW('v', 9, __u8)
#ifdef __KERNEL__
diff --git a/include/linux/spinlock.h b/include/linux/spinlock.h
index cd7428798399f..a78cd80f4ab63 100644
--- a/include/linux/spinlock.h
+++ b/include/linux/spinlock.h
@@ -204,7 +204,7 @@ do { \
#else
-#define preempt_get_count() do { } while (0)
+#define preempt_get_count() (0)
#define preempt_disable() do { } while (0)
#define preempt_enable_no_resched() do {} while(0)
#define preempt_enable() do { } while (0)
diff --git a/include/linux/string.h b/include/linux/string.h
index b5497d139d282..3d344c0190d8e 100644
--- a/include/linux/string.h
+++ b/include/linux/string.h
@@ -12,9 +12,7 @@
extern "C" {
#endif
-extern char * ___strtok;
extern char * strpbrk(const char *,const char *);
-extern char * strtok(char *,const char *);
extern char * strsep(char **,const char *);
extern __kernel_size_t strspn(const char *,const char *);
diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h
index 01829afb8e41b..30caa40c26be9 100644
--- a/include/linux/sysctl.h
+++ b/include/linux/sysctl.h
@@ -288,7 +288,8 @@ enum
NET_TCP_ADV_WIN_SCALE=87,
NET_IPV4_NONLOCAL_BIND=88,
NET_IPV4_ICMP_RATELIMIT=89,
- NET_IPV4_ICMP_RATEMASK=90
+ NET_IPV4_ICMP_RATEMASK=90,
+ NET_TCP_TW_REUSE=91
};
enum {
@@ -333,7 +334,8 @@ enum
NET_IPV4_CONF_BOOTP_RELAY=10,
NET_IPV4_CONF_LOG_MARTIANS=11,
NET_IPV4_CONF_TAG=12,
- NET_IPV4_CONF_ARPFILTER=13
+ NET_IPV4_CONF_ARPFILTER=13,
+ NET_IPV4_CONF_MEDIUM_ID=14,
};
/* /proc/sys/net/ipv6 */
diff --git a/include/linux/udf_fs.h b/include/linux/udf_fs.h
index 77a54446df3d9..07cbb273974f6 100644
--- a/include/linux/udf_fs.h
+++ b/include/linux/udf_fs.h
@@ -34,6 +34,10 @@
#ifndef _UDF_FS_H
#define _UDF_FS_H 1
+#include <linux/config.h>
+
+#include <linux/config.h>
+
#define UDF_PREALLOCATE
#define UDF_DEFAULT_PREALLOC_BLOCKS 8
diff --git a/include/linux/videodev.h b/include/linux/videodev.h
index 542e3ececef41..80966ed8e2885 100644
--- a/include/linux/videodev.h
+++ b/include/linux/videodev.h
@@ -37,8 +37,6 @@ struct video_device
* video_generic_ioctl() does the userspace copying of the
* ioctl arguments */
struct file_operations *fops;
- int (*kernel_ioctl)(struct inode *inode, struct file *file,
- unsigned int cmd, void *arg);
void *priv; /* Used to be 'private' but that upsets C++ */
/* for videodev.c intenal usage -- don't touch */
@@ -60,8 +58,10 @@ extern struct video_device* video_devdata(struct file*);
extern int video_exclusive_open(struct inode *inode, struct file *file);
extern int video_exclusive_release(struct inode *inode, struct file *file);
-extern int video_generic_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg);
+extern int video_usercopy(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg,
+ int (*func)(struct inode *inode, struct file *file,
+ unsigned int cmd, void *arg));
#endif /* __KERNEL__ */
#define VID_TYPE_CAPTURE 1 /* Can capture */
diff --git a/include/net/ndisc.h b/include/net/ndisc.h
index 2c37a36e4aa2c..407268c78def1 100644
--- a/include/net/ndisc.h
+++ b/include/net/ndisc.h
@@ -42,11 +42,7 @@ extern struct neigh_table nd_tbl;
struct nd_msg {
struct icmp6hdr icmph;
struct in6_addr target;
- struct {
- __u8 opt_type;
- __u8 opt_len;
- __u8 link_addr[MAX_ADDR_LEN];
- } opt;
+ __u8 opt[0];
};
struct ra_msg {
diff --git a/include/net/pkt_sched.h b/include/net/pkt_sched.h
index 58aa70d2cf844..84c94256dc65e 100644
--- a/include/net/pkt_sched.h
+++ b/include/net/pkt_sched.h
@@ -358,8 +358,8 @@ extern int psched_tod_diff(int delta_sec, int bound);
#define PSCHED_TDIFF(tv1, tv2) (long)((tv1) - (tv2))
#define PSCHED_TDIFF_SAFE(tv1, tv2, bound, guard) \
({ \
- long __delta = (tv1) - (tv2); \
- if ( __delta > (bound)) { __delta = (bound); guard; } \
+ long long __delta = (tv1) - (tv2); \
+ if ( __delta > (long long)(bound)) { __delta = (bound); guard; } \
__delta; \
})
diff --git a/include/net/sock.h b/include/net/sock.h
index d50815f55ff35..57159c6ce0bd4 100644
--- a/include/net/sock.h
+++ b/include/net/sock.h
@@ -80,7 +80,7 @@ typedef struct {
do { spin_lock_init(&((__sk)->lock.slock)); \
(__sk)->lock.users = 0; \
init_waitqueue_head(&((__sk)->lock.wq)); \
-} while(0);
+} while(0)
struct sock {
/* Begin of struct sock/struct tcp_tw_bucket shared layout */
diff --git a/include/net/tcp.h b/include/net/tcp.h
index c45fc3e128457..1e7cf2cdce474 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -78,7 +78,7 @@ struct tcp_ehash_bucket {
*/
struct tcp_bind_bucket {
unsigned short port;
- unsigned short fastreuse;
+ signed short fastreuse;
struct tcp_bind_bucket *next;
struct sock *owners;
struct tcp_bind_bucket **pprev;
@@ -469,6 +469,7 @@ extern int sysctl_tcp_wmem[3];
extern int sysctl_tcp_rmem[3];
extern int sysctl_tcp_app_win;
extern int sysctl_tcp_adv_win_scale;
+extern int sysctl_tcp_tw_reuse;
extern atomic_t tcp_memory_allocated;
extern atomic_t tcp_sockets_allocated;
@@ -507,7 +508,7 @@ struct open_request {
__u16 rmt_port;
__u16 mss;
__u8 retrans;
- __u8 index;
+ __u8 __pad;
__u16 snd_wscale : 4,
rcv_wscale : 4,
tstamp_ok : 1,
@@ -577,9 +578,7 @@ struct tcp_func {
struct sk_buff *skb,
struct open_request *req,
struct dst_entry *dst);
-
- int (*hash_connecting) (struct sock *sk);
-
+
int (*remember_stamp) (struct sock *sk);
__u16 net_header_len;
@@ -781,8 +780,7 @@ extern int tcp_v4_connect(struct sock *sk,
struct sockaddr *uaddr,
int addr_len);
-extern int tcp_connect(struct sock *sk,
- struct sk_buff *skb);
+extern int tcp_connect(struct sock *sk);
extern struct sk_buff * tcp_make_synack(struct sock *sk,
struct dst_entry *dst,
@@ -1834,6 +1832,6 @@ static inline int tcp_paws_check(struct tcp_opt *tp, int rst)
return 1;
}
-#define TCP_CHECK_TIMER(sk) do { } while (0);
+#define TCP_CHECK_TIMER(sk) do { } while (0)
#endif /* _TCP_H */
diff --git a/init/do_mounts.c b/init/do_mounts.c
index 3d9e02856b960..df1b125802841 100644
--- a/init/do_mounts.c
+++ b/init/do_mounts.c
@@ -826,7 +826,7 @@ void prepare_namespace(void)
create_dev("/dev/root", ROOT_DEV, NULL);
if (mount_initrd) {
- if (initrd_load() && kdev_same(ROOT_DEV, mk_kdev(RAMDISK_MAJOR, 0))) {
+ if (initrd_load() && !kdev_same(ROOT_DEV, mk_kdev(RAMDISK_MAJOR, 0))) {
handle_initrd();
goto out;
}
diff --git a/ipc/sem.c b/ipc/sem.c
index 1c8d9837082f0..eb145b62a5086 100644
--- a/ipc/sem.c
+++ b/ipc/sem.c
@@ -62,6 +62,7 @@
#include <linux/spinlock.h>
#include <linux/init.h>
#include <linux/proc_fs.h>
+#include <linux/smp_lock.h>
#include <asm/uaccess.h>
#include "util.h"
@@ -995,6 +996,8 @@ void sem_exit (void)
struct sem_array *sma;
int nsems, i;
+ lock_kernel();
+
/* If the current process was sleeping for a semaphore,
* remove it from the queue.
*/
@@ -1051,6 +1054,8 @@ next_entry:
sem_unlock(semid);
}
current->semundo = NULL;
+
+ unlock_kernel();
}
#ifdef CONFIG_PROC_FS
diff --git a/ipc/shm.c b/ipc/shm.c
index 6d7f6b3642945..650c93e471339 100644
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -674,16 +674,19 @@ asmlinkage long sys_shmdt (char *shmaddr)
{
struct mm_struct *mm = current->mm;
struct vm_area_struct *shmd, *shmdnext;
+ int retval = -EINVAL;
down_write(&mm->mmap_sem);
for (shmd = mm->mmap; shmd; shmd = shmdnext) {
shmdnext = shmd->vm_next;
if (shmd->vm_ops == &shm_vm_ops
- && shmd->vm_start - (shmd->vm_pgoff << PAGE_SHIFT) == (ulong) shmaddr)
+ && shmd->vm_start - (shmd->vm_pgoff << PAGE_SHIFT) == (ulong) shmaddr) {
do_munmap(mm, shmd->vm_start, shmd->vm_end - shmd->vm_start);
+ retval = 0;
+ }
}
up_write(&mm->mmap_sem);
- return 0;
+ return retval;
}
#ifdef CONFIG_PROC_FS
diff --git a/kernel/Makefile b/kernel/Makefile
index 54a8956562708..2384e5fe9bea0 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -14,12 +14,13 @@ export-objs = signal.o sys.o kmod.o context.o ksyms.o pm.o exec_domain.o \
obj-y = sched.o dma.o fork.o exec_domain.o panic.o printk.o \
module.o exit.o itimer.o info.o time.o softirq.o resource.o \
- sysctl.o acct.o capability.o ptrace.o timer.o user.o \
+ sysctl.o capability.o ptrace.o timer.o user.o \
signal.o sys.o kmod.o context.o futex.o
obj-$(CONFIG_UID16) += uid16.o
obj-$(CONFIG_MODULES) += ksyms.o
obj-$(CONFIG_PM) += pm.o
+obj-$(CONFIG_BSD_PROCESS_ACCT) += acct.o
ifneq ($(CONFIG_IA64),y)
# According to Alan Modra <alan@linuxcare.com.au>, the -fno-omit-frame-pointer is
diff --git a/kernel/acct.c b/kernel/acct.c
index 31390d55a72f5..dbb9312e06242 100644
--- a/kernel/acct.c
+++ b/kernel/acct.c
@@ -44,17 +44,11 @@
*/
#include <linux/config.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-
-#ifdef CONFIG_BSD_PROCESS_ACCT
#include <linux/mm.h>
#include <linux/slab.h>
#include <linux/acct.h>
-#include <linux/smp_lock.h>
#include <linux/file.h>
#include <linux/tty.h>
-
#include <asm/uaccess.h>
/*
@@ -397,15 +391,3 @@ int acct_process(long exitcode)
spin_unlock(&acct_globals.lock);
return 0;
}
-
-#else
-/*
- * Dummy system call when BSD process accounting is not configured
- * into the kernel.
- */
-
-asmlinkage long sys_acct(const char * filename)
-{
- return -ENOSYS;
-}
-#endif
diff --git a/kernel/exit.c b/kernel/exit.c
index d2cba1fc65d56..96472474ada78 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -14,9 +14,7 @@
#include <linux/personality.h>
#include <linux/tty.h>
#include <linux/namespace.h>
-#ifdef CONFIG_BSD_PROCESS_ACCT
#include <linux/acct.h>
-#endif
#include <linux/file.h>
#include <linux/binfmts.h>
@@ -492,13 +490,15 @@ NORET_TYPE void do_exit(long code)
tsk->flags |= PF_EXITING;
del_timer_sync(&tsk->real_timer);
+ if (unlikely(preempt_get_count()))
+ printk(KERN_ERR "error: %s[%d] exited with preempt_count %d\n",
+ current->comm, current->pid,
+ preempt_get_count());
+
fake_volatile:
-#ifdef CONFIG_BSD_PROCESS_ACCT
acct_process(code);
-#endif
__exit_mm(tsk);
- lock_kernel();
sem_exit();
__exit_files(tsk);
__exit_fs(tsk);
diff --git a/kernel/ksyms.c b/kernel/ksyms.c
index a59e0ee7bd86d..519a500fb5472 100644
--- a/kernel/ksyms.c
+++ b/kernel/ksyms.c
@@ -107,7 +107,7 @@ EXPORT_SYMBOL(kmalloc);
EXPORT_SYMBOL(kfree);
EXPORT_SYMBOL(vfree);
EXPORT_SYMBOL(__vmalloc);
-EXPORT_SYMBOL_GPL(vmalloc_to_page);
+EXPORT_SYMBOL(vmalloc_to_page);
EXPORT_SYMBOL(mem_map);
EXPORT_SYMBOL(remap_page_range);
EXPORT_SYMBOL(max_mapnr);
@@ -537,7 +537,6 @@ EXPORT_SYMBOL(sys_tz);
EXPORT_SYMBOL(file_fsync);
EXPORT_SYMBOL(fsync_buffers_list);
EXPORT_SYMBOL(clear_inode);
-EXPORT_SYMBOL(___strtok);
EXPORT_SYMBOL(init_special_inode);
EXPORT_SYMBOL(__get_hash_table);
EXPORT_SYMBOL(new_inode);
diff --git a/kernel/sys.c b/kernel/sys.c
index fc8e5e4060a01..54f018e69bf5a 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -173,6 +173,18 @@ asmlinkage long sys_ni_syscall(void)
return -ENOSYS;
}
+/*
+ * "Conditional" syscalls
+ *
+ * What we want is __attribute__((weak,alias("sys_ni_syscall"))),
+ * but it doesn't work on sparc64, so we just do it by hand
+ */
+#define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall");
+
+cond_syscall(sys_nfsservctl)
+cond_syscall(sys_quotactl)
+cond_syscall(sys_acct)
+
static int proc_sel(struct task_struct *p, int which, int who)
{
if(p->pid)
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index 64dca468d417b..66ccb010e1e5a 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -284,8 +284,6 @@ static ctl_table fs_table[] = {
0444, NULL, &proc_dointvec},
{FS_MAXFILE, "file-max", &files_stat.max_files, sizeof(int),
0644, NULL, &proc_dointvec},
- {FS_NRDQUOT, "dquot-nr", &nr_dquots, 2*sizeof(int),
- 0444, NULL, &proc_dointvec},
{FS_DENTRY, "dentry-state", &dentry_stat, 6*sizeof(int),
0444, NULL, &proc_dointvec},
{FS_OVERFLOWUID, "overflowuid", &fs_overflowuid, sizeof(int), 0644, NULL,
@@ -476,11 +474,11 @@ int do_sysctl_strategy (ctl_table *table,
}
/**
- * register_sysctl_table - register a sysctl heirarchy
+ * register_sysctl_table - register a sysctl hierarchy
* @table: the top-level table structure
* @insert_at_head: whether the entry should be inserted in front or at the end
*
- * Register a sysctl table heirarchy. @table should be a filled in ctl_table
+ * Register a sysctl table hierarchy. @table should be a filled in ctl_table
* array. An entry with a ctl_name of 0 terminates the table.
*
* The members of the &ctl_table structure are used as follows:
@@ -564,7 +562,7 @@ struct ctl_table_header *register_sysctl_table(ctl_table * table,
}
/**
- * unregister_sysctl_table - unregister a sysctl table heirarchy
+ * unregister_sysctl_table - unregister a sysctl table hierarchy
* @header: the header returned from register_sysctl_table
*
* Unregisters the sysctl table and all children. proc entries may not
diff --git a/lib/Makefile b/lib/Makefile
index 9a4607bd59bf6..349c9be41f25e 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -8,7 +8,7 @@
L_TARGET := lib.a
-export-objs := cmdline.o dec_and_lock.o rwsem-spinlock.o rwsem.o crc32.o
+export-objs := cmdline.o dec_and_lock.o rwsem-spinlock.o rwsem.o crc32.o rbtree.o
obj-y := errno.o ctype.o string.o vsprintf.o brlock.o cmdline.o bust_spinlocks.o rbtree.o
diff --git a/lib/rbtree.c b/lib/rbtree.c
index ee6d9713f29fc..bed359bd4a928 100644
--- a/lib/rbtree.c
+++ b/lib/rbtree.c
@@ -20,6 +20,7 @@
*/
#include <linux/rbtree.h>
+#include <linux/module.h>
static void __rb_rotate_left(rb_node_t * node, rb_root_t * root)
{
@@ -125,6 +126,7 @@ void rb_insert_color(rb_node_t * node, rb_root_t * root)
root->rb_node->rb_color = RB_BLACK;
}
+EXPORT_SYMBOL(rb_insert_color);
static void __rb_erase_color(rb_node_t * node, rb_node_t * parent,
rb_root_t * root)
@@ -291,3 +293,4 @@ void rb_erase(rb_node_t * node, rb_root_t * root)
if (color == RB_BLACK)
__rb_erase_color(child, parent, root);
}
+EXPORT_SYMBOL(rb_erase);
diff --git a/lib/string.c b/lib/string.c
index 41a90d37e35a3..97aa5eda36319 100644
--- a/lib/string.c
+++ b/lib/string.c
@@ -13,6 +13,10 @@
* * Fri Jun 25 1999, Ingo Oeser <ioe@informatik.tu-chemnitz.de>
* - Added strsep() which will replace strtok() soon (because strsep() is
* reentrant and should be faster). Use only strsep() in new code, please.
+ *
+ * * Sat Feb 09 2002, Jason Thomas <jason@topic.com.au>,
+ * Matthew Hawkins <matt@mh.dropbear.id.au>
+ * - Kissed strtok() goodbye
*/
#include <linux/types.h>
@@ -52,8 +56,6 @@ int strnicmp(const char *s1, const char *s2, size_t len)
}
#endif
-char * ___strtok;
-
#ifndef __HAVE_ARCH_STRCPY
/**
* strcpy - Copy a %NUL terminated string
@@ -290,35 +292,6 @@ char * strpbrk(const char * cs,const char * ct)
}
#endif
-#ifndef __HAVE_ARCH_STRTOK
-/**
- * strtok - Split a string into tokens
- * @s: The string to be searched
- * @ct: The characters to search for
- *
- * WARNING: strtok is deprecated, use strsep instead.
- */
-char * strtok(char * s,const char * ct)
-{
- char *sbegin, *send;
-
- sbegin = s ? s : ___strtok;
- if (!sbegin) {
- return NULL;
- }
- sbegin += strspn(sbegin,ct);
- if (*sbegin == '\0') {
- ___strtok = NULL;
- return( NULL );
- }
- send = strpbrk( sbegin, ct);
- if (send && *send != '\0')
- *send++ = '\0';
- ___strtok = send;
- return (sbegin);
-}
-#endif
-
#ifndef __HAVE_ARCH_STRSEP
/**
* strsep - Split a string into tokens
@@ -452,7 +425,7 @@ void * memmove(void * dest,const void *src,size_t count)
int memcmp(const void * cs,const void * ct,size_t count)
{
const unsigned char *su1, *su2;
- signed char res = 0;
+ int res = 0;
for( su1 = cs, su2 = ct; 0 < count; ++su1, ++su2, count--)
if ((res = *su1 - *su2) != 0)
diff --git a/mm/filemap.c b/mm/filemap.c
index a780037547a0f..38567aa582b3c 100644
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -742,26 +742,6 @@ static int read_cluster_nonblocking(struct file * file, unsigned long offset,
}
/*
- * Knuth recommends primes in approximately golden ratio to the maximum
- * integer representable by a machine word for multiplicative hashing.
- * Chuck Lever verified the effectiveness of this technique:
- * http://www.citi.umich.edu/techreports/reports/citi-tr-00-1.pdf
- *
- * These primes are chosen to be bit-sparse, that is operations on
- * them can use shifts and additions instead of multiplications for
- * machines where multiplications are slow.
- */
-#if BITS_PER_LONG == 32
-/* 2^31 + 2^29 - 2^25 + 2^22 - 2^19 - 2^16 + 1 */
-#define GOLDEN_RATIO_PRIME 0x9e370001UL
-#elif BITS_PER_LONG == 64
-/* 2^63 + 2^61 - 2^57 + 2^54 - 2^51 - 2^18 + 1 */
-#define GOLDEN_RATIO_PRIME 0x9e37fffffffc0001UL
-#else
-#error Define GOLDEN_RATIO_PRIME for your wordsize.
-#endif
-
-/*
* In order to wait for pages to become available there must be
* waitqueues associated with pages. By using a hash table of
* waitqueues where the bucket discipline is to maintain all
diff --git a/mm/mempool.c b/mm/mempool.c
index b9b6ae8c56084..dca9cd9735028 100644
--- a/mm/mempool.c
+++ b/mm/mempool.c
@@ -34,6 +34,9 @@ mempool_t * mempool_create(int min_nr, mempool_alloc_t *alloc_fn,
mempool_t *pool;
int i;
+ BUG_ON(!alloc_fn);
+ BUG_ON(!free_fn);
+
pool = kmalloc(sizeof(*pool), GFP_KERNEL);
if (!pool)
return NULL;
diff --git a/mm/shmem.c b/mm/shmem.c
index b2b19b9051166..bf477dd98f6e1 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -1203,10 +1203,9 @@ static int shmem_parse_options(char *options, int *mode, uid_t *uid, gid_t *gid,
{
char *this_char, *value, *rest;
- this_char = NULL;
- if ( options )
- this_char = strtok(options,",");
- for ( ; this_char; this_char = strtok(NULL,",")) {
+ while ((this_char = strsep(&options, ",")) != NULL) {
+ if (!*this_char)
+ continue;
if ((value = strchr(this_char,'=')) != NULL) {
*value++ = 0;
} else {
diff --git a/net/atm/pppoatm.c b/net/atm/pppoatm.c
index 0671938f57817..48c41db8bf3e9 100644
--- a/net/atm/pppoatm.c
+++ b/net/atm/pppoatm.c
@@ -363,3 +363,4 @@ module_exit(pppoatm_exit);
MODULE_AUTHOR("Mitchell Blank Jr <mitch@sfgoth.com>");
MODULE_DESCRIPTION("RFC2364 PPP over ATM/AAL5");
+MODULE_LICENSE("GPL");
diff --git a/net/atm/resources.c b/net/atm/resources.c
index c04f8b10ee220..3857176cc8bc2 100644
--- a/net/atm/resources.c
+++ b/net/atm/resources.c
@@ -31,95 +31,107 @@ static struct atm_dev *last_dev = NULL;
struct atm_vcc *nodev_vccs = NULL;
extern spinlock_t atm_dev_lock;
-
-static struct atm_dev *alloc_atm_dev(const char *type)
+/* Caller must hold atm_dev_lock. */
+static struct atm_dev *__alloc_atm_dev(const char *type)
{
struct atm_dev *dev;
- dev = kmalloc(sizeof(*dev),GFP_KERNEL);
- if (!dev) return NULL;
- memset(dev,0,sizeof(*dev));
+ dev = kmalloc(sizeof(*dev), GFP_ATOMIC);
+ if (!dev)
+ return NULL;
+ memset(dev, 0, sizeof(*dev));
dev->type = type;
dev->signal = ATM_PHY_SIG_UNKNOWN;
dev->link_rate = ATM_OC3_PCR;
dev->next = NULL;
- spin_lock(&atm_dev_lock);
-
dev->prev = last_dev;
- if (atm_devs) last_dev->next = dev;
- else atm_devs = dev;
+ if (atm_devs)
+ last_dev->next = dev;
+ else
+ atm_devs = dev;
last_dev = dev;
- spin_unlock(&atm_dev_lock);
+
return dev;
}
-
-static void free_atm_dev(struct atm_dev *dev)
+/* Caller must hold atm_dev_lock. */
+static void __free_atm_dev(struct atm_dev *dev)
{
- spin_lock (&atm_dev_lock);
-
- if (dev->prev) dev->prev->next = dev->next;
- else atm_devs = dev->next;
- if (dev->next) dev->next->prev = dev->prev;
- else last_dev = dev->prev;
+ if (dev->prev)
+ dev->prev->next = dev->next;
+ else
+ atm_devs = dev->next;
+ if (dev->next)
+ dev->next->prev = dev->prev;
+ else
+ last_dev = dev->prev;
kfree(dev);
-
- spin_unlock (&atm_dev_lock);
}
-
+/* Caller must hold atm_dev_lock. */
struct atm_dev *atm_find_dev(int number)
{
struct atm_dev *dev;
for (dev = atm_devs; dev; dev = dev->next)
- if (dev->ops && dev->number == number) return dev;
+ if (dev->ops && dev->number == number)
+ return dev;
return NULL;
}
-struct atm_dev *atm_dev_register(const char *type,const struct atmdev_ops *ops,
- int number,atm_dev_flags_t *flags)
+struct atm_dev *atm_dev_register(const char *type, const struct atmdev_ops *ops,
+ int number, atm_dev_flags_t *flags)
{
struct atm_dev *dev;
- dev = alloc_atm_dev(type);
+ spin_lock(&atm_dev_lock);
+
+ dev = __alloc_atm_dev(type);
if (!dev) {
printk(KERN_ERR "atm_dev_register: no space for dev %s\n",
type);
- return NULL;
+ goto done;
}
if (number != -1) {
if (atm_find_dev(number)) {
- free_atm_dev(dev);
- return NULL;
+ __free_atm_dev(dev);
+ dev = NULL;
+ goto done;
}
dev->number = number;
- }
- else {
+ } else {
dev->number = 0;
- while (atm_find_dev(dev->number)) dev->number++;
+ while (atm_find_dev(dev->number))
+ dev->number++;
}
dev->vccs = dev->last = NULL;
dev->dev_data = NULL;
barrier();
dev->ops = ops;
- if (flags) dev->flags = *flags;
- else memset(&dev->flags,0,sizeof(dev->flags));
- memset((void *) &dev->stats,0,sizeof(dev->stats));
+ if (flags)
+ dev->flags = *flags;
+ else
+ memset(&dev->flags, 0, sizeof(dev->flags));
+ memset(&dev->stats, 0, sizeof(dev->stats));
+
#ifdef CONFIG_PROC_FS
- if (ops->proc_read)
+ if (ops->proc_read) {
if (atm_proc_dev_register(dev) < 0) {
printk(KERN_ERR "atm_dev_register: "
- "atm_proc_dev_register failed for dev %s\n",type);
- spin_unlock (&atm_dev_lock);
- free_atm_dev(dev);
- return NULL;
+ "atm_proc_dev_register failed for dev %s\n",
+ type);
+ __free_atm_dev(dev);
+ dev = NULL;
+ goto done;
}
+ }
#endif
- spin_unlock (&atm_dev_lock);
+
+done:
+ spin_unlock(&atm_dev_lock);
return dev;
}
@@ -127,19 +139,22 @@ struct atm_dev *atm_dev_register(const char *type,const struct atmdev_ops *ops,
void atm_dev_deregister(struct atm_dev *dev)
{
#ifdef CONFIG_PROC_FS
- if (dev->ops->proc_read) atm_proc_dev_deregister(dev);
+ if (dev->ops->proc_read)
+ atm_proc_dev_deregister(dev);
#endif
- free_atm_dev(dev);
+ spin_lock(&atm_dev_lock);
+ __free_atm_dev(dev);
+ spin_unlock(&atm_dev_lock);
}
-
void shutdown_atm_dev(struct atm_dev *dev)
{
if (dev->vccs) {
- set_bit(ATM_DF_CLOSE,&dev->flags);
+ set_bit(ATM_DF_CLOSE, &dev->flags);
return;
}
- if (dev->ops->dev_close) dev->ops->dev_close(dev);
+ if (dev->ops->dev_close)
+ dev->ops->dev_close(dev);
atm_dev_deregister(dev);
}
@@ -149,16 +164,18 @@ struct sock *alloc_atm_vcc_sk(int family)
struct atm_vcc *vcc;
sk = sk_alloc(family, GFP_KERNEL, 1, NULL);
- if (!sk) return NULL;
+ if (!sk)
+ return NULL;
vcc = atm_sk(sk) = kmalloc(sizeof(*vcc), GFP_KERNEL);
if (!vcc) {
sk_free(sk);
return NULL;
}
- sock_init_data(NULL,sk);
- memset(vcc,0,sizeof(*vcc));
+ sock_init_data(NULL, sk);
+ memset(vcc, 0, sizeof(*vcc));
vcc->sk = sk;
- if (nodev_vccs) nodev_vccs->prev = vcc;
+ if (nodev_vccs)
+ nodev_vccs->prev = vcc;
vcc->prev = NULL;
vcc->next = nodev_vccs;
nodev_vccs = vcc;
@@ -168,11 +185,16 @@ struct sock *alloc_atm_vcc_sk(int family)
static void unlink_vcc(struct atm_vcc *vcc,struct atm_dev *hold_dev)
{
- if (vcc->prev) vcc->prev->next = vcc->next;
- else if (vcc->dev) vcc->dev->vccs = vcc->next;
- else nodev_vccs = vcc->next;
- if (vcc->next) vcc->next->prev = vcc->prev;
- else if (vcc->dev) vcc->dev->last = vcc->prev;
+ if (vcc->prev)
+ vcc->prev->next = vcc->next;
+ else if (vcc->dev)
+ vcc->dev->vccs = vcc->next;
+ else
+ nodev_vccs = vcc->next;
+ if (vcc->next)
+ vcc->next->prev = vcc->prev;
+ else if (vcc->dev)
+ vcc->dev->last = vcc->prev;
if (vcc->dev && vcc->dev != hold_dev && !vcc->dev->vccs &&
test_bit(ATM_DF_CLOSE,&vcc->dev->flags))
shutdown_atm_dev(vcc->dev);
@@ -185,7 +207,6 @@ void free_atm_vcc_sk(struct sock *sk)
sk_free(sk);
}
-
void bind_vcc(struct atm_vcc *vcc,struct atm_dev *dev)
{
unlink_vcc(vcc,dev);
@@ -193,19 +214,20 @@ void bind_vcc(struct atm_vcc *vcc,struct atm_dev *dev)
if (dev) {
vcc->next = NULL;
vcc->prev = dev->last;
- if (dev->vccs) dev->last->next = vcc;
- else dev->vccs = vcc;
+ if (dev->vccs)
+ dev->last->next = vcc;
+ else
+ dev->vccs = vcc;
dev->last = vcc;
- }
- else {
- if (nodev_vccs) nodev_vccs->prev = vcc;
+ } else {
+ if (nodev_vccs)
+ nodev_vccs->prev = vcc;
vcc->next = nodev_vccs;
vcc->prev = NULL;
nodev_vccs = vcc;
}
}
-
EXPORT_SYMBOL(atm_dev_register);
EXPORT_SYMBOL(atm_dev_deregister);
EXPORT_SYMBOL(atm_find_dev);
diff --git a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c
index 4a950d9ec7b04..8bf321a416980 100644
--- a/net/ax25/af_ax25.c
+++ b/net/ax25/af_ax25.c
@@ -1889,6 +1889,7 @@ module_init(ax25_init);
MODULE_AUTHOR("Jonathan Naylor G4KLX <g4klx@g4klx.demon.co.uk>");
MODULE_DESCRIPTION("The amateur radio AX.25 link layer protocol");
+MODULE_LICENSE("GPL");
static void __exit ax25_exit(void)
{
diff --git a/net/core/neighbour.c b/net/core/neighbour.c
index 47090dc65fd24..e1329d03182a2 100644
--- a/net/core/neighbour.c
+++ b/net/core/neighbour.c
@@ -1239,6 +1239,7 @@ int neigh_add(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
read_lock(&neigh_tbl_lock);
for (tbl=neigh_tables; tbl; tbl = tbl->next) {
int err = 0;
+ int override = 1;
struct neighbour *n;
if (tbl->family != ndm->ndm_family)
@@ -1266,6 +1267,7 @@ int neigh_add(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
if (n) {
if (nlh->nlmsg_flags&NLM_F_EXCL)
err = -EEXIST;
+ override = nlh->nlmsg_flags&NLM_F_REPLACE;
} else if (!(nlh->nlmsg_flags&NLM_F_CREATE))
err = -ENOENT;
else {
@@ -1278,7 +1280,7 @@ int neigh_add(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
if (err == 0) {
err = neigh_update(n, nda[NDA_LLADDR-1] ? RTA_DATA(nda[NDA_LLADDR-1]) : NULL,
ndm->ndm_state,
- nlh->nlmsg_flags&NLM_F_REPLACE, 0);
+ override, 0);
}
if (n)
neigh_release(n);
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index 3bddba5dbd2e2..9c2bc53758802 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -748,7 +748,7 @@ int ___pskb_trim(struct sk_buff *skb, unsigned int len, int realloc)
if (skb_cloned(skb)) {
if (!realloc)
BUG();
- if (!pskb_expand_head(skb, 0, 0, GFP_ATOMIC))
+ if (pskb_expand_head(skb, 0, 0, GFP_ATOMIC))
return -ENOMEM;
}
if (len <= offset) {
diff --git a/net/core/sock.c b/net/core/sock.c
index 9b78c14afa77a..23c251f8922cd 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -108,6 +108,7 @@
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/poll.h>
+#include <linux/tcp.h>
#include <linux/init.h>
#include <asm/uaccess.h>
diff --git a/net/econet/af_econet.c b/net/econet/af_econet.c
index 8aeaff1bb4713..69b9d72b8fe40 100644
--- a/net/econet/af_econet.c
+++ b/net/econet/af_econet.c
@@ -1133,3 +1133,5 @@ static int __init econet_proto_init(void)
module_init(econet_proto_init);
module_exit(econet_proto_exit);
+
+MODULE_LICENSE("GPL");
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
index 8b70a21036be6..f998e347e4320 100644
--- a/net/ipv4/af_inet.c
+++ b/net/ipv4/af_inet.c
@@ -627,7 +627,6 @@ int inet_stream_connect(struct socket *sock, struct sockaddr * uaddr,
int addr_len, int flags)
{
struct sock *sk=sock->sk;
- struct inet_opt *inet = inet_sk(sk);
int err;
long timeo;
@@ -655,13 +654,6 @@ int inet_stream_connect(struct socket *sock, struct sockaddr * uaddr,
if (sk->state != TCP_CLOSE)
goto out;
- err = -EAGAIN;
- if (!inet->num) {
- if (sk->prot->get_port(sk, 0) != 0)
- goto out;
- inet->sport = htons(inet->num);
- }
-
err = sk->prot->connect(sk, uaddr, addr_len);
if (err < 0)
goto out;
diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c
index 9e6a18144cbfb..dd26ec77a82fd 100644
--- a/net/ipv4/arp.c
+++ b/net/ipv4/arp.c
@@ -450,6 +450,32 @@ int arp_bind_neighbour(struct dst_entry *dst)
}
/*
+ * Check if we can use proxy ARP for this path
+ */
+
+static inline int arp_fwd_proxy(struct in_device *in_dev, struct rtable *rt)
+{
+ struct in_device *out_dev;
+ int imi, omi = -1;
+
+ if (!IN_DEV_PROXY_ARP(in_dev))
+ return 0;
+
+ if ((imi = IN_DEV_MEDIUM_ID(in_dev)) == 0)
+ return 1;
+ if (imi == -1)
+ return 0;
+
+ /* place to check for proxy_arp for routes */
+
+ if ((out_dev = in_dev_get(rt->u.dst.dev)) != NULL) {
+ omi = IN_DEV_MEDIUM_ID(out_dev);
+ in_dev_put(out_dev);
+ }
+ return (omi != imi && omi != -1);
+}
+
+/*
* Interface to link layer: send routine and receive handler.
*/
@@ -755,7 +781,7 @@ int arp_process(struct sk_buff *skb)
} else if (IN_DEV_FORWARD(in_dev)) {
if ((rt->rt_flags&RTCF_DNAT) ||
(addr_type == RTN_UNICAST && rt->u.dst.dev != dev &&
- (IN_DEV_PROXY_ARP(in_dev) || pneigh_lookup(&arp_tbl, &tip, dev, 0)))) {
+ (arp_fwd_proxy(in_dev, rt) || pneigh_lookup(&arp_tbl, &tip, dev, 0)))) {
n = neigh_event_ns(&arp_tbl, sha, &sip, dev);
if (n)
neigh_release(n);
diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c
index 8acc73398857e..80d1031f0a721 100644
--- a/net/ipv4/devinet.c
+++ b/net/ipv4/devinet.c
@@ -1032,7 +1032,7 @@ int devinet_sysctl_forward(ctl_table *ctl, int write, struct file * filp,
static struct devinet_sysctl_table
{
struct ctl_table_header *sysctl_header;
- ctl_table devinet_vars[14];
+ ctl_table devinet_vars[15];
ctl_table devinet_dev[2];
ctl_table devinet_conf_dir[2];
ctl_table devinet_proto_dir[2];
@@ -1066,6 +1066,9 @@ static struct devinet_sysctl_table
{NET_IPV4_CONF_PROXY_ARP, "proxy_arp",
&ipv4_devconf.proxy_arp, sizeof(int), 0644, NULL,
&proc_dointvec},
+ {NET_IPV4_CONF_MEDIUM_ID, "medium_id",
+ &ipv4_devconf.medium_id, sizeof(int), 0644, NULL,
+ &proc_dointvec},
{NET_IPV4_CONF_BOOTP_RELAY, "bootp_relay",
&ipv4_devconf.bootp_relay, sizeof(int), 0644, NULL,
&proc_dointvec},
diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c
index c3c48beb995ff..958b6218cf930 100644
--- a/net/ipv4/fib_frontend.c
+++ b/net/ipv4/fib_frontend.c
@@ -579,6 +579,9 @@ static int fib_inetaddr_event(struct notifier_block *this, unsigned long event,
switch (event) {
case NETDEV_UP:
fib_add_ifaddr(ifa);
+#ifdef CONFIG_IP_ROUTE_MULTIPATH
+ fib_sync_up(ifa->ifa_dev->dev);
+#endif
rt_cache_flush(-1);
break;
case NETDEV_DOWN:
diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c
index de25ddc0f658d..c6273f1ad2ec6 100644
--- a/net/ipv4/fib_semantics.c
+++ b/net/ipv4/fib_semantics.c
@@ -56,6 +56,8 @@ int fib_info_cnt;
#ifdef CONFIG_IP_ROUTE_MULTIPATH
+static spinlock_t fib_multipath_lock = SPIN_LOCK_UNLOCKED;
+
#define for_nexthops(fi) { int nhsel; const struct fib_nh * nh; \
for (nhsel=0, nh = (fi)->fib_nh; nhsel < (fi)->fib_nhs; nh++, nhsel++)
@@ -869,8 +871,14 @@ int fib_sync_down(u32 local, struct net_device *dev, int force)
nh->nh_scope != scope) {
nh->nh_flags |= RTNH_F_DEAD;
#ifdef CONFIG_IP_ROUTE_MULTIPATH
+ spin_lock_bh(&fib_multipath_lock);
fi->fib_power -= nh->nh_power;
nh->nh_power = 0;
+ spin_unlock_bh(&fib_multipath_lock);
+ if (force && nh->nh_dev) {
+ dev_put(nh->nh_dev);
+ nh->nh_dev = NULL;
+ }
#endif
dead++;
}
@@ -906,13 +914,19 @@ int fib_sync_up(struct net_device *dev)
alive++;
continue;
}
+ if (nh->nh_dev == NULL && nh->nh_oif == dev->ifindex) {
+ dev_hold(dev);
+ nh->nh_dev = dev;
+ }
if (nh->nh_dev == NULL || !(nh->nh_dev->flags&IFF_UP))
continue;
if (nh->nh_dev != dev || __in_dev_get(dev) == NULL)
continue;
alive++;
+ spin_lock_bh(&fib_multipath_lock);
nh->nh_power = 0;
nh->nh_flags &= ~RTNH_F_DEAD;
+ spin_unlock_bh(&fib_multipath_lock);
} endfor_nexthops(fi)
if (alive > 0) {
@@ -933,6 +947,7 @@ void fib_select_multipath(const struct rt_key *key, struct fib_result *res)
struct fib_info *fi = res->fi;
int w;
+ spin_lock_bh(&fib_multipath_lock);
if (fi->fib_power <= 0) {
int power = 0;
change_nexthops(fi) {
@@ -942,12 +957,12 @@ void fib_select_multipath(const struct rt_key *key, struct fib_result *res)
}
} endfor_nexthops(fi);
fi->fib_power = power;
-#if 1
if (power <= 0) {
- printk(KERN_CRIT "impossible 777\n");
+ spin_unlock_bh(&fib_multipath_lock);
+ /* Race condition: route has just become dead. */
+ res->nh_sel = 0;
return;
}
-#endif
}
@@ -963,15 +978,15 @@ void fib_select_multipath(const struct rt_key *key, struct fib_result *res)
nh->nh_power--;
fi->fib_power--;
res->nh_sel = nhsel;
+ spin_unlock_bh(&fib_multipath_lock);
return;
}
}
} endfor_nexthops(fi);
-#if 1
- printk(KERN_CRIT "impossible 888\n");
-#endif
- return;
+ /* Race condition: route has just become dead. */
+ res->nh_sel = 0;
+ spin_unlock_bh(&fib_multipath_lock);
}
#endif
diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c
index ec1b8e6c091d4..a5b7dbb0d0e1c 100644
--- a/net/ipv4/icmp.c
+++ b/net/ipv4/icmp.c
@@ -139,6 +139,8 @@ struct icmp_err icmp_err_convert[] = {
{ EHOSTUNREACH, 1 } /* ICMP_PREC_CUTOFF */
};
+extern int sysctl_ip_default_ttl;
+
/* Control parameters for ECHO replies. */
int sysctl_icmp_echo_ignore_all;
int sysctl_icmp_echo_ignore_broadcasts;
@@ -354,6 +356,7 @@ static void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb)
icmp_out_count(icmp_param->data.icmph.type);
inet->tos = skb->nh.iph->tos;
+ inet->ttl = sysctl_ip_default_ttl;
daddr = ipc.addr = rt->rt_src;
ipc.opt = NULL;
if (icmp_param->replyopts.optlen) {
@@ -498,6 +501,7 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, u32 info)
icmp_param.offset=skb_in->nh.raw - skb_in->data;
icmp_out_count(icmp_param.data.icmph.type);
inet_sk(icmp_socket->sk)->tos = tos;
+ inet_sk(icmp_socket->sk)->ttl = sysctl_ip_default_ttl;
ipc.addr = iph->saddr;
ipc.opt = &icmp_param.replyopts;
if (icmp_param.replyopts.srr) {
@@ -876,7 +880,7 @@ static void icmp_discard(struct sk_buff *skb)
int icmp_rcv(struct sk_buff *skb)
{
- struct icmphdr *icmph = skb->h.icmph;
+ struct icmphdr *icmph;
struct rtable *rt = (struct rtable*)skb->dst;
ICMP_INC_STATS_BH(IcmpInMsgs);
@@ -895,6 +899,8 @@ int icmp_rcv(struct sk_buff *skb)
if (!pskb_pull(skb, sizeof(struct icmphdr)))
goto error;
+ icmph = skb->h.icmph;
+
/*
* 18 is the highest 'known' ICMP type. Anything else is a mystery
*
diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c
index 899bbb02cd54e..c1056f760e9da 100644
--- a/net/ipv4/ip_gre.c
+++ b/net/ipv4/ip_gre.c
@@ -760,7 +760,10 @@ static int ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
}
df = tiph->frag_off;
- mtu = rt->u.dst.pmtu - tunnel->hlen;
+ if (df)
+ mtu = rt->u.dst.pmtu - tunnel->hlen;
+ else
+ mtu = skb->dst ? skb->dst->pmtu : dev->mtu;
if (skb->protocol == __constant_htons(ETH_P_IP)) {
if (skb->dst && mtu < skb->dst->pmtu && mtu >= 68)
diff --git a/net/ipv4/ip_input.c b/net/ipv4/ip_input.c
index 3f93680cc5fe8..85f756cdd6302 100644
--- a/net/ipv4/ip_input.c
+++ b/net/ipv4/ip_input.c
@@ -224,8 +224,6 @@ static inline int ip_local_deliver_finish(struct sk_buff *skb)
nf_debug_ip_local_deliver(skb);
#endif /*CONFIG_NETFILTER_DEBUG*/
- if (!pskb_may_pull(skb, ihl))
- goto out;
__skb_pull(skb, ihl);
#ifdef CONFIG_NETFILTER
@@ -279,7 +277,6 @@ static inline int ip_local_deliver_finish(struct sk_buff *skb)
sock_put(raw_sk);
} else if (!flag) { /* Free and report errors */
icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PROT_UNREACH, 0);
-out:
kfree_skb(skb);
}
}
@@ -346,7 +343,6 @@ static inline int ip_rcv_finish(struct sk_buff *skb)
goto drop;
iph = skb->nh.iph;
- skb->ip_summed = 0;
if (ip_options_compile(NULL, skb))
goto inhdr_error;
diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c
index 87ad2a5a65c61..82634df7c6fe7 100644
--- a/net/ipv4/ipip.c
+++ b/net/ipv4/ipip.c
@@ -572,7 +572,11 @@ static int ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
goto tx_error;
}
- mtu = rt->u.dst.pmtu - sizeof(struct iphdr);
+ if (tiph->frag_off)
+ mtu = rt->u.dst.pmtu - sizeof(struct iphdr);
+ else
+ mtu = skb->dst ? skb->dst->pmtu : dev->mtu;
+
if (mtu < 68) {
tunnel->stat.collisions++;
ip_rt_put(rt);
diff --git a/net/ipv4/netfilter/Config.help b/net/ipv4/netfilter/Config.help
index 5341465c4a2c5..8d1c9e23ffeb3 100644
--- a/net/ipv4/netfilter/Config.help
+++ b/net/ipv4/netfilter/Config.help
@@ -160,6 +160,17 @@ CONFIG_IP_NF_NAT
If you want to compile it as a module, say M here and read
<file:Documentation/modules.txt>. If unsure, say `N'.
+CONFIG_IP_NF_NAT_LOCAL
+ This option enables support for NAT of locally originated connections.
+ Enable this if you need to use destination NAT on connections
+ originating from local processes on the nat box itself.
+
+ Please note that you will need a recent version (>= 1.2.6a)
+ of the iptables userspace program in order to use this feature.
+ See http://www.iptables.org/ for download instructions.
+
+ If unsure, say 'N'.
+
CONFIG_IP_NF_TARGET_MASQUERADE
Masquerading is a special case of NAT: all outgoing connections are
changed to seem to come from a particular interface's address, and
diff --git a/net/ipv4/netfilter/Config.in b/net/ipv4/netfilter/Config.in
index 7f250e4313188..7bf12c2a0de79 100644
--- a/net/ipv4/netfilter/Config.in
+++ b/net/ipv4/netfilter/Config.in
@@ -47,7 +47,7 @@ if [ "$CONFIG_IP_NF_IPTABLES" != "n" ]; then
define_bool CONFIG_IP_NF_NAT_NEEDED y
dep_tristate ' MASQUERADE target support' CONFIG_IP_NF_TARGET_MASQUERADE $CONFIG_IP_NF_NAT
dep_tristate ' REDIRECT target support' CONFIG_IP_NF_TARGET_REDIRECT $CONFIG_IP_NF_NAT
- bool ' NAT of local connections' CONFIG_IP_NF_NAT_LOCAL
+ bool ' NAT of local connections (READ HELP)' CONFIG_IP_NF_NAT_LOCAL
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
dep_tristate ' Basic SNMP-ALG support (EXPERIMENTAL)' CONFIG_IP_NF_NAT_SNMP_BASIC $CONFIG_IP_NF_NAT
fi
diff --git a/net/ipv4/netfilter/Makefile b/net/ipv4/netfilter/Makefile
index 7e1bd4511532f..90c33ec641303 100644
--- a/net/ipv4/netfilter/Makefile
+++ b/net/ipv4/netfilter/Makefile
@@ -9,18 +9,18 @@
O_TARGET := netfilter.o
-export-objs = ip_conntrack_standalone.o ip_conntrack_ftp.o ip_fw_compat.o ip_nat_standalone.o ip_tables.o arp_tables.o
+export-objs = ip_conntrack_standalone.o ip_fw_compat.o ip_nat_standalone.o ip_tables.o arp_tables.o
# Multipart objects.
list-multi := ip_conntrack.o iptable_nat.o ipfwadm.o ipchains.o
# objects for the conntrack and NAT core (used by standalone and backw. compat)
ip_nf_conntrack-objs := ip_conntrack_core.o ip_conntrack_proto_generic.o ip_conntrack_proto_tcp.o ip_conntrack_proto_udp.o ip_conntrack_proto_icmp.o
-ip_nf_nat-objs := ip_nat_core.o ip_nat_proto_unknown.o ip_nat_proto_tcp.o ip_nat_proto_udp.o ip_nat_proto_icmp.o
+ip_nf_nat-objs := ip_nat_core.o ip_nat_helper.o ip_nat_proto_unknown.o ip_nat_proto_tcp.o ip_nat_proto_udp.o ip_nat_proto_icmp.o
# objects for the standalone - connection tracking / NAT
ip_conntrack-objs := ip_conntrack_standalone.o $(ip_nf_conntrack-objs)
-iptable_nat-objs := ip_nat_standalone.o ip_nat_rule.o ip_nat_helper.o $(ip_nf_nat-objs)
+iptable_nat-objs := ip_nat_standalone.o ip_nat_rule.o $(ip_nf_nat-objs)
# objects for backwards compatibility mode
ip_nf_compat-objs := ip_fw_compat.o ip_fw_compat_redir.o ip_fw_compat_masq.o $(ip_nf_conntrack-objs) $(ip_nf_nat-objs)
@@ -33,7 +33,14 @@ obj-$(CONFIG_IP_NF_CONNTRACK) += ip_conntrack.o
# connection tracking helpers
obj-$(CONFIG_IP_NF_FTP) += ip_conntrack_ftp.o
+ifdef CONFIG_IP_NF_NAT_FTP
+ export-objs += ip_conntrack_ftp.o
+endif
+
obj-$(CONFIG_IP_NF_IRC) += ip_conntrack_irc.o
+ifdef CONFIG_IP_NF_NAT_IRC
+ export-objs += ip_conntrack_irc.o
+endif
# NAT helpers
obj-$(CONFIG_IP_NF_NAT_FTP) += ip_nat_ftp.o
diff --git a/net/ipv4/netfilter/ip_conntrack_core.c b/net/ipv4/netfilter/ip_conntrack_core.c
index 41c893ed78bdd..eeb5419853ff9 100644
--- a/net/ipv4/netfilter/ip_conntrack_core.c
+++ b/net/ipv4/netfilter/ip_conntrack_core.c
@@ -3,7 +3,12 @@
extension. */
/* (c) 1999 Paul `Rusty' Russell. Licenced under the GNU General
- Public Licence. */
+ * Public Licence.
+ *
+ * 23 Apr 2001: Harald Welte <laforge@gnumonks.org>
+ * - new API and handling of conntrack/nat helpers
+ * - now capable of multiple expectations for one master
+ * */
#ifdef MODULE
#define __NO_VERSION__
@@ -38,6 +43,8 @@
#include <linux/netfilter_ipv4/ip_conntrack_core.h>
#include <linux/netfilter_ipv4/listhelp.h>
+#define IP_CONNTRACK_VERSION "2.0"
+
#if 0
#define DEBUGP printk
#else
@@ -45,6 +52,7 @@
#endif
DECLARE_RWLOCK(ip_conntrack_lock);
+DECLARE_RWLOCK(ip_conntrack_expect_tuple_lock);
void (*ip_conntrack_destroyed)(struct ip_conntrack *conntrack) = NULL;
LIST_HEAD(expect_list);
@@ -77,7 +85,7 @@ struct ip_conntrack_protocol *__find_proto(u_int8_t protocol)
return p;
}
-struct ip_conntrack_protocol *find_proto(u_int8_t protocol)
+struct ip_conntrack_protocol *ip_ct_find_proto(u_int8_t protocol)
{
struct ip_conntrack_protocol *p;
@@ -151,9 +159,58 @@ invert_tuple(struct ip_conntrack_tuple *inverse,
return protocol->invert_tuple(inverse, orig);
}
+/* remove one specific expectation from all lists and free it */
+static void unexpect_related(struct ip_conntrack_expect *expect)
+{
+ MUST_BE_WRITE_LOCKED(&ip_conntrack_lock);
+ DEBUGP("unexpect_related(%p)\n", expect);
+ /* delete from global and local lists */
+ list_del(&expect->list);
+ list_del(&expect->expected_list);
+ if (!expect->sibling)
+ expect->expectant->expecting--;
+ kfree(expect);
+}
+
+/* delete all expectations for this conntrack */
+static void destroy_expectations(struct ip_conntrack *ct)
+{
+ struct list_head *exp_entry, *next;
+ struct ip_conntrack_expect *exp;
+
+ DEBUGP("destroy_expectations(%p)\n", ct);
+
+ for (exp_entry = ct->sibling_list.next;
+ exp_entry != &ct->sibling_list; exp_entry = next) {
+ next = exp_entry->next;
+ exp = list_entry(exp_entry, struct ip_conntrack_expect,
+ expected_list);
+
+ /* we skip established expectations, as we want to delete
+ * the un-established ones only */
+ if (exp->sibling) {
+ DEBUGP("destroy_expectations: skipping established %p of %p\n", exp->sibling, ct);
+ continue;
+ }
+
+ IP_NF_ASSERT(list_inlist(&expect_list, exp));
+ IP_NF_ASSERT(exp->expectant == ct);
+
+ if (exp->expectant->helper->timeout
+ && ! del_timer(&exp->timeout)) {
+ DEBUGP("destroy_expectations: skipping dying expectation %p of %p\n", exp, ct);
+ continue;
+ }
+
+ /* delete expectation from global and private lists */
+ unexpect_related(exp);
+ }
+}
+
static void
clean_from_lists(struct ip_conntrack *ct)
{
+ DEBUGP("clean_from_lists(%p)\n", ct);
MUST_BE_WRITE_LOCKED(&ip_conntrack_lock);
/* Remove from both hash lists: must not NULL out next ptrs,
otherwise we'll look unconfirmed. Fortunately, LIST_DELETE
@@ -164,27 +221,45 @@ clean_from_lists(struct ip_conntrack *ct)
LIST_DELETE(&ip_conntrack_hash
[hash_conntrack(&ct->tuplehash[IP_CT_DIR_REPLY].tuple)],
&ct->tuplehash[IP_CT_DIR_REPLY]);
- /* If our expected is in the list, take it out. */
- if (ct->expected.expectant) {
- IP_NF_ASSERT(list_inlist(&expect_list, &ct->expected));
- IP_NF_ASSERT(ct->expected.expectant == ct);
- LIST_DELETE(&expect_list, &ct->expected);
- }
+
+ /* Destroy all un-established, pending expectations */
+ destroy_expectations(ct);
}
static void
destroy_conntrack(struct nf_conntrack *nfct)
{
struct ip_conntrack *ct = (struct ip_conntrack *)nfct;
+ struct ip_conntrack_protocol *proto;
+ DEBUGP("destroy_conntrack(%p)\n", ct);
IP_NF_ASSERT(atomic_read(&nfct->use) == 0);
IP_NF_ASSERT(!timer_pending(&ct->timeout));
- if (ct->master.master)
- nf_conntrack_put(&ct->master);
+ if (ct->master && master_ct(ct))
+ ip_conntrack_put(master_ct(ct));
+
+ /* To make sure we don't get any weird locking issues here:
+ * destroy_conntrack() MUST NOT be called with a write lock
+ * to ip_conntrack_lock!!! -HW */
+ proto = ip_ct_find_proto(ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.protonum);
+ if (proto && proto->destroy)
+ proto->destroy(ct);
if (ip_conntrack_destroyed)
ip_conntrack_destroyed(ct);
+
+ WRITE_LOCK(&ip_conntrack_lock);
+ /* Delete our master expectation from the local list
+ * and destroy it, if we've been expected */
+ if (ct->master) {
+ list_del(&ct->master->expected_list);
+ kfree(ct->master);
+ }
+ WRITE_UNLOCK(&ip_conntrack_lock);
+
+
+ DEBUGP("destroy_conntrack: returning ct=%p to slab\n", ct);
kmem_cache_free(ip_conntrack_cachep, ct);
atomic_dec(&ip_conntrack_count);
}
@@ -382,7 +457,7 @@ icmp_error_track(struct sk_buff *skb,
return NULL;
}
- innerproto = find_proto(inner->protocol);
+ innerproto = ip_ct_find_proto(inner->protocol);
/* Are they talking about one of our connections? */
if (inner->ihl * 4 + 8 > datalen
|| !get_tuple(inner, datalen, &origtuple, innerproto)) {
@@ -462,10 +537,18 @@ static inline int helper_cmp(const struct ip_conntrack_helper *i,
return ip_ct_tuple_mask_cmp(rtuple, &i->tuple, &i->mask);
}
+struct ip_conntrack_helper *ip_ct_find_helper(const struct ip_conntrack_tuple *tuple)
+{
+ return LIST_FIND(&helpers, helper_cmp,
+ struct ip_conntrack_helper *,
+ tuple);
+}
+
/* Compare parts depending on mask. */
static inline int expect_cmp(const struct ip_conntrack_expect *i,
const struct ip_conntrack_tuple *tuple)
{
+ MUST_BE_READ_LOCKED(&ip_conntrack_expect_tuple_lock);
return ip_ct_tuple_mask_cmp(tuple, &i->tuple, &i->mask);
}
@@ -514,7 +597,7 @@ init_conntrack(const struct ip_conntrack_tuple *tuple,
return ERR_PTR(-ENOMEM);
}
- memset(conntrack, 0, sizeof(struct ip_conntrack));
+ memset(conntrack, 0, sizeof(*conntrack));
atomic_set(&conntrack->ct_general.use, 1);
conntrack->ct_general.destroy = destroy_conntrack;
conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple = *tuple;
@@ -533,31 +616,44 @@ init_conntrack(const struct ip_conntrack_tuple *tuple,
conntrack->timeout.data = (unsigned long)conntrack;
conntrack->timeout.function = death_by_timeout;
+ INIT_LIST_HEAD(&conntrack->sibling_list);
+
/* Mark clearly that it's not in the hash table. */
conntrack->tuplehash[IP_CT_DIR_ORIGINAL].list.next = NULL;
- /* Write lock required for deletion of expected. Without
- this, a read-lock would do. */
WRITE_LOCK(&ip_conntrack_lock);
- conntrack->helper = LIST_FIND(&helpers, helper_cmp,
- struct ip_conntrack_helper *,
- &repl_tuple);
/* Need finding and deleting of expected ONLY if we win race */
+ READ_LOCK(&ip_conntrack_expect_tuple_lock);
expected = LIST_FIND(&expect_list, expect_cmp,
struct ip_conntrack_expect *, tuple);
+ READ_UNLOCK(&ip_conntrack_expect_tuple_lock);
+
+ /* Look up the conntrack helper for master connections only */
+ if (!expected)
+ conntrack->helper = ip_ct_find_helper(&repl_tuple);
+
+ /* If the expectation is dying, then this is a looser. */
+ if (expected
+ && expected->expectant->helper->timeout
+ && ! del_timer(&expected->timeout))
+ expected = NULL;
+
/* If master is not in hash table yet (ie. packet hasn't left
this machine yet), how can other end know about expected?
Hence these are not the droids you are looking for (if
master ct never got confirmed, we'd hold a reference to it
and weird things would happen to future packets). */
if (expected && is_confirmed(expected->expectant)) {
+ DEBUGP("conntrack: expectation arrives ct=%p exp=%p\n",
+ conntrack, expected);
/* Welcome, Mr. Bond. We've been expecting you... */
+ IP_NF_ASSERT(master_ct(conntrack));
conntrack->status = IPS_EXPECTED;
- conntrack->master.master = &expected->expectant->ct_general;
- IP_NF_ASSERT(conntrack->master.master);
+ conntrack->master = expected;
+ expected->sibling = conntrack;
LIST_DELETE(&expect_list, expected);
- expected->expectant = NULL;
- nf_conntrack_get(&conntrack->master);
+ expected->expectant->expecting--;
+ nf_conntrack_get(&master_ct(conntrack)->infos[0]);
}
atomic_inc(&ip_conntrack_count);
WRITE_UNLOCK(&ip_conntrack_lock);
@@ -662,7 +758,7 @@ unsigned int ip_conntrack_in(unsigned int hooknum,
return NF_STOLEN;
}
- proto = find_proto((*pskb)->nh.iph->protocol);
+ proto = ip_ct_find_proto((*pskb)->nh.iph->protocol);
/* It may be an icmp error... */
if ((*pskb)->nh.iph->protocol == IPPROTO_ICMP
@@ -706,66 +802,210 @@ unsigned int ip_conntrack_in(unsigned int hooknum,
int invert_tuplepr(struct ip_conntrack_tuple *inverse,
const struct ip_conntrack_tuple *orig)
{
- return invert_tuple(inverse, orig, find_proto(orig->dst.protonum));
+ return invert_tuple(inverse, orig, ip_ct_find_proto(orig->dst.protonum));
}
-static void unexpect_related(struct ip_conntrack *related_to)
+static inline int resent_expect(const struct ip_conntrack_expect *i,
+ const struct ip_conntrack_tuple *tuple,
+ const struct ip_conntrack_tuple *mask)
{
- MUST_BE_WRITE_LOCKED(&ip_conntrack_lock);
- list_del(&related_to->expected.list);
- related_to->expected.expectant = NULL;
+ DEBUGP("resent_expect\n");
+ DEBUGP(" tuple: "); DUMP_TUPLE(&i->tuple);
+ DEBUGP("ct_tuple: "); DUMP_TUPLE(&i->ct_tuple);
+ DEBUGP("test tuple: "); DUMP_TUPLE(tuple);
+ return (((i->ct_tuple.dst.protonum == 0 && ip_ct_tuple_equal(&i->tuple, tuple))
+ || (i->ct_tuple.dst.protonum && ip_ct_tuple_equal(&i->ct_tuple, tuple)))
+ && ip_ct_tuple_equal(&i->mask, mask));
}
/* Would two expected things clash? */
static inline int expect_clash(const struct ip_conntrack_expect *i,
- const struct ip_conntrack_expect *new)
+ const struct ip_conntrack_tuple *tuple,
+ const struct ip_conntrack_tuple *mask)
{
/* Part covered by intersection of masks must be unequal,
otherwise they clash */
struct ip_conntrack_tuple intersect_mask
- = { { i->mask.src.ip & new->mask.src.ip,
- { i->mask.src.u.all & new->mask.src.u.all } },
- { i->mask.dst.ip & new->mask.dst.ip,
- { i->mask.dst.u.all & new->mask.dst.u.all },
- i->mask.dst.protonum & new->mask.dst.protonum } };
+ = { { i->mask.src.ip & mask->src.ip,
+ { i->mask.src.u.all & mask->src.u.all } },
+ { i->mask.dst.ip & mask->dst.ip,
+ { i->mask.dst.u.all & mask->dst.u.all },
+ i->mask.dst.protonum & mask->dst.protonum } };
- return ip_ct_tuple_mask_cmp(&i->tuple, &new->tuple, &intersect_mask);
+ return ip_ct_tuple_mask_cmp(&i->tuple, tuple, &intersect_mask);
}
-/* Add a related connection. */
-int ip_conntrack_expect_related(struct ip_conntrack *related_to,
- const struct ip_conntrack_tuple *tuple,
- const struct ip_conntrack_tuple *mask,
- int (*expectfn)(struct ip_conntrack *))
+void ip_conntrack_unexpect_related(struct ip_conntrack_expect *expect)
{
WRITE_LOCK(&ip_conntrack_lock);
- if (related_to->expected.expectant)
- unexpect_related(related_to);
+ unexpect_related(expect);
+ WRITE_UNLOCK(&ip_conntrack_lock);
+}
+
+static void expectation_timed_out(unsigned long ul_expect)
+{
+ struct ip_conntrack_expect *expect = (void *) ul_expect;
- related_to->expected.tuple = *tuple;
- related_to->expected.mask = *mask;
- related_to->expected.expectfn = expectfn;
+ DEBUGP("expectation %p timed out\n", expect);
+ ip_conntrack_unexpect_related(expect);
+}
+
+/* Add a related connection. */
+int ip_conntrack_expect_related(struct ip_conntrack *related_to,
+ struct ip_conntrack_expect *expect)
+{
+ struct ip_conntrack_expect *new;
+ int ret = 0;
- if (LIST_FIND(&expect_list, expect_clash,
- struct ip_conntrack_expect *, &related_to->expected)) {
+ WRITE_LOCK(&ip_conntrack_lock);
+ /* Because of the write lock, no reader can walk the lists,
+ * so there is no need to use the tuple lock too */
+
+ DEBUGP("ip_conntrack_expect_related %p\n", related_to);
+ DEBUGP("tuple: "); DUMP_TUPLE(&expect->tuple);
+ DEBUGP("mask: "); DUMP_TUPLE(&expect->mask);
+
+ new = LIST_FIND(&expect_list, resent_expect,
+ struct ip_conntrack_expect *, &expect->tuple, &expect->mask);
+ if (new) {
+ /* Helper private data may contain offsets but no pointers
+ pointing into the payload - otherwise we should have to copy
+ the data filled out by the helper over the old one */
+ DEBUGP("expect_related: resent packet\n");
+ if (related_to->helper->timeout) {
+ /* Refresh timer, if possible... */
+ if (del_timer(&new->timeout)) {
+ new->timeout.expires = jiffies + related_to->helper->timeout * HZ;
+ add_timer(&new->timeout);
+ WRITE_UNLOCK(&ip_conntrack_lock);
+ return -EEXIST;
+ }
+ /* ... otherwise expectation is dying. Fall over and create a new one. */
+ new = NULL;
+ } else {
+ WRITE_UNLOCK(&ip_conntrack_lock);
+ return -EEXIST;
+ }
+ } else if (related_to->helper->max_expected
+ && related_to->expecting >= related_to->helper->max_expected) {
+ if (net_ratelimit())
+ printk(KERN_WARNING
+ "ip_conntrack: max number of expected connections %i of %s reached for %u.%u.%u.%u->%u.%u.%u.%u%s\n",
+ related_to->helper->max_expected,
+ related_to->helper->name,
+ NIPQUAD(related_to->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip),
+ NIPQUAD(related_to->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip),
+ related_to->helper->flags & IP_CT_HELPER_F_REUSE_EXPECT ?
+ ", reusing" : "");
+ if (related_to->helper->flags & IP_CT_HELPER_F_REUSE_EXPECT) {
+ struct list_head *cur_item;
+
+ /* Let's choose the the oldest expectation to overwrite */
+ list_for_each(cur_item, &related_to->sibling_list) {
+ new = list_entry(cur_item, struct ip_conntrack_expect,
+ expected_list);
+ if (new->sibling == NULL)
+ break;
+ }
+ IP_NF_ASSERT(new);
+ if (related_to->helper->timeout
+ && !del_timer(&new->timeout)) {
+ /* Expectation is dying. Fall over and create a new one */
+ new = NULL;
+ } else {
+ list_del(&new->list);
+ list_del(&new->expected_list);
+ related_to->expecting--;
+ ret = -EPERM;
+ }
+ } else {
+ WRITE_UNLOCK(&ip_conntrack_lock);
+ return -EPERM;
+ }
+ } else if (LIST_FIND(&expect_list, expect_clash,
+ struct ip_conntrack_expect *, &expect->tuple, &expect->mask)) {
WRITE_UNLOCK(&ip_conntrack_lock);
+ DEBUGP("expect_related: busy!\n");
return -EBUSY;
}
+
+ if (!new) {
+ new = (struct ip_conntrack_expect *)
+ kmalloc(sizeof(*expect), GFP_ATOMIC);
+ if (!new) {
+ WRITE_UNLOCK(&ip_conntrack_lock);
+ DEBUGP("expect_relaed: OOM allocating expect\n");
+ return -ENOMEM;
+ }
+ }
+
+ /* Zero out the new structure, then fill out it with the data */
+ DEBUGP("new expectation %p of conntrack %p\n", new, related_to);
+ memset(new, 0, sizeof(*expect));
+ INIT_LIST_HEAD(&new->list);
+ INIT_LIST_HEAD(&new->expected_list);
+ memcpy(new, expect, sizeof(*expect));
+ new->expectant = related_to;
+ new->sibling = NULL;
+
+ /* add to expected list for this connection */
+ list_add(&new->expected_list, &related_to->sibling_list);
+ /* add to global list of expectations */
+ list_prepend(&expect_list, &new->list);
+ /* add and start timer if required */
+ if (related_to->helper->timeout) {
+ init_timer(&new->timeout);
+ new->timeout.data = (unsigned long)new;
+ new->timeout.function = expectation_timed_out;
+ new->timeout.expires = jiffies + related_to->helper->timeout * HZ;
+ add_timer(&new->timeout);
+ }
+ related_to->expecting++;
- list_prepend(&expect_list, &related_to->expected);
- related_to->expected.expectant = related_to;
WRITE_UNLOCK(&ip_conntrack_lock);
- return 0;
+ return ret;
}
-void ip_conntrack_unexpect_related(struct ip_conntrack *related_to)
+/* Change tuple in an existing expectation */
+int ip_conntrack_change_expect(struct ip_conntrack_expect *expect,
+ struct ip_conntrack_tuple *newtuple)
{
- WRITE_LOCK(&ip_conntrack_lock);
- unexpect_related(related_to);
- WRITE_UNLOCK(&ip_conntrack_lock);
-}
+ MUST_BE_READ_LOCKED(&ip_conntrack_lock);
+
+ DEBUGP("change_expect:\n");
+ DEBUGP("exp tuple: "); DUMP_TUPLE(&expect->tuple);
+ DEBUGP("exp mask: "); DUMP_TUPLE(&expect->mask);
+ DEBUGP("newtuple: "); DUMP_TUPLE(newtuple);
+ if (expect->ct_tuple.dst.protonum == 0) {
+ /* Never seen before */
+ DEBUGP("change expect: never seen before\n");
+ if (!ip_ct_tuple_equal(&expect->tuple, newtuple)
+ && LIST_FIND(&expect_list, expect_clash,
+ struct ip_conntrack_expect *, newtuple, &expect->mask)) {
+ /* Force NAT to find an unused tuple */
+ return -1;
+ } else {
+ WRITE_LOCK(&ip_conntrack_expect_tuple_lock);
+ memcpy(&expect->ct_tuple, &expect->tuple, sizeof(expect->tuple));
+ memcpy(&expect->tuple, newtuple, sizeof(expect->tuple));
+ WRITE_UNLOCK(&ip_conntrack_expect_tuple_lock);
+ return 0;
+ }
+ } else {
+ /* Resent packet */
+ DEBUGP("change expect: resent packet\n");
+ if (ip_ct_tuple_equal(&expect->tuple, newtuple)) {
+ return 0;
+ } else {
+ /* Force NAT to choose again the same port */
+ return -1;
+ }
+ }
+ return -1;
+}
+
/* Alter reply tuple (maybe alter helper). If it's already taken,
return 0 and don't do alteration. */
int ip_conntrack_alter_reply(struct ip_conntrack *conntrack,
@@ -783,10 +1023,12 @@ int ip_conntrack_alter_reply(struct ip_conntrack *conntrack,
DUMP_TUPLE(newreply);
conntrack->tuplehash[IP_CT_DIR_REPLY].tuple = *newreply;
- conntrack->helper = LIST_FIND(&helpers, helper_cmp,
- struct ip_conntrack_helper *,
- newreply);
+ if (!conntrack->master)
+ conntrack->helper = LIST_FIND(&helpers, helper_cmp,
+ struct ip_conntrack_helper *,
+ newreply);
WRITE_UNLOCK(&ip_conntrack_lock);
+
return 1;
}
@@ -805,14 +1047,10 @@ static inline int unhelp(struct ip_conntrack_tuple_hash *i,
const struct ip_conntrack_helper *me)
{
if (i->ctrack->helper == me) {
- i->ctrack->helper = NULL;
/* Get rid of any expected. */
- if (i->ctrack->expected.expectant) {
- IP_NF_ASSERT(i->ctrack->expected.expectant
- == i->ctrack);
- LIST_DELETE(&expect_list, &i->ctrack->expected);
- i->ctrack->expected.expectant = NULL;
- }
+ destroy_expectations(i->ctrack);
+ /* And *then* set helper to NULL */
+ i->ctrack->helper = NULL;
}
return 0;
}
@@ -1096,8 +1334,10 @@ int __init ip_conntrack_init(void)
}
ip_conntrack_max = 8 * ip_conntrack_htable_size;
- printk("ip_conntrack (%u buckets, %d max)\n",
- ip_conntrack_htable_size, ip_conntrack_max);
+ printk("ip_conntrack version %s (%u buckets, %d max)"
+ " - %d bytes per conntrack\n", IP_CONNTRACK_VERSION,
+ ip_conntrack_htable_size, ip_conntrack_max,
+ sizeof(struct ip_conntrack));
ret = nf_register_sockopt(&so_getorigdst);
if (ret != 0)
diff --git a/net/ipv4/netfilter/ip_conntrack_ftp.c b/net/ipv4/netfilter/ip_conntrack_ftp.c
index 3de1af16dd75b..7dba1565d0631 100644
--- a/net/ipv4/netfilter/ip_conntrack_ftp.c
+++ b/net/ipv4/netfilter/ip_conntrack_ftp.c
@@ -1,4 +1,5 @@
/* FTP extension for IP connection tracking. */
+#include <linux/config.h>
#include <linux/module.h>
#include <linux/netfilter.h>
#include <linux/ip.h>
@@ -242,8 +243,10 @@ static int help(const struct iphdr *iph, size_t len,
u_int32_t array[6] = { 0 };
int dir = CTINFO2DIR(ctinfo);
unsigned int matchlen, matchoff;
- struct ip_conntrack_tuple t, mask;
- struct ip_ct_ftp *info = &ct->help.ct_ftp_info;
+ struct ip_ct_ftp_master *ct_ftp_info = &ct->help.ct_ftp_info;
+ struct ip_conntrack_expect expect, *exp = &expect;
+ struct ip_ct_ftp_expect *exp_ftp_info = &exp->help.exp_ftp_info;
+
unsigned int i;
int found = 0;
@@ -271,8 +274,8 @@ static int help(const struct iphdr *iph, size_t len,
}
LOCK_BH(&ip_ftp_lock);
- old_seq_aft_nl_set = info->seq_aft_nl_set[dir];
- old_seq_aft_nl = info->seq_aft_nl[dir];
+ old_seq_aft_nl_set = ct_ftp_info->seq_aft_nl_set[dir];
+ old_seq_aft_nl = ct_ftp_info->seq_aft_nl[dir];
DEBUGP("conntrack_ftp: datalen %u\n", datalen);
if ((datalen > 0) && (data[datalen-1] == '\n')) {
@@ -281,8 +284,9 @@ static int help(const struct iphdr *iph, size_t len,
|| after(ntohl(tcph->seq) + datalen, old_seq_aft_nl)) {
DEBUGP("conntrack_ftp: updating nl to %u\n",
ntohl(tcph->seq) + datalen);
- info->seq_aft_nl[dir] = ntohl(tcph->seq) + datalen;
- info->seq_aft_nl_set[dir] = 1;
+ ct_ftp_info->seq_aft_nl[dir] =
+ ntohl(tcph->seq) + datalen;
+ ct_ftp_info->seq_aft_nl_set[dir] = 1;
}
}
UNLOCK_BH(&ip_ftp_lock);
@@ -330,16 +334,17 @@ static int help(const struct iphdr *iph, size_t len,
DEBUGP("conntrack_ftp: match `%.*s' (%u bytes at %u)\n",
(int)matchlen, data + matchoff,
matchlen, ntohl(tcph->seq) + matchoff);
+
+ memset(&expect, 0, sizeof(expect));
/* Update the ftp info */
LOCK_BH(&ip_ftp_lock);
if (htonl((array[0] << 24) | (array[1] << 16) | (array[2] << 8) | array[3])
== ct->tuplehash[dir].tuple.src.ip) {
- info->is_ftp = 21;
- info->seq = ntohl(tcph->seq) + matchoff;
- info->len = matchlen;
- info->ftptype = search[i].ftptype;
- info->port = array[4] << 8 | array[5];
+ exp->seq = ntohl(tcph->seq) + matchoff;
+ exp_ftp_info->len = matchlen;
+ exp_ftp_info->ftptype = search[i].ftptype;
+ exp_ftp_info->port = array[4] << 8 | array[5];
} else {
/* Enrico Scholz's passive FTP to partially RNAT'd ftp
server: it really wants us to connect to a
@@ -356,18 +361,21 @@ static int help(const struct iphdr *iph, size_t len,
if (!loose) goto out;
}
- t = ((struct ip_conntrack_tuple)
+ exp->tuple = ((struct ip_conntrack_tuple)
{ { ct->tuplehash[!dir].tuple.src.ip,
{ 0 } },
{ htonl((array[0] << 24) | (array[1] << 16)
| (array[2] << 8) | array[3]),
{ htons(array[4] << 8 | array[5]) },
IPPROTO_TCP }});
- mask = ((struct ip_conntrack_tuple)
+ exp->mask = ((struct ip_conntrack_tuple)
{ { 0xFFFFFFFF, { 0 } },
{ 0xFFFFFFFF, { 0xFFFF }, 0xFFFF }});
+
+ exp->expectfn = NULL;
+
/* Ignore failure; should only happen with NAT */
- ip_conntrack_expect_related(ct, &t, &mask, NULL);
+ ip_conntrack_expect_related(ct, &expect);
out:
UNLOCK_BH(&ip_ftp_lock);
@@ -375,6 +383,7 @@ static int help(const struct iphdr *iph, size_t len,
}
static struct ip_conntrack_helper ftp[MAX_PORTS];
+static char ftp_names[MAX_PORTS][10];
/* Not __exit: called from init() */
static void fini(void)
@@ -390,9 +399,10 @@ static void fini(void)
static int __init init(void)
{
int i, ret;
+ char *tmpname;
if (ports[0] == 0)
- ports[0] = 21;
+ ports[0] = FTP_PORT;
for (i = 0; (i < MAX_PORTS) && ports[i]; i++) {
memset(&ftp[i], 0, sizeof(struct ip_conntrack_helper));
@@ -400,7 +410,19 @@ static int __init init(void)
ftp[i].tuple.dst.protonum = IPPROTO_TCP;
ftp[i].mask.src.u.tcp.port = 0xFFFF;
ftp[i].mask.dst.protonum = 0xFFFF;
+ ftp[i].max_expected = 1;
+ ftp[i].timeout = 0;
+ ftp[i].flags = IP_CT_HELPER_F_REUSE_EXPECT;
+ ftp[i].me = ip_conntrack_ftp;
ftp[i].help = help;
+
+ tmpname = &ftp_names[i][0];
+ if (ports[i] == FTP_PORT)
+ sprintf(tmpname, "ftp");
+ else
+ sprintf(tmpname, "ftp-%d", ports[i]);
+ ftp[i].name = tmpname;
+
DEBUGP("ip_ct_ftp: registering helper for port %d\n",
ports[i]);
ret = ip_conntrack_helper_register(&ftp[i]);
@@ -414,10 +436,10 @@ static int __init init(void)
return 0;
}
-
+#ifdef CONFIG_IP_NF_NAT_NEEDED
EXPORT_SYMBOL(ip_ftp_lock);
-EXPORT_SYMBOL(ip_conntrack_ftp);
-MODULE_LICENSE("GPL");
+#endif
+MODULE_LICENSE("GPL");
module_init(init);
module_exit(fini);
diff --git a/net/ipv4/netfilter/ip_conntrack_irc.c b/net/ipv4/netfilter/ip_conntrack_irc.c
index a92087b6daf89..39d31f60cb025 100644
--- a/net/ipv4/netfilter/ip_conntrack_irc.c
+++ b/net/ipv4/netfilter/ip_conntrack_irc.c
@@ -11,12 +11,18 @@
**
* Module load syntax:
* insmod ip_conntrack_irc.o ports=port1,port2,...port<MAX_PORTS>
+ * max_dcc_channels=n dcc_timeout=secs
*
* please give the ports of all IRC servers You wish to connect to.
- * If You don't specify ports, the default will be port 6667
+ * If You don't specify ports, the default will be port 6667.
+ * With max_dcc_channels you can define the maximum number of not
+ * yet answered DCC channels per IRC session (default 8).
+ * With dcc_timeout you can specify how long the system waits for
+ * an expected DCC channel (default 300 seconds).
*
*/
+#include <linux/config.h>
#include <linux/module.h>
#include <linux/netfilter.h>
#include <linux/ip.h>
@@ -30,6 +36,8 @@
#define MAX_PORTS 8
static int ports[MAX_PORTS];
static int ports_n_c = 0;
+static int max_dcc_channels = 8;
+static unsigned int dcc_timeout = 300;
MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
MODULE_DESCRIPTION("IRC (DCC) connection tracking module");
@@ -37,6 +45,10 @@ MODULE_LICENSE("GPL");
#ifdef MODULE_PARM
MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_PORTS) "i");
MODULE_PARM_DESC(ports, "port numbers of IRC servers");
+MODULE_PARM(max_dcc_channels, "i");
+MODULE_PARM_DESC(max_dcc_channels, "max number of expected DCC channels per IRC session");
+MODULE_PARM(dcc_timeout, "i");
+MODULE_PARM_DESC(dcc_timeout, "timeout on for unestablished DCC channels");
#endif
#define NUM_DCCPROTO 5
@@ -103,23 +115,15 @@ static int help(const struct iphdr *iph, size_t len,
u_int32_t tcplen = len - iph->ihl * 4;
u_int32_t datalen = tcplen - tcph->doff * 4;
int dir = CTINFO2DIR(ctinfo);
- struct ip_conntrack_tuple t, mask;
+ struct ip_conntrack_expect expect, *exp = &expect;
+ struct ip_ct_irc_expect *exp_irc_info = &exp->help.exp_irc_info;
u_int32_t dcc_ip;
u_int16_t dcc_port;
int i;
char *addr_beg_p, *addr_end_p;
- struct ip_ct_irc *info = &ct->help.ct_irc_info;
-
- mask = ((struct ip_conntrack_tuple)
- { { 0, { 0 } },
- { 0xFFFFFFFF, { 0xFFFF }, 0xFFFF }});
-
DEBUGP("entered\n");
- /* Can't track connections formed before we registered */
- if (!info)
- return NF_ACCEPT;
/* If packet is coming from IRC server */
if (dir == IP_CT_DIR_REPLY)
@@ -189,33 +193,37 @@ static int help(const struct iphdr *iph, size_t len,
continue;
}
+
+ memset(&expect, 0, sizeof(expect));
LOCK_BH(&ip_irc_lock);
/* save position of address in dcc string,
* neccessary for NAT */
- info->is_irc = IP_CONNTR_IRC;
DEBUGP("tcph->seq = %u\n", tcph->seq);
- info->seq = ntohl(tcph->seq) + (addr_beg_p - _data);
- info->len = (addr_end_p - addr_beg_p);
- info->port = dcc_port;
+ exp->seq = ntohl(tcph->seq) + (addr_beg_p - _data);
+ exp_irc_info->len = (addr_end_p - addr_beg_p);
+ exp_irc_info->port = dcc_port;
DEBUGP("wrote info seq=%u (ofs=%u), len=%d\n",
- info->seq, (addr_end_p - _data), info->len);
+ exp->seq, (addr_end_p - _data), exp_irc_info->len);
+
+ exp->tuple = ((struct ip_conntrack_tuple)
+ { { 0, { 0 } },
+ { htonl(dcc_ip), { htons(dcc_port) },
+ IPPROTO_TCP }});
+ exp->mask = ((struct ip_conntrack_tuple)
+ { { 0, { 0 } },
+ { 0xFFFFFFFF, { 0xFFFF }, 0xFFFF }});
- memset(&t, 0, sizeof(t));
- t.src.ip = 0;
- t.src.u.tcp.port = 0;
- t.dst.ip = htonl(dcc_ip);
- t.dst.u.tcp.port = htons(info->port);
- t.dst.protonum = IPPROTO_TCP;
+ exp->expectfn = NULL;
DEBUGP("expect_related %u.%u.%u.%u:%u-%u.%u.%u.%u:%u\n",
- NIPQUAD(t.src.ip),
- ntohs(t.src.u.tcp.port),
- NIPQUAD(t.dst.ip),
- ntohs(t.dst.u.tcp.port));
+ NIPQUAD(exp->tuple.src.ip),
+ ntohs(exp->tuple.src.u.tcp.port),
+ NIPQUAD(exp->tuple.dst.ip),
+ ntohs(exp->tuple.dst.u.tcp.port));
- ip_conntrack_expect_related(ct, &t, &mask, NULL);
+ ip_conntrack_expect_related(ct, &expect);
UNLOCK_BH(&ip_irc_lock);
return NF_ACCEPT;
@@ -226,29 +234,53 @@ static int help(const struct iphdr *iph, size_t len,
}
static struct ip_conntrack_helper irc_helpers[MAX_PORTS];
+static char irc_names[MAX_PORTS][10];
static void fini(void);
static int __init init(void)
{
int i, ret;
+ struct ip_conntrack_helper *hlpr;
+ char *tmpname;
+ if (max_dcc_channels < 1) {
+ printk("ip_conntrack_irc: max_dcc_channels must be a positive integer\n");
+ return -EBUSY;
+ }
+ if (dcc_timeout < 0) {
+ printk("ip_conntrack_irc: dcc_timeout must be a positive integer\n");
+ return -EBUSY;
+ }
+
/* If no port given, default to standard irc port */
if (ports[0] == 0)
- ports[0] = 6667;
+ ports[0] = IRC_PORT;
for (i = 0; (i < MAX_PORTS) && ports[i]; i++) {
- memset(&irc_helpers[i], 0,
+ hlpr = &irc_helpers[i];
+ memset(hlpr, 0,
sizeof(struct ip_conntrack_helper));
- irc_helpers[i].tuple.src.u.tcp.port = htons(ports[i]);
- irc_helpers[i].tuple.dst.protonum = IPPROTO_TCP;
- irc_helpers[i].mask.src.u.tcp.port = 0xFFFF;
- irc_helpers[i].mask.dst.protonum = 0xFFFF;
- irc_helpers[i].help = help;
+ hlpr->tuple.src.u.tcp.port = htons(ports[i]);
+ hlpr->tuple.dst.protonum = IPPROTO_TCP;
+ hlpr->mask.src.u.tcp.port = 0xFFFF;
+ hlpr->mask.dst.protonum = 0xFFFF;
+ hlpr->max_expected = max_dcc_channels;
+ hlpr->timeout = dcc_timeout;
+ hlpr->flags = IP_CT_HELPER_F_REUSE_EXPECT;
+ hlpr->me = ip_conntrack_irc;
+ hlpr->help = help;
+
+ tmpname = &irc_names[i][0];
+ if (ports[i] == IRC_PORT)
+ sprintf(tmpname, "irc");
+ else
+ sprintf(tmpname, "irc-%d", i);
+ hlpr->name = tmpname;
DEBUGP("port #%d: %d\n", i, ports[i]);
- ret = ip_conntrack_helper_register(&irc_helpers[i]);
+ ret = ip_conntrack_helper_register(hlpr);
if (ret) {
printk("ip_conntrack_irc: ERROR registering port %d\n",
@@ -273,5 +305,9 @@ static void fini(void)
}
}
+#ifdef CONFIG_IP_NF_NAT_NEEDED
+EXPORT_SYMBOL(ip_irc_lock);
+#endif
+
module_init(init);
module_exit(fini);
diff --git a/net/ipv4/netfilter/ip_conntrack_proto_generic.c b/net/ipv4/netfilter/ip_conntrack_proto_generic.c
index fcc0eed71a0f9..e5b399b26eba8 100644
--- a/net/ipv4/netfilter/ip_conntrack_proto_generic.c
+++ b/net/ipv4/netfilter/ip_conntrack_proto_generic.c
@@ -57,5 +57,5 @@ new(struct ip_conntrack *conntrack, struct iphdr *iph, size_t len)
struct ip_conntrack_protocol ip_conntrack_generic_protocol
= { { NULL, NULL }, 0, "unknown",
generic_pkt_to_tuple, generic_invert_tuple, generic_print_tuple,
- generic_print_conntrack, established, new, NULL };
+ generic_print_conntrack, established, new, NULL, NULL, NULL };
diff --git a/net/ipv4/netfilter/ip_conntrack_proto_icmp.c b/net/ipv4/netfilter/ip_conntrack_proto_icmp.c
index b0eb65891d5f8..b72e1a8eeea64 100644
--- a/net/ipv4/netfilter/ip_conntrack_proto_icmp.c
+++ b/net/ipv4/netfilter/ip_conntrack_proto_icmp.c
@@ -113,4 +113,4 @@ static int icmp_new(struct ip_conntrack *conntrack,
struct ip_conntrack_protocol ip_conntrack_protocol_icmp
= { { NULL, NULL }, IPPROTO_ICMP, "icmp",
icmp_pkt_to_tuple, icmp_invert_tuple, icmp_print_tuple,
- icmp_print_conntrack, icmp_packet, icmp_new, NULL };
+ icmp_print_conntrack, icmp_packet, icmp_new, NULL, NULL, NULL };
diff --git a/net/ipv4/netfilter/ip_conntrack_proto_tcp.c b/net/ipv4/netfilter/ip_conntrack_proto_tcp.c
index 4f52a027fb3cb..e22ba471b914b 100644
--- a/net/ipv4/netfilter/ip_conntrack_proto_tcp.c
+++ b/net/ipv4/netfilter/ip_conntrack_proto_tcp.c
@@ -7,6 +7,9 @@
#include <linux/in.h>
#include <linux/ip.h>
#include <linux/tcp.h>
+
+#include <net/tcp.h>
+
#include <linux/netfilter_ipv4/ip_conntrack.h>
#include <linux/netfilter_ipv4/ip_conntrack_protocol.h>
#include <linux/netfilter_ipv4/lockhelp.h>
@@ -227,7 +230,19 @@ static int tcp_new(struct ip_conntrack *conntrack,
return 1;
}
+static int tcp_exp_matches_pkt(struct ip_conntrack_expect *exp,
+ struct sk_buff **pskb)
+{
+ struct iphdr *iph = (*pskb)->nh.iph;
+ struct tcphdr *tcph = (struct tcphdr *)((u_int32_t *)iph + iph->ihl);
+ unsigned int datalen;
+
+ datalen = (*pskb)->len - iph->ihl*4 - tcph->doff*4;
+
+ return between(exp->seq, ntohl(tcph->seq), ntohl(tcph->seq) + datalen);
+}
+
struct ip_conntrack_protocol ip_conntrack_protocol_tcp
= { { NULL, NULL }, IPPROTO_TCP, "tcp",
tcp_pkt_to_tuple, tcp_invert_tuple, tcp_print_tuple, tcp_print_conntrack,
- tcp_packet, tcp_new, NULL };
+ tcp_packet, tcp_new, NULL, tcp_exp_matches_pkt, NULL };
diff --git a/net/ipv4/netfilter/ip_conntrack_proto_udp.c b/net/ipv4/netfilter/ip_conntrack_proto_udp.c
index 86544b03d2ceb..57e807026c185 100644
--- a/net/ipv4/netfilter/ip_conntrack_proto_udp.c
+++ b/net/ipv4/netfilter/ip_conntrack_proto_udp.c
@@ -71,4 +71,4 @@ static int udp_new(struct ip_conntrack *conntrack,
struct ip_conntrack_protocol ip_conntrack_protocol_udp
= { { NULL, NULL }, IPPROTO_UDP, "udp",
udp_pkt_to_tuple, udp_invert_tuple, udp_print_tuple, udp_print_conntrack,
- udp_packet, udp_new, NULL };
+ udp_packet, udp_new, NULL, NULL, NULL };
diff --git a/net/ipv4/netfilter/ip_conntrack_standalone.c b/net/ipv4/netfilter/ip_conntrack_standalone.c
index b93dd01676795..12480c0d91391 100644
--- a/net/ipv4/netfilter/ip_conntrack_standalone.c
+++ b/net/ipv4/netfilter/ip_conntrack_standalone.c
@@ -62,7 +62,13 @@ print_expect(char *buffer, const struct ip_conntrack_expect *expect)
{
unsigned int len;
- len = sprintf(buffer, "EXPECTING: proto=%u ",
+ if (expect->expectant->helper->timeout)
+ len = sprintf(buffer, "EXPECTING: %lu ",
+ timer_pending(&expect->timeout)
+ ? (expect->timeout.expires - jiffies)/HZ : 0);
+ else
+ len = sprintf(buffer, "EXPECTING: - ");
+ len += sprintf(buffer + len, "proto=%u ",
expect->tuple.dst.protonum);
len += print_tuple(buffer + len, &expect->tuple,
__find_proto(expect->tuple.dst.protonum));
@@ -314,7 +320,7 @@ void ip_conntrack_protocol_unregister(struct ip_conntrack_protocol *proto)
{
WRITE_LOCK(&ip_conntrack_lock);
- /* find_proto() returns proto_generic in case there is no protocol
+ /* ip_ct_find_proto() returns proto_generic in case there is no protocol
* helper. So this should be enough - HW */
LIST_DELETE(&protocol_list, proto);
WRITE_UNLOCK(&ip_conntrack_lock);
@@ -353,8 +359,12 @@ EXPORT_SYMBOL(ip_conntrack_helper_register);
EXPORT_SYMBOL(ip_conntrack_helper_unregister);
EXPORT_SYMBOL(ip_ct_selective_cleanup);
EXPORT_SYMBOL(ip_ct_refresh);
+EXPORT_SYMBOL(ip_ct_find_proto);
+EXPORT_SYMBOL(ip_ct_find_helper);
EXPORT_SYMBOL(ip_conntrack_expect_related);
+EXPORT_SYMBOL(ip_conntrack_change_expect);
EXPORT_SYMBOL(ip_conntrack_unexpect_related);
EXPORT_SYMBOL(ip_conntrack_tuple_taken);
EXPORT_SYMBOL(ip_ct_gather_frags);
EXPORT_SYMBOL(ip_conntrack_htable_size);
+EXPORT_SYMBOL(ip_conntrack_lock);
diff --git a/net/ipv4/netfilter/ip_fw_compat_masq.c b/net/ipv4/netfilter/ip_fw_compat_masq.c
index 1d462ac6d7a03..708dff11745bd 100644
--- a/net/ipv4/netfilter/ip_fw_compat_masq.c
+++ b/net/ipv4/netfilter/ip_fw_compat_masq.c
@@ -130,7 +130,7 @@ check_for_demasq(struct sk_buff **pskb)
struct ip_conntrack *ct;
int ret;
- protocol = find_proto(iph->protocol);
+ protocol = ip_ct_find_proto(iph->protocol);
/* We don't feed packets to conntrack system unless we know
they're part of an connection already established by an
diff --git a/net/ipv4/netfilter/ip_fw_compat_redir.c b/net/ipv4/netfilter/ip_fw_compat_redir.c
index 1b11391683e19..0540d87e1134a 100644
--- a/net/ipv4/netfilter/ip_fw_compat_redir.c
+++ b/net/ipv4/netfilter/ip_fw_compat_redir.c
@@ -43,7 +43,7 @@ do { \
netplay... */ \
printk("ASSERT: %s:%i(%s)\n", \
__FILE__, __LINE__, __FUNCTION__); \
-} while(0);
+} while(0)
#else
#define IP_NF_ASSERT(x)
#endif
diff --git a/net/ipv4/netfilter/ip_nat_core.c b/net/ipv4/netfilter/ip_nat_core.c
index ebbbde93ead4d..50873f1890e72 100644
--- a/net/ipv4/netfilter/ip_nat_core.c
+++ b/net/ipv4/netfilter/ip_nat_core.c
@@ -21,10 +21,14 @@
#define ASSERT_READ_LOCK(x) MUST_BE_READ_LOCKED(&ip_nat_lock)
#define ASSERT_WRITE_LOCK(x) MUST_BE_WRITE_LOCKED(&ip_nat_lock)
+#include <linux/netfilter_ipv4/ip_conntrack.h>
+#include <linux/netfilter_ipv4/ip_conntrack_core.h>
+#include <linux/netfilter_ipv4/ip_conntrack_protocol.h>
#include <linux/netfilter_ipv4/ip_nat.h>
#include <linux/netfilter_ipv4/ip_nat_protocol.h>
#include <linux/netfilter_ipv4/ip_nat_core.h>
#include <linux/netfilter_ipv4/ip_nat_helper.h>
+#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
#include <linux/netfilter_ipv4/listhelp.h>
#if 0
@@ -34,6 +38,7 @@
#endif
DECLARE_RWLOCK(ip_nat_lock);
+DECLARE_RWLOCK_EXTERN(ip_conntrack_lock);
/* Calculated at init based on memory size */
static unsigned int ip_nat_htable_size;
@@ -628,8 +633,9 @@ ip_nat_setup_info(struct ip_conntrack *conntrack,
}
/* If there's a helper, assign it; based on new tuple. */
- info->helper = LIST_FIND(&helpers, helper_cmp, struct ip_nat_helper *,
- &reply);
+ if (!conntrack->master)
+ info->helper = LIST_FIND(&helpers, helper_cmp, struct ip_nat_helper *,
+ &reply);
/* It's done. */
info->initialized |= (1 << HOOK2MANIP(hooknum));
@@ -724,6 +730,21 @@ manip_pkt(u_int16_t proto, struct iphdr *iph, size_t len,
#endif
}
+static inline int exp_for_packet(struct ip_conntrack_expect *exp,
+ struct sk_buff **pskb)
+{
+ struct ip_conntrack_protocol *proto;
+ int ret = 1;
+
+ READ_LOCK(&ip_conntrack_lock);
+ proto = ip_ct_find_proto((*pskb)->nh.iph->protocol);
+ if (proto->exp_matches_pkt)
+ ret = proto->exp_matches_pkt(exp, pskb);
+ READ_UNLOCK(&ip_conntrack_lock);
+
+ return ret;
+}
+
/* Do packet manipulations according to binding. */
unsigned int
do_bindings(struct ip_conntrack *ct,
@@ -735,6 +756,7 @@ do_bindings(struct ip_conntrack *ct,
unsigned int i;
struct ip_nat_helper *helper;
enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
+ int is_tcp = (*pskb)->nh.iph->protocol == IPPROTO_TCP;
/* Need nat lock to protect against modification, but neither
conntrack (referenced) and helper (deleted with
@@ -773,11 +795,66 @@ do_bindings(struct ip_conntrack *ct,
READ_UNLOCK(&ip_nat_lock);
if (helper) {
+ struct ip_conntrack_expect *exp = NULL;
+ struct list_head *cur_item;
+ int ret = NF_ACCEPT;
+
+ DEBUGP("do_bindings: helper existing for (%p)\n", ct);
+
/* Always defragged for helpers */
IP_NF_ASSERT(!((*pskb)->nh.iph->frag_off
& __constant_htons(IP_MF|IP_OFFSET)));
- return helper->help(ct, info, ctinfo, hooknum, pskb);
- } else return NF_ACCEPT;
+
+ /* Have to grab read lock before sibling_list traversal */
+ READ_LOCK(&ip_conntrack_lock);
+ list_for_each(cur_item, &ct->sibling_list) {
+ exp = list_entry(cur_item, struct ip_conntrack_expect,
+ expected_list);
+
+ /* if this expectation is already established, skip */
+ if (exp->sibling)
+ continue;
+
+ if (exp_for_packet(exp, pskb)) {
+ /* FIXME: May be true multiple times in the case of UDP!! */
+ DEBUGP("calling nat helper (exp=%p) for packet\n",
+ exp);
+ ret = helper->help(ct, exp, info, ctinfo,
+ hooknum, pskb);
+ if (ret != NF_ACCEPT) {
+ READ_UNLOCK(&ip_conntrack_lock);
+ return ret;
+ }
+ }
+ }
+ /* Helper might want to manip the packet even when there is no expectation */
+ if (!exp && helper->flags & IP_NAT_HELPER_F_ALWAYS) {
+ DEBUGP("calling nat helper for packet without expectation\n");
+ ret = helper->help(ct, NULL, info, ctinfo,
+ hooknum, pskb);
+ if (ret != NF_ACCEPT) {
+ READ_UNLOCK(&ip_conntrack_lock);
+ return ret;
+ }
+ }
+ READ_UNLOCK(&ip_conntrack_lock);
+
+ /* Adjust sequence number only once per packet
+ * (helper is called at all hooks) */
+ if (is_tcp && (hooknum == NF_IP_POST_ROUTING
+ || hooknum == NF_IP_LOCAL_IN)) {
+ DEBUGP("ip_nat_core: adjusting sequence number\n");
+ /* future: put this in a l4-proto specific function,
+ * and call this function here. */
+ ip_nat_seq_adjust(*pskb, ct, ctinfo);
+ }
+
+ return ret;
+
+ } else
+ return NF_ACCEPT;
+
+ /* not reached */
}
unsigned int
diff --git a/net/ipv4/netfilter/ip_nat_ftp.c b/net/ipv4/netfilter/ip_nat_ftp.c
index 788a6412d88fc..a539e979ae673 100644
--- a/net/ipv4/netfilter/ip_nat_ftp.c
+++ b/net/ipv4/netfilter/ip_nat_ftp.c
@@ -28,38 +28,30 @@ DECLARE_LOCK_EXTERN(ip_ftp_lock);
/* FIXME: Time out? --RR */
-static int
+static unsigned int
ftp_nat_expected(struct sk_buff **pskb,
unsigned int hooknum,
struct ip_conntrack *ct,
- struct ip_nat_info *info,
- struct ip_conntrack *master,
- struct ip_nat_info *masterinfo,
- unsigned int *verdict)
+ struct ip_nat_info *info)
{
struct ip_nat_multi_range mr;
u_int32_t newdstip, newsrcip, newip;
- struct ip_ct_ftp *ftpinfo;
+ struct ip_ct_ftp_expect *exp_ftp_info;
+ struct ip_conntrack *master = master_ct(ct);
+
IP_NF_ASSERT(info);
IP_NF_ASSERT(master);
- IP_NF_ASSERT(masterinfo);
IP_NF_ASSERT(!(info->initialized & (1<<HOOK2MANIP(hooknum))));
DEBUGP("nat_expected: We have a connection!\n");
- /* Master must be an ftp connection */
- ftpinfo = &master->help.ct_ftp_info;
+ exp_ftp_info = &ct->master->help.exp_ftp_info;
LOCK_BH(&ip_ftp_lock);
- if (ftpinfo->is_ftp != 21) {
- UNLOCK_BH(&ip_ftp_lock);
- DEBUGP("nat_expected: master not ftp\n");
- return 0;
- }
- if (ftpinfo->ftptype == IP_CT_FTP_PORT
- || ftpinfo->ftptype == IP_CT_FTP_EPRT) {
+ if (exp_ftp_info->ftptype == IP_CT_FTP_PORT
+ || exp_ftp_info->ftptype == IP_CT_FTP_EPRT) {
/* PORT command: make connection go to the client. */
newdstip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
newsrcip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip;
@@ -92,11 +84,9 @@ ftp_nat_expected(struct sk_buff **pskb,
mr.range[0].flags |= IP_NAT_RANGE_PROTO_SPECIFIED;
mr.range[0].min = mr.range[0].max
= ((union ip_conntrack_manip_proto)
- { htons(ftpinfo->port) });
+ { htons(exp_ftp_info->port) });
}
- *verdict = ip_nat_setup_info(ct, &mr, hooknum);
-
- return 1;
+ return ip_nat_setup_info(ct, &mr, hooknum);
}
static int
@@ -176,27 +166,22 @@ static int (*mangle[])(struct sk_buff **, u_int32_t, u_int16_t,
[IP_CT_FTP_EPSV] mangle_epsv_packet
};
-static int ftp_data_fixup(const struct ip_ct_ftp *ct_ftp_info,
+static int ftp_data_fixup(const struct ip_ct_ftp_expect *ct_ftp_info,
struct ip_conntrack *ct,
- unsigned int datalen,
struct sk_buff **pskb,
- enum ip_conntrack_info ctinfo)
+ enum ip_conntrack_info ctinfo,
+ struct ip_conntrack_expect *expect)
{
u_int32_t newip;
struct iphdr *iph = (*pskb)->nh.iph;
struct tcphdr *tcph = (void *)iph + iph->ihl*4;
u_int16_t port;
- struct ip_conntrack_tuple tuple;
- /* Don't care about source port */
- const struct ip_conntrack_tuple mask
- = { { 0xFFFFFFFF, { 0 } },
- { 0xFFFFFFFF, { 0xFFFF }, 0xFFFF } };
+ struct ip_conntrack_tuple newtuple;
- memset(&tuple, 0, sizeof(tuple));
MUST_BE_LOCKED(&ip_ftp_lock);
- DEBUGP("FTP_NAT: seq %u + %u in %u + %u\n",
- ct_ftp_info->seq, ct_ftp_info->len,
- ntohl(tcph->seq), datalen);
+ DEBUGP("FTP_NAT: seq %u + %u in %u\n",
+ expect->seq, ct_ftp_info->len,
+ ntohl(tcph->seq));
/* Change address inside packet to match way we're mapping
this connection. */
@@ -206,29 +191,34 @@ static int ftp_data_fixup(const struct ip_ct_ftp *ct_ftp_info,
is */
newip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip;
/* Expect something from client->server */
- tuple.src.ip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
- tuple.dst.ip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip;
+ newtuple.src.ip =
+ ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
+ newtuple.dst.ip =
+ ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip;
} else {
/* PORT command: must be where server thinks client is */
newip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;
/* Expect something from server->client */
- tuple.src.ip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip;
- tuple.dst.ip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;
+ newtuple.src.ip =
+ ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip;
+ newtuple.dst.ip =
+ ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;
}
- tuple.dst.protonum = IPPROTO_TCP;
+ newtuple.dst.protonum = IPPROTO_TCP;
+ newtuple.src.u.tcp.port = expect->tuple.src.u.tcp.port;
/* Try to get same port: if not, try to change it. */
for (port = ct_ftp_info->port; port != 0; port++) {
- tuple.dst.u.tcp.port = htons(port);
+ newtuple.dst.u.tcp.port = htons(port);
- if (ip_conntrack_expect_related(ct, &tuple, &mask, NULL) == 0)
+ if (ip_conntrack_change_expect(expect, &newtuple) == 0)
break;
}
if (port == 0)
return 0;
if (!mangle[ct_ftp_info->ftptype](pskb, newip, port,
- ct_ftp_info->seq - ntohl(tcph->seq),
+ expect->seq - ntohl(tcph->seq),
ct_ftp_info->len, ct, ctinfo))
return 0;
@@ -236,6 +226,7 @@ static int ftp_data_fixup(const struct ip_ct_ftp *ct_ftp_info,
}
static unsigned int help(struct ip_conntrack *ct,
+ struct ip_conntrack_expect *exp,
struct ip_nat_info *info,
enum ip_conntrack_info ctinfo,
unsigned int hooknum,
@@ -245,13 +236,12 @@ static unsigned int help(struct ip_conntrack *ct,
struct tcphdr *tcph = (void *)iph + iph->ihl*4;
unsigned int datalen;
int dir;
- int score;
- struct ip_ct_ftp *ct_ftp_info
- = &ct->help.ct_ftp_info;
+ struct ip_ct_ftp_expect *ct_ftp_info;
- /* Delete SACK_OK on initial TCP SYNs. */
- if (tcph->syn && !tcph->ack)
- ip_nat_delete_sack(*pskb, tcph);
+ if (!exp)
+ DEBUGP("ip_nat_ftp: no exp!!");
+
+ ct_ftp_info = &exp->help.exp_ftp_info;
/* Only mangle things once: original direction in POST_ROUTING
and reply direction on PRE_ROUTING. */
@@ -267,50 +257,34 @@ static unsigned int help(struct ip_conntrack *ct,
}
datalen = (*pskb)->len - iph->ihl * 4 - tcph->doff * 4;
- score = 0;
LOCK_BH(&ip_ftp_lock);
- if (ct_ftp_info->len) {
- /* If it's in the right range... */
- score += between(ct_ftp_info->seq, ntohl(tcph->seq),
- ntohl(tcph->seq) + datalen);
- score += between(ct_ftp_info->seq + ct_ftp_info->len,
- ntohl(tcph->seq),
- ntohl(tcph->seq) + datalen);
- if (score == 1) {
- /* Half a match? This means a partial retransmisison.
- It's a cracker being funky. */
- if (net_ratelimit()) {
- printk("FTP_NAT: partial packet %u/%u in %u/%u\n",
- ct_ftp_info->seq, ct_ftp_info->len,
- ntohl(tcph->seq),
- ntohl(tcph->seq) + datalen);
- }
+ /* If it's in the right range... */
+ if (between(exp->seq + ct_ftp_info->len,
+ ntohl(tcph->seq),
+ ntohl(tcph->seq) + datalen)) {
+ if (!ftp_data_fixup(ct_ftp_info, ct, pskb, ctinfo, exp)) {
UNLOCK_BH(&ip_ftp_lock);
return NF_DROP;
- } else if (score == 2) {
- if (!ftp_data_fixup(ct_ftp_info, ct, datalen,
- pskb, ctinfo)) {
- UNLOCK_BH(&ip_ftp_lock);
- return NF_DROP;
- }
- /* skb may have been reallocated */
- iph = (*pskb)->nh.iph;
- tcph = (void *)iph + iph->ihl*4;
}
+ } else {
+ /* Half a match? This means a partial retransmisison.
+ It's a cracker being funky. */
+ if (net_ratelimit()) {
+ printk("FTP_NAT: partial packet %u/%u in %u/%u\n",
+ exp->seq, ct_ftp_info->len,
+ ntohl(tcph->seq),
+ ntohl(tcph->seq) + datalen);
+ }
+ UNLOCK_BH(&ip_ftp_lock);
+ return NF_DROP;
}
-
UNLOCK_BH(&ip_ftp_lock);
- ip_nat_seq_adjust(*pskb, ct, ctinfo);
-
return NF_ACCEPT;
}
static struct ip_nat_helper ftp[MAX_PORTS];
-static char ftp_names[MAX_PORTS][6];
-
-static struct ip_nat_expect ftp_expect
-= { { NULL, NULL }, ftp_nat_expected };
+static char ftp_names[MAX_PORTS][10];
/* Not __exit: called from init() */
static void fini(void)
@@ -321,49 +295,49 @@ static void fini(void)
DEBUGP("ip_nat_ftp: unregistering port %d\n", ports[i]);
ip_nat_helper_unregister(&ftp[i]);
}
-
- ip_nat_expect_unregister(&ftp_expect);
}
static int __init init(void)
{
- int i, ret;
+ int i, ret = 0;
char *tmpname;
- ret = ip_nat_expect_register(&ftp_expect);
- if (ret == 0) {
- if (ports[0] == 0)
- ports[0] = 21;
-
- for (i = 0; (i < MAX_PORTS) && ports[i]; i++) {
-
- memset(&ftp[i], 0, sizeof(struct ip_nat_helper));
-
- ftp[i].tuple.dst.protonum = IPPROTO_TCP;
- ftp[i].tuple.src.u.tcp.port = htons(ports[i]);
- ftp[i].mask.dst.protonum = 0xFFFF;
- ftp[i].mask.src.u.tcp.port = 0xFFFF;
- ftp[i].help = help;
+ if (ports[0] == 0)
+ ports[0] = FTP_PORT;
- tmpname = &ftp_names[i][0];
- sprintf(tmpname, "ftp%2.2d", i);
- ftp[i].name = tmpname;
-
- DEBUGP("ip_nat_ftp: Trying to register for port %d\n",
- ports[i]);
- ret = ip_nat_helper_register(&ftp[i]);
+ for (i = 0; (i < MAX_PORTS) && ports[i]; i++) {
- if (ret) {
- printk("ip_nat_ftp: error registering helper for port %d\n", ports[i]);
- fini();
- return ret;
- }
- ports_c++;
+ memset(&ftp[i], 0, sizeof(struct ip_nat_helper));
+
+ ftp[i].tuple.dst.protonum = IPPROTO_TCP;
+ ftp[i].tuple.src.u.tcp.port = htons(ports[i]);
+ ftp[i].mask.dst.protonum = 0xFFFF;
+ ftp[i].mask.src.u.tcp.port = 0xFFFF;
+ ftp[i].help = help;
+ ftp[i].me = THIS_MODULE;
+ ftp[i].flags = 0;
+ ftp[i].expect = ftp_nat_expected;
+
+ tmpname = &ftp_names[i][0];
+ if (ports[i] == FTP_PORT)
+ sprintf(tmpname, "ftp");
+ else
+ sprintf(tmpname, "ftp-%d", i);
+ ftp[i].name = tmpname;
+
+ DEBUGP("ip_nat_ftp: Trying to register for port %d\n",
+ ports[i]);
+ ret = ip_nat_helper_register(&ftp[i]);
+
+ if (ret) {
+ printk("ip_nat_ftp: error registering "
+ "helper for port %d\n", ports[i]);
+ fini();
+ return ret;
}
-
- } else {
- ip_nat_expect_unregister(&ftp_expect);
+ ports_c++;
}
+
return ret;
}
diff --git a/net/ipv4/netfilter/ip_nat_helper.c b/net/ipv4/netfilter/ip_nat_helper.c
index 183ba3f85356d..dd0fab83bc48c 100644
--- a/net/ipv4/netfilter/ip_nat_helper.c
+++ b/net/ipv4/netfilter/ip_nat_helper.c
@@ -1,11 +1,18 @@
/* ip_nat_mangle.c - generic support functions for NAT helpers
*
- * (C) 2000 by Harald Welte <laforge@gnumonks.org>
+ * (C) 2000-2002 by Harald Welte <laforge@gnumonks.org>
*
* distributed under the terms of GNU GPL
+ *
+ * 14 Jan 2002 Harald Welte <laforge@gnumonks.org>:
+ * - add support for SACK adjustment
+ * 14 Mar 2002 Harald Welte <laforge@gnumonks.org>:
+ * - merge SACK support into newnat API
*/
#include <linux/version.h>
+#include <linux/config.h>
#include <linux/module.h>
+#include <linux/kmod.h>
#include <linux/types.h>
#include <linux/timer.h>
#include <linux/skbuff.h>
@@ -19,6 +26,8 @@
#define ASSERT_READ_LOCK(x) MUST_BE_READ_LOCKED(&ip_nat_lock)
#define ASSERT_WRITE_LOCK(x) MUST_BE_WRITE_LOCKED(&ip_nat_lock)
+#include <linux/netfilter_ipv4/ip_conntrack.h>
+#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
#include <linux/netfilter_ipv4/ip_nat.h>
#include <linux/netfilter_ipv4/ip_nat_protocol.h>
#include <linux/netfilter_ipv4/ip_nat_core.h>
@@ -32,7 +41,7 @@
#define DEBUGP(format, args...)
#define DUMP_OFFSET(x)
#endif
-
+
DECLARE_LOCK(ip_nat_seqofs_lock);
static inline int
@@ -199,6 +208,103 @@ ip_nat_mangle_tcp_packet(struct sk_buff **skb,
return 1;
}
+/* Adjust one found SACK option including checksum correction */
+static void
+sack_adjust(struct tcphdr *tcph,
+ unsigned char *ptr,
+ struct ip_nat_seq *natseq)
+{
+ struct tcp_sack_block *sp = (struct tcp_sack_block *)(ptr+2);
+ int num_sacks = (ptr[1] - TCPOLEN_SACK_BASE)>>3;
+ int i;
+
+ for (i = 0; i < num_sacks; i++, sp++) {
+ u_int32_t new_start_seq, new_end_seq;
+
+ if (after(ntohl(sp->start_seq) - natseq->offset_before,
+ natseq->correction_pos))
+ new_start_seq = ntohl(sp->start_seq)
+ - natseq->offset_after;
+ else
+ new_start_seq = ntohl(sp->start_seq)
+ - natseq->offset_before;
+ new_start_seq = htonl(new_start_seq);
+
+ if (after(ntohl(sp->end_seq) - natseq->offset_before,
+ natseq->correction_pos))
+ new_end_seq = ntohl(sp->end_seq)
+ - natseq->offset_after;
+ else
+ new_end_seq = ntohl(sp->end_seq)
+ - natseq->offset_before;
+ new_end_seq = htonl(new_end_seq);
+
+ DEBUGP("sack_adjust: start_seq: %d->%d, end_seq: %d->%d\n",
+ ntohl(sp->start_seq), new_start_seq,
+ ntohl(sp->end_seq), new_end_seq);
+
+ tcph->check =
+ ip_nat_cheat_check(~sp->start_seq, new_start_seq,
+ ip_nat_cheat_check(~sp->end_seq,
+ new_end_seq,
+ tcph->check));
+
+ sp->start_seq = new_start_seq;
+ sp->end_seq = new_end_seq;
+ }
+}
+
+
+/* TCP SACK sequence number adjustment, return 0 if sack found and adjusted */
+static inline int
+ip_nat_sack_adjust(struct sk_buff *skb,
+ struct ip_conntrack *ct,
+ enum ip_conntrack_info ctinfo)
+{
+ struct iphdr *iph;
+ struct tcphdr *tcph;
+ unsigned char *ptr;
+ int length, dir, sack_adjusted = 0;
+
+ iph = skb->nh.iph;
+ tcph = (void *)iph + iph->ihl*4;
+ length = (tcph->doff*4)-sizeof(struct tcphdr);
+ ptr = (unsigned char *)(tcph+1);
+
+ dir = CTINFO2DIR(ctinfo);
+
+ while (length > 0) {
+ int opcode = *ptr++;
+ int opsize;
+
+ switch (opcode) {
+ case TCPOPT_EOL:
+ return !sack_adjusted;
+ case TCPOPT_NOP:
+ length--;
+ continue;
+ default:
+ opsize = *ptr++;
+ if (opsize > length) /* no partial opts */
+ return !sack_adjusted;
+ if (opcode == TCPOPT_SACK) {
+ /* found SACK */
+ if((opsize >= (TCPOLEN_SACK_BASE
+ +TCPOLEN_SACK_PERBLOCK)) &&
+ !((opsize - TCPOLEN_SACK_BASE)
+ % TCPOLEN_SACK_PERBLOCK))
+ sack_adjust(tcph, ptr-2,
+ &ct->nat.info.seq[!dir]);
+
+ sack_adjusted = 1;
+ }
+ ptr += opsize-2;
+ length -= opsize;
+ }
+ }
+ return !sack_adjusted;
+}
+
/* TCP sequence number adjustment */
int
ip_nat_seq_adjust(struct sk_buff *skb,
@@ -243,51 +349,9 @@ ip_nat_seq_adjust(struct sk_buff *skb,
tcph->seq = newseq;
tcph->ack_seq = newack;
- return 0;
-}
-
-/* Grrr... SACK. Fuck me even harder. Don't want to fix it on the
- fly, so blow it away. */
-void
-ip_nat_delete_sack(struct sk_buff *skb, struct tcphdr *tcph)
-{
- unsigned int i;
- u_int8_t *opt = (u_int8_t *)tcph;
-
- DEBUGP("Seeking SACKPERM in SYN packet (doff = %u).\n",
- tcph->doff * 4);
- for (i = sizeof(struct tcphdr); i < tcph->doff * 4;) {
- DEBUGP("%u ", opt[i]);
- switch (opt[i]) {
- case TCPOPT_NOP:
- case TCPOPT_EOL:
- i++;
- break;
-
- case TCPOPT_SACK_PERM:
- goto found_opt;
+ ip_nat_sack_adjust(skb, ct, ctinfo);
- default:
- /* Worst that can happen: it will take us over. */
- i += opt[i+1] ?: 1;
- }
- }
- DEBUGP("\n");
- return;
-
- found_opt:
- DEBUGP("\n");
- DEBUGP("Found SACKPERM at offset %u.\n", i);
-
- /* Must be within TCP header, and valid SACK perm. */
- if (i + opt[i+1] <= tcph->doff*4 && opt[i+1] == 2) {
- /* Replace with NOPs. */
- tcph->check
- = ip_nat_cheat_check(*((u_int16_t *)(opt + i))^0xFFFF,
- (TCPOPT_NOP<<8)|TCPOPT_NOP, tcph->check);
- opt[i] = opt[i+1] = TCPOPT_NOP;
- }
- else DEBUGP("Something wrong with SACK_PERM.\n");
+ return 0;
}
static inline int
@@ -297,10 +361,51 @@ helper_cmp(const struct ip_nat_helper *helper,
return ip_ct_tuple_mask_cmp(tuple, &helper->tuple, &helper->mask);
}
+#define MODULE_MAX_NAMELEN 32
+
int ip_nat_helper_register(struct ip_nat_helper *me)
{
int ret = 0;
+ if (me->me && !(me->flags & IP_NAT_HELPER_F_STANDALONE)) {
+ struct ip_conntrack_helper *ct_helper;
+
+ if ((ct_helper = ip_ct_find_helper(&me->tuple))
+ && ct_helper->me) {
+ __MOD_INC_USE_COUNT(ct_helper->me);
+ } else {
+
+ /* We are a NAT helper for protocol X. If we need
+ * respective conntrack helper for protoccol X, compute
+ * conntrack helper name and try to load module */
+ char name[MODULE_MAX_NAMELEN];
+ const char *tmp = me->me->name;
+
+ if (strlen(tmp) + 6 > MODULE_MAX_NAMELEN) {
+ printk(__FUNCTION__ ": unable to "
+ "compute conntrack helper name "
+ "from %s\n", tmp);
+ return -EBUSY;
+ }
+ tmp += 6;
+ sprintf(name, "ip_conntrack%s", tmp);
+#ifdef CONFIG_KMOD
+ if (!request_module(name)
+ && (ct_helper = ip_ct_find_helper(&me->tuple))
+ && ct_helper->me) {
+ __MOD_INC_USE_COUNT(ct_helper->me);
+ } else {
+ printk("unable to load module %s\n", name);
+ return -EBUSY;
+ }
+#else
+ printk("unable to load module %s automatically "
+ "because kernel was compiled without kernel "
+ "module loader support\n", name);
+ return -EBUSY;
+#endif
+ }
+ }
WRITE_LOCK(&ip_nat_lock);
if (LIST_FIND(&helpers, helper_cmp, struct ip_nat_helper *,&me->tuple))
ret = -EBUSY;
@@ -327,8 +432,14 @@ kill_helper(const struct ip_conntrack *i, void *helper)
void ip_nat_helper_unregister(struct ip_nat_helper *me)
{
+ int found = 0;
+
WRITE_LOCK(&ip_nat_lock);
- LIST_DELETE(&helpers, me);
+ /* Autoloading conntrack helper might have failed */
+ if (LIST_FIND(&helpers, helper_cmp, struct ip_nat_helper *,&me->tuple)) {
+ LIST_DELETE(&helpers, me);
+ found = 1;
+ }
WRITE_UNLOCK(&ip_nat_lock);
/* Someone could be still looking at the helper in a bh. */
@@ -344,5 +455,19 @@ void ip_nat_helper_unregister(struct ip_nat_helper *me)
worse. --RR */
ip_ct_selective_cleanup(kill_helper, me);
- MOD_DEC_USE_COUNT;
+ if (found)
+ MOD_DEC_USE_COUNT;
+
+ /* If we are no standalone NAT helper, we need to decrement usage count
+ * on our conntrack helper */
+ if (me->me && !(me->flags & IP_NAT_HELPER_F_STANDALONE)) {
+ struct ip_conntrack_helper *ct_helper;
+
+ if ((ct_helper = ip_ct_find_helper(&me->tuple))
+ && ct_helper->me) {
+ __MOD_DEC_USE_COUNT(ct_helper->me);
+ } else
+ printk(__FUNCTION__ ": unable to decrement usage count"
+ " of conntrack helper %s\n", me->me->name);
+ }
}
diff --git a/net/ipv4/netfilter/ip_nat_irc.c b/net/ipv4/netfilter/ip_nat_irc.c
index 2a8b83afaf5b4..3edc319f56fbe 100644
--- a/net/ipv4/netfilter/ip_nat_irc.c
+++ b/net/ipv4/netfilter/ip_nat_irc.c
@@ -51,42 +51,29 @@ DECLARE_LOCK_EXTERN(ip_irc_lock);
/* FIXME: Time out? --RR */
-static int
+static unsigned int
irc_nat_expected(struct sk_buff **pskb,
unsigned int hooknum,
struct ip_conntrack *ct,
- struct ip_nat_info *info,
- struct ip_conntrack *master,
- struct ip_nat_info *masterinfo, unsigned int *verdict)
+ struct ip_nat_info *info)
{
struct ip_nat_multi_range mr;
u_int32_t newdstip, newsrcip, newip;
- struct ip_ct_irc *ircinfo;
+
+ struct ip_conntrack *master = master_ct(ct);
IP_NF_ASSERT(info);
IP_NF_ASSERT(master);
- IP_NF_ASSERT(masterinfo);
IP_NF_ASSERT(!(info->initialized & (1 << HOOK2MANIP(hooknum))));
DEBUGP("nat_expected: We have a connection!\n");
- /* Master must be an irc connection */
- ircinfo = &master->help.ct_irc_info;
- LOCK_BH(&ip_irc_lock);
- if (ircinfo->is_irc != IP_CONNTR_IRC) {
- UNLOCK_BH(&ip_irc_lock);
- DEBUGP("nat_expected: master not irc\n");
- return 0;
- }
-
newdstip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
newsrcip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
DEBUGP("nat_expected: DCC cmd. %u.%u.%u.%u->%u.%u.%u.%u\n",
NIPQUAD(newsrcip), NIPQUAD(newdstip));
- UNLOCK_BH(&ip_irc_lock);
-
if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC)
newip = newsrcip;
else
@@ -99,16 +86,14 @@ irc_nat_expected(struct sk_buff **pskb,
mr.range[0].flags = IP_NAT_RANGE_MAP_IPS;
mr.range[0].min_ip = mr.range[0].max_ip = newip;
- *verdict = ip_nat_setup_info(ct, &mr, hooknum);
-
- return 1;
+ return ip_nat_setup_info(ct, &mr, hooknum);
}
-static int irc_data_fixup(const struct ip_ct_irc *ct_irc_info,
+static int irc_data_fixup(const struct ip_ct_irc_expect *ct_irc_info,
struct ip_conntrack *ct,
- unsigned int datalen,
struct sk_buff **pskb,
- enum ip_conntrack_info ctinfo)
+ enum ip_conntrack_info ctinfo,
+ struct ip_conntrack_expect *expect)
{
u_int32_t newip;
struct ip_conntrack_tuple t;
@@ -121,9 +106,9 @@ static int irc_data_fixup(const struct ip_ct_irc *ct_irc_info,
MUST_BE_LOCKED(&ip_irc_lock);
- DEBUGP("IRC_NAT: info (seq %u + %u) packet(seq %u + %u)\n",
- ct_irc_info->seq, ct_irc_info->len,
- ntohl(tcph->seq), datalen);
+ DEBUGP("IRC_NAT: info (seq %u + %u) in %u\n",
+ expect->seq, ct_irc_info->len,
+ ntohl(tcph->seq));
newip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;
@@ -133,13 +118,11 @@ static int irc_data_fixup(const struct ip_ct_irc *ct_irc_info,
only set in ip_conntrack_irc, with ip_irc_lock held
writable */
- t = ct->expected.tuple;
+ t = expect->tuple;
t.dst.ip = newip;
for (port = ct_irc_info->port; port != 0; port++) {
t.dst.u.tcp.port = htons(port);
- if (ip_conntrack_expect_related(ct, &t,
- &ct->expected.mask,
- NULL) == 0) {
+ if (ip_conntrack_change_expect(expect, &t) == 0) {
DEBUGP("using port %d", port);
break;
}
@@ -166,26 +149,28 @@ static int irc_data_fixup(const struct ip_ct_irc *ct_irc_info,
buffer, NIPQUAD(newip), port);
return ip_nat_mangle_tcp_packet(pskb, ct, ctinfo,
- ct_irc_info->seq - ntohl(tcph->seq),
+ expect->seq - ntohl(tcph->seq),
ct_irc_info->len, buffer,
strlen(buffer));
}
static unsigned int help(struct ip_conntrack *ct,
+ struct ip_conntrack_expect *exp,
struct ip_nat_info *info,
enum ip_conntrack_info ctinfo,
- unsigned int hooknum, struct sk_buff **pskb)
+ unsigned int hooknum,
+ struct sk_buff **pskb)
{
struct iphdr *iph = (*pskb)->nh.iph;
struct tcphdr *tcph = (void *) iph + iph->ihl * 4;
unsigned int datalen;
int dir;
- int score;
- struct ip_ct_irc *ct_irc_info = &ct->help.ct_irc_info;
+ struct ip_ct_irc_expect *ct_irc_info;
- /* Delete SACK_OK on initial TCP SYNs. */
- if (tcph->syn && !tcph->ack)
- ip_nat_delete_sack(*pskb, tcph);
+ if (!exp)
+ DEBUGP("ip_nat_irc: no exp!!");
+
+ ct_irc_info = &exp->help.exp_irc_info;
/* Only mangle things once: original direction in POST_ROUTING
and reply direction on PRE_ROUTING. */
@@ -202,55 +187,35 @@ static unsigned int help(struct ip_conntrack *ct,
DEBUGP("got beyond not touching\n");
datalen = (*pskb)->len - iph->ihl * 4 - tcph->doff * 4;
- score = 0;
LOCK_BH(&ip_irc_lock);
- if (ct_irc_info->len) {
- DEBUGP("got beyond ct_irc_info->len\n");
-
- /* If it's in the right range... */
- score += between(ct_irc_info->seq, ntohl(tcph->seq),
- ntohl(tcph->seq) + datalen);
- score += between(ct_irc_info->seq + ct_irc_info->len,
- ntohl(tcph->seq),
- ntohl(tcph->seq) + datalen);
- if (score == 1) {
- /* Half a match? This means a partial retransmisison.
- It's a cracker being funky. */
- if (net_ratelimit()) {
- printk
- ("IRC_NAT: partial packet %u/%u in %u/%u\n",
- ct_irc_info->seq, ct_irc_info->len,
- ntohl(tcph->seq),
- ntohl(tcph->seq) + datalen);
- }
+ /* Check wether the whole IP/address pattern is carried in the payload */
+ if (between(exp->seq + ct_irc_info->len,
+ ntohl(tcph->seq),
+ ntohl(tcph->seq) + datalen)) {
+ if (!irc_data_fixup(ct_irc_info, ct, pskb, ctinfo, exp)) {
UNLOCK_BH(&ip_irc_lock);
return NF_DROP;
- } else if (score == 2) {
- DEBUGP("IRC_NAT: score=2, calling fixup\n");
- if (!irc_data_fixup(ct_irc_info, ct, datalen,
- pskb, ctinfo)) {
- UNLOCK_BH(&ip_irc_lock);
- return NF_DROP;
- }
- /* skb may have been reallocated */
- iph = (*pskb)->nh.iph;
- tcph = (void *) iph + iph->ihl * 4;
}
+ } else {
+ /* Half a match? This means a partial retransmisison.
+ It's a cracker being funky. */
+ if (net_ratelimit()) {
+ printk
+ ("IRC_NAT: partial packet %u/%u in %u/%u\n",
+ exp->seq, ct_irc_info->len,
+ ntohl(tcph->seq),
+ ntohl(tcph->seq) + datalen);
+ }
+ UNLOCK_BH(&ip_irc_lock);
+ return NF_DROP;
}
-
UNLOCK_BH(&ip_irc_lock);
- ip_nat_seq_adjust(*pskb, ct, ctinfo);
-
return NF_ACCEPT;
}
static struct ip_nat_helper ip_nat_irc_helpers[MAX_PORTS];
-static char ip_nih_names[MAX_PORTS][6];
-
-static struct ip_nat_expect irc_expect
- = { {NULL, NULL}, irc_nat_expected };
-
+static char irc_names[MAX_PORTS][10];
/* This function is intentionally _NOT_ defined as __exit, because
* it is needed by init() */
@@ -262,52 +227,54 @@ static void fini(void)
DEBUGP("ip_nat_irc: unregistering helper for port %d\n",
ports[i]);
ip_nat_helper_unregister(&ip_nat_irc_helpers[i]);
- }
- ip_nat_expect_unregister(&irc_expect);
+ }
}
+
static int __init init(void)
{
- int ret;
+ int ret = 0;
int i;
struct ip_nat_helper *hlpr;
char *tmpname;
- ret = ip_nat_expect_register(&irc_expect);
- if (ret == 0) {
-
- if (ports[0] == 0) {
- ports[0] = 6667;
- }
+ if (ports[0] == 0) {
+ ports[0] = IRC_PORT;
+ }
- for (i = 0; (i < MAX_PORTS) && ports[i] != 0; i++) {
- hlpr = &ip_nat_irc_helpers[i];
- memset(hlpr, 0,
- sizeof(struct ip_nat_helper));
-
- hlpr->tuple.dst.protonum = IPPROTO_TCP;
- hlpr->tuple.src.u.tcp.port = htons(ports[i]);
- hlpr->mask.src.u.tcp.port = 0xFFFF;
- hlpr->mask.dst.protonum = 0xFFFF;
- hlpr->help = help;
-
- tmpname = &ip_nih_names[i][0];
- sprintf(tmpname, "irc%2.2d", i);
-
- hlpr->name = tmpname;
- DEBUGP
- ("ip_nat_irc: Trying to register helper for port %d: name %s\n",
- ports[i], hlpr->name);
- ret = ip_nat_helper_register(hlpr);
-
- if (ret) {
- printk
- ("ip_nat_irc: error registering helper for port %d\n",
- ports[i]);
- fini();
- return 1;
- }
- ports_c++;
+ for (i = 0; (i < MAX_PORTS) && ports[i] != 0; i++) {
+ hlpr = &ip_nat_irc_helpers[i];
+ memset(hlpr, 0,
+ sizeof(struct ip_nat_helper));
+
+ hlpr->tuple.dst.protonum = IPPROTO_TCP;
+ hlpr->tuple.src.u.tcp.port = htons(ports[i]);
+ hlpr->mask.src.u.tcp.port = 0xFFFF;
+ hlpr->mask.dst.protonum = 0xFFFF;
+ hlpr->help = help;
+ hlpr->flags = 0;
+ hlpr->me = THIS_MODULE;
+ hlpr->expect = irc_nat_expected;
+
+ tmpname = &irc_names[i][0];
+ if (ports[i] == IRC_PORT)
+ sprintf(tmpname, "irc");
+ else
+ sprintf(tmpname, "irc-%d", i);
+ hlpr->name = tmpname;
+
+ DEBUGP
+ ("ip_nat_irc: Trying to register helper for port %d: name %s\n",
+ ports[i], hlpr->name);
+ ret = ip_nat_helper_register(hlpr);
+
+ if (ret) {
+ printk
+ ("ip_nat_irc: error registering helper for port %d\n",
+ ports[i]);
+ fini();
+ return 1;
}
+ ports_c++;
}
return ret;
}
diff --git a/net/ipv4/netfilter/ip_nat_proto_tcp.c b/net/ipv4/netfilter/ip_nat_proto_tcp.c
index ff25da08cd097..d27959ea3c414 100644
--- a/net/ipv4/netfilter/ip_nat_proto_tcp.c
+++ b/net/ipv4/netfilter/ip_nat_proto_tcp.c
@@ -4,7 +4,6 @@
#include <linux/ip.h>
#include <linux/tcp.h>
#include <linux/if.h>
-
#include <linux/netfilter_ipv4/ip_nat.h>
#include <linux/netfilter_ipv4/ip_nat_rule.h>
#include <linux/netfilter_ipv4/ip_nat_protocol.h>
diff --git a/net/ipv4/netfilter/ip_nat_proto_unknown.c b/net/ipv4/netfilter/ip_nat_proto_unknown.c
index 0e39070368f9a..a2b5de683dcea 100644
--- a/net/ipv4/netfilter/ip_nat_proto_unknown.c
+++ b/net/ipv4/netfilter/ip_nat_proto_unknown.c
@@ -1,5 +1,5 @@
/* The "unknown" protocol. This is what is used for protocols we
- * don't understand. It's returned by find_proto().
+ * don't understand. It's returned by ip_ct_find_proto().
*/
#include <linux/types.h>
diff --git a/net/ipv4/netfilter/ip_nat_rule.c b/net/ipv4/netfilter/ip_nat_rule.c
index 9eacf45d908c8..6ee71c8402424 100644
--- a/net/ipv4/netfilter/ip_nat_rule.c
+++ b/net/ipv4/netfilter/ip_nat_rule.c
@@ -106,8 +106,6 @@ static struct ipt_table nat_table
= { { NULL, NULL }, "nat", &nat_initial_table.repl,
NAT_VALID_HOOKS, RW_LOCK_UNLOCKED, NULL, THIS_MODULE };
-LIST_HEAD(nat_expect_list);
-
/* Source NAT */
static unsigned int ipt_snat_target(struct sk_buff **pskb,
unsigned int hooknum,
@@ -254,19 +252,6 @@ alloc_null_binding(struct ip_conntrack *conntrack,
return ip_nat_setup_info(conntrack, &mr, hooknum);
}
-static inline int call_expect(const struct ip_nat_expect *i,
- struct sk_buff **pskb,
- unsigned int hooknum,
- struct ip_conntrack *ct,
- struct ip_nat_info *info,
- struct ip_conntrack *master,
- struct ip_nat_info *masterinfo,
- unsigned int *verdict)
-{
- return i->expect(pskb, hooknum, ct, info, master, masterinfo,
- verdict);
-}
-
int ip_nat_rule_find(struct sk_buff **pskb,
unsigned int hooknum,
const struct net_device *in,
@@ -276,19 +261,8 @@ int ip_nat_rule_find(struct sk_buff **pskb,
{
int ret;
- /* Master won't vanish while this ctrack still alive */
- if (ct->master.master) {
- struct ip_conntrack *master;
-
- master = (struct ip_conntrack *)ct->master.master;
- if (LIST_FIND(&nat_expect_list,
- call_expect,
- struct ip_nat_expect *,
- pskb, hooknum, ct, info,
- master, &master->nat.info, &ret))
- return ret;
- }
ret = ipt_do_table(pskb, hooknum, in, out, &nat_table, NULL);
+
if (ret == NF_ACCEPT) {
if (!(info->initialized & (1 << HOOK2MANIP(hooknum))))
/* NUL mapping */
@@ -297,22 +271,6 @@ int ip_nat_rule_find(struct sk_buff **pskb,
return ret;
}
-int ip_nat_expect_register(struct ip_nat_expect *expect)
-{
- WRITE_LOCK(&ip_nat_lock);
- list_prepend(&nat_expect_list, expect);
- WRITE_UNLOCK(&ip_nat_lock);
-
- return 0;
-}
-
-void ip_nat_expect_unregister(struct ip_nat_expect *expect)
-{
- WRITE_LOCK(&ip_nat_lock);
- LIST_DELETE(&nat_expect_list, expect);
- WRITE_UNLOCK(&ip_nat_lock);
-}
-
static struct ipt_target ipt_snat_reg
= { { NULL, NULL }, "SNAT", ipt_snat_target, ipt_snat_checkentry, NULL };
static struct ipt_target ipt_dnat_reg
diff --git a/net/ipv4/netfilter/ip_nat_snmp_basic.c b/net/ipv4/netfilter/ip_nat_snmp_basic.c
index eaf18396fd95a..f1f22e6ef446f 100644
--- a/net/ipv4/netfilter/ip_nat_snmp_basic.c
+++ b/net/ipv4/netfilter/ip_nat_snmp_basic.c
@@ -1244,6 +1244,7 @@ static int snmp_translate(struct ip_conntrack *ct,
* NAT helper function, packets arrive here from NAT code.
*/
static unsigned int nat_help(struct ip_conntrack *ct,
+ struct ip_conntrack_expect *exp,
struct ip_nat_info *info,
enum ip_conntrack_info ctinfo,
unsigned int hooknum,
@@ -1304,19 +1305,27 @@ static unsigned int nat_help(struct ip_conntrack *ct,
return NF_DROP;
}
-static struct ip_nat_helper snmp = { { NULL, NULL },
+static struct ip_nat_helper snmp = {
+ { NULL, NULL },
+ "snmp",
+ IP_NAT_HELPER_F_STANDALONE,
+ THIS_MODULE,
{ { 0, { __constant_htons(SNMP_PORT) } },
{ 0, { 0 }, IPPROTO_UDP } },
{ { 0, { 0xFFFF } },
{ 0, { 0 }, 0xFFFF } },
- nat_help, "snmp" };
+ nat_help, NULL };
-static struct ip_nat_helper snmp_trap = { { NULL, NULL },
+static struct ip_nat_helper snmp_trap = {
+ { NULL, NULL },
+ "snmp_trap",
+ IP_NAT_HELPER_F_STANDALONE,
+ THIS_MODULE,
{ { 0, { __constant_htons(SNMP_TRAP_PORT) } },
{ 0, { 0 }, IPPROTO_UDP } },
{ { 0, { 0xFFFF } },
{ 0, { 0 }, 0xFFFF } },
- nat_help, "snmp_trap" };
+ nat_help, NULL };
/*****************************************************************************
*
diff --git a/net/ipv4/netfilter/ip_nat_standalone.c b/net/ipv4/netfilter/ip_nat_standalone.c
index b0d2997032696..f30fa72b0f45e 100644
--- a/net/ipv4/netfilter/ip_nat_standalone.c
+++ b/net/ipv4/netfilter/ip_nat_standalone.c
@@ -5,7 +5,12 @@
*/
/* (c) 1999 Paul `Rusty' Russell. Licenced under the GNU General
- Public Licence. */
+ * Public Licence.
+ *
+ * 23 Apr 2001: Harald Welte <laforge@gnumonks.org>
+ * - new API and handling of conntrack/nat helpers
+ * - now capable of multiple expectations for one master
+ * */
#include <linux/config.h>
#include <linux/types.h>
@@ -45,6 +50,15 @@
: ((hooknum) == NF_IP_LOCAL_IN ? "LOCAL_IN" \
: "*ERROR*")))
+static inline int call_expect(struct ip_conntrack *master,
+ struct sk_buff **pskb,
+ unsigned int hooknum,
+ struct ip_conntrack *ct,
+ struct ip_nat_info *info)
+{
+ return master->nat.info.helper->expect(pskb, hooknum, ct, info);
+}
+
static unsigned int
ip_nat_fn(unsigned int hooknum,
struct sk_buff **pskb,
@@ -111,8 +125,16 @@ ip_nat_fn(unsigned int hooknum,
int in_hashes = info->initialized;
unsigned int ret;
- ret = ip_nat_rule_find(pskb, hooknum, in, out,
- ct, info);
+ if (ct->master
+ && master_ct(ct)->nat.info.helper
+ && master_ct(ct)->nat.info.helper->expect) {
+ ret = call_expect(master_ct(ct), pskb,
+ hooknum, ct, info);
+ } else {
+ ret = ip_nat_rule_find(pskb, hooknum, in, out,
+ ct, info);
+ }
+
if (ret != NF_ACCEPT) {
WRITE_UNLOCK(&ip_nat_lock);
return ret;
@@ -335,11 +357,7 @@ EXPORT_SYMBOL(ip_nat_protocol_register);
EXPORT_SYMBOL(ip_nat_protocol_unregister);
EXPORT_SYMBOL(ip_nat_helper_register);
EXPORT_SYMBOL(ip_nat_helper_unregister);
-EXPORT_SYMBOL(ip_nat_expect_register);
-EXPORT_SYMBOL(ip_nat_expect_unregister);
EXPORT_SYMBOL(ip_nat_cheat_check);
EXPORT_SYMBOL(ip_nat_mangle_tcp_packet);
-EXPORT_SYMBOL(ip_nat_seq_adjust);
-EXPORT_SYMBOL(ip_nat_delete_sack);
EXPORT_SYMBOL(ip_nat_used_tuple);
MODULE_LICENSE("GPL");
diff --git a/net/ipv4/netfilter/ip_queue.c b/net/ipv4/netfilter/ip_queue.c
index 0894fc63c7a25..e9932533f87ad 100644
--- a/net/ipv4/netfilter/ip_queue.c
+++ b/net/ipv4/netfilter/ip_queue.c
@@ -464,7 +464,7 @@ static int netlink_send_peer(ipq_queue_element_t *e)
return netlink_unicast(nfnl, skb, nlq->peer.pid, MSG_DONTWAIT);
}
-#define RCV_SKB_FAIL(err) do { netlink_ack(skb, nlh, (err)); return; } while (0);
+#define RCV_SKB_FAIL(err) do { netlink_ack(skb, nlh, (err)); return; } while (0)
static __inline__ void netlink_receive_user_skb(struct sk_buff *skb)
{
diff --git a/net/ipv4/netfilter/ipt_ULOG.c b/net/ipv4/netfilter/ipt_ULOG.c
index a978874f48496..3f5e6b0748548 100644
--- a/net/ipv4/netfilter/ipt_ULOG.c
+++ b/net/ipv4/netfilter/ipt_ULOG.c
@@ -61,7 +61,7 @@ MODULE_LICENSE("GPL");
#define DEBUGP(format, args...)
#endif
-#define PRINTR(format, args...) do { if (net_ratelimit()) printk(format, ## args); } while (0);
+#define PRINTR(format, args...) do { if (net_ratelimit()) printk(format, ## args); } while (0)
MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
MODULE_DESCRIPTION("IP tables userspace logging module");
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index 110ba12eb3dfe..098312a7bf6af 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -583,7 +583,7 @@ static int rt_garbage_collect(void)
if (atomic_read(&ipv4_dst_ops.entries) < ip_rt_max_size)
goto out;
if (net_ratelimit())
- printk("dst cache overflow\n");
+ printk(KERN_WARNING "dst cache overflow\n");
return 1;
work_done:
@@ -657,7 +657,7 @@ restart:
}
if (net_ratelimit())
- printk("Neighbour table overflow.\n");
+ printk(KERN_WARNING "Neighbour table overflow.\n");
rt_drop(rt);
return -ENOBUFS;
}
@@ -667,8 +667,8 @@ restart:
#if RT_CACHE_DEBUG >= 2
if (rt->u.rt_next) {
struct rtable *trt;
- printk("rt_cache @%02x: %u.%u.%u.%u", hash,
- NIPQUAD(rt->rt_dst));
+ printk(KERN_DEBUG "rt_cache @%02x: %u.%u.%u.%u", hash,
+ NIPQUAD(rt->rt_dst));
for (trt = rt->u.rt_next; trt; trt = trt->u.rt_next)
printk(" . %u.%u.%u.%u", NIPQUAD(trt->rt_dst));
printk("\n");
@@ -2454,7 +2454,7 @@ void __init ip_rt_init(void)
#ifdef CONFIG_NET_CLS_ROUTE
for (order = 0;
- (PAGE_SIZE << order) < 256 * sizeof(ip_rt_acct) * NR_CPUS; order++)
+ (PAGE_SIZE << order) < 256 * sizeof(struct ip_rt_acct) * NR_CPUS; order++)
/* NOTHING */;
ip_rt_acct = (struct ip_rt_acct *)__get_free_pages(GFP_KERNEL, order);
if (!ip_rt_acct)
@@ -2487,7 +2487,7 @@ void __init ip_rt_init(void)
if (!rt_hash_table)
panic("Failed to allocate IP route cache hash table\n");
- printk("IP: routing cache hash table of %u buckets, %ldKbytes\n",
+ printk(KERN_INFO "IP: routing cache hash table of %u buckets, %ldKbytes\n",
rt_hash_mask,
(long) (rt_hash_mask * sizeof(struct rt_hash_bucket)) / 1024);
diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c
index 1e0fb441c74cb..b3b60b30c1826 100644
--- a/net/ipv4/sysctl_net_ipv4.c
+++ b/net/ipv4/sysctl_net_ipv4.c
@@ -219,6 +219,8 @@ ctl_table ipv4_table[] = {
&sysctl_icmp_ratelimit, sizeof(int), 0644, NULL, &proc_dointvec},
{NET_IPV4_ICMP_RATEMASK, "icmp_ratemask",
&sysctl_icmp_ratemask, sizeof(int), 0644, NULL, &proc_dointvec},
+ {NET_TCP_TW_REUSE, "tcp_tw_reuse",
+ &sysctl_tcp_tw_reuse, sizeof(int), 0644, NULL, &proc_dointvec},
{0}
};
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index 286c18ca2ee48..78b0c6fb03dfd 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -1792,7 +1792,7 @@ void tcp_destroy_sock(struct sock *sk)
#ifdef TCP_DEBUG
if (sk->zapped) {
- printk("TCP: double destroy sk=%p\n", sk);
+ printk(KERN_DEBUG "TCP: double destroy sk=%p\n", sk);
sock_hold(sk);
}
sk->zapped = 1;
@@ -2558,7 +2558,7 @@ void __init tcp_init(void)
sysctl_tcp_rmem[2] = 2*43689;
}
- printk("TCP: Hash tables configured (established %d bind %d)\n",
+ printk(KERN_INFO "TCP: Hash tables configured (established %d bind %d)\n",
tcp_ehash_size<<1, tcp_bhash_size);
tcpdiag_init();
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index a397d84e00447..9755d32c27f33 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -124,9 +124,6 @@ static __inline__ void tcp_measure_rcv_mss(struct tcp_opt *tp, struct sk_buff *s
len = skb->len;
if (len >= tp->ack.rcv_mss) {
tp->ack.rcv_mss = len;
- /* Dubious? Rather, it is final cut. 8) */
- if (tcp_flag_word(skb->h.th)&TCP_REMNANT)
- tp->ack.pending |= TCP_ACK_PUSHED;
} else {
/* Otherwise, we make more careful check taking into account,
* that SACKs block is variable.
@@ -463,7 +460,7 @@ static __inline__ void tcp_rtt_estimator(struct tcp_opt *tp, __u32 mrtt)
if (after(tp->snd_una, tp->rtt_seq)) {
if (tp->mdev_max < tp->rttvar)
tp->rttvar -= (tp->rttvar-tp->mdev_max)>>2;
- tp->rtt_seq = tp->snd_una;
+ tp->rtt_seq = tp->snd_nxt;
tp->mdev_max = TCP_RTO_MIN;
}
} else {
@@ -1769,6 +1766,7 @@ static int tcp_clean_rtx_queue(struct sock *sk)
acked |= FLAG_DATA_ACKED;
} else {
acked |= FLAG_SYN_ACKED;
+ tp->retrans_stamp = 0;
}
if (sacked) {
@@ -3873,6 +3871,7 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
switch (sk->state) {
case TCP_CLOSE_WAIT:
case TCP_CLOSING:
+ case TCP_LAST_ACK:
if (!before(TCP_SKB_CB(skb)->seq, tp->rcv_nxt))
break;
case TCP_FIN_WAIT1:
@@ -3890,7 +3889,6 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
}
}
/* Fall through */
- case TCP_LAST_ACK:
case TCP_ESTABLISHED:
tcp_data_queue(sk, skb);
queued = 1;
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index b7049e4294afb..b839d36b93f18 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -64,6 +64,8 @@
#include <linux/ipsec.h>
extern int sysctl_ip_dynaddr;
+extern int sysctl_ip_default_ttl;
+int sysctl_tcp_tw_reuse = 0;
/* Check TCP sequence numbers in ICMP packets. */
#define ICMP_MIN_LENGTH 8
@@ -163,18 +165,18 @@ __inline__ void tcp_inherit_port(struct sock *sk, struct sock *child)
local_bh_enable();
}
-static inline void tcp_bind_hash(struct sock *sk, struct tcp_bind_bucket *tb, unsigned short snum)
-{
- inet_sk(sk)->num = snum;
+static inline void tcp_bind_hash(struct sock *sk, struct tcp_bind_bucket *tb, unsigned short snum)
+{
+ inet_sk(sk)->num = snum;
if ((sk->bind_next = tb->owners) != NULL)
tb->owners->bind_pprev = &sk->bind_next;
tb->owners = sk;
sk->bind_pprev = &tb->owners;
sk->prev = (struct sock *) tb;
-}
+}
static inline int tcp_bind_conflict(struct sock *sk, struct tcp_bind_bucket *tb)
-{
+{
struct inet_opt *inet = inet_sk(sk);
struct sock *sk2 = tb->owners;
int sk_reuse = sk->reuse;
@@ -193,8 +195,8 @@ static inline int tcp_bind_conflict(struct sock *sk, struct tcp_bind_bucket *tb)
}
}
}
- return sk2 != NULL;
-}
+ return sk2 != NULL;
+}
/* Obtain a reference to a local port for the given sock,
* if snum is zero it means select any available local port.
@@ -247,12 +249,14 @@ static int tcp_v4_get_port(struct sock *sk, unsigned short snum)
break;
}
if (tb != NULL && tb->owners != NULL) {
- if (tb->fastreuse != 0 && sk->reuse != 0 && sk->state != TCP_LISTEN) {
+ if (sk->reuse > 1)
+ goto success;
+ if (tb->fastreuse > 0 && sk->reuse != 0 && sk->state != TCP_LISTEN) {
goto success;
} else {
- ret = 1;
+ ret = 1;
if (tcp_bind_conflict(sk, tb))
- goto fail_unlock;
+ goto fail_unlock;
}
}
ret = 1;
@@ -269,7 +273,7 @@ static int tcp_v4_get_port(struct sock *sk, unsigned short snum)
tb->fastreuse = 0;
success:
if (sk->prev == NULL)
- tcp_bind_hash(sk, tb, snum);
+ tcp_bind_hash(sk, tb, snum);
BUG_TRAP(sk->prev == (struct sock *) tb);
ret = 0;
@@ -341,13 +345,13 @@ void tcp_listen_wlock(void)
}
}
-static __inline__ void __tcp_v4_hash(struct sock *sk)
+static __inline__ void __tcp_v4_hash(struct sock *sk, const int listen_possible)
{
struct sock **skp;
rwlock_t *lock;
BUG_TRAP(sk->pprev==NULL);
- if(sk->state == TCP_LISTEN) {
+ if(listen_possible && sk->state == TCP_LISTEN) {
skp = &tcp_listening_hash[tcp_sk_listen_hashfn(sk)];
lock = &tcp_lhash_lock;
tcp_listen_wlock();
@@ -362,7 +366,7 @@ static __inline__ void __tcp_v4_hash(struct sock *sk)
sk->pprev = skp;
sock_prot_inc_use(sk->prot);
write_unlock(lock);
- if (sk->state == TCP_LISTEN)
+ if (listen_possible && sk->state == TCP_LISTEN)
wake_up(&tcp_lhash_wait);
}
@@ -370,7 +374,7 @@ static void tcp_v4_hash(struct sock *sk)
{
if (sk->state != TCP_CLOSE) {
local_bh_disable();
- __tcp_v4_hash(sk);
+ __tcp_v4_hash(sk, 1);
local_bh_enable();
}
}
@@ -379,6 +383,9 @@ void tcp_unhash(struct sock *sk)
{
rwlock_t *lock;
+ if (!sk->pprev)
+ goto ende;
+
if (sk->state == TCP_LISTEN) {
local_bh_disable();
tcp_listen_wlock();
@@ -397,6 +404,8 @@ void tcp_unhash(struct sock *sk)
sock_prot_dec_use(sk->prot);
}
write_unlock_bh(lock);
+
+ ende:
if (sk->state == TCP_LISTEN)
wake_up(&tcp_lhash_wait);
}
@@ -538,20 +547,22 @@ static inline __u32 tcp_v4_init_sequence(struct sock *sk, struct sk_buff *skb)
skb->h.th->source);
}
-static int tcp_v4_check_established(struct sock *sk)
+/* called with local bh disabled */
+static int __tcp_v4_check_established(struct sock *sk, __u16 lport,
+ struct tcp_tw_bucket **twp)
{
struct inet_opt *inet = inet_sk(sk);
u32 daddr = inet->rcv_saddr;
u32 saddr = inet->daddr;
int dif = sk->bound_dev_if;
TCP_V4_ADDR_COOKIE(acookie, saddr, daddr)
- __u32 ports = TCP_COMBINED_PORTS(inet->dport, inet->num);
- int hash = tcp_hashfn(daddr, inet->num, saddr, inet->dport);
+ __u32 ports = TCP_COMBINED_PORTS(inet->dport, lport);
+ int hash = tcp_hashfn(daddr, lport, saddr, inet->dport);
struct tcp_ehash_bucket *head = &tcp_ehash[hash];
struct sock *sk2, **skp;
struct tcp_tw_bucket *tw;
- write_lock_bh(&head->lock);
+ write_lock(&head->lock);
/* Check TIME-WAIT sockets first. */
for(skp = &(head + tcp_ehash_size)->chain; (sk2=*skp) != NULL;
@@ -575,7 +586,9 @@ static int tcp_v4_check_established(struct sock *sk)
fall back to VJ's scheme and use initial
timestamp retrieved from peer table.
*/
- if (tw->ts_recent_stamp) {
+ if (tw->ts_recent_stamp &&
+ (!twp || (sysctl_tcp_tw_reuse &&
+ xtime.tv_sec - tw->ts_recent_stamp > 1))) {
if ((tp->write_seq =
tw->snd_nxt + 65535 + 2) == 0)
tp->write_seq = 1;
@@ -597,6 +610,10 @@ static int tcp_v4_check_established(struct sock *sk)
}
unique:
+ /* Must record num and sport now. Otherwise we will see
+ * in hash table socket with a funny identity. */
+ inet->num = lport;
+ inet->sport = htons(lport);
BUG_TRAP(sk->pprev==NULL);
if ((sk->next = *skp) != NULL)
(*skp)->pprev = &sk->next;
@@ -605,15 +622,16 @@ unique:
sk->pprev = skp;
sk->hashent = hash;
sock_prot_inc_use(sk->prot);
- write_unlock_bh(&head->lock);
+ write_unlock(&head->lock);
- if (tw) {
+ if (twp) {
+ *twp = tw;
+ NET_INC_STATS_BH(TimeWaitRecycled);
+ } else if (tw) {
/* Silly. Should hash-dance instead... */
- local_bh_disable();
tcp_tw_deschedule(tw);
tcp_timewait_kill(tw);
NET_INC_STATS_BH(TimeWaitRecycled);
- local_bh_enable();
tcp_tw_put(tw);
}
@@ -621,34 +639,120 @@ unique:
return 0;
not_unique:
- write_unlock_bh(&head->lock);
+ write_unlock(&head->lock);
return -EADDRNOTAVAIL;
}
-/* Hash SYN-SENT socket to established hash table after
- * checking that it is unique. Note, that without kernel lock
- * we MUST make these two operations atomically.
- *
- * Optimization: if it is bound and tcp_bind_bucket has the only
- * owner (us), we need not to scan established bucket.
+/*
+ * Bind a port for a connect operation and hash it.
*/
-
-int tcp_v4_hash_connecting(struct sock *sk)
+static int tcp_v4_hash_connect(struct sock *sk)
{
unsigned short snum = inet_sk(sk)->num;
- struct tcp_bind_hashbucket *head = &tcp_bhash[tcp_bhashfn(snum)];
- struct tcp_bind_bucket *tb = (struct tcp_bind_bucket *)sk->prev;
-
+ struct tcp_bind_hashbucket *head;
+ struct tcp_bind_bucket *tb;
+
+ if (snum == 0) {
+ int rover;
+ int low = sysctl_local_port_range[0];
+ int high = sysctl_local_port_range[1];
+ int remaining = (high - low) + 1;
+ struct tcp_tw_bucket *tw = NULL;
+
+ local_bh_disable();
+
+ /* TODO. Actually it is not so bad idea to remove
+ * tcp_portalloc_lock before next submission to Linus.
+ * As soon as we touch this place at all it is time to think.
+ *
+ * Now it protects single _advisory_ variable tcp_port_rover,
+ * hence it is mostly useless.
+ * Code will work nicely if we just delete it, but
+ * I am afraid in contented case it will work not better or
+ * even worse: another cpu just will hit the same bucket
+ * and spin there.
+ * So some cpu salt could remove both contention and
+ * memory pingpong. Any ideas how to do this in a nice way?
+ */
+ spin_lock(&tcp_portalloc_lock);
+ rover = tcp_port_rover;
+
+ do {
+ rover++;
+ if ((rover < low) || (rover > high))
+ rover = low;
+ head = &tcp_bhash[tcp_bhashfn(rover)];
+ spin_lock(&head->lock);
+
+ /* Does not bother with rcv_saddr checks,
+ * because the established check is already
+ * unique enough.
+ */
+ for (tb = head->chain; tb; tb = tb->next) {
+ if (tb->port == rover) {
+ BUG_TRAP(tb->owners != NULL);
+ if (tb->fastreuse >= 0)
+ goto next_port;
+ if (!__tcp_v4_check_established(sk, rover, &tw))
+ goto ok;
+ goto next_port;
+ }
+ }
+
+ tb = tcp_bucket_create(head, rover);
+ if (!tb) {
+ spin_unlock(&head->lock);
+ break;
+ }
+ tb->fastreuse = -1;
+ goto ok;
+
+ next_port:
+ spin_unlock(&head->lock);
+ } while (--remaining > 0);
+ tcp_port_rover = rover;
+ spin_unlock(&tcp_portalloc_lock);
+
+ local_bh_enable();
+
+ return -EADDRNOTAVAIL;
+
+ ok:
+ /* All locks still held and bhs disabled */
+ tcp_port_rover = rover;
+ spin_unlock(&tcp_portalloc_lock);
+
+ tcp_bind_hash(sk, tb, rover);
+ if (!sk->pprev) {
+ inet_sk(sk)->sport = htons(rover);
+ __tcp_v4_hash(sk, 0);
+ }
+ spin_unlock(&head->lock);
+
+ if (tw) {
+ tcp_tw_deschedule(tw);
+ tcp_timewait_kill(tw);
+ tcp_tw_put(tw);
+ }
+
+ local_bh_enable();
+ return 0;
+ }
+
+ head = &tcp_bhash[tcp_bhashfn(snum)];
+ tb = (struct tcp_bind_bucket *)sk->prev;
spin_lock_bh(&head->lock);
if (tb->owners == sk && sk->bind_next == NULL) {
- __tcp_v4_hash(sk);
+ __tcp_v4_hash(sk, 0);
spin_unlock_bh(&head->lock);
return 0;
} else {
- spin_unlock_bh(&head->lock);
-
+ int ret;
+ spin_unlock(&head->lock);
/* No definite answer... Walk to established hash table */
- return tcp_v4_check_established(sk);
+ ret = __tcp_v4_check_established(sk, snum, NULL);
+ local_bh_enable();
+ return ret;
}
}
@@ -658,7 +762,6 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
struct inet_opt *inet = inet_sk(sk);
struct tcp_opt *tp = tcp_sk(sk);
struct sockaddr_in *usin = (struct sockaddr_in *) uaddr;
- struct sk_buff *buff;
struct rtable *rt;
u32 daddr, nexthop;
int tmp;
@@ -693,12 +796,6 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
if (!inet->opt || !inet->opt->srr)
daddr = rt->rt_dst;
- err = -ENOBUFS;
- buff = alloc_skb(MAX_TCP_HEADER + 15, sk->allocation);
-
- if (buff == NULL)
- goto failure;
-
if (!inet->saddr)
inet->saddr = rt->rt_src;
inet->rcv_saddr = inet->saddr;
@@ -729,24 +826,38 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
inet->dport = usin->sin_port;
inet->daddr = daddr;
+ tp->ext_header_len = 0;
+ if (inet->opt)
+ tp->ext_header_len = inet->opt->optlen;
+
+ tp->mss_clamp = 536;
+
+ /* Socket identity is still unknown (sport may be zero).
+ * However we set state to SYN-SENT and not releasing socket
+ * lock select source port, enter ourselves into the hash tables and
+ * complete initalization after this.
+ */
+ tcp_set_state(sk, TCP_SYN_SENT);
+ err = tcp_v4_hash_connect(sk);
+ if (err)
+ goto failure;
+
if (!tp->write_seq)
tp->write_seq = secure_tcp_sequence_number(inet->saddr,
inet->daddr,
inet->sport,
usin->sin_port);
- tp->ext_header_len = 0;
- if (inet->opt)
- tp->ext_header_len = inet->opt->optlen;
inet->id = tp->write_seq ^ jiffies;
- tp->mss_clamp = 536;
+ err = tcp_connect(sk);
+ if (err)
+ goto failure;
- err = tcp_connect(sk, buff);
- if (err == 0)
- return 0;
+ return 0;
failure:
+ tcp_set_state(sk, TCP_CLOSE);
__sk_dst_reset(sk);
sk->route_caps = 0;
inet->dport = 0;
@@ -799,7 +910,6 @@ static void tcp_v4_synq_add(struct sock *sk, struct open_request *req)
req->expires = jiffies + TCP_TIMEOUT_INIT;
req->retrans = 0;
req->sk = NULL;
- req->index = h;
req->dl_next = lopt->syn_table[h];
write_lock(&tp->syn_wait_lock);
@@ -1092,6 +1202,7 @@ static void tcp_v4_send_reset(struct sk_buff *skb)
arg.n_iov = 1;
arg.csumoffset = offsetof(struct tcphdr, check) / 2;
+ inet_sk(tcp_socket->sk)->ttl = sysctl_ip_default_ttl;
ip_send_reply(tcp_socket->sk, skb, &arg, sizeof rth);
TCP_INC_STATS_BH(TcpOutSegs);
@@ -1478,7 +1589,7 @@ struct sock * tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
newtp->advmss = dst->advmss;
tcp_initialize_rcv_mss(newsk);
- __tcp_v4_hash(newsk);
+ __tcp_v4_hash(newsk, 0);
__tcp_inherit_port(sk, newsk);
return newsk;
@@ -1902,7 +2013,6 @@ struct tcp_func ipv4_specific = {
tcp_v4_rebuild_header,
tcp_v4_conn_request,
tcp_v4_syn_recv_sock,
- tcp_v4_hash_connecting,
tcp_v4_remember_stamp,
sizeof(struct iphdr),
diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c
index 318bceafa44ed..b429b96c3af6b 100644
--- a/net/ipv4/tcp_minisocks.c
+++ b/net/ipv4/tcp_minisocks.c
@@ -786,6 +786,8 @@ struct sock *tcp_create_openreq_child(struct sock *sk, struct open_request *req,
newtp->ack.last_seg_size = skb->len-newtp->tcp_header_len;
newtp->mss_clamp = req->mss;
TCP_ECN_openreq_child(newtp, req);
+
+ TCP_INC_STATS_BH(TcpPassiveOpens);
}
return newsk;
}
@@ -849,8 +851,38 @@ struct sock *tcp_check_req(struct sock *sk,struct sk_buff *skb,
/* Further reproduces section "SEGMENT ARRIVES"
for state SYN-RECEIVED of RFC793.
It is broken, however, it does not work only
- when SYNs are crossed, which is impossible in our
- case.
+ when SYNs are crossed.
+
+ You would think that SYN crossing is impossible here, since
+ we should have a SYN_SENT socket (from connect()) on our end,
+ but this is not true if the crossed SYNs were sent to both
+ ends by a malicious third party. We must defend against this,
+ and to do that we first verify the ACK (as per RFC793, page
+ 36) and reset if it is invalid. Is this a true full defense?
+ To convince ourselves, let us consider a way in which the ACK
+ test can still pass in this 'malicious crossed SYNs' case.
+ Malicious sender sends identical SYNs (and thus identical sequence
+ numbers) to both A and B:
+
+ A: gets SYN, seq=7
+ B: gets SYN, seq=7
+
+ By our good fortune, both A and B select the same initial
+ send sequence number of seven :-)
+
+ A: sends SYN|ACK, seq=7, ack_seq=8
+ B: sends SYN|ACK, seq=7, ack_seq=8
+
+ So we are now A eating this SYN|ACK, ACK test passes. So
+ does sequence test, SYN is truncated, and thus we consider
+ it a bare ACK.
+
+ If tp->defer_accept, we silently drop this bare ACK. Otherwise,
+ we create an established connection. Both ends (listening sockets)
+ accept the new incoming connection and try to talk to each other. 8-)
+
+ Note: This case is both harmless, and rare. Possibility is about the
+ same as us discovering intelligent life on another plant tomorrow.
But generally, we should (RFC lies!) to accept ACK
from SYNACK both here and in tcp_rcv_state_process().
@@ -862,6 +894,22 @@ struct sock *tcp_check_req(struct sock *sk,struct sk_buff *skb,
before attempt to create socket.
*/
+ /* RFC793 page 36: "If the connection is in any non-synchronized state ...
+ * and the incoming segment acknowledges something not yet
+ * sent (the segment carries an unaccaptable ACK) ...
+ * a reset is sent."
+ */
+ if (!(flg & TCP_FLAG_ACK))
+ return NULL;
+
+ /* Invalid ACK: reset will be sent by listening socket */
+ if (TCP_SKB_CB(skb)->ack_seq != req->snt_isn+1)
+ return sk;
+ /* Also, it would be not so bad idea to check rcv_tsecr, which
+ * is essentially ACK extension and too early or too late values
+ * should cause reset in unsynchronized states.
+ */
+
/* RFC793: "first check sequence number". */
if (paws_reject || !tcp_in_window(TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq,
@@ -891,19 +939,6 @@ struct sock *tcp_check_req(struct sock *sk,struct sk_buff *skb,
if (flg & (TCP_FLAG_RST|TCP_FLAG_SYN))
goto embryonic_reset;
- /* RFC793: "fifth check the ACK field" */
-
- if (!(flg & TCP_FLAG_ACK))
- return NULL;
-
- /* Invalid ACK: reset will be sent by listening socket */
- if (TCP_SKB_CB(skb)->ack_seq != req->snt_isn+1)
- return sk;
- /* Also, it would be not so bad idea to check rcv_tsecr, which
- * is essentially ACK extension and too early or too late values
- * should cause reset in unsynchronized states.
- */
-
/* If TCP_DEFER_ACCEPT is set, drop bare ACK. */
if (tp->defer_accept && TCP_SKB_CB(skb)->end_seq == req->rcv_isn+1) {
req->acked = 1;
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index 71b406306d247..2f95c9a138800 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -38,6 +38,7 @@
#include <net/tcp.h>
+#include <linux/compiler.h>
#include <linux/smp_lock.h>
/* People can turn this off for buggy TCP's found in printers etc. */
@@ -1156,14 +1157,14 @@ struct sk_buff * tcp_make_synack(struct sock *sk, struct dst_entry *dst,
return skb;
}
-int tcp_connect(struct sock *sk, struct sk_buff *buff)
+/*
+ * Do all connect socket setups that can be done AF independent.
+ */
+static inline void tcp_connect_init(struct sock *sk)
{
struct dst_entry *dst = __sk_dst_get(sk);
struct tcp_opt *tp = tcp_sk(sk);
- /* Reserve space for headers. */
- skb_reserve(buff, MAX_TCP_HEADER);
-
/* We'll fix this up when we get a response from the other end.
* See tcp_input.c:tcp_rcv_state_process case TCP_SYN_SENT.
*/
@@ -1190,14 +1191,6 @@ int tcp_connect(struct sock *sk, struct sk_buff *buff)
tp->rcv_ssthresh = tp->rcv_wnd;
- /* Socket identity change complete, no longer
- * in TCP_CLOSE, so enter ourselves into the
- * hash tables.
- */
- tcp_set_state(sk,TCP_SYN_SENT);
- if (tp->af_specific->hash_connecting(sk))
- goto err_out;
-
sk->err = 0;
sk->done = 0;
tp->snd_wnd = 0;
@@ -1211,6 +1204,24 @@ int tcp_connect(struct sock *sk, struct sk_buff *buff)
tp->rto = TCP_TIMEOUT_INIT;
tp->retransmits = 0;
tcp_clear_retrans(tp);
+}
+
+/*
+ * Build a SYN and send it off.
+ */
+int tcp_connect(struct sock *sk)
+{
+ struct tcp_opt *tp = tcp_sk(sk);
+ struct sk_buff *buff;
+
+ tcp_connect_init(sk);
+
+ buff = alloc_skb(MAX_TCP_HEADER + 15, sk->allocation);
+ if (unlikely(buff == NULL))
+ return -ENOBUFS;
+
+ /* Reserve space for headers. */
+ skb_reserve(buff, MAX_TCP_HEADER);
TCP_SKB_CB(buff)->flags = TCPCB_FLAG_SYN;
TCP_ECN_send_syn(tp, buff);
@@ -1233,11 +1244,6 @@ int tcp_connect(struct sock *sk, struct sk_buff *buff)
/* Timer for repeating the SYN until an answer. */
tcp_reset_xmit_timer(sk, TCP_TIME_RETRANS, tp->rto);
return 0;
-
-err_out:
- tcp_set_state(sk,TCP_CLOSE);
- kfree_skb(buff);
- return -EADDRNOTAVAIL;
}
/* Send out a delayed ack, the caller does the policy checking
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index b0b616b52a124..c67ea0c1191b9 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -725,6 +725,8 @@ int udp_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
struct inet_opt *inet = inet_sk(sk);
struct sockaddr_in *usin = (struct sockaddr_in *) uaddr;
struct rtable *rt;
+ u32 saddr;
+ int oif;
int err;
@@ -736,8 +738,16 @@ int udp_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
sk_dst_reset(sk);
- err = ip_route_connect(&rt, usin->sin_addr.s_addr, inet->saddr,
- RT_CONN_FLAGS(sk), sk->bound_dev_if);
+ oif = sk->bound_dev_if;
+ saddr = inet->saddr;
+ if (MULTICAST(usin->sin_addr.s_addr)) {
+ if (!oif)
+ oif = inet->mc_index;
+ if (!saddr)
+ saddr = inet->mc_addr;
+ }
+ err = ip_route_connect(&rt, usin->sin_addr.s_addr, saddr,
+ RT_CONN_FLAGS(sk), oif);
if (err)
return err;
if ((rt->rt_flags&RTCF_BROADCAST) && !sk->broadcast) {
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 397a86e3a6084..cdc2e011fc68c 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -62,6 +62,8 @@
#include <asm/uaccess.h>
+#define IPV6_MAX_ADDRESSES 16
+
/* Set to 3 to get tracing... */
#define ACONF_DEBUG 2
@@ -586,6 +588,18 @@ int ipv6_get_lladdr(struct net_device *dev, struct in6_addr *addr)
return err;
}
+int ipv6_count_addresses(struct inet6_dev *idev)
+{
+ int cnt = 0;
+ struct inet6_ifaddr *ifp;
+
+ read_lock_bh(&idev->lock);
+ for (ifp=idev->addr_list; ifp; ifp=ifp->if_next)
+ cnt++;
+ read_unlock_bh(&idev->lock);
+ return cnt;
+}
+
int ipv6_chk_addr(struct in6_addr *addr, struct net_device *dev)
{
struct inet6_ifaddr * ifp;
@@ -895,8 +909,12 @@ ok:
ifp = ipv6_get_ifaddr(&addr, dev);
if (ifp == NULL && valid_lft) {
- ifp = ipv6_add_addr(in6_dev, &addr, pinfo->prefix_len,
- addr_type&IPV6_ADDR_SCOPE_MASK, 0);
+ /* Do not allow to create too much of autoconfigured
+ * addresses; this would be too easy way to crash kernel.
+ */
+ if (ipv6_count_addresses(in6_dev) < IPV6_MAX_ADDRESSES)
+ ifp = ipv6_add_addr(in6_dev, &addr, pinfo->prefix_len,
+ addr_type&IPV6_ADDR_SCOPE_MASK, 0);
if (ifp == NULL) {
in6_dev_put(in6_dev);
diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
index 2231feb00c2fa..994e627963f19 100644
--- a/net/ipv6/ndisc.c
+++ b/net/ipv6/ndisc.c
@@ -361,7 +361,7 @@ void ndisc_send_na(struct net_device *dev, struct neighbour *neigh,
ipv6_addr_copy(&msg->target, solicited_addr);
if (inc_opt)
- ndisc_fill_option((void*)&msg->opt, ND_OPT_TARGET_LL_ADDR, dev->dev_addr, dev->addr_len);
+ ndisc_fill_option(msg->opt, ND_OPT_TARGET_LL_ADDR, dev->dev_addr, dev->addr_len);
/* checksum */
msg->icmph.icmp6_cksum = csum_ipv6_magic(solicited_addr, daddr, len,
@@ -422,7 +422,7 @@ void ndisc_send_ns(struct net_device *dev, struct neighbour *neigh,
ipv6_addr_copy(&msg->target, solicit);
if (send_llinfo)
- ndisc_fill_option((void*)&msg->opt, ND_OPT_SOURCE_LL_ADDR, dev->dev_addr, dev->addr_len);
+ ndisc_fill_option(msg->opt, ND_OPT_SOURCE_LL_ADDR, dev->dev_addr, dev->addr_len);
/* checksum */
msg->icmph.icmp6_cksum = csum_ipv6_magic(&skb->nh.ipv6h->saddr,
@@ -572,6 +572,11 @@ static void ndisc_router_discovery(struct sk_buff *skb)
printk(KERN_WARNING "ICMP RA: source address is not linklocal\n");
return;
}
+ if (optlen < 0) {
+ if (net_ratelimit())
+ printk(KERN_WARNING "ICMP RA: packet too short\n");
+ return;
+ }
/*
* set the RA_RECV flag in the interface
@@ -928,7 +933,7 @@ ndisc_recv_ns(struct in6_addr *saddr, struct sk_buff *skb)
u8 *opt;
opt = skb->h.raw;
- opt += sizeof(struct icmp6hdr) + sizeof(struct in6_addr);
+ opt += sizeof(struct nd_msg);
opt = ndisc_find_option(opt, skb->dev->addr_len+2, skb->tail - opt, ND_OPT_SOURCE_LL_ADDR);
return neigh_event_ns(&nd_tbl, opt, saddr, skb->dev);
@@ -936,12 +941,11 @@ ndisc_recv_ns(struct in6_addr *saddr, struct sk_buff *skb)
static __inline__ int ndisc_recv_na(struct neighbour *neigh, struct sk_buff *skb)
{
- struct nd_msg *msg = (struct nd_msg *) skb->h.raw;
u8 *opt;
+ struct nd_msg *msg = (struct nd_msg*) skb->h.raw;
- opt = skb->h.raw;
- opt += sizeof(struct icmp6hdr) + sizeof(struct in6_addr);
- opt = ndisc_find_option(opt, skb->dev->addr_len+2, skb->tail - opt, ND_OPT_TARGET_LL_ADDR);
+ opt = ndisc_find_option(msg->opt, skb->dev->addr_len+2,
+ skb->tail - msg->opt, ND_OPT_TARGET_LL_ADDR);
return neigh_update(neigh, opt,
msg->icmph.icmp6_solicited ? NUD_REACHABLE : NUD_STALE,
@@ -962,7 +966,6 @@ int ndisc_rcv(struct sk_buff *skb)
struct nd_msg *msg = (struct nd_msg *) skb->h.raw;
struct neighbour *neigh;
struct inet6_ifaddr *ifp;
- unsigned int payload_len;
__skb_push(skb, skb->data-skb->h.raw);
@@ -985,11 +988,9 @@ int ndisc_rcv(struct sk_buff *skb)
* (Some checking in ndisc_find_option)
*/
- payload_len = ntohs(skb->nh.ipv6h->payload_len);
switch (msg->icmph.icmp6_type) {
case NDISC_NEIGHBOUR_SOLICITATION:
- /* XXX: import nd_neighbor_solicit from glibc netinet/icmp6.h */
- if (payload_len < 8+16) {
+ if (skb->len < sizeof(struct nd_msg)) {
if (net_ratelimit())
printk(KERN_WARNING "ICMP NS: packet too short\n");
return 0;
@@ -1069,12 +1070,13 @@ int ndisc_rcv(struct sk_buff *skb)
neigh = ndisc_recv_ns(saddr, skb);
- if (neigh) {
+ if (neigh || !dev->hard_header) {
ndisc_send_na(dev, neigh, saddr, &ifp->addr,
ifp->idev->cnf.forwarding, 1,
ipv6_addr_type(&ifp->addr)&IPV6_ADDR_ANYCAST ? 0 : 1,
1);
- neigh_release(neigh);
+ if (neigh)
+ neigh_release(neigh);
}
}
in6_ifa_put(ifp);
@@ -1118,8 +1120,7 @@ int ndisc_rcv(struct sk_buff *skb)
return 0;
case NDISC_NEIGHBOUR_ADVERTISEMENT:
- /* XXX: import nd_neighbor_advert from glibc netinet/icmp6.h */
- if (payload_len < 16+8 ) {
+ if (skb->len < sizeof(struct nd_msg)) {
if (net_ratelimit())
printk(KERN_WARNING "ICMP NA: packet too short\n");
return 0;
@@ -1180,35 +1181,12 @@ int ndisc_rcv(struct sk_buff *skb)
break;
case NDISC_ROUTER_ADVERTISEMENT:
- /* XXX: import nd_router_advert from glibc netinet/icmp6.h */
- if (payload_len < 8+4+4) {
- if (net_ratelimit())
- printk(KERN_WARNING "ICMP RA: packet too short\n");
- return 0;
- }
ndisc_router_discovery(skb);
break;
case NDISC_REDIRECT:
- /* XXX: import nd_redirect from glibc netinet/icmp6.h */
- if (payload_len < 8+16+16) {
- if (net_ratelimit())
- printk(KERN_WARNING "ICMP redirect: packet too short\n");
- return 0;
- }
ndisc_redirect_rcv(skb);
break;
-
- case NDISC_ROUTER_SOLICITATION:
- /* No RS support in the kernel, but we do some required checks */
-
- /* XXX: import nd_router_solicit from glibc netinet/icmp6.h */
- if (payload_len < 8) {
- if (net_ratelimit())
- printk(KERN_WARNING "ICMP RS: packet too short\n");
- return 0;
- }
- break;
};
return 0;
diff --git a/net/ipv6/netfilter/ip6_queue.c b/net/ipv6/netfilter/ip6_queue.c
index 235533afd4fe9..07e58857d7775 100644
--- a/net/ipv6/netfilter/ip6_queue.c
+++ b/net/ipv6/netfilter/ip6_queue.c
@@ -518,7 +518,7 @@ static int netlink_send_peer(ip6q_queue_element_t *e)
return netlink_unicast(nfnl, skb, nlq6->peer.pid, MSG_DONTWAIT);
}
-#define RCV_SKB_FAIL(err) do { netlink_ack(skb, nlh, (err)); return; } while (0);
+#define RCV_SKB_FAIL(err) do { netlink_ack(skb, nlh, (err)); return; } while (0)
static __inline__ void netlink_receive_user_skb(struct sk_buff *skb)
{
diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c
index b3cc361c9ca28..389674e2c9c4b 100644
--- a/net/ipv6/sit.c
+++ b/net/ipv6/sit.c
@@ -517,7 +517,11 @@ static int ipip6_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
goto tx_error;
}
- mtu = rt->u.dst.pmtu - sizeof(struct iphdr);
+ if (tiph->frag_off)
+ mtu = rt->u.dst.pmtu - sizeof(struct iphdr);
+ else
+ mtu = skb->dst ? skb->dst->pmtu : dev->mtu;
+
if (mtu < 68) {
tunnel->stat.collisions++;
ip_rt_put(rt);
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index 7ff24c734daeb..27a49a6260ce2 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -136,7 +136,7 @@ static int tcp_v6_get_port(struct sock *sk, unsigned short snum)
break;
}
if (tb != NULL && tb->owners != NULL) {
- if (tb->fastreuse != 0 && sk->reuse != 0 && sk->state != TCP_LISTEN) {
+ if (tb->fastreuse > 0 && sk->reuse != 0 && sk->state != TCP_LISTEN) {
goto success;
} else {
struct ipv6_pinfo *np = inet6_sk(sk);
@@ -377,22 +377,22 @@ static __inline__ unsigned tcp_v6_synq_hash(struct in6_addr *raddr, u16 rport)
}
static struct open_request *tcp_v6_search_req(struct tcp_opt *tp,
- struct ipv6hdr *ip6h,
- struct tcphdr *th,
- int iif,
- struct open_request ***prevp)
+ struct open_request ***prevp,
+ __u16 rport,
+ struct in6_addr *raddr,
+ struct in6_addr *laddr,
+ int iif)
{
struct tcp_listen_opt *lopt = tp->listen_opt;
struct open_request *req, **prev;
- __u16 rport = th->source;
- for (prev = &lopt->syn_table[tcp_v6_synq_hash(&ip6h->saddr, rport)];
+ for (prev = &lopt->syn_table[tcp_v6_synq_hash(raddr, rport)];
(req = *prev) != NULL;
prev = &req->dl_next) {
if (req->rmt_port == rport &&
req->class->family == AF_INET6 &&
- !ipv6_addr_cmp(&req->af.v6_req.rmt_addr, &ip6h->saddr) &&
- !ipv6_addr_cmp(&req->af.v6_req.loc_addr, &ip6h->daddr) &&
+ !ipv6_addr_cmp(&req->af.v6_req.rmt_addr, raddr) &&
+ !ipv6_addr_cmp(&req->af.v6_req.loc_addr, laddr) &&
(!req->af.v6_req.iif || req->af.v6_req.iif == iif)) {
BUG_TRAP(req->sk == NULL);
*prevp = prev;
@@ -499,11 +499,21 @@ not_unique:
return -EADDRNOTAVAIL;
}
-static int tcp_v6_hash_connecting(struct sock *sk)
+static int tcp_v6_hash_connect(struct sock *sk)
{
- unsigned short snum = inet_sk(sk)->num;
- struct tcp_bind_hashbucket *head = &tcp_bhash[tcp_bhashfn(snum)];
- struct tcp_bind_bucket *tb = head->chain;
+ struct tcp_bind_hashbucket *head;
+ struct tcp_bind_bucket *tb;
+
+ /* XXX */
+ if (inet_sk(sk)->num == 0) {
+ int err = tcp_v6_get_port(sk, inet_sk(sk)->num);
+ if (err)
+ return err;
+ inet_sk(sk)->sport = htons(inet_sk(sk)->num);
+ }
+
+ head = &tcp_bhash[tcp_bhashfn(inet_sk(sk)->num)];
+ tb = head->chain;
spin_lock_bh(&head->lock);
@@ -534,7 +544,6 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
struct in6_addr saddr_buf;
struct flowi fl;
struct dst_entry *dst;
- struct sk_buff *buff;
int addr_type;
int err;
@@ -675,17 +684,12 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
tp->ext_header_len = np->opt->opt_flen + np->opt->opt_nflen;
tp->mss_clamp = IPV6_MIN_MTU - sizeof(struct tcphdr) - sizeof(struct ipv6hdr);
- err = -ENOBUFS;
- buff = alloc_skb(MAX_TCP_HEADER + 15, sk->allocation);
-
- if (buff == NULL)
- goto failure;
-
inet->dport = usin->sin6_port;
- /*
- * Init variables
- */
+ tcp_set_state(sk, TCP_SYN_SENT);
+ err = tcp_v6_hash_connect(sk);
+ if (err)
+ goto late_failure;
if (!tp->write_seq)
tp->write_seq = secure_tcpv6_sequence_number(np->saddr.s6_addr32,
@@ -693,10 +697,14 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
inet->sport,
inet->dport);
- err = tcp_connect(sk, buff);
- if (err == 0)
- return 0;
+ err = tcp_connect(sk);
+ if (err)
+ goto late_failure;
+
+ return 0;
+late_failure:
+ tcp_set_state(sk, TCP_CLOSE);
failure:
__sk_dst_reset(sk);
inet->dport = 0;
@@ -708,8 +716,6 @@ void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
int type, int code, int offset, __u32 info)
{
struct ipv6hdr *hdr = (struct ipv6hdr*)skb->data;
- struct in6_addr *saddr = &hdr->saddr;
- struct in6_addr *daddr = &hdr->daddr;
struct tcphdr *th = (struct tcphdr *)(skb->data+offset);
struct ipv6_pinfo *np;
struct sock *sk;
@@ -717,7 +723,7 @@ void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
struct tcp_opt *tp;
__u32 seq;
- sk = tcp_v6_lookup(daddr, th->dest, saddr, th->source, skb->dev->ifindex);
+ sk = tcp_v6_lookup(&hdr->daddr, th->dest, &hdr->saddr, th->source, skb->dev->ifindex);
if (sk == NULL) {
ICMP6_INC_STATS_BH(Icmp6InErrors);
@@ -790,15 +796,12 @@ void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
/* Might be for an open_request */
switch (sk->state) {
struct open_request *req, **prev;
- struct ipv6hdr hd;
case TCP_LISTEN:
if (sk->lock.users)
goto out;
- /* Grrrr - fix this later. */
- ipv6_addr_copy(&hd.saddr, saddr);
- ipv6_addr_copy(&hd.daddr, daddr);
- req = tcp_v6_search_req(tp, &hd, th, tcp_v6_iif(skb), &prev);
+ req = tcp_v6_search_req(tp, &prev, th->dest, &hdr->daddr,
+ &hdr->saddr, tcp_v6_iif(skb));
if (!req)
goto out;
@@ -1107,7 +1110,8 @@ static struct sock *tcp_v6_hnd_req(struct sock *sk,struct sk_buff *skb)
struct sock *nsk;
/* Find possible connection requests. */
- req = tcp_v6_search_req(tp, skb->nh.ipv6h, th, tcp_v6_iif(skb), &prev);
+ req = tcp_v6_search_req(tp, &prev, th->source, &skb->nh.ipv6h->saddr,
+ &skb->nh.ipv6h->daddr, tcp_v6_iif(skb));
if (req)
return tcp_check_req(sk, skb, req, prev);
@@ -1142,7 +1146,6 @@ static void tcp_v6_synq_add(struct sock *sk, struct open_request *req)
req->sk = NULL;
req->expires = jiffies + TCP_TIMEOUT_INIT;
req->retrans = 0;
- req->index = h;
req->dl_next = lopt->syn_table[h];
write_lock(&tp->syn_wait_lock);
@@ -1790,7 +1793,6 @@ static struct tcp_func ipv6_specific = {
tcp_v6_rebuild_header,
tcp_v6_conn_request,
tcp_v6_syn_recv_sock,
- tcp_v6_hash_connecting,
tcp_v6_remember_stamp,
sizeof(struct ipv6hdr),
@@ -1810,7 +1812,6 @@ static struct tcp_func ipv6_mapped = {
tcp_v4_rebuild_header,
tcp_v6_conn_request,
tcp_v6_syn_recv_sock,
- tcp_v4_hash_connecting,
tcp_v4_remember_stamp,
sizeof(struct iphdr),
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index a895089358aad..f0be1474dcdb1 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -293,6 +293,8 @@ ipv4_connected:
return -EINVAL;
}
sk->bound_dev_if = usin->sin6_scope_id;
+ if (!sk->bound_dev_if && (addr_type&IPV6_ADDR_MULTICAST))
+ fl.oif = np->mcast_oif;
}
/* Connect to link-local address requires an interface */
@@ -317,6 +319,9 @@ ipv4_connected:
fl.uli_u.ports.dport = inet->dport;
fl.uli_u.ports.sport = inet->sport;
+ if (!fl.oif && (addr_type&IPV6_ADDR_MULTICAST))
+ fl.oif = np->mcast_oif;
+
if (flowlabel) {
if (flowlabel->opt && flowlabel->opt->srcrt) {
struct rt0_hdr *rt0 = (struct rt0_hdr *) flowlabel->opt->srcrt;
diff --git a/net/khttpd/sockets.c b/net/khttpd/sockets.c
index 74bfe614d4632..0241f9bfc7f31 100644
--- a/net/khttpd/sockets.c
+++ b/net/khttpd/sockets.c
@@ -82,7 +82,7 @@ int StartListening(const int Port)
MainSocket = sock;
- EnterFunction("StartListening");
+ LeaveFunction("StartListening");
return 1;
}
diff --git a/net/lapb/lapb_iface.c b/net/lapb/lapb_iface.c
index aeafa310f1e40..5142e74ae9aa5 100644
--- a/net/lapb/lapb_iface.c
+++ b/net/lapb/lapb_iface.c
@@ -407,5 +407,6 @@ static int __init lapb_init(void)
MODULE_AUTHOR("Jonathan Naylor <g4klx@g4klx.demon.co.uk>");
MODULE_DESCRIPTION("The X.25 Link Access Procedure B link layer protocol");
+MODULE_LICENSE("GPL");
module_init(lapb_init);
diff --git a/net/netlink/netlink_dev.c b/net/netlink/netlink_dev.c
index a5bb25ab50891..131209fea01d7 100644
--- a/net/netlink/netlink_dev.c
+++ b/net/netlink/netlink_dev.c
@@ -206,6 +206,8 @@ int __init init_netlink(void)
#ifdef MODULE
+MODULE_LICENSE("GPL");
+
int init_module(void)
{
printk(KERN_INFO "Network Kernel/User communications module 0.04\n");
diff --git a/net/netrom/af_netrom.c b/net/netrom/af_netrom.c
index 65b59754b62ed..ebaae2dbd2daa 100644
--- a/net/netrom/af_netrom.c
+++ b/net/netrom/af_netrom.c
@@ -29,7 +29,7 @@
* NET/ROM 006 Alan(GW4PTS) Brought in line with the ANK changes
* Jonathan(G4KLX) Removed hdrincl.
* NET/ROM 007 Jonathan(G4KLX) New timer architecture.
- * Impmented Idle timer.
+ * Implemented Idle timer.
* Arnaldo C. Melo s/suser/capable/, micro cleanups
*/
@@ -1338,6 +1338,7 @@ MODULE_PARM_DESC(nr_ndevs, "number of NET/ROM devices");
MODULE_AUTHOR("Jonathan Naylor G4KLX <g4klx@g4klx.demon.co.uk>");
MODULE_DESCRIPTION("The amateur radio NET/ROM network and transport layer protocol");
+MODULE_LICENSE("GPL");
static void __exit nr_exit(void)
{
diff --git a/net/netsyms.c b/net/netsyms.c
index abf875169c990..9aa257b30a6eb 100644
--- a/net/netsyms.c
+++ b/net/netsyms.c
@@ -364,7 +364,6 @@ EXPORT_SYMBOL(tcp_inherit_port);
EXPORT_SYMBOL(tcp_v4_syn_recv_sock);
EXPORT_SYMBOL(tcp_v4_do_rcv);
EXPORT_SYMBOL(tcp_v4_connect);
-EXPORT_SYMBOL(tcp_v4_hash_connecting);
EXPORT_SYMBOL(tcp_unhash);
EXPORT_SYMBOL(udp_prot);
EXPORT_SYMBOL(tcp_prot);
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
index 84e1262d6660e..75000d6946816 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -358,6 +358,8 @@ static int packet_sendmsg_spkt(struct socket *sock, struct msghdr *msg, int len,
if (dev->hard_header) {
skb->data -= dev->hard_header_len;
skb->tail -= dev->hard_header_len;
+ if (len < dev->hard_header_len)
+ skb->nh.raw = skb->data;
}
/* Returns -EFAULT on error */
diff --git a/net/rose/af_rose.c b/net/rose/af_rose.c
index 6a2c2decc5160..e183529c23206 100644
--- a/net/rose/af_rose.c
+++ b/net/rose/af_rose.c
@@ -1519,6 +1519,7 @@ MODULE_PARM_DESC(rose_ndevs, "number of ROSE devices");
MODULE_AUTHOR("Jonathan Naylor G4KLX <g4klx@g4klx.demon.co.uk>");
MODULE_DESCRIPTION("The amateur radio ROSE network layer protocol");
+MODULE_LICENSE("GPL");
static void __exit rose_exit(void)
{
diff --git a/net/sched/sch_prio.c b/net/sched/sch_prio.c
index 6d056b86c04d2..62a37363c841a 100644
--- a/net/sched/sch_prio.c
+++ b/net/sched/sch_prio.c
@@ -327,6 +327,7 @@ static int prio_dump_class(struct Qdisc *sch, unsigned long cl, struct sk_buff *
if (cl - 1 > q->bands)
return -ENOENT;
+ tcm->tcm_handle |= TC_H_MIN(cl);
if (q->queues[cl-1])
tcm->tcm_info = q->queues[cl-1]->handle;
return 0;
diff --git a/net/sched/sch_sfq.c b/net/sched/sch_sfq.c
index f2d0d92f7b8ee..c96762fbdcb92 100644
--- a/net/sched/sch_sfq.c
+++ b/net/sched/sch_sfq.c
@@ -105,6 +105,7 @@ struct sfq_sched_data
/* Parameters */
int perturb_period;
unsigned quantum; /* Allotment per round: MUST BE >= MTU */
+ int limit;
/* Variables */
struct timer_list perturb_timer;
@@ -275,7 +276,7 @@ sfq_enqueue(struct sk_buff *skb, struct Qdisc* sch)
q->tail = x;
}
}
- if (++sch->q.qlen < SFQ_DEPTH-1) {
+ if (++sch->q.qlen < q->limit-1) {
sch->stats.bytes += skb->len;
sch->stats.packets++;
return 0;
@@ -310,7 +311,7 @@ sfq_requeue(struct sk_buff *skb, struct Qdisc* sch)
q->tail = x;
}
}
- if (++sch->q.qlen < SFQ_DEPTH-1)
+ if (++sch->q.qlen < q->limit - 1)
return 0;
sch->stats.drops++;
@@ -390,6 +391,11 @@ static int sfq_change(struct Qdisc *sch, struct rtattr *opt)
sch_tree_lock(sch);
q->quantum = ctl->quantum ? : psched_mtu(sch->dev);
q->perturb_period = ctl->perturb_period*HZ;
+ if (ctl->limit)
+ q->limit = min_t(u32, ctl->limit, SFQ_DEPTH);
+
+ while (sch->q.qlen >= q->limit-1)
+ sfq_drop(sch);
del_timer(&q->perturb_timer);
if (q->perturb_period) {
@@ -416,6 +422,7 @@ static int sfq_init(struct Qdisc *sch, struct rtattr *opt)
q->dep[i+SFQ_DEPTH].next = i+SFQ_DEPTH;
q->dep[i+SFQ_DEPTH].prev = i+SFQ_DEPTH;
}
+ q->limit = SFQ_DEPTH;
q->max_depth = 0;
q->tail = SFQ_DEPTH;
if (opt == NULL) {
@@ -448,9 +455,9 @@ static int sfq_dump(struct Qdisc *sch, struct sk_buff *skb)
opt.quantum = q->quantum;
opt.perturb_period = q->perturb_period/HZ;
- opt.limit = SFQ_DEPTH;
+ opt.limit = q->limit;
opt.divisor = SFQ_HASH_DIVISOR;
- opt.flows = SFQ_DEPTH;
+ opt.flows = q->limit;
RTA_PUT(skb, TCA_OPTIONS, sizeof(opt), &opt);
diff --git a/net/sunrpc/stats.c b/net/sunrpc/stats.c
index 7adc5541fa2f0..5f8bc3fc0761c 100644
--- a/net/sunrpc/stats.c
+++ b/net/sunrpc/stats.c
@@ -21,6 +21,7 @@
#include <linux/proc_fs.h>
#include <linux/sunrpc/clnt.h>
#include <linux/sunrpc/svcsock.h>
+#include <linux/init.h>
#define RPCDBG_FACILITY RPCDBG_MISC
diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c
index 0751536f78280..8f3f3fe5fbb57 100644
--- a/net/sunrpc/xprt.c
+++ b/net/sunrpc/xprt.c
@@ -1097,7 +1097,7 @@ udp_write_space(struct sock *sk)
return;
/* Wait until we have enough socket memory. */
- if (sock_writeable(sk))
+ if (!sock_writeable(sk))
return;
if (!xprt_test_and_set_wspace(xprt)) {
diff --git a/net/x25/af_x25.c b/net/x25/af_x25.c
index d169cffdc6639..f70de78a143e0 100644
--- a/net/x25/af_x25.c
+++ b/net/x25/af_x25.c
@@ -1371,6 +1371,7 @@ EXPORT_NO_SYMBOLS;
MODULE_AUTHOR("Jonathan Naylor <g4klx@g4klx.demon.co.uk>");
MODULE_DESCRIPTION("The X.25 Packet Layer network layer protocol");
+MODULE_LICENSE("GPL");
static void __exit x25_exit(void)
{
diff --git a/scripts/mkspec b/scripts/mkspec
index 43ee7367718ba..f20dce629d046 100644
--- a/scripts/mkspec
+++ b/scripts/mkspec
@@ -6,9 +6,15 @@
# The only gothic bit here is redefining install_post to avoid
# stripping the symbols from files in the kernel which we want
#
+if [ "`grep CONFIG_DRM=y .config | cut -f2 -d\=`" = "y" ]; then
+ PROVIDES=kernel-drm
+fi
+
+PROVIDES="$PROVIDES kernel-$VERSION.$PATCHLEVEL.$SUBLEVEL$EXTRAVERSION"
+
echo "Name: kernel"
echo "Summary: The Linux Kernel"
-echo "Version: "$VERSION.$PATCHLEVEL.$SUBLEVEL$EXTRAVERSION | sed -e "s/-//"
+echo "Version: "$VERSION.$PATCHLEVEL.$SUBLEVEL$EXTRAVERSION | sed -e "s/-//g"
# we need to determine the NEXT version number so that uname and
# rpm -q will agree
echo "Release: `. scripts/mkversion`"
@@ -17,8 +23,9 @@ echo "Group: System Environment/Kernel"
echo "Vendor: The Linux Community"
echo "URL: http://www.kernel.org"
echo -n "Source: kernel-$VERSION.$PATCHLEVEL.$SUBLEVEL"
-echo "$EXTRAVERSION.tar.gz" | sed -e "s/-//"
+echo "$EXTRAVERSION.tar.gz" | sed -e "s/-//g"
echo "BuildRoot: /var/tmp/%{name}-%{PACKAGE_VERSION}-root"
+echo "Provides: $PROVIDES"
echo "%define __spec_install_post /usr/lib/rpm/brp-compress || :"
echo ""
echo "%description"
@@ -35,6 +42,7 @@ echo 'mkdir -p $RPM_BUILD_ROOT/boot $RPM_BUILD_ROOT/lib $RPM_BUILD_ROOT/lib/modu
echo 'INSTALL_MOD_PATH=$RPM_BUILD_ROOT make modules_install'
echo 'cp arch/i386/boot/bzImage $RPM_BUILD_ROOT'"/boot/vmlinuz-$VERSION.$PATCHLEVEL.$SUBLEVEL$EXTRAVERSION"
echo 'cp System.map $RPM_BUILD_ROOT'"/boot/System.map-$VERSION.$PATCHLEVEL.$SUBLEVEL$EXTRAVERSION"
+echo 'cp .config $RPM_BUILD_ROOT'"/boot/config-$VERSION.$PATCHLEVEL.$SUBLEVEL$EXTRAVERSION"
echo ""
echo "%clean"
echo '#echo -rf $RPM_BUILD_ROOT'
diff --git a/sound/core/rtctimer.c b/sound/core/rtctimer.c
index 68e4f7cb65871..bf25b44ce47a0 100644
--- a/sound/core/rtctimer.c
+++ b/sound/core/rtctimer.c
@@ -52,7 +52,7 @@ static int rtctimer_stop(snd_timer_t *t);
/*
- * The hardware dependent description for this timer.
+ * The hardware dependant description for this timer.
*/
static struct _snd_timer_hardware rtc_hw = {
flags: SNDRV_TIMER_HW_FIRST|SNDRV_TIMER_HW_AUTO,
diff --git a/sound/oss/ac97_codec.c b/sound/oss/ac97_codec.c
index 093058e7d30c5..0fabf7da415ac 100644
--- a/sound/oss/ac97_codec.c
+++ b/sound/oss/ac97_codec.c
@@ -105,7 +105,9 @@ static const struct {
{0x41445340, "Analog Devices AD1881", &null_ops},
{0x41445348, "Analog Devices AD1881A", &null_ops},
{0x41445360, "Analog Devices AD1885", &default_ops},
+ {0x41445361, "Analog Devices AD1886", &default_ops},
{0x41445460, "Analog Devices AD1885", &default_ops},
+ {0x41445461, "Analog Devices AD1886", &default_ops},
{0x414B4D00, "Asahi Kasei AK4540", &null_ops},
{0x414B4D01, "Asahi Kasei AK4542", &null_ops},
{0x414B4D02, "Asahi Kasei AK4543", &null_ops},
diff --git a/sound/oss/ad1848.h b/sound/oss/ad1848.h
index 234bbb8235b92..6791c2745ca12 100644
--- a/sound/oss/ad1848.h
+++ b/sound/oss/ad1848.h
@@ -1,8 +1,3 @@
-/*
- * ad1848.c
- *
- * Copyright: Christoph Hellwig <chhellwig@gmx.net>
- */
#define AD_F_CS4231 0x0001 /* Returned if a CS4232 (or compatible) detected */
#define AD_F_CS4248 0x0001 /* Returned if a CS4248 (or compatible) detected */
diff --git a/sound/oss/cs4232.h b/sound/oss/cs4232.h
index 73377b4316993..31c8d8b23c91e 100644
--- a/sound/oss/cs4232.h
+++ b/sound/oss/cs4232.h
@@ -1,9 +1,3 @@
-/*
- * cs4232.h
- *
- * Copyright: Christoph Hellwig <chhellwig@gmx.net>
- *
- */
int probe_cs4232 (struct address_info *hw_config,int useisapnp);
void attach_cs4232 (struct address_info *hw_config);
diff --git a/sound/oss/gus.h b/sound/oss/gus.h
index fe795ecdb7b9b..53b70bce01180 100644
--- a/sound/oss/gus.h
+++ b/sound/oss/gus.h
@@ -1,9 +1,3 @@
-/*
- * gus.h
- *
- * Copyright: Christoph Hellwig <chhellwig@gmx.net>
- *
- */
#include "ad1848.h"
diff --git a/sound/oss/mad16.c b/sound/oss/mad16.c
index 268c31f3c479d..6f242b8d25b0f 100644
--- a/sound/oss/mad16.c
+++ b/sound/oss/mad16.c
@@ -42,6 +42,7 @@
#include <linux/config.h>
#include <linux/init.h>
#include <linux/module.h>
+#include <linux/gameport.h>
#include "sound_config.h"
@@ -51,6 +52,7 @@
static int mad16_conf;
static int mad16_cdsel;
+static struct gameport gameport;
static int already_initialized = 0;
@@ -664,13 +666,13 @@ static void __init attach_mad16(struct address_info *hw_config)
outb((bits | dma_bits[dma] | dma2_bit), config_port); /* Write IRQ+DMA setup */
- hw_config->slots[0] = ad1848_init("MAD16 WSS", hw_config->io_base + 4,
+ hw_config->slots[0] = ad1848_init("mad16 WSS", hw_config->io_base + 4,
hw_config->irq,
dma,
dma2, 0,
hw_config->osp,
THIS_MODULE);
- request_region(hw_config->io_base, 4, "MAD16 WSS config");
+ request_region(hw_config->io_base, 4, "mad16 WSS config");
}
static int __init probe_mad16_mpu(struct address_info *hw_config)
@@ -1010,14 +1012,6 @@ static int __init init_mad16(void)
}
printk(".\n");
- printk(KERN_INFO "Joystick port ");
- if (joystick == 1)
- printk("enabled.\n");
- else
- {
- joystick = 0;
- printk("disabled.\n");
- }
cfg.io_base = io;
cfg.irq = irq;
@@ -1038,6 +1032,18 @@ static int __init init_mad16(void)
attach_mad16(&cfg);
found_mpu = probe_mad16_mpu(&cfg_mpu);
+
+ if (joystick == 1) {
+ /* register gameport */
+ if (!request_region(0x201, 1, "mad16 gameport"))
+ printk(KERN_ERR "mad16: gameport address 0x201 already in use\n");
+ else {
+ printk(KERN_ERR "mad16: gameport enabled at 0x201\n");
+ gameport.io = 0x201;
+ gameport_register_port(&gameport);
+ }
+ }
+ else printk(KERN_ERR "mad16: gameport disabled.\n");
return 0;
}
@@ -1055,16 +1061,17 @@ module_exit(cleanup_mad16);
static int __init setup_mad16(char *str)
{
/* io, irq */
- int ints[7];
+ int ints[8];
str = get_options(str, ARRAY_SIZE(ints), ints);
- io = ints[1];
- irq = ints[2];
- dma = ints[3];
- dma16 = ints[4];
- mpu_io = ints[5];
- mpu_irq = ints[6];
+ io = ints[1];
+ irq = ints[2];
+ dma = ints[3];
+ dma16 = ints[4];
+ mpu_io = ints[5];
+ mpu_irq = ints[6];
+ joystick = ints[7];
return 1;
}
diff --git a/sound/oss/mpu401.h b/sound/oss/mpu401.h
index 455a4bde5fa2a..e5812623b2d38 100644
--- a/sound/oss/mpu401.h
+++ b/sound/oss/mpu401.h
@@ -1,9 +1,3 @@
-/*
- * uart401.h
- *
- * Copyright: Christoph Hellwig <chhellwig@gmx.net>
- *
- */
/* From uart401.c */
int probe_uart401 (struct address_info *hw_config, struct module *owner);
diff --git a/sound/oss/opl3.h b/sound/oss/opl3.h
index 104ae9ff4e7d2..0bc9a4bcda131 100644
--- a/sound/oss/opl3.h
+++ b/sound/oss/opl3.h
@@ -1,9 +1,3 @@
-/*
- * opl3.h
- *
- * Copyright: Christoph Hellwig <chhellwig@gmx.net>
- *
- */
int opl3_detect (int ioaddr, int *osp);
int opl3_init(int ioaddr, int *osp, struct module *owner);
diff --git a/sound/oss/pas2.h b/sound/oss/pas2.h
index 7ac521fe016c2..fa12c55f560e0 100644
--- a/sound/oss/pas2.h
+++ b/sound/oss/pas2.h
@@ -1,9 +1,3 @@
-/*
- * pas2.h
- *
- * Copyright: Christoph Hellwig <chhellwig@gmx.net>
- *
- */
/* From pas_card.c */
int pas_set_intr(int mask);
diff --git a/sound/oss/pss.c b/sound/oss/pss.c
index 1804f9d69ed11..250b618327307 100644
--- a/sound/oss/pss.c
+++ b/sound/oss/pss.c
@@ -48,7 +48,7 @@
* Added module parameter pss_firmware to allow the user to tell
* the driver where the fireware file is located. The default
* setting is the previous hardcoded setting "/etc/sound/pss_synth".
- * 00-03-03: Christoph Hellwig <chhellwig@gmx.net>
+ * 00-03-03: Christoph Hellwig <chhellwig@infradead.org>
* Adapted to module_init/module_exit
* 11-10-2000: Bartlomiej Zolnierkiewicz <bkz@linux-ide.org>
* Added __init to probe_pss(), attach_pss() and probe_pss_mpu()