diff -u --recursive --new-file v2.4.6/linux/CREDITS linux/CREDITS --- v2.4.6/linux/CREDITS Tue Jul 3 17:08:18 2001 +++ linux/CREDITS Wed Jul 4 14:41:33 2001 @@ -78,8 +78,8 @@ D: Unix98 pty support. D: APM update to 1.2 spec. D: /devfs hacking. -S: 322 N. Riverside Dr. -S: Neptune, NJ 07753 +S: 7 Kiwi Loop +S: Howell, NJ 07731 S: USA N: Erik Andersen @@ -679,6 +679,14 @@ S: K1N 6Z9 S: CANADA +N: Jeff Dike +E: jdike@karaya.com +W: http://user-mode-linux.sourceforge.net +D: User mode kernel port +S: RR1 Box 67C +S: Deering NH 03244 +S: USA + N: Eddie C. Dost E: ecd@skynet.be D: Linux/Sparc kernel hacker @@ -957,6 +965,12 @@ S: New South Wales, 2121 S: Australia +N: Carlos E. Gorges +E: carlos@techlinux.com.br +D: fix smp support on cmpci driver +P: 2048G/EA3C4B19 FF31 33A6 0362 4915 B7EB E541 17D0 0379 EA3C 4B19 +S: Brazil + N: Dmitry S. Gorodchanin E: pgmdsg@ibi.com D: RISCom/8 driver, misc kernel fixes. @@ -1056,6 +1070,11 @@ S: 2400 AG, Alphen aan den Rijn S: The Netherlands +N: Enver Haase +E: ehaase@inf.fu-berlin.de +W: http://www.inf.fu-berlin.de/~ehaase +D: Driver for the Commodore A2232 serial board + N: Bruno Haible E: haible@ma2s2.mathematik.uni-karlsruhe.de D: SysV FS, shm swapping, memory management fixes @@ -1269,12 +1288,11 @@ S: USA N: Gareth Hughes -E: gareth@valinux.com -E: gareth@precisioninsight.com +E: gareth.hughes@acm.org D: Pentium III FXSR, SSE support -S: 11/187 West Street -S: Crows Nest NSW 2065 -S: Australia +D: Author/maintainer of most DRM drivers (especially ATI, MGA) +D: Core DRM templates, general DRM and 3D-related hacking +S: No fixed address N: Kenn Humborg E: kenn@wombat.ie @@ -2253,6 +2271,15 @@ E: ken@halcyon.com D: CDROM driver "sonycd535" (Sony CDU-535/531) +N: Stelian Pop +E: stelian.pop@fr.alcove.com +P: 1024D/EDBB6147 7B36 0E07 04BC 11DC A7A0 D3F7 7185 9E7A EDBB 6147 +D: sonypi, meye drivers, mct_u232 usb serial hacks +S: Alcôve +S: 153, bd. Anatole France +S: 93200 Saint Denis +S: France + N: Frederic Potter E: fpotter@cirpack.com D: Some PCI kernel support @@ -2349,14 +2376,15 @@ S: France N: Rik van Riel -E: riel@nl.linux.org -W: http://www.nl.linux.org/~riel/ +E: riel@conectiva.com.br +W: http://www.surriel.com/ D: Linux-MM site, Documentation/sysctl/*, swap/mm readaround D: clustering contributor, kswapd fixes, random kernel hacker, -D: nl.linux.org maintainer, minor scheduler additions -S: IJsselstraat 23a -S: 9725 GA Groningen -S: The Netherlands +D: nl.linux.org administrator, minor scheduler additions +S: Conectiva S.A. +S: R. Tocantins, 89 - Cristo Rei +S: 80050-430 - Curitiba - Paraná +S: Brazil N: Pekka Riikonen E: priikone@poseidon.pspt.fi @@ -2862,6 +2890,7 @@ N: Petr Vandrovec E: vandrove@vc.cvut.cz D: Small contributions to ncpfs +D: Matrox framebuffer driver S: Chudenicka 8 S: 10200 Prague 10, Hostivar S: Czech Republic diff -u --recursive --new-file v2.4.6/linux/Documentation/Configure.help linux/Documentation/Configure.help --- v2.4.6/linux/Documentation/Configure.help Tue Jul 3 17:08:18 2001 +++ linux/Documentation/Configure.help Thu Jul 19 17:48:15 2001 @@ -3372,6 +3372,30 @@ As this card technology is 15 years old, most people will answer N here. +NEC PowerVR 2 display support +CONFIG_FB_PVR2 + Say Y here if you have a PowerVR 2 card in your box. If you plan to + run linux on your Dreamcast, you will have to say Y here. This driver + may or may not work on other PowerVR 2 cards, but is totally untested. + Use at your own risk. If unsure, say N. + + This driver is also available as a module ( = code which can be + inserted and removed from the running kernel whenever you want). + The module will be called pvr2fb.o. If you want to compile it as + a module, say M here and read Documentation/modules.txt. + + You can pass several parameters to the driver at boot time or at + module load time. The parameters look like "video=pvr2:XXX", where + the meaning of XXX can be found at the end of the main source file + (drivers/video/pvr2fb.c). Please see the file + Documentation/fb/pvr2fb.txt. + +Debug pvr2fb +CONFIG_FB_PVR2_DEBUG + Say Y here if you wish for the pvr2fb driver to print out debugging + messages. Most people will want to say N here. If unsure, you will + also want to say N. + Matrox unified accelerated driver (EXPERIMENTAL) CONFIG_FB_MATROX Say Y here if you have a Matrox Millennium, Matrox Millennium II, @@ -3712,6 +3736,12 @@ If unsure, say Y. +Parallel+serial PCI card support +CONFIG_PARPORT_SERIAL + This adds support for multi-IO PCI cards that have parallel and serial + ports. You should say Y or M here. If you say M, the module will be + called parport_serial.o. + Use FIFO/DMA if available CONFIG_PARPORT_PC_FIFO Many parallel port chipsets provide hardware that can speed up @@ -6849,7 +6879,7 @@ TI PCILynx IEEE 1394 support CONFIG_IEEE1394_PCILYNX - Say Y here if you have a IEEE-1394 controller with the Texas + Say Y here if you have an IEEE-1394 controller with the Texas Instruments PCILynx chip. Note: this driver is written for revision 2 of this chip and may not work with revision 0. @@ -6883,29 +6913,30 @@ If unsure, say N. -Adaptec AIC-5800 IEEE 1394 support -CONFIG_IEEE1394_AIC5800 - Say Y here if you have a IEEE 1394 controller using the Adaptec - AIC-5800 chip. All Adaptec host adapters (89xx series) use this - chip, as well as miro's DV boards. - - If you want to compile this as a module ( = code which can be - inserted in and removed from the running kernel whenever you want), - say M here and read Documentation/modules.txt. The module will be - called aic5800.o. - -OHCI (Open Host Controller Interface) support +OHCI-1394 support CONFIG_IEEE1394_OHCI1394 - Say Y here if you have a IEEE 1394 controller based on OHCI. - The current driver was only tested with OHCI chipsets made - by Texas Instruments. However, most third-party vendors use - TI chips. + Enable this driver if you have an IEEE 1394 controller based on the + OHCI-1394 specification. The current driver is only tested with OHCI + chipsets made by Texas Instruments and NEC. Most third-party vendors + use one of these chipsets. It should work with any OHCI-1394 compliant + card, however. If you want to compile this as a module ( = code which can be inserted in and removed from the running kernel whenever you want), say M here and read Documentation/modules.txt. The module will be called ohci1394.o. +OHCI-1394 Video support +CONFIG_IEEE1394_VIDEO1394 + This option enables video device usage for OHCI-1394 cards. Enable this + option only if you have an IEEE 1394 video device connected to an + OHCI-1394 card. + +SBP-2 support (Harddisks etc.) +CONFIG_IEEE1394_SBP2 + This option enables you to use SBP-2 devices connected to your IEEE 1394 + bus. SBP-2 devices include harddrives and DVD devices. + Raw IEEE 1394 I/O support CONFIG_IEEE1394_RAWIO Say Y here if you want support for the raw device. This is generally @@ -8842,6 +8873,18 @@ say M here and read Documentation/modules.txt. This is recommended. The module will be called myri_sbus.o. +D-Link 2000-based Gigabit Ethernet support +CONFIG_DL2K + This driver supports D-Link 2000-based gigabit ethernet cards, which + includes + D-Link DGE-550T Gigabit Ethernet Adapter. + D-Link DL2000-based Gigabit Ethernet Adapter. + + If you want to compile this driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt. This is recommended. + The module will be called dl2k.o. + AMD LANCE and PCnet (AT1500 and NE2100) support CONFIG_LANCE If you have a network (Ethernet) card of this type, say Y and read @@ -12162,34 +12205,38 @@ The module is called freevxfs.o. If you want to compile it as a module, say M here and read Documentation/modules.txt. If unsure, say N. -NTFS support (read only) +NTFS file system support (read-only) CONFIG_NTFS_FS NTFS is the file system of Microsoft Windows NT. Say Y if you want to get read access to files on NTFS partitions of your hard drive. The Linux NTFS driver supports most of the mount options of the VFAT - driver, see Documentation/filesystems/ntfs.txt. Saying Y here will - give you read-only access to NTFS partitions. + driver, see . Saying Y here + will give you read-only access to NTFS partitions. This code is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). The module will be called ntfs.o. If you want to compile it as a - module, say M here and read Documentation/modules.txt. + module, say M here and read . NTFS write support (DANGEROUS) CONFIG_NTFS_RW If you say Y here, you will (maybe) be able to write to NTFS file - systems as well as read from them. The read-write support in - NTFS is far from being complete and is not well tested. If you - say Y here, back up your NTFS volume first since it may get - damaged. Also, make sure to run chkdsk from within Microsoft - Windows NT after having performed any writes to a NTFS partition - from Linux to detect any problems as early as possible. + systems as well as read from them. The read-write support in NTFS + is far from being complete and is not well tested. If you say Y + here, back up your NTFS volume first, since it will probably get + damaged. Also, download the Linux-NTFS project distribution from + Sourceforge at and always run the + included ntfsfix utility after writing to an NTFS partition from + Linux to fix some of the damage done by the driver. You should run + ntfsfix _after_ unmounting the partition in Linux but _before_ + rebooting into Windows. When Windows next boots, chkdsk will be + run automatically to fix the remaining damage. Please note that write support is limited to Windows NT4 and earlier versions. If unsure, say N. -System V, Version 7, Xenix and Coherent filesystem support (read only) +System V, Version 7, Xenix and Coherent filesystem support CONFIG_SYSV_FS SCO, Xenix and Coherent are commercial Unix systems for Intel machines, and Version 7 was used on the DEC PDP-11. Saying Y @@ -12199,14 +12246,12 @@ If you have floppies or hard disk partitions like that, it is likely that they contain binaries from those other Unix systems; in order - to run these binaries, you will want to install iBCS2 (Intel Binary - Compatibility Standard is a kernel module which lets you run SCO, - Xenix, Wyse, UnixWare, Dell Unix and System V programs under Linux - and is often needed to run commercial software that's only available - for those systems. It's available via FTP (user: anonymous) from - ftp://tsx-11.mit.edu/pub/linux/BETA ). NOTE: that will work only for - binaries from Intel-based systems; PDP ones will have to wait until - somebody ports Linux to -11 ;-) + to run these binaries, you will want to install linux-abi which is a + a set of kernel modules that lets you run SCO, Xenix, Wyse, UnixWare, + Dell Unix and System V programs under Linux. It's available via FTP + (user: ftp) from ftp://ftp.openlinux.org/pub/people/hch/linux-abi). + NOTE: that will work only for binaries from Intel-based systems; + PDP ones will have to wait until somebody ports Linux to -11 ;-) If you only intend to mount files from some other Unix over the network using NFS, you don't need the System V file system support @@ -12227,15 +12272,6 @@ If you haven't heard about all of this before, it's safe to say N. -SYSV file system write support (DANGEROUS) -CONFIG_SYSV_FS_WRITE - If you say Y here, you will be able to write to hard drive - partitions and floppy disks which carry a SYSV file system used the - commercial Unixes SCO, Xenix and Coherent. - - This support is experimental and you may destroy your data. If - unsure, say N. - Amiga FFS file system support CONFIG_AFFS_FS The Fast File System (FFS) is the common file system used on hard @@ -13480,10 +13516,12 @@ doing that; to actually get it to happen you need to pass the option "console=lp0" to the kernel at boot time. - Note that kernel messages can get lost if the printer is out of - paper (or off, or unplugged, or too busy..), but this behaviour - can be changed. See drivers/char/lp.c (do this at your own risk). - + If the printer is out of paper (or off, or unplugged, or too + busy..) the kernel will stall until the printer is ready again. + By defining CONSOLE_LP_STRICT to 0 (at your own risk) you + can make the kernel continue when this happens, + but it'll lose the kernel messages. + If unsure, say N. Support for user-space parallel port device drivers @@ -15587,9 +15625,18 @@ VIA 82Cxxx Audio Codec CONFIG_SOUND_VIA82CXXX Say Y here to include support for the audio codec found on VIA - 82Cxxx-based chips. Typically these are built into a motherboard. DO - NOT select Sound Blaster or Adlib with this driver, unless you have - a Sound Blaster or Adlib card in addition to your VIA audio chip. + 82Cxxx-based chips. Typically these are built into a motherboard. + + DO NOT select Sound Blaster or Adlib with this driver, unless + you have a Sound Blaster or Adlib card in addition to your VIA + audio chip. + +VIA 82C686 MIDI +CONFIG_MIDI_VIA82CXXX + Answer Y to use the MIDI interface of the Via686. You may need to + enable this in the BIOS before it will work. This is for connection + to external MIDI hardware, and is not required for software playback + of MIDI files. NeoMagic 256AV/256ZX sound chipsets CONFIG_SOUND_NM256 diff -u --recursive --new-file v2.4.6/linux/Documentation/DocBook/Makefile linux/Documentation/DocBook/Makefile --- v2.4.6/linux/Documentation/DocBook/Makefile Tue Jul 3 17:08:18 2001 +++ linux/Documentation/DocBook/Makefile Sun Jul 8 13:13:47 2001 @@ -1,7 +1,7 @@ BOOKS := wanbook.sgml z8530book.sgml mcabook.sgml videobook.sgml \ kernel-api.sgml parportbook.sgml kernel-hacking.sgml \ kernel-locking.sgml via-audio.sgml mousedrivers.sgml sis900.sgml \ - deviceiobook.sgml procfs-guide.sgml + deviceiobook.sgml procfs-guide.sgml tulip-user.sgml PS := $(patsubst %.sgml, %.ps, $(BOOKS)) PDF := $(patsubst %.sgml, %.pdf, $(BOOKS)) @@ -61,6 +61,9 @@ via-audio.sgml: via-audio.tmpl $(TOPDIR)/drivers/sound/via82cxxx_audio.c $(TOPDIR)/scripts/docgen $(TOPDIR)/drivers/sound/via82cxxx_audio.c \ via-audio.sgml + +tulip-user.sgml: tulip-user.tmpl + $(TOPDIR)/scripts/docgen <$< >$@ sis900.sgml: sis900.tmpl $(TOPDIR)/drivers/net/sis900.c $(TOPDIR)/scripts/docgen $(TOPDIR)/drivers/net/sis900.c \ diff -u --recursive --new-file v2.4.6/linux/Documentation/DocBook/via-audio.tmpl linux/Documentation/DocBook/via-audio.tmpl --- v2.4.6/linux/Documentation/DocBook/via-audio.tmpl Mon Oct 30 12:24:22 2000 +++ linux/Documentation/DocBook/via-audio.tmpl Sun Jul 8 13:14:00 2001 @@ -17,7 +17,7 @@ - 2000 + 1999-2001 Jeff Garzik @@ -149,23 +149,6 @@ Known Bugs And Assumptions - MMAP support - - - MMAP support is currently missing. Make sure to - test with Quake. - - - - AC97 codec timeout during init - - - A warning message "via82cxxx: timeout while reading AC97 - codec" is printed during driver initialization. This - message can safely be ignored. - - - Low volume @@ -198,6 +181,16 @@ AC97 mixer interface fixes and debugging by Ron Cemer roncemer@gte.net. + + Rui Sousa rui.sousa@conexant.com, for bugfixing + MMAP support, and several other notable fixes that resulted from + his hard work and testing. + + + Adrian Cox adrian@humboldt.co.uk, for bugfixing + MMAP support, and several other notable fixes that resulted from + his hard work and testing. + @@ -219,7 +212,10 @@ and device ids are not examined. - GNU indent formatting options: -kr -i8 -pcs + GNU indent formatting options: + +-kr -i8 -ts8 -br -ce -bap -sob -l80 -pcs -cs -ss -bs -di1 -nbc -lp -psl + Via has graciously donated e-mail support and source code to help further @@ -237,6 +233,79 @@ Driver ChangeLog + + +Version 1.1.15 + + + + + Support for variable fragment size and variable fragment number (Rui + Sousa) + + + + + + Fixes for the SPEED, STEREO, CHANNELS, FMT ioctls when in read & + write mode (Rui Sousa) + + + + + + Mmaped sound is now fully functional. (Rui Sousa) + + + + + + Make sure to enable PCI device before reading any of its PCI + config information. (fixes potential hotplug problems) + + + + + + Clean up code a bit and add more internal function documentation. + + + + + + AC97 codec access fixes (Adrian Cox) + + + + + + Big endian fixes (Adrian Cox) + + + + + + MIDI support (Adrian Cox) + + + + + + Detect and report locked-rate AC97 codecs. If your hardware only + supports 48Khz (locked rate), then your recording/playback software + must upsample or downsample accordingly. The hardware cannot do it. + + + + + + Use new pci_request_regions and pci_disable_device functions in + kernel 2.4.6. + + + + + Version 1.1.14 diff -u --recursive --new-file v2.4.6/linux/Documentation/DocBook/videobook.tmpl linux/Documentation/DocBook/videobook.tmpl --- v2.4.6/linux/Documentation/DocBook/videobook.tmpl Thu Jan 4 12:50:12 2001 +++ linux/Documentation/DocBook/videobook.tmpl Sun Jul 15 16:15:44 2001 @@ -179,23 +179,23 @@ <tgroup cols=3 align=left> <tbody> <row> - <entry>VFL_TYPE_RADIO</><>/dev/radio{n}</><> + <entry>VFL_TYPE_RADIO</><entry>/dev/radio{n}</><entry> Radio devices are assigned in this block. As with all of these selections the actual number assignment is done by the video layer accordijng to what is free.</entry> </row><row> - <entry>VFL_TYPE_GRABBER</><>/dev/video{n}</><> + <entry>VFL_TYPE_GRABBER</><entry>/dev/video{n}</><entry> Video capture devices and also -- counter-intuitively for the name -- hardware video playback devices such as MPEG2 cards.</entry> </row><row> - <entry>VFL_TYPE_VBI</><>/dev/vbi{n}</><> + <entry>VFL_TYPE_VBI</><entry>/dev/vbi{n}</><entry> The VBI devices capture the hidden lines on a television picture that carry further information like closed caption data, teletext (primarily in Europe) and now Intercast and the ATVEC internet television encodings.</entry> </row><row> - <entry>VFL_TYPE_VTX</><>/dev/vtx[n}</><> + <entry>VFL_TYPE_VTX</><entry>/dev/vtx[n}</><entry> VTX is 'Videotext' also known as 'Teletext'. This is a system for sending numbered, 40x25, mostly textual page images over the hidden lines. Unlike the /dev/vbi interfaces, this is for 'smart' decoder @@ -302,25 +302,25 @@ <tgroup cols=2 align=left> <tbody> <row> - <entry>name</><>The device text name. This is intended for the user.</> + <entry>name</><entry>The device text name. This is intended for the user.</> </row><row> - <entry>channels</><>The number of different channels you can tune on + <entry>channels</><entry>The number of different channels you can tune on this card. It could even by zero for a card that has no tuning capability. For our simple FM radio it is 1. An AM/FM radio would report 2.</entry> </row><row> - <entry>audios</><>The number of audio inputs on this device. For our + <entry>audios</><entry>The number of audio inputs on this device. For our radio there is only one audio input.</entry> </row><row> - <entry>minwidth,minheight</><>The smallest size the card is capable of capturing + <entry>minwidth,minheight</><entry>The smallest size the card is capable of capturing images in. We set these to zero. Radios do not capture pictures</entry> </row><row> - <entry>maxwidth,maxheight</><>The largest image size the card is capable of + <entry>maxwidth,maxheight</><entry>The largest image size the card is capable of capturing. For our radio we report 0. </entry> </row><row> - <entry>type</><>This reports the capabilities of the device, and + <entry>type</><entry>This reports the capabilities of the device, and matches the field we filled in in the struct video_device when registering.</entry> </row> @@ -415,7 +415,7 @@ </row><row> <entry>VIDEO_TUNER_SECAM</><entry>A SECAM (French) TV tuner</entry> </row><row> - <entry>VIDEO_TUNER_LOW</><> + <entry>VIDEO_TUNER_LOW</><entry> The tuner frequency is scaled in 1/16th of a KHz steps. If not it is in 1/16th of a MHz steps </entry> @@ -432,13 +432,13 @@ <tgroup cols=2 align=left> <tbody> <row> - <entry>VIDEO_MODE_PAL</><>PAL Format</entry> + <entry>VIDEO_MODE_PAL</><entry>PAL Format</entry> </row><row> - <entry>VIDEO_MODE_NTSC</><>NTSC Format (USA)</entry> + <entry>VIDEO_MODE_NTSC</><entry>NTSC Format (USA)</entry> </row><row> - <entry>VIDEO_MODE_SECAM</><>French Format</entry> + <entry>VIDEO_MODE_SECAM</><entry>French Format</entry> </row><row> - <entry>VIDEO_MODE_AUTO</><>A device that does not need to do + <entry>VIDEO_MODE_AUTO</><entry>A device that does not need to do TV format switching</entry> </row> </tbody> @@ -583,30 +583,30 @@ <tgroup cols=2 align=left> <tbody> <row> - <entry>audio</><>The input the user wishes to query</> + <entry>audio</><entry>The input the user wishes to query</> </row><row> - <entry>volume</><>The volume setting on a scale of 0-65535</> + <entry>volume</><entry>The volume setting on a scale of 0-65535</> </row><row> - <entry>base</><>The base level on a scale of 0-65535</> + <entry>base</><entry>The base level on a scale of 0-65535</> </row><row> - <entry>treble</><>The treble level on a scale of 0-65535</> + <entry>treble</><entry>The treble level on a scale of 0-65535</> </row><row> - <entry>flags</><>The features this audio device supports + <entry>flags</><entry>The features this audio device supports </entry> </row><row> - <entry>name</><>A text name to display to the user. We picked + <entry>name</><entry>A text name to display to the user. We picked "Radio" as it explains things quite nicely.</> </row><row> - <entry>mode</><>The current reception mode for the audio + <entry>mode</><entry>The current reception mode for the audio We report MONO because our card is too stupid to know if it is in mono or stereo. </entry> </row><row> - <entry>balance</><>The stereo balance on a scale of 0-65535, 32768 is + <entry>balance</><entry>The stereo balance on a scale of 0-65535, 32768 is middle.</> </row><row> - <entry>step</><>The step by which the volume control jumps. This is + <entry>step</><entry>The step by which the volume control jumps. This is used to help make it easy for applications to set slider behaviour.</> </row> @@ -618,15 +618,15 @@ <tgroup cols=2 align=left> <tbody> <row> - <entry>VIDEO_AUDIO_MUTE</><>The audio is currently muted. We + <entry>VIDEO_AUDIO_MUTE</><entry>The audio is currently muted. We could fake this in our driver but we choose not to bother.</entry> </row><row> - <entry>VIDEO_AUDIO_MUTABLE</><>The input has a mute option</entry> + <entry>VIDEO_AUDIO_MUTABLE</><entry>The input has a mute option</entry> </row><row> - <entry>VIDEO_AUDIO_TREBLE</><>The input has a treble control</entry> + <entry>VIDEO_AUDIO_TREBLE</><entry>The input has a treble control</entry> </row><row> - <entry>VIDEO_AUDIO_BASS</><>The input has a base control</entry> + <entry>VIDEO_AUDIO_BASS</><entry>The input has a base control</entry> </row> </tbody> </tgroup> @@ -636,13 +636,13 @@ <tgroup cols=2 align=left> <tbody> <row> - <entry>VIDEO_SOUND_MONO</><>Mono sound</entry> + <entry>VIDEO_SOUND_MONO</><entry>Mono sound</entry> </row><row> - <entry>VIDEO_SOUND_STEREO</><>Stereo sound</entry> + <entry>VIDEO_SOUND_STEREO</><entry>Stereo sound</entry> </row><row> - <entry>VIDEO_SOUND_LANG1</><>Alternative language 1 (TV specific)</entry> + <entry>VIDEO_SOUND_LANG1</><entry>Alternative language 1 (TV specific)</entry> </row><row> - <entry>VIDEO_SOUND_LANG2</><>Alternative language 2 (TV specific)</entry> + <entry>VIDEO_SOUND_LANG2</><entry>Alternative language 2 (TV specific)</entry> </row> </tbody> </tgroup> @@ -867,33 +867,33 @@ <tgroup cols=2 align=left> <tbody> <row> -<entry>VID_TYPE_CAPTURE</><>We support image capture</> +<entry>VID_TYPE_CAPTURE</><entry>We support image capture</> </row><row> -<entry>VID_TYPE_TELETEXT</><>A teletext capture device (vbi{n])</> +<entry>VID_TYPE_TELETEXT</><entry>A teletext capture device (vbi{n])</> </row><row> -<entry>VID_TYPE_OVERLAY</><>The image can be directly overlaid onto the +<entry>VID_TYPE_OVERLAY</><entry>The image can be directly overlaid onto the frame buffer</> </row><row> -<entry>VID_TYPE_CHROMAKEY</><>Chromakey can be used to select which parts +<entry>VID_TYPE_CHROMAKEY</><entry>Chromakey can be used to select which parts of the image to display</> </row><row> -<entry>VID_TYPE_CLIPPING</><>It is possible to give the board a list of +<entry>VID_TYPE_CLIPPING</><entry>It is possible to give the board a list of rectangles to draw around. </> </row><row> -<entry>VID_TYPE_FRAMERAM</><>The video capture goes into the video memory +<entry>VID_TYPE_FRAMERAM</><entry>The video capture goes into the video memory and actually changes it. Applications need to know this so they can clean up after the card</> </row><row> -<entry>VID_TYPE_SCALES</><>The image can be scaled to various sizes, +<entry>VID_TYPE_SCALES</><entry>The image can be scaled to various sizes, rather than being a single fixed size.</> </row><row> -<entry>VID_TYPE_MONOCHROME</><>The capture will be monochrome. This isn't a +<entry>VID_TYPE_MONOCHROME</><entry>The capture will be monochrome. This isn't a complete answer to the question since a mono camera on a colour capture card will still produce mono output.</> </row><row> -<entry>VID_TYPE_SUBCAPTURE</><>The card allows only part of its field of +<entry>VID_TYPE_SUBCAPTURE</><entry>The card allows only part of its field of view to be captured. This enables applications to avoid copying all of a large image into memory when only some section is @@ -1209,18 +1209,18 @@ <tbody> <row> - <entry>channel</><>The channel number we are selecting</entry> + <entry>channel</><entry>The channel number we are selecting</entry> </row><row> - <entry>name</><>The name for this channel. This is intended + <entry>name</><entry>The name for this channel. This is intended to describe the port to the user. Appropriate names are therefore things like "Camera" "SCART input"</entry> </row><row> - <entry>flags</><>Channel properties</entry> + <entry>flags</><entry>Channel properties</entry> </row><row> - <entry>type</><>Input type</entry> + <entry>type</><entry>Input type</entry> </row><row> - <entry>norm</><>The current television encoding being used + <entry>norm</><entry>The current television encoding being used if relevant for this channel. </entry> </row> @@ -1231,9 +1231,9 @@ <tgroup cols=2 align=left> <tbody> <row> - <entry>VIDEO_VC_TUNER</><>Channel has a tuner.</entry> + <entry>VIDEO_VC_TUNER</><entry>Channel has a tuner.</entry> </row><row> - <entry>VIDEO_VC_AUDIO</><>Channel has audio.</entry> + <entry>VIDEO_VC_AUDIO</><entry>Channel has audio.</entry> </row> </tbody> </tgroup> @@ -1242,11 +1242,11 @@ <tgroup cols=2 align=left> <tbody> <row> - <entry>VIDEO_TYPE_TV</><>Television input.</entry> + <entry>VIDEO_TYPE_TV</><entry>Television input.</entry> </row><row> - <entry>VIDEO_TYPE_CAMERA</><>Fixed camera input.</entry> + <entry>VIDEO_TYPE_CAMERA</><entry>Fixed camera input.</entry> </row><row> - <entry>0</><>Type is unknown.</entry> + <entry>0</><entry>Type is unknown.</entry> </row> </tbody> </tgroup> @@ -1255,13 +1255,13 @@ <tgroup cols=2 align=left> <tbody> <row> - <entry>VIDEO_MODE_PAL</><>PAL encoded Television</entry> + <entry>VIDEO_MODE_PAL</><entry>PAL encoded Television</entry> </row><row> - <entry>VIDEO_MODE_NTSC</><>NTSC (US) encoded Television</entry> + <entry>VIDEO_MODE_NTSC</><entry>NTSC (US) encoded Television</entry> </row><row> - <entry>VIDEO_MODE_SECAM</><>SECAM (French) Television </entry> + <entry>VIDEO_MODE_SECAM</><entry>SECAM (French) Television </entry> </row><row> - <entry>VIDEO_MODE_AUTO</><>Automatic switching, or format does not + <entry>VIDEO_MODE_AUTO</><entry>Automatic switching, or format does not matter</entry> </row> </tbody> @@ -1341,13 +1341,13 @@ <tgroup cols=2 align=left> <tbody> <row> - <entry>GREY</><>Linear greyscale. This is for simple cameras and the + <entry>GREY</><entry>Linear greyscale. This is for simple cameras and the like</> </row><row> - <entry>RGB565</><>The top 5 bits hold 32 red levels, the next six bits + <entry>RGB565</><entry>The top 5 bits hold 32 red levels, the next six bits hold green and the low 5 bits hold blue. </> </row><row> - <entry>RGB555</><>The top bit is clear. The red green and blue levels + <entry>RGB555</><entry>The top bit is clear. The red green and blue levels each occupy five bits.</> </row> </tbody> @@ -1479,32 +1479,32 @@ <tgroup cols=2 align=left> <tbody> <row> - <entry>width</><>The width in pixels of the desired image. The card + <entry>width</><entry>The width in pixels of the desired image. The card may use a smaller size if this size is not available</> </row><row> - <entry>height</><>The height of the image. The card may use a smaller + <entry>height</><entry>The height of the image. The card may use a smaller size if this size is not available.</> </row><row> - <entry>x</><> The X position of the top left of the window. This + <entry>x</><entry> The X position of the top left of the window. This is in pixels relative to the left hand edge of the picture. Not all cards can display images aligned on any pixel boundary. If the position is unsuitable the card adjusts the image right and reduces the width.</> </row><row> - <entry>y</><> The Y position of the top left of the window. This + <entry>y</><entry> The Y position of the top left of the window. This is counted in pixels relative to the top edge of the picture. As with the width if the card cannot display starting on this line it will adjust the values.</> </row><row> - <entry>chromakey</><>The colour (expressed in RGB32 format) for the + <entry>chromakey</><entry>The colour (expressed in RGB32 format) for the chromakey colour if chroma keying is being used. </> </row><row> - <entry>clips</><>An array of rectangles that must not be drawn + <entry>clips</><entry>An array of rectangles that must not be drawn over.</> </row><row> - <entry>clipcount</><>The number of clips in this array.</> + <entry>clipcount</><entry>The number of clips in this array.</> </row> </tbody> </tgroup> @@ -1516,11 +1516,11 @@ <tgroup cols=2 align=left> <tbody> <row> - <entry>x, y</><>Co-ordinates relative to the display</> + <entry>x, y</><entry>Co-ordinates relative to the display</> </row><row> - <entry>width, height</><>Width and height in pixels</> + <entry>width, height</><entry>Width and height in pixels</> </row><row> - <entry>next</><>A spare field for the application to use</> + <entry>next</><entry>A spare field for the application to use</> </row> </tbody> </tgroup> diff -u --recursive --new-file v2.4.6/linux/Documentation/README.nsp_cs.eng linux/Documentation/README.nsp_cs.eng --- v2.4.6/linux/Documentation/README.nsp_cs.eng Wed Dec 31 16:00:00 1969 +++ linux/Documentation/README.nsp_cs.eng Wed Jul 4 11:50:38 2001 @@ -0,0 +1,127 @@ + + WorkBiT NinjaSCSI-3/32Bi driver for Linux + +1. Comment + This is Workbit corp.'s(http://www.workbit.co.jp/) NinjaSCSI-3 +(http://www.workbit.co.jp/ts/z_nj3r.html) and NinjaSCSI-32Bi +(http://www.workbit.co.jp/ts/z_njsc32bi.html) PCMCIA card driver module +for Linux. + +2. My Linux environment +Linux kernel: 2.4.0 / 2.2.18 +pcmcia-cs: 3.1.24 +gcc: gcc-2.95.2 +PC card: I-O data PCSC-F (NinjaSCSI-3) + I-O data CBSC-II in 16 bit mode (NinjaSCSI-32Bi) +SCSI device: I-O data CDPS-PX24 (CD-ROM drive) + Media Intelligent MMO-640GT (Optical disk drive) + +3. Install +[1] Check your PC card is true "NinjaSCSI-3" card. + If you installed pcmcia-cs already, pcmcia reports your card as UNKNOWN + card, and write ["WBT", "NinjaSCSI-3", "R1.0"] or some other string to + your console or log file. + You can also use "cardctl" program (this program is in pcmcia-cs source + code) to get more info. + +# cat /var/log/messgaes +... +Jan 2 03:45:06 lindberg cardmgr[78]: unsupported card in socket 1 +Jan 2 03:45:06 lindberg cardmgr[78]: product info: "WBT", "NinjaSCSI-3", "R1.0" +... +# cardctl ident +Socket 0: + no product info available +Socket 1: + product info: "IO DATA", "CBSC16 ", "1" + + +[2] Get Linux kernel source, and extract it to /usr/src. + Because NinjaSCSI driver requiers some SCSI header files in Linux kernel + source. + I recomend rebuilding your kernel. This eliminate some versioning problem. +$ cd /usr/src +$ tar -zxvf linux-x.x.x.tar.gz +$ cd linux +$ make config +... + +[3] If you use this driver with Kernel 2.2, Unpack pcmcia-cs in some directory + and make & install. This driver requies pcmcia-cs header file. +$ cd /usr/src +$ tar zxvf cs-pcmcia-cs-3.x.x.tar.gz +... + +[4] Extract this driver's archive somewhere, and edit Makefile, then do make. +$ tar -zxvf nsp_cs-x.x.tar.gz +$ cd nsp_cs-x.x +$ make + +[5] Copy nsp_cs.o to suitable plase, like /lib/modules/<Kernel version>/pcmcia/ . + +[6] Add these lines to /etc/pcmcia/config . + If you yse pcmcia-cs-3.1.8 or later, we can use "nsp_cs.conf" file. + So, you don't need to edit file. Just copy to /etc/pcmcia/ . + +------------------------------------- +device "nsp_cs" + class "scsi" module "nsp_cs" + +card "WorkBit NinjaSCSI-3" + version "WBT", "NinjaSCSI-3", "R1.0" + bind "nsp_cs" + +card "WorkBit NinjaSCSI-32Bi (16bit)" + version "WORKBIT", "UltraNinja-16", "1" + bind "nsp_cs" + +# OEM +card "WorkBit NinjaSCSI-32Bi (16bit) / IO-DATA" + version "IO DATA", "CBSC16 ", "1" + bind "nsp_cs" + +# OEM +card "WorkBit NinjaSCSI-32Bi (16bit) / KME-1" + version "KME ", "SCSI-CARD-001", "1" + bind "nsp_cs" +card "WorkBit NinjaSCSI-32Bi (16bit) / KME-2" + version "KME ", "SCSI-CARD-002", "1" + bind "nsp_cs" +card "WorkBit NinjaSCSI-32Bi (16bit) / KME-3" + version "KME ", "SCSI-CARD-003", "1" + bind "nsp_cs" +card "WorkBit NinjaSCSI-32Bi (16bit) / KME-4" + version "KME ", "SCSI-CARD-004", "1" + bind "nsp_cs" +------------------------------------- + +[7] Boot (or reboot) pcmcia-cs. +# /etc/rc.d/rc.pcmcia start (BSD style) +or +# /etc/init.d/pcmcia start (SYSV style) + + +4. History +See README.nin_cs . + +5. Caution + If you eject card when doing some operation for your SCSI device or suspend +your computer, you encount some *BAD* error like disk crash. + It works good when I using this driver right way. But I'm not guarantee +your data. Please backup your data when you use this driver. + +6. Known Bugs + Some write error occurs when you use slow device. + +7. Testing + Please send me some reports(bug reports etc..) of this software. +When you send report, please tell me these or more. + card name + kernel version + your SCSI device name(hard drive, CD-ROM, etc...) + +8. Copyright + See GPL. + + +2001/02/01 yokota@netlab.is.tsukuba.ac.jp <YOKOTA Hiroshi> diff -u --recursive --new-file v2.4.6/linux/Documentation/fb/00-INDEX linux/Documentation/fb/00-INDEX --- v2.4.6/linux/Documentation/fb/00-INDEX Tue Jul 18 22:54:33 2000 +++ linux/Documentation/fb/00-INDEX Tue Jul 10 20:16:30 2001 @@ -17,6 +17,8 @@ - info on the Cirrus Logic frame buffer driver matroxfb.txt - info on the Matrox frame buffer driver +pvr2fb.txt + - info on the PowerVR 2 frame buffer driver tgafb.txt - info on the TGA (DECChip 21030) frame buffer driver vesafb.txt diff -u --recursive --new-file v2.4.6/linux/Documentation/fb/pvr2fb.txt linux/Documentation/fb/pvr2fb.txt --- v2.4.6/linux/Documentation/fb/pvr2fb.txt Wed Dec 31 16:00:00 1969 +++ linux/Documentation/fb/pvr2fb.txt Tue Jul 10 20:16:30 2001 @@ -0,0 +1,61 @@ +$Id: pvr2fb.txt,v 1.1 2001/05/24 05:09:16 mrbrown Exp $ + +What is pvr2fb? +=============== + +This is a driver for PowerVR 2 based graphics frame buffers, such as the +one found in the Dreamcast. + +Advantages: + + * It provides a nice large console (128 cols + 48 lines with 1024x768) + without using tiny, unreadable fonts. + * You can run XF86_FBDev on top of /dev/fb0 + * Most important: boot logo :-) + +Disadvantages: + + * Driver is currently limited to the Dreamcast PowerVR 2 implementation + at the time of this writing. + +Configuration +============= + +You can pass kernel command line options to pvr2fb with +`video=pvr2:option1,option2:value2,option3' (multiple options should be +separated by comma, values are separated from options by `:'). +Accepted options: + +font:X - default font to use. All fonts are supported, including the + SUN12x22 font which is very nice at high resolutions. + +mode:X - default video mode. The following video modes are supported: + 640x240-60, 640x480-60. + + Note: the 640x240 mode is currently broken, and should not be + used for any reason. It is only mentioned as a reference. + +inverse - invert colors on screen (for LCD displays) + +nomtrr - disables write combining on frame buffer. This slows down driver + but there is reported minor incompatibility between GUS DMA and + XFree under high loads if write combining is enabled (sound + dropouts). MTRR is enabled by default on systems that have it + configured and that support it. + +cable:X - cable type. This can be any of the following: vga, rgb, and + composite. If none is specified, we guess. + +output:X - output type. This can be any of the following: pal, ntsc, and + vga. If none is specified, we guess. + +X11 +=== + +XF86_FBDev should work, in theory. At the time of this writing it is +totally untested and may or may not even portray the beginnings of +working. If you end up testing this, please let me know! + +-- +Paul Mundt <lethal@linuxdc.org> + diff -u --recursive --new-file v2.4.6/linux/Documentation/filesystems/cramfs.txt linux/Documentation/filesystems/cramfs.txt --- v2.4.6/linux/Documentation/filesystems/cramfs.txt Sat May 20 11:30:31 2000 +++ linux/Documentation/filesystems/cramfs.txt Thu Jul 19 16:14:53 2001 @@ -47,6 +47,21 @@ mind the filesystem becoming unreadable to future kernels. +For /usr/share/magic +------------------ + +0 long 0x28cd3d45 Linux cramfs +>4 long x size %d +>8 long x flags 0x%x +>12 long x future 0x%x +>16 string >\0 signature "%.16s" +>32 long x fsid.crc 0x%x +>36 long x fsid.edition %d +>40 long x fsid.blocks %d +>44 long x fsid.files %d +>48 string >\0 name "%.16s" + + Hacker Notes ------------ diff -u --recursive --new-file v2.4.6/linux/Documentation/filesystems/devfs/ChangeLog linux/Documentation/filesystems/devfs/ChangeLog --- v2.4.6/linux/Documentation/filesystems/devfs/ChangeLog Tue Jul 3 17:08:18 2001 +++ linux/Documentation/filesystems/devfs/ChangeLog Wed Jul 11 14:55:41 2001 @@ -1661,3 +1661,17 @@ - Replaced <devfsd_read> stack usage with <devfsd_ioctl> kmalloc - Simplified locking in <devfsd_ioctl> and fixed memory leak +=============================================================================== +Changes for patch v182 + +- Created <devfs_*alloc_major> and <devfs_*alloc_devnum> + +- Removed broken devnum allocation and use <devfs_alloc_devnum> + +- Fixed old devnum leak by calling new <devfs_dealloc_devnum> + +- Created <devfs_*alloc_unique_number> + +- Fixed number leak for /dev/cdroms/cdrom%d + +- Fixed number leak for /dev/discs/disc%d diff -u --recursive --new-file v2.4.6/linux/Documentation/filesystems/ext2.txt linux/Documentation/filesystems/ext2.txt --- v2.4.6/linux/Documentation/filesystems/ext2.txt Fri Apr 20 16:18:35 2001 +++ linux/Documentation/filesystems/ext2.txt Wed Jul 11 15:44:45 2001 @@ -299,6 +299,8 @@ so 8kB blocks are only allowed on Alpha systems (and other architectures which support larger pages). +There is an upper limit of 32768 subdirectories in a single directory. + There is a "soft" upper limit of about 10-15k files in a single directory with the current linear linked-list directory implementation. This limit stems from performance problems when creating and deleting (and also diff -u --recursive --new-file v2.4.6/linux/Documentation/filesystems/ntfs.txt linux/Documentation/filesystems/ntfs.txt --- v2.4.6/linux/Documentation/filesystems/ntfs.txt Fri Feb 16 15:53:08 2001 +++ linux/Documentation/filesystems/ntfs.txt Mon Jul 16 15:14:10 2001 @@ -1,6 +1,9 @@ NTFS Overview ============= +Driver development has as of recently (since June '01) been sponsored +by Legato Systems, Inc. (http://www.legato.com) + To mount an NTFS volume, use the filesystem type 'ntfs'. The driver currently works only in read-only mode, with no fault-tolerance supported. @@ -9,9 +12,18 @@ distribution from Sourceforge at http://sourceforge.net/projects/linux-ntfs/ and always run the included ntfsfix utility after performing a write to an NTFS partition from Linux to fix some of the damage done by the Linux NTFS -driver. You should run ntfsfix _after_ unmounting the partition in Linux but -_before_ rebooting into Windows. During the next reboot into Windows, chkdsk -will be run automatically to fix the remaining damage. +driver and to schedule an automatic chkdsk when Windows reboots. You should +run ntfsfix _after_ unmounting the partition in Linux but _before_ rebooting +into Windows. During the next reboot into Windows, chkdsk will be run +automatically fixing the remaining damage. If no errors are found it is a +good indication that the driver + ntfsfix together worked to full +satisfaction. (-; + +Please note that the experimental write support is limited to Windows NT4 and +earlier versions at the moment. + +If you think you have discovered a bug please have look at the "Known bugs" +section below to see whether it isn't known already. For ftdisk support, limited success was reported with volume sets on top of the md driver, although mirror and stripe sets should work as well - if the @@ -19,25 +31,78 @@ using the md driver will fail if any of your NTFS partitions have an odd number of sectors. -Please note that the experimental write support is limited to -Windows NT4 and earlier versions at the moment. +Supported mount options +======================= + +iocharset=name Character set to use when returning file names. + Unlike VFAT, NTFS suppresses names that contain + unconvertible characters + +utf8=<bool> Use UTF-8 for converting file names + +uni_xlate=<bool>,2 Use the VFAT-style encoding for file names outside + the current character set. A boolean value will + enable the feature, a value of 2 will enable the + encoding as documented in vfat.txt: + ':', (u & 0x3f), ((u>>6) & 0x3f), (u>>12), -The ntfs driver supports the following mount options: -iocharset=name Character set to use when returning file names. - Unlike VFAT, NTFS suppresses names that contain - unconvertible characters -utf8=<bool> Use UTF-8 for converting file names -uni_xlate=<bool>,2 Use the VFAT-style encoding for file names outside - the current character set. A boolean value will - enable the feature, a value of 2 will enable the - encoding as documented in vfat.txt: - ':', (u & 0x3f), ((u>>6) & 0x3f), (u>>12), uid= gid= -umask= These options work as documented in mount(8). - By default, the files are owned by root and - not readable by somebody else. -posix=<bool> If enabled, the file system distinguishes between - upper and lower case. The 8.3 alias names are presented - as hard links instead of being suppressed. +umask= These options work as documented in mount(8). + By default, the files are owned by root and + not readable by anyone else. + +posix=<bool> If enabled, the file system distinguishes between + upper and lower case. The 8.3 alias names are presented + as hard links instead of being suppressed. + +show_sys_files=<bool> If enabled, show all system files as normal files. Note + that $MFT does not appear unless specifically + requested. For example in bash, use: "ls -l \$MFT". + Be careful not to write anything to them or you could + crash the kernel and/or corrupt your file system! + +Known bugs and (mis-)features +============================= + +- Do not use the driver for writing as it corrupts the file system. If you do + use it, get the Linux-NTFS tools and use the ntfsfix utility after + dismounting a partition you wrote to. + +- Use the show_sys_files mount option which should make things work generally + better. (It results in both the short and long file names being shown as well + as the sytem files.) + +- Writing of extension records is not supported properly. + +Please send bug reports/comments/feed back/abuse to the Linux-NTFS development +list at sourceforge: linux-ntfs-dev@lists.sourceforge.net + +ChangeLog +========= + +NTFS 1.1.15 (changes since kernel 2.4.4's NTFS driver): + + - New mount option show_sys_files=<bool> to show all system files as + normal files. + - Support for files and in general any attributes up to the full 2TiB + size supported by the NTFS filesystem. Note we only support up to + 32-bits worth of inodes/clusters at this point. + - Support for more than 128kiB sized runlists (using vmalloc_32() + instead of kmalloc()). + - Fixed races in allocation of clusters and mft records. + - Fixed major bugs in attribute handling / searching / collation. + - Fixed major bugs in compressing a run list into a mapping pairs array. + - Fixed major bugs in inode allocation. Especially file create and + mkdir. + - Fixed memory leaks. + - Fixed major bug in inode layout assignment of sequence numbers. + - Lots of other bug fixes I can't think of right now... + - Fixed NULL bug found by the Stanford checker in ntfs_dupuni2map(). + - Convert large stack variable to dynamically allocated one in + ntfs_get_free_cluster_count() (found by Stanford checker). + +Kernel 2.4.4: + + - Started ChangeLog. diff -u --recursive --new-file v2.4.6/linux/Documentation/ioctl-number.txt linux/Documentation/ioctl-number.txt --- v2.4.6/linux/Documentation/ioctl-number.txt Sat May 19 17:54:14 2001 +++ linux/Documentation/ioctl-number.txt Wed Jul 11 16:35:37 2001 @@ -187,3 +187,5 @@ 0xB1 00-1F PPPoX <mailto:mostrows@styx.uwaterloo.ca> 0xCB 00-1F CBM serial IEC bus in development: <mailto:michael.klein@puffin.lb.shuttle.de> + +0xFE 00-9F Logical Volume Manager <mailto:linux-lvm@sistina.com> diff -u --recursive --new-file v2.4.6/linux/Documentation/networking/8139too.txt linux/Documentation/networking/8139too.txt --- v2.4.6/linux/Documentation/networking/8139too.txt Mon May 7 14:13:19 2001 +++ linux/Documentation/networking/8139too.txt Sun Jul 8 13:17:30 2001 @@ -185,6 +185,20 @@ Change History -------------- +Version 0.9.18 - July 6, 2001 + +* Fix race leading to crashes on some machines. +* Minimize race leading to low performance. +* Correct interrupt acknowledgement to cover all three + relevant Rx events. +* Add ethtool driver info support. +* Collect additional driver-internal statistics. +* Add descriptions for module parameters. +* Support new SIOCxMIIxxx ioctls added in kernel 2.4.6. +* Multicast filter big endian fix. +* Support new PCI PM API added in kernel 2.4.6. + + Version 0.9.17 - May 7, 2001 * Fix chipset wakeup bug which prevent media connection for 8139B diff -u --recursive --new-file v2.4.6/linux/Documentation/networking/dl2k.txt linux/Documentation/networking/dl2k.txt --- v2.4.6/linux/Documentation/networking/dl2k.txt Wed Dec 31 16:00:00 1969 +++ linux/Documentation/networking/dl2k.txt Tue Jul 17 18:53:55 2001 @@ -0,0 +1,246 @@ + + D-Link DL2000-based Gigabit Ethernet Adapter Installation + for Linux + July 5, 2001 + +Contents +======== + - Compatibility List + - Quick Install + - Compiling the Driver + - Installing the Driver + - Option parameter + - Configuration Script Sample + - Troubleshooting + + +Compatiblity List +================= +Adapter Support: + +D-Link DGE-550T Gigabit Ethernet Adapter. +D-Link DL2000-based Gigabit Ethernet Adapter. + + +The driver support Linux kernal 2.4.x later. We had tested it +on the environments below. + + . Red Hat v6.2 (update to kernel 2.4.4) + . Red Hat v7.0 (update to kernel 2.4.4) + . Red Hat v7.1 (kernel 2.4.2-2) + + +Quick Install +============= +Install linux driver as following command: + +1. make all +2. insmod dl2x.o +3. ifconfig eth0 up 10.xxx.xxx.xxx netmask 255.0.0.0 + ^^^^^^^^^^^^^^^\ ^^^^^^^^\ + IP NETMASK +Now eth0 bring up, you can test it by "ping" or get more information by +"ifconfig". If test ok, then continue next step. + +4. cp dl2x.o /lib/modules/`uname -r`/kernel/drivers/net +5. Add the following lines to /etc/modules.conf: + alias eth0 dl2x +6. Run "netconfig" or "netconf" to create configuration script ifcfg-eth0 + located at /etc/sysconfig/network-scripts or create it manually. + [see - Configuration Script Sample] +7. Driver will automatically load and configure at next boot time. + +Compiling the Driver +==================== + In Linux, NIC drivers are most commonly configured as loadable modules. +The approach of building a monolithic kernel has become obsolete. The driver +can be compiled as part of a monolithic kernel, but is strongly discouraged. +The remainder of this section assumes the driver is built as a loadable module. +In the Linux environment, it is a good idea to rebuild the driver from the +source instead of relying on a precompiled version. This approach provides +better reliability since a precompiled driver might depend on libraries or +kernel features that are not present in a given Linux installation. + +The 3 files necessary to build Linux device driver are dl2x.c, dl2x.h and +Makefile. To compile, the Linux installation must include the gcc compiler, +the kernel source, and the kernel headers. The Linux driver supports Linux +Kernels 2.4.x. Copy the files to a directory and enter the following command +to compile and link the driver: + +CD-ROM drive +------------ + +[root@XXX /] mkdir cdrom +[root@XXX /] mount -r -t iso9660 -o conv=auto /dev/cdrom /cdrom +[root@XXX /] cd root +[root@XXX /root] mkdir dl2x +[root@XXX /root] cd dl2x +[root@XXX dl2x] cp /cdrom/linux/dl2x.tgz /root/dl2x +[root@XXX dl2x] tar xfvz dl2x.tgz +[root@XXX dl2x] make all + +Floppy disc drive +----------------- + +[root@XXX /] cd root +[root@XXX /root] mkdir dl2x +[root@XXX /root] cd dl2x +[root@XXX dl2x] mcopy a:/linux/dl2x.tgz /root/dl2x +[root@XXX dl2x] tar xfvz dl2x.tgz +[root@XXX dl2x] make all + +Installing the Driver +===================== + + Manual Installation + ------------------- + Once the driver has been compiled, it must be loaded, enabled, and bound + to a protocol stack in order to establish network connectivity. To load a + module enter the command: + + insmod dl2x.o + + + or + + insmod dl2x.o <optional parameter> ; add parameter + + =============================================================== + example: insmod dl2x.o media=100mbps_hd + or insmod dl2x.o media=3 + or insmod dl2x.o media=3 2 ; for 2 cards + =============================================================== + + Please reference the list of the command line parameters supported by + the Linux device driver below. + + The insmod command only loads the driver and gives it a name of the form + eth0, eth1, etc. To bring the NIC into an operational state, + it is necessary to issue the following command: + + ifconfig eth0 up + + Finally, to bind the driver to the active protocol (e.g., TCP/IP with + Linux), enter the following command: + + ifup eth0 + + Note that this is meaningful only if the system can find a configuration + script that contains the necessary network information. A sample will be + given in the next paragraph. + + The commands to unload a driver are as follows: + + ifdown eth0 + ifconfig eth0 down + rmmod dl2x.o + + The following are the commands to list the currently loaded modules and + to see the current network configuration. + + lsmod + ifconfig + + + Automated Installation + ---------------------- + This section describes how to install the driver such that it is + automatically loaded and configured at boot time. The following description + is based on a Red Hat 6.0/7.0 distribution, but it can easily be ported to + other distributions as well. + + Red Hat v6.x/v7.x + ----------------- + 1. Copy dl2x.o to the network modules directory, typically + /lib/modules/2.x.x-xx/net or /lib/modules/2.x.x/kernel/drivers/net. + 2. Locate the boot module configuration file, most commonly modules.conf + or conf.modules in the /etc directory. Add the following lines: + + alias ethx dl2x + options dl2x <optional parameters> + + where ethx will be eth0 if the NIC is the only ethernet adapter, eth1 if + one other ethernet adapter is installed, etc. Refer to the table in the + previous section for the list of optional parameters. + 3. Locate the network configuration scripts, normally the + /etc/sysconfig/network-scripts directory, and create a configuration + script named ifcfg-ethx that contains network information. + 4. Note that for most Linux distributions, Red Hat included, a configuration + utility with a graphical user interface is provided to perform steps 2 + and 3 above. + + +Parameter Description +===================== +You can install this driver without any addtional parameter. However, if you +are going to have extensive functions then it is necessary to set extra +parameter. Below is a list of the command line parameters supported by the +Linux device +driver. + +mtu=packet_size - Specifies the maximum packet size. default + is 1500. + +media=xxxxxxxxx - Specifies the media type the NIC operates at. + autosense Autosensing active media. + 10mbps_hd 10Mbps half duplex. + 10mbps_fd 10Mbps full duplex. + 100mbps_hd 100Mbps half duplex. + 100mbps_fd 100Mbps full duplex. + 1000mbps_fd 1000Mbps full duplex. + 1000mbps_hd 1000Mbps half duplex. + 0 Autosensing active media. + 1 10Mbps half duplex. + 2 10Mbps full duplex. + 3 100Mbps half duplex. + 4 100Mbps full duplex. + 5 1000Mbps full duplex. + 6 1000Mbps half duplex. + By default, the NIC operates at autosense. + +vlan=x - Specifies the VLAN ID. If vlan=0, the + Virtual Local Area Network (VLAN) function is + disable. + +jumbo=x - Specifies the jumbo frame support. If jumbo=1, + the NIC accept jumbo frames. By default, this + function is disabled. + +Configuration Script Sample +=========================== +Here is a sample of a simple configuration script: + +DEVICE=eth0 +USERCTL=no +ONBOOT=yes +POOTPROTO=none +BROADCAST=207.200.5.255 +NETWORK=207.200.5.0 +NETMASK=255.255.255.0 +IPADDR=207.200.5.2 + + +Troubleshooting +=============== +Q1. Source files contain behind every line. + Make sure all files are Unix file format (no LF). Try the following + shell command to convert files. + + cat dl2k.c | col -b > dl2k.tmp + mv dl2k.tmp dl2k.c + + OR + + cat dl2k.c | tr -d "\r" > dl2k.tmp + mv dl2k.tmp dl2k.c + +Q2: Could not find header files (*.h) ? + To compile the driver, you need kernel header files. After + installing the kernel source, the header files are usually located in + /usr/src/linux/include, which is the default include directory configured + in Makefile. For some distributions, there is a copy of header files in + /usr/src/include/linux and /usr/src/include/asm, that you can change the + INCLUDEDIR in Makefile to /usr/include without installing kernel source. + Note that RH 7.0 didn't provide correct header files in /usr/include, + including those files will make a wrong version driver. + diff -u --recursive --new-file v2.4.6/linux/Documentation/networking/multicast.txt linux/Documentation/networking/multicast.txt --- v2.4.6/linux/Documentation/networking/multicast.txt Mon Aug 9 10:23:09 1999 +++ linux/Documentation/networking/multicast.txt Wed Jul 4 11:50:38 2001 @@ -39,11 +39,13 @@ hp YES YES YES Hardware hp100 YES YES YES Hardware ibmtr NO NO NO N/A +ioc3-eth YES YES YES Hardware lance YES YES YES Software(#) ne YES YES YES Hardware ni52 <------------------ Buggy ------------------> ni65 YES YES YES Software(#) seeq NO NO NO N/A +sgiseek <------------------ Buggy ------------------> sk_g16 NO NO YES N/A smc-ultra YES YES YES Hardware sunlance YES YES YES Hardware diff -u --recursive --new-file v2.4.6/linux/Documentation/sonypi.txt linux/Documentation/sonypi.txt --- v2.4.6/linux/Documentation/sonypi.txt Wed Dec 31 16:00:00 1969 +++ linux/Documentation/sonypi.txt Wed Jul 4 14:41:33 2001 @@ -0,0 +1,70 @@ +Sony Programmable I/O Control Device Driver Readme +-------------------------------------------------- + Copyright (C) 2001 Stelian Pop <stelian.pop@fr.alcove.com>, Alcôve + Copyright (C) 2001 Michael Ashley <m.ashley@unsw.edu.au> + Copyright (C) 2001 Junichi Morita <jun1m@mars.dti.ne.jp> + Copyright (C) 2000 Takaya Kinjo <t-kinjo@tc4.so-net.ne.jp> + Copyright (C) 2000 Andrew Tridgell <tridge@samba.org> + +This driver enables access to the Sony Programmable I/O Control Device which +can be found in many (all ?) Sony Vaio laptops. + +It will give access (through a user space utility) to some events those laptops +generate, like: + - jogdial events (the small wheel on the side of Vaios) + - capture button events (only on Vaio Picturebook series) + - Fn keys + - bluetooth button (only on C1VR model) + +Those events (see linux/sonypi.h) can be polled using the character device node +/dev/sonypi (major 10, minor auto allocated or specified as a option). + +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). + +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 +Motion Eye camera. + +Please note that this driver was created by reverse engineering the Windows +driver and the ACPI BIOS, because Sony doesn't agree to release any programming +specs for its laptops. If someone convinces them to do so, drop me a note. + +Module options: +--------------- + + minor: minor number of the misc device /dev/sonypi, + default is -1 (automatic allocation, see /proc/misc + or kernel logs) + + camera: if you have a PictureBook series Vaio (with the + integrated MotionEye camera), set this parameter to 1 + in order to let the driver access to the camera + + fnkeyinit: on some Vaios (C1VE, C1VR etc), the Fn key events don't + get enabled unless you set this parameter to 1 + + verbose: print unknown events from the sonypi device + +Module use: +----------- + +In order to automatically load the sonypi module on use, you can put those +lines in your /etc/modules.conf file: + + alias char-major-10-250 sonypi + options sonypi minor=250 fnkeyinit=1 + +This supposes the use of minor 250 for the sonypi device: + + # mknod /dev/sonypi c 10 250 + +Bugs: +----- + + - since all development was done by reverse engineering, there is + _absolutely no guarantee_ that this driver will not crash your + laptop. Permanently. diff -u --recursive --new-file v2.4.6/linux/Documentation/sound/CMI8338 linux/Documentation/sound/CMI8338 --- v2.4.6/linux/Documentation/sound/CMI8338 Fri Jul 28 12:50:52 2000 +++ linux/Documentation/sound/CMI8338 Wed Jul 4 11:50:38 2001 @@ -8,59 +8,80 @@ On-board C-Media chips -WHAT'S NEW +STEPS TO BUILD DRIVER ================================================================================ - 1. Support modem interface for 8738. (select in kernel configuration) - 2. Enable S/PDIF-in to S/PDIF-out (S/PDIF loop). - 3. Enable 4 channels analog duplicate mode on 3 jack or 4 jack - configuration. + 1. Backup the Config.in and Makefile in the sound driver directory + (/usr/src/linux/driver/sound). + The Configure.help provide help when you config driver in step + 4, please backup the original one (/usr/src/linux/Document) and + copy this file. + The cmpci is document for the driver in detail, please copy it + to /usr/src/linux/Document/sound so you can refer it. Backup if + there is already one. + 2. Extract the tar file by 'tar xvzf cmpci-xx.tar.gz' in the above + directory. - Be aware: C-Media Electronics Inc. is basically an IC design house, - and whose development of software drivers is mainly for use by its OEM - customers in their products. C-Media Electronics Inc. itself does not - manufacture end-user products, such as PC or sound cards, so it can - not fully control the drivers provided to consumers. Drivers provided - at this site, therefore, MAY NOT BE APPLICABLE to all sound cards. - Drivers you download from this site may function well at certain - situation, but C-Media Electronics Inc. does not give any guarantee or - assurances. Please be aware that these drivers might cause some - technical difficulties when installed + 3. Change directory to /usr/src/linux + 4. Config cm8338 driver by 'make menuconfig', 'make config' or + 'make xconfig' command. -1. Config cm8338 driver by 'make menuconfig' or 'make config' command. + 5. Please select Sound Card (CONFIG_SOUND=m) support and CMPCI + driver (CONFIG_SOUND_CMPCI=m) as modules. Resident mode not tested. + For driver option, please refer 'DRIVER PARAMETER' -2. Please select Sound Card (CONFIG_SOUND=m) support and CMPCI driver (CONFIG_SOUND_CMPCI=m) as modules. Resident mode not tested. + 6. Compile the kernel if necessary. -3. Compile the kernel if necessary. + 7. Compile the modules by 'make modules'. -4. Compile the modules by 'make modules'. + 8. Install the modules by 'make modules_install' -5. Install the modules by 'make modules_install' -6. Before first time to run the driver, create module dependency by 'depmod -a' +INSTALL DRIVER +================================================================================ + + 1. Before first time to run the driver, create module dependency by + 'depmod -a' + + 2. To install the driver manually, enter 'modprobe cmpci'. + + 3. Driver installation for various distributions: -7. To install the driver, enter 'modprobe cmpci'. + a. Slackware 4.0 + Add the 'modprobe cmpci' command in your /etc/rc.d/rc.modules + file.so you can start the driver automatically each time booting. + b. Caldera OpenLinux 2.2 + Use LISA to load the cmpci module. -DRIVER PARAMETERS + c. RedHat 6.0 and S.u.S.E. 6.1 + Add following command in /etc/conf.modules: + + alias sound cmpci + + also visit http://www.cmedia.com.tw for installation instruction. + +DRIVER PARAMETER ================================================================================ Some functions for the cm8738 can be configured in Kernel Configuration or modules parameters. Set these parameters to 1 to enable. + mpu_io: I/O ports base for MPU-401, 0 if disabled. + fm_io: I/O ports base for OPL-3, 0 if disabled. + spdif_inverse:Inverse the S/PDIF-in signal, this depends on your + CD-ROM or DVD-ROM. spdif_loop: Enable S/PDIF loop, this route S/PDIF-in to S/PDIF-out directly. - four_ch: Enable 4 channels mode, rear-out or line-in will output - the same as line-out. - rear_out: Enable this if you have independent rear-out jacket on - your sound card, otherwise line-in will be used as + speakers: Number of speakers used. + use_line_as_rear:Enable this if you want to use line-in as rear-out. + use_line_as_bass:Enable this if you want to use line-in as + bass-out. modem: You will need to set this parameter if you want to use the HSP modem. You need install the pctel.o, the modem driver itself. - - (You will need to get the pctel driver (binary only) and the support for - this option from the CMI site. It is not included in the Linux kernel - proper as it is non-free). + joystick: Enable joystick. You will need to install Linux joystick + driver. diff -u --recursive --new-file v2.4.6/linux/Documentation/sound/OPL3-SA2 linux/Documentation/sound/OPL3-SA2 --- v2.4.6/linux/Documentation/sound/OPL3-SA2 Sun Feb 4 10:05:29 2001 +++ linux/Documentation/sound/OPL3-SA2 Wed Jul 18 07:14:01 2001 @@ -21,7 +21,7 @@ different chipset, the OPL3-SAx. After an email exhange with Yamaha, however, it turns out that the 719 is just a re-badged 715, and the chipsets are identical. The chipset detection code -has been updated to refkect this. +has been updated to reflect this. Anyways, all of these chipsets implement the following devices: diff -u --recursive --new-file v2.4.6/linux/Documentation/usb/philips.txt linux/Documentation/usb/philips.txt --- v2.4.6/linux/Documentation/usb/philips.txt Tue May 22 10:25:36 2001 +++ linux/Documentation/usb/philips.txt Wed Jul 4 11:50:38 2001 @@ -34,6 +34,10 @@ specificly, red and blue are swapped), try palette=bgr24 or palette=rgb24. + Only the native yuv420/yuv420p format is supported by the in kernel driver. + If you want to use other formats with in-kernel conversion download the + driver from the URL given. [Alan] + fbufs This paramter specifies the number of internal buffers to use for storing frames from the cam. This will help if the process that reads images from diff -u --recursive --new-file v2.4.6/linux/Documentation/video4linux/Zoran linux/Documentation/video4linux/Zoran --- v2.4.6/linux/Documentation/video4linux/Zoran Wed Dec 31 16:00:00 1969 +++ linux/Documentation/video4linux/Zoran Wed Jul 4 14:41:33 2001 @@ -0,0 +1,517 @@ +DC10/DC10plus/LML33/Buz Driver for Linux +========================================= + +by Rainer Johanni <Rainer@Johanni.de> (for Iomega Buz Driver) + +Adapted for DC10/DC10plus by Wolfgang Scherr <scherr@net4you.net> + +Further changes for DC10/DC10plus and LML33 cards by +Serguei Miridonov <mirsev@cicese.mx> + +Current homepage: http://www.cicese.mx/~mirsev/Linux/DC10plus/ +Current maintainer: Serguei Miridonov <mirsev@cicese.mx> + + This is a driver for DC10plus capture cards from Pinnacle Systems + Inc., LML33 cards from Linux Media Labs and Buz from Iomega. + It also works with many old Miro DC10 cards with SAA7110A TV decoder + and ADV7176 TV encoder (please, make sure that your card has these + chips, otherwise the driver will not work). + + The driver is Video4Linux compliant and contains extensions to + provide hardware support for full motion MJPEG compression and + decompression. Since this driver is a derivative from the driver for + Buz Iomega cards written by Dr. Rainer Johanni, + http://www.johanni.de/munich-vision/buz/ they both have compatible + API. I hope that this API will become a part of V4L standard. + +Copyright: This driver is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License. Please, +check http://www.gnu.org/ for details. + +No warranty: This software is provided on AN "AS-IS" basis WITHOUT +WARRANTY OF ANY KIND. YOU USE IT AT YOUR OWN RISK. + + + +CONTENTS +~~~~~~~~ + +Supported Formats +Hardware compression +Compiling and Loading the Driver +Driver Options +Tested applications +Programming interface +Features for testing +Mailing lists +Bug Reports + + +Supported Formats +================= + +Card: DC10/DC10plus LML33/Buz + +TV standard: NTSC/PAL/SECAM(*) NTSC/PAL + +Format: Square pixel CCIR.601 + 640x480 NTSC 720x480 NTSC + 768x576 PAL/SECAM(*) 720x576 PAL + +Frame rates: 30 frames/60 fields per second NTSC + 25 frames/50 fields per second PAL/SECAM(*) + +(*) - SECAM is supported for input only in DC10/DC10plus cards. The +output of the recorded SECAM video stream will be in PAL standard. +Also, please, note that monitoring of the SECAM input signal at the +DC10/DC10plus analog output may not be available. Please, use +appropriate application like XawTV to watch full color SECAM video at +the card input. + +Hardware compression +==================== + +Since the card provides hardware compression, even low end machines can +be successfully used for movie capture and playback. I'm testing the +driver with with 2.2.16 kernel running on 233 MHz Pentium MMX with 64M +RAM on 430TX motherboard and with 10GB IDE drive from Western Digital +Corp. + +On one test run with DC10plus card I've got 0 frames dropped during +about 20 minutes of full motion NTSC (I live in Mexico) video capture +with fully synchronized audio. The command was + + lavrec -fa -in -d1 -l -1 -q30 -w /dos/g/capture/Linux/test%03d.avi + +for recording, and + + lavplay -n128 /dos/g/capture/Linux/test*.avi + +for playback. (See lavtools distribution for more information). + +Typical run of similar test can provide as few as 6-8 dropped frames per +half of an hour. You mileage may vary, though. + +Compiling and Loading the Driver +================================ + +You should run a 2.2.x kernel in order to use this driver. The driver +was also tested with 2.4-test6 kernel, so hopefully it will work +with 2.4 kernels too. + +I would recommend to use only official kernels from www.kernel.org and +its mirrors. Kernels supplied with some Linux distributions may be +patched in some way to meet specific needs of particular Linux +distributor and could be incompatible with this driver. As a driver +maintainer, I am not able to follow every unofficial kernel release, +and no unofficial kernels will be supported. + +Besides the files in this directory, the driver needs the 'videodev' +and the 'i2c' module from the Linux kernel (i2c-old for 2.4 kernels). +In order to get these modules available, enable module support for +VIDEODEV and BTTV (which implies i2c) in your 2.2.x kernel +configuration. You will find these devices in the menu "Character +Devices" in your Kernel Configuration. + +In newer kernels (2.4) instead of BTTV you should enable support for +Iomega Buz cards and for Zoran 36060/36067 chipset. This will include +i2c or i2c-old modules and Buz/LML33 driver. However, instead of +modules for Buz/LML33 driver from the kernel, use modules from _this_ +driver. + +To compile the driver, just type make. + +Before you load the driver you must have a video device at major device +node 81. If you don't have it yet, do the following (as root!): + +cd /dev +mknod video0 c 81 0 +ln -s video0 video + +If you have more than one card, add more nodes in /dev directory: + +mknod video1 c 81 1 +mknod video2 c 81 2 +... + +The driver should operate properly with several cards. It was tested +with one DC10plus and one LML33 cards installed together and the driver +correctly identifies both cards and works with both of them. + +Currently the driver does not support LML33 and Buz cards installed +together in the same system. This will be fixed in future versions. + +Edit the 'update' script if you want to give the driver special options +(see below for options descriptions) and then type (as root) + +./update <card_list> + +to insert all necessary modules into the kernel. <card_list> is a list of +cards installed in your system separated by white space. Supported cards +are dc10, dc10plus, lml33, and buz. For example, if you have both dc10plus +and lml33 cards, please type + +./update dc10 lml33 + +If you want to make full use of the Video for Linux _uncompressed_ +grabbing facilities, you must either + +- obtain and install the "big_physarea patch" for your kernel and + 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 + + or + +- start your kernel with the mem=xxx option, where xxx is your + real memory minus the memory needed for the buffers. + For doing this add an entry in lilo.conf (if you use lilo): + append "mem=xxxM" + or add a line in your linux.par file (if you use loadlin): + mem=xxxM + +The second method is by far easier, however it is dangerous if more +than one driver at a time has the idea to use the memory leftover by +setting the mem=xxx parameter below the actual memory size. + +Read also below how to use this memory! + + + If you use only MJPEG compressed capture provided by the driver, you + should not need large memory areas for DMA. In this case, you will be + able to capture and playback movies with lavtools, however you will + not be able to use capture features of XawTV and other similar + programs (you can still watch video on the screen). + + + +Driver Options +============== + +You are able to customize the behavior of the driver by giving +it some options at start time. + +default_input, default_norm +--------------------------- + +As soon as the driver is loaded, the Buz samples video signals +from one of its input ports and displays it on its output. +The driver uses the Composite Input and the video norm PAL for this. +If you want to change this default behavior, set default_input=1 +(for S-VHS input) or default_norm=1 for NTSC or default_norm=2 +for SECAM (DC10/DC10plus only). + +lock_norm +--------- + +This option was introduced to disable norm (TV standard) change by some +not well behaving programs. For example, if you have some application +which was written by somebody who lives in a country with PAL standard, +this program may not have NTSC option and may always try to set the +driver to PAL. In this case, you may load the driver with +default_norm=1 and lock_norm=1 and the card will be forced to work in +NTSC standard only. + + Options: + + lock_norm=0 default, TV standard change is enabled; + lock_norm=1 TV standard change is disabled but the driver + will not notify the application about any error; + lock_norm=2 TV standard change is disabled and the driver + will notify the program that TV standards other + than set by default_norm=X option are not + supported. + +pass_through +------------ + +When the driver is not in use (device is not opened by any program) and +pass_through=0 (default) the driver will set the TV encoder to produce +color bar signal at the output. If the driver was loaded with +pass_through=1, the color bar will be disabled and input signal will be +sent to the output even if the driver not in use. If you have LML33 card +and wish the color bar signal at the output, you will also need to set +lml33dpath=1 (please, see next section). + +lml33dpath +---------- + +LML33 card normally (lml33dpath=0) connects its output to the input +using analog switch. Additionally, it also allows real-time monitoring +of digitized video using TV monitor connected to the output. This +"digital path" option can be enabled setting lml33dpath=1. In this +mode, the input is connected only to the TV decoder, digital video data +is sent via internal video bus to the TV encoder and resulting analog +signal is sent to the output. This mode could be very useful for testing and +picture adjustment while watching video at the TV monitor connected to +the output. However, because of lack of 75 ohm terminating resistors at +TV decoder input, the signal will suffer serious distortions. + +# These distortions could be eliminated by soldering two 75 ohm resistors +# in LML33 card: in parallel to capacitors C73 and C82 (see schematics of +# H33 board available at www.linuxmedialabs.com and www.zoran.com). Be +# aware, however, that doing so will void card warranty and the card, +# after this change, must always be used with loading option lml33dpath=1. +# +# WARNING: I DID NOT TRY THIS CARD CHANGE YET, THIS IS JUST AN ASSUMPTION +# AND I WILL NOT BE RESPONSIBLE FOR ANY DAMAGE ASSOCIATED WITH THIS +# CHANGE. IF YOU WISH TO TRY IT, DO IT AT YOUR OWN RISK. + +Please, note that DC10/DC10plus cards always use "digital path" for +signal monitoring. Its input and output are both properly terminated +and the digitized signal quality does not depend on the connection of +the output load. + + +v4l_nbufs, v4l_bufsize +---------------------- + +In order to make to make full use of the Video for Linux uncompressed +picture grabbing facilities of the driver (which are needed by many +Video for Linux applications), the driver needs a set of physically +contiguous buffers for grabbing. These parameters determine how many +buffers of which size the driver will allocate at open (the open will +fail if it is unable to do so!). + +These values do not affect the MJPEG grabbing facilities of the driver, +they are needed for uncompressed image grabbing only!!! + +v4l_nbufs is the number of buffers to allocate, a value of 2 (the default) +should be sufficient in almost all cases. Only special applications +(streaming captures) will need more buffers and then mostly the +MJPEG capturing features of the Buz will be more appropriate. +So leave this parameter at it's default unless you know what you do. + +The things for v4l_bufsize are more complicated: v4l_bufsize is set by +default to 128 [KB] which is the maximum amount of physically +contiguous memory Linux is able to allocate without kernel changes. +This is sufficient for grabbing 24 bit color images up to sizes of +approx. 240x180 pixels (240*180*3 = 129600, 128 KB = 131072). + +In order to be able to capture bigger images you have either to +- obtain and install the "big_physarea patch" and set aside + the necessary memory during boot time or +- start your kernel with the mem=xxx option, where xxx is your + real memory minus the memory needed for the buffers. +In that case, useful settings for v4l_bufsize are +- 1296 [Kb] for grabbing 24 bit images of max size 768*576 +- 1728 [Kb] for 32bit images of same size (4*768*576 = 1728 Kb!) +You may reduce these numbers accordingly if you know you are only +grabbing 720 pixels wide images or NTSC images (max height 480). + +In some cases it may happen that Linux isn't even able to obtain +the default 128 KB buffers. If you don't need uncompressed image +grabbing at all, set v4l_bufsize to an arbitrary small value (e.g. 4) +in order to be able to open the video device. + +triton, natoma +-------------- + +The driver tries to detect if you have a triton or natoma chipset +in order to take special measures for these chipsets. +If this detection fails but you are sure you have such a chipset, +set the corresponding variable to 1. +This is a very special option and may go away in the future. + + +Tested applications +=================== + + XawTV to watch video on your computer monitor. + + kwintv the same (you might need to use option lock_norm=1). + + lavtools To record and playback AVI or Quicktime files. Note: you + will need patched version, lavtools-1.2p2 to support new + features of this driver. Please visit driver homepage for + more info. + + Broadcast2000 reportedly (I didn't try that) can accept movies recorded + by lavrec in Quicktime format for editing and then edited + movie can be played back by lavplay program. + + MainActor 3.5x also can accept movies recorded by lavrec for editing. + + +The driver can to be used by two programs at the same time +(please, see warning note below regarding this feature). Using XawTV +you can watch what you are recording or playing back with lavtools. +I've tested the following sequence and it worked for me: + +* start xawtv and switch inputs, TV standards, and adjust video + (contrast, saturation, etc.). You may also run your favorite + audio mixer application to adjust audio inputs. + +* run lavrec with options: + + -i<set your input and norm here> (to choose proper input + and TV standard) + + -l -1 (to use audio mixer settings) + + Other lavrec option can be added at your choice. + +* watch the movie in xawtv window while recording it as AVI or + Quicktime file. + +* when recording is finished, run lavplay or xlav and watch your + clip in xawtv window. + +* Note: you should not quit xawtv during recording or playing back. + If you quit xawtv during recording or playback, another lavtools + program will stop and may even crash. + +I'm not sure that the same will work for you. You can try but, +please, be careful. + +WARNING! This is an experimental feature and I'm not sure if it will be +supported in the future. The original driver was not designed to be +used like this and it has no protection against any interference +between two running programs. THEREFORE, IT IS POTENTIALLY DANGEROUS +AND SINCE THE DRIVER OPERATES IN KERNEL SPACE, USING THIS FEATURE MAY +CRASH YOUR ENTIRE SYSTEM. + + +Programming interface +===================== + +This driver should be fully compliant to Video for Linux, so all +tools working with Video for Linux should work with (hopefully) +no problems. + +A description of the Video for Linux programming interface can be found at: +http://roadrunner.swansea.linux.org.uk/v4lapi.shtml + +Besides the Video for Linux interface, the driver has a "proprietary" +interface for accessing the Buz's MJPEG capture and playback facilities. + +For a full description of all members and ioctls see "zoran.h" (used to +be buz.h or dc10.h in previous versions, so, please, update your +programs accordingly). + +The ioctls for that interface are as follows: + +BUZIOC_G_PARAMS +BUZIOC_S_PARAMS + +Get and set the parameters of the buz. The user should always do a +BUZIOC_G_PARAMS (with a struct buz_params) to obtain the default +settings, change what he likes and then make a BUZIOC_S_PARAMS call. + +BUZIOC_REQBUFS + +Before being able to capture/playback, the user has to request +the buffers he is wanting to use. Fill the structure +zoran_requestbuffers with the size (recommended: 256*1024) and +the number (recommended 32 up to 256). There are no such restrictions +as for the Video for Linux buffers, you should LEAVE SUFFICIENT +MEMORY for your system however, else strange things will happen .... +On return, the zoran_requestbuffers structure contains number and +size of the actually allocated buffers. +You should use these numbers for doing a mmap of the buffers +into the user space. +The BUZIOC_REQBUFS ioctl also makes it happen, that the next mmap +maps the MJPEG buffer instead of the V4L buffers. + +BUZIOC_QBUF_CAPT +BUZIOC_QBUF_PLAY + +Queue a buffer for capture or playback. The first call also starts +streaming capture. When streaming capture is going on, you may +only queue further buffers or issue syncs until streaming +capture is switched off again with a argument of -1 to +a BUZIOC_QBUF_CAPT/BUZIOC_QBUF_PLAY ioctl. + +BUZIOC_SYNC + +Issue this ioctl when all buffers are queued. This ioctl will +block until the first buffer becomes free for saving its +data to disk (after BUZIOC_QBUF_CAPT) or for reuse (after BUZIOC_QBUF_PLAY). + +BUZIOC_G_STATUS + +Get the status of the input lines (video source connected/norm). +This ioctl may be subject to change. + +For programming example, please, look at lavrec.c and lavplay.c code in +lavtools-1.2p2 package (URL: http://www.cicese.mx/~mirsev/DC10plus/) +and the 'examples' directory in the original Buz driver distribution. + +Additional notes for software developers: + + The driver returns maxwidth and maxheight parameters according to + the current TV standard (norm). Therefore, the software which + communicates with the driver and "asks" for these parameters should + first set the correct norm. Well, it seems logically correct: TV + standard is "more constant" for current country than geometry + settings of a variety of TV capture cards which may work in ITU or + square pixel format. Remember that users now can lock the norm to + avoid any ambiguity. + +Features for testing +==================== + +When loaded, the driver creates a /proc/zoranX entry for each card: +using 'cat /proc/zoran0' for your first card you can see the contents +of ZR36057/67 chip registers. It is also possible to modify the +contents of some registers directly. WARNING: modified contents is not +stored in the driver memory, if you restart any program which uses this +driver or even change position or cause redraw of a window of xawtv or +other program, the original registers contents will be restored by the +driver. However, it can be used to change ZR36067 registers on the fly +for fine tuning and then to include these changes into driver code. +This feature is very limited and still requires some documentation. +However, if you are impatient, look at zoran_procfs.c code and +(IMPORTANT!) read ZR36057/67 manual. To set TopField bit, for example, +you need to type as root: + +echo TopField=1 > /proc/zoranX # change X to 0 for your first card, + # 1 for second and so on... + +If you use this feature and have found some interesting result, please, let +me know. + +Mailing lists +============= + +There are two mailing lists available to discuss application issues and +suggest driver improvements: + +1. A mailing list buz-linux was set up to discuss Iomega Buz driver. +Since this driver is derivative of that driver, you can also post your +questions and suggestions there. Subscribe with a message (with +"subscribe" in the subject) to buz-linux-subscribe@webmages.com. +Unsubscribe with a message (with "unsubscribe" in the subject) to +buz-linux-unsubscribe@webmages.com. The mailing list archive can be +found at http://buz.webmages.com/list/. + +2. Video4Linux mailing list is set for more general discussions related +to uncompressed video capture, V4L and V4L2 API, many Video4Linux +applications, etc. to subscribe to this mailing list, please, visit +https://listman.redhat.com/mailman/listinfo/video4linux-list + +Bug Reports +=========== + +If you have found a bug, please, do the following: + +1. Edit first line of zoran.c file and set DEBUGLEVEL to 3; +2. Recompile the driver and install it running update script + in the driver directory; +3. Run the application(s) which you used when you had found a + suspisious behavior; +4. When application stops, look at you /var/log/messages file + (or whatever file you use to log kernel messages) and copy + all lines related to the driver activity to a separate file + in the same order of their appearence in your log file. +5. Mail a message to <mirsev@cicese.mx> with a subject + "Linux DC10(plus)/LML33/Buz driver bug report" with a detailed + description of your problem, kernel version, application name and + attach that file with kernel messages as plain text (please, don't + attach it using base64, uuencode, or any other encoding). + + If you have a Buz card, please, also mail the same message to + Wolfgang Scherr <scherr@net4you.net> diff -u --recursive --new-file v2.4.6/linux/Documentation/video4linux/meye.txt linux/Documentation/video4linux/meye.txt --- v2.4.6/linux/Documentation/video4linux/meye.txt Wed Dec 31 16:00:00 1969 +++ linux/Documentation/video4linux/meye.txt Wed Jul 4 14:41:33 2001 @@ -0,0 +1,102 @@ +Vaio Picturebook Motion Eye Camera Driver Readme +------------------------------------------------ + Copyright (C) 2001 Stelian Pop <stelian.pop@fr.alcove.com>, Alcôve + Copyright (C) 2000 Andrew Tridgell <tridge@samba.org> + +This driver enable the use of video4linux compatible applications with the +Motion Eye camera. + +It can do at maximum 30 fps @ 320x240 or 15 fps @ 640x480. + +Grabbing is supported in packed YUV colorspace only. + +MJPEG hardware grabbing is supported via a private API (see below). + +Module options: +--------------- + + gbuffers: number of capture buffers, default is 2 (32 max) + + gbufsize: size of each capture buffer, default is 614400 + + video_nr: video device to register (0 = /dev/video0, etc) + +Module use: +----------- + +In order to automatically load the meye module on use, you can put those lines +in your /etc/modules.conf file: + + alias char-major-81 videodev + alias char-major-81-0 meye + options meye gbuffers=32 + +Usage: +------ + + xawtv >= 3.49 (<http://bytesex.org/xawtv/>) + for display and uncompressed video capture: + + xawtv -c /dev/video0 -geometry 640x480 + or + xawtv -c /dev/video0 -geometry 320x240 + + motioneye (<http://www.alcove-labs.org/en/software/meye/>) + for getting ppm or jpg snapshots, mjpeg video + +Private API: +------------ + + The driver supports frame grabbing with the video4linux API, so + all video4linux tools (like xawtv) should work with this driver. + + Besides the video4linux interface, the driver has a private interface + for accessing the Motion Eye extended parameters (camera sharpness, + agc, video framerate), the shapshot and the MJPEG capture facilities. + + This interface consists of several ioctls (prototypes and structures + can be found in include/linux/meye.h): + + MEYEIOC_G_PARAMS + MEYEIOC_S_PARAMS + Get and set the extended parameters of the motion eye camera. + The user should always query the current parameters with + MEYEIOC_G_PARAMS, change what he likes and then issue the + MEYEIOC_S_PARAMS call (checking for -EINVAL). The extended + parameters are described by the meye_params structure. + + + MEYEIOC_QBUF_CAPT + Queue a buffer for capture (the buffers must have been + obtained with a VIDIOCGMBUF call and mmap'ed by the + application). The argument to MEYEIOC_QBUF_CAPT is the + buffer number to queue (or -1 to end capture). The first + call to MEYEIOC_QBUF_CAPT starts the streaming capture. + + MEYEIOC_SYNC + Takes as an argument the buffer number you want to sync. + This ioctl blocks untils the buffer is filled and ready + for the application to use. It returns the buffer size. + + MEYEIOC_STILLCAPT + MEYEIOC_STILLJCAPT + Takes a snapshot in an uncompressed or compressed jpeg format. + This ioctl blocks until the snapshot is done and returns (for + jpeg snapshot) the size of the image. The image data is + available from the first mmap'ed buffer. + + Look at the 'motioneye' application code for an actual example. + +Bugs / Todo: +------------ + + - overlay output is not supported (although the camera is capable of). + (it should not be too hard to to it, provided we found how...) + + - mjpeg hardware playback doesn't work (depends on overlay...) + + - rewrite the driver to use some commun video4linux API for snapshot + and mjpeg capture. Unfortunately, video4linux1 does not permit it, + the BUZ API seems to be targeted to TV cards only. The video4linux 2 + API may be an option, if it goes into the kernel (maybe 2.5 + material ?). diff -u --recursive --new-file v2.4.6/linux/Documentation/video4linux/w9966.txt linux/Documentation/video4linux/w9966.txt --- v2.4.6/linux/Documentation/video4linux/w9966.txt Wed Dec 31 16:00:00 1969 +++ linux/Documentation/video4linux/w9966.txt Wed Jul 4 14:41:33 2001 @@ -0,0 +1,37 @@ + +W9966 Camera driver, written by Jakob Kemi (jakob.kemi@post.utfors.se) + +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 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. + +Options: +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 slow framerate is due to missing DMA ECP read support in the +parport drivers. I might add working EPP support later. + +Good luck! + + /Jakob diff -u --recursive --new-file v2.4.6/linux/MAINTAINERS linux/MAINTAINERS --- v2.4.6/linux/MAINTAINERS Tue Jul 3 17:08:18 2001 +++ linux/MAINTAINERS Sun Jul 15 16:15:44 2001 @@ -106,6 +106,12 @@ L: linux-net@vger.kernel.org S: Maintained +ACENIC DRIVER +P: Jes Sorensen +M: jes@trained-monkey.org +L: linux-acenic@sunsite.dk +S: Maintained + ACI MIXER DRIVER P: Robert Siemer M: Robert.Siemer@gmx.de @@ -566,8 +572,8 @@ HIPPI P: Jes Sorensen -M: jes@linuxcare.com -L: linux-hippi@sunsite.auc.dk +M: jes@trained-monkey.org +L: linux-hippi@sunsite.dk S: Maintained HP100: Driver for HP 10/100 Mbit/s Voice Grade Network Adapter Series @@ -812,7 +818,7 @@ M68K P: Jes Sorensen -M: jes@linuxcare.com +M: jes@trained-monkey.org W: http://www.clark.net/pub/lawrencc/linux/index.html L: linux-m68k@lists.linux-m68k.org S: Maintained @@ -835,6 +841,12 @@ M: zab@zabbo.net S: Odd Fixes +MATROX FRAMEBUFFER DRIVER +P: Petr Vandrovec +M: vandrove@vc.cvut.cz +L: linux-fbdev-devel@lists.sourceforge.net +S: Maintained + MEMORY TECHNOLOGY DEVICES P: David Woodhouse M: dwmw2@redhat.com @@ -1298,10 +1310,11 @@ S: Maintained TOKEN-RING NETWORK DRIVER -P: Paul Norton -M: pnorton@ieee.org +P: Mike Phillips +M: mikep@linuxtr.net L: linux-net@vger.kernel.org L: linux-tr@linuxtr.net +W: http://www.linuxtr.net S: Maintained TRIDENT 4DWAVE/SIS 7018 PCI AUDIO CORE diff -u --recursive --new-file v2.4.6/linux/Makefile linux/Makefile --- v2.4.6/linux/Makefile Tue Jul 3 17:08:18 2001 +++ linux/Makefile Thu Jul 19 22:03:56 2001 @@ -1,6 +1,6 @@ VERSION = 2 PATCHLEVEL = 4 -SUBLEVEL = 6 +SUBLEVEL = 7 EXTRAVERSION = KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) @@ -88,7 +88,7 @@ CPPFLAGS := -D__KERNEL__ -I$(HPATH) CFLAGS := $(CPPFLAGS) -Wall -Wstrict-prototypes -Wno-trigraphs -O2 \ - -fomit-frame-pointer -fno-strict-aliasing + -fomit-frame-pointer -fno-strict-aliasing -fno-common AFLAGS := -D__ASSEMBLY__ $(CPPFLAGS) # @@ -147,6 +147,7 @@ DRIVERS-$(CONFIG_ATM) += drivers/atm/atm.o DRIVERS-$(CONFIG_IDE) += drivers/ide/idedriver.o DRIVERS-$(CONFIG_SCSI) += drivers/scsi/scsidrv.o +DRIVERS-$(CONFIG_FUSION_BOOT) += drivers/message/fusion/fusion.o DRIVERS-$(CONFIG_IEEE1394) += drivers/ieee1394/ieee1394drv.o ifneq ($(CONFIG_CD_NO_IDESCSI)$(CONFIG_BLK_DEV_IDECD)$(CONFIG_BLK_DEV_SR)$(CONFIG_PARIDE_PCD),) @@ -333,14 +334,14 @@ TAGS: dummy etags `find include/asm-$(ARCH) -name '*.h'` find include -type d \( -name "asm-*" -o -name config \) -prune -o -name '*.h' -print | xargs etags -a - find $(SUBDIRS) init -name '*.c' | xargs etags -a + find $(SUBDIRS) init -name '*.[ch]' | xargs etags -a # Exuberant ctags works better with -I tags: dummy CTAGSF=`ctags --version | grep -i exuberant >/dev/null && echo "-I __initdata,__exitdata,EXPORT_SYMBOL,EXPORT_SYMBOL_NOVERS"`; \ ctags $$CTAGSF `find include/asm-$(ARCH) -name '*.h'` && \ find include -type d \( -name "asm-*" -o -name config \) -prune -o -name '*.h' -print | xargs ctags $$CTAGSF -a && \ - find $(SUBDIRS) init -name '*.c' | xargs ctags $$CTAGSF -a + find $(SUBDIRS) init -name '*.[ch]' | xargs ctags $$CTAGSF -a ifdef CONFIG_MODULES ifdef CONFIG_MODVERSIONS diff -u --recursive --new-file v2.4.6/linux/arch/alpha/config.in linux/arch/alpha/config.in --- v2.4.6/linux/arch/alpha/config.in Tue Jul 3 17:08:18 2001 +++ linux/arch/alpha/config.in Tue Jul 10 20:08:51 2001 @@ -5,8 +5,8 @@ define_bool CONFIG_ALPHA y define_bool CONFIG_UID16 n -define_bool CONFIG_RWSEM_GENERIC_SPINLOCK y -define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM n +define_bool CONFIG_RWSEM_GENERIC_SPINLOCK n +define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM y mainmenu_name "Kernel configuration of Linux for Alpha machines" diff -u --recursive --new-file v2.4.6/linux/arch/alpha/kernel/alpha_ksyms.c linux/arch/alpha/kernel/alpha_ksyms.c --- v2.4.6/linux/arch/alpha/kernel/alpha_ksyms.c Tue Jul 3 17:08:18 2001 +++ linux/arch/alpha/kernel/alpha_ksyms.c Tue Jul 10 20:08:51 2001 @@ -178,10 +178,6 @@ EXPORT_SYMBOL(down_interruptible); EXPORT_SYMBOL(down_trylock); EXPORT_SYMBOL(up); -EXPORT_SYMBOL(down_read); -EXPORT_SYMBOL(down_write); -EXPORT_SYMBOL(up_read); -EXPORT_SYMBOL(up_write); /* * SMP-specific symbols. diff -u --recursive --new-file v2.4.6/linux/arch/alpha/kernel/entry.S linux/arch/alpha/kernel/entry.S --- v2.4.6/linux/arch/alpha/kernel/entry.S Tue Jul 3 17:08:18 2001 +++ linux/arch/alpha/kernel/entry.S Mon Jul 9 14:47:39 2001 @@ -576,17 +576,6 @@ .align 3 ret_from_sys_call: cmovne $26,0,$19 /* $19 = 0 => non-restartable */ -#ifdef CONFIG_SMP - ldl $3,TASK_PROCESSOR($8) - sll $3,L1_CACHE_SHIFT,$3 -#endif - lda $4,irq_stat -#ifdef CONFIG_SMP - addq $3,$4,$4 -#endif - ldq $4,0($4) /* __softirq_pending */ - bne $4,handle_softirq -ret_from_softirq: ldq $0,SP_OFF($30) and $0,8,$0 beq $0,restore_all @@ -664,17 +653,6 @@ mov $31,$26 /* tell "ret_from_sys_call" we can restart */ br ret_from_sys_call - .align 3 -handle_softirq: - subq $30,16,$30 - stq $19,0($30) /* save syscall nr */ - stq $20,8($30) /* and error indication (a3) */ - jsr $26,do_softirq - ldq $19,0($30) - ldq $20,8($30) - addq $30,16,$30 - br ret_from_softirq - .align 3 syscall_error: /* diff -u --recursive --new-file v2.4.6/linux/arch/alpha/kernel/ptrace.c linux/arch/alpha/kernel/ptrace.c --- v2.4.6/linux/arch/alpha/kernel/ptrace.c Fri Feb 9 11:29:44 2001 +++ linux/arch/alpha/kernel/ptrace.c Fri Jul 20 12:39:55 2001 @@ -264,32 +264,7 @@ if (!child) goto out_notsk; if (request == PTRACE_ATTACH) { - ret = -EPERM; - if (child == current) - goto out; - if ((!child->dumpable || - (current->uid != child->euid) || - (current->uid != child->suid) || - (current->uid != child->uid) || - (current->gid != child->egid) || - (current->gid != child->sgid) || - (current->gid != child->gid) || - (!cap_issubset(child->cap_permitted, current->cap_permitted))) - && !capable(CAP_SYS_PTRACE)) - goto out; - /* the same process cannot be attached many times */ - if (child->ptrace & PT_PTRACED) - goto out; - child->ptrace |= PT_PTRACED; - write_lock_irq(&tasklist_lock); - if (child->p_pptr != current) { - REMOVE_LINKS(child); - child->p_pptr = current; - SET_LINKS(child); - } - write_unlock_irq(&tasklist_lock); - send_sig(SIGSTOP, child, 1); - ret = 0; + ret = ptrace_attach(child); goto out; } ret = -ESRCH; diff -u --recursive --new-file v2.4.6/linux/arch/alpha/kernel/time.c linux/arch/alpha/kernel/time.c --- v2.4.6/linux/arch/alpha/kernel/time.c Sun Nov 12 19:27:11 2000 +++ linux/arch/alpha/kernel/time.c Wed Jul 4 11:50:46 2001 @@ -169,6 +169,77 @@ init_rtc_irq(); } +/* + * Calibrate CPU clock using legacy 8254 timer/counter. Stolen from + * arch/i386/time.c. + */ + +#define CALIBRATE_LATCH (52 * LATCH) +#define CALIBRATE_TIME (52 * 1000020 / HZ) + +static unsigned long __init +calibrate_cc_with_pic(void) +{ + int cc; + unsigned long count = 0; + + /* Set the Gate high, disable speaker */ + outb((inb(0x61) & ~0x02) | 0x01, 0x61); + + /* + * Now let's take care of CTC channel 2 + * + * Set the Gate high, program CTC channel 2 for mode 0, + * (interrupt on terminal count mode), binary count, + * load 5 * LATCH count, (LSB and MSB) to begin countdown. + */ + outb(0xb0, 0x43); /* binary, mode 0, LSB/MSB, Ch 2 */ + outb(CALIBRATE_LATCH & 0xff, 0x42); /* LSB of count */ + outb(CALIBRATE_LATCH >> 8, 0x42); /* MSB of count */ + + cc = rpcc(); + do { + count++; + } while ((inb(0x61) & 0x20) == 0); + cc = rpcc() - cc; + + /* Error: ECTCNEVERSET */ + if (count <= 1) + goto bad_ctc; + + /* Error: ECPUTOOFAST */ + if (count >> 32) + goto bad_ctc; + + /* Error: ECPUTOOSLOW */ + if (cc <= CALIBRATE_TIME) + goto bad_ctc; + + return ((long)cc * 1000000) / CALIBRATE_TIME; + + /* + * The CTC wasn't reliable: we got a hit on the very first read, + * or the CPU was so fast/slow that the quotient wouldn't fit in + * 32 bits.. + */ + bad_ctc: + return 0; +} + +/* The Linux interpretation of the CMOS clock register contents: + When the Update-In-Progress (UIP) flag goes from 1 to 0, the + RTC registers show the second which has precisely just started. + Let's hope other operating systems interpret the RTC the same way. */ + +static unsigned long __init +rpcc_after_update_in_progress(void) +{ + do { } while (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP)); + do { } while (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP); + + return rpcc(); +} + void __init time_init(void) { @@ -176,24 +247,15 @@ unsigned long cycle_freq, one_percent; long diff; - /* - * The Linux interpretation of the CMOS clock register contents: - * When the Update-In-Progress (UIP) flag goes from 1 to 0, the - * RTC registers show the second which has precisely just started. - * Let's hope other operating systems interpret the RTC the same way. - */ - do { } while (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP)); - do { } while (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP); + /* Calibrate CPU clock -- attempt #1. */ + if (!est_cycle_freq) + est_cycle_freq = calibrate_cc_with_pic(); - /* Read cycle counter exactly on falling edge of update flag */ - cc1 = rpcc(); + cc1 = rpcc_after_update_in_progress(); + /* Calibrate CPU clock -- attempt #2. */ if (!est_cycle_freq) { - /* Sometimes the hwrpb->cycle_freq value is bogus. - Go another round to check up on it and see. */ - do { } while (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP)); - do { } while (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP); - cc2 = rpcc(); + cc2 = rpcc_after_update_in_progress(); est_cycle_freq = cc2 - cc1; cc1 = cc2; } diff -u --recursive --new-file v2.4.6/linux/arch/alpha/kernel/traps.c linux/arch/alpha/kernel/traps.c --- v2.4.6/linux/arch/alpha/kernel/traps.c Thu May 24 15:24:37 2001 +++ linux/arch/alpha/kernel/traps.c Wed Jul 4 11:50:38 2001 @@ -61,202 +61,6 @@ "a0", "a1", "a2", "a3", "a4", "a5", "t8", "t9", "t10", "t11", "ra", "pv", "at", "gp", "sp", "zero"}; -static char * inst_name[] = {"call_pal", "", "", "", "", "", "", "", - "lda", "ldah", "ldbu", "ldq_u", "ldwu", "stw", "stb", "stq_u", - "ALU", "ALU", "ALU", "ALU", "SQRT", "FVAX", "FIEEE", "FLOAT", - "MISC", "PAL19", "JMP", "PAL1B", "GRAPH", "PAL1D", "PAL1E", "PAL1F", - "ldf", "ldg", "lds", "ldt", "stf", "stg", "sts", "stt", - "ldl", "ldq", "ldl_l", "ldq_l", "stl", "stq", "stl_c", "stq_c", - "br", "fbeq", "fblt", "fble", "bsr", "fbne", "fbge", "fbgt" - "blbc", "beq", "blt", "ble", "blbs", "bne", "bge", "bgt" -}; - -static char * jump_name[] = {"jmp", "jsr", "ret", "jsr_coroutine"}; - -typedef struct {int func; char * text;} alist; - -static alist inta_name[] = {{0, "addl"}, {2, "s4addl"}, {9, "subl"}, - {0xb, "s4subl"}, {0xf, "cmpbge"}, {0x12, "s8addl"}, {0x1b, "s8subl"}, - {0x1d, "cmpult"}, {0x20, "addq"}, {0x22, "s4addq"}, {0x29, "subq"}, - {0x2b, "s4subq"}, {0x2d, "cmpeq"}, {0x32, "s8addq"}, {0x3b, "s8subq"}, - {0x3d, "cmpule"}, {0x40, "addl/v"}, {0x49, "subl/v"}, {0x4d, "cmplt"}, - {0x60, "addq/v"}, {0x69, "subq/v"}, {0x6d, "cmple"}, {-1, 0}}; - -static alist intl_name[] = {{0, "and"}, {8, "andnot"}, {0x14, "cmovlbs"}, - {0x16, "cmovlbc"}, {0x20, "or"}, {0x24, "cmoveq"}, {0x26, "cmovne"}, - {0x28, "ornot"}, {0x40, "xor"}, {0x44, "cmovlt"}, {0x46, "cmovge"}, - {0x48, "eqv"}, {0x61, "amask"}, {0x64, "cmovle"}, {0x66, "cmovgt"}, - {0x6c, "implver"}, {-1, 0}}; - -static alist ints_name[] = {{2, "mskbl"}, {6, "extbl"}, {0xb, "insbl"}, - {0x12, "mskwl"}, {0x16, "extwl"}, {0x1b, "inswl"}, {0x22, "mskll"}, - {0x26, "extll"}, {0x2b, "insll"}, {0x30, "zap"}, {0x31, "zapnot"}, - {0x32, "mskql"}, {0x34, "srl"}, {0x36, "extql"}, {0x39, "sll"}, - {0x3b, "insql"}, {0x3c, "sra"}, {0x52, "mskwh"}, {0x57, "inswh"}, - {0x5a, "extwh"}, {0x62, "msklh"}, {0x67, "inslh"}, {0x6a, "extlh"}, - {0x72, "mskqh"}, {0x77, "insqh"}, {0x7a, "extqh"}, {-1, 0}}; - -static alist intm_name[] = {{0, "mull"}, {0x20, "mulq"}, {0x30, "umulh"}, - {0x40, "mull/v"}, {0x60, "mulq/v"}, {-1, 0}}; - -static alist * int_name[] = {inta_name, intl_name, ints_name, intm_name}; - -static char * -assoc(int fcode, alist * a) -{ - while ((fcode != a->func) && (a->func != -1)) - ++a; - return a->text; -} - -static char * -iname(unsigned int instr) -{ - int opcode = instr >> 26; - char * name = inst_name[opcode]; - - switch (opcode) { - default: - break; - - case 0x10: - case 0x11: - case 0x12: - case 0x13: { - char * specific_name - = assoc((instr >> 5) & 0x3f, int_name[opcode - 0x10]); - if (specific_name) - name = specific_name; - break; - } - - case 0x1a: - name = jump_name[(instr >> 14) & 3]; - break; - } - - return name; -} - -static enum {NOT_INST, PAL, BRANCH, MEMORY, JUMP, OPERATE, FOPERATE, MISC} -iformat(int opcode) -{ - if (opcode >= 0x30) - return BRANCH; - if (opcode >= 0x20) - return MEMORY; - if (opcode == 0) - return PAL; - if (opcode < 8) - return NOT_INST; - if (opcode < 0x10) - return MEMORY; - if (opcode < 0x14) - return OPERATE; - if (opcode < 0x18) - return FOPERATE; - switch (opcode) { - case 0x18: - return MISC; - case 0x1A: - return JUMP; - case 0x1C: - return OPERATE; - default: - return NOT_INST; - } -} - -/* - * The purpose here is to provide useful clues about a kernel crash, so - * less likely instructions, e.g. floating point, aren't fully decoded. - */ -static void -disassemble(unsigned int instr) -{ - int optype = instr >> 26; - char buf[40], *s = buf; - - s += sprintf(buf, "%08x %s ", instr, iname(instr)); - switch (iformat(optype)) { - default: - case NOT_INST: - case MISC: - break; - - case PAL: - s += sprintf(s, "%d", instr); - break; - - case BRANCH: { - int reg = (instr >> 21) & 0x1f; - int offset = instr & 0x1fffff; - - if (offset >= 0x100000) - offset -= 0x200000; - if (((optype & 3) == 0) || (optype >= 0x38)) { - if ((optype != 0x30) || (reg != 0x1f)) - s += sprintf(s, "%s,", ireg_name[reg]); - } else - s += sprintf(s, "f%d,", reg); - s += sprintf(s, ".%+d", (offset + 1) << 2); - break; - } - - case MEMORY: { - int addr_reg = (instr >> 16) & 0x1f; - int value_reg = (instr >> 21) & 0x1f; - int offset = instr & 0xffff; - - if (offset >= 0x8000) - offset -= 0x10000; - if ((optype >= 0x20) && (optype < 0x28)) - s += sprintf(s, "f%d", value_reg); - else - s += sprintf(s, "%s", ireg_name[value_reg]); - - s += sprintf(s, ",%d(%s)", offset, ireg_name[addr_reg]); - break; - } - - case JUMP: { - int target_reg = (instr >> 16) & 0x1f; - int return_reg = (instr >> 21) & 0x1f; - - s += sprintf(s, "%s,", ireg_name[return_reg]); - s += sprintf(s, "(%s)", ireg_name[target_reg]); - break; - } - - case OPERATE: { - int areg = (instr >> 21) & 0x1f; - int breg = (instr >> 16) & 0x1f; - int creg = instr & 0x1f; - int litflag = instr & (1<<12); - int lit = (instr >> 13) & 0xff; - - s += sprintf(s, "%s,", ireg_name[areg]); - if (litflag) - s += sprintf(s, "%d", lit); - else - s += sprintf(s, "%s", ireg_name[breg]); - s += sprintf(s, ",%s", ireg_name[creg]); - break; - } - - case FOPERATE: { - int areg = (instr >> 21) & 0x1f; - int breg = (instr >> 16) & 0x1f; - int creg = instr & 0x1f; - - s += sprintf(s, "f%d,f%d,f%d", areg, breg, creg); - break; - } - } - buf[s-buf] = 0; - printk("%s\n", buf); -} - static void dik_show_code(unsigned int *pc) { @@ -267,8 +71,7 @@ unsigned int insn; if (__get_user(insn, pc+i)) break; - printk("%c", i ? ' ' : '*'); - disassemble(insn); + printk("%c%08x%c", i ? ' ' : '<', insn, i ? ' ' : '>'); } printk("\n"); } @@ -286,17 +89,11 @@ continue; if (tmp >= (unsigned long) &_etext) continue; - /* - * Assume that only the low 24-bits of a kernel text address - * is interesting. - */ - printk("%6x%c", (int)tmp & 0xffffff, (++i % 11) ? ' ' : '\n'); -#if 0 + printk("%lx%c", tmp, ' '); if (i > 40) { printk(" ..."); break; } -#endif } printk("\n"); } @@ -337,8 +134,8 @@ #endif printk("%s(%d): %s %ld\n", current->comm, current->pid, str, err); dik_show_regs(regs, r9_15); - dik_show_code((unsigned int *)regs->pc); dik_show_trace((unsigned long *)(regs+1)); + dik_show_code((unsigned int *)regs->pc); if (current->thread.flags & (1UL << 63)) { printk("die_if_kernel recursion detected.\n"); diff -u --recursive --new-file v2.4.6/linux/arch/arm/kernel/bios32.c linux/arch/arm/kernel/bios32.c --- v2.4.6/linux/arch/arm/kernel/bios32.c Thu Apr 12 12:20:31 2001 +++ linux/arch/arm/kernel/bios32.c Wed Jul 4 15:43:05 2001 @@ -8,6 +8,7 @@ #include <linux/config.h> #include <linux/kernel.h> #include <linux/pci.h> +#include <linux/slab.h> #include <linux/init.h> #include <asm/page.h> /* for BUG() */ @@ -18,6 +19,20 @@ static int debug_pci; int have_isa_bridge; +struct pci_sys_data { + /* + * The hardware we are attached to + */ + struct hw_pci *hw; + + unsigned long mem_offset; + + /* + * These are the resources for the root bus. + */ + struct resource *resource[3]; +}; + void pcibios_report_status(u_int status_mask, int warn) { struct pci_dev *dev; @@ -118,19 +133,22 @@ } /* - * Prevent the PCI layer from seeing the resources - * allocated to this device. These resources are - * of no consequence to the PCI layer (they are - * handled elsewhere). + * Prevent the PCI layer from seeing the resources allocated to this device + * if it is the host bridge by marking it as such. These resources are of + * no consequence to the PCI layer (they are handled elsewhere). */ -static void __init pci_fixup_disable(struct pci_dev *dev) +static void __init pci_fixup_dec21285(struct pci_dev *dev) { int i; - for (i = 0; i < PCI_NUM_RESOURCES; i++) { - dev->resource[i].start = 0; - dev->resource[i].end = 0; - dev->resource[i].flags = 0; + if (dev->devfn == 0) { + dev->class &= 0xff; + dev->class |= PCI_CLASS_BRIDGE_HOST << 8; + for (i = 0; i < PCI_NUM_RESOURCES; i++) { + dev->resource[i].start = 0; + dev->resource[i].end = 0; + dev->resource[i].flags = 0; + } } } @@ -167,7 +185,7 @@ { PCI_FIXUP_HEADER, PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_21285, - pci_fixup_disable + pci_fixup_dec21285 }, { PCI_FIXUP_HEADER, PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_83C553, @@ -187,27 +205,11 @@ }, { 0 } }; -/* - * Allocate resources for all PCI devices that have been enabled. - * We need to do that before we try to fix up anything. - */ -static void __init pcibios_claim_resources(void) -{ - struct pci_dev *dev; - int idx; - - pci_for_each_dev(dev) { - for (idx = 0; idx < PCI_NUM_RESOURCES; idx++) - if (dev->resource[idx].flags && - dev->resource[idx].start) - pci_claim_resource(dev, idx); - } -} - void __init pcibios_update_resource(struct pci_dev *dev, struct resource *root, struct resource *res, int resource) { + struct pci_sys_data *sys = dev->sysdata; u32 val, check; int reg; @@ -216,12 +218,9 @@ res->flags & IORESOURCE_IO ? "IO" : "MEM", res->start, dev->name); - val = res->start | (res->flags & PCI_REGION_FLAG_MASK); if (resource < 6) { reg = PCI_BASE_ADDRESS_0 + 4*resource; } else if (resource == PCI_ROM_RESOURCE) { - res->flags |= PCI_ROM_ADDRESS_ENABLE; - val |= PCI_ROM_ADDRESS_ENABLE; reg = dev->rom_base_reg; } else { /* Somebody might have asked allocation of a @@ -229,6 +228,12 @@ */ return; } + + val = res->start; + if (res->flags & IORESOURCE_MEM) + val -= sys->mem_offset; + val |= res->flags & PCI_REGION_FLAG_MASK; + pci_write_config_dword(dev, reg, val); pci_read_config_dword(dev, reg, &check); if ((val ^ check) & ((val & PCI_BASE_ADDRESS_SPACE_IO) ? @@ -246,77 +251,93 @@ pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq); } -/** - * pcibios_fixup_bus - Called after each bus is probed, but before its children - * are examined. +/* + * If the bus contains any of these devices, then we must not turn on + * parity checking of any kind. Currently this is CyberPro 20x0 only. */ -void __init pcibios_fixup_bus(struct pci_bus *bus) +static inline int pdev_bad_for_parity(struct pci_dev *dev) +{ + return (dev->vendor == PCI_VENDOR_ID_INTERG && + (dev->device == PCI_DEVICE_ID_INTERG_2000 || + dev->device == PCI_DEVICE_ID_INTERG_2010)); +} + +/* + * Adjust the device resources from bus-centric to Linux-centric. + */ +static void __init +pdev_fixup_device_resources(struct pci_sys_data *root, struct pci_dev *dev) +{ + int i; + + for (i = 0; i < PCI_NUM_RESOURCES; i++) { + if (dev->resource[i].start == 0) + continue; + if (dev->resource[i].flags & IORESOURCE_MEM) { + dev->resource[i].start += root->mem_offset; + dev->resource[i].end += root->mem_offset; + } + } +} + +static void __init +pbus_assign_bus_resources(struct pci_bus *bus, struct pci_sys_data *root) { - struct list_head *walk = &bus->devices; - struct arm_pci_sysdata *sysdata = - (struct arm_pci_sysdata *)bus->sysdata; - struct arm_bus_sysdata *busdata; - - if (bus->number >= MAX_NR_BUS) - BUG(); - - if (bus->self) { - struct pci_dev *dev = bus->self; - int i; + struct pci_dev *dev = bus->self; + int i; + if (dev) { for (i = 0; i < 3; i++) { - bus->resource[i] = &dev->resource[PCI_BRIDGE_RESOURCES + i]; - bus->resource[i]->name = bus->name; + bus->resource[i] = &dev->resource[PCI_BRIDGE_RESOURCES+i]; + bus->resource[i]->name = bus->name; } - bus->resource[0]->start = ioport_resource.start; - bus->resource[0]->end = ioport_resource.end; bus->resource[0]->flags |= pci_bridge_check_io(dev); - bus->resource[1]->start = iomem_resource.start; - bus->resource[1]->end = iomem_resource.end; bus->resource[1]->flags |= IORESOURCE_MEM; - /* Turn off downsteam prefetchable memory address range */ - bus->resource[2]->start = 1024*1024; - bus->resource[2]->end = bus->resource[2]->start - 1; + if (root->resource[2]) + bus->resource[2]->flags = root->resource[2]->flags; + else { + /* no prefetchable memory region - disable it */ + bus->resource[2]->start = 1024*1024; + bus->resource[2]->end = bus->resource[2]->start - 1; + } + } else { + /* + * Assign root bus resources. + */ + for (i = 0; i < 3; i++) + bus->resource[i] = root->resource[i]; } +} - busdata = sysdata->bus + bus->number; - busdata->max_lat = 255; +/* + * pcibios_fixup_bus - Called after each bus is probed, + * but before its children are examined. + */ +void __init pcibios_fixup_bus(struct pci_bus *bus) +{ + struct pci_sys_data *root = bus->sysdata; + struct list_head *walk; + u16 features = PCI_COMMAND_SERR | PCI_COMMAND_PARITY; + u16 all_status = -1; + + pbus_assign_bus_resources(bus, root); /* * Walk the devices on this bus, working out what we can * and can't support. */ - for (walk = walk->next; walk != &bus->devices; walk = walk->next) { + for (walk = bus->devices.next; walk != &bus->devices; walk = walk->next) { struct pci_dev *dev = pci_dev_b(walk); u16 status; - u8 max_lat, min_gnt; - - pci_read_config_word(dev, PCI_STATUS, &status); - /* - * If this device does not support fast back to back - * transfers, the bus as a whole cannot support them. - */ - if (!(status & PCI_STATUS_FAST_BACK)) - busdata->features &= ~PCI_COMMAND_FAST_BACK; + pdev_fixup_device_resources(root, dev); - /* - * If we encounter a CyberPro 2000, then we disable - * SERR and PERR reporting - this chip doesn't drive the - * parity line correctly. - */ - if (dev->vendor == PCI_VENDOR_ID_INTERG && - (dev->device == PCI_DEVICE_ID_INTERG_2000 || - dev->device == PCI_DEVICE_ID_INTERG_2010)) - busdata->features &= ~(PCI_COMMAND_SERR | - PCI_COMMAND_PARITY); + pci_read_config_word(dev, PCI_STATUS, &status); + all_status &= status; - /* - * Calculate the maximum devsel latency. - */ - if (busdata->maxdevsel < (status & PCI_STATUS_DEVSEL_MASK)) - busdata->maxdevsel = (status & PCI_STATUS_DEVSEL_MASK); + if (pdev_bad_for_parity(dev)) + features &= ~(PCI_COMMAND_SERR | PCI_COMMAND_PARITY); /* * If this device is an ISA bridge, set the have_isa_bridge @@ -326,63 +347,48 @@ if (dev->class >> 8 == PCI_CLASS_BRIDGE_ISA || dev->class >> 8 == PCI_CLASS_BRIDGE_EISA) have_isa_bridge = !0; - - /* - * Calculate the maximum latency on this bus. Note - * that we ignore any device which reports its max - * latency is the same as its use. - */ - pci_read_config_byte(dev, PCI_MAX_LAT, &max_lat); - pci_read_config_byte(dev, PCI_MIN_GNT, &min_gnt); - if (max_lat && max_lat != min_gnt && max_lat < busdata->max_lat) - busdata->max_lat = max_lat; } /* + * If any device on this bus does not support fast back to back + * transfers, then the bus as a whole is not able to support them. + * Having fast back to back transfers on saves us one PCI cycle + * per transaction. + */ + if (all_status & PCI_STATUS_FAST_BACK) + features |= PCI_COMMAND_FAST_BACK; + + /* * Now walk the devices again, this time setting them up. */ - walk = &bus->devices; - for (walk = walk->next; walk != &bus->devices; walk = walk->next) { + for (walk = bus->devices.next; walk != &bus->devices; walk = walk->next) { struct pci_dev *dev = pci_dev_b(walk); u16 cmd; - u8 min_gnt, latency; - - /* - * Calculate this masters latency timer value. - * This is rather primitive - it does not take - * account of the number of masters in a system - * wanting to use the bus. - */ - pci_read_config_byte(dev, PCI_MIN_GNT, &min_gnt); - if (min_gnt) { - if (min_gnt > busdata->max_lat) - min_gnt = busdata->max_lat; - - latency = (int)min_gnt * 25 / 3; - } else - latency = 32; /* 1us */ - - pci_write_config_byte(dev, PCI_LATENCY_TIMER, latency); - /* - * Set the cache line size to 32 bytes. - * Also, set system error enable, parity error enable. - * Disable ROM. - */ - pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, 8); pci_read_config_word(dev, PCI_COMMAND, &cmd); - - cmd |= busdata->features; - + cmd |= features; pci_write_config_word(dev, PCI_COMMAND, cmd); - pci_read_config_word(dev, PCI_COMMAND, &cmd); - pci_write_config_dword(dev, PCI_ROM_ADDRESS, 0); } + + /* + * Report what we did for this bus + */ + printk(KERN_INFO "PCI: bus%d: Fast back to back transfers %sabled\n", + bus->number, (features & PCI_COMMAND_FAST_BACK) ? "en" : "dis"); } +/* + * Convert from Linux-centric to bus-centric addresses for bridge devices. + */ void __init pcibios_fixup_pbus_ranges(struct pci_bus *bus, struct pbus_set_ranges_data *ranges) { + struct pci_sys_data *root = bus->sysdata; + + ranges->mem_start -= root->mem_offset; + ranges->mem_end -= root->mem_offset; + ranges->prefetch_start -= root->mem_offset; + ranges->prefetch_end -= root->mem_offset; } u8 __init no_swizzle(struct pci_dev *dev, u8 *pin) @@ -400,81 +406,90 @@ void __init pcibios_init(void) { - struct hw_pci *hw_pci = NULL; - struct arm_pci_sysdata sysdata; - int i; + struct pci_sys_data *root; + struct hw_pci *hw = NULL; do { #ifdef CONFIG_ARCH_EBSA285 if (machine_is_ebsa285()) { - hw_pci = &ebsa285_pci; + hw = &ebsa285_pci; break; } #endif #ifdef CONFIG_ARCH_SHARK if (machine_is_shark()) { - hw_pci = &shark_pci; + hw = &shark_pci; break; } #endif #ifdef CONFIG_ARCH_CATS if (machine_is_cats()) { - hw_pci = &cats_pci; + hw = &cats_pci; break; } #endif #ifdef CONFIG_ARCH_NETWINDER if (machine_is_netwinder()) { - hw_pci = &netwinder_pci; + hw = &netwinder_pci; break; } #endif #ifdef CONFIG_ARCH_PERSONAL_SERVER if (machine_is_personal_server()) { - hw_pci = &personal_server_pci; + hw = &personal_server_pci; break; } #endif #ifdef CONFIG_ARCH_FTVPCI if (machine_is_ftvpci()) { - hw_pci = &ftv_pci; + hw = &ftv_pci; break; } #endif #ifdef CONFIG_ARCH_INTEGRATOR if (machine_is_integrator()) { - hw_pci = &integrator_pci; + hw = &integrator_pci; break; } #endif } while (0); - if (hw_pci == NULL) + if (hw == NULL) return; - for (i = 0; i < MAX_NR_BUS; i++) { - sysdata.bus[i].features = PCI_COMMAND_FAST_BACK | - PCI_COMMAND_SERR | - PCI_COMMAND_PARITY; - sysdata.bus[i].maxdevsel = PCI_STATUS_DEVSEL_FAST; + root = kmalloc(sizeof(*root), GFP_KERNEL); + if (!root) + panic("PCI: unable to allocate root data!"); + + root->hw = hw; + root->mem_offset = hw->mem_offset; + + memset(root->resource, 0, sizeof(root->resource)); + + /* + * Setup the resources for this bus. + * resource[0] - IO ports + * resource[1] - non-prefetchable memory + * resource[2] - prefetchable memory + */ + if (root->hw->setup_resources) + root->hw->setup_resources(root->resource); + else { + root->resource[0] = &ioport_resource; + root->resource[1] = &iomem_resource; + root->resource[2] = NULL; } /* * Set up the host bridge, and scan the bus. */ - hw_pci->init(&sysdata); - - /* - * Claim the currently allocated resources. This ensures - * that we will not allocate an already inuse region. - */ - pcibios_claim_resources(); + root->hw->init(root); /* * Assign any unassigned resources. */ pci_assign_unassigned_resources(); - pci_fixup_irqs(hw_pci->swizzle, hw_pci->map_irq); + pci_fixup_irqs(root->hw->swizzle, root->hw->map_irq); } char * __init pcibios_setup(char *str) @@ -499,7 +514,7 @@ * is reserved for motherboard devices that decode all 16 * bits, so it's ok to allocate at, say, 0x2800-0x28ff, * but we want to try to avoid allocating at 0x2900-0x2bff - * which might have be mirrored at 0x0100-0x03ff.. + * which might be mirrored at 0x0100-0x03ff.. */ void pcibios_align_resource(void *data, struct resource *res, unsigned long size) { diff -u --recursive --new-file v2.4.6/linux/arch/arm/kernel/dec21285.c linux/arch/arm/kernel/dec21285.c --- v2.4.6/linux/arch/arm/kernel/dec21285.c Mon Nov 27 17:07:59 2000 +++ linux/arch/arm/kernel/dec21285.c Wed Jul 4 15:43:05 2001 @@ -13,6 +13,7 @@ #include <linux/ptrace.h> #include <linux/interrupt.h> #include <linux/mm.h> +#include <linux/slab.h> #include <linux/init.h> #include <linux/ioport.h> @@ -24,6 +25,11 @@ #define MAX_SLOTS 21 +#define PCICMD_ERROR_BITS ((PCI_STATUS_DETECTED_PARITY | \ + PCI_STATUS_REC_MASTER_ABORT | \ + PCI_STATUS_REC_TARGET_ABORT | \ + PCI_STATUS_PARITY) << 16) + extern int setup_arm_irq(int, struct irqaction *); extern void pcibios_report_status(u_int status_mask, int warn); extern void register_isa_ports(unsigned int, unsigned int, unsigned int); @@ -255,12 +261,33 @@ add_timer(timer); } -void __init dc21285_init(struct arm_pci_sysdata *sysdata) +void __init dc21285_setup_resources(struct resource **resource) +{ + struct resource *busmem, *busmempf; + + busmem = kmalloc(sizeof(*busmem), GFP_KERNEL); + busmempf = kmalloc(sizeof(*busmempf), GFP_KERNEL); + memset(busmem, 0, sizeof(*busmem)); + memset(busmempf, 0, sizeof(*busmempf)); + + busmem->flags = IORESOURCE_MEM; + busmem->name = "Footbridge non-prefetch"; + busmempf->flags = IORESOURCE_MEM | IORESOURCE_PREFETCH; + busmempf->name = "Footbridge prefetch"; + + allocate_resource(&iomem_resource, busmempf, 0x20000000, + 0x80000000, 0xffffffff, 0x20000000, NULL, NULL); + allocate_resource(&iomem_resource, busmem, 0x40000000, + 0x80000000, 0xffffffff, 0x40000000, NULL, NULL); + + resource[0] = &ioport_resource; + resource[1] = busmem; + resource[2] = busmempf; +} + +void __init dc21285_init(void *sysdata) { - unsigned long cntl; unsigned int mem_size, mem_mask; - unsigned int pci_cmd = PCI_COMMAND_IO | PCI_COMMAND_MEMORY | - PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE; int cfn_mode; mem_size = (unsigned int)high_memory - PAGE_OFFSET; @@ -286,26 +313,17 @@ "central function" : "addin"); if (cfn_mode) { - static struct resource csrmem, csrio, busmem, busmempf; - struct pci_bus *bus; + static struct resource csrmem, csrio; - csrio.flags = IORESOURCE_IO; - csrio.name = "Footbridge"; + csrio.flags = IORESOURCE_IO; + csrio.name = "Footbridge"; csrmem.flags = IORESOURCE_MEM; csrmem.name = "Footbridge"; - busmem.flags = IORESOURCE_MEM; - busmem.name = "Footbridge non-prefetch"; - busmempf.flags = IORESOURCE_MEM | IORESOURCE_PREFETCH; - busmempf.name = "Footbridge prefetch"; allocate_resource(&ioport_resource, &csrio, 128, 0xff00, 0xffff, 128, NULL, NULL); allocate_resource(&iomem_resource, &csrmem, 128, 0xf4000000, 0xf8000000, 128, NULL, NULL); - allocate_resource(&iomem_resource, &busmempf, 0x20000000, - 0x00000000, 0x80000000, 0x20000000, NULL, NULL); - allocate_resource(&iomem_resource, &busmem, 0x40000000, - 0x00000000, 0x80000000, 0x40000000, NULL, NULL); /* * Map our SDRAM at a known address in PCI space, just in case @@ -313,37 +331,23 @@ * necessary, since some VGA cards forcefully use PCI addresses * in the range 0x000a0000 to 0x000c0000. (eg, S3 cards). */ - *CSR_PCICACHELINESIZE = 0x00002008; *CSR_PCICSRBASE = csrmem.start; *CSR_PCICSRIOBASE = csrio.start; *CSR_PCISDRAMBASE = __virt_to_bus(PAGE_OFFSET); *CSR_PCIROMBASE = 0; - *CSR_PCICMD = pci_cmd | - (1 << 31) | (1 << 29) | (1 << 28) | (1 << 24); - - bus = pci_scan_bus(0, &dc21285_ops, sysdata); - /* - * bus->resource[0] is the IO resource for this bus - * bus->resource[1] is the mem resource for this bus - * bus->resource[2] is the prefetch mem resource for this bus - */ - bus->resource[1] = &busmem; - bus->resource[2] = &busmempf; - - pci_cmd |= sysdata->bus[0].features; + *CSR_PCICMD = PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | + PCI_COMMAND_INVALIDATE | PCICMD_ERROR_BITS; - printk("PCI: Fast back to back transfers %sabled\n", - (sysdata->bus[0].features & PCI_COMMAND_FAST_BACK) ? - "en" : "dis"); + pci_scan_bus(0, &dc21285_ops, sysdata); /* * Clear any existing errors - we aren't * interested in historical data... */ - cntl = *CSR_SA110_CNTL & 0xffffde07; - *CSR_SA110_CNTL = cntl | SA110_CNTL_RXSERR; - *CSR_PCICMD = pci_cmd | 1 << 31 | 1 << 29 | 1 << 28 | 1 << 24; - } else { + *CSR_SA110_CNTL = (*CSR_SA110_CNTL & 0xffffde07) | + SA110_CNTL_RXSERR; + *CSR_PCICMD = (*CSR_PCICMD & 0xffff) | PCICMD_ERROR_BITS; + } else if (footbridge_cfn_mode() != 0) { /* * If we are not compiled to accept "add-in" mode, then * we are using a constant virt_to_bus translation which diff -u --recursive --new-file v2.4.6/linux/arch/arm/kernel/dma-arc.c linux/arch/arm/kernel/dma-arc.c --- v2.4.6/linux/arch/arm/kernel/dma-arc.c Thu Feb 8 16:32:44 2001 +++ linux/arch/arm/kernel/dma-arc.c Wed Jul 4 14:56:44 2001 @@ -155,7 +155,7 @@ } memcpy((void *)0x1c, fiqhandler_start, fiqhandler_length); regs.ARM_r9 = dma->buf.length; - regs.ARM_r10 = dma->buf.address; + regs.ARM_r10 = (unsigned long)dma->buf.address; regs.ARM_fp = FLOPPYDMA_BASE; set_fiq_regs(®s); enable_fiq(dma->dma_irq); diff -u --recursive --new-file v2.4.6/linux/arch/arm/kernel/head-armv.S linux/arch/arm/kernel/head-armv.S --- v2.4.6/linux/arch/arm/kernel/head-armv.S Thu Apr 12 12:20:31 2001 +++ linux/arch/arm/kernel/head-armv.S Wed Jul 4 14:56:44 2001 @@ -79,7 +79,7 @@ * ideal, but in this case, it should ONLY set r0 and r1 to the * appropriate value. */ -#if defined(CONFIG_ARCH_NETWINDER) || defined(CONFIG_ARCH_INTEGRATOR) +#if defined(CONFIG_ARCH_NETWINDER) /* * Compatability cruft for old NetWinder NeTTroms. This * code is currently scheduled for destruction in 2.5.xx @@ -124,8 +124,6 @@ * FIXME - No bootloader, so manually set 'r1' with our architecture number. */ mov r1, #MACH_TYPE_L7200 -#elif defined(CONFIG_ARCH_INTEGRATOR) - mov r1, #MACH_TYPE_INTEGRATOR #endif mov r0, #F_BIT | I_BIT | MODE_SVC @ make sure svc mode @@ -236,14 +234,16 @@ * nearest megabyte boundary. */ add r0, r4, #(TEXTADDR & 0xff000000) >> 18 @ start of kernel + bic r2, r3, #0x00f00000 + str r2, [r0] @ PAGE_OFFSET + 0MB add r0, r0, #(TEXTADDR & 0x00f00000) >> 18 - str r3, [r0], #4 @ PAGE_OFFSET + 0MB + str r3, [r0], #4 @ KERNEL + 0MB add r3, r3, #1 << 20 - str r3, [r0], #4 @ PAGE_OFFSET + 1MB + str r3, [r0], #4 @ KERNEL + 1MB add r3, r3, #1 << 20 - str r3, [r0], #4 @ PAGE_OFFSET + 2MB + str r3, [r0], #4 @ KERNEL + 2MB add r3, r3, #1 << 20 - str r3, [r0], #4 @ PAGE_OFFSET + 3MB + str r3, [r0], #4 @ KERNEL + 3MB /* * Ensure that the first section of RAM is present. diff -u --recursive --new-file v2.4.6/linux/arch/arm/kernel/irq.c linux/arch/arm/kernel/irq.c --- v2.4.6/linux/arch/arm/kernel/irq.c Thu Apr 12 12:20:31 2001 +++ linux/arch/arm/kernel/irq.c Wed Jul 4 14:56:44 2001 @@ -216,7 +216,7 @@ irq_exit(cpu, irq); - if (softirq_active(cpu) & softirq_mask(cpu)) + if (softirq_pending(cpu)) do_softirq(); return; diff -u --recursive --new-file v2.4.6/linux/arch/arm/kernel/oldlatches.c linux/arch/arm/kernel/oldlatches.c --- v2.4.6/linux/arch/arm/kernel/oldlatches.c Thu Apr 12 12:20:31 2001 +++ linux/arch/arm/kernel/oldlatches.c Wed Jul 4 14:56:44 2001 @@ -50,13 +50,14 @@ BUG(); } -static void __init oldlatch_init(void) +static int __init oldlatch_init(void) { if (machine_is_archimedes()) { oldlatch_aupdate(0xff, 0xff); /* Thats no FDC reset...*/ oldlatch_bupdate(0xff, LATCHB_FDCRESET); } + return 0; } __initcall(oldlatch_init); diff -u --recursive --new-file v2.4.6/linux/arch/arm/kernel/plx90x0.c linux/arch/arm/kernel/plx90x0.c --- v2.4.6/linux/arch/arm/kernel/plx90x0.c Mon Sep 18 15:15:25 2000 +++ linux/arch/arm/kernel/plx90x0.c Wed Jul 4 15:43:05 2001 @@ -129,8 +129,6 @@ static const unsigned long int base = PLX_BASE; char *what; unsigned long bar = (unsigned long)virt_to_bus((void *)PAGE_OFFSET); - unsigned int pci_cmd = PCI_COMMAND_IO | PCI_COMMAND_MEMORY | - PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE; /* Have a sniff around and see which PLX device is present. */ unsigned long id = __raw_readl(base + 0xf0); @@ -189,10 +187,4 @@ "system error", NULL); pci_scan_bus(0, &plx90x0_ops, sysdata); - - pci_cmd |= sysdata->bus[0].features; - - printk("PCI: Fast back to back transfers %sabled\n", - (sysdata->bus[0].features & PCI_COMMAND_FAST_BACK) ? - "en" : "dis"); } diff -u --recursive --new-file v2.4.6/linux/arch/arm/kernel/ptrace.c linux/arch/arm/kernel/ptrace.c --- v2.4.6/linux/arch/arm/kernel/ptrace.c Mon Sep 18 15:15:25 2000 +++ linux/arch/arm/kernel/ptrace.c Fri Jul 20 12:39:55 2001 @@ -594,32 +594,7 @@ goto out_tsk; if (request == PTRACE_ATTACH) { - if (child == current) - goto out_tsk; - if ((!child->dumpable || - (current->uid != child->euid) || - (current->uid != child->suid) || - (current->uid != child->uid) || - (current->gid != child->egid) || - (current->gid != child->sgid) || - (!cap_issubset(child->cap_permitted, current->cap_permitted)) || - (current->gid != child->gid)) && !capable(CAP_SYS_PTRACE)) - goto out_tsk; - /* the same process cannot be attached many times */ - if (child->ptrace & PT_PTRACED) - goto out_tsk; - child->ptrace |= PT_PTRACED; - - write_lock_irq(&tasklist_lock); - if (child->p_pptr != current) { - REMOVE_LINKS(child); - child->p_pptr = current; - SET_LINKS(child); - } - write_unlock_irq(&tasklist_lock); - - send_sig(SIGSTOP, child, 1); - ret = 0; + ret = ptrace_attach(child); goto out_tsk; } ret = -ESRCH; diff -u --recursive --new-file v2.4.6/linux/arch/arm/kernel/sys_arm.c linux/arch/arm/kernel/sys_arm.c --- v2.4.6/linux/arch/arm/kernel/sys_arm.c Tue Jul 3 17:08:18 2001 +++ linux/arch/arm/kernel/sys_arm.c Wed Jul 4 14:56:44 2001 @@ -28,9 +28,9 @@ #include <asm/uaccess.h> #include <asm/ipc.h> -/* - * Constant strings used in inlined functions in header files - */ +extern unsigned long do_mremap(unsigned long addr, unsigned long old_len, + unsigned long new_len, unsigned long flags, + unsigned long new_addr); /* * sys_pipe() is the normal C calling standard for creating diff -u --recursive --new-file v2.4.6/linux/arch/arm/mach-footbridge/cats-pci.c linux/arch/arm/mach-footbridge/cats-pci.c --- v2.4.6/linux/arch/arm/mach-footbridge/cats-pci.c Sun Sep 3 11:19:11 2000 +++ linux/arch/arm/mach-footbridge/cats-pci.c Wed Jul 4 15:43:05 2001 @@ -11,6 +11,7 @@ #include <asm/irq.h> #include <asm/mach/pci.h> +#include <asm/hardware/dec21285.h> /* cats host-specific stuff */ static int irqmap_cats[] __initdata = { IRQ_PCI, IRQ_IN0, IRQ_IN1, IRQ_IN3 }; @@ -31,7 +32,9 @@ } struct hw_pci cats_pci __initdata = { - init: dc21285_init, - swizzle: no_swizzle, - map_irq: cats_map_irq, + setup_resources: dc21285_setup_resources, + init: dc21285_init, + mem_offset: DC21285_PCI_MEM, + swizzle: no_swizzle, + map_irq: cats_map_irq, }; diff -u --recursive --new-file v2.4.6/linux/arch/arm/mach-footbridge/ebsa285-pci.c linux/arch/arm/mach-footbridge/ebsa285-pci.c --- v2.4.6/linux/arch/arm/mach-footbridge/ebsa285-pci.c Sun Sep 3 11:19:11 2000 +++ linux/arch/arm/mach-footbridge/ebsa285-pci.c Wed Jul 4 15:43:05 2001 @@ -11,6 +11,7 @@ #include <asm/irq.h> #include <asm/mach/pci.h> +#include <asm/hardware/dec21285.h> static int irqmap_ebsa285[] __initdata = { IRQ_IN3, IRQ_IN1, IRQ_IN0, IRQ_PCI }; @@ -33,7 +34,9 @@ } struct hw_pci ebsa285_pci __initdata = { - init: dc21285_init, - swizzle: ebsa285_swizzle, - map_irq: ebsa285_map_irq, + setup_resources: dc21285_setup_resources, + init: dc21285_init, + mem_offset: DC21285_PCI_MEM, + swizzle: ebsa285_swizzle, + map_irq: ebsa285_map_irq, }; diff -u --recursive --new-file v2.4.6/linux/arch/arm/mach-footbridge/netwinder-pci.c linux/arch/arm/mach-footbridge/netwinder-pci.c --- v2.4.6/linux/arch/arm/mach-footbridge/netwinder-pci.c Sun Sep 3 11:19:11 2000 +++ linux/arch/arm/mach-footbridge/netwinder-pci.c Wed Jul 4 15:43:05 2001 @@ -11,6 +11,7 @@ #include <asm/irq.h> #include <asm/mach/pci.h> +#include <asm/hardware/dec21285.h> /* netwinder host-specific stuff */ static int __init netwinder_map_irq(struct pci_dev *dev, u8 slot, u8 pin) @@ -48,7 +49,9 @@ } struct hw_pci netwinder_pci __initdata = { - init: dc21285_init, - swizzle: no_swizzle, - map_irq: netwinder_map_irq, + setup_resources: dc21285_setup_resources, + init: dc21285_init, + mem_offset: DC21285_PCI_MEM, + swizzle: no_swizzle, + map_irq: netwinder_map_irq, }; diff -u --recursive --new-file v2.4.6/linux/arch/arm/mach-footbridge/personal-pci.c linux/arch/arm/mach-footbridge/personal-pci.c --- v2.4.6/linux/arch/arm/mach-footbridge/personal-pci.c Sun Sep 3 11:19:11 2000 +++ linux/arch/arm/mach-footbridge/personal-pci.c Wed Jul 4 15:43:05 2001 @@ -11,6 +11,7 @@ #include <asm/irq.h> #include <asm/mach/pci.h> +#include <asm/hardware/dec21285.h> static int irqmap_personal_server[] __initdata = { IRQ_IN0, IRQ_IN1, IRQ_IN2, IRQ_IN3, 0, 0, 0, @@ -37,7 +38,9 @@ } struct hw_pci personal_server_pci __initdata = { - init: dc21285_init, - swizzle: no_swizzle, - map_irq: personal_server_map_irq, + setup_resources: dc21285_setup_resources, + init: dc21285_init, + mem_offset: DC21285_PCI_MEM, + swizzle: no_swizzle, + map_irq: personal_server_map_irq, }; diff -u --recursive --new-file v2.4.6/linux/arch/arm/tools/mach-types linux/arch/arm/tools/mach-types --- v2.4.6/linux/arch/arm/tools/mach-types Tue Jul 3 17:08:18 2001 +++ linux/arch/arm/tools/mach-types Wed Jul 4 14:56:44 2001 @@ -6,7 +6,7 @@ # To add an entry into this database, please see Documentation/arm/README, # or contact rmk@arm.linux.org.uk # -# Last update: Sun Jun 17 00:53:17 2001 +# Last update: Wed Jul 4 20:04:11 2001 # # machine_is_xxx CONFIG_xxxx MACH_TYPE_xxx number # @@ -91,12 +91,17 @@ empeg SA1100_EMPEG EMPEG 79 adi_eb ARCH_I80200FCC I80200FCC 80 itt_cpb SA1100_ITT_CPB ITT_CPB 81 -sa1110_svc ARCH_SA1110_SVC SA1110_SVC 82 +svc SA1100_SVC SVC 82 alpha2 SA1100_ALPHA2 ALPHA2 84 alpha1 SA1100_ALPHA1 ALPHA1 85 netarm ARCH_NETARM NETARM 86 simpad SA1100_SIMPAD SIMPAD 87 pda1 ARCH_PDA1 PDA1 88 lubbock ARCH_LUBBOCK LUBBOCK 89 +aniko ARCH_ANIKO ANIKO 90 +clep7212 ARCH_CLEP7212 CLEP7212 91 +cs89712 ARCH_CS89712 CS89712 92 +weararm SA1100_WEARARM WEARARM 93 +possio_px SA1100_POSSIO_PX POSSIO_PX 94 # The following are unallocated diff -u --recursive --new-file v2.4.6/linux/arch/cris/Makefile linux/arch/cris/Makefile --- v2.4.6/linux/arch/cris/Makefile Tue May 1 16:04:56 2001 +++ linux/arch/cris/Makefile Wed Jul 4 11:50:38 2001 @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.18 2001/04/17 13:58:38 orjanf Exp $ +# $Id: Makefile,v 1.19 2001/06/11 12:06:40 bjornw Exp $ # cris/Makefile # # This file is included by the global makefile so that you can add your own @@ -49,7 +49,12 @@ HEAD := arch/cris/kernel/head.o -SUBDIRS += arch/cris/kernel arch/cris/mm arch/cris/lib arch/cris/drivers arch/cris/boot/rescue +SUBDIRS += arch/cris/kernel arch/cris/mm arch/cris/lib arch/cris/drivers +ifdef CONFIG_ETRAX_AXISFLASHMAP +# only build this if axis flash map is used, because they depend on +# each others config options +SUBDIRS += arch/cris/boot/rescue +endif CORE_FILES += arch/cris/kernel/kernel.o arch/cris/mm/mm.o arch/cris/drivers/drivers.o LIBGCC = $(shell $(CC) $(CFLAGS) -print-file-name=libgcc.a) LIBS := $(TOPDIR)/arch/cris/lib/lib.a $(LIBS) $(TOPDIR)/arch/cris/lib/lib.a $(LIBGCC) diff -u --recursive --new-file v2.4.6/linux/arch/cris/config.in linux/arch/cris/config.in --- v2.4.6/linux/arch/cris/config.in Tue May 1 16:04:56 2001 +++ linux/arch/cris/config.in Wed Jul 4 11:50:38 2001 @@ -18,11 +18,10 @@ bool 'Networking support' CONFIG_NET bool 'System V IPC' CONFIG_SYSVIPC +bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT +bool 'Sysctl support' CONFIG_SYSCTL tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF -if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - tristate 'Kernel support for JAVA binaries' CONFIG_BINFMT_JAVA -fi bool 'Use kernel gdb debugger' CONFIG_ETRAX_KGDB @@ -38,9 +37,9 @@ Etrax-100-LX-v2 CONFIG_ETRAX100LX_V2 \ Etrax-100-LX-for-xsim-simulator CONFIG_SVINTO_SIM" Etrax-100-LX-v1 -# For both LX version 1 and the current simulator we enable the low VM mapping +# Etrax100 LX v1 has a MMU "feature" requiring a low mapping -if [ "$CONFIG_ETRAX100LX" = "y" -o "$CONFIG_SVINTO_SIM" = "y" ]; then +if [ "$CONFIG_ETRAX100LX" = "y" ]; then define_bool CONFIG_CRIS_LOW_MAP y define_hex CONFIG_ETRAX_DRAM_VIRTUAL_BASE 60000000 else @@ -98,7 +97,7 @@ hex 'R_WAITSTATES' CONFIG_ETRAX_DEF_R_WAITSTATES 95a6 hex 'R_BUS_CONFIG' CONFIG_ETRAX_DEF_R_BUS_CONFIG 104 -bool 'SDRAM support' CONFIG_ETRAX_SDRAM n +bool 'SDRAM support' CONFIG_ETRAX_SDRAM if [ "$CONFIG_ETRAX_SDRAM" = "n" ]; then hex 'R_DRAM_CONFIG' CONFIG_ETRAX_DEF_R_DRAM_CONFIG 1a200040 hex 'R_DRAM_TIMING' CONFIG_ETRAX_DEF_R_DRAM_TIMING 5611 @@ -115,6 +114,12 @@ hex 'R_PORT_PB_DIR' CONFIG_ETRAX_DEF_R_PORT_PB_DIR 00 hex 'R_PORT_PB_DATA' CONFIG_ETRAX_DEF_R_PORT_PB_DATA ff +bool 'Software Shutdown Support' CONFIG_ETRAX_SOFT_SHUTDOWN +if [ "$CONFIG_ETRAX_SOFT_SHUTDOWN" = "y" ]; then + int 'Shutdown bit on port CSP0' CONFIG_ETRAX_SHUTDOWN_BIT 12 + int 'Power button bit on port G' CONFIG_ETRAX_POWERBUTTON_BIT 25 +fi + endmenu # bring in Etrax built-in drivers @@ -164,7 +169,7 @@ source drivers/ieee1394/Config.in -source drivers/i2o/Config.in +source drivers/message/i2o/Config.in if [ "$CONFIG_NET" = "y" ]; then mainmenu_option next_comment @@ -214,8 +219,6 @@ source drivers/media/Config.in source fs/Config.in - -source drivers/char/Config.in mainmenu_option next_comment comment 'Sound' diff -u --recursive --new-file v2.4.6/linux/arch/cris/defconfig linux/arch/cris/defconfig --- v2.4.6/linux/arch/cris/defconfig Tue May 1 16:04:56 2001 +++ linux/arch/cris/defconfig Wed Jul 4 11:50:38 2001 @@ -2,6 +2,8 @@ # Automatically generated make config: don't edit # CONFIG_UID16=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set # # Code maturity level options @@ -13,8 +15,9 @@ # CONFIG_NET=y CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set +# CONFIG_SYSCTL is not set CONFIG_BINFMT_ELF=y -# CONFIG_BINFMT_JAVA is not set # CONFIG_ETRAX_KGDB is not set # CONFIG_ETRAX_WATCHDOG is not set @@ -27,16 +30,30 @@ CONFIG_CRIS_LOW_MAP=y CONFIG_ETRAX_DRAM_VIRTUAL_BASE=60000000 CONFIG_ETRAX_DRAM_SIZE=8 -CONFIG_ETRAX_FLASH_LENGTH=2 CONFIG_ETRAX_FLASH_BUSWIDTH=2 CONFIG_ETRAX_PA_LEDS=y # CONFIG_ETRAX_PB_LEDS is not set -# CONFIG_ETRAX_90000000_LEDS is not set +# CONFIG_ETRAX_CSP0_LEDS is not set # CONFIG_ETRAX_NO_LEDS is not set CONFIG_ETRAX_LED1G=2 CONFIG_ETRAX_LED1R=2 CONFIG_ETRAX_LED2G=2 CONFIG_ETRAX_LED2R=2 +CONFIG_ETRAX_LED3R=2 +CONFIG_ETRAX_LED3G=2 +CONFIG_ETRAX_LED4R=2 +CONFIG_ETRAX_LED4G=2 +CONFIG_ETRAX_LED5R=2 +CONFIG_ETRAX_LED5G=2 +CONFIG_ETRAX_LED6R=2 +CONFIG_ETRAX_LED6G=2 +CONFIG_ETRAX_LED7R=2 +CONFIG_ETRAX_LED7G=2 +CONFIG_ETRAX_LED8Y=2 +CONFIG_ETRAX_LED9Y=2 +CONFIG_ETRAX_LED10Y=2 +CONFIG_ETRAX_LED11Y=2 +CONFIG_ETRAX_LED12R=2 CONFIG_ETRAX_DEBUG_PORT0=y # CONFIG_ETRAX_DEBUG_PORT1 is not set # CONFIG_ETRAX_DEBUG_PORT2 is not set @@ -55,13 +72,17 @@ CONFIG_ETRAX_DEF_R_PORT_PB_CONFIG=00 CONFIG_ETRAX_DEF_R_PORT_PB_DIR=1e CONFIG_ETRAX_DEF_R_PORT_PB_DATA=f3 +# CONFIG_ETRAX_SOFT_SHUTDOWN is not set # -# Drivers for Etrax built-in interfaces +# Drivers for ETRAX 100LX built-in interfaces # CONFIG_ETRAX_ETHERNET=y CONFIG_NET_ETHERNET=y -CONFIG_ETRAX_SERIAL=y +# CONFIG_ETRAX_NETWORK_LED_ON_WHEN_LINK is not set +CONFIG_ETRAX_NETWORK_LED_ON_WHEN_ACTIVITY=y +C# CONFIG_ETRAX_ETHERNET_LPSLAVE is not set +ONFIG_ETRAX_SERIAL=y # CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_ON_PB is not set CONFIG_ETRAX_SERIAL_PORT1=y # CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_ON_PB is not set @@ -71,6 +92,7 @@ # CONFIG_ETRAX_SYNCHRONOUS_SERIAL is not set # CONFIG_ETRAX_IDE is not set CONFIG_ETRAX_AXISFLASHMAP=y +CONFIG_ETRAX_PTABLE_SECTOR=65536 CONFIG_MTD=y CONFIG_MTD_CFI=y # CONFIG_MTD_CFI_INTELEXT is not set @@ -80,6 +102,7 @@ CONFIG_MTD_BLOCK=y CONFIG_ETRAX_I2C=y CONFIG_ETRAX_I2C_USES_PB_NOT_PB_I2C=y +# CONFIG_ETRAX_I2C_EEPROM is not set CONFIG_ETRAX_GPIO=y CONFIG_ETRAX_PA_BUTTON_BITMASK=02 CONFIG_ETRAX_PA_CHANGEABLE_DIR=00 @@ -87,21 +110,35 @@ CONFIG_ETRAX_PB_CHANGEABLE_DIR=00 CONFIG_ETRAX_PB_CHANGEABLE_BITS=FF # CONFIG_ETRAX_USB_HOST is not set +# CONFIG_USB is not set +# CONFIG_ETRAX_DS1302 is not set # # Memory Technology Devices (MTD) # CONFIG_MTD=y # CONFIG_MTD_DEBUG is not set + +# +# Disk-On-Chip Device Drivers +# # CONFIG_MTD_DOC1000 is not set # CONFIG_MTD_DOC2000 is not set # CONFIG_MTD_DOC2001 is not set # CONFIG_MTD_DOCPROBE is not set + +# +# RAM/ROM Device Drivers +# # CONFIG_MTD_PMC551 is not set # CONFIG_MTD_SLRAM is not set # CONFIG_MTD_RAM is not set # CONFIG_MTD_ROM is not set # CONFIG_MTD_MTDRAM is not set + +# +# Linearly Mapped Flash Device Drivers +# CONFIG_MTD_CFI=y # CONFIG_MTD_CFI_GEOMETRY is not set # CONFIG_MTD_CFI_INTELEXT is not set @@ -112,6 +149,7 @@ # CONFIG_MTD_NORA is not set # CONFIG_MTD_PNC2000 is not set # CONFIG_MTD_RPXLITE is not set +# CONFIG_MTD_SC520CDP is not set # CONFIG_MTD_SBC_MEDIAGX is not set # CONFIG_MTD_ELAN_104NC is not set # CONFIG_MTD_SA1100 is not set @@ -121,8 +159,16 @@ # CONFIG_MTD_MIXMEM is not set # CONFIG_MTD_OCTAGON is not set # CONFIG_MTD_VMAX is not set + +# +# NAND Flash Device Drivers +# # CONFIG_MTD_NAND is not set # CONFIG_MTD_NAND_SPIA is not set + +# +# User Modules And Translation Layers +# CONFIG_MTD_CHAR=y CONFIG_MTD_BLOCK=y # CONFIG_FTL is not set diff -u --recursive --new-file v2.4.6/linux/arch/cris/drivers/Config.in linux/arch/cris/drivers/Config.in --- v2.4.6/linux/arch/cris/drivers/Config.in Tue May 1 16:04:56 2001 +++ linux/arch/cris/drivers/Config.in Wed Jul 4 11:50:38 2001 @@ -6,10 +6,21 @@ # this is just so that the user does not have to go into the # normal ethernet driver section just to enable ethernetworking define_bool CONFIG_NET_ETHERNET y + + choice 'Network LED behavior' \ + "LED_on_when_link CONFIG_ETRAX_NETWORK_LED_ON_WHEN_LINK \ + LED_on_when_activity CONFIG_ETRAX_NETWORK_LED_ON_WHEN_ACTIVITY" \ + LED_on_when_activity + else define_bool CONFIG_NET_ETHERNET n fi +bool 'Etrax Ethernet slave support (over lp0/1)' CONFIG_ETRAX_ETHERNET_LPSLAVE +if [ "$CONFIG_ETRAX_ETHERNET_LPSLAVE" = "y" ]; then + bool ' Slave has its own LEDs' CONFIG_ETRAX_ETHERNET_LPSLAVE_HAS_LEDS +fi + bool 'Serial-port support' CONFIG_ETRAX_SERIAL if [ "$CONFIG_ETRAX_SERIAL" = "y" ]; then comment ' Port 0 is always enabled' @@ -99,7 +110,7 @@ define_bool CONFIG_BLK_DEV_IDEDMA y define_bool CONFIG_DMA_NONPCI y - int 'Delay for drives to regain consciousness' CONFIG_IDE_DELAY 15 + int 'Delay for drives to regain consciousness' CONFIG_ETRAX_IDE_DELAY 15 choice 'IDE reset pin' \ "Port_PB_Bit_7 CONFIG_ETRAX_IDE_PB7_RESET\ diff -u --recursive --new-file v2.4.6/linux/arch/cris/drivers/Makefile linux/arch/cris/drivers/Makefile --- v2.4.6/linux/arch/cris/drivers/Makefile Tue May 1 16:04:56 2001 +++ linux/arch/cris/drivers/Makefile Wed Jul 4 11:50:38 2001 @@ -7,18 +7,21 @@ obj-y := -obj-$(CONFIG_ETRAX_ETHERNET) += ethernet.o -obj-$(CONFIG_ETRAX_SERIAL) += serial.o -obj-$(CONFIG_ETRAX_IDE) += ide.o -obj-$(CONFIG_ETRAX_AXISFLASHMAP) += axisflashmap.o -obj-$(CONFIG_ETRAX_I2C) += i2c.o -obj-$(CONFIG_ETRAX_I2C_EEPROM) += eeprom.o -obj-$(CONFIG_ETRAX_GPIO) += gpio.o -obj-$(CONFIG_ETRAX_USB_HOST) += usb-host.o -obj-$(CONFIG_ETRAX_SYNCHRONOUS_SERIAL) += sync_serial.o -obj-$(CONFIG_ETRAX_PARPORT) += parport.o -obj-$(CONFIG_ETRAX_DS1302) += ds1302.o +obj-$(CONFIG_ETRAX_ETHERNET) += ethernet.o +obj-$(CONFIG_ETRAX_SERIAL) += serial.o +obj-$(CONFIG_ETRAX_IDE) += ide.o +obj-$(CONFIG_ETRAX_AXISFLASHMAP) += axisflashmap.o +obj-$(CONFIG_ETRAX_I2C) += i2c.o +obj-$(CONFIG_ETRAX_I2C_EEPROM) += eeprom.o +obj-$(CONFIG_ETRAX_GPIO) += gpio.o +obj-$(CONFIG_ETRAX_USB_HOST) += usb-host.o +obj-$(CONFIG_ETRAX_SYNCHRONOUS_SERIAL) += sync_serial.o +obj-$(CONFIG_ETRAX_PARPORT) += parport.o +obj-$(CONFIG_ETRAX_DS1302) += ds1302.o +obj-$(CONFIG_ETRAX_ETHERNET_LPSLAVE) += lpslave/lpslavedrivers.o +subdir-$(CONFIG_ETRAX_ETHERNET_LPSLAVE) += lpslave include $(TOPDIR)/Rules.make + diff -u --recursive --new-file v2.4.6/linux/arch/cris/drivers/axisflashmap.c linux/arch/cris/drivers/axisflashmap.c --- v2.4.6/linux/arch/cris/drivers/axisflashmap.c Tue May 1 16:04:56 2001 +++ linux/arch/cris/drivers/axisflashmap.c Wed Jul 4 11:50:38 2001 @@ -11,6 +11,23 @@ * partition split defined below. * * $Log: axisflashmap.c,v $ + * Revision 1.12 2001/06/11 09:50:30 jonashg + * Oops, 2MB is 0x200000 bytes. + * + * Revision 1.11 2001/06/08 11:39:44 jonashg + * Changed sizes and offsets in axis_default_partitions to use + * CONFIG_ETRAX_PTABLE_SECTOR. + * + * Revision 1.10 2001/05/29 09:42:03 jonashg + * Use macro for end marker length instead of sizeof. + * + * Revision 1.9 2001/05/29 08:52:52 jonashg + * Gave names to the magic fours (size of the ptable end marker). + * + * Revision 1.8 2001/05/28 15:36:20 jonashg + * * Removed old comment about ptable location in flash (it's a CONFIG_ option). + * * Variable ptable was initialized twice to the same value. + * * Revision 1.7 2001/04/05 13:41:46 markusl * Updated according to review remarks * @@ -130,6 +147,10 @@ #define MAX_PARTITIONS 7 #define NUM_DEFAULT_PARTITIONS 3 +/* Default flash size is 2MB. CONFIG_ETRAX_PTABLE_SECTOR is most likely the + * size of one flash block and "filesystem"-partition needs 5 blocks to be able + * to use JFFS. + */ static struct mtd_partition axis_default_partitions[NUM_DEFAULT_PARTITIONS] = { { name: "boot firmware", @@ -138,13 +159,13 @@ }, { name: "kernel", - size: 0x1a0000, + size: 0x200000 - (6 * CONFIG_ETRAX_PTABLE_SECTOR), offset: CONFIG_ETRAX_PTABLE_SECTOR }, { name: "filesystem", - size: 0x50000, - offset: (0x1a0000 + CONFIG_ETRAX_PTABLE_SECTOR) + size: 5 * CONFIG_ETRAX_PTABLE_SECTOR, + offset: 0x200000 - (5 * CONFIG_ETRAX_PTABLE_SECTOR) } }; @@ -223,21 +244,17 @@ mymtd->module = THIS_MODULE; - /* The partition-table is at an offset within the second - * sector of the flash. We _define_ this to be at offset 64k - * even if the actual sector-size in the flash changes.. for - * now at least. - */ - ptable_head = (struct partitiontable_head *)(FLASH_CACHED_ADDR + CONFIG_ETRAX_PTABLE_SECTOR + PARTITION_TABLE_OFFSET); pidx++; /* first partition is always set to the default */ if ((ptable_head->magic == PARTITION_TABLE_MAGIC) && (ptable_head->size < - (MAX_PARTITIONS * sizeof(struct partitiontable_entry) + 4)) + (MAX_PARTITIONS * sizeof(struct partitiontable_entry) + + PARTITIONTABLE_END_MARKER_SIZE)) && (*(unsigned long*)((void*)ptable_head + sizeof(*ptable_head) + - ptable_head->size - 4) + ptable_head->size - + PARTITIONTABLE_END_MARKER_SIZE) == PARTITIONTABLE_END_MARKER)) { /* Looks like a start, sane length and end of a * partition table, lets check csum etc. @@ -268,9 +285,6 @@ ptable_ok = (csum == ptable_head->checksum); /* Read the entries and use/show the info. */ - ptable = (struct partitiontable_entry *) - ((unsigned long)ptable_head + sizeof(*ptable_head)); - printk(" Found %s partition table at 0x%08lX-0x%08lX.\n", (ptable_ok ? "valid" : "invalid"), (unsigned long)ptable_head, diff -u --recursive --new-file v2.4.6/linux/arch/cris/drivers/ds1302.c linux/arch/cris/drivers/ds1302.c --- v2.4.6/linux/arch/cris/drivers/ds1302.c Tue May 1 16:04:56 2001 +++ linux/arch/cris/drivers/ds1302.c Wed Jul 4 11:50:38 2001 @@ -7,6 +7,32 @@ *! Functions exported: ds1302_readreg, ds1302_writereg, ds1302_init, get_rtc_status *! *! $Log: ds1302.c,v $ +*! Revision 1.11 2001/06/14 12:35:52 jonashg +*! The ATA hack is back. It is unfortunately the only way to set g27 to output. +*! +*! Revision 1.9 2001/06/14 10:00:14 jonashg +*! No need for tempudelay to be inline anymore (had to adjust the usec to +*! loops conversion because of this to make it slow enough to be a udelay). +*! +*! Revision 1.8 2001/06/14 08:06:32 jonashg +*! Made tempudelay delay usecs (well, just a tad more). +*! +*! Revision 1.7 2001/06/13 14:18:11 jonashg +*! Only allow processes with SYS_TIME capability to set time and charge. +*! +*! Revision 1.6 2001/06/12 15:22:07 jonashg +*! * Made init function __init. +*! * Parameter to out_byte() is unsigned char. +*! * The magic number 42 has got a name. +*! * Removed comment about /proc (nothing is exported there). +*! +*! Revision 1.5 2001/06/12 14:35:13 jonashg +*! Gave the module a name and added it to printk's. +*! +*! Revision 1.4 2001/05/31 14:53:40 jonashg +*! Made tempudelay() inline so that the watchdog doesn't reset (see +*! function comment). +*! *! Revision 1.3 2001/03/26 16:03:06 bjornw *! Needs linux/config.h *! @@ -56,13 +82,14 @@ *! *! (C) Copyright 1999, 2000, 2001 Axis Communications AB, LUND, SWEDEN *! -*! $Id: ds1302.c,v 1.3 2001/03/26 16:03:06 bjornw Exp $ +*! $Id: ds1302.c,v 1.11 2001/06/14 12:35:52 jonashg Exp $ *! *!***************************************************************************/ #include <linux/config.h> #include <linux/fs.h> +#include <linux/init.h> #include <linux/mm.h> #include <linux/module.h> #include <linux/miscdevice.h> @@ -76,13 +103,15 @@ #define RTC_MAJOR_NR 121 /* local major, change later */ +static const char ds1302_name[] = "ds1302"; + /* The DS1302 might be connected to different bits on different products. * It has three signals - SDA, SCL and RST. RST and SCL are always outputs, * but SDA can have a selected direction. * For now, only PORT_PB is hardcoded. */ -/* The RST bit may be on either the Generic Port or Port PB */ +/* The RST bit may be on either the Generic Port or Port PB. */ #ifdef CONFIG_ETRAX_DS1302_RST_ON_GENERIC_PORT #define TK_RST_OUT(x) REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow, CONFIG_ETRAX_DS1302_RSTBIT, x) #define TK_RST_DIR(x) @@ -106,21 +135,23 @@ * (used in udelay) is not set when functions here are called from time.c */ -static void tempudelay(int time) +static void tempudelay(int usecs) { - int i; - for(i = 0; i < time * 10000; i++); + volatile int loops; + + for(loops = usecs * 12; loops > 0; loops--) + /* nothing */; } -/* send 8 bits */ +/* Send 8 bits. */ static void -out_byte(int x) +out_byte(unsigned char x) { int i; TK_SDA_DIR(1); for (i = 8; i--;) { - /* the chip latches incoming bits on the rising edge of SCL */ + /* The chip latches incoming bits on the rising edge of SCL. */ TK_SCL_OUT(0); TK_SDA_OUT(x & 1); tempudelay(1); @@ -138,7 +169,7 @@ int i; /* Read byte. Bits come LSB first, on the falling edge of SCL. - * Assume SDA is in input direction already + * Assume SDA is in input direction already. */ TK_SDA_DIR(0); @@ -154,7 +185,7 @@ return x; } -/* prepares for a transaction by de-activating RST (active-low) */ +/* Prepares for a transaction by de-activating RST (active-low). */ static void start(void) @@ -166,7 +197,7 @@ TK_RST_OUT(1); } -/* ends a transaction by taking RST active again */ +/* Ends a transaction by taking RST active again. */ static void stop(void) @@ -175,7 +206,7 @@ TK_RST_OUT(0); } -/* enable writing */ +/* Enable writing. */ static void ds1302_wenable(void) @@ -186,7 +217,7 @@ stop(); } -/* disable writing */ +/* Disable writing. */ static void ds1302_wdisable(void) @@ -197,7 +228,9 @@ stop(); } -/* probe for the chip by writing something to its RAM and try reading it back */ +/* Probe for the chip by writing something to its RAM and try reading it back. */ + +#define MAGIC_PATTERN 0x42 static int ds1302_probe(void) @@ -208,36 +241,36 @@ TK_SCL_DIR(1); TK_SDA_DIR(0); - /* try to talk to timekeeper */ + /* Try to talk to timekeeper. */ ds1302_wenable(); start(); out_byte(0xc0); /* write RAM byte 0 */ - out_byte(0x42); /* write something magic */ + out_byte(MAGIC_PATTERN); /* write something magic */ start(); out_byte(0xc1); /* read RAM byte 0 */ - if((res = in_byte()) == 0x42) { + if((res = in_byte()) == MAGIC_PATTERN) { char buf[100]; stop(); ds1302_wdisable(); - printk("DS1302 RTC found.\n"); - printk("SDA, SCL, RST on PB%i, PB%i, %s%i\n", - CONFIG_ETRAX_DS1302_SDABIT, - CONFIG_ETRAX_DS1302_SCLBIT, + printk("%s: RTC found.\n", ds1302_name); + printk("%s: SDA, SCL, RST on PB%i, PB%i, %s%i\n", + ds1302_name, + CONFIG_ETRAX_DS1302_SDABIT, + CONFIG_ETRAX_DS1302_SCLBIT, #ifdef CONFIG_ETRAX_DS1302_RST_ON_GENERIC_PORT - "GENIO", + "GENIO", #else - "PB", + "PB", #endif - CONFIG_ETRAX_DS1302_RSTBIT - ); + CONFIG_ETRAX_DS1302_RSTBIT); get_rtc_status(buf); printk(buf); retval = 1; } else { stop(); - printk("DS1302 RTC not found.\n"); + printk("%s: RTC not found.\n", ds1302_name); retval = 0; } @@ -245,7 +278,7 @@ } -/* read a byte from the selected register in the DS1302 */ +/* Read a byte from the selected register in the DS1302. */ unsigned char ds1302_readreg(int reg) @@ -253,21 +286,21 @@ unsigned char x; start(); - out_byte(0x81 | (reg << 1)); /* Read register */ + out_byte(0x81 | (reg << 1)); /* read register */ x = in_byte(); stop(); return x; } -/* write a byte to the selected register */ +/* Write a byte to the selected register. */ void ds1302_writereg(int reg, unsigned char val) { ds1302_wenable(); start(); - out_byte(0x80 | (reg << 1)); /* Write register */ + out_byte(0x80 | (reg << 1)); /* write register */ out_byte(val); stop(); ds1302_wdisable(); @@ -311,7 +344,7 @@ static unsigned char days_in_mo[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; -/* ioctl that supports RTC_RD_TIME and RTC_SET_TIME (read and set time/date) */ +/* ioctl that supports RTC_RD_TIME and RTC_SET_TIME (read and set time/date). */ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, @@ -320,7 +353,7 @@ unsigned long flags; switch(cmd) { - case RTC_RD_TIME: /* Read the time/date from RTC */ + case RTC_RD_TIME: /* read the time/date from RTC */ { struct rtc_time rtc_tm; @@ -330,16 +363,16 @@ return 0; } - case RTC_SET_TIME: /* Set the RTC */ + case RTC_SET_TIME: /* set the RTC */ { struct rtc_time rtc_tm; unsigned char mon, day, hrs, min, sec, leap_yr; unsigned char save_control, save_freq_select; unsigned int yrs; -#if 0 - if (!suser()) - return -EACCES; -#endif + + if (!capable(CAP_SYS_TIME)) + return -EPERM; + if (copy_from_user(&rtc_tm, (struct rtc_time*)arg, sizeof(struct rtc_time))) return -EFAULT; @@ -387,21 +420,21 @@ CMOS_WRITE(sec, RTC_SECONDS); restore_flags(flags); - /* notice that at this point, the RTC is updated but the kernel - * is still running with the old time. you need to set that - * separately with settimeofday or adjtimex. + /* Notice that at this point, the RTC is updated but + * the kernel is still running with the old time. + * You need to set that separately with settimeofday + * or adjtimex. */ return 0; } - case RTC_SET_CHARGE: /* Set the RTC TRICKLE CHARGE register */ + case RTC_SET_CHARGE: /* set the RTC TRICKLE CHARGE register */ { int tcs_val; unsigned char save_control, save_freq_select; -#if 0 - if (!suser()) - return -EACCES; -#endif + + if (!capable(CAP_SYS_TIME)) + return -EPERM; if(copy_from_user(&tcs_val, (int*)arg, sizeof(int))) return -EFAULT; @@ -415,10 +448,6 @@ } } -/* - * Info exported via "/proc/rtc". - */ - int get_rtc_status(char *buf) { @@ -444,45 +473,41 @@ } -/* - * The various file operations we support. - */ +/* The various file operations we support. */ static struct file_operations rtc_fops = { owner: THIS_MODULE, ioctl: rtc_ioctl, }; -/* just probe for the RTC and register the device to handle the ioctl needed */ +/* Just probe for the RTC and register the device to handle the ioctl needed. */ -int +int __init ds1302_init(void) { - - /* Ugly hack to handle both 2100 and 2400 hardware. - Remove... - */ - if(!ds1302_probe()) { + if (!ds1302_probe()) { #ifdef CONFIG_ETRAX_DS1302_RST_ON_GENERIC_PORT - /* - * Make sure that R_GEN_CONFIG is - * setup correct. - */ - genconfig_shadow = ( (genconfig_shadow & ~IO_MASK(R_GEN_CONFIG, ata) ) | - ( IO_STATE( R_GEN_CONFIG, ata, select ) ) ); + /* + * The only way to set g27 to output is to enable ATA. + * + * Make sure that R_GEN_CONFIG is setup correct. + */ + genconfig_shadow = ((genconfig_shadow & + ~IO_MASK(R_GEN_CONFIG, ata)) + | + (IO_STATE(R_GEN_CONFIG, ata, select))); *R_GEN_CONFIG = genconfig_shadow; - if(!ds1302_probe()) + if (!ds1302_probe()) return -1; #else return -1; #endif } - if (register_chrdev(RTC_MAJOR_NR, "rtc", &rtc_fops)) { - printk("unable to get major %d for rtc\n", RTC_MAJOR_NR); + if (register_chrdev(RTC_MAJOR_NR, ds1302_name, &rtc_fops)) { + printk(KERN_INFO "%s: unable to get major %d for rtc\n", + ds1302_name, RTC_MAJOR_NR); return -1; } return 0; } - - diff -u --recursive --new-file v2.4.6/linux/arch/cris/drivers/eeprom.c linux/arch/cris/drivers/eeprom.c --- v2.4.6/linux/arch/cris/drivers/eeprom.c Tue May 1 16:04:56 2001 +++ linux/arch/cris/drivers/eeprom.c Wed Jul 4 11:50:38 2001 @@ -1,32 +1,12 @@ -/*!************************************************************************** +/*!***************************************************************************** *! -*! FILE NAME: e100eeprom.c -*! -*! DESCRIPTION: Implements an interface for i2c compatible eeproms to run -*! under linux. -*! Supports 2k, 8k(?) and 16k -*! Uses adaptive timing adjustents by Johan.Adolfsson@axis.com -*! Probing results: -*! 8k or not is detected (the assumes 2k or 16k) -*! 2k or 16k detected using test reads and writes. -*! -*! FUNCTIONS: -*! -*! (Exported) -*! eeprom_init() -*! -*! (Local) -*! -*! eeprom_open() -*! eeprom_lseek() -*! eeprom_read() -*! eeprom_write() -*! eeprom_close() -*! eeprom_address() -*! eeprom_disable_write_protect() -*! -*! -*! $Id: eeprom.c,v 1.3 2001/03/19 16:04:46 markusl Exp $ +*! Implements an interface for i2c compatible eeproms to run under linux. +*! Supports 2k, 8k(?) and 16k. Uses adaptive timing adjustents by +*! Johan.Adolfsson@axis.com +*! +*! Probing results: +*! 8k or not is detected (the assumes 2k or 16k) +*! 2k or 16k detected using test reads and writes. *! *!------------------------------------------------------------------------ *! HISTORY @@ -40,6 +20,13 @@ *! in the spin-lock. *! *! $Log: eeprom.c,v $ +*! Revision 1.5 2001/06/14 14:39:51 jonashg +*! Forgot to use name when registering the driver. +*! +*! Revision 1.4 2001/06/14 14:35:47 jonashg +*! * Gave driver a name and used it in printk's. +*! * Cleanup. +*! *! Revision 1.3 2001/03/19 16:04:46 markusl *! Fixed init of fops struct *! @@ -64,9 +51,7 @@ *! *! *! (c) 1999 Axis Communications AB, Lund, Sweden -*!**************************************************************************/ - -/********************** INCLUDE FILES SECTION ******************************/ +*!*****************************************************************************/ #include <linux/config.h> #include <linux/kernel.h> @@ -76,7 +61,6 @@ #include <linux/delay.h> #include "i2c.h" -/********************** CONSTANT AND MACRO SECTION *************************/ #define D(x) /* If we should use adaptive timing or not: */ @@ -86,9 +70,8 @@ #define EEPROM_MINOR_NR 0 #define MAX_WRITEDELAY_US 10000 /* 10 ms according to spec for 2KB EEPROM */ -/* - * this one defines how many times to try when eeprom fails. - */ + +/* This one defines how many times to try when eeprom fails. */ #define EEPROM_RETRIES 10 #define EEPROM_2KB (2 * 1024) @@ -98,8 +81,6 @@ #define i2c_delay(x) udelay(x) -/********************** TYPE DEFINITION SECTION ****************************/ - /* * This structure describes the attached eeprom chip. * The values are probed for. @@ -110,51 +91,42 @@ unsigned long size; unsigned long sequential_write_pagesize; unsigned char select_cmd; - unsigned long usec_delay_writecycles; /* Min time between write cycles (up to 10ms for some models) */ - unsigned long int usec_delay_step; /* For adaptive algorithm */ + unsigned long usec_delay_writecycles; /* Min time between write cycles + (up to 10ms for some models) */ + unsigned long usec_delay_step; /* For adaptive algorithm */ int adapt_state; /* 1 = To high , 0 = Even, -1 = To low */ /* this one is to keep the read/write operations atomic */ wait_queue_head_t wait_q; int busy; int retry_cnt_addr; /* Used to keep track of number of retries for - adaptive timing adjustments */ + adaptive timing adjustments */ int retry_cnt_read; - - - }; -/********************** LOCAL FUNCTION DECLARATION SECTION *****************/ - -static int eeprom_open (struct inode * inode, struct file * file); +static int eeprom_open(struct inode * inode, struct file * file); static loff_t eeprom_lseek(struct file * file, loff_t offset, int orig); -static ssize_t eeprom_read (struct file * file, char * buf, size_t count, loff_t *off); -static ssize_t eeprom_write(struct file * file, const char * buf, size_t count, loff_t *off); +static ssize_t eeprom_read(struct file * file, char * buf, size_t count, + loff_t *off); +static ssize_t eeprom_write(struct file * file, const char * buf, size_t count, + loff_t *off); static int eeprom_close(struct inode * inode, struct file * file); static int eeprom_address(unsigned long addr); static int read_from_eeprom(char * buf, int count); -static int eeprom_write_buf(unsigned long int addr, - const char * buf, int count); +static int eeprom_write_buf(unsigned long addr, const char * buf, int count); static int eeprom_read_buf(unsigned long addr, char * buf, int count); static void eeprom_disable_write_protect(void); -/********************** GLOBAL VARIABLE DECLARATION SECTION ****************/ - -/********************** LOCAL VARIABLE DECLARATION SECTION *****************/ +static const char eeprom_name[] = "eeprom"; /* chip description */ static struct eeprom_type eeprom; -/* - * This is the exported file-operations structure - * for this device. - */ - +/* This is the exported file-operations structure for this device. */ struct file_operations eeprom_fops = { llseek: eeprom_lseek, @@ -164,29 +136,7 @@ release: eeprom_close }; -/********************** FUNCTION DEFINITION SECTION ************************/ - -/*#************************************************************************** -*# -*# FUNCTION NAME: eeprom_init -*# -*# PARAMETERS : none -*# -*# RETURNS : 0 if OK -*# -*# SIDE EFFECTS : -*# -*# DESCRIPTION : eeprom init call. Probes for different eeprom models. -*# -*#--------------------------------------------------------------------------- -*# HISTORY -*# -*# DATE NAME CHANGES -*# ---- ---- ------- -*# Aug 28 1999 Edgar Iglesias Initial version -*# Sep 03 1999 Edgar Iglesias Updated probing. Added forced values. -*# -*#**************************************************************************/ +/* eeprom init call. Probes for different eeprom models. */ int __init eeprom_init(void) { @@ -198,9 +148,10 @@ #else #define EETEXT "Assuming" #endif - if (register_chrdev(EEPROM_MAJOR_NR, "mem", &eeprom_fops)) + if (register_chrdev(EEPROM_MAJOR_NR, eeprom_name, &eeprom_fops)) { - printk("unable to get major %d for eeprom device\n", EEPROM_MAJOR_NR); + printk(KERN_INFO "%s: unable to get major %d for eeprom device\n", + eeprom_name, EEPROM_MAJOR_NR); return -1; } @@ -213,7 +164,6 @@ * for all models. If you encounter problems the easiest way * is probably to define your model within #ifdef's, and hard- * code it. - * */ eeprom.size = 0; @@ -240,7 +190,6 @@ * 2. if it doesn't differ - write diferent value to one of the locations, * check the other - if content still is the same it's a 2k EEPROM, * restore original data. - * */ #define LOC1 8 #define LOC2 (0x1fb) /*1fb, 3ed, 5df, 7d1 */ @@ -256,7 +205,7 @@ } else { - printk("Failed to read in 2k mode!\n"); + printk(KERN_INFO "%s: Failed to read in 2k mode!\n", eeprom_name); } /* 16k settings */ @@ -276,7 +225,7 @@ if (memcmp(loc1, loc2, 4) != 0 ) { /* It's 16k */ - printk("16k detected in step 1\n"); + printk(KERN_INFO "%s: 16k detected in step 1\n", eeprom_name); eeprom.size = EEPROM_16KB; success = 1; } @@ -299,7 +248,8 @@ LOC1, loc1, tmp)); if (memcmp(loc1, tmp, 4) != 0 ) { - printk("read and write differs! Not 16kB\n"); + printk(KERN_INFO "%s: read and write differs! Not 16kB\n", + eeprom_name); loc1[0] = ~loc1[0]; if (eeprom_write_buf(LOC1, loc1, 1) == 1) @@ -308,7 +258,8 @@ } else { - printk("eeprom: Restore 2k failed during probe EEPROM might be corrupt!\n"); + printk(KERN_INFO "%s: Restore 2k failed during probe," + " EEPROM might be corrupt!\n", eeprom_name); } i2c_stop(); @@ -321,7 +272,8 @@ } else { - printk("Failed to write back 2k start!\n"); + printk(KERN_INFO "%s: Failed to write back 2k start!\n", + eeprom_name); } eeprom.size = EEPROM_2KB; @@ -338,7 +290,7 @@ { /* Data the same, must be mirrored -> 2k */ /* Restore data */ - printk("2k detected in step 2\n"); + printk(KERN_INFO "%s: 2k detected in step 2\n", eeprom_name); loc1[0] = ~loc1[0]; if (eeprom_write_buf(LOC1, loc1, 1) == 1) { @@ -346,7 +298,8 @@ } else { - printk("eeprom: Restore 2k failed during probe EEPROM might be corrupt!\n"); + printk(KERN_INFO "%s: Restore 2k failed during probe," + " EEPROM might be corrupt!\n", eeprom_name); } @@ -354,7 +307,8 @@ } else { - printk("16k detected in step 2\n"); + printk(KERN_INFO "%s: 16k detected in step 2\n", + eeprom_name); loc1[0] = ~loc1[0]; /* Data differs, assume 16k */ /* Restore data */ @@ -364,7 +318,8 @@ } else { - printk("eeprom: Restore 16k failed during probe EEPROM might be corrupt!\n"); + printk(KERN_INFO "%s: Restore 16k failed during probe," + " EEPROM might be corrupt!\n", eeprom_name); } eeprom.size = EEPROM_16KB; @@ -376,7 +331,7 @@ } /* address LOC1 */ if (!success) { - printk("eeprom: Probing failed!, using 2KB!\n"); + printk(KERN_INFO "%s: Probing failed!, using 2KB!\n", eeprom_name); eeprom.size = EEPROM_2KB; } } /* read */ @@ -418,23 +373,23 @@ switch(eeprom.size) { case (EEPROM_2KB): - printk("e100eeprom: " EETEXT " i2c compatible 2Kb eeprom.\n"); + printk("%s: " EETEXT " i2c compatible 2Kb eeprom.\n", eeprom_name); eeprom.sequential_write_pagesize = 16; eeprom.select_cmd = 0xA0; break; case (EEPROM_8KB): - printk("e100eeprom: " EETEXT " i2c compatible 8Kb eeprom.\n"); + printk("%s: " EETEXT " i2c compatible 8Kb eeprom.\n", eeprom_name); eeprom.sequential_write_pagesize = 16; eeprom.select_cmd = 0x80; break; case (EEPROM_16KB): - printk("e100eeprom: " EETEXT " i2c compatible 16Kb eeprom.\n"); + printk("%s: " EETEXT " i2c compatible 16Kb eeprom.\n", eeprom_name); eeprom.sequential_write_pagesize = 64; eeprom.select_cmd = 0xA0; break; default: eeprom.size = 0; - printk("e100eeprom: Did not find a supported eeprom\n"); + printk("%s: Did not find a supported eeprom\n", eeprom_name); break; } @@ -445,28 +400,7 @@ return 0; } -/*#************************************************************************** -*# -*# FUNCTION NAME: eeprom_open -*# -*# PARAMETERS : inode : Pointer to the inode -*# file : Pointer to the file -*# -*# RETURNS : 0 if OK -*# -*# SIDE EFFECTS : -*# -*# DESCRIPTION : Opens the device. -*# -*#--------------------------------------------------------------------------- -*# HISTORY -*# -*# DATE NAME CHANGES -*# ---- ---- ------- -*# Aug 28 1999 Edgar Iglesias Initial version -*# Sep 03 1999 Edgar Iglesias Removed users check. -*# -*#**************************************************************************/ +/* Opens the device. */ static int eeprom_open(struct inode * inode, struct file * file) { @@ -486,29 +420,7 @@ return -EFAULT; } -/*#************************************************************************** -*# -*# FUNCTION NAME: eeprom_lseek -*# -*# PARAMETERS : file : Pointer to the file -*# offset : The offset (in bytes) -*# orig : look at the note -*# -*# RETURNS : 0 if OK -*# -*# SIDE EFFECTS : -*# -*# DESCRIPTION : Changes the current file position. -*# -*#--------------------------------------------------------------------------- -*# HISTORY -*# -*# DATE NAME CHANGES -*# ---- ---- ------- -*# Aug 28 1999 Edgar Iglesias Initial version -*# Sep 03 1999 Edgar Iglesias Return -EOVERFLOW when beyond eeprom size. -*# -*#**************************************************************************/ +/* Changes the current file position. */ static loff_t eeprom_lseek(struct file * file, loff_t offset, int orig) { @@ -549,29 +461,8 @@ return ( file->f_pos ); } -/*#************************************************************************** -*# -*# FUNCTION NAME: eeprom_read -*# -*# PARAMETERS : inode : Pointer to the inode -*# file : Pointer to the file -*# buf : Destination buffer -*# count : max nr bytes to read -*# -*# RETURNS : number of read bytes. -*# -*# SIDE EFFECTS : updates file->f_pos -*# -*# DESCRIPTION : Reads data from eeprom. -*# -*#--------------------------------------------------------------------------- -*# HISTORY -*# -*# DATE NAME CHANGES -*# ---- ---- ------- -*# Jan 17 2000 Johan Adolfsson Initial version -*# -*#**************************************************************************/ +/* Reads data from eeprom. */ + static int eeprom_read_buf(unsigned long addr, char * buf, int count) { @@ -583,31 +474,7 @@ -/*#************************************************************************** -*# -*# FUNCTION NAME: eeprom_read -*# -*# PARAMETERS : file : Pointer to the file -*# buf : Destination buffer -*# count : max nr bytes to read -*# -*# RETURNS : number of read bytes. -*# -*# SIDE EFFECTS : updates file->f_pos -*# -*# DESCRIPTION : Reads data from eeprom. -*# -*#--------------------------------------------------------------------------- -*# HISTORY -*# -*# DATE NAME CHANGES -*# ---- ---- ------- -*# Aug 28 1999 Edgar Iglesias Initial version -*# Aug 31 1999 Edgar Iglesias Made operation atomic with wait queues -*# Sep 03 1999 Edgar Iglesias Added bail-out stuff if we get interrupted -*# in the spin-lock. -*# -*#**************************************************************************/ +/* Reads data from eeprom. */ static ssize_t eeprom_read(struct file * file, char * buf, size_t count, loff_t *off) { @@ -636,8 +503,8 @@ if(!eeprom_address(p)) { - printk("eeprom: Read failed to address the eeprom: " - "0x%08X (%i) page: %i\n", p, p, page); + printk(KERN_INFO "%s: Read failed to address the eeprom: " + "0x%08X (%i) page: %i\n", eeprom_name, p, p, page); i2c_stop(); /* don't forget to wake them up */ @@ -674,30 +541,9 @@ return read; } -/*#************************************************************************** -*# -*# FUNCTION NAME: eeprom_write_buf -*# -*# PARAMETERS : addr : Address to write to -*# buf : Data buffer to write from -*# count : number bytes to write -*# -*# RETURNS : number of bytes actualy written. -*# -*# SIDE EFFECTS : None -*# -*# DESCRIPTION : Writes data to eeprom. -*# -*#--------------------------------------------------------------------------- -*# HISTORY -*# -*# DATE NAME CHANGES -*# ---- ---- ------- -*# Jan 17 2000 Johan Adolfsson Initial vesion -*# -*#**************************************************************************/ -static int eeprom_write_buf(unsigned long int addr, - const char * buf, int count) +/* Writes data to eeprom. */ + +static int eeprom_write_buf(unsigned long addr, const char * buf, int count) { struct file f; @@ -707,33 +553,7 @@ } -/*#************************************************************************** -*# -*# FUNCTION NAME: eeprom_write -*# -*# PARAMETERS : file : Pointer to the file -*# buf : Data buffer to write from -*# count : number bytes to write -*# -*# RETURNS : number of bytes actualy written. -*# -*# SIDE EFFECTS : updates file->f_pos -*# -*# DESCRIPTION : Writes data to eeprom. -*# -*#--------------------------------------------------------------------------- -*# HISTORY -*# -*# DATE NAME CHANGES -*# ---- ---- ------- -*# Aug 28 1999 Edgar Iglesias Initial version -*# Aug 31 1999 Edgar Iglesias Made operation atomic with wait queues -*# Sep 03 1999 Edgar Iglesias Moved the actual reading to read_from_eeprom -*# Sep 03 1999 Edgar Iglesias Added bail-out stuff if we get interrupted -*# in the spin-lock. -*# May 18 2000 Edgar Iglesias Make sure to end write cycle after every write. -*# -*#**************************************************************************/ +/* Writes data to eeprom. */ static ssize_t eeprom_write(struct file * file, const char * buf, size_t count, loff_t *off) @@ -761,8 +581,8 @@ /* address the eeprom */ if(!eeprom_address(p)) { - printk("eeprom: Write failed to address the eeprom: 0x%08X (%i) \n", - p, p); + printk(KERN_INFO "%s: Write failed to address the eeprom: " + "0x%08X (%i) \n", eeprom_name, p, p); i2c_stop(); /* don't forget to wake them up */ @@ -868,7 +688,7 @@ if(!i2c_getack()) { restart=1; - printk("eeprom: write error, retrying. %d\n", i); + printk(KERN_INFO "%s: write error, retrying. %d\n", eeprom_name, i); i2c_stop(); break; } @@ -891,28 +711,7 @@ return written; } -/*#************************************************************************** -*# -*# FUNCTION NAME: eeprom_close -*# -*# PARAMETERS : inode : Pointer to the inode -*# file : Pointer to the file -*# -*# RETURNS : nothing -*# -*# SIDE EFFECTS : -*# -*# DESCRIPTION : Closes the device. -*# -*#--------------------------------------------------------------------------- -*# HISTORY -*# -*# DATE NAME CHANGES -*# ---- ---- ------- -*# Aug 28 1999 Edgar Iglesias Initial version -*# Sep 03 1999 Edgar Iglesias Removed eeprom.users stuff. -*# -*#**************************************************************************/ +/* Closes the device. */ static int eeprom_close(struct inode * inode, struct file * file) { @@ -920,27 +719,7 @@ return 0; } -/*#************************************************************************** -*# -*# FUNCTION NAME: eeprom_address -*# -*# PARAMETERS : addr : Address to be given to eeprom -*# -*# RETURNS : 1 if OK, 0 if failure. -*# -*# SIDE EFFECTS : -*# -*# DESCRIPTION : Sets the current address of the eeprom. -*# -*#--------------------------------------------------------------------------- -*# HISTORY -*# -*# DATE NAME CHANGES -*# ---- ---- ------- -*# Aug 28 1999 Edgar Iglesias Initial version -*# Sep 03 1999 Edgar Iglesias Corrected typo. -*# -*#**************************************************************************/ +/* Sets the current address of the eeprom. */ static int eeprom_address(unsigned long addr) { @@ -999,27 +778,7 @@ return 1; } -/*#************************************************************************** -*# -*# FUNCTION NAME: read_from_eeprom -*# -*# PARAMETERS : buf : Destination buffer. -*# count : Number of bytes to read. -*# -*# RETURNS : number of read bytes or -EFAULT. -*# -*# SIDE EFFECTS : -*# -*# DESCRIPTION : Reads from current adress. -*# -*#--------------------------------------------------------------------------- -*# HISTORY -*# -*# DATE NAME CHANGES -*# ---- ---- ------- -*# Sep 03 1999 Edgar Iglesias Initial version -*# -*#**************************************************************************/ +/* Reads from current adress. */ static int read_from_eeprom(char * buf, int count) { @@ -1040,7 +799,7 @@ if(i == EEPROM_RETRIES) { - printk("eeprom: failed to read from eeprom\n"); + printk(KERN_INFO "%s: failed to read from eeprom\n", eeprom_name); i2c_stop(); return -EFAULT; @@ -1066,26 +825,8 @@ return read; } -/*#************************************************************************** -*# -*# FUNCTION NAME: eeprom_disable_write_protect -*# -*# PARAMETERS : None -*# -*# RETURNS : Nothing -*# -*# SIDE EFFECTS : -*# -*# DESCRIPTION : Disables write protection if applicable -*# -*#--------------------------------------------------------------------------- -*# HISTORY -*# -*# DATE NAME CHANGES -*# ---- ---- ------- -*# Jan 14 2000 Johan Adolfsson Initial version (from PS pareerom.c) -*# -*#**************************************************************************/ +/* Disables write protection if applicable. */ + #define DBP_SAVE(x) #define ax_printf printk static void eeprom_disable_write_protect(void) @@ -1133,7 +874,7 @@ } i2c_stop(); - /* Step 3 Set BP1, BP0, and/or WPEN bits (write 00000110 to address 1FFFh*/ + /* Step 3 Set BP1, BP0, and/or WPEN bits (write 00000110 to address 1FFFh */ i2c_start(); i2c_outbyte(0xbe); if(!i2c_getack()) @@ -1157,5 +898,3 @@ } module_init(eeprom_init); - -/********************** END OF FILE e100eeprom.c *****************************/ diff -u --recursive --new-file v2.4.6/linux/arch/cris/drivers/ethernet.c linux/arch/cris/drivers/ethernet.c --- v2.4.6/linux/arch/cris/drivers/ethernet.c Tue May 1 16:04:56 2001 +++ linux/arch/cris/drivers/ethernet.c Wed Jul 4 11:50:38 2001 @@ -1,4 +1,4 @@ -/* $Id: ethernet.c,v 1.12 2001/04/05 11:43:11 tobiasa Exp $ +/* $Id: ethernet.c,v 1.17 2001/06/11 12:43:46 olof Exp $ * * e100net.c: A network driver for the ETRAX 100LX network controller. * @@ -7,6 +7,23 @@ * The outline of this driver comes from skeleton.c. * * $Log: ethernet.c,v $ + * Revision 1.17 2001/06/11 12:43:46 olof + * Modified defines for network LED behavior + * + * Revision 1.16 2001/05/30 06:12:46 markusl + * TxDesc.next should not be set to NULL + * + * Revision 1.15 2001/05/29 10:27:04 markusl + * Updated after review remarks: + * +Use IO_EXTRACT + * +Handle underrun + * + * Revision 1.14 2001/05/29 09:20:14 jonashg + * Use driver name on printk output so one can tell which driver that complains. + * + * Revision 1.13 2001/05/09 12:35:59 johana + * Use DMA_NBR and IRQ_NBR defines from dma.h and irq.h + * * Revision 1.12 2001/04/05 11:43:11 tobiasa * Check dev before panic. * @@ -80,6 +97,7 @@ #include <asm/svinto.h> /* DMA and register descriptions */ #include <asm/io.h> /* LED_* I/O functions */ +#include <asm/irq.h> #include <asm/dma.h> #include <asm/system.h> #include <asm/bitops.h> @@ -87,8 +105,6 @@ //#define ETHDEBUG #define D(x) -#define ETH_TX_DMA 0 -#define ETH_RX_DMA 1 /* * The name of the card. Is used for messages and in the requests for @@ -116,9 +132,6 @@ spinlock_t lock; }; -#define NETWORK_DMARX_IRQ 17 /* irq 17 is the DMA1 irq */ -#define NETWORK_DMATX_IRQ 16 /* irq 16 is the DMA0 irq */ -#define NETWORK_STATUS_IRQ 6 /* irq 6 is the network irq */ /* Dma descriptors etc. */ @@ -231,7 +244,8 @@ /* make Linux aware of the new hardware */ if (!dev) { - printk("dev == NULL. Should this happen?\n"); + printk(KERN_WARNING "%s: dev == NULL. Should this happen?\n", + cardname); dev = init_etherdev(dev, sizeof(struct net_local)); if (!dev) panic("init_etherdev failed\n"); @@ -250,8 +264,8 @@ /* now setup our etrax specific stuff */ - dev->irq = NETWORK_DMARX_IRQ; /* we really use DMATX as well... */ - dev->dma = 1; + dev->irq = NETWORK_DMA_RX_IRQ_NBR; /* we really use DMATX as well... */ + dev->dma = NETWORK_RX_DMA_NBR; /* fill in our handlers so the network layer can talk to us in the future */ @@ -381,30 +395,30 @@ /* Reset and wait for the DMA channels */ - RESET_DMA(0); - RESET_DMA(1); - WAIT_DMA(0); - WAIT_DMA(1); + RESET_DMA(NETWORK_TX_DMA_NBR); + RESET_DMA(NETWORK_RX_DMA_NBR); + WAIT_DMA(NETWORK_TX_DMA_NBR); + WAIT_DMA(NETWORK_RX_DMA_NBR); /* Initialise the etrax network controller */ /* allocate the irq corresponding to the receiving DMA */ - if (request_irq(NETWORK_DMARX_IRQ, e100rx_interrupt, 0, + if (request_irq(NETWORK_DMA_RX_IRQ_NBR, e100rx_interrupt, 0, cardname, (void *)dev)) { goto grace_exit; } /* allocate the irq corresponding to the transmitting DMA */ - if (request_irq(NETWORK_DMATX_IRQ, e100tx_interrupt, 0, + if (request_irq(NETWORK_DMA_TX_IRQ_NBR, e100tx_interrupt, 0, cardname, (void *)dev)) { goto grace_exit; } /* allocate the irq corresponding to the network errors etc */ - if (request_irq(NETWORK_STATUS_IRQ, e100nw_interrupt, 0, + if (request_irq(NETWORK_STATUS_IRQ_NBR, e100nw_interrupt, 0, cardname, (void *)dev)) { goto grace_exit; } @@ -414,17 +428,17 @@ * and clean up on failure. */ - if(request_dma(ETH_TX_DMA, cardname)) { + if(request_dma(NETWORK_TX_DMA_NBR, cardname)) { goto grace_exit; } - if(request_dma(ETH_RX_DMA, cardname)) { + if(request_dma(NETWORK_RX_DMA_NBR, cardname)) { grace_exit: /* this will cause some 'trying to free free irq' but what the heck... */ - free_dma(ETH_TX_DMA); - free_irq(NETWORK_DMARX_IRQ, (void *)dev); - free_irq(NETWORK_DMATX_IRQ, (void *)dev); - free_irq(NETWORK_STATUS_IRQ, (void *)dev); + free_dma(NETWORK_TX_DMA_NBR); + free_irq(NETWORK_DMA_RX_IRQ_NBR, (void *)dev); + free_irq(NETWORK_DMA_TX_IRQ_NBR, (void *)dev); + free_irq(NETWORK_STATUS_IRQ_NBR, (void *)dev); return -EAGAIN; } @@ -625,8 +639,8 @@ /* reset the TX DMA in case it has hung on something */ - RESET_DMA(0); - WAIT_DMA(0); + RESET_DMA(NETWORK_TX_DMA_NBR); + WAIT_DMA(NETWORK_TX_DMA_NBR); /* Reset the tranceiver. */ @@ -751,7 +765,8 @@ tx_skb = 0; netif_wake_queue(dev); } else { - printk("tx weird interrupt\n"); + printk(KERN_WARNING "%s: tx weird interrupt\n", + cardname); } spin_unlock(&np->lock); @@ -765,6 +780,13 @@ struct net_local *np = (struct net_local *)dev->priv; unsigned long irqbits = *R_IRQ_MASK0_RD; + /* check for underrun irq */ + if(irqbits & IO_STATE(R_IRQ_MASK0_RD, underrun, active)) { + *R_NETWORK_TR_CTRL = IO_STATE(R_NETWORK_TR_CTRL, clr_error, clr); + np->stats.tx_errors++; + D(printk("ethernet receiver underrun!\n")); + } + /* check for overrun irq */ if(irqbits & IO_STATE(R_IRQ_MASK0_RD, overrun, active)) { update_rx_stats(&np->stats); /* this will ack the irq */ @@ -900,17 +922,17 @@ /* Stop the receiver and the transmitter */ - RESET_DMA(0); - RESET_DMA(1); + RESET_DMA(NETWORK_TX_DMA_NBR); + RESET_DMA(NETWORK_RX_DMA_NBR); /* Flush the Tx and disable Rx here. */ - free_irq(NETWORK_DMARX_IRQ, (void *)dev); - free_irq(NETWORK_DMATX_IRQ, (void *)dev); - free_irq(NETWORK_STATUS_IRQ, (void *)dev); + free_irq(NETWORK_DMA_RX_IRQ_NBR, (void *)dev); + free_irq(NETWORK_DMA_TX_IRQ_NBR, (void *)dev); + free_irq(NETWORK_STATUS_IRQ_NBR, (void *)dev); - free_dma(ETH_TX_DMA); - free_dma(ETH_RX_DMA); + free_dma(NETWORK_TX_DMA_NBR); + free_dma(NETWORK_RX_DMA_NBR); /* Update the statistics here. */ @@ -925,10 +947,10 @@ { unsigned long r = *R_REC_COUNTERS; /* update stats relevant to reception errors */ - es->rx_fifo_errors += r >> 24; /* fifo overrun */ - es->rx_crc_errors += r & 0xff; /* crc error */ - es->rx_frame_errors += (r >> 8) & 0xff; /* alignment error */ - es->rx_length_errors += (r >> 16) & 0xff; /* oversized frames */ + es->rx_fifo_errors += IO_EXTRACT(R_REC_COUNTERS, congestion, r); + es->rx_crc_errors += IO_EXTRACT(R_REC_COUNTERS, crc_error, r); + es->rx_frame_errors += IO_EXTRACT(R_REC_COUNTERS, alignment_error, r); + es->rx_length_errors += IO_EXTRACT(R_REC_COUNTERS, oversize, r); } static void @@ -936,8 +958,10 @@ { unsigned long r = *R_TR_COUNTERS; /* update stats relevant to transmission errors */ - es->collisions += (r & 0xff) + ((r >> 8) & 0xff); /* single_col + multiple_col */ - es->tx_errors += (r >> 24) & 0xff; /* deferred transmit frames */ + es->collisions += + IO_EXTRACT(R_TR_COUNTERS, single_col, r) + + IO_EXTRACT(R_TR_COUNTERS, multiple_col, r); + es->tx_errors += IO_EXTRACT(R_TR_COUNTERS, deferred, r); } /* @@ -1082,10 +1106,12 @@ static void e100_set_network_leds(int active) { -#ifdef CONFIG_LED_OFF_DURING_ACTIVITY +#if defined(CONFIG_ETRAX_NETWORK_LED_ON_WHEN_LINK) int light_leds = (active == NO_NETWORK_ACTIVITY); -#else +#elif defined(CONFIG_ETRAX_NETWORK_LED_ON_WHEN_ACTIVITY) int light_leds = (active == NETWORK_ACTIVITY); +#else +#error "Define either CONFIG_ETRAX_NETWORK_LED_ON_WHEN_LINK or CONFIG_ETRAX_NETWORK_LED_ON_WHEN_ACTIVITY" #endif if (!current_speed) { diff -u --recursive --new-file v2.4.6/linux/arch/cris/drivers/gpio.c linux/arch/cris/drivers/gpio.c --- v2.4.6/linux/arch/cris/drivers/gpio.c Sat May 19 17:43:05 2001 +++ linux/arch/cris/drivers/gpio.c Wed Jul 4 11:50:38 2001 @@ -1,4 +1,4 @@ -/* $Id: gpio.c,v 1.7 2001/04/04 13:30:08 matsfg Exp $ +/* $Id: gpio.c,v 1.9 2001/05/04 14:16:07 matsfg Exp $ * * Etrax general port I/O device * @@ -9,6 +9,14 @@ * Johan Adolfsson (read/set directions) * * $Log: gpio.c,v $ + * Revision 1.9 2001/05/04 14:16:07 matsfg + * Corrected spelling error + * + * Revision 1.8 2001/04/27 13:55:26 matsfg + * Moved initioremap. + * Turns off all LEDS on init. + * Added support for shutdown and powerbutton. + * * Revision 1.7 2001/04/04 13:30:08 matsfg * Added bitset and bitclear for leds. Calls init_ioremap to set up memmapping * @@ -247,6 +255,16 @@ *priv->dir = *priv->dir_shadow |= ((unsigned char)arg & priv->changeable_dir); return *priv->dir_shadow; + case IO_SHUTDOWN: + SOFT_SHUTDOWN(); + break; + case IO_GET_PWR_BT: +#if defined (CONFIG_ETRAX_SOFT_SHUTDOWN) + return (*R_PORT_G_DATA & + ( 1 << CONFIG_ETRAX_POWERBUTTON_BIT)); +#else + return 0; +#endif default: if(priv->minor == LEDS) return gpio_leds_ioctl(cmd, arg); @@ -262,12 +280,6 @@ { unsigned char green; unsigned char red; - static int initialized = 0; - if(!initialized) - { - initialized = 1; - init_ioremap(); - } switch (_IOC_NR(cmd)) { case IO_LEDACTIVE_SET: green = ((unsigned char) arg) & 1; @@ -298,7 +310,7 @@ static __init int gpio_init(void) { - int res; + int res,i; /* do the formalities */ @@ -307,6 +319,24 @@ printk(KERN_ERR "gpio: couldn't get a major number.\n"); return res; } + + /* Clear all leds */ +#if defined (CONFIG_ETRAX_CSP0_LEDS) || defined (CONFIG_ETRAX_PA_LEDS) || defined (CONFIG_ETRAX_PB_LEDS) + + init_ioremap(); + LED_NETWORK_SET(0); + LED_ACTIVE_SET(0); + LED_DISK_READ(0); + LED_DISK_WRITE(0); + +#if defined (CONFIG_ETRAX_CSP0_LEDS) + for( i = 0; i < 32; i ++) + { + LED_BIT_SET(i); + } +#endif + +#endif printk("ETRAX 100LX GPIO driver v2.1, (c) 2001 Axis Communications AB\n"); diff -u --recursive --new-file v2.4.6/linux/arch/cris/drivers/ide.c linux/arch/cris/drivers/ide.c --- v2.4.6/linux/arch/cris/drivers/ide.c Tue Jul 3 17:08:18 2001 +++ linux/arch/cris/drivers/ide.c Wed Jul 4 11:50:38 2001 @@ -1,4 +1,4 @@ -/* $Id: ide.c,v 1.16 2001/04/05 08:30:07 matsfg Exp $ +/* $Id: ide.c,v 1.19 2001/05/09 12:53:16 johana Exp $ * * Etrax specific IDE functions, like init and PIO-mode setting etc. * Almost the entire ide.c is used for the rest of the Etrax ATA driver. @@ -8,6 +8,15 @@ * Mikael Starvik (pio setup stuff) * * $Log: ide.c,v $ + * Revision 1.19 2001/05/09 12:53:16 johana + * Added #include <asm/dma.h> + * + * Revision 1.18 2001/05/09 12:37:00 johana + * Use DMA_NBR macros from dma.h. + * + * Revision 1.17 2001/04/23 13:36:30 matsfg + * Changed CONFIG_IDE_DELAY to CONFIG_ETRAX_IDE_DELAY + * * Revision 1.16 2001/04/05 08:30:07 matsfg * Corrected cse1 and csp0 reset. * @@ -98,6 +107,7 @@ #include <asm/io.h> #include <asm/svinto.h> +#include <asm/dma.h> /* number of Etrax DMA descriptors */ #define MAX_DMA_DESCRS 64 @@ -341,17 +351,17 @@ IO_STATE( R_IRQ_MASK0_SET, ata_irq2, set ) | IO_STATE( R_IRQ_MASK0_SET, ata_irq3, set ) ); - printk("ide: waiting %d seconds for drives to regain consciousness\n", CONFIG_IDE_DELAY); + printk("ide: waiting %d seconds for drives to regain consciousness\n", CONFIG_ETRAX_IDE_DELAY); - h = jiffies + (CONFIG_IDE_DELAY * HZ); + h = jiffies + (CONFIG_ETRAX_IDE_DELAY * HZ); while(jiffies < h) ; /* reset the dma channels we will use */ - RESET_DMA(2); - RESET_DMA(3); - WAIT_DMA(2); - WAIT_DMA(3); + RESET_DMA(ATA_TX_DMA_NBR); + RESET_DMA(ATA_RX_DMA_NBR); + WAIT_DMA(ATA_TX_DMA_NBR); + WAIT_DMA(ATA_RX_DMA_NBR); } @@ -378,8 +388,8 @@ } /* make sure the DMA channel is available */ - RESET_DMA(3); - WAIT_DMA(3); + RESET_DMA(ATA_RX_DMA_NBR); + WAIT_DMA(ATA_RX_DMA_NBR); /* setup DMA descriptor */ @@ -406,7 +416,7 @@ /* wait for completion */ LED_DISK_READ(1); - WAIT_DMA(3); + WAIT_DMA(ATA_RX_DMA_NBR); LED_DISK_READ(0); #if 0 @@ -457,8 +467,8 @@ } /* make sure the DMA channel is available */ - RESET_DMA(2); - WAIT_DMA(2); + RESET_DMA(ATA_TX_DMA_NBR); + WAIT_DMA(ATA_TX_DMA_NBR); /* setup DMA descriptor */ @@ -485,7 +495,7 @@ /* wait for completion */ LED_DISK_WRITE(1); - WAIT_DMA(2); + WAIT_DMA(ATA_TX_DMA_NBR); LED_DISK_WRITE(0); #if 0 @@ -794,8 +804,8 @@ if(reading) { - RESET_DMA(3); /* sometimes the DMA channel get stuck so we need to do this */ - WAIT_DMA(3); + RESET_DMA(ATA_RX_DMA_NBR); /* sometimes the DMA channel get stuck so we need to do this */ + WAIT_DMA(ATA_RX_DMA_NBR); /* set up the Etrax DMA descriptors */ @@ -837,8 +847,8 @@ } else { /* writing */ - RESET_DMA(2); /* sometimes the DMA channel get stuck so we need to do this */ - WAIT_DMA(2); + RESET_DMA(ATA_TX_DMA_NBR); /* sometimes the DMA channel get stuck so we need to do this */ + WAIT_DMA(ATA_TX_DMA_NBR); /* set up the Etrax DMA descriptors */ diff -u --recursive --new-file v2.4.6/linux/arch/cris/drivers/lpslave/Makefile linux/arch/cris/drivers/lpslave/Makefile --- v2.4.6/linux/arch/cris/drivers/lpslave/Makefile Wed Dec 31 16:00:00 1969 +++ linux/arch/cris/drivers/lpslave/Makefile Wed Jul 4 11:50:38 2001 @@ -0,0 +1,20 @@ +# +# Makefile for parallel port slave drivers +# + +O_TARGET := lpslavedrivers.o + +obj-y = e100lpslavenet.o e100lpslave_code.o + + +include $(TOPDIR)/Rules.make + +e100lpslave_code.o: e100lpslave.o e100lpslaveld + $(CROSS_COMPILE)ld -qmagic -Te100lpslaveld e100lpslave.o -o e100lpslave + $(CROSS_COMPILE)objcopy -O binary --remove-section=.data --remove-section=.bss e100lpslave e100lpslave.text + $(CROSS_COMPILE)objcopy -O binary --remove-section=.text --remove-section=.bss e100lpslave e100lpslave.data + cat e100lpslave.text e100lpslave.data |\ + ./bintocarr.pl e100lpslaveprog |\ + $(CC) $(CFLAGS) -pipe -o e100lpslave_code.o -c -x c - + ls -l e100lpslave.text e100lpslave.data + rm -f e100lpslave e100lpslave.text e100lpslave.data diff -u --recursive --new-file v2.4.6/linux/arch/cris/drivers/lpslave/bintocarr.pl linux/arch/cris/drivers/lpslave/bintocarr.pl --- v2.4.6/linux/arch/cris/drivers/lpslave/bintocarr.pl Wed Dec 31 16:00:00 1969 +++ linux/arch/cris/drivers/lpslave/bintocarr.pl Wed Jul 4 11:50:38 2001 @@ -0,0 +1,29 @@ +#!/usr/bin/perl -w +# $Id: bintocarr.pl,v 1.3 2001/06/08 08:46:50 olof Exp $ +# Copy of mkjulbin.pl made by Olof +# convert a binary stdin to a C-file containing a char array of the input +# first argument is the symbol name + +$symbol = shift @ARGV; + +print "#include <linux/init.h>\n\n"; +print "unsigned char $symbol", "[] __initdata = {\n"; + +my $char; + +$bcount = 0; + +while(read STDIN, $char, 1) { + printf("0x%x, ", ord($char)); + $bcount++; + if(!($bcount % 16)) { + print "\n"; + } +} + +print "\n};\n"; + +$lensymb = ("_" . ($symbol . "_length")); + +print "__asm__(\"\\t.globl $lensymb\\n$lensymb = $bcount\\n\");\n"; + diff -u --recursive --new-file v2.4.6/linux/arch/cris/drivers/lpslave/e100lpslave.README linux/arch/cris/drivers/lpslave/e100lpslave.README --- v2.4.6/linux/arch/cris/drivers/lpslave/e100lpslave.README Wed Dec 31 16:00:00 1969 +++ linux/arch/cris/drivers/lpslave/e100lpslave.README Wed Jul 4 11:50:38 2001 @@ -0,0 +1,54 @@ +***** MODIFICATIONS +To use a 5600 as a slave device it has to somewhat modified. +This has to be done on a 5600 (art no 16144 R2) to automatically set it to parallel port boot mode: + +1) +Close to the LPT1 connector there are two resistors, between the "Pulse" inductor and +the LS245. The one closest to the LS245 is a 4k7 pull up (R105). Remove it. + +2) +Between the other "Pulse" inductor and Etrax there is a black 5-pin inverter +(D15). Short connectors 2 and 3 with a solder blob. + + +***** PINOUT +To use this driver use cables connected like this: +DSUB25-Male DSUB25Male + +1 10 +2-9 2-9 +10 1 +11 14 +12 18 +13 NC +14 11 +15 NC +16 NC +17 NC +18 12 +19 NC +20-25 20-25 + +Thus the cables are symmetrical with most cables straight through, +some crossed (1-10, 11-14 and 12-18) +and some Not connected (NC 13,15,16,17 and 19). + + +******* Only for reference +To ease the use of flat-cable connectors, here are the notes of wich wires to cross and cut with pin 1 being cable 1: +Cross: +1 19 +2 21 +10 23 +Cut: +4 +6 +8 +12 +25 + +jonas.dellenvall@axis.com + + + + diff -u --recursive --new-file v2.4.6/linux/arch/cris/drivers/lpslave/e100lpslave.S linux/arch/cris/drivers/lpslave/e100lpslave.S --- v2.4.6/linux/arch/cris/drivers/lpslave/e100lpslave.S Wed Dec 31 16:00:00 1969 +++ linux/arch/cris/drivers/lpslave/e100lpslave.S Wed Jul 4 11:50:39 2001 @@ -0,0 +1,429 @@ + ;; $Id: e100lpslave.S,v 1.2 2001/06/11 12:50:01 olof Exp $ + ;; + ;; Etrax100 slave network<->parport forwarder + ;; + ;; Copyright (c) 1999 Bjorn Wesen, Axis Communications AB + ;; + ;; We got 784 bytes (par loader size) to do DMA forwarding + ;; between DMA0/1 (ethernet) and DMA3/4 (par port 0 RX/1 TX) + ;; + +#include <linux/config.h> +#if 0 +#define ASSEMBLER_MACROS_ONLY +#endif +#include <asm/sv_addr_ag.h> + +#define BUFSIZE 0x600 + + ;; R_IRQ_READ2 + +#define DMA1EOPBIT 3 +#define DMA0EOPBIT 1 +#define DMA3EOPBIT 7 +#define DMA4DESCBIT 8 + + ;; R_IRQ_READ0 + +#define PAR0ECPCMDBIT 11 + + ;; get host CMDs + +#include "e100lpslave.h" + +start: + ;; disable interrupts. we are not going to use them at all. + + di + + ;; setup DMA connections and port configuration + + movu.w 0x84, r0 ; DMA2/3/4/5 to par ports + move.d r0, [R_GEN_CONFIG] + + ;; setup port PA dirs and turn on the LED to show were alive + + movu.w 0x0cfb, r0 ; PA2-PA3 out, PA2 inactive + move.d r0, [R_PORT_PA_SET] + + ;; enable MDIO output pin + moveq IO_STATE(R_NETWORK_MGM_CTRL, mdoe, enable), r0 + move.d r0, [R_NETWORK_MGM_CTRL] + + ;; accept broadcast frames, and enable station address 0 + moveq IO_STATE(R_NETWORK_REC_CONFIG, broadcast, receive) | \ + IO_STATE(R_NETWORK_REC_CONFIG, ma0, enable), r0 + move.d r0, [R_NETWORK_REC_CONFIG] + + ;; use MII CLK mode, and enable the controller + moveq IO_STATE(R_NETWORK_GEN_CONFIG, phy, mii_clk) | \ + IO_STATE(R_NETWORK_GEN_CONFIG, enable, on), r0 + move.d r0, [R_NETWORK_GEN_CONFIG] + + move.d IO_STATE(R_PAR0_CONFIG, ioe, noninv) | \ + IO_STATE(R_PAR0_CONFIG, iseli, noninv) | \ + IO_STATE(R_PAR0_CONFIG, iautofd, noninv) | \ + IO_STATE(R_PAR0_CONFIG, istrb, noninv) | \ + IO_STATE(R_PAR0_CONFIG, iinit, noninv) | \ + IO_STATE(R_PAR0_CONFIG, iperr, noninv) | \ + IO_STATE(R_PAR0_CONFIG, iack, noninv) | \ + IO_STATE(R_PAR0_CONFIG, ibusy, noninv) | \ + IO_STATE(R_PAR0_CONFIG, ifault, noninv) | \ + IO_STATE(R_PAR0_CONFIG, isel, noninv) | \ + IO_STATE(R_PAR0_CONFIG, dma, enable) | \ + IO_STATE(R_PAR0_CONFIG, rle_in, disable) | \ + IO_STATE(R_PAR0_CONFIG, rle_out, disable) | \ + IO_STATE(R_PAR0_CONFIG, enable, on) | \ + IO_STATE(R_PAR0_CONFIG, force, on) | \ + IO_STATE(R_PAR0_CONFIG, mode, ecp_rev), r0 ; Reverse ECP - PAR0 is RX + + move.d r0, [R_PAR0_CONFIG] + + move.d IO_STATE(R_PAR1_CONFIG, ioe, noninv) | \ + IO_STATE(R_PAR1_CONFIG, iseli, noninv) | \ + IO_STATE(R_PAR1_CONFIG, iautofd, noninv) | \ + IO_STATE(R_PAR1_CONFIG, istrb, noninv) | \ + IO_STATE(R_PAR1_CONFIG, iinit, noninv) | \ + IO_STATE(R_PAR1_CONFIG, iperr, inv) | \ + IO_STATE(R_PAR1_CONFIG, iack, noninv) | \ + IO_STATE(R_PAR1_CONFIG, ibusy, noninv) | \ + IO_STATE(R_PAR1_CONFIG, ifault, noninv) | \ + IO_STATE(R_PAR1_CONFIG, isel, noninv) | \ + IO_STATE(R_PAR1_CONFIG, dma, enable) | \ + IO_STATE(R_PAR1_CONFIG, rle_in, disable) | \ + IO_STATE(R_PAR1_CONFIG, rle_out, disable) | \ + IO_STATE(R_PAR1_CONFIG, enable, on) | \ + IO_STATE(R_PAR1_CONFIG, force, on) | \ + IO_STATE(R_PAR1_CONFIG, mode, ecp_fwd), r0 ; Forward ECP - PAR1 is TX + + move.d r0, [R_PAR1_CONFIG] + + moveq IO_FIELD(R_PAR1_DELAY, setup, 1), r0 ; setup time of value * 160 + 20 + move.d r0, [R_PAR1_DELAY] + + ;; we got four descriptors, that can be active at the same time: + ;; 1) from network + ;; 2) to parport + ;; 3) from parport + ;; 4) to network + ;; + ;; we got four buffers, each can hold a max packet (we use 1536 bytes) + ;; buffers 1 and 2 are used from network to parport, while + ;; buffers 3 and 4 are used from parport to network. + ;; + ;; a double buffering scheme is used, so that new data can be read + ;; into a buffer pair while the last data is written out from the + ;; last buffer. if the read buffer is done before the write buffer, + ;; the reading will halt until the writing is done, at which point + ;; writing starts from the newly read and reading can start with + ;; the newly written. + ;; + + move.d R_DMA_CH0_FIRST, r1 ; we use this as base for subsequent DMA ops + moveq IO_STATE(R_DMA_CH1_CMD, cmd, start), r6 + move.d FN1desc, r7 + move.d R_IRQ_READ0, r9 + + ;; start receiving from network + + jsr startdmaFPTN + jsr startdmaFNTP + + + + ;; ------------------- MAIN LOOP + + ;; IRQ bits: parport rcv is par0_ecp_cmd, then dma3_eop + ;; network rcv is dma1_eop + ;; parport tx is dma4_desc + ;; network tx is dma0_eop + +mainloop: + + ;; ------- first handle the parport -> network link + + ;; check if we got something from the parport + + move.d [r9], r0 ; r0 <- *R_IRQ_READ0 + btstq PAR0ECPCMDBIT, r0 + bpl noparecp + nop + + ;; ack it by reading PAR0_STATUS_DATA + + move.d [R_PAR0_STATUS_DATA], r0 + + ;; trigger EOP on DMA3 (par0 incoming channel) + + moveq IO_STATE(R_SET_EOP, ch3_eop, set), r0 + move.d r0, [R_SET_EOP] + +noparecp: + + ;; if we simultaneously have parport rx EOP and + ;; network TX eop, we can swap buffers and start a new RX/TX + + move.d [r9 + (R_IRQ_READ2 - R_IRQ_READ0)], r0 + btstq DMA3EOPBIT, r0 ; check parport rx + bpl noswap1 + btstq DMA0EOPBIT, r0 ; check network tx + bpl noswap1 + nop + + ;; prepare to swap buffer ptrs (FN3b <-> TN4b) + + move.d [r4 = r7 + 56], r0; FP3b + move.d [r3 = r7 + 72], r2; TN4b + + ;; but first check if this was a Host Command Packet + + move.d [r0], r5 ; r5 <- first 4 bytes in PAR-received packet + bne handle_command ; if non-zero, it was a host command + addq 4, r0 ; skip command (in delay slot - handle_command requires this) + move.d r0, [r3] ; write to To Network descriptor + subq 4, r2 ; undo the skipping done last swap + move.d r2, [r4] ; write to From Parport descriptor + + ;; clear the interrupts + + moveq IO_STATE(R_DMA_CH0_CLR_INTR, clr_eop, do), r0 + move.b r0, [r1 + (R_DMA_CH0_CLR_INTR - R_DMA_CH0_FIRST)] + move.b r0, [r1 + (R_DMA_CH3_CLR_INTR - R_DMA_CH0_FIRST)] + + ;; copy received length to outgoing network length + + move.w [r7 + 60], r0 ; FPhlen + subq 4, r0 ; skip command + move.w r0, [r7 + 64] ; TN4desc + + ;; restart DMAs + + jsr startdmaFPTN + +#ifdef CONFIG_ETRAX_ETHERNET_LPSLAVE_HAS_LEDS +#if defined(CONFIG_ETRAX_NETWORK_LED_ON_WHEN_LINK) + ;; Turn off the LED signaling an outgoing network packet + movu.b [LEDOff], r0 +#elif defined(CONFIG_ETRAX_NETWORK_LED_ON_WHEN_ACTIVITY) + ;; Light the LED signaling an outgoing network packet + movu.b [LEDAmber], r0 +#else +#error "Define either CONFIG_ETRAX_NETWORK_LED_ON_WHEN_LINK or CONFIG_ETRAX_NETWORK_LED_ON_WHEN_ACTIVITY" +#endif + move.b r0, [R_PORT_PA_DATA] + move.d 0x00011000, r0 + move.d r0,[LEDCount] +#endif + +noswap1: + ;; ----- now check the network -> parport link + + + ;; if we simultaneously have network rx EOP and + ;; parport TX desc, we can swap buffers and start a new RX/TX + + move.d [r9 + (R_IRQ_READ2 - R_IRQ_READ0)], r0 + btstq DMA1EOPBIT, r0 ; check network rx + bpl noswap2 + btstq DMA4DESCBIT, r0 ; check parport tx + bpl noswap2 + nop + + ;; prepare to swap buffer ptrs (FP1b <-> TP2b) + + move.d [r4 = r7 + 8], r0; FN1b + move.d [r3 = r7 + 24], r2; TP2b + move.d r0, [r3] ; write to To Parport descriptor + move.d r2, [r4] ; write to From Network descriptor + + ;; clear the interrupts + + moveq IO_STATE(R_DMA_CH1_CLR_INTR, clr_eop, do) | \ + IO_STATE(R_DMA_CH1_CLR_INTR, clr_descr, do), r0 + move.b r0, [r1 + (R_DMA_CH1_CLR_INTR - R_DMA_CH0_FIRST)] + move.b r0, [r1 + (R_DMA_CH4_CLR_INTR - R_DMA_CH0_FIRST)] + + ;; copy received network length to outgoing parport length + + move.w [r7 + 12], r0 ; FNhlen + move.w r0, [r7 + 16] ; TP2desc + + ;; restart DMAs + + jsr startdmaFNTP +#if 0 +#ifdef CONFIG_ETRAX_ETHERNET_LPSLAVE_HAS_LEDS + ;; Light the LED signaling an incoming networkpacket + movu.b 0xFB, r0 + move.b r0, [R_PORT_PA_DATA] + move.d 0x00010000, r0 + move.d r0,[LEDCount] +#endif +#endif + +noswap2: +#ifdef CONFIG_ETRAX_ETHERNET_LPSLAVE_HAS_LEDS + + ;; Count down LED counter, and turn off the network LED if required + move.d [LEDCount], r0 + beq mainloop + nop + + subq 1, r0 + move.d r0, [LEDCount] + bne mainloop + nop + +#if defined(CONFIG_ETRAX_NETWORK_LED_ON_WHEN_LINK) + ;; Light the network LED , and start over the main loop + movu.b [LEDAmber], r0 +#elif defined(CONFIG_ETRAX_NETWORK_LED_ON_WHEN_ACTIVITY) + ;; Turn off the network LED, and start over the main loop + movu.b [LEDOff], r0 +#else +#error "Define either CONFIG_ETRAX_NETWORK_LED_ON_WHEN_LINK or CONFIG_ETRAX_NETWORK_LED_ON_WHEN_ACTIVITY" +#endif + move.b r0, [R_PORT_PA_DATA] +#endif + + ba mainloop + nop + + ;; --- some useful subroutines. + +handle_command: + ;; handle command. we also need to clear the PAR0 RX EOP IRQ, and + ;; restart the PAR0 dma. command is in R5, packet after cmd is in R0 + + moveq IO_STATE(R_DMA_CH3_CLR_INTR, clr_eop, do), r2 + move.b r2, [r1 + (R_DMA_CH3_CLR_INTR - R_DMA_CH0_FIRST)] + + cmpq HOST_CMD_SETMAC, r5 + bne no_setmac + nop + + ;; copy station address (6 bytes) from packet to hardware + + move.d [r0+], r2 + move.d R_NETWORK_SA_0, r3 + move.d r2, [r3] + move.w [r0], r2 + move.w r2, [r3 + 4] + +no_setmac: + move noswap1, SRP + ba startdmaFP + nop + + ;; start DMAs, from parport and to network + +startdmaFPTN: + + ;; start transmitting to the network (CH0) + + move.d TN4desc, r8 + move.d r8, [r1] ; TN4desc -> FIRST0 + move.b r6, [r1 + (R_DMA_CH0_CMD - R_DMA_CH0_FIRST)] ; start -> CMD0 + +startdmaFP: + + ;; start receiving from parport (CH3) + + move.d FP3desc, r8 + move.d r8, [r1 + (R_DMA_CH3_FIRST - R_DMA_CH0_FIRST)] ; FP3desc -> FIRST3 + move.b r6, [r1 + (R_DMA_CH3_CMD - R_DMA_CH0_FIRST)] ; start -> CMD3 + + ret + nop + + ;; start DMAs, from network and to parport + +startdmaFNTP: + + ;; start transmitting to the parport (CH4) + + move.d TP2desc, r8 + move.d r8, [r1 + (R_DMA_CH4_FIRST - R_DMA_CH0_FIRST)] ; TP2desc -> FIRST4 + move.b r6, [r1 + (R_DMA_CH4_CMD - R_DMA_CH0_FIRST)] ; start -> CMD4 + + ;; start receiving from network (CH1) (r7 already contains FN1desc) + + move.d r7, [r1 + (R_DMA_CH1_FIRST - R_DMA_CH0_FIRST)] ; FN1desc -> FIRST1 + move.b r6, [r1 + (R_DMA_CH1_CMD - R_DMA_CH0_FIRST)] ; start -> CMD1 + + ret + nop + + ;; --- DMA descriptors - each descriptor is 4 longwords (16 bytes) + ;; DONT MOVE THESE AROUND. Due to the as/ld "hole-in-the-head", + ;; we cant write stuff like (TP2b - TP2desc) but the offsets + ;; have to be hardcoded. + + .data + + ;; 0 from network +FN1desc: + .word BUFSIZE ; sw_len + .word 0x0001 ; ctrl, d_eol is only flag we need + .dword 0 ; next +FN1b: .dword buffers ; buffer 1 8 + .word 0 ; hw_len + .word 0 ; status + + ;; 16 to parport +TP2desc: + .word 2 ; sw_len, filled in by code + .word 0x0004 ; ctrl, d_wait because ecp cmd in next + .dword TP2desc2 ; next +TP2b: .dword buffers + BUFSIZE ; buffer 2 24 + .word 0 ; hw_len + .word 0 ; status + + ;; 32 to parport second descriptor, for the ECP command +TP2desc2: + .word 0x0001 ; sw_len, 1 byte (ecp command) + .word 0x0019 ; ctrl, d_ecp | d_eol | d_int + .dword 0 ; next + .dword TP2desc2 ; buffer, dont care + .word 0 ; hw_len + .word 0 ; status + + ;; 48 from parport +FP3desc: + .word BUFSIZE ; sw_len + .word 0x0001 ; ctrl, d_eol is only flag we need + .dword 0 ; next +FP3b: .dword buffers + BUFSIZE * 2 ; 56 buffer 3 +FPhlen: .word 0 ; 60 hw_len + .word 0 ; status + + ;; 64 to network +TN4desc: + .word 2 ; sw_len, filled in by code + .word 0x0007 ; ctrl, d_eop | d_eol | d_wait + .dword 0 ; next +TN4b: .dword buffers + BUFSIZE * 3 + 4 ; 72 buffer 4 (the +4 is to offset the anti-skipping) + .word 0 ; hw_len + .word 0 ; status + +#ifdef CONFIG_ETRAX_ETHERNET_LPSLAVE_HAS_LEDS +LEDCount: + .dword 0 +LEDOff: + .word 0xff +LEDGreen: + .word 0xfb +LEDRed: + .word 0xf7 +LEDAmber: + .word 0xf3 +LED: + .word 0xf7 +#endif + + ;; after the prog we put the buffers. not in the asm program, we just use + ;; the address generated + +buffers: + + ;; END diff -u --recursive --new-file v2.4.6/linux/arch/cris/drivers/lpslave/e100lpslave.h linux/arch/cris/drivers/lpslave/e100lpslave.h --- v2.4.6/linux/arch/cris/drivers/lpslave/e100lpslave.h Wed Dec 31 16:00:00 1969 +++ linux/arch/cris/drivers/lpslave/e100lpslave.h Wed Jul 4 11:50:39 2001 @@ -0,0 +1,2 @@ +#define HOST_CMD_SENDPACK 0 +#define HOST_CMD_SETMAC 1 diff -u --recursive --new-file v2.4.6/linux/arch/cris/drivers/lpslave/e100lpslaveld linux/arch/cris/drivers/lpslave/e100lpslaveld --- v2.4.6/linux/arch/cris/drivers/lpslave/e100lpslaveld Wed Dec 31 16:00:00 1969 +++ linux/arch/cris/drivers/lpslave/e100lpslaveld Wed Jul 4 11:50:39 2001 @@ -0,0 +1,22 @@ +MEMORY + { + cache : ORIGIN = 0x380000f0, + LENGTH = 784 + } + +SECTIONS +{ + .text : + { + *(.text) + } > cache + .data : + { + *(.data) + *(COMMON) + } > cache + .bss : + { + *(.bss) + } > cache +} diff -u --recursive --new-file v2.4.6/linux/arch/cris/drivers/lpslave/e100lpslavenet.c linux/arch/cris/drivers/lpslave/e100lpslavenet.c --- v2.4.6/linux/arch/cris/drivers/lpslave/e100lpslavenet.c Wed Dec 31 16:00:00 1969 +++ linux/arch/cris/drivers/lpslave/e100lpslavenet.c Wed Jul 4 11:50:39 2001 @@ -0,0 +1,1031 @@ +/* $Id: e100lpslavenet.c,v 1.2 2001/06/11 15:39:52 olof Exp $ + * + * e100lpslavenet.c: A network driver for the ETRAX 100LX slave controller. + * + * Copyright (c) 1998-2001 Axis Communications AB. + * + * The outline of this driver comes from skeleton.c. + * + * $Log: e100lpslavenet.c,v $ + * Revision 1.2 2001/06/11 15:39:52 olof + * Clean up and sync with ethernet.c rev 1.16. Increased reset time of slave. + * + * Revision 1.1 2001/06/06 08:56:26 olof + * Added support for slave Etrax defined by CONFIG_ETRAX_ETHERNET_LPSLAVE + * + */ + +#include <linux/config.h> + +#include <linux/module.h> + +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/delay.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/slab.h> +#include <linux/string.h> +#include <linux/spinlock.h> +#include <linux/errno.h> +#include <linux/init.h> + +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/skbuff.h> + +#include <asm/svinto.h> /* DMA and register descriptions */ +#include <asm/io.h> /* LED_* I/O functions */ +#include <asm/irq.h> +#include <asm/dma.h> +#include <asm/system.h> +#include <asm/bitops.h> + +#include "e100lpslave.h" + +/* #define ETHDEBUG */ +#define D(x) + +/* + * The name of the card. Is used for messages and in the requests for + * io regions, irqs and dma channels + */ + +static const char* cardname = "Etrax 100LX ethernet slave controller"; + +/* A default ethernet address. Highlevel SW will set the real one later */ + +static struct sockaddr default_mac = { + 0, + { 0x00, 0x40, 0x8C, 0xCD, 0x00, 0x00 } +}; + +/* Information that need to be kept for each board. */ +struct net_local { + struct net_device_stats stats; + + /* Tx control lock. This protects the transmit buffer ring + * state along with the "tx full" state of the driver. This + * means all netif_queue flow control actions are protected + * by this lock as well. + */ + spinlock_t lock; +}; + +/* Dma descriptors etc. */ + +#define RX_BUF_SIZE 32768 +#define ETHER_HEAD_LEN 14 + +#define PAR0_ECP_IRQ_NBR 4 + +#define RX_DESC_BUF_SIZE 256 +#define NBR_OF_RX_DESC (RX_BUF_SIZE / \ + RX_DESC_BUF_SIZE) + +/* Size of slave etrax boot image */ +#define ETRAX_PAR_BOOT_LENGTH 784 + +static etrax_dma_descr *myNextRxDesc; /* Points to the next descriptor to + to be processed */ +static etrax_dma_descr *myLastRxDesc; /* The last processed descriptor */ +static etrax_dma_descr *myPrevRxDesc; /* The descriptor right before myNextRxDesc */ + +static unsigned char RxBuf[RX_BUF_SIZE]; + +static etrax_dma_descr RxDescList[NBR_OF_RX_DESC] __attribute__ ((aligned(4))); +static etrax_dma_descr TxDescList[3] __attribute__ ((aligned(4))); + /* host command, data, bogus ECP command */ + +static struct sk_buff *tx_skb; + +/* Index to functions, as function prototypes. */ + +static int etrax_ethernet_lpslave_init(struct net_device *dev); + +static int e100_open(struct net_device *dev); +static int e100_set_mac_address(struct net_device *dev, void *addr); +static int e100_send_packet(struct sk_buff *skb, struct net_device *dev); +static void e100rx_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static void e100tx_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static void ecp_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static void e100_rx(struct net_device *dev); +static int e100_close(struct net_device *dev); +static struct net_device_stats *e100_get_stats(struct net_device *dev); +static void set_multicast_list(struct net_device *dev); +static void e100_hardware_send_packet(unsigned long hostcmd, char *buf, int length); +static void update_rx_stats(struct net_device_stats *); +static void update_tx_stats(struct net_device_stats *); +static void e100_reset_tranceiver(void); + +static void boot_slave(unsigned char *code); + +#ifdef ETHDEBUG +static void dump_parport_status(void); +#endif + +#define tx_done(dev) (*R_DMA_CH0_CMD == 0) + +static unsigned long host_command; +extern unsigned char e100lpslaveprog; + +/* + * This driver uses PAR0 to recevice data from slave ETRAX and PAR1 to boot + * and send data to slave ETRAX. + * Used ETRAX100 DMAchannels with corresponding IRQ: + * PAR0 RX : DMA3 - IRQ 19 + * PAR1 TX : DMA4 - IRQ 20 + * IRQ 4 is used to detect ECP commands from slave ETRAX + * + * NOTE! PAR0 and PAR1 shares DMA and IRQ numbers with SER2 and SER3 + */ + + +/* + * Check for a network adaptor of this type, and return '0' if one exists. + * If dev->base_addr == 0, probe all likely locations. + * If dev->base_addr == 1, always return failure. + * If dev->base_addr == 2, allocate space for the device and return success + * (detachable devices only). + */ +static int __init +etrax_ethernet_lpslave_init(struct net_device *dev) +{ + int i; + int anOffset = 0; + + printk("Etrax/100 lpslave ethernet driver v0.3, (c) 1999 Axis Communications AB\n"); + + dev->base_addr = 2; + + printk("%s initialized\n", dev->name); + + /* make Linux aware of the new hardware */ + + if (!dev) { + printk(KERN_WARNING "%s: dev == NULL. Should this happen?\n", + cardname); + dev = init_etherdev(dev, sizeof(struct net_local)); + if (!dev) + panic("init_etherdev failed\n"); + } + + /* setup generic handlers and stuff in the dev struct */ + + ether_setup(dev); + + /* make room for the local structure containing stats etc */ + + dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL); + if (dev->priv == NULL) + return -ENOMEM; + memset(dev->priv, 0, sizeof(struct net_local)); + + /* now setup our etrax specific stuff */ + + dev->irq = DMA3_RX_IRQ_NBR; /* we really use DMATX as well... */ + dev->dma = PAR0_RX_DMA_NBR; + + /* fill in our handlers so the network layer can talk to us in the future */ + + dev->open = e100_open; + dev->hard_start_xmit = e100_send_packet; + dev->stop = e100_close; + dev->get_stats = e100_get_stats; + dev->set_multicast_list = set_multicast_list; + dev->set_mac_address = e100_set_mac_address; + + /* set the default MAC address */ + + e100_set_mac_address(dev, &default_mac); + + /* Initialise the list of Etrax DMA-descriptors */ + + /* Initialise receive descriptors */ + + for(i = 0; i < (NBR_OF_RX_DESC - 1); i++) { + RxDescList[i].ctrl = 0; + RxDescList[i].sw_len = RX_DESC_BUF_SIZE; + RxDescList[i].next = virt_to_phys(&RxDescList[i + 1]); + RxDescList[i].buf = virt_to_phys(RxBuf + anOffset); + RxDescList[i].status = 0; + RxDescList[i].hw_len = 0; + anOffset += RX_DESC_BUF_SIZE; + } + + RxDescList[i].ctrl = d_eol; + RxDescList[i].sw_len = RX_DESC_BUF_SIZE; + RxDescList[i].next = virt_to_phys(&RxDescList[0]); + RxDescList[i].buf = virt_to_phys(RxBuf + anOffset); + RxDescList[i].status = 0; + RxDescList[i].hw_len = 0; + + /* Initialise initial pointers */ + + myNextRxDesc = &RxDescList[0]; + myLastRxDesc = &RxDescList[NBR_OF_RX_DESC - 1]; + myPrevRxDesc = &RxDescList[NBR_OF_RX_DESC - 1]; + + /* setup some TX descriptor data */ + + TxDescList[0].sw_len = 4; + TxDescList[0].ctrl = 0; + TxDescList[0].buf = virt_to_phys(&host_command); + TxDescList[0].next = virt_to_phys(&TxDescList[1]); + + return 0; +} + +/* set MAC address of the interface. called from the core after a + * SIOCSIFADDR ioctl, and from the bootup above. + */ + +static int +e100_set_mac_address(struct net_device *dev, void *p) +{ + struct sockaddr *addr = p; + int i; + + /* remember it */ + + memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); + + /* Write it to the hardware. + * Note the way the address is wrapped: + * *R_NETWORK_SA_0 = a0_0 | (a0_1 << 8) | (a0_2 << 16) | (a0_3 << 24); + * *R_NETWORK_SA_1 = a0_4 | (a0_5 << 8); + */ + + tx_skb = 0; + e100_hardware_send_packet(HOST_CMD_SETMAC, dev->dev_addr, 6); + + /* show it in the log as well */ + + printk("%s: changed MAC to ", dev->name); + + for (i = 0; i < 5; i++) + printk("%02X:", dev->dev_addr[i]); + + printk("%02X\n", dev->dev_addr[i]); + + return 0; +} + +/* + * 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 +e100_open(struct net_device *dev) +{ + unsigned long flags; + + /* configure the PAR0 (RX) and PAR1 (TX) ports + * + * perror is nAckReverse, which must be 1 at the TX side, + * and 0 at the RX side + * + * select is XFlag, which must be 1 at both sides + */ +#ifdef ETHDEBUG + printk("Setting up PAR ports\n"); +#endif + *R_PAR0_CONFIG = + /* We do not have an external buffer, don't care */ + IO_STATE(R_PAR0_CONFIG, ioe, noninv) | + /* Not connected, don't care */ + IO_STATE(R_PAR0_CONFIG, iseli, noninv) | + /* iautofd is not inverted, noninv */ + IO_STATE(R_PAR0_CONFIG, iautofd, noninv) | + /* Not used in reverse direction, don't care */ + IO_STATE(R_PAR0_CONFIG, istrb, noninv) | + /* Not connected, don't care / + IO_STATE(R_PAR0_CONFIG, iinit, noninv) | + /* perror is GND and reverse wants 0, noninv */ + IO_STATE(R_PAR0_CONFIG, iperr, noninv) | + /* ack is not inverted, noninv */ + IO_STATE(R_PAR0_CONFIG, iack, noninv) | + /* busy is not inverted, noninv */ + IO_STATE(R_PAR0_CONFIG, ibusy, noninv) | + /* fault is not inverted, noninv */ + IO_STATE(R_PAR0_CONFIG, ifault, noninv) | + /* select is Vcc and we want 1, noninv */ + IO_STATE(R_PAR0_CONFIG, isel, noninv) | + /* We will run dma, enable */ + IO_STATE(R_PAR0_CONFIG, dma, enable) | + /* No run length encoding, disable */ + IO_STATE(R_PAR0_CONFIG, rle_in, disable) | + /* No run length encoding, disable */ + IO_STATE(R_PAR0_CONFIG, rle_out, disable) | + /* Enable parallel port */ + IO_STATE(R_PAR0_CONFIG, enable, on) | + /* Force mode regardless of pin status */ + IO_STATE(R_PAR0_CONFIG, force, on) | + /* We want ECP forward mode since PAR0 is RX */ + IO_STATE(R_PAR0_CONFIG, mode, ecp_rev); + + *R_PAR1_CONFIG = + /* We do not have an external buffer, don't care */ + IO_STATE(R_PAR1_CONFIG, ioe, noninv) | + + /* Not connected, don't care */ + IO_STATE(R_PAR1_CONFIG, iseli, noninv) | + + /* HostAck must indicate data cycle, noninv */ + IO_STATE(R_PAR1_CONFIG, iautofd, noninv) | + + /* HostClk has no external inverter, noninv */ + IO_STATE(R_PAR1_CONFIG, istrb, noninv) | + + /* Not connected, don't care */ + IO_STATE(R_PAR1_CONFIG, iinit, noninv) | + + /* nAckReverse must be 1 in forward mode but is grounded, inv */ + IO_STATE(R_PAR1_CONFIG, iperr, inv) | + + /* PeriphClk must be 1 in forward mode, noninv */ + IO_STATE(R_PAR1_CONFIG, iack, noninv) | + + /* PeriphAck has no external inverter, noninv */ + IO_STATE(R_PAR1_CONFIG, ibusy, noninv) | + + /* nPerihpRequest has no external inverter, noniv */ + IO_STATE(R_PAR1_CONFIG, ifault, noninv) | + + /* Select is VCC and we want 1, noninv */ + IO_STATE(R_PAR1_CONFIG, isel, noninv) | + + /* No EPP mode, disable */ + IO_STATE(R_PAR1_CONFIG, ext_mode, disable) | + + /* We will run dma, enable */ + IO_STATE(R_PAR1_CONFIG, dma, enable) | + + /* No run length encoding, disable */ + IO_STATE(R_PAR1_CONFIG, rle_in, disable) | + + /* No run length encoding, disable */ + IO_STATE(R_PAR1_CONFIG, rle_out, disable) | + + /* Enable parallel port */ + IO_STATE(R_PAR1_CONFIG, enable, on) | + + /* Force mode regardless of pin status */ + IO_STATE(R_PAR1_CONFIG, force, on) | + + /* We want ECP forward mode since PAR1 is TX */ + IO_STATE(R_PAR1_CONFIG, mode, ecp_fwd); + + /* Setup time of value * 160 + 20 ns == 180 ns below */ + *R_PAR1_DELAY = IO_FIELD(R_PAR1_DELAY, setup, 1); + + *R_PAR1_CTRL = 0; + + while ((((*R_PAR1_STATUS)&0xE000) >> 13) != 5); /* Wait for ECP_FWD mode */ +#ifdef ETHDEBUG + dump_parport_status(); +#endif + + /* make sure ECP irq is acked when we enable it below */ + + (void)*R_PAR0_STATUS_DATA; + (void)*R_PAR1_STATUS_DATA; + + /* Reset and wait for the DMA channels */ + + RESET_DMA(4); /* PAR1_TX_DMA_NBR */ + RESET_DMA(3); /* PAR0_RX_DMA_NBR */ + WAIT_DMA(4); + WAIT_DMA(3); + + /* boot the slave Etrax, by sending code on PAR1. + * do this before we start up the IRQ handlers and stuff, + * beacuse we simply poll for completion in boot_slave. + */ + + boot_slave(&e100lpslaveprog); + + /* allocate the irq corresponding to the receiving DMA */ + + if (request_irq(DMA3_RX_IRQ_NBR, e100rx_interrupt, 0, + cardname, (void *)dev)) { + printk("Failed to allocate DMA3_RX_IRQ_NBR\n"); + goto grace_exit; + } + + /* allocate the irq corresponding to the transmitting DMA */ + + if (request_irq(DMA4_TX_IRQ_NBR, e100tx_interrupt, 0, + cardname, (void *)dev)) { + printk("Failed to allocate DMA4_TX_IRQ_NBR\n"); + goto grace_exit; + } + + /* allocate the irq used for detecting ECP commands on the RX port (PAR0) */ + + if (request_irq(PAR0_ECP_IRQ_NBR, ecp_interrupt, 0, + cardname, (void *)dev)) { + printk("Failed to allocate PAR0_ECP_IRQ_NBR\n"); + grace_exit: + free_irq(PAR0_ECP_IRQ_NBR, (void *)dev); + free_irq(DMA4_TX_IRQ_NBR, (void *)dev); + free_irq(DMA3_RX_IRQ_NBR, (void *)dev); + + return -EAGAIN; + } + +#if 0 + /* We are not allocating DMA since DMA4 is reserved for 'cascading' + * and will always fail with the current dma.c + */ + + /* + * Always allocate the DMA channels after the IRQ, + * and clean up on failure. + */ + + if(request_dma(PAR0_RX_DMA_NBR, cardname)) { + printk("Failed to allocate PAR0_RX_DMA_NBR\n"); + goto grace_exit; + } + + if(request_dma(PAR1_TX_DMA_NBR, cardname)) { + printk("Failed to allocate PAR1_TX_DMA_NBR\n"); + grace_exit: + /* this will cause some 'trying to free free irq' but what the heck... */ + + free_dma(PAR1_TX_DMA_NBR); + free_dma(PAR0_RX_DMA_NBR); + free_irq(PAR0_ECP_IRQ_NBR, (void *)dev); + free_irq(DMA4_TX_IRQ_NBR, (void *)dev); + free_irq(DMA3_RX_IRQ_NBR, (void *)dev); + + return -EAGAIN; + } +#endif + +#ifdef ETHDEBUG + printk("Par port IRQ and DMA allocated\n"); +#endif + save_flags(flags); + cli(); + + /* enable the irq's for PAR0/1 DMA */ + + *R_IRQ_MASK2_SET = + IO_STATE(R_IRQ_MASK2_SET, dma3_eop, set) | + IO_STATE(R_IRQ_MASK2_SET, dma4_descr, set); + + *R_IRQ_MASK0_SET = + IO_STATE(R_IRQ_MASK0_SET, par0_ecp_cmd, set); + + tx_skb = 0; + + /* make sure the irqs are cleared */ + + *R_DMA_CH3_CLR_INTR = IO_STATE(R_DMA_CH3_CLR_INTR, clr_eop, do); + *R_DMA_CH4_CLR_INTR = IO_STATE(R_DMA_CH4_CLR_INTR, clr_descr, do); + + /* Write the MAC address to the slave HW */ + udelay(5000); + e100_hardware_send_packet(HOST_CMD_SETMAC, dev->dev_addr, 6); + + /* make sure the rec and transmit error counters are cleared */ + + (void)*R_REC_COUNTERS; /* dummy read */ + (void)*R_TR_COUNTERS; /* dummy read */ + + /* start the receiving DMA channel so we can receive packets from now on */ + + *R_DMA_CH3_FIRST = virt_to_phys(myNextRxDesc); + *R_DMA_CH3_CMD = IO_STATE(R_DMA_CH3_CMD, cmd, start); + + restore_flags(flags); + + /* We are now ready to accept transmit requeusts from + * the queueing layer of the networking. + */ +#ifdef ETHDEBUG + printk("Starting slave network transmit queue\n"); +#endif + netif_start_queue(dev); + + return 0; +} + +static void +e100_reset_tranceiver(void) +{ + /* To do: Reboot and setup slave Etrax */ +} + +/* Called by upper layers if they decide it took too long to complete + * sending a packet - we need to reset and stuff. + */ + +static void +e100_tx_timeout(struct net_device *dev) +{ + struct net_local *np = (struct net_local *)dev->priv; + + printk(KERN_WARNING "%s: transmit timed out, %s?\n", dev->name, + tx_done(dev) ? "IRQ problem" : "network cable problem"); + + /* remember we got an error */ + + np->stats.tx_errors++; + + /* reset the TX DMA in case it has hung on something */ + + RESET_DMA(4); + WAIT_DMA(4); + + /* Reset the tranceiver. */ + + e100_reset_tranceiver(); + + /* and get rid of the packet that never got an interrupt */ + + dev_kfree_skb(tx_skb); + tx_skb = 0; + + /* tell the upper layers we're ok again */ + + netif_wake_queue(dev); +} + + +/* This will only be invoked if the driver is _not_ in XOFF state. + * What this means is that we need not check it, and that this + * invariant will hold if we make sure that the netif_*_queue() + * calls are done at the proper times. + */ + +static int +e100_send_packet(struct sk_buff *skb, struct net_device *dev) +{ + struct net_local *np = (struct net_local *)dev->priv; + int length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; + unsigned char *buf = skb->data; + +#ifdef ETHDEBUG + unsigned char *temp_data_ptr = buf; + int i; + + printk("Sending a packet of length %d:\n", length); + /* dump the first bytes in the packet */ + for(i = 0; i < 8; i++) { + printk("%d: %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x\n", i * 8, + temp_data_ptr[0],temp_data_ptr[1],temp_data_ptr[2], + temp_data_ptr[3],temp_data_ptr[4],temp_data_ptr[5], + temp_data_ptr[6],temp_data_ptr[7]); + temp_data_ptr += 8; + } +#endif + spin_lock_irq(&np->lock); /* protect from tx_interrupt */ + + tx_skb = skb; /* remember it so we can free it in the tx irq handler later */ + dev->trans_start = jiffies; + + e100_hardware_send_packet(HOST_CMD_SENDPACK, buf, length); + + /* this simple TX driver has only one send-descriptor so we're full + * directly. If this had a send-ring instead, we would only do this if + * the ring got full. + */ + + netif_stop_queue(dev); + + spin_unlock_irq(&np->lock); + + return 0; +} + +/* + * The typical workload of the driver: + * Handle the network interface interrupts. + */ + +static void +e100rx_interrupt(int irq, void *dev_id, struct pt_regs * regs) +{ + struct net_device *dev = (struct net_device *)dev_id; + unsigned long irqbits = *R_IRQ_MASK2_RD; + + if(irqbits & IO_STATE(R_IRQ_MASK2_RD, dma3_eop, active)) { + + /* acknowledge the eop interrupt */ + + *R_DMA_CH3_CLR_INTR = IO_STATE(R_DMA_CH3_CLR_INTR, clr_eop, do); + + /* check if one or more complete packets were indeed received */ + + while(*R_DMA_CH3_FIRST != virt_to_phys(myNextRxDesc)) { + /* Take out the buffer and give it to the OS, then + * allocate a new buffer to put a packet in. + */ + e100_rx(dev); + ((struct net_local *)dev->priv)->stats.rx_packets++; + /* restart/continue on the channel, for safety */ + *R_DMA_CH3_CMD = IO_STATE(R_DMA_CH3_CMD, cmd, restart); + /* clear dma channel 3 eop/descr irq bits */ + *R_DMA_CH3_CLR_INTR = + IO_STATE(R_DMA_CH3_CLR_INTR, clr_eop, do) | + IO_STATE(R_DMA_CH3_CLR_INTR, clr_descr, do); + + /* now, we might have gotten another packet + so we have to loop back and check if so */ + } + } +} + +/* the transmit dma channel interrupt + * + * this is supposed to free the skbuff which was pending during transmission, + * and inform the kernel that we can send one more buffer + */ + +static void +e100tx_interrupt(int irq, void *dev_id, struct pt_regs * regs) +{ + struct net_device *dev = (struct net_device *)dev_id; + unsigned long irqbits = *R_IRQ_MASK2_RD; + struct net_local *np = (struct net_local *)dev->priv; + +#ifdef ETHDEBUG + printk("We got tx interrupt\n"); +#endif + /* check for a dma4_eop interrupt */ + if(irqbits & IO_STATE(R_IRQ_MASK2_RD, dma4_descr, active)) { + /* This protects us from concurrent execution of + * our dev->hard_start_xmit function above. + */ + + spin_lock(&np->lock); + + /* acknowledge the eop interrupt */ + + *R_DMA_CH4_CLR_INTR = IO_STATE(R_DMA_CH4_CLR_INTR, clr_descr, do); + + /* skip *R_DMA_CH4_FIRST == 0 test since we use d_wait... */ + if(tx_skb) { + + np->stats.tx_bytes += tx_skb->len; + np->stats.tx_packets++; + /* dma is ready with the transmission of the data in tx_skb, so now we can release the skb memory */ + dev_kfree_skb_irq(tx_skb); + tx_skb = 0; + netif_wake_queue(dev); + } else { + printk(KERN_WARNING "%s: tx weird interrupt\n", + cardname); + } + + spin_unlock(&np->lock); + } +} + +static void +ecp_interrupt(int irq, void *dev_id, struct pt_regs * regs) +{ + struct net_device *dev = (struct net_device *)dev_id; + struct net_local *lp = (struct net_local *)dev->priv; + unsigned long temp, irqbits = *R_IRQ_MASK0_RD; + + /* check for ecp irq */ + if(irqbits & IO_MASK(R_IRQ_MASK0_RD, par0_ecp_cmd)) { + /* acknowledge by reading the bit */ + temp = *R_PAR0_STATUS_DATA; + /* force an EOP on the incoming channel, so we'll get an rx interrupt */ + *R_SET_EOP = IO_STATE(R_SET_EOP, ch3_eop, set); + } +} + +/* We have a good packet(s), get it/them out of the buffers. */ +static void +e100_rx(struct net_device *dev) +{ + struct sk_buff *skb; + int length=0; + int i; + struct net_local *np = (struct net_local *)dev->priv; + struct etrax_dma_descr *mySaveRxDesc = myNextRxDesc; + unsigned char *skb_data_ptr; + + /* If the packet is broken down in many small packages then merge + * count how much space we will need to alloc with skb_alloc() for + * it to fit. + */ + + while (!(myNextRxDesc->status & d_eop)) { + length += myNextRxDesc->sw_len; /* use sw_len for the first descs */ + myNextRxDesc->status = 0; + myNextRxDesc = phys_to_virt(myNextRxDesc->next); + } + + length += myNextRxDesc->hw_len; /* use hw_len for the last descr */ + +#ifdef ETHDEBUG + printk("Got a packet of length %d:\n", length); + /* dump the first bytes in the packet */ + skb_data_ptr = (unsigned char *)phys_to_virt(mySaveRxDesc->buf); + for(i = 0; i < 8; i++) { + printk("%d: %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x\n", i * 8, + skb_data_ptr[0],skb_data_ptr[1],skb_data_ptr[2],skb_data_ptr[3], + skb_data_ptr[4],skb_data_ptr[5],skb_data_ptr[6],skb_data_ptr[7]); + skb_data_ptr += 8; + } +#endif + + skb = dev_alloc_skb(length - ETHER_HEAD_LEN); + if (!skb) { + np->stats.rx_errors++; + printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n", + dev->name); + return; + } + + skb_put(skb, length - ETHER_HEAD_LEN); /* allocate room for the packet body */ + skb_data_ptr = skb_push(skb, ETHER_HEAD_LEN); /* allocate room for the header */ + +#ifdef ETHDEBUG + printk("head = 0x%x, data = 0x%x, tail = 0x%x, end = 0x%x\n", + skb->head, skb->data, skb->tail, skb->end); + printk("copying packet to 0x%x.\n", skb_data_ptr); +#endif + + /* this loop can be made using max two memcpy's if optimized */ + + while(mySaveRxDesc != myNextRxDesc) { + memcpy(skb_data_ptr, phys_to_virt(mySaveRxDesc->buf), + mySaveRxDesc->sw_len); + skb_data_ptr += mySaveRxDesc->sw_len; + mySaveRxDesc = phys_to_virt(mySaveRxDesc->next); + } + + memcpy(skb_data_ptr, phys_to_virt(mySaveRxDesc->buf), + mySaveRxDesc->hw_len); + + skb->dev = dev; + skb->protocol = eth_type_trans(skb, dev); + + /* Send the packet to the upper layers */ + + netif_rx(skb); + + /* Prepare for next packet */ + + myNextRxDesc->status = 0; + myPrevRxDesc = myNextRxDesc; + myNextRxDesc = phys_to_virt(myNextRxDesc->next); + + myPrevRxDesc->ctrl |= d_eol; + myLastRxDesc->ctrl &= ~d_eol; + myLastRxDesc = myPrevRxDesc; + + return; +} + +/* The inverse routine to net_open(). */ +static int +e100_close(struct net_device *dev) +{ + struct net_local *np = (struct net_local *)dev->priv; + + printk("Closing %s.\n", dev->name); + + netif_stop_queue(dev); + + *R_IRQ_MASK0_CLR = IO_STATE(R_IRQ_MASK0_CLR, par0_ecp_cmd, clr); + + *R_IRQ_MASK2_CLR = + IO_STATE(R_IRQ_MASK2_CLR, dma3_eop, clr) | + IO_STATE(R_IRQ_MASK2_CLR, dma4_descr, clr); + + /* Stop the receiver and the transmitter */ + + RESET_DMA(3); + RESET_DMA(4); + + /* Flush the Tx and disable Rx here. */ + + free_irq(DMA3_RX_IRQ_NBR, (void *)dev); + free_irq(DMA4_TX_IRQ_NBR, (void *)dev); + free_irq(PAR0_ECP_IRQ_NBR, (void *)dev); + + free_dma(PAR1_TX_DMA_NBR); + free_dma(PAR0_RX_DMA_NBR); + + /* Update the statistics here. */ + + update_rx_stats(&np->stats); + update_tx_stats(&np->stats); + + return 0; +} + +static void +update_rx_stats(struct net_device_stats *es) +{ + unsigned long r = *R_REC_COUNTERS; + /* update stats relevant to reception errors */ + es->rx_fifo_errors += r >> 24; /* fifo overrun */ + es->rx_crc_errors += r & 0xff; /* crc error */ + es->rx_frame_errors += (r >> 8) & 0xff; /* alignment error */ + es->rx_length_errors += (r >> 16) & 0xff; /* oversized frames */ +} + +static void +update_tx_stats(struct net_device_stats *es) +{ + unsigned long r = *R_TR_COUNTERS; + /* update stats relevant to transmission errors */ + es->collisions += (r & 0xff) + ((r >> 8) & 0xff); /* single_col + multiple_col */ + es->tx_errors += (r >> 24) & 0xff; /* deferred transmit frames */ +} + +/* + * Get the current statistics. + * This may be called with the card open or closed. + */ +static struct net_device_stats * +e100_get_stats(struct net_device *dev) +{ + struct net_local *lp = (struct net_local *)dev->priv; + + update_rx_stats(&lp->stats); + update_tx_stats(&lp->stats); + + return &lp->stats; +} + +/* + * 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 +set_multicast_list(struct net_device *dev) +{ + /* To do */ +} + +void +e100_hardware_send_packet(unsigned long hostcmd, char *buf, int length) +{ + static char bogus_ecp[] = { 42, 42 }; + int i; + + +#ifdef ETHDEBUG + printk("e100 send pack, buf 0x%x len %d\n", buf, length); +#endif + + host_command = hostcmd; + + /* Configure the tx dma descriptor. Desc 0 is already configured.*/ + + TxDescList[1].sw_len = length; + /* bug workaround - etrax100 needs d_wait on the descriptor _before_ + * a descriptor containing an ECP command + */ + TxDescList[1].ctrl = d_wait; + TxDescList[1].buf = virt_to_phys(buf); + TxDescList[1].next = virt_to_phys(&TxDescList[2]); + + /* append the ecp dummy descriptor - its only purpose is to + * make the receiver generate an irq due to the ecp command + * so the receiver knows where packets end + */ + + TxDescList[2].sw_len = 1; + TxDescList[2].ctrl = d_ecp | d_eol | d_int; + TxDescList[2].buf = virt_to_phys(bogus_ecp); + + + /* setup the dma channel and start it */ + + *R_DMA_CH4_FIRST = virt_to_phys(TxDescList); + *R_DMA_CH4_CMD = IO_STATE(R_DMA_CH4_CMD, cmd, start); + +#ifdef ETHDEBUG + printk("done\n"); +#endif +} + +/* send a chunk of code to the slave chip to boot it. */ + +static void +boot_slave(unsigned char *code) +{ + int i; + +#ifdef ETHDEBUG + printk(" booting slave ETRAX...\n"); +#endif + *R_PORT_PB_DATA = 0x7F; /* Reset slave */ + udelay(15); /* Time enough to reset WAN tranciever */ + *R_PORT_PB_DATA = 0xFF; /* Reset slave */ + + /* configure the tx dma data descriptor */ + + TxDescList[1].sw_len = ETRAX_PAR_BOOT_LENGTH; + TxDescList[1].ctrl = d_eol | d_int; + + TxDescList[1].buf = virt_to_phys(code); + /*TxDescList[1].buf = code;*/ + TxDescList[1].next = 0; + + /* setup the dma channel and start it */ + *R_DMA_CH4_FIRST = virt_to_phys(&TxDescList[1]); + *R_DMA_CH4_CMD = IO_STATE(R_DMA_CH4_CMD, cmd, start); + + /* wait for completion */ + while(!(*R_IRQ_READ2 & IO_MASK(R_IRQ_READ2, dma4_descr))); + + /* ack the irq */ + + *R_DMA_CH4_CLR_INTR = IO_STATE(R_DMA_CH4_CLR_INTR, clr_descr, do); + +#if 0 + /* manual transfer of boot code - requires dma turned off */ + for (i=0; i<ETRAX_PAR_BOOT_LENGTH; i++) + { + printk(" sending byte: %u value: %x\n",i,code[i]); + while (((*R_PAR1_STATUS)&0x02) == 0); /* Wait while tr_rdy is busy*/ + *R_PAR1_CTRL_DATA = code[i]; + } +#endif + +#ifdef ETHDEBUG + printk(" done\n"); +#endif +} + +#ifdef ETHDEBUG +/* debug code to check the current status of PAR1 */ +static void +dump_parport_status(void) +{ + unsigned long temp; + + printk("Parport1 status:\n"); + + temp = (*R_PAR1_STATUS)&0xE000; + temp = temp >> 13; + printk("Reg mode: %u (ecp_fwd(5), ecp_rev(6))\n", temp); + + temp = (*R_PAR1_STATUS)&0x1000; + temp = temp >> 12; + printk("Reg perr: %u (ecp_rev(0))\n", temp); + + temp = (*R_PAR1_STATUS)&0x0800; + temp = temp >> 11; + printk("Reg ack: %u (inactive (1), active (0))\n", temp); + + temp = (*R_PAR1_STATUS)&0x0400; + temp = temp >> 10; + printk("Reg busy: %u (inactive (0), active (1))\n", temp); + + temp = (*R_PAR1_STATUS)&0x0200; + temp = temp >> 9; + printk("Reg fault: %u (inactive (1), active (0))\n", temp); + + temp = (*R_PAR1_STATUS)&0x0100; + temp = temp >> 8; + printk("Reg sel: %u (inactive (0), active (1), xflag(1))\n", temp); + + temp = (*R_PAR1_STATUS)&0x02; + temp = temp >> 1; + printk("Reg tr_rdy: %u (busy (0), ready (1))\n", temp); + +} +#endif /* ETHDEBUG */ + +static struct net_device dev_etrax_slave_ethernet; + +static int +etrax_init_module(void) +{ + struct net_device *d = &dev_etrax_slave_ethernet; + + d->init = etrax_ethernet_lpslave_init; + + if(register_netdev(d) == 0) + return 0; + else + return -ENODEV; +} + +module_init(etrax_init_module); diff -u --recursive --new-file v2.4.6/linux/arch/cris/drivers/parport.c linux/arch/cris/drivers/parport.c --- v2.4.6/linux/arch/cris/drivers/parport.c Tue May 1 16:04:56 2001 +++ linux/arch/cris/drivers/parport.c Wed Jul 4 11:50:39 2001 @@ -1,4 +1,4 @@ -/* $Id: parport.c,v 1.4 2001/04/06 13:04:02 hugo Exp $ +/* $Id: parport.c,v 1.5 2001/05/09 12:38:42 johana Exp $ * * Elinux parallel port driver * NOTE! @@ -501,8 +501,8 @@ #ifdef CONFIG_ETRAX_PARALLEL_PORT0 #ifdef CONFIG_ETRAX_PAR0_DMA - RESET_DMA(2); - WAIT_DMA(2); + RESET_DMA(PAR0_TX_DMA_NBR); + WAIT_DMA(PAR0_TX_DMA_NBR); #ifdef CONFIG_ETRAX_SERIAL_PORT2 printk(" Warning - DMA clash with ser2!\n"); #endif /* SERIAL_PORT2 */ @@ -511,8 +511,8 @@ #ifdef CONFIG_ETRAX_PARALLEL_PORT1 #ifdef CONFIG_ETRAX_PAR1_DMA - RESET_DMA(4); - WAIT_DMA(4); + RESET_DMA(PAR1_TX_DMA_NBR); + WAIT_DMA(PAR1_TX_DMA_NBR); #ifdef CONFIG_ETRAX_SERIAL_PORT3 printk(" Warning - DMA clash with ser3!\n"); #endif /* SERIAL_PORT3 */ diff -u --recursive --new-file v2.4.6/linux/arch/cris/drivers/serial.c linux/arch/cris/drivers/serial.c --- v2.4.6/linux/arch/cris/drivers/serial.c Tue May 1 16:04:56 2001 +++ linux/arch/cris/drivers/serial.c Wed Jul 4 11:50:39 2001 @@ -1,4 +1,4 @@ -/* $Id: serial.c,v 1.12 2001/04/19 12:23:07 bjornw Exp $ +/* $Id: serial.c,v 1.13 2001/05/09 12:40:31 johana Exp $ * * Serial port driver for the ETRAX 100LX chip * @@ -7,6 +7,9 @@ * Many, many authors. Based once upon a time on serial.c for 16x50. * * $Log: serial.c,v $ + * Revision 1.13 2001/05/09 12:40:31 johana + * Use DMA_NBR and IRQ_NBR defines from dma.h and irq.h + * * Revision 1.12 2001/04/19 12:23:07 bjornw * CONFIG_RS485 -> CONFIG_ETRAX_RS485 * @@ -199,7 +202,7 @@ * */ -static char *serial_version = "$Revision: 1.12 $"; +static char *serial_version = "$Revision: 1.13 $"; #include <linux/config.h> #include <linux/version.h> @@ -495,7 +498,6 @@ #endif #ifdef CONFIG_ETRAX_SERIAL_FLUSH_DMA_FAST -#define TIMER1_IRQ_NBR 3 /* clock select 10 for timer 1 gives 230400 Hz */ #define FASTTIMER_SELECT (10) @@ -3049,32 +3051,32 @@ #ifndef CONFIG_SVINTO_SIM /* Not needed in simulator. May only complicate stuff. */ /* hook the irq's for DMA channel 6 and 7, serial output and input, and some more... */ - if(request_irq(22, tr_interrupt, SA_INTERRUPT, "serial 0 dma tr", NULL)) + if(request_irq(SER0_DMA_TX_IRQ_NBR, tr_interrupt, SA_INTERRUPT, "serial 0 dma tr", NULL)) panic("irq22"); - if(request_irq(23, rec_interrupt, SA_INTERRUPT, "serial 0 dma rec", NULL)) + if(request_irq(SER0_DMA_RX_IRQ_NBR, rec_interrupt, SA_INTERRUPT, "serial 0 dma rec", NULL)) panic("irq23"); #ifdef SERIAL_HANDLE_EARLY_ERRORS - if(request_irq(8, ser_interrupt, SA_INTERRUPT, "serial ", NULL)) + if(request_irq(SERIAL_IRQ_NBR, ser_interrupt, SA_INTERRUPT, "serial ", NULL)) panic("irq8"); #endif #ifdef CONFIG_ETRAX_SERIAL_PORT1 - if(request_irq(24, tr_interrupt, SA_INTERRUPT, "serial 1 dma tr", NULL)) + if(request_irq(SER1_DMA_TX_IRQ_NBR, tr_interrupt, SA_INTERRUPT, "serial 1 dma tr", NULL)) panic("irq24"); - if(request_irq(25, rec_interrupt, SA_INTERRUPT, "serial 1 dma rec", NULL)) + if(request_irq(SER1_DMA_RX_IRQ_NBR, rec_interrupt, SA_INTERRUPT, "serial 1 dma rec", NULL)) panic("irq25"); #endif #ifdef CONFIG_ETRAX_SERIAL_PORT2 /* DMA Shared with par0 (and SCSI0 and ATA) */ - if(request_irq(18, tr_interrupt, SA_SHIRQ, "serial 2 dma tr", NULL)) + if(request_irq(SER2_DMA_TX_IRQ_NBR, tr_interrupt, SA_SHIRQ, "serial 2 dma tr", NULL)) panic("irq18"); - if(request_irq(19, rec_interrupt, SA_SHIRQ, "serial 2 dma rec", NULL)) + if(request_irq(SER2_DMA_RX_IRQ_NBR, rec_interrupt, SA_SHIRQ, "serial 2 dma rec", NULL)) panic("irq19"); #endif #ifdef CONFIG_ETRAX_SERIAL_PORT3 /* DMA Shared with par1 (and SCSI1 and Extern DMA 0) */ - if(request_irq(20, tr_interrupt, SA_SHIRQ, "serial 3 dma tr", NULL)) + if(request_irq(SER3_DMA_TX_IRQ_NBR, tr_interrupt, SA_SHIRQ, "serial 3 dma tr", NULL)) panic("irq20"); - if(request_irq(21, rec_interrupt, SA_SHIRQ, "serial 3 dma rec", NULL)) + if(request_irq(SER3_DMA_RX_IRQ_NBR, rec_interrupt, SA_SHIRQ, "serial 3 dma rec", NULL)) panic("irq21"); #endif #ifdef CONFIG_ETRAX_SERIAL_FLUSH_DMA_FAST diff -u --recursive --new-file v2.4.6/linux/arch/cris/drivers/usb-host.c linux/arch/cris/drivers/usb-host.c --- v2.4.6/linux/arch/cris/drivers/usb-host.c Tue May 1 16:04:56 2001 +++ linux/arch/cris/drivers/usb-host.c Wed Jul 4 11:50:39 2001 @@ -3,7 +3,7 @@ * * Copyright (c) 2001 Axis Communications AB. * - * $Id: usb-host.c,v 1.8 2001/02/27 13:52:48 bjornw Exp $ + * $Id: usb-host.c,v 1.9 2001/05/09 12:54:12 johana Exp $ * */ @@ -23,17 +23,18 @@ #include <asm/uaccess.h> #include <asm/io.h> #include <asm/irq.h> +#include <asm/dma.h> #include <asm/system.h> #include <asm/svinto.h> #include <linux/usb.h> #include "usb-host.h" -#define ETRAX_USB_HC_IRQ 31 -#define ETRAX_USB_RX_IRQ 25 -#define ETRAX_USB_TX_IRQ 24 +#define ETRAX_USB_HC_IRQ USB_HC_IRQ_NBR +#define ETRAX_USB_RX_IRQ USB_DMA_RX_IRQ_NBR +#define ETRAX_USB_TX_IRQ USB_DMA_TX_IRQ_NBR -static const char *usb_hcd_version = "$Revision: 1.8 $"; +static const char *usb_hcd_version = "$Revision: 1.9 $"; #undef KERN_DEBUG #define KERN_DEBUG "" @@ -2034,21 +2035,21 @@ OK (4); /* hub power ** */ case RH_GET_STATUS | RH_OTHER | RH_CLASS: - if (wIndex == 1) { + if (wIndex == 1) { *((__u16*)data) = cpu_to_le16(hc->rh.prev_wPortStatus_1); *((__u16*)data + 1) = cpu_to_le16(hc->rh.wPortChange_1); - } - else if (wIndex == 2) { + } + else if (wIndex == 2) { *((__u16*)data) = cpu_to_le16(hc->rh.prev_wPortStatus_2); *((__u16*)data + 1) = cpu_to_le16(hc->rh.wPortChange_2); - } - else { + } + else { dbg_rh("RH_GET_STATUS whith invalid wIndex !!"); OK(0); - } + } - OK(4); - + OK(4); + case RH_CLEAR_FEATURE | RH_ENDPOINT: switch (wValue) { case (RH_ENDPOINT_STALL): @@ -2114,16 +2115,16 @@ OK (0); /* port power ** */ case (RH_C_PORT_CONNECTION): - if (wIndex == 1) { + if (wIndex == 1) { hc->rh.wPortChange_1 &= ~(1 << RH_PORT_CONNECTION); - } - else if (wIndex == 2) { + } + else if (wIndex == 2) { hc->rh.wPortChange_2 &= ~(1 << RH_PORT_CONNECTION); - } - else { + } + else { dbg_rh("RH_CLEAR_FEATURE->RH_C_PORT_CONNECTION " "with invalid wIndex == %d!!", wIndex); - } + } OK (0); case (RH_C_PORT_ENABLE): @@ -2182,7 +2183,7 @@ OK (0); case (RH_PORT_RESET): - if (wIndex == 1) { + if (wIndex == 1) { int port1_retry; port1_redo: @@ -2205,8 +2206,8 @@ not even schedule() works !!! WHY ?? */ udelay(15000); - } - else if (wIndex == 2) { + } + else if (wIndex == 2) { int port2_retry; port2_redo: @@ -2229,7 +2230,7 @@ not even schedule() works !!! WHY ?? */ udelay(15000); - } + } /* Try to bring the HC into running state */ *R_USB_COMMAND = @@ -2237,21 +2238,21 @@ nop(); while (*R_USB_COMMAND & IO_MASK(R_USB_COMMAND, busy)); - dbg_rh("...Done"); - OK(0); - + dbg_rh("...Done"); + OK(0); + case (RH_PORT_POWER): OK (0); /* port power ** */ case (RH_PORT_ENABLE): /* There is no rh port enable command in the Etrax USB interface!!!! */ OK (0); - + } break; case RH_SET_ADDRESS: hc->rh.devnum = wValue; - dbg_rh("RH address set to: %d", hc->rh.devnum); + dbg_rh("RH address set to: %d", hc->rh.devnum); OK (0); case RH_GET_DESCRIPTOR: @@ -2324,7 +2325,7 @@ etrax_usb_bus = bus = usb_alloc_bus(&etrax_usb_device_operations); hc->bus = bus; bus->hcpriv = hc; - + /* Initalize RH to the default address. And make sure that we have no status change indication */ hc->rh.numports = 2; /* The RH has two ports */ @@ -2339,7 +2340,7 @@ /* Initialize the intr-traffic flags */ hc->intr.sleeping = 0; hc->intr.wq = NULL; - + /* Initially all ep's are free except ep 0 */ ep_usage_bitmask = 0; set_bit(0, (void *)&ep_usage_bitmask); @@ -2349,20 +2350,20 @@ /* This code should really be moved */ - if (request_dma(8, "ETRAX 100LX built-in USB (Tx)")) { + if (request_dma(USB_TX_DMA_NBR, "ETRAX 100LX built-in USB (Tx)")) { err("Could not allocate DMA ch 8 for USB"); etrax_usb_hc_cleanup(); DBFEXIT; return -1; } - if (request_dma(9, "ETRAX 100LX built-in USB (Rx)")) { + if (request_dma(USB_RX_DMA_NBR, "ETRAX 100LX built-in USB (Rx)")) { err("Could not allocate DMA ch 9 for USB"); etrax_usb_hc_cleanup(); DBFEXIT; return -1; } -#if 0 /* Moved to head.S */ +#if 0 /* Moved to head.S */ *R_GEN_CONFIG = genconfig_shadow = (genconfig_shadow & ~(IO_MASK(R_GEN_CONFIG, usb1) | IO_MASK(R_GEN_CONFIG, usb2) | @@ -2490,8 +2491,8 @@ free_irq(ETRAX_USB_RX_IRQ, NULL); free_irq(ETRAX_USB_TX_IRQ, NULL); - free_dma(8); - free_dma(9); + free_dma(USB_TX_DMA_NBR); + free_dma(USB_RX_DMA_NBR); usb_deregister_bus(etrax_usb_bus); DBFEXIT; diff -u --recursive --new-file v2.4.6/linux/arch/cris/kernel/Makefile linux/arch/cris/kernel/Makefile --- v2.4.6/linux/arch/cris/kernel/Makefile Tue May 1 16:04:56 2001 +++ linux/arch/cris/kernel/Makefile Wed Jul 4 11:50:39 2001 @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.4 2001/04/17 13:58:39 orjanf Exp $ +# $Id: Makefile,v 1.5 2001/05/15 05:10:00 hp Exp $ # # Makefile for the linux kernel. # @@ -19,6 +19,11 @@ debugport.o semaphore.o obj-$(CONFIG_ETRAX_KGDB) += kgdb.o + +entry.o: entryoffsets.s + +entryoffsets.s: entryoffsets.c + $(CC) $(CFLAGS) -S -c $< clean: diff -u --recursive --new-file v2.4.6/linux/arch/cris/kernel/entry.S linux/arch/cris/kernel/entry.S --- v2.4.6/linux/arch/cris/kernel/entry.S Sun May 20 12:11:38 2001 +++ linux/arch/cris/kernel/entry.S Wed Jul 4 11:50:39 2001 @@ -1,4 +1,4 @@ -/* $Id: entry.S,v 1.22 2001/04/17 13:58:39 orjanf Exp $ +/* $Id: entry.S,v 1.27 2001/05/29 11:25:27 markusl Exp $ * * linux/arch/cris/entry.S * @@ -7,6 +7,21 @@ * Authors: Bjorn Wesen (bjornw@axis.com) * * $Log: entry.S,v $ + * Revision 1.27 2001/05/29 11:25:27 markusl + * In case of "spurious_interrupt", do hard_reset instead of hanging system in a loop... + * + * Revision 1.26 2001/05/15 15:46:03 bjornw + * Include config.h now that we use some CONFIG_ options + * + * Revision 1.25 2001/05/15 05:38:47 hp + * Tweaked code in _ret_from_sys_call + * + * Revision 1.24 2001/05/15 05:27:49 hp + * Save r9 in r1 over function call rather than on stack. + * + * Revision 1.23 2001/05/15 05:10:00 hp + * Generate entry.S structure offsets from C + * * Revision 1.22 2001/04/17 13:58:39 orjanf * * Renamed CONFIG_KGDB to CONFIG_ETRAX_KGDB. * @@ -140,39 +155,21 @@ LENOSYS = 38 - ;; offsets into the task_struct (found at sp aligned to THREAD_SIZE, 8192) - ;; linux/sched.h - -LTASK_SIGPENDING = 8 -LTASK_NEEDRESCHED = 20 -LTASK_PTRACE = 24 -LTASK_PID = 105 + ;; Get offsets into various structs. + .include "entryoffsets.s" - ;; process bits for ptrace + ;; process bits for ptrace. FIXME: Should be in a header file. PT_TRACESYS_BIT = 1 - ;; some pt_regs offsets (from ptrace.h) - -LORIG_R10 = 4 -LR13 = 8 -LR12 = 12 -LR11 = 16 -LR10 = 20 -LR9 = 24 -LMOF = 64 -LDCCR = 68 -LSRP = 72 -LIRP = 76 - ;; below are various parts of system_call which are not in the fast-path ;; handle software irqs handle_softirq: - push r9 + move.d r9,r1 jsr _do_softirq ; call the C routine for softirq handling - pop r9 + move.d r1,r9 ;; fall-through @@ -188,11 +185,10 @@ reschedule: ;; keep r9 intact - push r9 + move.d r9,r1 jsr _schedule - pop r9 ba _ret_from_sys_call - nop + move.d r1,r9 ;; return but call do_signal first signal_return: @@ -275,8 +271,9 @@ ;; check if any bottom halves need service - move.d [_irq_stat],r0 ; softirq_active - and.d [_irq_stat+4],r0 ; softirq_mask + move.d _irq_stat,r10 + move.d [r10+],r0 ; softirq_active + and.d [r10],r0 ; softirq_mask bne handle_softirq nop @@ -378,12 +375,6 @@ ba _ret_from_sys_call nop - ;; from asm/processor.h, the thread_struct - -LTHREAD_KSP = 0 -LTHREAD_USP = 4 -LTHREAD_DCCR = 8 - ;; _resume performs the actual task-switching, by switching stack pointers ;; input arguments: r10 = prev, r11 = next, r12 = thread offset in task struct ;; returns old current in r10 @@ -495,7 +486,7 @@ _IRQ1_interrupt: _spurious_interrupt: di -basse2: ba basse2 + jsr _hard_reset_now nop ;; this handles the case when multiple interrupts arrive at the same time diff -u --recursive --new-file v2.4.6/linux/arch/cris/kernel/entryoffsets.c linux/arch/cris/kernel/entryoffsets.c --- v2.4.6/linux/arch/cris/kernel/entryoffsets.c Wed Dec 31 16:00:00 1969 +++ linux/arch/cris/kernel/entryoffsets.c Wed Jul 4 11:50:39 2001 @@ -0,0 +1,54 @@ +/* linux/arch/cris/entryoffsets.c + * + * Copyright (C) 2001 Axis Communications AB + * + * Generate structure offsets for use in entry.S. No extra processing + * needed more than compiling this file to assembly code. Horrendous + * assembly code will be generated, so don't look at that. + * + * Authors: Hans-Peter Nilsson (hp@axis.com) + */ + +/* There can be string constants fallout from inline functions, so we'd + better make sure we don't assemble anything emitted from inclusions. */ +__asm__ (".if 0"); + +#include <linux/sched.h> +#include <linux/ptrace.h> +#include <asm/processor.h> + +/* Exclude everything except the assembly by wrapping it in ".if 0". */ +#undef OF +#define OF(NAME, TYPE, MEMBER) \ +void NAME ## _fun (void) \ + { \ + __asm__ (".endif \n" \ + #NAME " = %0 \n" \ + ".if 0\n" \ + : : "i" (offsetof (TYPE, MEMBER))); \ + } + +/* task_struct offsets. */ +OF (LTASK_SIGPENDING, struct task_struct, sigpending) +OF (LTASK_NEEDRESCHED, struct task_struct, need_resched) +OF (LTASK_PTRACE, struct task_struct, ptrace) +OF (LTASK_PID, struct task_struct, pid) + +/* pt_regs offsets. */ +OF (LORIG_R10, struct pt_regs, orig_r10) +OF (LR13, struct pt_regs, r13) +OF (LR12, struct pt_regs, r12) +OF (LR11, struct pt_regs, r11) +OF (LR10, struct pt_regs, r10) +OF (LR9, struct pt_regs, r9) +OF (LMOF, struct pt_regs, mof) +OF (LDCCR, struct pt_regs, dccr) +OF (LSRP, struct pt_regs, srp) +OF (LIRP, struct pt_regs, irp) + +/* thread_struct offsets. */ +OF (LTHREAD_KSP, struct thread_struct, ksp) +OF (LTHREAD_USP, struct thread_struct, usp) +OF (LTHREAD_DCCR, struct thread_struct, dccr) + +__asm__ (".endif"); diff -u --recursive --new-file v2.4.6/linux/arch/cris/kernel/head.S linux/arch/cris/kernel/head.S --- v2.4.6/linux/arch/cris/kernel/head.S Tue May 1 16:04:56 2001 +++ linux/arch/cris/kernel/head.S Wed Jul 4 11:50:39 2001 @@ -1,4 +1,4 @@ -/* $Id: head.S,v 1.29 2001/04/18 12:51:59 orjanf Exp $ +/* $Id: head.S,v 1.34 2001/05/15 07:08:14 hp Exp $ * * Head of the kernel - alter with care * @@ -7,6 +7,21 @@ * Authors: Bjorn Wesen (bjornw@axis.com) * * $Log: head.S,v $ + * Revision 1.34 2001/05/15 07:08:14 hp + * Tweak "notice" to reflect that both r8 r9 are used + * + * Revision 1.33 2001/05/15 06:40:05 hp + * Put bulk of code in .text.init, data in .data.init + * + * Revision 1.32 2001/05/15 06:18:56 hp + * Execute review comment: s/bcc/bhs/g; s/bcs/blo/g + * + * Revision 1.31 2001/05/15 06:08:40 hp + * Add sentence about autodetecting the bit31-MMU-bug + * + * Revision 1.30 2001/05/15 06:00:05 hp + * Update comment: LOW_MAP is not forced on xsim anymore. + * * Revision 1.29 2001/04/18 12:51:59 orjanf * * Reverted review change regarding the use of bcs/bcc. * * Removed non-working LED-clearing code. @@ -127,9 +142,9 @@ ;; since etrax actually starts at address 2 when booting from flash, we ;; put a nop (2 bytes) here first so we dont accidentally skip the di ;; - ;; NOTICE! The registers r8 and r9 are used as a parameter carrying + ;; NOTICE! The registers r8 and r9 are used as parameters carrying ;; information from the decompressor (if the kernel was compressed). - ;; They should not be used in the code below until it is read. + ;; They should not be used in the code below until read. nop di @@ -143,8 +158,11 @@ ;; temporarily map those segments linearily. ;; ;; Due to a bug in Etrax-100 LX version 1 we need to map the memory - ;; slightly different. We also let the simulator get this mapping for now. - ;; (The bug is that you can't remap bit 31.) + ;; slightly different. The bug is that you can't remap bit 31 of + ;; an address. Though we can check the version register for + ;; whether the bug is present, some constants would then have to + ;; be variables, so we don't. The drawback is that you can "only" map + ;; 1G per process with CONFIG_CRIS_LOW_MAP. #ifdef CONFIG_CRIS_LOW_MAP move.d 0x0004b098, r0 ; kseg mappings, temporary map of 0xc0->0x40 @@ -190,11 +208,18 @@ move.d pc,r0 and.d 0x7fffffff,r0 ; get rid of the non-cache bit cmp.d 0x10000,r0 ; arbitrary... just something above this code - bcs inflash + blo inflash0 nop jump inram ; enter cached ram - + + ;; Jumpgate for branches. +inflash0: + jump inflash + + ;; Put this in a suitable section where we can reclaim storage + ;; after init. + .section ".text.init" inflash: ;; We need to initialze DRAM registers before we start using the DRAM @@ -225,7 +250,7 @@ 1: move.w [r0+], r3 move.w r3, [r1+] cmp.d r2, r1 - bcs 1b + blo 1b nop ;; We keep the cramfs in the flash. @@ -271,7 +296,7 @@ ;; to a cramfs magic is small.. ) cmp.d 0x0ffffff8, r9 - bcc no_romfs_in_flash ; r9 points outside the flash area + bhs no_romfs_in_flash ; r9 points outside the flash area nop move.d [r9], r0 ; cramfs_super.magic cmp.d CRAMFS_MAGIC, r0 @@ -353,7 +378,7 @@ move.d _end, r1 1: clear.d [r0+] cmp.d r1, r0 - bcs 1b + blo 1b nop #ifdef CONFIG_BLK_DEV_ETRAXIDE @@ -575,5 +600,6 @@ #else _swapper_pg_dir = 0xc0002000 #endif - + + .section ".data.init" #include "../lib/hw_settings.S" diff -u --recursive --new-file v2.4.6/linux/arch/cris/kernel/irq.c linux/arch/cris/kernel/irq.c --- v2.4.6/linux/arch/cris/kernel/irq.c Tue May 1 16:04:56 2001 +++ linux/arch/cris/kernel/irq.c Wed Jul 4 11:50:39 2001 @@ -1,4 +1,4 @@ -/* $Id: irq.c,v 1.14 2001/04/17 13:58:39 orjanf Exp $ +/* $Id: irq.c,v 1.15 2001/06/10 11:18:46 bjornw Exp $ * * linux/arch/cris/kernel/irq.c * @@ -485,3 +485,10 @@ #endif } + +#if defined(CONFIG_PROC_FS) && defined(CONFIG_SYSCTL) +/* Used by other archs to show/control IRQ steering during SMP */ +void init_irq_proc(void) +{ +} +#endif diff -u --recursive --new-file v2.4.6/linux/arch/cris/kernel/process.c linux/arch/cris/kernel/process.c --- v2.4.6/linux/arch/cris/kernel/process.c Tue May 1 16:04:56 2001 +++ linux/arch/cris/kernel/process.c Wed Jul 4 11:50:39 2001 @@ -1,4 +1,4 @@ -/* $Id: process.c,v 1.13 2001/03/20 19:44:06 bjornw Exp $ +/* $Id: process.c,v 1.14 2001/05/29 11:27:59 markusl Exp $ * * linux/arch/cris/kernel/process.c * @@ -8,6 +8,9 @@ * Authors: Bjorn Wesen (bjornw@axis.com) * * $Log: process.c,v $ + * Revision 1.14 2001/05/29 11:27:59 markusl + * Fixed so that hard_reset_now will do reset even if watchdog wasn't enabled + * * Revision 1.13 2001/03/20 19:44:06 bjornw * Use the 7th syscall argument for regs instead of current_regs * @@ -90,12 +93,21 @@ /* if the watchdog is enabled, we can simply disable interrupts and go * into an eternal loop, and the watchdog will reset the CPU after 0.1s + * if on the other hand the watchdog wasn't enabled, we just enable it and wait */ void hard_reset_now (void) { printk("*** HARD RESET ***\n"); cli(); + +#ifndef CONFIG_ETRAX_WATCHDOG + /* Since we dont plan to keep on reseting the watchdog, + the key can be arbitrary hence three */ + *R_WATCHDOG = IO_FIELD(R_WATCHDOG, key, 3) | + IO_STATE(R_WATCHDOG, enable, start); +#endif + while(1) /* waiting for RETRIBUTION! */ ; } diff -u --recursive --new-file v2.4.6/linux/arch/cris/kernel/ptrace.c linux/arch/cris/kernel/ptrace.c --- v2.4.6/linux/arch/cris/kernel/ptrace.c Tue May 1 16:04:56 2001 +++ linux/arch/cris/kernel/ptrace.c Fri Jul 20 12:39:55 2001 @@ -115,32 +115,7 @@ if (pid == 1) /* you may not mess with init */ goto out_tsk; if (request == PTRACE_ATTACH) { - if (child == current) - goto out_tsk; - if ((!child->dumpable || - (current->uid != child->euid) || - (current->uid != child->suid) || - (current->uid != child->uid) || - (current->gid != child->egid) || - (current->gid != child->sgid) || - (!cap_issubset(child->cap_permitted, current->cap_permitted)) || - (current->gid != child->gid)) && !capable(CAP_SYS_PTRACE)) - goto out_tsk; - /* the same process cannot be attached many times */ - if (child->ptrace & PT_PTRACED) - goto out_tsk; - child->ptrace |= PT_PTRACED; - - write_lock_irq(&tasklist_lock); - if (child->p_pptr != current) { - REMOVE_LINKS(child); - child->p_pptr = current; - SET_LINKS(child); - } - write_unlock_irq(&tasklist_lock); - - send_sig(SIGSTOP, child, 1); - ret = 0; + ret = ptrace_attach(child); goto out_tsk; } ret = -ESRCH; diff -u --recursive --new-file v2.4.6/linux/arch/cris/kernel/setup.c linux/arch/cris/kernel/setup.c --- v2.4.6/linux/arch/cris/kernel/setup.c Tue May 1 16:04:56 2001 +++ linux/arch/cris/kernel/setup.c Wed Jul 4 11:50:39 2001 @@ -1,4 +1,4 @@ -/* $Id: setup.c,v 1.14 2001/04/03 12:54:12 starvik Exp $ +/* $Id: setup.c,v 1.16 2001/05/15 01:23:13 hp Exp $ * * linux/arch/cris/kernel/setup.c * @@ -190,14 +190,10 @@ unsigned short cache; unsigned short flags; } cpu_info[] = { + /* The first four models will never ever run this code and are + only here for display. */ { "ETRAX 1", 0, 0 }, - { "ETRAX 2", 0, 0 }, /* Don't say it HAS_TOKENRING - there are - lethal bugs in that chip that - prevents T-R from ever working. - Never go there, and never lead anyone - into believing it can work. BTW: - Anyone working on a T-R network - driver? :-) :-) :-) :-/ */ + { "ETRAX 2", 0, 0 }, { "ETRAX 3", 0, HAS_TOKENRING }, { "ETRAX 4", 0, HAS_TOKENRING | HAS_SCSI }, { "Unknown", 0, 0 }, diff -u --recursive --new-file v2.4.6/linux/arch/cris/kernel/signal.c linux/arch/cris/kernel/signal.c --- v2.4.6/linux/arch/cris/kernel/signal.c Tue May 1 16:04:56 2001 +++ linux/arch/cris/kernel/signal.c Wed Jul 4 11:50:39 2001 @@ -7,7 +7,7 @@ * * Ideas also taken from arch/arm. * - * Copyright (C) 2000 Axis Communications AB + * Copyright (C) 2000, 2001 Axis Communications AB * * Authors: Bjorn Wesen (bjornw@axis.com) * @@ -101,7 +101,14 @@ current->state = TASK_INTERRUPTIBLE; schedule(); if (do_signal(0, &saveset, regs)) - return -EINTR; + /* We will get here twice: once to call the signal + handler, then again to return from the + sigsuspend system call. When calling the + signal handler, R10 holds the signal number as + set through do_signal. The sigsuspend call + will return with the restored value set above; + always -EINTR. */ + return regs->r10; } } @@ -133,7 +140,14 @@ current->state = TASK_INTERRUPTIBLE; schedule(); if (do_signal(0, &saveset, regs)) - return -EINTR; + /* We will get here twice: once to call the signal + handler, then again to return from the + sigsuspend system call. When calling the + signal handler, R10 holds the signal number as + set through do_signal. The sigsuspend call + will return with the restored value set above; + always -EINTR. */ + return regs->r10; } } @@ -413,6 +427,7 @@ regs->irp = (unsigned long) ka->sa.sa_handler; /* what we enter NOW */ regs->srp = return_ip; /* what we enter LATER */ + regs->r10 = sig; /* first argument is signo */ /* actually move the usp to reflect the stacked frame */ @@ -462,7 +477,6 @@ /* trampoline - the desired return ip is the retcode itself */ return_ip = (unsigned long)&frame->retcode; /* This is movu.w __NR_sigreturn, r9; break 13; */ - /* TODO: check byteorder */ err |= __put_user(0x9c5f, (short *)(frame->retcode+0)); err |= __put_user(__NR_sigreturn, (short *)(frame->retcode+2)); err |= __put_user(0xe93d, (short *)(frame->retcode+4)); @@ -477,6 +491,7 @@ regs->irp = (unsigned long) ka->sa.sa_handler; /* what we enter NOW */ regs->srp = return_ip; /* what we enter LATER */ + regs->r10 = sig; /* first argument is signo */ /* actually move the usp to reflect the stacked frame */ diff -u --recursive --new-file v2.4.6/linux/arch/cris/kernel/sys_cris.c linux/arch/cris/kernel/sys_cris.c --- v2.4.6/linux/arch/cris/kernel/sys_cris.c Tue May 1 16:04:56 2001 +++ linux/arch/cris/kernel/sys_cris.c Wed Jul 4 11:50:39 2001 @@ -1,4 +1,4 @@ -/* $Id: sys_cris.c,v 1.7 2001/04/17 11:52:15 orjanf Exp $ +/* $Id: sys_cris.c,v 1.9 2001/05/30 06:20:26 markusl Exp $ * * linux/arch/cris/kernel/sys_cris.c * diff -u --recursive --new-file v2.4.6/linux/arch/cris/kernel/time.c linux/arch/cris/kernel/time.c --- v2.4.6/linux/arch/cris/kernel/time.c Thu Feb 8 16:32:44 2001 +++ linux/arch/cris/kernel/time.c Wed Jul 4 11:50:39 2001 @@ -1,4 +1,4 @@ -/* $Id: time.c,v 1.4 2000/10/17 14:44:58 bjornw Exp $ +/* $Id: time.c,v 1.6 2001/05/29 11:29:42 markusl Exp $ * * linux/arch/cris/kernel/time.c * @@ -83,12 +83,9 @@ * avoiding timer inconsistencies (they are rare, but they happen)... * there are three kinds of problems that must be avoided here: * 1. the timer counter underflows - * 2. hardware problem with the timer, not giving us continuous time, - * the counter does small "jumps" upwards on some Pentium systems, - * thus causes time warps - * 3. we are after the timer interrupt, but the bottom half handler + * 2. we are after the timer interrupt, but the bottom half handler * hasn't executed yet. - */ + */ if( jiffies_t == jiffies_p ) { if( count > count_p ) { } @@ -195,7 +192,7 @@ return retval; } -/* Except from the Etrax100 HSDD about the built-in watchdog: +/* Excerpt from the Etrax100 HSDD about the built-in watchdog: * * 3.10.4 Watchdog timer @@ -231,14 +228,12 @@ #define WATCHDOG_MIN_FREE_PAGES 8 -extern int nr_free_pages; - static inline void reset_watchdog(void) { #if defined(CONFIG_ETRAX_WATCHDOG) && !defined(CONFIG_SVINTO_SIM) /* only keep watchdog happy as long as we have memory left! */ - if(nr_free_pages > WATCHDOG_MIN_FREE_PAGES) { + if(nr_free_pages() > WATCHDOG_MIN_FREE_PAGES) { /* reset the watchdog with the inverse of the old key */ watchdog_key ^= 0x7; /* invert key, which is 3 bits */ *R_WATCHDOG = IO_FIELD(R_WATCHDOG, key, watchdog_key) | diff -u --recursive --new-file v2.4.6/linux/arch/cris/kernel/traps.c linux/arch/cris/kernel/traps.c --- v2.4.6/linux/arch/cris/kernel/traps.c Sun May 20 12:11:38 2001 +++ linux/arch/cris/kernel/traps.c Wed Jul 4 11:50:39 2001 @@ -1,4 +1,4 @@ -/* $Id: traps.c,v 1.11 2001/04/04 09:43:31 orjanf Exp $ +/* $Id: traps.c,v 1.12 2001/05/15 15:46:40 bjornw Exp $ * * linux/arch/cris/traps.c * diff -u --recursive --new-file v2.4.6/linux/arch/cris/lib/checksum.S linux/arch/cris/lib/checksum.S --- v2.4.6/linux/arch/cris/lib/checksum.S Fri Apr 6 10:42:55 2001 +++ linux/arch/cris/lib/checksum.S Wed Jul 4 11:50:39 2001 @@ -1,4 +1,4 @@ -/* $Id: checksum.S,v 1.4 2001/02/19 11:11:33 bjornw Exp $ +/* $Id: checksum.S,v 1.5 2001/05/29 11:40:14 markusl Exp $ * A fast checksum routine using movem * Copyright (c) 1998-2001 Axis Communications AB * @@ -13,6 +13,8 @@ ;; r12 - checksum ;; check for breakeven length between movem and normal word looping versions + ;; we also do _NOT_ want to compute a checksum over more than the + ;; actual length when length < 40 cmpu.w 80,r11 blo word_loop @@ -20,6 +22,8 @@ ;; need to save the registers we use below in the movem loop ;; this overhead is why we have a check above for breakeven length + ;; only r0 - r8 have to be saved, the other ones are clobber-able + ;; according to the ABI subq 9*4,sp movem r8,[sp] diff -u --recursive --new-file v2.4.6/linux/arch/cris/lib/checksumcopy.S linux/arch/cris/lib/checksumcopy.S --- v2.4.6/linux/arch/cris/lib/checksumcopy.S Fri Apr 6 10:42:55 2001 +++ linux/arch/cris/lib/checksumcopy.S Wed Jul 4 11:50:39 2001 @@ -1,4 +1,4 @@ -/* $Id: checksumcopy.S,v 1.4 2001/02/19 11:11:34 bjornw Exp $ +/* $Id: checksumcopy.S,v 1.5 2001/05/29 11:40:14 markusl Exp $ * A fast checksum+copy routine using movem * Copyright (c) 1998, 2001 Axis Communications AB * @@ -17,6 +17,8 @@ ;; r13 - checksum ;; check for breakeven length between movem and normal word looping versions + ;; we also do _NOT_ want to compute a checksum over more than the + ;; actual length when length < 40 cmpu.w 80,r12 blo word_loop @@ -24,6 +26,8 @@ ;; need to save the registers we use below in the movem loop ;; this overhead is why we have a check above for breakeven length + ;; only r0 - r8 have to be saved, the other ones are clobber-able + ;; according to the ABI subq 9*4,sp movem r8,[sp] diff -u --recursive --new-file v2.4.6/linux/arch/cris/lib/dram_init.S linux/arch/cris/lib/dram_init.S --- v2.4.6/linux/arch/cris/lib/dram_init.S Tue May 1 16:04:56 2001 +++ linux/arch/cris/lib/dram_init.S Wed Jul 4 11:50:39 2001 @@ -1,4 +1,4 @@ -/* $Id: dram_init.S,v 1.7 2001/04/18 12:05:39 bjornw Exp $ +/* $Id: dram_init.S,v 1.8 2001/05/15 07:12:45 hp Exp $ * * DRAM/SDRAM initialization - alter with care * This file is intended to be included from other assembler files @@ -11,6 +11,9 @@ * Authors: Mikael Starvik (starvik@axis.com) * * $Log: dram_init.S,v $ + * Revision 1.8 2001/05/15 07:12:45 hp + * Copy warning from head.S about r8 and r9 + * * Revision 1.7 2001/04/18 12:05:39 bjornw * Fixed comments, and explicitely include config.h to be sure its there * @@ -44,6 +47,9 @@ #include <linux/config.h> + ;; WARNING! The registers r8 and r9 are used as parameters carrying + ;; information from the decompressor (if the kernel was compressed). + ;; They should not be used in the code below. #ifndef CONFIG_SVINTO_SIM move.d CONFIG_ETRAX_DEF_R_WAITSTATES, r0 diff -u --recursive --new-file v2.4.6/linux/arch/cris/lib/hw_settings.S linux/arch/cris/lib/hw_settings.S --- v2.4.6/linux/arch/cris/lib/hw_settings.S Sun May 20 12:11:38 2001 +++ linux/arch/cris/lib/hw_settings.S Wed Jul 4 11:50:39 2001 @@ -1,14 +1,15 @@ - ;; $Id: hw_settings.S,v 1.2 2001/04/03 11:11:09 starvik Exp $ - ;; - ;; This table is used by some tools to extract hardware parameters. - ;; The table should be included in the kernel and the decompressor. - ;; Don't forget to update the tools if you change this table. - ;; - ;; Copyright (C) 2001 Axis Communications AB - ;; - ;; Authors: Mikael Starvik (starvik@axis.com) +/* + * $Id: hw_settings.S,v 1.3 2001/04/21 17:02:46 bjornw Exp $ + * + * This table is used by some tools to extract hardware parameters. + * The table should be included in the kernel and the decompressor. + * Don't forget to update the tools if you change this table. + * + * Copyright (C) 2001 Axis Communications AB + * + * Authors: Mikael Starvik (starvik@axis.com) + */ - #define PA_SET_VALUE ((CONFIG_ETRAX_DEF_R_PORT_PA_DIR << 8) | \ (CONFIG_ETRAX_DEF_R_PORT_PA_DATA)) #define PB_SET_VALUE ((CONFIG_ETRAX_DEF_R_PORT_PB_CONFIG << 16) | \ diff -u --recursive --new-file v2.4.6/linux/arch/cris/lib/usercopy.c linux/arch/cris/lib/usercopy.c --- v2.4.6/linux/arch/cris/lib/usercopy.c Thu Feb 8 16:32:44 2001 +++ linux/arch/cris/lib/usercopy.c Wed Jul 4 11:50:39 2001 @@ -273,20 +273,27 @@ movem r10,[r13+] addq 44,r12 ;; compensate for last loop underflowing n - +8: ;; Restore registers from stack movem [sp+],r10 .section .fixup,\"ax\" -; To provide a correct count in r10 of bytes that failed to be copied, -; we jump back into the loop if the loop-branch was taken. -; There is no performance penalty; the program will segfault soon -; enough. +;; Do not jump back into the loop if we fail. For some uses, we get a +;; page fault but for performance reasons we care to not get further +;; faults. For example, fs/super.c at one time did +;; i = size - copy_from_user((void *)page, data, size); +;; which would cause repeated faults while clearing the remainder of +;; the SIZE bytes at PAGE after the first fault. 3: move.d [sp],r10 + +;; Number of remaining bytes, cleared but not copied, is r12 + 44. + + add.d r12,r10 addq 44,r10 + move.d r10,[sp] clear.d r0 clear.d r1 @@ -299,7 +306,40 @@ clear.d r8 clear.d r9 clear.d r10 - jump 1b + +;; Perform clear similar to the copy-loop. + +4: + subq 44,r12 + bge 4b + movem r10,[r13+] + +;; Clear by four for the remaining multiples. + + addq 40,r12 + bmi 6f + nop +5: + subq 4,r12 + bpl 5b + clear.d [r13+] +6: + addq 4,r12 + beq 7f + nop + + subq 1,r12 + beq 7f + clear.b [r13+] + + subq 1,r12 + beq 7f + clear.b [r13+] + + clear.d r12 + clear.b [r13+] +7: + jump 8b .previous .section __ex_table,\"a\" diff -u --recursive --new-file v2.4.6/linux/arch/cris/mm/fault.c linux/arch/cris/mm/fault.c --- v2.4.6/linux/arch/cris/mm/fault.c Tue May 1 16:04:56 2001 +++ linux/arch/cris/mm/fault.c Wed Jul 4 11:50:39 2001 @@ -6,6 +6,19 @@ * Authors: Bjorn Wesen * * $Log: fault.c,v $ + * Revision 1.16 2001/06/13 00:06:08 bjornw + * current_pgd should be volatile + * + * Revision 1.15 2001/06/13 00:02:23 bjornw + * Use a separate variable to store the current pgd to avoid races in schedule + * + * Revision 1.14 2001/05/16 17:41:07 hp + * Last comment tweak further tweaked. + * + * Revision 1.13 2001/05/15 00:58:44 hp + * Expand a bit on the comment why we compare address >= TASK_SIZE rather + * than >= VMALLOC_START. + * * Revision 1.12 2001/04/04 10:51:14 bjornw * mmap_sem is grabbed for reading * @@ -59,6 +72,10 @@ /* debug of higher-level faults */ #define DPG(x) +/* current active page directory */ + +volatile pgd_t *current_pgd; + /* fast TLB-fill fault handler */ void @@ -94,9 +111,11 @@ if(miss) { - /* see if the pte exists at all */ + /* see if the pte exists at all + * refer through current_pgd, dont use mm->pgd + */ - pmd = (pmd_t *)pgd_offset(mm, address); + pmd = (pmd_t *)(current_pgd + pgd_index(address)); if(pmd_none(*pmd)) goto dofault; if(pmd_bad(*pmd)) { @@ -206,7 +225,9 @@ * should really be >= VMALLOC_START, however, kernel fixup errors * will be handled more quickly by going through vmalloc_fault and then * into bad_area_nosemaphore than falling through the find_vma user-mode - * tests. + * tests. As an aside can be mentioned that the difference in + * compiled code is neglibible; the instruction is the same, just a + * comparison with a different address of the same size. */ if (address >= TASK_SIZE) @@ -384,12 +405,17 @@ /* * Synchronize this task's top level page-table * with the 'reference' page table. + * + * Use current_pgd instead of tsk->active_mm->pgd + * since the latter might be unavailable if this + * code is executed in a misfortunately run irq */ + int offset = pgd_index(address); pgd_t *pgd, *pgd_k; pmd_t *pmd, *pmd_k; - pgd = tsk->active_mm->pgd + offset; + pgd = current_pgd + offset; pgd_k = init_mm.pgd + offset; if (!pgd_present(*pgd)) { diff -u --recursive --new-file v2.4.6/linux/arch/cris/mm/init.c linux/arch/cris/mm/init.c --- v2.4.6/linux/arch/cris/mm/init.c Tue May 1 16:04:56 2001 +++ linux/arch/cris/mm/init.c Wed Jul 4 11:50:39 2001 @@ -7,6 +7,12 @@ * Authors: Bjorn Wesen (bjornw@axis.com) * * $Log: init.c,v $ + * Revision 1.25 2001/06/13 00:02:23 bjornw + * Use a separate variable to store the current pgd to avoid races in schedule + * + * Revision 1.24 2001/05/15 00:52:20 hp + * Only map segment 0xa as seg if CONFIG_JULIETTE + * * Revision 1.23 2001/04/04 14:35:40 bjornw * * Removed get_pte_slow and friends (2.4.3 change) * * Removed bad_pmd handling (2.4.3 change) @@ -85,6 +91,7 @@ #include <asm/dma.h> #include <asm/svinto.h> #include <asm/io.h> +#include <asm/mmu_context.h> static unsigned long totalram_pages; @@ -177,6 +184,13 @@ for(i = 0; i < PTRS_PER_PGD; i++) swapper_pg_dir[i] = __pgd(0); + + /* make sure the current pgd table points to something sane + * (even if it is most probably not used until the next + * switch_mm) + */ + + current_pgd = init_mm.pgd; /* initialise the TLB (tlb.c) */ @@ -241,7 +255,11 @@ IO_STATE(R_MMU_KSEG, seg_d, page ) | IO_STATE(R_MMU_KSEG, seg_c, page ) | IO_STATE(R_MMU_KSEG, seg_b, seg ) | /* kernel reg area */ +#ifdef CONFIG_JULIETTE IO_STATE(R_MMU_KSEG, seg_a, seg ) | /* ARTPEC etc. */ +#else + IO_STATE(R_MMU_KSEG, seg_a, page ) | +#endif IO_STATE(R_MMU_KSEG, seg_9, seg ) | /* LED's on some boards */ IO_STATE(R_MMU_KSEG, seg_8, seg ) | /* CSE0/1, flash and I/O */ IO_STATE(R_MMU_KSEG, seg_7, page ) | /* kernel vmalloc area */ @@ -258,7 +276,11 @@ IO_FIELD(R_MMU_KBASE_HI, base_d, 0x0 ) | IO_FIELD(R_MMU_KBASE_HI, base_c, 0x0 ) | IO_FIELD(R_MMU_KBASE_HI, base_b, 0xb ) | +#ifdef CONFIG_JULIETTE IO_FIELD(R_MMU_KBASE_HI, base_a, 0xa ) | +#else + IO_FIELD(R_MMU_KBASE_HI, base_a, 0x0 ) | +#endif IO_FIELD(R_MMU_KBASE_HI, base_9, 0x9 ) | IO_FIELD(R_MMU_KBASE_HI, base_8, 0x8 ) ); @@ -442,7 +464,7 @@ i = max_mapnr; val->totalram = 0; - val->sharedram = 0; + val->sharedram = atomic_read(&shmem_nrpages); val->freeram = nr_free_pages(); val->bufferram = atomic_read(&buffermem_pages); while (i-- > 0) { diff -u --recursive --new-file v2.4.6/linux/arch/cris/mm/tlb.c linux/arch/cris/mm/tlb.c --- v2.4.6/linux/arch/cris/mm/tlb.c Tue May 1 16:04:56 2001 +++ linux/arch/cris/mm/tlb.c Wed Jul 4 11:50:39 2001 @@ -1,7 +1,7 @@ /* * linux/arch/cris/mm/tlb.c * - * Copyright (C) 2000 Axis Communications AB + * Copyright (C) 2000, 2001 Axis Communications AB * * Authors: Bjorn Wesen (bjornw@axis.com) * @@ -21,6 +21,7 @@ #include <asm/segment.h> #include <asm/pgtable.h> #include <asm/svinto.h> +#include <asm/mmu_context.h> #define D(x) @@ -252,6 +253,15 @@ get_mmu_context(next); + /* remember the pgd for the fault handlers + * this is similar to the pgd register in some other CPU's. + * we need our own copy of it because current and active_mm + * might be invalid at points where we still need to derefer + * the pgd. + */ + + current_pgd = next->pgd; + /* switch context in the MMU */ D(printk("switching mmu_context to %d (%p)\n", next->context, next)); @@ -288,7 +298,7 @@ /* clear the page_id map */ - for(i = 0; i < NUM_PAGEID; i++) + for (i = 1; i < sizeof (page_id_map) / sizeof (page_id_map[0]); i++) page_id_map[i] = NULL; /* invalidate the entire TLB */ diff -u --recursive --new-file v2.4.6/linux/arch/i386/boot/video.S linux/arch/i386/boot/video.S --- v2.4.6/linux/arch/i386/boot/video.S Sun Nov 21 00:09:51 1999 +++ linux/arch/i386/boot/video.S Thu Jul 5 11:28:16 2001 @@ -496,7 +496,7 @@ jnc setbad addw %bx, %bx - .word 0xa7ff, spec_inits # JMP [BX+spec_inits] + jmp *spec_inits(%bx) setmenu: orb %al, %al # 80x25 is an exception @@ -1008,7 +1008,7 @@ vesa1: # gas version 2.9.1, using BFD version 2.9.1.0.23 buggers the next inst. # XXX: lodsw %gs:(%si), %ax # Get next mode in the list - .byte 0x65, 0xAD # %gs seg prefix + lodsw + gs; lodsw cmpw $0xffff, %ax # End of the table? jz vesar diff -u --recursive --new-file v2.4.6/linux/arch/i386/config.in linux/arch/i386/config.in --- v2.4.6/linux/arch/i386/config.in Tue Jul 3 17:08:18 2001 +++ linux/arch/i386/config.in Sun Jul 15 16:15:44 2001 @@ -303,6 +303,8 @@ fi endmenu +source drivers/message/fusion/Config.in + source drivers/ieee1394/Config.in source drivers/i2o/Config.in diff -u --recursive --new-file v2.4.6/linux/arch/i386/defconfig linux/arch/i386/defconfig --- v2.4.6/linux/arch/i386/defconfig Tue Jul 3 17:08:18 2001 +++ linux/arch/i386/defconfig Mon Jul 16 10:45:15 2001 @@ -335,6 +335,15 @@ # CONFIG_SCSI_PCMCIA is not set # +# Fusion MPT device support +# +# CONFIG_FUSION is not set +# CONFIG_FUSION_BOOT is not set +# CONFIG_FUSION_ISENSE is not set +# CONFIG_FUSION_CTL is not set +# CONFIG_FUSION_LAN is not set + +# # I2O device support # # CONFIG_I2O is not set @@ -414,6 +423,7 @@ # # CONFIG_ACENIC is not set # CONFIG_ACENIC_OMIT_TIGON_I is not set +# CONFIG_DL2K is not set # CONFIG_MYRI_SBUS is not set # CONFIG_HAMACHI is not set # CONFIG_YELLOWFIN is not set diff -u --recursive --new-file v2.4.6/linux/arch/i386/kernel/dmi_scan.c linux/arch/i386/kernel/dmi_scan.c --- v2.4.6/linux/arch/i386/kernel/dmi_scan.c Tue Feb 13 14:13:43 2001 +++ linux/arch/i386/kernel/dmi_scan.c Wed Jul 18 09:43:27 2001 @@ -1,8 +1,10 @@ +#include <linux/config.h> #include <linux/types.h> #include <linux/kernel.h> #include <linux/string.h> #include <linux/init.h> #include <linux/apm_bios.h> +#include <linux/slab.h> #include <asm/io.h> struct dmi_header @@ -13,6 +15,7 @@ }; #define dmi_printk(x) +//#define dmi_printk(x) printk(x) static char * __init dmi_string(struct dmi_header *dm, u8 s) { @@ -90,9 +93,254 @@ } +enum +{ + DMI_BIOS_VENDOR, + DMI_BIOS_VERSION, + DMI_BIOS_DATE, + DMI_SYS_VENDOR, + DMI_PRODUCT_NAME, + DMI_PRODUCT_VERSION, + DMI_BOARD_VENDOR, + DMI_BOARD_NAME, + DMI_BOARD_VERSION, + DMI_STRING_MAX +}; + +static char *dmi_ident[DMI_STRING_MAX]; + +/* + * Save a DMI string + */ + +static void __init dmi_save_ident(struct dmi_header *dm, int slot, int string) +{ + char *d = (char*)dm; + char *p = dmi_string(dm, d[string]); + if(p==NULL || *p == 0) + return; + if (dmi_ident[slot]) + return; + dmi_ident[slot] = kmalloc(strlen(p)+1, GFP_KERNEL); + if(dmi_ident[slot]) + strcpy(dmi_ident[slot], p); + else + printk(KERN_ERR "dmi_save_ident: out of memory.\n"); +} + +/* + * DMI callbacks for problem boards + */ + +struct dmi_strmatch +{ + u8 slot; + char *substr; +}; + +#define NONE 255 + +struct dmi_blacklist +{ + int (*callback)(struct dmi_blacklist *); + char *ident; + struct dmi_strmatch matches[4]; +}; + +#define NO_MATCH { NONE, NULL} +#define MATCH(a,b) { a, b } + +/* + * We have problems with IDE DMA on some platforms. In paticular the + * KT7 series. On these it seems the newer BIOS has fixed them. The + * rule needs to be improved to match specific BIOS revisions with + * corruption problems + */ + +static __init int disable_ide_dma(struct dmi_blacklist *d) +{ +#ifdef CONFIG_BLK_DEV_IDE + extern int noautodma; + if(noautodma == 0) + { + noautodma = 1; + printk(KERN_INFO "%s series board detected. Disabling IDE DMA.\n", d->ident); + } +#endif + return 0; +} + +/* + * Some machines require the "reboot=b" commandline option, this quirk makes that automatic. + */ +static __init int set_bios_reboot(struct dmi_blacklist *d) +{ + extern int reboot_thru_bios; + if (reboot_thru_bios == 0) + { + reboot_thru_bios = 1; + printk(KERN_INFO "%s series board detected. Selecting BIOS-method for reboots.\n", d->ident); + } + return 0; +} + +/* + * Some bioses have a broken protected mode poweroff and need to use realmode + */ + +static __init int set_realmode_power_off(struct dmi_blacklist *d) +{ + if (apm_info.realmode_power_off == 0) + { + apm_info.realmode_power_off = 1; + printk(KERN_INFO "%s bios detected. Using realmode poweroff only.\n", d->ident); + } + return 0; +} + + +/* + * Some laptops require interrupts to be enabled during APM calls + */ + +static __init int set_apm_ints(struct dmi_blacklist *d) +{ + if (apm_info.allow_ints == 0) + { + apm_info.allow_ints = 1; + printk(KERN_INFO "%s machine detected. Enabling interrupts during APM calls.\n", d->ident); + } + return 0; +} + +/* + * Some APM bioses corrupt memory or just plain do not work + */ + +static __init int apm_is_horked(struct dmi_blacklist *d) +{ + if (apm_info.disabled == 0) + { + apm_info.disabled = 1; + printk(KERN_INFO "%s machine detected. Disabling APM.\n", d->ident); + } + return 0; +} + + +/* + * Check for clue free BIOS implementations who use + * the following QA technique + * + * [ Write BIOS Code ]<------ + * | ^ + * < Does it Compile >----N-- + * |Y ^ + * < Does it Boot Win98 >-N-- + * |Y + * [Ship It] + * + * Phoenix A04 08/24/2000 is known bad (Dell Inspiron 5000e) + * Phoenix A07 09/29/2000 is known good (Dell Inspiron 5000) + */ + +static __init int broken_apm_power(struct dmi_blacklist *d) +{ + apm_info.get_power_status_broken = 1; + printk(KERN_WARNING "BIOS strings suggest APM bugs, disabling power status reporting.\n"); + return 0; +} + +/* + * Process the DMI blacklists + */ + + +/* + * This will be expanded over time to force things like the APM + * interrupt mask settings according to the laptop + */ + +static __initdata struct dmi_blacklist dmi_blacklist[]={ +#if 0 + { disable_ide_dma, "KT7", { /* Overbroad right now - kill DMA on problem KT7 boards */ + MATCH(DMI_PRODUCT_NAME, "KT7-RAID"), + NO_MATCH, NO_MATCH, NO_MATCH + } }, +#endif + { 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"), + MATCH(DMI_BIOS_DATE, "08/24/2000"), NO_MATCH + } }, + { set_realmode_power_off, "Award Software v4.60 PGMA", { /* broken PM poweroff bios */ + MATCH(DMI_BIOS_VENDOR, "Award Software International, Inc."), + MATCH(DMI_BIOS_VERSION, "4.60 PGMA"), + MATCH(DMI_BIOS_DATE, "134526184"), NO_MATCH + } }, + { set_bios_reboot, "PowerEdge 1300/500", { /* Handle problems with rebooting on Dell 1300's */ + MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"), + MATCH(DMI_PRODUCT_NAME, "PowerEdge 1300/500"), + NO_MATCH, NO_MATCH + } }, + { set_bios_reboot, "PowerEdge 1300/550", { /* Handle problems with rebooting on Dell 1300's */ + MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"), + MATCH(DMI_PRODUCT_NAME, "PowerEdge 1300/550"), + NO_MATCH, NO_MATCH + } }, + { set_apm_ints, "IBM", { /* Allow interrupts during suspend on IBM laptops */ + MATCH(DMI_SYS_VENDOR, "IBM"), + NO_MATCH, NO_MATCH, NO_MATCH + } }, + { set_apm_ints, "ASUSTeK", { /* Allow interrupts during APM or the clock goes slow */ + MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."), + MATCH(DMI_PRODUCT_NAME, "L8400K series Notebook PC"), + NO_MATCH, NO_MATCH + } }, + { apm_is_horked, "Trigem Delhi3", { /* APM crashes */ + MATCH(DMI_SYS_VENDOR, "TriGem Computer, Inc"), + MATCH(DMI_PRODUCT_NAME, "Delhi3"), + NO_MATCH, NO_MATCH, + } }, + { NULL, } +}; + + +/* + * Walk the blacklist table running matching functions until someone + * returns 1 or we hit the end. + */ + +static __init void dmi_check_blacklist(void) +{ + struct dmi_blacklist *d; + int i; + + d=&dmi_blacklist[0]; + while(d->callback) + { + for(i=0;i<4;i++) + { + int s = d->matches[i].slot; + if(s==NONE) + continue; + if(dmi_ident[s] && strstr(dmi_ident[s], d->matches[i].substr)) + continue; + /* No match */ + goto fail; + } + if(d->callback(d)) + return; +fail: + d++; + } +} + + + /* * Process a DMI table entry. Right now all we care about are the BIOS - * and machine entries. For 2.4 we should pull the smbus controller info + * and machine entries. For 2.5 we should pull the smbus controller info * out of here. */ @@ -105,66 +353,47 @@ { case 0: p=dmi_string(dm,data[4]); - - if(*p && *p!=' ') + if(*p) { dmi_printk(("BIOS Vendor: %s\n", p)); + dmi_save_ident(dm, DMI_BIOS_VENDOR, 4); dmi_printk(("BIOS Version: %s\n", dmi_string(dm, data[5]))); + dmi_save_ident(dm, DMI_BIOS_VERSION, 5); dmi_printk(("BIOS Release: %s\n", dmi_string(dm, data[8]))); - } - - /* - * Check for clue free BIOS implementations who use - * the following QA technique - * - * [ Write BIOS Code ]<------ - * | ^ - * < Does it Compile >----N-- - * |Y ^ - * < Does it Boot Win98 >-N-- - * |Y - * [Ship It] - * - * Phoenix A04 08/24/2000 is known bad (Dell Inspiron 5000e) - * Phoenix A07 09/29/2000 is known good (Dell Inspiron 5000) - */ - - if(strcmp(dmi_string(dm, data[4]), "Phoenix Technologies LTD")==0) - { - if(strcmp(dmi_string(dm, data[5]), "A04")==0 - && strcmp(dmi_string(dm, data[8]), "08/24/2000")==0) - { - apm_info.get_power_status_broken = 1; - printk(KERN_WARNING "BIOS strings suggest APM bugs, disabling power status reporting.\n"); - } + dmi_save_ident(dm, DMI_BIOS_DATE, 8); } break; + case 1: p=dmi_string(dm,data[4]); - - if(*p && *p!=' ') + if(*p) { dmi_printk(("System Vendor: %s.\n",p)); + dmi_save_ident(dm, DMI_SYS_VENDOR, 4); dmi_printk(("Product Name: %s.\n", dmi_string(dm, data[5]))); + dmi_save_ident(dm, DMI_PRODUCT_NAME, 5); dmi_printk(("Version %s.\n", dmi_string(dm, data[6]))); + dmi_save_ident(dm, DMI_PRODUCT_VERSION, 6); dmi_printk(("Serial Number %s.\n", dmi_string(dm, data[7]))); } break; case 2: p=dmi_string(dm,data[4]); - - if(*p && *p!=' ') + if(*p) { dmi_printk(("Board Vendor: %s.\n",p)); + dmi_save_ident(dm, DMI_BOARD_VENDOR, 4); dmi_printk(("Board Name: %s.\n", dmi_string(dm, data[5]))); + dmi_save_ident(dm, DMI_BOARD_NAME, 5); dmi_printk(("Board Version: %s.\n", dmi_string(dm, data[6]))); + dmi_save_ident(dm, DMI_BOARD_VERSION, 6); } break; case 3: @@ -177,7 +406,10 @@ static int __init dmi_scan_machine(void) { - return dmi_iterate(dmi_decode); + int err = dmi_iterate(dmi_decode); + if(err == 0) + dmi_check_blacklist(); + return err; } module_init(dmi_scan_machine); diff -u --recursive --new-file v2.4.6/linux/arch/i386/kernel/pci-irq.c linux/arch/i386/kernel/pci-irq.c --- v2.4.6/linux/arch/i386/kernel/pci-irq.c Tue Jul 3 17:08:18 2001 +++ linux/arch/i386/kernel/pci-irq.c Wed Jul 4 15:39:28 2001 @@ -391,6 +391,38 @@ return 1; } +/* Support for AMD756 PCI IRQ Routing + * Jhon H. Caicedo <jhcaiced@osso.org.co> + * Jun/21/2001 0.2.0 Release, fixed to use "nybble" functions... (jhcaiced) + * Jun/19/2001 Alpha Release 0.1.0 (jhcaiced) + * The AMD756 pirq rules are nibble-based + * offset 0x56 0-3 PIRQA 4-7 PIRQB + * offset 0x57 0-3 PIRQC 4-7 PIRQD + */ +static int pirq_amd756_get(struct pci_dev *router, struct pci_dev *dev, int pirq) +{ + u8 irq; + irq = 0; + if (pirq <= 4) + { + irq = read_config_nybble(router, 0x56, pirq - 1); + } + printk(KERN_INFO "AMD756: dev %04x:%04x, router pirq : %d get irq : %2d\n", + dev->vendor, dev->device, pirq, irq); + return irq; +} + +static int pirq_amd756_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq) +{ + printk(KERN_INFO "AMD756: dev %04x:%04x, router pirq : %d SET irq : %2d\n", + dev->vendor, dev->device, pirq, irq); + if (pirq <= 4) + { + write_config_nybble(router, 0x56, pirq - 1, irq); + } + return 1; +} + #ifdef CONFIG_PCI_BIOS static int pirq_bios_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq) @@ -426,6 +458,8 @@ { "VLSI 82C534", PCI_VENDOR_ID_VLSI, PCI_DEVICE_ID_VLSI_82C534, pirq_vlsi_get, pirq_vlsi_set }, { "ServerWorks", PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_OSB4, pirq_serverworks_get, pirq_serverworks_set }, + { "AMD756 VIPER", PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_740B, + pirq_amd756_get, pirq_amd756_set }, { "default", 0, 0, NULL, NULL } }; diff -u --recursive --new-file v2.4.6/linux/arch/i386/kernel/process.c linux/arch/i386/kernel/process.c --- v2.4.6/linux/arch/i386/kernel/process.c Fri Feb 9 11:29:44 2001 +++ linux/arch/i386/kernel/process.c Wed Jul 4 14:41:33 2001 @@ -152,7 +152,7 @@ static long no_idt[2]; static int reboot_mode; -static int reboot_thru_bios; +int reboot_thru_bios; static int __init reboot_setup(char *str) { diff -u --recursive --new-file v2.4.6/linux/arch/i386/kernel/ptrace.c linux/arch/i386/kernel/ptrace.c --- v2.4.6/linux/arch/i386/kernel/ptrace.c Tue Mar 6 19:44:37 2001 +++ linux/arch/i386/kernel/ptrace.c Fri Jul 20 12:39:55 2001 @@ -165,34 +165,7 @@ goto out_tsk; if (request == PTRACE_ATTACH) { - if (child == current) - goto out_tsk; - if(((current->uid != child->euid) || - (current->uid != child->suid) || - (current->uid != child->uid) || - (current->gid != child->egid) || - (current->gid != child->sgid) || - (!cap_issubset(child->cap_permitted, current->cap_permitted)) || - (current->gid != child->gid)) && !capable(CAP_SYS_PTRACE)) - goto out_tsk; - rmb(); - if (!child->dumpable && !capable(CAP_SYS_PTRACE)) - goto out_tsk; - /* the same process cannot be attached many times */ - if (child->ptrace & PT_PTRACED) - goto out_tsk; - child->ptrace |= PT_PTRACED; - - write_lock_irq(&tasklist_lock); - if (child->p_pptr != current) { - REMOVE_LINKS(child); - child->p_pptr = current; - SET_LINKS(child); - } - write_unlock_irq(&tasklist_lock); - - send_sig(SIGSTOP, child, 1); - ret = 0; + ret = ptrace_attach(child); goto out_tsk; } ret = -ESRCH; diff -u --recursive --new-file v2.4.6/linux/arch/i386/kernel/setup.c linux/arch/i386/kernel/setup.c --- v2.4.6/linux/arch/i386/kernel/setup.c Fri May 25 17:07:09 2001 +++ linux/arch/i386/kernel/setup.c Wed Jul 11 09:31:44 2001 @@ -1123,7 +1123,6 @@ static int __init init_amd(struct cpuinfo_x86 *c) { u32 l, h; - unsigned long flags; int mbytes = max_mapnr >> (20-PAGE_SHIFT); int r; @@ -1187,14 +1186,13 @@ mbytes=508; rdmsr(0xC0000082, l, h); - if((l&0x0000FFFF)==0) - { + if ((l&0x0000FFFF)==0) { + unsigned long flags; l=(1<<0)|((mbytes/4)<<1); - save_flags(flags); - __cli(); + local_irq_save(flags); __asm__ __volatile__ ("wbinvd": : :"memory"); wrmsr(0xC0000082, l, h); - restore_flags(flags); + local_irq_restore(flags); printk(KERN_INFO "Enabling old style K6 write allocation for %d Mb\n", mbytes); @@ -1209,14 +1207,13 @@ mbytes=4092; rdmsr(0xC0000082, l, h); - if((l&0xFFFF0000)==0) - { + if ((l&0xFFFF0000)==0) { + unsigned long flags; l=((mbytes>>2)<<22)|(1<<16); - save_flags(flags); - __cli(); + local_irq_save(flags); __asm__ __volatile__ ("wbinvd": : :"memory"); wrmsr(0xC0000082, l, h); - restore_flags(flags); + local_irq_restore(flags); printk(KERN_INFO "Enabling new style K6 write allocation for %d Mb\n", mbytes); } @@ -1243,12 +1240,13 @@ /* * Read Cyrix DEVID registers (DIR) to get more detailed info. about the CPU */ -static inline void do_cyrix_devid(unsigned char *dir0, unsigned char *dir1) +static void do_cyrix_devid(unsigned char *dir0, unsigned char *dir1) { unsigned char ccr2, ccr3; + unsigned long flags; /* we test for DEVID by checking whether CCR3 is writable */ - cli(); + local_irq_save(flags); ccr3 = getCx86(CX86_CCR3); setCx86(CX86_CCR3, ccr3 ^ 0x80); getCx86(0xc0); /* dummy to change bus */ @@ -1272,7 +1270,7 @@ *dir0 = getCx86(CX86_DIR0); *dir1 = getCx86(CX86_DIR1); } - sti(); + local_irq_restore(flags); } /* @@ -1316,15 +1314,16 @@ { if (Cx86_dir0_msb == 3) { unsigned char ccr3, ccr5; + unsigned long flags; - cli(); + local_irq_save(flags); ccr3 = getCx86(CX86_CCR3); setCx86(CX86_CCR3, (ccr3 & 0x0f) | 0x10); /* enable MAPEN */ ccr5 = getCx86(CX86_CCR5); if (ccr5 & 2) setCx86(CX86_CCR5, ccr5 & 0xfd); /* reset SLOP */ setCx86(CX86_CCR3, ccr3); /* disable MAPEN */ - sti(); + local_irq_restore(flags); if (ccr5 & 2) { /* possible wrong calibration done */ printk(KERN_INFO "Recalibrating delay loop with SLOP bit reset\n"); @@ -1438,8 +1437,16 @@ break; case 5: /* 6x86MX/M II */ - if (dir1 > 7) dir0_msn++; /* M II */ - else c->coma_bug = 1; /* 6x86MX, it has the bug. */ + if (dir1 > 7) + { + dir0_msn++; /* M II */ + /* Enable MMX extensions (App note 108) */ + setCx86(CX86_CCR7, getCx86(CX86_CCR7)|1); + } + else + { + c->coma_bug = 1; /* 6x86MX, it has the bug. */ + } tmp = (!(dir0_lsn & 7) || dir0_lsn & 1) ? 2 : 0; Cx86_cb[tmp] = cyrix_model_mult2[dir0_lsn & 7]; p = Cx86_cb+tmp; @@ -1987,6 +1994,9 @@ wrmsr(0x119,lo,hi); printk(KERN_NOTICE "CPU serial number disabled.\n"); clear_bit(X86_FEATURE_PN, &c->x86_capability); + + /* Disabling the serial number may affect the cpuid level */ + c->cpuid_level = cpuid_eax(0); } } @@ -2092,15 +2102,16 @@ if (dir0 == 5 || dir0 == 3) { unsigned char ccr3, ccr4; + unsigned long flags; printk(KERN_INFO "Enabling CPUID on Cyrix processor.\n"); - cli(); + local_irq_save(flags); ccr3 = getCx86(CX86_CCR3); setCx86(CX86_CCR3, (ccr3 & 0x0f) | 0x10); /* enable MAPEN */ ccr4 = getCx86(CX86_CCR4); setCx86(CX86_CCR4, ccr4 | 0x80); /* enable cpuid */ setCx86(CX86_CCR3, ccr3); /* disable MAPEN */ - sti(); + local_irq_restore(flags); } } else diff -u --recursive --new-file v2.4.6/linux/arch/i386/kernel/signal.c linux/arch/i386/kernel/signal.c --- v2.4.6/linux/arch/i386/kernel/signal.c Tue Feb 13 13:15:04 2001 +++ linux/arch/i386/kernel/signal.c Wed Jul 4 14:41:33 2001 @@ -370,7 +370,7 @@ /* This is the X/Open sanctioned signal stack switching. */ if (ka->sa.sa_flags & SA_ONSTACK) { - if (! on_sig_stack(esp)) + if (sas_ss_flags(esp) == 0) esp = current->sas_ss_sp + current->sas_ss_size; } diff -u --recursive --new-file v2.4.6/linux/arch/i386/kernel/vm86.c linux/arch/i386/kernel/vm86.c --- v2.4.6/linux/arch/i386/kernel/vm86.c Sun Oct 1 20:35:15 2000 +++ linux/arch/i386/kernel/vm86.c Fri Jul 6 17:05:07 2001 @@ -456,7 +456,7 @@ if (VMPI.vm86dbg_active && VMPI.vm86dbg_TFpendig) \ pushw(ssp,sp,popw(ssp,sp) | TF_MASK); #define VM86_FAULT_RETURN \ - if (VMPI.force_return_for_pic && (VEFLAGS & IF_MASK)) \ + if (VMPI.force_return_for_pic && (VEFLAGS & (IF_MASK | VIF_MASK))) \ return_to_32bit(regs, VM86_PICRETURN); \ return; diff -u --recursive --new-file v2.4.6/linux/arch/i386/math-emu/reg_u_div.S linux/arch/i386/math-emu/reg_u_div.S --- v2.4.6/linux/arch/i386/math-emu/reg_u_div.S Fri Apr 6 10:42:47 2001 +++ linux/arch/i386/math-emu/reg_u_div.S Wed Jul 4 14:41:33 2001 @@ -89,10 +89,8 @@ movl REGB,%ebx movl DEST,%edi - movw EXP(%esi),%dx - movw EXP(%ebx),%ax - .byte 0x0f,0xbf,0xc0 /* movsx %ax,%eax */ - .byte 0x0f,0xbf,0xd2 /* movsx %dx,%edx */ + movswl EXP(%esi),%edx + movswl EXP(%ebx),%eax subl %eax,%edx addl EXP_BIAS,%edx diff -u --recursive --new-file v2.4.6/linux/arch/ia64/kernel/entry.S linux/arch/ia64/kernel/entry.S --- v2.4.6/linux/arch/ia64/kernel/entry.S Thu Apr 5 12:51:47 2001 +++ linux/arch/ia64/kernel/entry.S Thu Jul 19 20:38:52 2001 @@ -68,7 +68,7 @@ /* * In theory, we'd have to zap this state only to prevent leaking of - * security sensitive state (e.g., if current->dumpable is zero). However, + * security sensitive state (e.g., if current->mm->dumpable is zero). However, * this executes in less than 20 cycles even on Itanium, so it's not worth * optimizing for...). */ diff -u --recursive --new-file v2.4.6/linux/arch/ia64/kernel/ptrace.c linux/arch/ia64/kernel/ptrace.c --- v2.4.6/linux/arch/ia64/kernel/ptrace.c Thu Apr 5 12:51:47 2001 +++ linux/arch/ia64/kernel/ptrace.c Fri Jul 20 12:39:55 2001 @@ -768,32 +768,7 @@ goto out_tsk; if (request == PTRACE_ATTACH) { - if (child == current) - goto out_tsk; - if ((!child->dumpable || - (current->uid != child->euid) || - (current->uid != child->suid) || - (current->uid != child->uid) || - (current->gid != child->egid) || - (current->gid != child->sgid) || - (!cap_issubset(child->cap_permitted, current->cap_permitted)) || - (current->gid != child->gid)) && !capable(CAP_SYS_PTRACE)) - goto out_tsk; - /* the same process cannot be attached many times */ - if (child->ptrace & PT_PTRACED) - goto out_tsk; - child->ptrace |= PT_PTRACED; - if (child->p_pptr != current) { - unsigned long flags; - - write_lock_irqsave(&tasklist_lock, flags); - REMOVE_LINKS(child); - child->p_pptr = current; - SET_LINKS(child); - write_unlock_irqrestore(&tasklist_lock, flags); - } - send_sig(SIGSTOP, child, 1); - ret = 0; + ret = ptrace_attach(child); goto out_tsk; } ret = -ESRCH; diff -u --recursive --new-file v2.4.6/linux/arch/m68k/kernel/ptrace.c linux/arch/m68k/kernel/ptrace.c --- v2.4.6/linux/arch/m68k/kernel/ptrace.c Tue Jul 3 17:08:18 2001 +++ linux/arch/m68k/kernel/ptrace.c Fri Jul 20 12:39:55 2001 @@ -118,32 +118,7 @@ goto out_tsk; if (request == PTRACE_ATTACH) { - if (child == current) - goto out_tsk; - if ((!child->dumpable || - (current->uid != child->euid) || - (current->uid != child->suid) || - (current->uid != child->uid) || - (current->gid != child->egid) || - (current->gid != child->sgid) || - (!cap_issubset(child->cap_permitted, current->cap_permitted)) || - (current->gid != child->gid)) && !capable(CAP_SYS_PTRACE)) - goto out_tsk; - /* the same process cannot be attached many times */ - if (child->ptrace & PT_PTRACED) - goto out_tsk; - child->ptrace |= PT_PTRACED; - - write_lock_irqsave(&tasklist_lock, flags); - if (child->p_pptr != current) { - REMOVE_LINKS(child); - child->p_pptr = current; - SET_LINKS(child); - } - write_unlock_irqrestore(&tasklist_lock, flags); - - send_sig(SIGSTOP, child, 1); - ret = 0; + ret = ptrace_attach(child); goto out_tsk; } ret = -ESRCH; diff -u --recursive --new-file v2.4.6/linux/arch/mips/kernel/ptrace.c linux/arch/mips/kernel/ptrace.c --- v2.4.6/linux/arch/mips/kernel/ptrace.c Tue Jul 3 17:08:18 2001 +++ linux/arch/mips/kernel/ptrace.c Fri Jul 20 12:39:55 2001 @@ -66,34 +66,7 @@ goto out; if (request == PTRACE_ATTACH) { - if (child == current) - goto out_tsk; - if ((!child->dumpable || - (current->uid != child->euid) || - (current->uid != child->suid) || - (current->uid != child->uid) || - (current->gid != child->egid) || - (current->gid != child->sgid) || - (current->gid != child->gid) || - (!cap_issubset(child->cap_permitted, - current->cap_permitted)) || - (current->gid != child->gid)) && !capable(CAP_SYS_PTRACE)) - goto out_tsk; - /* the same process cannot be attached many times */ - if (child->ptrace & PT_PTRACED) - goto out_tsk; - child->ptrace |= PT_PTRACED; - - write_lock_irq(&tasklist_lock); - if (child->p_pptr != current) { - REMOVE_LINKS(child); - child->p_pptr = current; - SET_LINKS(child); - } - write_unlock_irq(&tasklist_lock); - - send_sig(SIGSTOP, child, 1); - res = 0; + res = ptrace_attach(child); goto out_tsk; } res = -ESRCH; diff -u --recursive --new-file v2.4.6/linux/arch/mips/mm/andes.c linux/arch/mips/mm/andes.c --- v2.4.6/linux/arch/mips/mm/andes.c Thu Jul 27 18:36:54 2000 +++ linux/arch/mips/mm/andes.c Wed Jul 4 11:50:39 2001 @@ -119,6 +119,17 @@ /* XXX */ } +static void __andes_flush_icache_range(unsigned long start, unsigned long end) +{ + /* XXX */ +} + +static void andes_flush_icache_page(struct vm_area_struct *vma, + struct page *page) +{ + /* XXX */ +} + static void andes_flush_cache_sigtramp(unsigned long page) { /* XXX */ @@ -146,10 +157,6 @@ /* XXX */ } -void load_pgd(unsigned long pg_dir) -{ -} - void pgd_init(unsigned long page) { } @@ -166,11 +173,14 @@ _copy_page = andes_copy_page; _flush_cache_all = andes_flush_cache_all; + ___flush_cache_all = andes_flush_cache_all; _flush_cache_mm = andes_flush_cache_mm; _flush_cache_range = andes_flush_cache_range; _flush_cache_page = andes_flush_cache_page; _flush_cache_sigtramp = andes_flush_cache_sigtramp; _flush_page_to_ram = andes_flush_page_to_ram; + _flush_icache_page = andes_flush_icache_page; + _flush_icache_range = andes_flush_icache_range; flush_cache_all(); flush_tlb_all(); diff -u --recursive --new-file v2.4.6/linux/arch/mips/mm/extable.c linux/arch/mips/mm/extable.c --- v2.4.6/linux/arch/mips/mm/extable.c Thu Feb 24 22:52:30 2000 +++ linux/arch/mips/mm/extable.c Wed Jul 4 11:50:39 2001 @@ -3,6 +3,7 @@ */ #include <linux/config.h> #include <linux/module.h> +#include <linux/spinlock.h> #include <asm/uaccess.h> extern const struct exception_table_entry __start___ex_table[]; @@ -29,26 +30,33 @@ return 0; } +extern spinlock_t modlist_lock; + unsigned long search_exception_table(unsigned long addr) { - unsigned long ret; - + unsigned long ret = 0; + #ifndef CONFIG_MODULES /* There is only the kernel to search. */ ret = search_one_table(__start___ex_table, __stop___ex_table-1, addr); - if (ret) return ret; + return ret; #else + unsigned long flags; + /* The kernel is the last "module" -- no need to treat it special. */ struct module *mp; + + spin_lock_irqsave(&modlist_lock, flags); for (mp = module_list; mp != NULL; mp = mp->next) { - if (mp->ex_table_start == NULL) + if (mp->ex_table_start == NULL || !(mp->flags&(MOD_RUNNING|MOD_INITIALIZING))) continue; ret = search_one_table(mp->ex_table_start, mp->ex_table_end - 1, addr); - if (ret) return ret; + if (ret) + break; } + spin_unlock_irqrestore(&modlist_lock, flags); + return ret; #endif - - return 0; } diff -u --recursive --new-file v2.4.6/linux/arch/mips/mm/fault.c linux/arch/mips/mm/fault.c --- v2.4.6/linux/arch/mips/mm/fault.c Mon Mar 19 12:35:09 2001 +++ linux/arch/mips/mm/fault.c Wed Jul 4 11:50:39 2001 @@ -49,6 +49,18 @@ unsigned long fixup; siginfo_t info; + /* + * We fault-in kernel-space virtual memory on-demand. The + * 'reference' page table is init_mm.pgd. + * + * NOTE! We MUST NOT take any locks for this case. We may + * be in an interrupt or a critical region, and should + * only copy the information from the master page table, + * nothing more. + */ + if (address >= TASK_SIZE) + goto vmalloc_fault; + info.si_code = SEGV_MAPERR; /* * If we're in an interrupt or have no user @@ -113,6 +125,8 @@ bad_area: up_read(&mm->mmap_sem); +bad_area_nosemaphore: + /* User mode accesses just cause a SIGSEGV */ if (user_mode(regs)) { tsk->thread.cp0_badvaddr = address; tsk->thread.error_code = write; @@ -186,4 +200,34 @@ /* Kernel mode? Handle exceptions or die */ if (!user_mode(regs)) goto no_context; + + return; + +vmalloc_fault: + { + /* + * Synchronize this task's top level page-table + * with the 'reference' page table. + */ + int offset = pgd_index(address); + pgd_t *pgd, *pgd_k; + pmd_t *pmd, *pmd_k; + + pgd = tsk->active_mm->pgd + offset; + pgd_k = init_mm.pgd + offset; + + if (!pgd_present(*pgd)) { + if (!pgd_present(*pgd_k)) + goto bad_area_nosemaphore; + set_pgd(pgd, *pgd_k); + return; + } + + pmd = pmd_offset(pgd, address); + pmd_k = pmd_offset(pgd_k, address); + + if (pmd_present(*pmd) || !pmd_present(*pmd_k)) + goto bad_area_nosemaphore; + set_pmd(pmd, *pmd_k); + } } diff -u --recursive --new-file v2.4.6/linux/arch/mips/mm/init.c linux/arch/mips/mm/init.c --- v2.4.6/linux/arch/mips/mm/init.c Mon Oct 16 12:58:51 2000 +++ linux/arch/mips/mm/init.c Wed Jul 4 11:50:39 2001 @@ -1,11 +1,13 @@ -/* $Id: init.c,v 1.26 2000/02/23 00:41:00 ralf Exp $ - * +/* * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. * * Copyright (C) 1994 - 2000 by Ralf Baechle * Copyright (C) 2000 Silicon Graphics, Inc. + * + * Kevin D. Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com + * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved. */ #include <linux/config.h> #include <linux/init.h> @@ -29,6 +31,7 @@ #include <asm/bootinfo.h> #include <asm/cachectl.h> +#include <asm/cpu.h> #include <asm/dma.h> #include <asm/jazzdma.h> #include <asm/system.h> @@ -38,74 +41,20 @@ #include <asm/sgialib.h> #endif #include <asm/mmu_context.h> +#include <asm/tlb.h> + +mmu_gather_t mmu_gathers[NR_CPUS]; static unsigned long totalram_pages; -extern void prom_fixup_mem_map(unsigned long start, unsigned long end); extern void prom_free_prom_memory(void); -void __bad_pte_kernel(pmd_t *pmd) -{ - printk("Bad pmd in pte_alloc_kernel: %08lx\n", pmd_val(*pmd)); - pmd_set(pmd, BAD_PAGETABLE); -} - -void __bad_pte(pmd_t *pmd) -{ - printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd)); - pmd_set(pmd, BAD_PAGETABLE); -} - -pte_t *get_pte_kernel_slow(pmd_t *pmd, unsigned long offset) -{ - pte_t *page; - - page = (pte_t *) __get_free_page(GFP_USER); - if (pmd_none(*pmd)) { - if (page) { - clear_page(page); - pmd_val(*pmd) = (unsigned long)page; - return page + offset; - } - pmd_set(pmd, BAD_PAGETABLE); - return NULL; - } - free_page((unsigned long)page); - if (pmd_bad(*pmd)) { - __bad_pte_kernel(pmd); - return NULL; - } - return (pte_t *) pmd_page(*pmd) + offset; -} - -pte_t *get_pte_slow(pmd_t *pmd, unsigned long offset) -{ - pte_t *page; - - page = (pte_t *) __get_free_page(GFP_KERNEL); - if (pmd_none(*pmd)) { - if (page) { - clear_page(page); - pmd_val(*pmd) = (unsigned long)page; - return page + offset; - } - pmd_set(pmd, BAD_PAGETABLE); - return NULL; - } - free_page((unsigned long)page); - if (pmd_bad(*pmd)) { - __bad_pte(pmd); - return NULL; - } - return (pte_t *) pmd_page(*pmd) + offset; -} - - asmlinkage int sys_cacheflush(void *addr, int bytes, int cache) { - /* XXX Just get it working for now... */ - flush_cache_all(); + /* This should flush more selectivly ... */ + __flush_cache_all(); + return 0; } @@ -122,17 +71,10 @@ { unsigned long order, size; struct page *page; - - switch (mips_cputype) { - case CPU_R4000SC: - case CPU_R4000MC: - case CPU_R4400SC: - case CPU_R4400MC: + if(mips_cpu.options & MIPS_CPU_VCE) order = 3; - break; - default: + else order = 0; - } empty_zero_page = __get_free_pages(GFP_KERNEL, order); if (!empty_zero_page) @@ -169,48 +111,6 @@ return freed; } -/* - * BAD_PAGE is the page that is used for page faults when linux - * is out-of-memory. Older versions of linux just did a - * do_exit(), but using this instead means there is less risk - * for a process dying in kernel mode, possibly leaving a inode - * unused etc.. - * - * BAD_PAGETABLE is the accompanying page-table: it is initialized - * to point to BAD_PAGE entries. - * - * ZERO_PAGE is a special page that is used for zero-initialized - * data and COW. - */ -pte_t * __bad_pagetable(void) -{ - extern char empty_bad_page_table[PAGE_SIZE]; - unsigned long page, dummy1, dummy2; - - page = (unsigned long) empty_bad_page_table; - __asm__ __volatile__( - ".set\tnoreorder\n" - "1:\tsw\t%2,(%0)\n\t" - "subu\t%1,1\n\t" - "bnez\t%1,1b\n\t" - "addiu\t%0,4\n\t" - ".set\treorder" - :"=r" (dummy1), "=r" (dummy2) - :"r" (pte_val(BAD_PAGE)), "0" (page), "1" (PAGE_SIZE/4) - :"$1"); - - return (pte_t *)page; -} - -pte_t __bad_page(void) -{ - extern char empty_bad_page[PAGE_SIZE]; - unsigned long page = (unsigned long) empty_bad_page; - - clear_page((void *)page); - return pte_mkdirty(mk_pte_phys(__pa(page), PAGE_SHARED)); -} - void show_mem(void) { int i, free = 0, total = 0, reserved = 0; @@ -271,7 +171,30 @@ free_area_init(zones_size); } -extern int page_is_ram(unsigned long pagenr); +#define PFN_UP(x) (((x) + PAGE_SIZE - 1) >> PAGE_SHIFT) +#define PFN_DOWN(x) ((x) >> PAGE_SHIFT) + +static inline int page_is_ram(unsigned long pagenr) +{ + int i; + + for (i = 0; i < boot_mem_map.nr_map; i++) { + unsigned long addr, end; + + if (boot_mem_map.map[i].type != BOOT_MEM_RAM) + /* not usable memory */ + continue; + + addr = PFN_UP(boot_mem_map.map[i].addr); + end = PFN_DOWN(boot_mem_map.map[i].addr + + boot_mem_map.map[i].size); + + if (pagenr >= addr && pagenr < end) + return 1; + } + + return 0; +} void __init mem_init(void) { @@ -309,13 +232,16 @@ #ifdef CONFIG_BLK_DEV_INITRD void free_initrd_mem(unsigned long start, unsigned long end) { + if (start < end) + printk("Freeing initrd memory: %ldk freed\n", + (end - start) >> 10); + for (; start < end; start += PAGE_SIZE) { ClearPageReserved(virt_to_page(start)); set_page_count(virt_to_page(start), 1); free_page(start); totalram_pages++; } - printk ("Freeing initrd memory: %ldk freed\n", (end - start) >> 10); } #endif @@ -343,7 +269,7 @@ void si_meminfo(struct sysinfo *val) { val->totalram = totalram_pages; - val->sharedram = 0; + val->sharedram = atomic_read(&shmem_nrpages); val->freeram = nr_free_pages(); val->bufferram = atomic_read(&buffermem_pages); val->totalhigh = 0; diff -u --recursive --new-file v2.4.6/linux/arch/mips/mm/ioremap.c linux/arch/mips/mm/ioremap.c --- v2.4.6/linux/arch/mips/mm/ioremap.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/mm/ioremap.c Wed Jul 4 11:50:39 2001 @@ -0,0 +1,176 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * (C) Copyright 1995 1996 Linus Torvalds + * (C) Copyright 2001 Ralf Baechle + */ +#include <linux/module.h> +#include <asm/addrspace.h> +#include <asm/byteorder.h> + +#include <linux/vmalloc.h> +#include <asm/io.h> +#include <asm/pgalloc.h> + +static inline void remap_area_pte(pte_t * pte, unsigned long address, unsigned long size, + unsigned long phys_addr, unsigned long flags) +{ + unsigned long end; + pgprot_t pgprot = __pgprot(_PAGE_GLOBAL | _PAGE_PRESENT | __READABLE + | __WRITEABLE | flags); + + address &= ~PMD_MASK; + end = address + size; + if (end > PMD_SIZE) + end = PMD_SIZE; + if (address >= end) + BUG(); + do { + if (!pte_none(*pte)) { + printk("remap_area_pte: page already exists\n"); + BUG(); + } + set_pte(pte, mk_pte_phys(phys_addr, pgprot)); + address += PAGE_SIZE; + phys_addr += PAGE_SIZE; + pte++; + } while (address && (address < end)); +} + +static inline int remap_area_pmd(pmd_t * pmd, unsigned long address, unsigned long size, + unsigned long phys_addr, unsigned long flags) +{ + unsigned long end; + + address &= ~PGDIR_MASK; + end = address + size; + if (end > PGDIR_SIZE) + end = PGDIR_SIZE; + phys_addr -= address; + if (address >= end) + BUG(); + do { + pte_t * pte = pte_alloc(&init_mm, pmd, address); + if (!pte) + return -ENOMEM; + remap_area_pte(pte, address, end - address, address + phys_addr, flags); + address = (address + PMD_SIZE) & PMD_MASK; + pmd++; + } while (address && (address < end)); + return 0; +} + +static int remap_area_pages(unsigned long address, unsigned long phys_addr, + unsigned long size, unsigned long flags) +{ + int error; + pgd_t * dir; + unsigned long end = address + size; + + phys_addr -= address; + dir = pgd_offset(&init_mm, address); + flush_cache_all(); + if (address >= end) + BUG(); + spin_lock(&init_mm.page_table_lock); + do { + pmd_t *pmd; + pmd = pmd_alloc(&init_mm, dir, address); + error = -ENOMEM; + if (!pmd) + break; + if (remap_area_pmd(pmd, address, end - address, + phys_addr + address, flags)) + break; + error = 0; + address = (address + PGDIR_SIZE) & PGDIR_MASK; + dir++; + } while (address && (address < end)); + spin_unlock(&init_mm.page_table_lock); + flush_tlb_all(); + return error; +} + +/* + * Generic mapping function (not visible outside): + */ + +/* + * Remap an arbitrary physical address space into the kernel virtual + * address space. Needed when the kernel wants to access high addresses + * directly. + * + * NOTE! We need to allow non-page-aligned mappings too: we will obviously + * have to convert them into an offset in a page-aligned mapping, but the + * caller shouldn't need to know that small detail. + */ + +#define IS_LOW512(addr) (!((unsigned long)(addr) & ~0x1fffffffUL)) + +void * __ioremap(unsigned long phys_addr, unsigned long size, unsigned long flags) +{ + void * addr; + struct vm_struct * area; + unsigned long offset, last_addr; + + /* Don't allow wraparound or zero size */ + last_addr = phys_addr + size - 1; + if (!size || last_addr < phys_addr) + return NULL; + + /* + * Map objects in the low 512mb of address space using KSEG1, otherwise + * map using page tables. + */ + if (IS_LOW512(phys_addr) && IS_LOW512(phys_addr + size - 1)) + return (void *) KSEG1ADDR(phys_addr); + + /* + * Don't allow anybody to remap normal RAM that we're using.. + */ + if (phys_addr < virt_to_phys(high_memory)) { + char *t_addr, *t_end; + struct page *page; + + t_addr = __va(phys_addr); + t_end = t_addr + (size - 1); + + for(page = virt_to_page(t_addr); page <= virt_to_page(t_end); page++) + if(!PageReserved(page)) + return NULL; + } + + /* + * Mappings have to be page-aligned + */ + offset = phys_addr & ~PAGE_MASK; + phys_addr &= PAGE_MASK; + size = PAGE_ALIGN(last_addr) - phys_addr; + + /* + * Ok, go for it.. + */ + area = get_vm_area(size, VM_IOREMAP); + if (!area) + return NULL; + addr = area->addr; + if (remap_area_pages(VMALLOC_VMADDR(addr), phys_addr, size, flags)) { + vfree(addr); + return NULL; + } + + return (void *) (offset + (char *)addr); +} + +#define IS_KSEG1(addr) (((unsigned long)(addr) & ~0x1fffffffUL) == KSEG1) + +void iounmap(void *addr) +{ + if (!IS_KSEG1(addr)) + return vfree((void *) (PAGE_MASK & (unsigned long) addr)); +} + +EXPORT_SYMBOL(__ioremap); +EXPORT_SYMBOL(iounmap); diff -u --recursive --new-file v2.4.6/linux/arch/mips/mm/loadmmu.c linux/arch/mips/mm/loadmmu.c --- v2.4.6/linux/arch/mips/mm/loadmmu.c Sat May 13 08:29:14 2000 +++ linux/arch/mips/mm/loadmmu.c Wed Jul 4 11:50:39 2001 @@ -2,8 +2,8 @@ * loadmmu.c: Setup cpu/cache specific function ptrs at boot time. * * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) - * - * $Id: loadmmu.c,v 1.17 2000/03/13 10:33:05 raiko Exp $ + * Kevin D. Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com + * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved. */ #include <linux/config.h> #include <linux/init.h> @@ -11,10 +11,11 @@ #include <linux/sched.h> #include <linux/mm.h> +#include <asm/bootinfo.h> +#include <asm/cpu.h> #include <asm/page.h> #include <asm/pgtable.h> #include <asm/system.h> -#include <asm/bootinfo.h> /* memory functions */ void (*_clear_page)(void * page); @@ -22,84 +23,79 @@ /* Cache operations. */ void (*_flush_cache_all)(void); +void (*___flush_cache_all)(void); void (*_flush_cache_mm)(struct mm_struct *mm); void (*_flush_cache_range)(struct mm_struct *mm, unsigned long start, unsigned long end); void (*_flush_cache_page)(struct vm_area_struct *vma, unsigned long page); void (*_flush_cache_sigtramp)(unsigned long addr); void (*_flush_page_to_ram)(struct page * page); +void (*_flush_icache_range)(unsigned long start, unsigned long end); +void (*_flush_icache_page)(struct vm_area_struct *vma, struct page *page); /* DMA cache operations. */ void (*_dma_cache_wback_inv)(unsigned long start, unsigned long size); void (*_dma_cache_wback)(unsigned long start, unsigned long size); void (*_dma_cache_inv)(unsigned long start, unsigned long size); -#ifdef CONFIG_CPU_R3000 -extern void ld_mmu_r2300(void); -#endif -#if defined(CONFIG_CPU_R4X00) || defined(CONFIG_CPU_R4300) || \ - defined(CONFIG_CPU_R5000) || defined(CONFIG_CPU_NEVADA) +extern void ld_mmu_r23000(void); extern void ld_mmu_r4xx0(void); -#endif -#ifdef CONFIG_CPU_R6000 +extern void ld_mmu_r5432(void); extern void ld_mmu_r6000(void); -#endif -#ifdef CONFIG_CPU_R8000 +extern void ld_mmu_rm7k(void); extern void ld_mmu_tfp(void); -#endif -#ifdef CONFIG_CPU_R10000 extern void ld_mmu_andes(void); -#endif +extern void ld_mmu_sb1(void); +extern void ld_mmu_mips32(void); void __init loadmmu(void) { - switch(mips_cputype) { -#ifdef CONFIG_CPU_R3000 - case CPU_R2000: - case CPU_R3000: - case CPU_R3000A: - case CPU_R3081E: - printk("Loading R[23]00 MMU routines.\n"); - ld_mmu_r2300(); - break; -#endif + if (mips_cpu.options & MIPS_CPU_4KTLB) { #if defined(CONFIG_CPU_R4X00) || defined(CONFIG_CPU_R4300) || \ defined(CONFIG_CPU_R5000) || defined(CONFIG_CPU_NEVADA) - case CPU_R4000PC: - case CPU_R4000SC: - case CPU_R4000MC: - case CPU_R4200: - case CPU_R4300: - case CPU_R4400PC: - case CPU_R4400SC: - case CPU_R4400MC: - case CPU_R4600: - case CPU_R4640: - case CPU_R4650: - case CPU_R4700: - case CPU_R5000: - case CPU_R5000A: - case CPU_NEVADA: printk("Loading R4000 MMU routines.\n"); ld_mmu_r4xx0(); - break; +#endif +#if defined(CONFIG_CPU_RM7000) + printk("Loading RM7000 MMU routines.\n"); + ld_mmu_rm7k(); +#endif +#if defined(CONFIG_CPU_R5432) + printk("Loading R5432 MMU routines.\n"); + ld_mmu_r5432(); #endif +#if defined(CONFIG_CPU_MIPS32) + printk("Loading MIPS32 MMU routines.\n"); + ld_mmu_mips32(); +#endif + } else switch(mips_cpu.cputype) { +#ifdef CONFIG_CPU_R3000 + case CPU_R2000: + case CPU_R3000: + case CPU_R3000A: + case CPU_TX3912: + case CPU_TX3922: + case CPU_TX3927: + case CPU_R3081E: + printk("Loading R[23]000 MMU routines.\n"); + ld_mmu_r23000(); + break; +#endif #ifdef CONFIG_CPU_R10000 case CPU_R10000: printk("Loading R10000 MMU routines.\n"); ld_mmu_andes(); break; #endif - +#ifdef CONFIG_CPU_SB1 + case CPU_SB1: + printk("Loading SB1 MMU routines.\n"); + ld_mmu_sb1(); + break; +#endif default: - /* XXX We need an generic routine in the MIPS port - * XXX to jabber stuff onto the screen on all machines - * XXX before the console is setup. The ARCS prom - * XXX routines look good for this, but only the SGI - * XXX code has a full library for that at this time. - */ panic("Yeee, unsupported mmu/cache architecture."); } } diff -u --recursive --new-file v2.4.6/linux/arch/mips/mm/mips32.c linux/arch/mips/mm/mips32.c --- v2.4.6/linux/arch/mips/mm/mips32.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/mm/mips32.c Wed Jul 4 11:50:39 2001 @@ -0,0 +1,1078 @@ +/* + * Kevin D. Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com + * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved. + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope 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. + * + * MIPS32 CPU variant specific MMU/Cache routines. + */ +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/mm.h> + +#include <asm/bootinfo.h> +#include <asm/cpu.h> +#include <asm/bcache.h> +#include <asm/io.h> +#include <asm/page.h> +#include <asm/pgtable.h> +#include <asm/system.h> +#include <asm/mmu_context.h> + +/* CP0 hazard avoidance. */ +#define BARRIER __asm__ __volatile__(".set noreorder\n\t" \ + "nop; nop; nop; nop; nop; nop;\n\t" \ + ".set reorder\n\t") + +/* Primary cache parameters. */ +static int icache_size, dcache_size; /* Size in bytes */ +static int ic_lsize, dc_lsize; /* LineSize in bytes */ + +/* Secondary cache (if present) parameters. */ +static unsigned int scache_size, sc_lsize; /* Again, in bytes */ + +#include <asm/cacheops.h> +#include <asm/mips32_cache.h> + +#undef DEBUG_CACHE + +/* + * Dummy cache handling routines for machines without boardcaches + */ +static void no_sc_noop(void) {} + +static struct bcache_ops no_sc_ops = { + (void *)no_sc_noop, (void *)no_sc_noop, + (void *)no_sc_noop, (void *)no_sc_noop +}; + +struct bcache_ops *bcops = &no_sc_ops; + + +/* + * Zero an entire page. + */ + +static void mips32_clear_page_dc(unsigned long page) +{ + unsigned long i; + + if (mips_cpu.options & MIPS_CPU_CACHE_CDEX) + { + for (i=page; i<page+PAGE_SIZE; i+=dc_lsize) + { + __asm__ __volatile__( + ".set\tnoreorder\n\t" + ".set\tnoat\n\t" + ".set\tmips3\n\t" + "cache\t%2,(%0)\n\t" + ".set\tmips0\n\t" + ".set\tat\n\t" + ".set\treorder" + :"=r" (i) + :"0" (i), + "I" (Create_Dirty_Excl_D)); + } + } + for (i=page; i<page+PAGE_SIZE; i+=4) + *(unsigned long *)(i) = 0; +} + +static void mips32_clear_page_sc(unsigned long page) +{ + unsigned long i; + + if (mips_cpu.options & MIPS_CPU_CACHE_CDEX) + { + for (i=page; i<page+PAGE_SIZE; i+=sc_lsize) + { + __asm__ __volatile__( + ".set\tnoreorder\n\t" + ".set\tnoat\n\t" + ".set\tmips3\n\t" + "cache\t%2,(%0)\n\t" + ".set\tmips0\n\t" + ".set\tat\n\t" + ".set\treorder" + :"=r" (i) + :"0" (i), + "I" (Create_Dirty_Excl_SD)); + } + } + for (i=page; i<page+PAGE_SIZE; i+=4) + *(unsigned long *)(i) = 0; +} + +static void mips32_copy_page_dc(unsigned long to, unsigned long from) +{ + unsigned long i; + + if (mips_cpu.options & MIPS_CPU_CACHE_CDEX) + { + for (i=to; i<to+PAGE_SIZE; i+=dc_lsize) + { + __asm__ __volatile__( + ".set\tnoreorder\n\t" + ".set\tnoat\n\t" + ".set\tmips3\n\t" + "cache\t%2,(%0)\n\t" + ".set\tmips0\n\t" + ".set\tat\n\t" + ".set\treorder" + :"=r" (i) + :"0" (i), + "I" (Create_Dirty_Excl_D)); + } + } + for (i=0; i<PAGE_SIZE; i+=4) + *(unsigned long *)(to+i) = *(unsigned long *)(from+i); +} + +static void mips32_copy_page_sc(unsigned long to, unsigned long from) +{ + unsigned long i; + + if (mips_cpu.options & MIPS_CPU_CACHE_CDEX) + { + for (i=to; i<to+PAGE_SIZE; i+=sc_lsize) + { + __asm__ __volatile__( + ".set\tnoreorder\n\t" + ".set\tnoat\n\t" + ".set\tmips3\n\t" + "cache\t%2,(%0)\n\t" + ".set\tmips0\n\t" + ".set\tat\n\t" + ".set\treorder" + :"=r" (i) + :"0" (i), + "I" (Create_Dirty_Excl_SD)); + } + } + for (i=0; i<PAGE_SIZE; i+=4) + *(unsigned long *)(to+i) = *(unsigned long *)(from+i); +} + +static inline void mips32_flush_cache_all_sc(void) +{ + unsigned long flags; + + __save_and_cli(flags); + blast_dcache(); blast_icache(); blast_scache(); + __restore_flags(flags); +} + +static inline void mips32_flush_cache_all_pc(void) +{ + unsigned long flags; + + __save_and_cli(flags); + blast_dcache(); blast_icache(); + __restore_flags(flags); +} + +static void +mips32_flush_cache_range_sc(struct mm_struct *mm, + unsigned long start, + unsigned long end) +{ + struct vm_area_struct *vma; + unsigned long flags; + + if(mm->context == 0) + return; + + start &= PAGE_MASK; +#ifdef DEBUG_CACHE + printk("crange[%d,%08lx,%08lx]", (int)mm->context, start, end); +#endif + vma = find_vma(mm, start); + if(vma) { + if(mm->context != current->mm->context) { + mips32_flush_cache_all_sc(); + } else { + pgd_t *pgd; + pmd_t *pmd; + pte_t *pte; + + __save_and_cli(flags); + while(start < end) { + pgd = pgd_offset(mm, start); + pmd = pmd_offset(pgd, start); + pte = pte_offset(pmd, start); + + if(pte_val(*pte) & _PAGE_VALID) + blast_scache_page(start); + start += PAGE_SIZE; + } + __restore_flags(flags); + } + } +} + +static void mips32_flush_cache_range_pc(struct mm_struct *mm, + unsigned long start, + unsigned long end) +{ + if(mm->context != 0) { + unsigned long flags; + +#ifdef DEBUG_CACHE + printk("crange[%d,%08lx,%08lx]", (int)mm->context, start, end); +#endif + __save_and_cli(flags); + blast_dcache(); blast_icache(); + __restore_flags(flags); + } +} + +/* + * On architectures like the Sparc, we could get rid of lines in + * the cache created only by a certain context, but on the MIPS + * (and actually certain Sparc's) we cannot. + */ +static void mips32_flush_cache_mm_sc(struct mm_struct *mm) +{ + if(mm->context != 0) { +#ifdef DEBUG_CACHE + printk("cmm[%d]", (int)mm->context); +#endif + mips32_flush_cache_all_sc(); + } +} + +static void mips32_flush_cache_mm_pc(struct mm_struct *mm) +{ + if(mm->context != 0) { +#ifdef DEBUG_CACHE + printk("cmm[%d]", (int)mm->context); +#endif + mips32_flush_cache_all_pc(); + } +} + + + + + +static void mips32_flush_cache_page_sc(struct vm_area_struct *vma, + unsigned long page) +{ + struct mm_struct *mm = vma->vm_mm; + unsigned long flags; + pgd_t *pgdp; + pmd_t *pmdp; + pte_t *ptep; + + /* + * If ownes no valid ASID yet, cannot possibly have gotten + * this page into the cache. + */ + if (mm->context == 0) + return; + +#ifdef DEBUG_CACHE + printk("cpage[%d,%08lx]", (int)mm->context, page); +#endif + __save_and_cli(flags); + page &= PAGE_MASK; + pgdp = pgd_offset(mm, page); + pmdp = pmd_offset(pgdp, page); + ptep = pte_offset(pmdp, page); + + /* + * If the page isn't marked valid, the page cannot possibly be + * in the cache. + */ + if (!(pte_val(*ptep) & _PAGE_VALID)) + goto out; + + /* + * Doing flushes for another ASID than the current one is + * too difficult since R4k caches do a TLB translation + * for every cache flush operation. So we do indexed flushes + * in that case, which doesn't overly flush the cache too much. + */ + if (mm->context != current->active_mm->context) { + /* + * Do indexed flush, too much work to get the (possible) + * tlb refills to work correctly. + */ + page = (KSEG0 + (page & (scache_size - 1))); + blast_dcache_page_indexed(page); + blast_scache_page_indexed(page); + } else + blast_scache_page(page); +out: + __restore_flags(flags); +} + +static void mips32_flush_cache_page_pc(struct vm_area_struct *vma, + unsigned long page) +{ + struct mm_struct *mm = vma->vm_mm; + unsigned long flags; + pgd_t *pgdp; + pmd_t *pmdp; + pte_t *ptep; + + /* + * If ownes no valid ASID yet, cannot possibly have gotten + * this page into the cache. + */ + if (mm->context == 0) + return; + +#ifdef DEBUG_CACHE + printk("cpage[%d,%08lx]", (int)mm->context, page); +#endif + __save_and_cli(flags); + page &= PAGE_MASK; + pgdp = pgd_offset(mm, page); + pmdp = pmd_offset(pgdp, page); + ptep = pte_offset(pmdp, page); + + /* + * If the page isn't marked valid, the page cannot possibly be + * in the cache. + */ + if (!(pte_val(*ptep) & _PAGE_VALID)) + goto out; + + /* + * Doing flushes for another ASID than the current one is + * too difficult since Mips32 caches do a TLB translation + * for every cache flush operation. So we do indexed flushes + * in that case, which doesn't overly flush the cache too much. + */ + if (mm == current->active_mm) { + blast_dcache_page(page); + } else { + /* Do indexed flush, too much work to get the (possible) + * tlb refills to work correctly. + */ + page = (KSEG0 + (page & (dcache_size - 1))); + blast_dcache_page_indexed(page); + } +out: + __restore_flags(flags); +} + +/* If the addresses passed to these routines are valid, they are + * either: + * + * 1) In KSEG0, so we can do a direct flush of the page. + * 2) In KSEG2, and since every process can translate those + * addresses all the time in kernel mode we can do a direct + * flush. + * 3) In KSEG1, no flush necessary. + */ +static void mips32_flush_page_to_ram_sc(struct page *page) +{ + blast_scache_page((unsigned long)page_address(page)); +} + +static void mips32_flush_page_to_ram_pc(struct page *page) +{ + blast_dcache_page((unsigned long)page_address(page)); +} + +static void +mips32_flush_icache_page_s(struct vm_area_struct *vma, struct page *page) +{ + /* + * We did an scache flush therefore PI is already clean. + */ +} + +static void +mips32_flush_icache_range(unsigned long start, unsigned long end) +{ + flush_cache_all(); +} + +static void +mips32_flush_icache_page(struct vm_area_struct *vma, struct page *page) +{ + int address; + + if (!(vma->vm_flags & VM_EXEC)) + return; + + address = KSEG0 + ((unsigned long)page_address(page) & PAGE_MASK & (dcache_size - 1)); + blast_icache_page_indexed(address); +} + +/* + * Writeback and invalidate the primary cache dcache before DMA. + */ +static void +mips32_dma_cache_wback_inv_pc(unsigned long addr, unsigned long size) +{ + unsigned long end, a; + unsigned int flags; + + if (size >= dcache_size) { + flush_cache_all(); + } else { + __save_and_cli(flags); + a = addr & ~(dc_lsize - 1); + end = (addr + size) & ~(dc_lsize - 1); + while (1) { + flush_dcache_line(a); /* Hit_Writeback_Inv_D */ + if (a == end) break; + a += dc_lsize; + } + __restore_flags(flags); + } + bc_wback_inv(addr, size); +} + +static void +mips32_dma_cache_wback_inv_sc(unsigned long addr, unsigned long size) +{ + unsigned long end, a; + + if (size >= scache_size) { + flush_cache_all(); + return; + } + + a = addr & ~(sc_lsize - 1); + end = (addr + size) & ~(sc_lsize - 1); + while (1) { + flush_scache_line(a); /* Hit_Writeback_Inv_SD */ + if (a == end) break; + a += sc_lsize; + } +} + +static void +mips32_dma_cache_inv_pc(unsigned long addr, unsigned long size) +{ + unsigned long end, a; + unsigned int flags; + + if (size >= dcache_size) { + flush_cache_all(); + } else { + __save_and_cli(flags); + a = addr & ~(dc_lsize - 1); + end = (addr + size) & ~(dc_lsize - 1); + while (1) { + flush_dcache_line(a); /* Hit_Writeback_Inv_D */ + if (a == end) break; + a += dc_lsize; + } + __restore_flags(flags); + } + + bc_inv(addr, size); +} + +static void +mips32_dma_cache_inv_sc(unsigned long addr, unsigned long size) +{ + unsigned long end, a; + + if (size >= scache_size) { + flush_cache_all(); + return; + } + + a = addr & ~(sc_lsize - 1); + end = (addr + size) & ~(sc_lsize - 1); + while (1) { + flush_scache_line(a); /* Hit_Writeback_Inv_SD */ + if (a == end) break; + a += sc_lsize; + } +} + +static void +mips32_dma_cache_wback(unsigned long addr, unsigned long size) +{ + panic("mips32_dma_cache called - should not happen.\n"); +} + +/* + * While we're protected against bad userland addresses we don't care + * very much about what happens in that case. Usually a segmentation + * fault will dump the process later on anyway ... + */ +static void mips32_flush_cache_sigtramp(unsigned long addr) +{ + unsigned long daddr, iaddr; + + daddr = addr & ~(dc_lsize - 1); + protected_writeback_dcache_line(daddr); + protected_writeback_dcache_line(daddr + dc_lsize); + iaddr = addr & ~(ic_lsize - 1); + protected_flush_icache_line(iaddr); + protected_flush_icache_line(iaddr + ic_lsize); +} + +#undef DEBUG_TLB +#undef DEBUG_TLBUPDATE + +void flush_tlb_all(void) +{ + unsigned long flags; + unsigned long old_ctx; + int entry; + +#ifdef DEBUG_TLB + printk("[tlball]"); +#endif + + __save_and_cli(flags); + /* Save old context and create impossible VPN2 value */ + old_ctx = (get_entryhi() & 0xff); + set_entryhi(KSEG0); + set_entrylo0(0); + set_entrylo1(0); + BARRIER; + + entry = get_wired(); + + /* Blast 'em all away. */ + while(entry < mips_cpu.tlbsize) { + /* Make sure all entries differ. */ + set_entryhi(KSEG0+entry*0x2000); + set_index(entry); + BARRIER; + tlb_write_indexed(); + BARRIER; + entry++; + } + BARRIER; + set_entryhi(old_ctx); + __restore_flags(flags); +} + +void flush_tlb_mm(struct mm_struct *mm) +{ + if (mm->context != 0) { + unsigned long flags; + +#ifdef DEBUG_TLB + printk("[tlbmm<%d>]", mm->context); +#endif + __save_and_cli(flags); + get_new_mmu_context(mm, asid_cache); + if (mm == current->active_mm) + set_entryhi(mm->context & 0xff); + __restore_flags(flags); + } +} + +void flush_tlb_range(struct mm_struct *mm, unsigned long start, + unsigned long end) +{ + if(mm->context != 0) { + unsigned long flags; + int size; + +#ifdef DEBUG_TLB + printk("[tlbrange<%02x,%08lx,%08lx>]", (mm->context & 0xff), + start, end); +#endif + __save_and_cli(flags); + size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT; + size = (size + 1) >> 1; + if(size <= mips_cpu.tlbsize/2) { + int oldpid = (get_entryhi() & 0xff); + int newpid = (mm->context & 0xff); + + start &= (PAGE_MASK << 1); + end += ((PAGE_SIZE << 1) - 1); + end &= (PAGE_MASK << 1); + while(start < end) { + int idx; + + set_entryhi(start | newpid); + start += (PAGE_SIZE << 1); + BARRIER; + tlb_probe(); + BARRIER; + idx = get_index(); + set_entrylo0(0); + set_entrylo1(0); + if(idx < 0) + continue; + /* Make sure all entries differ. */ + set_entryhi(KSEG0+idx*0x2000); + BARRIER; + tlb_write_indexed(); + BARRIER; + } + set_entryhi(oldpid); + } else { + get_new_mmu_context(mm, asid_cache); + if (mm == current->active_mm) + set_entryhi(mm->context & 0xff); + } + __restore_flags(flags); + } +} + +void flush_tlb_page(struct vm_area_struct *vma, unsigned long page) +{ + if (vma->vm_mm->context != 0) { + unsigned long flags; + int oldpid, newpid, idx; + +#ifdef DEBUG_TLB + printk("[tlbpage<%d,%08lx>]", vma->vm_mm->context, page); +#endif + newpid = (vma->vm_mm->context & 0xff); + page &= (PAGE_MASK << 1); + __save_and_cli(flags); + oldpid = (get_entryhi() & 0xff); + set_entryhi(page | newpid); + BARRIER; + tlb_probe(); + BARRIER; + idx = get_index(); + set_entrylo0(0); + set_entrylo1(0); + if(idx < 0) + goto finish; + /* Make sure all entries differ. */ + set_entryhi(KSEG0+idx*0x2000); + BARRIER; + tlb_write_indexed(); + + finish: + BARRIER; + set_entryhi(oldpid); + __restore_flags(flags); + } +} + +void pgd_init(unsigned long page) +{ + unsigned long *p = (unsigned long *) page; + int i; + + for(i = 0; i < USER_PTRS_PER_PGD; i+=8) { + p[i + 0] = (unsigned long) invalid_pte_table; + p[i + 1] = (unsigned long) invalid_pte_table; + p[i + 2] = (unsigned long) invalid_pte_table; + p[i + 3] = (unsigned long) invalid_pte_table; + p[i + 4] = (unsigned long) invalid_pte_table; + p[i + 5] = (unsigned long) invalid_pte_table; + p[i + 6] = (unsigned long) invalid_pte_table; + p[i + 7] = (unsigned long) invalid_pte_table; + } +} + +/* + * Updates the TLB with the new pte(s). + */ +void update_mmu_cache(struct vm_area_struct * vma, + unsigned long address, pte_t pte) +{ + unsigned long flags; + pgd_t *pgdp; + pmd_t *pmdp; + pte_t *ptep; + int idx, pid; + + /* + * Handle debugger faulting in for debugee. + */ + if (current->active_mm != vma->vm_mm) + return; + + pid = get_entryhi() & 0xff; + +#ifdef DEBUG_TLB + if((pid != (vma->vm_mm->context & 0xff)) || (vma->vm_mm->context == 0)) { + printk("update_mmu_cache: Wheee, bogus tlbpid mmpid=%d tlbpid=%d\n", + (int) (vma->vm_mm->context & 0xff), pid); + } +#endif + + __save_and_cli(flags); + address &= (PAGE_MASK << 1); + set_entryhi(address | (pid)); + pgdp = pgd_offset(vma->vm_mm, address); + BARRIER; + tlb_probe(); + BARRIER; + pmdp = pmd_offset(pgdp, address); + idx = get_index(); + ptep = pte_offset(pmdp, address); + BARRIER; + set_entrylo0(pte_val(*ptep++) >> 6); + set_entrylo1(pte_val(*ptep) >> 6); + set_entryhi(address | (pid)); + BARRIER; + if(idx < 0) { + tlb_write_random(); + } else { + tlb_write_indexed(); + } + BARRIER; + set_entryhi(pid); + BARRIER; + __restore_flags(flags); +} + +void show_regs(struct pt_regs * regs) +{ + /* Saved main processor registers. */ + printk("$0 : %08lx %08lx %08lx %08lx\n", + 0UL, regs->regs[1], regs->regs[2], regs->regs[3]); + printk("$4 : %08lx %08lx %08lx %08lx\n", + regs->regs[4], regs->regs[5], regs->regs[6], regs->regs[7]); + printk("$8 : %08lx %08lx %08lx %08lx\n", + regs->regs[8], regs->regs[9], regs->regs[10], regs->regs[11]); + printk("$12: %08lx %08lx %08lx %08lx\n", + regs->regs[12], regs->regs[13], regs->regs[14], regs->regs[15]); + printk("$16: %08lx %08lx %08lx %08lx\n", + regs->regs[16], regs->regs[17], regs->regs[18], regs->regs[19]); + printk("$20: %08lx %08lx %08lx %08lx\n", + regs->regs[20], regs->regs[21], regs->regs[22], regs->regs[23]); + printk("$24: %08lx %08lx\n", + regs->regs[24], regs->regs[25]); + printk("$28: %08lx %08lx %08lx %08lx\n", + regs->regs[28], regs->regs[29], regs->regs[30], regs->regs[31]); + + /* Saved cp0 registers. */ + printk("epc : %08lx\nStatus: %08lx\nCause : %08lx\n", + regs->cp0_epc, regs->cp0_status, regs->cp0_cause); +} + +void add_wired_entry(unsigned long entrylo0, unsigned long entrylo1, + unsigned long entryhi, unsigned long pagemask) +{ + unsigned long flags; + unsigned long wired; + unsigned long old_pagemask; + unsigned long old_ctx; + + __save_and_cli(flags); + /* Save old context and create impossible VPN2 value */ + old_ctx = (get_entryhi() & 0xff); + old_pagemask = get_pagemask(); + wired = get_wired(); + set_wired (wired + 1); + set_index (wired); + BARRIER; + set_pagemask (pagemask); + set_entryhi(entryhi); + set_entrylo0(entrylo0); + set_entrylo1(entrylo1); + BARRIER; + tlb_write_indexed(); + BARRIER; + + set_entryhi(old_ctx); + BARRIER; + set_pagemask (old_pagemask); + flush_tlb_all(); + __restore_flags(flags); +} + +/* Detect and size the various caches. */ +static void __init probe_icache(unsigned long config) +{ + unsigned long config1; + unsigned int lsize; + + if (!(config & (1 << 31))) { + /* + * Not a MIPS32 complainant CPU. + * Config 1 register not supported, we assume R4k style. + */ + icache_size = 1 << (12 + ((config >> 9) & 7)); + ic_lsize = 16 << ((config >> 5) & 1); + mips_cpu.icache.linesz = ic_lsize; + + /* + * We cannot infer associativity - assume direct map + * unless probe template indicates otherwise + */ + if(!mips_cpu.icache.ways) mips_cpu.icache.ways = 1; + mips_cpu.icache.sets = + (icache_size / ic_lsize) / mips_cpu.icache.ways; + } else { + config1 = read_mips32_cp0_config1(); + + if ((lsize = ((config1 >> 19) & 7))) + mips_cpu.icache.linesz = 2 << lsize; + else + mips_cpu.icache.linesz = lsize; + mips_cpu.icache.sets = 64 << ((config1 >> 22) & 7); + mips_cpu.icache.ways = 1 + ((config1 >> 16) & 7); + + ic_lsize = mips_cpu.icache.linesz; + icache_size = mips_cpu.icache.sets * mips_cpu.icache.ways * + ic_lsize; + } + printk("Primary instruction cache %dkb, linesize %d bytes (%d ways)\n", + icache_size >> 10, ic_lsize, mips_cpu.icache.ways); +} + +static void __init probe_dcache(unsigned long config) +{ + unsigned long config1; + unsigned int lsize; + + if (!(config & (1 << 31))) { + /* + * Not a MIPS32 complainant CPU. + * Config 1 register not supported, we assume R4k style. + */ + dcache_size = 1 << (12 + ((config >> 6) & 7)); + dc_lsize = 16 << ((config >> 4) & 1); + mips_cpu.dcache.linesz = dc_lsize; + /* + * We cannot infer associativity - assume direct map + * unless probe template indicates otherwise + */ + if(!mips_cpu.dcache.ways) mips_cpu.dcache.ways = 1; + mips_cpu.dcache.sets = + (dcache_size / dc_lsize) / mips_cpu.dcache.ways; + } else { + config1 = read_mips32_cp0_config1(); + + if ((lsize = ((config1 >> 10) & 7))) + mips_cpu.dcache.linesz = 2 << lsize; + else + mips_cpu.dcache.linesz= lsize; + mips_cpu.dcache.sets = 64 << ((config1 >> 13) & 7); + mips_cpu.dcache.ways = 1 + ((config1 >> 7) & 7); + + dc_lsize = mips_cpu.dcache.linesz; + dcache_size = + mips_cpu.dcache.sets * mips_cpu.dcache.ways + * dc_lsize; + } + printk("Primary data cache %dkb, linesize %d bytes (%d ways)\n", + dcache_size >> 10, dc_lsize, mips_cpu.dcache.ways); +} + + +/* If you even _breathe_ on this function, look at the gcc output + * and make sure it does not pop things on and off the stack for + * the cache sizing loop that executes in KSEG1 space or else + * you will crash and burn badly. You have been warned. + */ +static int __init probe_scache(unsigned long config) +{ + extern unsigned long stext; + unsigned long flags, addr, begin, end, pow2; + int tmp; + + if (mips_cpu.scache.flags == MIPS_CACHE_NOT_PRESENT) + return 0; + + tmp = ((config >> 17) & 1); + if(tmp) + return 0; + tmp = ((config >> 22) & 3); + switch(tmp) { + case 0: + sc_lsize = 16; + break; + case 1: + sc_lsize = 32; + break; + case 2: + sc_lsize = 64; + break; + case 3: + sc_lsize = 128; + break; + } + + begin = (unsigned long) &stext; + begin &= ~((4 * 1024 * 1024) - 1); + end = begin + (4 * 1024 * 1024); + + /* This is such a bitch, you'd think they would make it + * easy to do this. Away you daemons of stupidity! + */ + __save_and_cli(flags); + + /* Fill each size-multiple cache line with a valid tag. */ + pow2 = (64 * 1024); + for(addr = begin; addr < end; addr = (begin + pow2)) { + unsigned long *p = (unsigned long *) addr; + __asm__ __volatile__("nop" : : "r" (*p)); /* whee... */ + pow2 <<= 1; + } + + /* Load first line with zero (therefore invalid) tag. */ + set_taglo(0); + set_taghi(0); + __asm__ __volatile__("nop; nop; nop; nop;"); /* avoid the hazard */ + __asm__ __volatile__("\n\t.set noreorder\n\t" + ".set mips3\n\t" + "cache 8, (%0)\n\t" + ".set mips0\n\t" + ".set reorder\n\t" : : "r" (begin)); + __asm__ __volatile__("\n\t.set noreorder\n\t" + ".set mips3\n\t" + "cache 9, (%0)\n\t" + ".set mips0\n\t" + ".set reorder\n\t" : : "r" (begin)); + __asm__ __volatile__("\n\t.set noreorder\n\t" + ".set mips3\n\t" + "cache 11, (%0)\n\t" + ".set mips0\n\t" + ".set reorder\n\t" : : "r" (begin)); + + /* Now search for the wrap around point. */ + pow2 = (128 * 1024); + tmp = 0; + for(addr = (begin + (128 * 1024)); addr < (end); addr = (begin + pow2)) { + __asm__ __volatile__("\n\t.set noreorder\n\t" + ".set mips3\n\t" + "cache 7, (%0)\n\t" + ".set mips0\n\t" + ".set reorder\n\t" : : "r" (addr)); + __asm__ __volatile__("nop; nop; nop; nop;"); /* hazard... */ + if(!get_taglo()) + break; + pow2 <<= 1; + } + __restore_flags(flags); + addr -= begin; + printk("Secondary cache sized at %dK linesize %d bytes.\n", + (int) (addr >> 10), sc_lsize); + scache_size = addr; + return 1; +} + +static void __init setup_noscache_funcs(void) +{ + _clear_page = (void *)mips32_clear_page_dc; + _copy_page = (void *)mips32_copy_page_dc; + _flush_cache_all = mips32_flush_cache_all_pc; + ___flush_cache_all = mips32_flush_cache_all_pc; + _flush_cache_mm = mips32_flush_cache_mm_pc; + _flush_cache_range = mips32_flush_cache_range_pc; + _flush_cache_page = mips32_flush_cache_page_pc; + _flush_page_to_ram = mips32_flush_page_to_ram_pc; + + _flush_icache_page = mips32_flush_icache_page; + + _dma_cache_wback_inv = mips32_dma_cache_wback_inv_pc; + _dma_cache_wback = mips32_dma_cache_wback; + _dma_cache_inv = mips32_dma_cache_inv_pc; +} + +static void __init setup_scache_funcs(void) +{ + _flush_cache_all = mips32_flush_cache_all_sc; + ___flush_cache_all = mips32_flush_cache_all_sc; + _flush_cache_mm = mips32_flush_cache_mm_sc; + _flush_cache_range = mips32_flush_cache_range_sc; + _flush_cache_page = mips32_flush_cache_page_sc; + _flush_page_to_ram = mips32_flush_page_to_ram_sc; + _clear_page = (void *)mips32_clear_page_sc; + _copy_page = (void *)mips32_copy_page_sc; + + _flush_icache_page = mips32_flush_icache_page_s; + + _dma_cache_wback_inv = mips32_dma_cache_wback_inv_sc; + _dma_cache_wback = mips32_dma_cache_wback; + _dma_cache_inv = mips32_dma_cache_inv_sc; +} + +typedef int (*probe_func_t)(unsigned long); + +static inline void __init setup_scache(unsigned int config) +{ + probe_func_t probe_scache_kseg1; + int sc_present = 0; + + /* Maybe the cpu knows about a l2 cache? */ + probe_scache_kseg1 = (probe_func_t) (KSEG1ADDR(&probe_scache)); + sc_present = probe_scache_kseg1(config); + + if (sc_present) { + mips_cpu.scache.linesz = sc_lsize; + /* + * We cannot infer associativity - assume direct map + * unless probe template indicates otherwise + */ + if(!mips_cpu.scache.ways) mips_cpu.scache.ways = 1; + mips_cpu.scache.sets = + (scache_size / sc_lsize) / mips_cpu.scache.ways; + + setup_scache_funcs(); + return; + } + + setup_noscache_funcs(); +} + +static void __init probe_tlb(unsigned long config) +{ + unsigned long config1; + + if (!(config & (1 << 31))) { + /* + * Not a MIPS32 complainant CPU. + * Config 1 register not supported, we assume R4k style. + */ + mips_cpu.tlbsize = 48; + } else { + config1 = read_mips32_cp0_config1(); + if (!((config >> 7) & 3)) + panic("No MMU present"); + else + mips_cpu.tlbsize = ((config1 >> 25) & 0x3f) + 1; + } + + printk("Number of TLB entries %d.\n", mips_cpu.tlbsize); +} + +void __init ld_mmu_mips32(void) +{ + unsigned long config = read_32bit_cp0_register(CP0_CONFIG); + + printk("CPU revision is: %08x\n", read_32bit_cp0_register(CP0_PRID)); + +#ifdef CONFIG_MIPS_UNCACHED + change_cp0_config(CONF_CM_CMASK, CONF_CM_UNCACHED); +#else + change_cp0_config(CONF_CM_CMASK, CONF_CM_CACHABLE_NONCOHERENT); +#endif + + probe_icache(config); + probe_dcache(config); + setup_scache(config); + probe_tlb(config); + + _flush_cache_sigtramp = mips32_flush_cache_sigtramp; + _flush_icache_range = mips32_flush_icache_range; /* Ouch */ + + __flush_cache_all(); + write_32bit_cp0_register(CP0_WIRED, 0); + + /* + * You should never change this register: + * - The entire mm handling assumes the c0_pagemask register to + * be set for 4kb pages. + */ + write_32bit_cp0_register(CP0_PAGEMASK, PM_4K); + flush_tlb_all(); +} diff -u --recursive --new-file v2.4.6/linux/arch/mips/mm/r2300.c linux/arch/mips/mm/r2300.c --- v2.4.6/linux/arch/mips/mm/r2300.c Thu Jul 27 18:36:54 2000 +++ linux/arch/mips/mm/r2300.c Wed Jul 4 11:50:39 2001 @@ -4,7 +4,8 @@ * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) * * with a lot of changes to make this thing work for R3000s - * Copyright (C) 1998, 2000 Harald Koerfgen + * Tx39XX R4k style caches added. HK + * Copyright (C) 1998, 1999, 2000 Harald Koerfgen * Copyright (C) 1998 Gleb Raiko & Vladimir Roganov */ #include <linux/init.h> @@ -19,6 +20,8 @@ #include <asm/isadep.h> #include <asm/io.h> #include <asm/wbflush.h> +#include <asm/bootinfo.h> +#include <asm/cpu.h> /* * According to the paper written by D. Miller about Linux cache & TLB @@ -27,15 +30,17 @@ * Define this if driver does not handle cache consistency during DMA ops. */ -/* Primary cache parameters. */ -static int icache_size, dcache_size; /* Size in bytes */ -/* the linesizes are usually fixed on R3000s */ +/* For R3000 cores with R4000 style caches */ +static unsigned long icache_size, dcache_size; /* Size in bytes */ +static unsigned long icache_lsize, dcache_lsize; /* Size in bytes */ +static unsigned long scache_size = 0; + +#include <asm/cacheops.h> +#include <asm/r4kcache.h> #undef DEBUG_TLB #undef DEBUG_CACHE -#define NTLB_ENTRIES 64 /* Fixed on all R23000 variants... */ - /* page functions */ void r3k_clear_page(void * page) { @@ -120,7 +125,7 @@ p = (volatile unsigned long *) KSEG0; - save_and_cli(flags); + flags = read_32bit_cp0_register(CP0_STATUS); /* isolate cache space */ write_32bit_cp0_register(CP0_STATUS, (ca_flags|flags)&~ST0_IEC); @@ -142,34 +147,30 @@ if (size > 0x40000) size = 0; } - restore_flags(flags); + write_32bit_cp0_register(CP0_STATUS, flags); return size * sizeof(*p); } -static void __init probe_dcache(void) +static void __init r3k_probe_cache(void) { dcache_size = r3k_cache_size(ST0_ISC); - printk("Primary data cache %dkb, linesize 4 bytes\n", - dcache_size >> 10); -} + dcache_lsize = 4; -static void __init probe_icache(void) -{ icache_size = r3k_cache_size(ST0_ISC|ST0_SWC); - printk("Primary instruction cache %dkb, linesize 4 bytes\n", - icache_size >> 10); + icache_lsize = 4; } -static void r3k_flush_icache_range(unsigned long start, unsigned long size) +static void r3k_flush_icache_range(unsigned long start, unsigned long end) { - unsigned long i, flags; + unsigned long size, i, flags; volatile unsigned char *p = (char *)start; + size = end - start; if (size > icache_size) size = icache_size; - save_and_cli(flags); + flags = read_32bit_cp0_register(CP0_STATUS); /* isolate cache space */ write_32bit_cp0_register(CP0_STATUS, (ST0_ISC|ST0_SWC|flags)&~ST0_IEC); @@ -211,18 +212,19 @@ p += 0x080; } - restore_flags(flags); + write_32bit_cp0_register(CP0_STATUS,flags); } -static void r3k_flush_dcache_range(unsigned long start, unsigned long size) +static void r3k_flush_dcache_range(unsigned long start, unsigned long end) { - unsigned long i, flags; + unsigned long size, i, flags; volatile unsigned char *p = (char *)start; + size = end - start; if (size > dcache_size) size = dcache_size; - save_and_cli(flags); + flags = read_32bit_cp0_register(CP0_STATUS); /* isolate cache space */ write_32bit_cp0_register(CP0_STATUS, (ST0_ISC|flags)&~ST0_IEC); @@ -264,7 +266,7 @@ p += 0x080; } - restore_flags(flags); + write_32bit_cp0_register(CP0_STATUS,flags); } static inline unsigned long get_phys_page (unsigned long addr, @@ -279,15 +281,15 @@ pmd = pmd_offset(pgd, addr); pte = pte_offset(pmd, addr); - if((physpage = pte_val(*pte)) & _PAGE_VALID) - return KSEG1ADDR(physpage & PAGE_MASK); - else - return 0; + if ((physpage = pte_val(*pte)) & _PAGE_VALID) + return KSEG0ADDR(physpage & PAGE_MASK); + + return 0; } static inline void r3k_flush_cache_all(void) { - r3k_flush_icache_range(KSEG0, icache_size); + r3k_flush_icache_range(KSEG0, KSEG0 + icache_size); } static void r3k_flush_cache_mm(struct mm_struct *mm) @@ -301,9 +303,8 @@ } } -static void r3k_flush_cache_range(struct mm_struct *mm, - unsigned long start, - unsigned long end) +static void r3k_flush_cache_range(struct mm_struct *mm, unsigned long start, + unsigned long end) { struct vm_area_struct *vma; @@ -315,21 +316,22 @@ printk("crange[%d,%08lx,%08lx]", (int)mm->context, start, end); #endif vma = find_vma(mm, start); - if (vma) { - if (mm->context != current->active_mm->context) { - flush_cache_all(); - } else { - unsigned long flags, physpage; + if (!vma) + return; - save_and_cli(flags); - while (start < end) { - if ((physpage = get_phys_page(start, mm))) - r3k_flush_icache_range(physpage, PAGE_SIZE); - - start += PAGE_SIZE; - } - restore_flags(flags); + if (mm->context != current->active_mm->context) { + flush_cache_all(); + } else { + unsigned long flags, physpage; + + save_and_cli(flags); + while (start < end) { + if ((physpage = get_phys_page(start, mm))) + r3k_flush_icache_range(physpage, + physpage + PAGE_SIZE); + start += PAGE_SIZE; } + restore_flags(flags); } } @@ -348,8 +350,7 @@ unsigned long physpage; if ((physpage = get_phys_page(page, vma->vm_mm))) - r3k_flush_icache_range(physpage, PAGE_SIZE); - + r3k_flush_icache_range(physpage, physpage + PAGE_SIZE); } } @@ -360,6 +361,26 @@ */ } +static void r3k_flush_icache_page(struct vm_area_struct *vma, struct page *page) +{ + struct mm_struct *mm = vma->vm_mm; + unsigned long physpage; + + if (mm->context == 0) + return; + + if (!(vma->vm_flags & VM_EXEC)) + return; + +#ifdef DEBUG_CACHE + printk("cpage[%d,%08lx]", (int)mm->context, page); +#endif + + physpage = (unsigned long) page_address(page); + if (physpage) + r3k_flush_icache_range(physpage, physpage + PAGE_SIZE); +} + static void r3k_flush_cache_sigtramp(unsigned long addr) { unsigned long flags; @@ -367,26 +388,23 @@ #ifdef DEBUG_CACHE printk("csigtramp[%08lx]", addr); #endif - /* - * I am assuming an 8 Byte cacheline here. HK - */ - addr &= ~7; - save_and_cli(flags); + flags = read_32bit_cp0_register(CP0_STATUS); write_32bit_cp0_register(CP0_STATUS, (ST0_ISC|ST0_SWC|flags)&~ST0_IEC); asm ( "sb\t$0,0x000(%0)\n\t" + "sb\t$0,0x004(%0)\n\t" "sb\t$0,0x008(%0)\n\t" : : "r" (addr) ); - restore_flags(flags); + write_32bit_cp0_register(CP0_STATUS, flags); } static void r3k_dma_cache_wback_inv(unsigned long start, unsigned long size) { wbflush(); - r3k_flush_dcache_range(start, size); + r3k_flush_dcache_range(start, start + size); } /* TLB operations. */ @@ -403,7 +421,7 @@ save_and_cli(flags); old_ctx = (get_entryhi() & 0xfc0); write_32bit_cp0_register(CP0_ENTRYLO0, 0); - for(entry = 0; entry < NTLB_ENTRIES; entry++) { + for (entry = 8; entry < mips_cpu.tlbsize; entry++) { write_32bit_cp0_register(CP0_INDEX, entry << 8); write_32bit_cp0_register(CP0_ENTRYHI, ((entry | 0x80000) << 12)); __asm__ __volatile__("tlbwi"); @@ -418,7 +436,7 @@ unsigned long flags; #ifdef DEBUG_TLB - printk("[tlbmm<%d>]", mm->context); + printk("[tlbmm<%lu>]", (unsigned long) mm->context); #endif save_and_cli(flags); get_new_mmu_context(mm, asid_cache); @@ -429,19 +447,19 @@ } void flush_tlb_range(struct mm_struct *mm, unsigned long start, - unsigned long end) + unsigned long end) { if (mm->context != 0) { unsigned long flags; int size; #ifdef DEBUG_TLB - printk("[tlbrange<%02x,%08lx,%08lx>]", (mm->context & 0xfc0), - start, end); + printk("[tlbrange<%lu,0x%08lx,0x%08lx>]", + (mm->context & 0xfc0), start, end); #endif save_and_cli(flags); size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT; - if(size <= NTLB_ENTRIES) { + if(size <= mips_cpu.tlbsize) { int oldpid = (get_entryhi() & 0xfc0); int newpid = (mm->context & 0xfc0); @@ -478,7 +496,7 @@ int oldpid, newpid, idx; #ifdef DEBUG_TLB - printk("[tlbpage<%d,%08lx>]", vma->vm_mm->context, page); + printk("[tlbpage<%lu,0x%08lx>]", vma->vm_mm->context, page); #endif newpid = (vma->vm_mm->context & 0xfc0); page &= PAGE_MASK; @@ -531,8 +549,8 @@ "1" (PAGE_SIZE/(sizeof(pmd_t)*8))); } -void update_mmu_cache(struct vm_area_struct * vma, - unsigned long address, pte_t pte) +void update_mmu_cache(struct vm_area_struct * vma, unsigned long address, + pte_t pte) { unsigned long flags; pgd_t *pgdp; @@ -550,8 +568,8 @@ #ifdef DEBUG_TLB if((pid != (vma->vm_mm->context & 0xfc0)) || (vma->vm_mm->context == 0)) { - printk("update_mmu_cache: Wheee, bogus tlbpid mmpid=%d tlbpid=%d\n", - (int) (vma->vm_mm->context & 0xfc0), pid); + printk("update_mmu_cache: Wheee, bogus tlbpid mmpid=%lu tlbpid=%d\n", + (vma->vm_mm->context & 0xfc0), pid); } #endif @@ -576,19 +594,6 @@ printk("[HIT]"); #endif } -#if 0 - if(!strcmp(current->comm, "args")) { - printk("<"); - for(idx = 0; idx < NTLB_ENTRIES; idx++) { - set_index(idx); - tlb_read(); - address = get_entryhi(); - if((address & 0xfc0) != 0) - printk("[%08lx]", address); - } - printk(">\n"); - } -#endif set_entryhi(pid); restore_flags(flags); } @@ -626,33 +631,135 @@ (unsigned int) regs->cp0_cause); } +/* Todo: handle r4k-style TX39 TLB */ void add_wired_entry(unsigned long entrylo0, unsigned long entrylo1, - unsigned long entryhi, unsigned long pagemask) + unsigned long entryhi, unsigned long pagemask) { -printk("r3k_add_wired_entry"); - /* - * FIXME, to be done - */ + unsigned long flags; + unsigned long old_ctx; + static unsigned long wired = 0; + + if (wired < 8) { + save_and_cli(flags); + old_ctx = get_entryhi() & 0xfc0; + set_entrylo0(entrylo0); + set_entryhi(entryhi); + set_index(wired); + wired++; + tlb_write_indexed(); + set_entryhi(old_ctx); + flush_tlb_all(); + restore_flags(flags); + } } -void __init ld_mmu_r2300(void) +static void tx39_flush_icache_all(void ) { + + unsigned long start = KSEG0; + unsigned long end = (start + icache_size); + unsigned long dummy = 0; + + /* disable icache and stop streaming */ + __asm__ __volatile__( + ".set\tnoreorder\n\t" + "mfc0\t%0,$3\n\t" + "xori\t%0,32\n\t" + "mtc0\t%0,$3\n\t" + "j\t1f\n\t" + "nop\n\t" + "1:\t.set\treorder\n\t" + : : "r"(dummy)); + + /* invalidate icache */ + while (start < end) { + cache16_unroll32(start,Index_Invalidate_I); + start += 0x200; + } + + /* enable icache */ + __asm__ __volatile__( + ".set\tnoreorder\n\t" + "mfc0\t%0,$3\n\t" + "xori\t%0,32\n\t" + "mtc0\t%0,$3\n\t" + ".set\treorder\n\t" + : : "r"(dummy)); +} + +static __init void tx39_probe_cache(void) +{ + unsigned long config; + + config = read_32bit_cp0_register(CP0_CONF); + + icache_size = 1 << (10 + ((config >> 19) & 3)); + icache_lsize = 16; + + dcache_size = 1 << (10 + ((config >> 16) & 3)); + dcache_lsize = 4; +} + +void __init ld_mmu_r23000(void) +{ + unsigned long config; + printk("CPU revision is: %08x\n", read_32bit_cp0_register(CP0_PRID)); _clear_page = r3k_clear_page; _copy_page = r3k_copy_page; - probe_icache(); - probe_dcache(); - - _flush_cache_all = r3k_flush_cache_all; - _flush_cache_mm = r3k_flush_cache_mm; - _flush_cache_range = r3k_flush_cache_range; - _flush_cache_page = r3k_flush_cache_page; - _flush_cache_sigtramp = r3k_flush_cache_sigtramp; - _flush_page_to_ram = r3k_flush_page_to_ram; - - _dma_cache_wback_inv = r3k_dma_cache_wback_inv; + switch (mips_cpu.cputype) { + case CPU_R2000: + case CPU_R3000: + case CPU_R3000A: + case CPU_R3081: + case CPU_R3081E: + + r3k_probe_cache(); + + _flush_cache_all = r3k_flush_cache_all; + ___flush_cache_all = r3k_flush_cache_all; + _flush_cache_mm = r3k_flush_cache_mm; + _flush_cache_range = r3k_flush_cache_range; + _flush_cache_page = r3k_flush_cache_page; + _flush_cache_sigtramp = r3k_flush_cache_sigtramp; + _flush_page_to_ram = r3k_flush_page_to_ram; + _flush_icache_page = r3k_flush_icache_page; + _flush_icache_range = r3k_flush_icache_range; + + _dma_cache_wback_inv = r3k_dma_cache_wback_inv; + break; + + case CPU_TX3912: + case CPU_TX3922: + case CPU_TX3927: + + config=read_32bit_cp0_register(CP0_CONF); + config &= ~TX39_CONF_WBON; + write_32bit_cp0_register(CP0_CONF, config); + + tx39_probe_cache(); + + _flush_cache_all = tx39_flush_icache_all; + ___flush_cache_all = tx39_flush_icache_all; + _flush_cache_mm = tx39_flush_icache_all; + _flush_cache_range = tx39_flush_icache_all; + _flush_cache_page = tx39_flush_icache_all; + _flush_cache_sigtramp = tx39_flush_icache_all; + _flush_page_to_ram = r3k_flush_page_to_ram; + _flush_icache_page = tx39_flush_icache_all; + _flush_icache_range = tx39_flush_icache_all; + + _dma_cache_wback_inv = r3k_dma_cache_wback_inv; + + break; + } + + printk("Primary instruction cache %dkb, linesize %d bytes\n", + (int) (icache_size >> 10), (int) icache_lsize); + printk("Primary data cache %dkb, linesize %d bytes\n", + (int) (dcache_size >> 10), (int) dcache_lsize); flush_tlb_all(); } diff -u --recursive --new-file v2.4.6/linux/arch/mips/mm/r4xx0.c linux/arch/mips/mm/r4xx0.c --- v2.4.6/linux/arch/mips/mm/r4xx0.c Sun Aug 6 11:43:17 2000 +++ linux/arch/mips/mm/r4xx0.c Wed Jul 4 11:50:39 2001 @@ -19,12 +19,13 @@ #include <linux/sched.h> #include <linux/mm.h> +#include <asm/bootinfo.h> +#include <asm/cpu.h> #include <asm/bcache.h> #include <asm/io.h> #include <asm/page.h> #include <asm/pgtable.h> #include <asm/system.h> -#include <asm/bootinfo.h> #include <asm/mmu_context.h> /* CP0 hazard avoidance. */ @@ -208,7 +209,7 @@ { unsigned int flags; - save_and_cli(flags); + __save_and_cli(flags); *(volatile unsigned int *)KSEG1; __asm__ __volatile__( ".set\tnoreorder\n\t" @@ -235,7 +236,7 @@ "I" (PAGE_SIZE), "i" (Create_Dirty_Excl_D) :"$1","memory"); - restore_flags(flags); + __restore_flags(flags); } /* @@ -626,7 +627,7 @@ :"0" (to), "1" (from), "I" (PAGE_SIZE), "i" (Create_Dirty_Excl_D)); - restore_flags(flags); + __restore_flags(flags); } /* @@ -910,81 +911,81 @@ { unsigned long flags; - save_and_cli(flags); + __save_and_cli(flags); blast_dcache16(); blast_icache16(); blast_scache16(); - restore_flags(flags); + __restore_flags(flags); } static inline void r4k_flush_cache_all_s32d16i16(void) { unsigned long flags; - save_and_cli(flags); + __save_and_cli(flags); blast_dcache16(); blast_icache16(); blast_scache32(); - restore_flags(flags); + __restore_flags(flags); } static inline void r4k_flush_cache_all_s64d16i16(void) { unsigned long flags; - save_and_cli(flags); + __save_and_cli(flags); blast_dcache16(); blast_icache16(); blast_scache64(); - restore_flags(flags); + __restore_flags(flags); } static inline void r4k_flush_cache_all_s128d16i16(void) { unsigned long flags; - save_and_cli(flags); + __save_and_cli(flags); blast_dcache16(); blast_icache16(); blast_scache128(); - restore_flags(flags); + __restore_flags(flags); } static inline void r4k_flush_cache_all_s32d32i32(void) { unsigned long flags; - save_and_cli(flags); + __save_and_cli(flags); blast_dcache32(); blast_icache32(); blast_scache32(); - restore_flags(flags); + __restore_flags(flags); } static inline void r4k_flush_cache_all_s64d32i32(void) { unsigned long flags; - save_and_cli(flags); + __save_and_cli(flags); blast_dcache32(); blast_icache32(); blast_scache64(); - restore_flags(flags); + __restore_flags(flags); } static inline void r4k_flush_cache_all_s128d32i32(void) { unsigned long flags; - save_and_cli(flags); + __save_and_cli(flags); blast_dcache32(); blast_icache32(); blast_scache128(); - restore_flags(flags); + __restore_flags(flags); } static inline void r4k_flush_cache_all_d16i16(void) { unsigned long flags; - save_and_cli(flags); + __save_and_cli(flags); blast_dcache16(); blast_icache16(); - restore_flags(flags); + __restore_flags(flags); } static inline void r4k_flush_cache_all_d32i32(void) { unsigned long flags; - save_and_cli(flags); + __save_and_cli(flags); blast_dcache32(); blast_icache32(); - restore_flags(flags); + __restore_flags(flags); } static void @@ -1010,10 +1011,8 @@ pgd_t *pgd; pmd_t *pmd; pte_t *pte; - int text; - save_and_cli(flags); - text = vma->vm_flags & VM_EXEC; + __save_and_cli(flags); while(start < end) { pgd = pgd_offset(mm, start); pmd = pmd_offset(pgd, start); @@ -1023,7 +1022,7 @@ blast_scache16_page(start); start += PAGE_SIZE; } - restore_flags(flags); + __restore_flags(flags); } } } @@ -1051,10 +1050,8 @@ pgd_t *pgd; pmd_t *pmd; pte_t *pte; - int text; - save_and_cli(flags); - text = vma->vm_flags & VM_EXEC; + __save_and_cli(flags); while(start < end) { pgd = pgd_offset(mm, start); pmd = pmd_offset(pgd, start); @@ -1064,7 +1061,7 @@ blast_scache32_page(start); start += PAGE_SIZE; } - restore_flags(flags); + __restore_flags(flags); } } } @@ -1091,10 +1088,8 @@ pgd_t *pgd; pmd_t *pmd; pte_t *pte; - int text; - save_and_cli(flags); - text = vma->vm_flags & VM_EXEC; + __save_and_cli(flags); while(start < end) { pgd = pgd_offset(mm, start); pmd = pmd_offset(pgd, start); @@ -1104,7 +1099,7 @@ blast_scache64_page(start); start += PAGE_SIZE; } - restore_flags(flags); + __restore_flags(flags); } } } @@ -1131,10 +1126,8 @@ pgd_t *pgd; pmd_t *pmd; pte_t *pte; - int text; - save_and_cli(flags); - text = vma->vm_flags & VM_EXEC; + __save_and_cli(flags); while(start < end) { pgd = pgd_offset(mm, start); pmd = pmd_offset(pgd, start); @@ -1144,7 +1137,7 @@ blast_scache128_page(start); start += PAGE_SIZE; } - restore_flags(flags); + __restore_flags(flags); } } } @@ -1171,10 +1164,8 @@ pgd_t *pgd; pmd_t *pmd; pte_t *pte; - int text; - save_and_cli(flags); - text = vma->vm_flags & VM_EXEC; + __save_and_cli(flags); while(start < end) { pgd = pgd_offset(mm, start); pmd = pmd_offset(pgd, start); @@ -1184,7 +1175,7 @@ blast_scache32_page(start); start += PAGE_SIZE; } - restore_flags(flags); + __restore_flags(flags); } } } @@ -1211,10 +1202,8 @@ pgd_t *pgd; pmd_t *pmd; pte_t *pte; - int text; - save_and_cli(flags); - text = vma->vm_flags & VM_EXEC; + __save_and_cli(flags); while(start < end) { pgd = pgd_offset(mm, start); pmd = pmd_offset(pgd, start); @@ -1224,7 +1213,7 @@ blast_scache64_page(start); start += PAGE_SIZE; } - restore_flags(flags); + __restore_flags(flags); } } } @@ -1251,10 +1240,8 @@ pgd_t *pgd; pmd_t *pmd; pte_t *pte; - int text; - save_and_cli(flags); - text = vma->vm_flags & VM_EXEC; + __save_and_cli(flags); while(start < end) { pgd = pgd_offset(mm, start); pmd = pmd_offset(pgd, start); @@ -1264,7 +1251,7 @@ blast_scache128_page(start); start += PAGE_SIZE; } - restore_flags(flags); + __restore_flags(flags); } } } @@ -1279,9 +1266,9 @@ #ifdef DEBUG_CACHE printk("crange[%d,%08lx,%08lx]", (int)mm->context, start, end); #endif - save_and_cli(flags); + __save_and_cli(flags); blast_dcache16(); blast_icache16(); - restore_flags(flags); + __restore_flags(flags); } } @@ -1295,9 +1282,9 @@ #ifdef DEBUG_CACHE printk("crange[%d,%08lx,%08lx]", (int)mm->context, start, end); #endif - save_and_cli(flags); + __save_and_cli(flags); blast_dcache32(); blast_icache32(); - restore_flags(flags); + __restore_flags(flags); } } @@ -1404,7 +1391,6 @@ pgd_t *pgdp; pmd_t *pmdp; pte_t *ptep; - int text; /* * If ownes no valid ASID yet, cannot possibly have gotten @@ -1416,7 +1402,7 @@ #ifdef DEBUG_CACHE printk("cpage[%d,%08lx]", (int)mm->context, page); #endif - save_and_cli(flags); + __save_and_cli(flags); page &= PAGE_MASK; pgdp = pgd_offset(mm, page); pmdp = pmd_offset(pgdp, page); @@ -1429,25 +1415,24 @@ if (!(pte_val(*ptep) & _PAGE_VALID)) goto out; - text = (vma->vm_flags & VM_EXEC); - /* Doing flushes for another ASID than the current one is + /* + * Doing flushes for another ASID than the current one is * too difficult since stupid R4k caches do a TLB translation * for every cache flush operation. So we do indexed flushes * in that case, which doesn't overly flush the cache too much. */ if (mm->context != current->active_mm->context) { - /* Do indexed flush, too much work to get the (possible) + /* + * Do indexed flush, too much work to get the (possible) * tlb refills to work correctly. */ page = (KSEG0 + (page & (scache_size - 1))); blast_dcache16_page_indexed(page); - if(text) - blast_icache16_page_indexed(page); blast_scache16_page_indexed(page); } else blast_scache16_page(page); out: - restore_flags(flags); + __restore_flags(flags); } static void r4k_flush_cache_page_s32d16i16(struct vm_area_struct *vma, @@ -1458,7 +1443,6 @@ pgd_t *pgdp; pmd_t *pmdp; pte_t *ptep; - int text; /* * If ownes no valid ASID yet, cannot possibly have gotten @@ -1470,7 +1454,7 @@ #ifdef DEBUG_CACHE printk("cpage[%d,%08lx]", (int)mm->context, page); #endif - save_and_cli(flags); + __save_and_cli(flags); page &= PAGE_MASK; pgdp = pgd_offset(mm, page); pmdp = pmd_offset(pgdp, page); @@ -1482,25 +1466,24 @@ if (!(pte_val(*ptep) & _PAGE_VALID)) goto out; - text = (vma->vm_flags & VM_EXEC); - /* Doing flushes for another ASID than the current one is + /* + * Doing flushes for another ASID than the current one is * too difficult since stupid R4k caches do a TLB translation * for every cache flush operation. So we do indexed flushes * in that case, which doesn't overly flush the cache too much. */ if (mm->context != current->active_mm->context) { - /* Do indexed flush, too much work to get the (possible) + /* + * Do indexed flush, too much work to get the (possible) * tlb refills to work correctly. */ page = (KSEG0 + (page & (scache_size - 1))); blast_dcache16_page_indexed(page); - if(text) - blast_icache16_page_indexed(page); blast_scache32_page_indexed(page); } else blast_scache32_page(page); out: - restore_flags(flags); + __restore_flags(flags); } static void r4k_flush_cache_page_s64d16i16(struct vm_area_struct *vma, @@ -1511,7 +1494,6 @@ pgd_t *pgdp; pmd_t *pmdp; pte_t *ptep; - int text; /* * If ownes no valid ASID yet, cannot possibly have gotten @@ -1523,7 +1505,7 @@ #ifdef DEBUG_CACHE printk("cpage[%d,%08lx]", (int)mm->context, page); #endif - save_and_cli(flags); + __save_and_cli(flags); page &= PAGE_MASK; pgdp = pgd_offset(mm, page); pmdp = pmd_offset(pgdp, page); @@ -1535,7 +1517,6 @@ if (!(pte_val(*ptep) & _PAGE_VALID)) goto out; - text = (vma->vm_flags & VM_EXEC); /* * Doing flushes for another ASID than the current one is * too difficult since stupid R4k caches do a TLB translation @@ -1543,18 +1524,17 @@ * in that case, which doesn't overly flush the cache too much. */ if (mm->context != current->active_mm->context) { - /* Do indexed flush, too much work to get the (possible) + /* + * Do indexed flush, too much work to get the (possible) * tlb refills to work correctly. */ page = (KSEG0 + (page & (scache_size - 1))); blast_dcache16_page_indexed(page); - if(text) - blast_icache16_page_indexed(page); blast_scache64_page_indexed(page); } else blast_scache64_page(page); out: - restore_flags(flags); + __restore_flags(flags); } static void r4k_flush_cache_page_s128d16i16(struct vm_area_struct *vma, @@ -1565,7 +1545,6 @@ pgd_t *pgdp; pmd_t *pmdp; pte_t *ptep; - int text; /* * If ownes no valid ASID yet, cannot possibly have gotten @@ -1577,7 +1556,7 @@ #ifdef DEBUG_CACHE printk("cpage[%d,%08lx]", (int)mm->context, page); #endif - save_and_cli(flags); + __save_and_cli(flags); page &= PAGE_MASK; pgdp = pgd_offset(mm, page); pmdp = pmd_offset(pgdp, page); @@ -1590,8 +1569,8 @@ if (!(pte_val(*ptep) & _PAGE_VALID)) goto out; - text = (vma->vm_flags & VM_EXEC); - /* Doing flushes for another ASID than the current one is + /* + * Doing flushes for another ASID than the current one is * too difficult since stupid R4k caches do a TLB translation * for every cache flush operation. So we do indexed flushes * in that case, which doesn't overly flush the cache too much. @@ -1603,13 +1582,11 @@ */ page = (KSEG0 + (page & (scache_size - 1))); blast_dcache16_page_indexed(page); - if(text) - blast_icache16_page_indexed(page); blast_scache128_page_indexed(page); } else blast_scache128_page(page); out: - restore_flags(flags); + __restore_flags(flags); } static void r4k_flush_cache_page_s32d32i32(struct vm_area_struct *vma, @@ -1620,7 +1597,6 @@ pgd_t *pgdp; pmd_t *pmdp; pte_t *ptep; - int text; /* * If ownes no valid ASID yet, cannot possibly have gotten @@ -1632,7 +1608,7 @@ #ifdef DEBUG_CACHE printk("cpage[%d,%08lx]", (int)mm->context, page); #endif - save_and_cli(flags); + __save_and_cli(flags); page &= PAGE_MASK; pgdp = pgd_offset(mm, page); pmdp = pmd_offset(pgdp, page); @@ -1645,7 +1621,6 @@ if (!(pte_val(*ptep) & _PAGE_VALID)) goto out; - text = (vma->vm_flags & VM_EXEC); /* * Doing flushes for another ASID than the current one is * too difficult since stupid R4k caches do a TLB translation @@ -1659,13 +1634,11 @@ */ page = (KSEG0 + (page & (scache_size - 1))); blast_dcache32_page_indexed(page); - if(text) - blast_icache32_page_indexed(page); blast_scache32_page_indexed(page); } else blast_scache32_page(page); out: - restore_flags(flags); + __restore_flags(flags); } static void r4k_flush_cache_page_s64d32i32(struct vm_area_struct *vma, @@ -1676,7 +1649,6 @@ pgd_t *pgdp; pmd_t *pmdp; pte_t *ptep; - int text; /* * If ownes no valid ASID yet, cannot possibly have gotten @@ -1688,7 +1660,7 @@ #ifdef DEBUG_CACHE printk("cpage[%d,%08lx]", (int)mm->context, page); #endif - save_and_cli(flags); + __save_and_cli(flags); page &= PAGE_MASK; pgdp = pgd_offset(mm, page); pmdp = pmd_offset(pgdp, page); @@ -1701,7 +1673,6 @@ if (!(pte_val(*ptep) & _PAGE_VALID)) goto out; - text = (vma->vm_flags & VM_EXEC); /* * Doing flushes for another ASID than the current one is * too difficult since stupid R4k caches do a TLB translation @@ -1715,13 +1686,11 @@ */ page = (KSEG0 + (page & (scache_size - 1))); blast_dcache32_page_indexed(page); - if(text) - blast_icache32_page_indexed(page); blast_scache64_page_indexed(page); } else blast_scache64_page(page); out: - restore_flags(flags); + __restore_flags(flags); } static void r4k_flush_cache_page_s128d32i32(struct vm_area_struct *vma, @@ -1732,7 +1701,6 @@ pgd_t *pgdp; pmd_t *pmdp; pte_t *ptep; - int text; /* * If ownes no valid ASID yet, cannot possibly have gotten @@ -1744,19 +1712,19 @@ #ifdef DEBUG_CACHE printk("cpage[%d,%08lx]", (int)mm->context, page); #endif - save_and_cli(flags); + __save_and_cli(flags); page &= PAGE_MASK; pgdp = pgd_offset(mm, page); pmdp = pmd_offset(pgdp, page); ptep = pte_offset(pmdp, page); - /* If the page isn't marked valid, the page cannot possibly be + /* + * If the page isn't marked valid, the page cannot possibly be * in the cache. */ if (!(pte_val(*ptep) & _PAGE_VALID)) goto out; - text = (vma->vm_flags & VM_EXEC); /* * Doing flushes for another ASID than the current one is * too difficult since stupid R4k caches do a TLB translation @@ -1769,13 +1737,11 @@ */ page = (KSEG0 + (page & (scache_size - 1))); blast_dcache32_page_indexed(page); - if(text) - blast_icache32_page_indexed(page); blast_scache128_page_indexed(page); } else blast_scache128_page(page); out: - restore_flags(flags); + __restore_flags(flags); } static void r4k_flush_cache_page_d16i16(struct vm_area_struct *vma, @@ -1786,7 +1752,6 @@ pgd_t *pgdp; pmd_t *pmdp; pte_t *ptep; - int text; /* * If ownes no valid ASID yet, cannot possibly have gotten @@ -1798,19 +1763,19 @@ #ifdef DEBUG_CACHE printk("cpage[%d,%08lx]", (int)mm->context, page); #endif - save_and_cli(flags); + __save_and_cli(flags); page &= PAGE_MASK; pgdp = pgd_offset(mm, page); pmdp = pmd_offset(pgdp, page); ptep = pte_offset(pmdp, page); - /* If the page isn't marked valid, the page cannot possibly be + /* + * If the page isn't marked valid, the page cannot possibly be * in the cache. */ if (!(pte_val(*ptep) & _PAGE_VALID)) goto out; - text = (vma->vm_flags & VM_EXEC); /* * Doing flushes for another ASID than the current one is * too difficult since stupid R4k caches do a TLB translation @@ -1819,19 +1784,15 @@ */ if (mm == current->active_mm) { blast_dcache16_page(page); - if(text) - blast_icache16_page(page); } else { /* Do indexed flush, too much work to get the (possible) * tlb refills to work correctly. */ page = (KSEG0 + (page & (dcache_size - 1))); blast_dcache16_page_indexed(page); - if(text) - blast_icache16_page_indexed(page); } out: - restore_flags(flags); + __restore_flags(flags); } static void r4k_flush_cache_page_d32i32(struct vm_area_struct *vma, @@ -1842,7 +1803,6 @@ pgd_t *pgdp; pmd_t *pmdp; pte_t *ptep; - int text; /* * If ownes no valid ASID yet, cannot possibly have gotten @@ -1854,7 +1814,7 @@ #ifdef DEBUG_CACHE printk("cpage[%d,%08lx]", (int)mm->context, page); #endif - save_and_cli(flags); + __save_and_cli(flags); page &= PAGE_MASK; pgdp = pgd_offset(mm, page); pmdp = pmd_offset(pgdp, page); @@ -1867,7 +1827,6 @@ if (!(pte_val(*ptep) & _PAGE_PRESENT)) goto out; - text = (vma->vm_flags & VM_EXEC); /* * Doing flushes for another ASID than the current one is * too difficult since stupid R4k caches do a TLB translation @@ -1876,8 +1835,6 @@ */ if ((mm == current->active_mm) && (pte_val(*ptep) & _PAGE_VALID)) { blast_dcache32_page(page); - if(text) - blast_icache32_page(page); } else { /* * Do indexed flush, too much work to get the (possible) @@ -1885,11 +1842,9 @@ */ page = (KSEG0 + (page & (dcache_size - 1))); blast_dcache32_page_indexed(page); - if(text) - blast_icache32_page_indexed(page); } out: - restore_flags(flags); + __restore_flags(flags); } static void r4k_flush_cache_page_d32i32_r4600(struct vm_area_struct *vma, @@ -1900,7 +1855,6 @@ pgd_t *pgdp; pmd_t *pmdp; pte_t *ptep; - int text; /* * If ownes no valid ASID yet, cannot possibly have gotten @@ -1912,7 +1866,7 @@ #ifdef DEBUG_CACHE printk("cpage[%d,%08lx]", (int)mm->context, page); #endif - save_and_cli(flags); + __save_and_cli(flags); page &= PAGE_MASK; pgdp = pgd_offset(mm, page); pmdp = pmd_offset(pgdp, page); @@ -1925,7 +1879,6 @@ if (!(pte_val(*ptep) & _PAGE_PRESENT)) goto out; - text = (vma->vm_flags & VM_EXEC); /* * Doing flushes for another ASID than the current one is * too difficult since stupid R4k caches do a TLB translation @@ -1934,8 +1887,6 @@ */ if ((mm == current->active_mm) && (pte_val(*ptep) & _PAGE_VALID)) { blast_dcache32_page(page); - if(text) - blast_icache32_page(page); } else { /* Do indexed flush, too much work to get the (possible) * tlb refills to work correctly. @@ -1943,13 +1894,9 @@ page = (KSEG0 + (page & (dcache_size - 1))); blast_dcache32_page_indexed(page); blast_dcache32_page_indexed(page ^ dcache_waybit); - if(text) { - blast_icache32_page_indexed(page); - blast_icache32_page_indexed(page ^ icache_waybit); - } } out: - restore_flags(flags); + __restore_flags(flags); } /* If the addresses passed to these routines are valid, they are @@ -1961,120 +1908,71 @@ * flush. * 3) In KSEG1, no flush necessary. */ -static void r4k_flush_page_to_ram_s16d16i16(struct page * page) +static void r4k_flush_page_to_ram_s16(struct page *page) { - unsigned long addr = (unsigned long) page_address(page) & PAGE_MASK; - - if ((addr >= KSEG0 && addr < KSEG1) || (addr >= KSEG2)) { -#ifdef DEBUG_CACHE - printk("cram[%08lx]", addr); -#endif - blast_scache16_page(addr); - } + blast_scache16_page((unsigned long)page_address(page)); } -static void r4k_flush_page_to_ram_s32d16i16(struct page * page) +static void r4k_flush_page_to_ram_s32(struct page *page) { - unsigned long addr = (unsigned long) page_address(page) & PAGE_MASK; - - if ((addr >= KSEG0 && addr < KSEG1) || (addr >= KSEG2)) { -#ifdef DEBUG_CACHE - printk("cram[%08lx]", addr); -#endif - blast_scache32_page(addr); - } + blast_scache32_page((unsigned long)page_address(page)); } -static void r4k_flush_page_to_ram_s64d16i16(struct page * page) +static void r4k_flush_page_to_ram_s64(struct page *page) { - unsigned long addr = (unsigned long) page_address(page) & PAGE_MASK; - - if ((addr >= KSEG0 && addr < KSEG1) || (addr >= KSEG2)) { -#ifdef DEBUG_CACHE - printk("cram[%08lx]", addr); -#endif - blast_scache64_page(addr); - } + blast_scache64_page((unsigned long)page_address(page)); } -static void r4k_flush_page_to_ram_s128d16i16(struct page * page) +static void r4k_flush_page_to_ram_s128(struct page *page) { - unsigned long addr = (unsigned long) page_address(page) & PAGE_MASK; - - if ((addr >= KSEG0 && addr < KSEG1) || (addr >= KSEG2)) { -#ifdef DEBUG_CACHE - printk("cram[%08lx]", addr); -#endif - blast_scache128_page(addr); - } + blast_scache128_page((unsigned long)page_address(page)); } -static void r4k_flush_page_to_ram_s32d32i32(struct page * page) +static void r4k_flush_page_to_ram_d16(struct page *page) { - unsigned long addr = (unsigned long) page_address(page) & PAGE_MASK; - - if ((addr >= KSEG0 && addr < KSEG1) || (addr >= KSEG2)) { -#ifdef DEBUG_CACHE - printk("cram[%08lx]", addr); -#endif - blast_scache32_page(addr); - } + blast_dcache16_page((unsigned long)page_address(page)); } -static void r4k_flush_page_to_ram_s64d32i32(struct page * page) +static void r4k_flush_page_to_ram_d32(struct page *page) { - unsigned long addr = (unsigned long) page_address(page) & PAGE_MASK; - - if ((addr >= KSEG0 && addr < KSEG1) || (addr >= KSEG2)) { -#ifdef DEBUG_CACHE - printk("cram[%08lx]", addr); -#endif - blast_scache64_page(addr); - } + blast_dcache32_page((unsigned long)page_address(page)); } -static void r4k_flush_page_to_ram_s128d32i32(struct page * page) +static void r4k_flush_page_to_ram_d32_r4600(struct page *page) { - unsigned long addr = (unsigned long) page_address(page) & PAGE_MASK; + unsigned long flags; - if ((addr >= KSEG0 && addr < KSEG1) || (addr >= KSEG2)) { -#ifdef DEBUG_CACHE - printk("cram[%08lx]", addr); -#endif - blast_scache128_page(addr); - } + __save_and_cli(flags); /* For R4600 v1.7 bug. */ + blast_dcache32_page((unsigned long)page_address(page)); + __restore_flags(flags); } -static void r4k_flush_page_to_ram_d16i16(struct page * page) +static void +r4k_flush_icache_page_s(struct vm_area_struct *vma, struct page *page) { - unsigned long addr = (unsigned long) page_address(page) & PAGE_MASK; - - if ((addr >= KSEG0 && addr < KSEG1) || (addr >= KSEG2)) { - unsigned long flags; - -#ifdef DEBUG_CACHE - printk("cram[%08lx]", addr); -#endif - __save_and_cli(flags); - blast_dcache16_page(addr); - __restore_flags(flags); - } + /* + * We did an scache flush therefore PI is already clean. + */ } -static void r4k_flush_page_to_ram_d32i32(struct page * page) +static void +r4k_flush_icache_range(unsigned long start, unsigned long end) { - unsigned long addr = (unsigned long) page_address(page) & PAGE_MASK; + flush_cache_all(); +} - if ((addr >= KSEG0 && addr < KSEG1) || (addr >= KSEG2)) { - unsigned long flags; +/* + * Ok, this seriously sucks. We use them to flush a user page but don't + * know the virtual address, so we have to blast away the whole icache + * which is significantly more expensive than the real thing. + */ +static void +r4k_flush_icache_page_p(struct vm_area_struct *vma, struct page *page) +{ + if (!(vma->vm_flags & VM_EXEC)) + return; -#ifdef DEBUG_CACHE - printk("cram[%08lx]", addr); -#endif - __save_and_cli(flags); - blast_dcache32_page(addr); - __restore_flags(flags); - } + flush_cache_all(); } /* @@ -2098,7 +1996,7 @@ flush_cache_all(); } else { /* Workaround for R4600 bug. See comment above. */ - save_and_cli(flags); + __save_and_cli(flags); *(volatile unsigned long *)KSEG1; a = addr & ~(dc_lsize - 1); @@ -2108,9 +2006,9 @@ if (a == end) break; a += dc_lsize; } - restore_flags(flags); + __restore_flags(flags); } - bcops->bc_wback_inv(addr, size); + bc_wback_inv(addr, size); } static void @@ -2142,7 +2040,7 @@ flush_cache_all(); } else { /* Workaround for R4600 bug. See comment above. */ - save_and_cli(flags); + __save_and_cli(flags); *(volatile unsigned long *)KSEG1; a = addr & ~(dc_lsize - 1); @@ -2152,10 +2050,10 @@ if (a == end) break; a += dc_lsize; } - restore_flags(flags); + __restore_flags(flags); } - bcops->bc_inv(addr, size); + bc_inv(addr, size); } static void @@ -2237,7 +2135,7 @@ printk("[tlball]"); #endif - save_and_cli(flags); + __save_and_cli(flags); /* Save old context and create impossible VPN2 value */ old_ctx = (get_entryhi() & 0xff); set_entryhi(KSEG0); @@ -2257,7 +2155,7 @@ } BARRIER; set_entryhi(old_ctx); - restore_flags(flags); + __restore_flags(flags); } void flush_tlb_mm(struct mm_struct *mm) @@ -2268,11 +2166,11 @@ #ifdef DEBUG_TLB printk("[tlbmm<%d>]", mm->context); #endif - save_and_cli(flags); + __save_and_cli(flags); get_new_mmu_context(mm, asid_cache); if (mm == current->active_mm) set_entryhi(mm->context & 0xff); - restore_flags(flags); + __restore_flags(flags); } } @@ -2287,7 +2185,7 @@ printk("[tlbrange<%02x,%08lx,%08lx>]", (mm->context & 0xff), start, end); #endif - save_and_cli(flags); + __save_and_cli(flags); size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT; size = (size + 1) >> 1; if(size <= NTLB_ENTRIES_HALF) { @@ -2321,7 +2219,7 @@ if (mm == current->active_mm) set_entryhi(mm->context & 0xff); } - restore_flags(flags); + __restore_flags(flags); } } @@ -2336,7 +2234,7 @@ #endif newpid = (vma->vm_mm->context & 0xff); page &= (PAGE_MASK << 1); - save_and_cli(flags); + __save_and_cli(flags); oldpid = (get_entryhi() & 0xff); set_entryhi(page | newpid); BARRIER; @@ -2354,15 +2252,10 @@ finish: BARRIER; set_entryhi(oldpid); - restore_flags(flags); + __restore_flags(flags); } } -/* Load a new root pointer into the TLB. */ -void load_pgd(unsigned long pg_dir) -{ -} - void pgd_init(unsigned long page) { unsigned long *p = (unsigned long *) page; @@ -2380,12 +2273,6 @@ } } -#ifdef DEBUG_TLBUPDATE -static unsigned long ehi_debug[NTLB_ENTRIES]; -static unsigned long el0_debug[NTLB_ENTRIES]; -static unsigned long el1_debug[NTLB_ENTRIES]; -#endif - /* We will need multiple versions of update_mmu_cache(), one that just * updates the TLB with the new pte(s), and another which also checks * for the R4k "end of page" hardware bug and does the needy. @@ -2414,7 +2301,7 @@ } #endif - save_and_cli(flags); + __save_and_cli(flags); address &= (PAGE_MASK << 1); set_entryhi(address | (pid)); pgdp = pgd_offset(vma->vm_mm, address); @@ -2437,7 +2324,7 @@ BARRIER; set_entryhi(pid); BARRIER; - restore_flags(flags); + __restore_flags(flags); } #if 0 @@ -2450,7 +2337,7 @@ pte_t *ptep; int idx; - save_and_cli(flags); + __save_and_cli(flags); address &= (PAGE_MASK << 1); set_entryhi(address | (get_entryhi() & 0xff)); pgdp = pgd_offset(vma->vm_mm, address); @@ -2466,7 +2353,7 @@ else tlb_write_indexed(); BARRIER; - restore_flags(flags); + __restore_flags(flags); } #endif @@ -2503,7 +2390,7 @@ unsigned long old_pagemask; unsigned long old_ctx; - save_and_cli(flags); + __save_and_cli(flags); /* Save old context and create impossible VPN2 value */ old_ctx = (get_entryhi() & 0xff); old_pagemask = get_pagemask(); @@ -2523,7 +2410,7 @@ BARRIER; set_pagemask (old_pagemask); flush_tlb_all(); - restore_flags(flags); + __restore_flags(flags); } /* Detect and size the various r4k caches. */ @@ -2532,7 +2419,7 @@ icache_size = 1 << (12 + ((config >> 9) & 7)); ic_lsize = 16 << ((config >> 5) & 1); - printk("Primary instruction cache %dkb, linesize %d bytes)\n", + printk("Primary instruction cache %dkb, linesize %d bytes.\n", icache_size >> 10, ic_lsize); } @@ -2541,7 +2428,7 @@ dcache_size = 1 << (12 + ((config >> 6) & 7)); dc_lsize = 16 << ((config >> 4) & 1); - printk("Primary data cache %dkb, linesize %d bytes)\n", + printk("Primary data cache %dkb, linesize %d bytes.\n", dcache_size >> 10, dc_lsize); } @@ -2583,7 +2470,7 @@ /* This is such a bitch, you'd think they would make it * easy to do this. Away you daemons of stupidity! */ - save_and_cli(flags); + __save_and_cli(flags); /* Fill each size-multiple cache line with a valid tag. */ pow2 = (64 * 1024); @@ -2627,9 +2514,9 @@ break; pow2 <<= 1; } - restore_flags(flags); + __restore_flags(flags); addr -= begin; - printk("Secondary cache sized at %dK linesize %d\n", + printk("Secondary cache sized at %dK linesize %d bytes.\n", (int) (addr >> 10), sc_lsize); scache_size = addr; return 1; @@ -2647,27 +2534,33 @@ _flush_cache_mm = r4k_flush_cache_mm_d16i16; _flush_cache_range = r4k_flush_cache_range_d16i16; _flush_cache_page = r4k_flush_cache_page_d16i16; - _flush_page_to_ram = r4k_flush_page_to_ram_d16i16; + _flush_page_to_ram = r4k_flush_page_to_ram_d16; break; case 32: prid = read_32bit_cp0_register(CP0_PRID) & 0xfff0; if (prid == 0x2010) { /* R4600 V1.7 */ _clear_page = r4k_clear_page_r4600_v1; _copy_page = r4k_copy_page_r4600_v1; + _flush_page_to_ram = r4k_flush_page_to_ram_d32_r4600; } else if (prid == 0x2020) { /* R4600 V2.0 */ _clear_page = r4k_clear_page_r4600_v2; _copy_page = r4k_copy_page_r4600_v2; + _flush_page_to_ram = r4k_flush_page_to_ram_d32; } else { _clear_page = r4k_clear_page_d32; _copy_page = r4k_copy_page_d32; + _flush_page_to_ram = r4k_flush_page_to_ram_d32; } _flush_cache_all = r4k_flush_cache_all_d32i32; _flush_cache_mm = r4k_flush_cache_mm_d32i32; _flush_cache_range = r4k_flush_cache_range_d32i32; _flush_cache_page = r4k_flush_cache_page_d32i32; - _flush_page_to_ram = r4k_flush_page_to_ram_d32i32; break; } + ___flush_cache_all = _flush_cache_all; + + _flush_icache_page = r4k_flush_icache_page_p; + _dma_cache_wback_inv = r4k_dma_cache_wback_inv_pc; _dma_cache_wback = r4k_dma_cache_wback; _dma_cache_inv = r4k_dma_cache_inv_pc; @@ -2683,11 +2576,11 @@ _flush_cache_mm = r4k_flush_cache_mm_s16d16i16; _flush_cache_range = r4k_flush_cache_range_s16d16i16; _flush_cache_page = r4k_flush_cache_page_s16d16i16; - _flush_page_to_ram = r4k_flush_page_to_ram_s16d16i16; break; case 32: panic("Invalid cache configuration detected"); }; + _flush_page_to_ram = r4k_flush_page_to_ram_s16; _clear_page = r4k_clear_page_s16; _copy_page = r4k_copy_page_s16; break; @@ -2698,16 +2591,15 @@ _flush_cache_mm = r4k_flush_cache_mm_s32d16i16; _flush_cache_range = r4k_flush_cache_range_s32d16i16; _flush_cache_page = r4k_flush_cache_page_s32d16i16; - _flush_page_to_ram = r4k_flush_page_to_ram_s32d16i16; break; case 32: _flush_cache_all = r4k_flush_cache_all_s32d32i32; _flush_cache_mm = r4k_flush_cache_mm_s32d32i32; _flush_cache_range = r4k_flush_cache_range_s32d32i32; _flush_cache_page = r4k_flush_cache_page_s32d32i32; - _flush_page_to_ram = r4k_flush_page_to_ram_s32d32i32; break; }; + _flush_page_to_ram = r4k_flush_page_to_ram_s32; _clear_page = r4k_clear_page_s32; _copy_page = r4k_copy_page_s32; break; @@ -2718,16 +2610,15 @@ _flush_cache_mm = r4k_flush_cache_mm_s64d16i16; _flush_cache_range = r4k_flush_cache_range_s64d16i16; _flush_cache_page = r4k_flush_cache_page_s64d16i16; - _flush_page_to_ram = r4k_flush_page_to_ram_s64d16i16; break; case 32: _flush_cache_all = r4k_flush_cache_all_s64d32i32; _flush_cache_mm = r4k_flush_cache_mm_s64d32i32; _flush_cache_range = r4k_flush_cache_range_s64d32i32; _flush_cache_page = r4k_flush_cache_page_s64d32i32; - _flush_page_to_ram = r4k_flush_page_to_ram_s64d32i32; break; }; + _flush_page_to_ram = r4k_flush_page_to_ram_s64; _clear_page = r4k_clear_page_s64; _copy_page = r4k_copy_page_s64; break; @@ -2738,20 +2629,21 @@ _flush_cache_mm = r4k_flush_cache_mm_s128d16i16; _flush_cache_range = r4k_flush_cache_range_s128d16i16; _flush_cache_page = r4k_flush_cache_page_s128d16i16; - _flush_page_to_ram = r4k_flush_page_to_ram_s128d16i16; break; case 32: _flush_cache_all = r4k_flush_cache_all_s128d32i32; _flush_cache_mm = r4k_flush_cache_mm_s128d32i32; _flush_cache_range = r4k_flush_cache_range_s128d32i32; _flush_cache_page = r4k_flush_cache_page_s128d32i32; - _flush_page_to_ram = r4k_flush_page_to_ram_s128d32i32; break; }; + _flush_page_to_ram = r4k_flush_page_to_ram_s128; _clear_page = r4k_clear_page_s128; _copy_page = r4k_copy_page_s128; break; } + ___flush_cache_all = _flush_cache_all; + _flush_icache_page = r4k_flush_icache_page_s; _dma_cache_wback_inv = r4k_dma_cache_wback_inv_sc; _dma_cache_wback = r4k_dma_cache_wback; _dma_cache_inv = r4k_dma_cache_inv_sc; @@ -2782,13 +2674,17 @@ printk("CPU revision is: %08x\n", read_32bit_cp0_register(CP0_PRID)); - set_cp0_config(CONF_CM_CMASK, CONF_CM_CACHABLE_NONCOHERENT); +#ifdef CONFIG_MIPS_UNCACHED + change_cp0_config(CONF_CM_CMASK, CONF_CM_UNCACHED); +#else + change_cp0_config(CONF_CM_CMASK, CONF_CM_CACHABLE_NONCOHERENT); +#endif probe_icache(config); probe_dcache(config); setup_scache(config); - switch(mips_cputype) { + switch(mips_cpu.cputype) { case CPU_R4600: /* QED style two way caches? */ case CPU_R4700: case CPU_R5000: @@ -2797,11 +2693,12 @@ } _flush_cache_sigtramp = r4k_flush_cache_sigtramp; + _flush_icache_range = r4k_flush_icache_range; /* Ouch */ if ((read_32bit_cp0_register(CP0_PRID) & 0xfff0) == 0x2020) { _flush_cache_sigtramp = r4600v20k_flush_cache_sigtramp; } - flush_cache_all(); + __flush_cache_all(); write_32bit_cp0_register(CP0_WIRED, 0); /* diff -u --recursive --new-file v2.4.6/linux/arch/mips/mm/r5432.c linux/arch/mips/mm/r5432.c --- v2.4.6/linux/arch/mips/mm/r5432.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/mm/r5432.c Wed Jul 4 11:50:39 2001 @@ -0,0 +1,868 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * r5432.c: NEC Vr5432 processor. We cannot use r4xx0.c because of + * its unique way-selection method for indexed operations. + * + * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) + * Copyright (C) 1997, 1998, 1999, 2000 Ralf Baechle (ralf@gnu.org) + * Copyright (C) 2000 Jun Sun (jsun@mvista.com) + * + */ + +/* + * [jsun] + * In a sense, this is really silly. We cannot re-use r4xx0.c because + * the lowest-level indexed cache operation does not take way-selection + * into account. So all what I am doing here is to copy all the funcs + * and macros (in r4kcache.h) relavent to R5432 to this file, and then + * modify a few indexed cache operations. *sigh* + */ + +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/mm.h> + +#include <asm/bcache.h> +#include <asm/io.h> +#include <asm/page.h> +#include <asm/pgtable.h> +#include <asm/system.h> +#include <asm/bootinfo.h> +#include <asm/mmu_context.h> + +/* CP0 hazard avoidance. */ +#define BARRIER __asm__ __volatile__(".set noreorder\n\t" \ + "nop; nop; nop; nop; nop; nop;\n\t" \ + ".set reorder\n\t") + +#include <asm/asm.h> +#include <asm/cacheops.h> + +#undef DEBUG_CACHE + +/* Primary cache parameters. */ +static int icache_size, dcache_size; /* Size in bytes */ +static int ic_lsize, dc_lsize; /* LineSize in bytes */ + + +/* -------------------------------------------------------------------- */ +/* #include <asm/r4kcache.h> */ + +extern inline void flush_icache_line_indexed(unsigned long addr) +{ + __asm__ __volatile__( + ".set noreorder\n\t" + ".set mips3\n\t" + "cache %1, (%0)\n\t" + "cache %1, 1(%0)\n\t" + ".set mips0\n\t" + ".set reorder" + : + : "r" (addr), + "i" (Index_Invalidate_I)); +} + +extern inline void flush_dcache_line_indexed(unsigned long addr) +{ + __asm__ __volatile__( + ".set noreorder\n\t" + ".set mips3\n\t" + "cache %1, (%0)\n\t" + "cache %1, 1(%0)\n\t" + ".set mips0\n\t" + ".set reorder" + : + : "r" (addr), + "i" (Index_Writeback_Inv_D)); +} + +extern inline void flush_icache_line(unsigned long addr) +{ + __asm__ __volatile__( + ".set noreorder\n\t" + ".set mips3\n\t" + "cache %1, (%0)\n\t" + ".set mips0\n\t" + ".set reorder" + : + : "r" (addr), + "i" (Hit_Invalidate_I)); +} + +extern inline void flush_dcache_line(unsigned long addr) +{ + __asm__ __volatile__( + ".set noreorder\n\t" + ".set mips3\n\t" + "cache %1, (%0)\n\t" + ".set mips0\n\t" + ".set reorder" + : + : "r" (addr), + "i" (Hit_Writeback_Inv_D)); +} + +extern inline void invalidate_dcache_line(unsigned long addr) +{ + __asm__ __volatile__( + ".set noreorder\n\t" + ".set mips3\n\t" + "cache %1, (%0)\n\t" + ".set mips0\n\t" + ".set reorder" + : + : "r" (addr), + "i" (Hit_Invalidate_D)); +} + + +/* + * The next two are for badland addresses like signal trampolines. + */ +extern inline void protected_flush_icache_line(unsigned long addr) +{ + __asm__ __volatile__( + ".set noreorder\n\t" + ".set mips3\n" + "1:\tcache %1,(%0)\n" + "2:\t.set mips0\n\t" + ".set reorder\n\t" + ".section\t__ex_table,\"a\"\n\t" + STR(PTR)"\t1b,2b\n\t" + ".previous" + : + : "r" (addr), + "i" (Hit_Invalidate_I)); +} + +extern inline void protected_writeback_dcache_line(unsigned long addr) +{ + __asm__ __volatile__( + ".set noreorder\n\t" + ".set mips3\n" + "1:\tcache %1,(%0)\n" + "2:\t.set mips0\n\t" + ".set reorder\n\t" + ".section\t__ex_table,\"a\"\n\t" + STR(PTR)"\t1b,2b\n\t" + ".previous" + : + : "r" (addr), + "i" (Hit_Writeback_D)); +} + + +#define cache32_unroll32(base,op) \ + __asm__ __volatile__(" \ + .set noreorder; \ + .set mips3; \ + cache %1, 0x000(%0); cache %1, 0x020(%0); \ + cache %1, 0x040(%0); cache %1, 0x060(%0); \ + cache %1, 0x080(%0); cache %1, 0x0a0(%0); \ + cache %1, 0x0c0(%0); cache %1, 0x0e0(%0); \ + cache %1, 0x100(%0); cache %1, 0x120(%0); \ + cache %1, 0x140(%0); cache %1, 0x160(%0); \ + cache %1, 0x180(%0); cache %1, 0x1a0(%0); \ + cache %1, 0x1c0(%0); cache %1, 0x1e0(%0); \ + cache %1, 0x200(%0); cache %1, 0x220(%0); \ + cache %1, 0x240(%0); cache %1, 0x260(%0); \ + cache %1, 0x280(%0); cache %1, 0x2a0(%0); \ + cache %1, 0x2c0(%0); cache %1, 0x2e0(%0); \ + cache %1, 0x300(%0); cache %1, 0x320(%0); \ + cache %1, 0x340(%0); cache %1, 0x360(%0); \ + cache %1, 0x380(%0); cache %1, 0x3a0(%0); \ + cache %1, 0x3c0(%0); cache %1, 0x3e0(%0); \ + .set mips0; \ + .set reorder" \ + : \ + : "r" (base), \ + "i" (op)); + +extern inline void blast_dcache32(void) +{ + unsigned long start = KSEG0; + unsigned long end = (start + dcache_size/2); + + while(start < end) { + cache32_unroll32(start,Index_Writeback_Inv_D); + cache32_unroll32(start+1,Index_Writeback_Inv_D); + start += 0x400; + } +} + +extern inline void blast_dcache32_page(unsigned long page) +{ + unsigned long start = page; + unsigned long end = (start + PAGE_SIZE); + + while(start < end) { + cache32_unroll32(start,Hit_Writeback_Inv_D); + start += 0x400; + } +} + +extern inline void blast_dcache32_page_indexed(unsigned long page) +{ + unsigned long start = page; + unsigned long end = (start + PAGE_SIZE); + + while(start < end) { + cache32_unroll32(start,Index_Writeback_Inv_D); + cache32_unroll32(start+1,Index_Writeback_Inv_D); + start += 0x400; + } +} + +extern inline void blast_icache32(void) +{ + unsigned long start = KSEG0; + unsigned long end = (start + icache_size/2); + + while(start < end) { + cache32_unroll32(start,Index_Invalidate_I); + cache32_unroll32(start+1,Index_Invalidate_I); + start += 0x400; + } +} + +extern inline void blast_icache32_page(unsigned long page) +{ + unsigned long start = page; + unsigned long end = (start + PAGE_SIZE); + + while(start < end) { + cache32_unroll32(start,Hit_Invalidate_I); + start += 0x400; + } +} + +extern inline void blast_icache32_page_indexed(unsigned long page) +{ + unsigned long start = page; + unsigned long end = (start + PAGE_SIZE); + + while(start < end) { + cache32_unroll32(start,Index_Invalidate_I); + cache32_unroll32(start+1,Index_Invalidate_I); + start += 0x400; + } +} + +/* -------------------------------------------------------------------- */ + +static void r5432_clear_page_d32(void * page) +{ + __asm__ __volatile__( + ".set\tnoreorder\n\t" + ".set\tnoat\n\t" + ".set\tmips3\n\t" + "daddiu\t$1,%0,%2\n" + "1:\tcache\t%3,(%0)\n\t" + "sd\t$0,(%0)\n\t" + "sd\t$0,8(%0)\n\t" + "sd\t$0,16(%0)\n\t" + "sd\t$0,24(%0)\n\t" + "daddiu\t%0,64\n\t" + "cache\t%3,-32(%0)\n\t" + "sd\t$0,-32(%0)\n\t" + "sd\t$0,-24(%0)\n\t" + "sd\t$0,-16(%0)\n\t" + "bne\t$1,%0,1b\n\t" + "sd\t$0,-8(%0)\n\t" + ".set\tmips0\n\t" + ".set\tat\n\t" + ".set\treorder" + :"=r" (page) + :"0" (page), + "I" (PAGE_SIZE), + "i" (Create_Dirty_Excl_D) + :"$1","memory"); +} + + + +/* + * This is still inefficient. We only can do better if we know the + * virtual address where the copy will be accessed. + */ + +static void r5432_copy_page_d32(void * to, void * from) +{ + unsigned long dummy1, dummy2; + unsigned long reg1, reg2, reg3, reg4; + + __asm__ __volatile__( + ".set\tnoreorder\n\t" + ".set\tnoat\n\t" + ".set\tmips3\n\t" + "daddiu\t$1,%0,%8\n" + "1:\tcache\t%9,(%0)\n\t" + "lw\t%2,(%1)\n\t" + "lw\t%3,4(%1)\n\t" + "lw\t%4,8(%1)\n\t" + "lw\t%5,12(%1)\n\t" + "sw\t%2,(%0)\n\t" + "sw\t%3,4(%0)\n\t" + "sw\t%4,8(%0)\n\t" + "sw\t%5,12(%0)\n\t" + "lw\t%2,16(%1)\n\t" + "lw\t%3,20(%1)\n\t" + "lw\t%4,24(%1)\n\t" + "lw\t%5,28(%1)\n\t" + "sw\t%2,16(%0)\n\t" + "sw\t%3,20(%0)\n\t" + "sw\t%4,24(%0)\n\t" + "sw\t%5,28(%0)\n\t" + "cache\t%9,32(%0)\n\t" + "daddiu\t%0,64\n\t" + "daddiu\t%1,64\n\t" + "lw\t%2,-32(%1)\n\t" + "lw\t%3,-28(%1)\n\t" + "lw\t%4,-24(%1)\n\t" + "lw\t%5,-20(%1)\n\t" + "sw\t%2,-32(%0)\n\t" + "sw\t%3,-28(%0)\n\t" + "sw\t%4,-24(%0)\n\t" + "sw\t%5,-20(%0)\n\t" + "lw\t%2,-16(%1)\n\t" + "lw\t%3,-12(%1)\n\t" + "lw\t%4,-8(%1)\n\t" + "lw\t%5,-4(%1)\n\t" + "sw\t%2,-16(%0)\n\t" + "sw\t%3,-12(%0)\n\t" + "sw\t%4,-8(%0)\n\t" + "bne\t$1,%0,1b\n\t" + "sw\t%5,-4(%0)\n\t" + ".set\tmips0\n\t" + ".set\tat\n\t" + ".set\treorder" + :"=r" (dummy1), "=r" (dummy2), + "=&r" (reg1), "=&r" (reg2), "=&r" (reg3), "=&r" (reg4) + :"0" (to), "1" (from), + "I" (PAGE_SIZE), + "i" (Create_Dirty_Excl_D)); +} + + +/* + * If you think for one second that this stuff coming up is a lot + * of bulky code eating too many kernel cache lines. Think _again_. + * + * Consider: + * 1) Taken branches have a 3 cycle penalty on R4k + * 2) The branch itself is a real dead cycle on even R4600/R5000. + * 3) Only one of the following variants of each type is even used by + * the kernel based upon the cache parameters we detect at boot time. + * + * QED. + */ + +static inline void r5432_flush_cache_all_d32i32(void) +{ + blast_dcache32(); blast_icache32(); +} + +static void r5432_flush_cache_range_d32i32(struct mm_struct *mm, + unsigned long start, + unsigned long end) +{ + if (mm->context != 0) { +#ifdef DEBUG_CACHE + printk("crange[%d,%08lx,%08lx]", (int)mm->context, start, end); +#endif + blast_dcache32(); blast_icache32(); + } +} + +/* + * On architectures like the Sparc, we could get rid of lines in + * the cache created only by a certain context, but on the MIPS + * (and actually certain Sparc's) we cannot. + */ +static void r5432_flush_cache_mm_d32i32(struct mm_struct *mm) +{ + if (mm->context != 0) { +#ifdef DEBUG_CACHE + printk("cmm[%d]", (int)mm->context); +#endif + r5432_flush_cache_all_d32i32(); + } +} + +static void r5432_flush_cache_page_d32i32(struct vm_area_struct *vma, + unsigned long page) +{ + struct mm_struct *mm = vma->vm_mm; + pgd_t *pgdp; + pmd_t *pmdp; + pte_t *ptep; + + /* + * If ownes no valid ASID yet, cannot possibly have gotten + * this page into the cache. + */ + if (mm->context == 0) + return; + +#ifdef DEBUG_CACHE + printk("cpage[%d,%08lx]", (int)mm->context, page); +#endif + page &= PAGE_MASK; + pgdp = pgd_offset(mm, page); + pmdp = pmd_offset(pgdp, page); + ptep = pte_offset(pmdp, page); + + /* + * If the page isn't marked valid, the page cannot possibly be + * in the cache. + */ + if (!(pte_val(*ptep) & _PAGE_PRESENT)) + return; + + /* + * Doing flushes for another ASID than the current one is + * too difficult since stupid R4k caches do a TLB translation + * for every cache flush operation. So we do indexed flushes + * in that case, which doesn't overly flush the cache too much. + */ + if ((mm == current->active_mm) && (pte_val(*ptep) & _PAGE_VALID)) { + blast_dcache32_page(page); + } else { + /* + * Do indexed flush, too much work to get the (possible) + * tlb refills to work correctly. + */ + page = (KSEG0 + (page & (dcache_size - 1))); + blast_dcache32_page_indexed(page); + } +} + + +/* If the addresses passed to these routines are valid, they are + * either: + * + * 1) In KSEG0, so we can do a direct flush of the page. + * 2) In KSEG2, and since every process can translate those + * addresses all the time in kernel mode we can do a direct + * flush. + * 3) In KSEG1, no flush necessary. + */ +static void r5432_flush_page_to_ram_d32(struct page *page) +{ + blast_dcache32_page((unsigned long)page_address(page)); +} + +static void +r5432_flush_icache_range(unsigned long start, unsigned long end) +{ + r5432_flush_cache_all_d32i32(); +} + +/* + * Ok, this seriously sucks. We use them to flush a user page but don't + * know the virtual address, so we have to blast away the whole icache + * which is significantly more expensive than the real thing. + */ +static void +r5432_flush_icache_page_i32(struct vm_area_struct *vma, struct page *page) +{ + if (!(vma->vm_flags & VM_EXEC)) + return; + + r5432_flush_cache_all_d32i32(); +} + +/* + * Writeback and invalidate the primary cache dcache before DMA. + */ +static void +r5432_dma_cache_wback_inv_pc(unsigned long addr, unsigned long size) +{ + unsigned long end, a; + + if (size >= dcache_size) { + flush_cache_all(); + } else { + a = addr & ~(dc_lsize - 1); + end = (addr + size) & ~(dc_lsize - 1); + while (1) { + flush_dcache_line(a); /* Hit_Writeback_Inv_D */ + if (a == end) break; + a += dc_lsize; + } + } + bc_wback_inv(addr, size); +} + +static void +r5432_dma_cache_inv_pc(unsigned long addr, unsigned long size) +{ + unsigned long end, a; + + if (size >= dcache_size) { + flush_cache_all(); + } else { + a = addr & ~(dc_lsize - 1); + end = (addr + size) & ~(dc_lsize - 1); + while (1) { + flush_dcache_line(a); /* Hit_Writeback_Inv_D */ + if (a == end) break; + a += dc_lsize; + } + } + + bc_inv(addr, size); +} + +static void +r5432_dma_cache_wback(unsigned long addr, unsigned long size) +{ + panic("r5432_dma_cache called - should not happen.\n"); +} + +/* + * While we're protected against bad userland addresses we don't care + * very much about what happens in that case. Usually a segmentation + * fault will dump the process later on anyway ... + */ +static void r5432_flush_cache_sigtramp(unsigned long addr) +{ + unsigned long daddr, iaddr; + + daddr = addr & ~(dc_lsize - 1); + protected_writeback_dcache_line(daddr); + protected_writeback_dcache_line(daddr + dc_lsize); + iaddr = addr & ~(ic_lsize - 1); + protected_flush_icache_line(iaddr); + protected_flush_icache_line(iaddr + ic_lsize); +} + +#undef DEBUG_TLB +#undef DEBUG_TLBUPDATE + +#define NTLB_ENTRIES 48 /* Fixed on all R4XX0 variants... */ + +#define NTLB_ENTRIES_HALF 24 /* Fixed on all R4XX0 variants... */ + +void flush_tlb_all(void) +{ + unsigned long old_ctx; + int entry; + unsigned long flags; + +#ifdef DEBUG_TLB + printk("[tlball]"); +#endif + + __save_and_cli(flags); + /* Save old context and create impossible VPN2 value */ + old_ctx = (get_entryhi() & 0xff); + set_entryhi(KSEG0); + set_entrylo0(0); + set_entrylo1(0); + BARRIER; + + entry = get_wired(); + + /* Blast 'em all away. */ + while(entry < NTLB_ENTRIES) { + set_index(entry); + BARRIER; + tlb_write_indexed(); + BARRIER; + entry++; + } + BARRIER; + set_entryhi(old_ctx); + __restore_flags(flags); +} + +void flush_tlb_mm(struct mm_struct *mm) +{ + if (mm->context != 0) { + unsigned long flags; + +#ifdef DEBUG_TLB + printk("[tlbmm<%d>]", mm->context); +#endif + __save_and_cli(flags); + get_new_mmu_context(mm, asid_cache); + if (mm == current->active_mm) + set_entryhi(mm->context & 0xff); + __restore_flags(flags); + } +} + +void flush_tlb_range(struct mm_struct *mm, unsigned long start, + unsigned long end) +{ + if(mm->context != 0) { + unsigned long flags; + int size; + +#ifdef DEBUG_TLB + printk("[tlbrange<%02x,%08lx,%08lx>]", (mm->context & 0xff), + start, end); +#endif + __save_and_cli(flags); + size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT; + size = (size + 1) >> 1; + if(size <= NTLB_ENTRIES_HALF) { + int oldpid = (get_entryhi() & 0xff); + int newpid = (mm->context & 0xff); + + start &= (PAGE_MASK << 1); + end += ((PAGE_SIZE << 1) - 1); + end &= (PAGE_MASK << 1); + while(start < end) { + int idx; + + set_entryhi(start | newpid); + start += (PAGE_SIZE << 1); + BARRIER; + tlb_probe(); + BARRIER; + idx = get_index(); + set_entrylo0(0); + set_entrylo1(0); + set_entryhi(KSEG0); + BARRIER; + if(idx < 0) + continue; + tlb_write_indexed(); + BARRIER; + } + set_entryhi(oldpid); + } else { + get_new_mmu_context(mm, asid_cache); + if (mm == current->active_mm) + set_entryhi(mm->context & 0xff); + } + __restore_flags(flags); + } +} + +void flush_tlb_page(struct vm_area_struct *vma, unsigned long page) +{ + if (vma->vm_mm->context != 0) { + unsigned long flags; + int oldpid, newpid, idx; + +#ifdef DEBUG_TLB + printk("[tlbpage<%d,%08lx>]", vma->vm_mm->context, page); +#endif + newpid = (vma->vm_mm->context & 0xff); + page &= (PAGE_MASK << 1); + __save_and_cli(flags); + oldpid = (get_entryhi() & 0xff); + set_entryhi(page | newpid); + BARRIER; + tlb_probe(); + BARRIER; + idx = get_index(); + set_entrylo0(0); + set_entrylo1(0); + set_entryhi(KSEG0); + if(idx < 0) + goto finish; + BARRIER; + tlb_write_indexed(); + + finish: + BARRIER; + set_entryhi(oldpid); + __restore_flags(flags); + } +} + +void pgd_init(unsigned long page) +{ + unsigned long *p = (unsigned long *) page; + int i; + + for(i = 0; i < USER_PTRS_PER_PGD; i+=8) { + p[i + 0] = (unsigned long) invalid_pte_table; + p[i + 1] = (unsigned long) invalid_pte_table; + p[i + 2] = (unsigned long) invalid_pte_table; + p[i + 3] = (unsigned long) invalid_pte_table; + p[i + 4] = (unsigned long) invalid_pte_table; + p[i + 5] = (unsigned long) invalid_pte_table; + p[i + 6] = (unsigned long) invalid_pte_table; + p[i + 7] = (unsigned long) invalid_pte_table; + } +} + +/* We will need multiple versions of update_mmu_cache(), one that just + * updates the TLB with the new pte(s), and another which also checks + * for the R4k "end of page" hardware bug and does the needy. + */ +void update_mmu_cache(struct vm_area_struct * vma, + unsigned long address, pte_t pte) +{ + unsigned long flags; + pgd_t *pgdp; + pmd_t *pmdp; + pte_t *ptep; + int idx, pid; + + /* + * Handle debugger faulting in for debugee. + */ + if (current->active_mm != vma->vm_mm) + return; + + pid = get_entryhi() & 0xff; + +#ifdef DEBUG_TLB + if((pid != (vma->vm_mm->context & 0xff)) || (vma->vm_mm->context == 0)) { + printk("update_mmu_cache: Wheee, bogus tlbpid mmpid=%d tlbpid=%d\n", + (int) (vma->vm_mm->context & 0xff), pid); + } +#endif + + __save_and_cli(flags); + address &= (PAGE_MASK << 1); + set_entryhi(address | (pid)); + pgdp = pgd_offset(vma->vm_mm, address); + BARRIER; + tlb_probe(); + BARRIER; + pmdp = pmd_offset(pgdp, address); + idx = get_index(); + ptep = pte_offset(pmdp, address); + BARRIER; + set_entrylo0(pte_val(*ptep++) >> 6); + set_entrylo1(pte_val(*ptep) >> 6); + set_entryhi(address | (pid)); + BARRIER; + if(idx < 0) { + tlb_write_random(); + } else { + tlb_write_indexed(); + } + BARRIER; + set_entryhi(pid); + BARRIER; + __restore_flags(flags); +} + +void show_regs(struct pt_regs * regs) +{ + /* Saved main processor registers. */ + printk("$0 : %08lx %08lx %08lx %08lx\n", + 0UL, regs->regs[1], regs->regs[2], regs->regs[3]); + printk("$4 : %08lx %08lx %08lx %08lx\n", + regs->regs[4], regs->regs[5], regs->regs[6], regs->regs[7]); + printk("$8 : %08lx %08lx %08lx %08lx\n", + regs->regs[8], regs->regs[9], regs->regs[10], regs->regs[11]); + printk("$12: %08lx %08lx %08lx %08lx\n", + regs->regs[12], regs->regs[13], regs->regs[14], regs->regs[15]); + printk("$16: %08lx %08lx %08lx %08lx\n", + regs->regs[16], regs->regs[17], regs->regs[18], regs->regs[19]); + printk("$20: %08lx %08lx %08lx %08lx\n", + regs->regs[20], regs->regs[21], regs->regs[22], regs->regs[23]); + printk("$24: %08lx %08lx\n", + regs->regs[24], regs->regs[25]); + printk("$28: %08lx %08lx %08lx %08lx\n", + regs->regs[28], regs->regs[29], regs->regs[30], regs->regs[31]); + + /* Saved cp0 registers. */ + printk("epc : %08lx\nStatus: %08lx\nCause : %08lx\n", + regs->cp0_epc, regs->cp0_status, regs->cp0_cause); +} + +void add_wired_entry(unsigned long entrylo0, unsigned long entrylo1, + unsigned long entryhi, unsigned long pagemask) +{ + unsigned long flags; + unsigned long wired; + unsigned long old_pagemask; + unsigned long old_ctx; + + __save_and_cli(flags); + /* Save old context and create impossible VPN2 value */ + old_ctx = (get_entryhi() & 0xff); + old_pagemask = get_pagemask(); + wired = get_wired(); + set_wired (wired + 1); + set_index (wired); + BARRIER; + set_pagemask (pagemask); + set_entryhi(entryhi); + set_entrylo0(entrylo0); + set_entrylo1(entrylo1); + BARRIER; + tlb_write_indexed(); + BARRIER; + + set_entryhi(old_ctx); + BARRIER; + set_pagemask (old_pagemask); + flush_tlb_all(); + __restore_flags(flags); +} + +/* Detect and size the various r4k caches. */ +static void __init probe_icache(unsigned long config) +{ + icache_size = 1 << (12 + ((config >> 9) & 7)); + ic_lsize = 16 << ((config >> 5) & 1); + + printk("Primary instruction cache %dkb, linesize %d bytes.\n", + icache_size >> 10, ic_lsize); +} + +static void __init probe_dcache(unsigned long config) +{ + dcache_size = 1 << (12 + ((config >> 6) & 7)); + dc_lsize = 16 << ((config >> 4) & 1); + + printk("Primary data cache %dkb, linesize %d bytes.\n", + dcache_size >> 10, dc_lsize); +} + + +void __init ld_mmu_r5432(void) +{ + unsigned long config = read_32bit_cp0_register(CP0_CONFIG); + + printk("CPU revision is: %08x\n", read_32bit_cp0_register(CP0_PRID)); + + change_cp0_config(CONF_CM_CMASK, CONF_CM_CACHABLE_NONCOHERENT); + + probe_icache(config); + probe_dcache(config); + + _clear_page = r5432_clear_page_d32; + _copy_page = r5432_copy_page_d32; + _flush_cache_all = r5432_flush_cache_all_d32i32; + ___flush_cache_all = r5432_flush_cache_all_d32i32; + _flush_page_to_ram = r5432_flush_page_to_ram_d32; + _flush_cache_mm = r5432_flush_cache_mm_d32i32; + _flush_cache_range = r5432_flush_cache_range_d32i32; + _flush_cache_page = r5432_flush_cache_page_d32i32; + _flush_icache_page = r5432_flush_icache_page_i32; + _dma_cache_wback_inv = r5432_dma_cache_wback_inv_pc; + _dma_cache_wback = r5432_dma_cache_wback; + _dma_cache_inv = r5432_dma_cache_inv_pc; + + _flush_cache_sigtramp = r5432_flush_cache_sigtramp; + _flush_icache_range = r5432_flush_icache_range; /* Ouch */ + + __flush_cache_all(); + write_32bit_cp0_register(CP0_WIRED, 0); + + /* + * You should never change this register: + * - On R4600 1.7 the tlbp never hits for pages smaller than + * the value in the c0_pagemask register. + * - The entire mm handling assumes the c0_pagemask register to + * be set for 4kb pages. + */ + write_32bit_cp0_register(CP0_PAGEMASK, PM_4K); + flush_tlb_all(); +} diff -u --recursive --new-file v2.4.6/linux/arch/mips/mm/rm7k.c linux/arch/mips/mm/rm7k.c --- v2.4.6/linux/arch/mips/mm/rm7k.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/mm/rm7k.c Wed Jul 4 11:50:39 2001 @@ -0,0 +1,751 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * r4xx0.c: R4000 processor variant specific MMU/Cache routines. + * + * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) + * Copyright (C) 1997, 1998 Ralf Baechle ralf@gnu.org + * + * To do: + * + * - this code is a overbloated pig + * - many of the bug workarounds are not efficient at all, but at + * least they are functional ... + */ +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/mm.h> + +#include <asm/io.h> +#include <asm/page.h> +#include <asm/pgtable.h> +#include <asm/system.h> +#include <asm/bootinfo.h> +#include <asm/mmu_context.h> + +/* CP0 hazard avoidance. */ +#define BARRIER __asm__ __volatile__(".set noreorder\n\t" \ + "nop; nop; nop; nop; nop; nop;\n\t" \ + ".set reorder\n\t") + +/* Primary cache parameters. */ +static int icache_size, dcache_size; /* Size in bytes */ + +#define ic_lsize 32 /* Fixed to 32 byte on RM7000 */ +#define dc_lsize 32 /* Fixed to 32 byte on RM7000 */ +#define sc_lsize 32 /* Fixed to 32 byte on RM7000 */ +#define tc_pagesize (32*128) + +/* Secondary cache parameters. */ +#define scache_size (256*1024) /* Fixed to 256KiB on RM7000 */ + +#include <asm/cacheops.h> +#include <asm/r4kcache.h> + +int rm7k_tcache_enabled = 0; + +/* + * Not added to asm/r4kcache.h because it seems to be RM7000-specific. + */ +#define Page_Invalidate_T 0x16 + +static inline void invalidate_tcache_page(unsigned long addr) +{ + __asm__ __volatile__( + ".set\tnoreorder\t\t\t# invalidate_tcache_page\n\t" + ".set\tmips3\n\t" + "cache\t%1, (%0)\n\t" + ".set\tmips0\n\t" + ".set\treorder" + : + : "r" (addr), + "i" (Page_Invalidate_T)); +} + +/* + * Zero an entire page. Note that while the RM7000 has a second level cache + * it doesn't have a Create_Dirty_Excl_SD operation. + */ +static void rm7k_clear_page(void * page) +{ + __asm__ __volatile__( + ".set\tnoreorder\n\t" + ".set\tnoat\n\t" + ".set\tmips3\n\t" + "daddiu\t$1,%0,%2\n" + "1:\tcache\t%3,(%0)\n\t" + "sd\t$0,(%0)\n\t" + "sd\t$0,8(%0)\n\t" + "sd\t$0,16(%0)\n\t" + "sd\t$0,24(%0)\n\t" + "daddiu\t%0,64\n\t" + "cache\t%3,-32(%0)\n\t" + "sd\t$0,-32(%0)\n\t" + "sd\t$0,-24(%0)\n\t" + "sd\t$0,-16(%0)\n\t" + "bne\t$1,%0,1b\n\t" + "sd\t$0,-8(%0)\n\t" + ".set\tmips0\n\t" + ".set\tat\n\t" + ".set\treorder" + :"=r" (page) + :"0" (page), + "I" (PAGE_SIZE), + "i" (Create_Dirty_Excl_D) + :"$1","memory"); +} + + +/* + * Copy an entire page. Note that while the RM7000 has a second level cache + * it doesn't have a Create_Dirty_Excl_SD operation. + */ +static void rm7k_copy_page(void * to, void * from) +{ + unsigned long dummy1, dummy2; + unsigned long reg1, reg2, reg3, reg4; + + __asm__ __volatile__( + ".set\tnoreorder\n\t" + ".set\tnoat\n\t" + ".set\tmips3\n\t" + "daddiu\t$1,%0,%8\n" + "1:\tcache\t%9,(%0)\n\t" + "lw\t%2,(%1)\n\t" + "lw\t%3,4(%1)\n\t" + "lw\t%4,8(%1)\n\t" + "lw\t%5,12(%1)\n\t" + "sw\t%2,(%0)\n\t" + "sw\t%3,4(%0)\n\t" + "sw\t%4,8(%0)\n\t" + "sw\t%5,12(%0)\n\t" + "lw\t%2,16(%1)\n\t" + "lw\t%3,20(%1)\n\t" + "lw\t%4,24(%1)\n\t" + "lw\t%5,28(%1)\n\t" + "sw\t%2,16(%0)\n\t" + "sw\t%3,20(%0)\n\t" + "sw\t%4,24(%0)\n\t" + "sw\t%5,28(%0)\n\t" + "cache\t%9,32(%0)\n\t" + "daddiu\t%0,64\n\t" + "daddiu\t%1,64\n\t" + "lw\t%2,-32(%1)\n\t" + "lw\t%3,-28(%1)\n\t" + "lw\t%4,-24(%1)\n\t" + "lw\t%5,-20(%1)\n\t" + "sw\t%2,-32(%0)\n\t" + "sw\t%3,-28(%0)\n\t" + "sw\t%4,-24(%0)\n\t" + "sw\t%5,-20(%0)\n\t" + "lw\t%2,-16(%1)\n\t" + "lw\t%3,-12(%1)\n\t" + "lw\t%4,-8(%1)\n\t" + "lw\t%5,-4(%1)\n\t" + "sw\t%2,-16(%0)\n\t" + "sw\t%3,-12(%0)\n\t" + "sw\t%4,-8(%0)\n\t" + "bne\t$1,%0,1b\n\t" + "sw\t%5,-4(%0)\n\t" + ".set\tmips0\n\t" + ".set\tat\n\t" + ".set\treorder" + :"=r" (dummy1), "=r" (dummy2), + "=&r" (reg1), "=&r" (reg2), "=&r" (reg3), "=&r" (reg4) + :"0" (to), "1" (from), + "I" (PAGE_SIZE), + "i" (Create_Dirty_Excl_D)); +} + +static void __flush_cache_all_d32i32(void) +{ + blast_dcache32(); + blast_icache32(); +} + +static inline void rm7k_flush_cache_all_d32i32(void) +{ + /* Yes! Caches that don't suck ... */ +} + +static void rm7k_flush_cache_range_d32i32(struct mm_struct *mm, + unsigned long start, + unsigned long end) +{ + /* RM7000 caches are sane ... */ +} + +static void rm7k_flush_cache_mm_d32i32(struct mm_struct *mm) +{ + /* RM7000 caches are sane ... */ +} + +static void rm7k_flush_cache_page_d32i32(struct vm_area_struct *vma, + unsigned long page) +{ + /* RM7000 caches are sane ... */ +} + +static void rm7k_flush_page_to_ram_d32i32(struct page * page) +{ + /* Yes! Caches that don't suck! */ +} + +static void rm7k_flush_icache_range(unsigned long start, unsigned long end) +{ + /* + * FIXME: This is overdoing things and harms performance. + */ + __flush_cache_all_d32i32(); +} + +static void rm7k_flush_icache_page(struct vm_area_struct *vma, + struct page *page) +{ + /* + * FIXME: We should not flush the entire cache but establish some + * temporary mapping and use hit_invalidate operation to flush out + * the line from the cache. + */ + __flush_cache_all_d32i32(); +} + + +/* + * Writeback and invalidate the primary cache dcache before DMA. + * (XXX These need to be fixed ...) + */ +static void +rm7k_dma_cache_wback_inv(unsigned long addr, unsigned long size) +{ + unsigned long end, a; + + a = addr & ~(sc_lsize - 1); + end = (addr + size) & ~(sc_lsize - 1); + while (1) { + flush_dcache_line(a); /* Hit_Writeback_Inv_D */ + flush_icache_line(a); /* Hit_Invalidate_I */ + flush_scache_line(a); /* Hit_Writeback_Inv_SD */ + if (a == end) break; + a += sc_lsize; + } + + if (!rm7k_tcache_enabled) + return; + + a = addr & ~(tc_pagesize - 1); + end = (addr + size) & ~(tc_pagesize - 1); + while(1) { + invalidate_tcache_page(a); /* Page_Invalidate_T */ + if (a == end) break; + a += tc_pagesize; + } +} + +static void +rm7k_dma_cache_inv(unsigned long addr, unsigned long size) +{ + unsigned long end, a; + + a = addr & ~(sc_lsize - 1); + end = (addr + size) & ~(sc_lsize - 1); + while (1) { + invalidate_dcache_line(a); /* Hit_Invalidate_D */ + flush_icache_line(a); /* Hit_Invalidate_I */ + invalidate_scache_line(a); /* Hit_Invalidate_SD */ + if (a == end) break; + a += sc_lsize; + } + + if (!rm7k_tcache_enabled) + return; + + a = addr & ~(tc_pagesize - 1); + end = (addr + size) & ~(tc_pagesize - 1); + while(1) { + invalidate_tcache_page(a); /* Page_Invalidate_T */ + if (a == end) break; + a += tc_pagesize; + } +} + +static void +rm7k_dma_cache_wback(unsigned long addr, unsigned long size) +{ + panic("rm7k_dma_cache_wback called - should not happen.\n"); +} + +/* + * While we're protected against bad userland addresses we don't care + * very much about what happens in that case. Usually a segmentation + * fault will dump the process later on anyway ... + */ +static void rm7k_flush_cache_sigtramp(unsigned long addr) +{ + protected_writeback_dcache_line(addr & ~(dc_lsize - 1)); + protected_flush_icache_line(addr & ~(ic_lsize - 1)); +} + +/* + * Undocumented RM7000: Bit 29 in the info register of the RM7000 v2.0 + * indicates if the TLB has 48 or 64 entries. + * + * 29 1 => 64 entry JTLB + * 0 => 48 entry JTLB + */ +static inline int __attribute__((const)) ntlb_entries(void) +{ + if (get_info() & (1 << 29)) + return 64; + + return 48; +} + +void flush_tlb_all(void) +{ + unsigned long flags; + unsigned long old_ctx; + int entry; + + __save_and_cli(flags); + /* Save old context and create impossible VPN2 value */ + old_ctx = get_entryhi() & 0xff; + set_entryhi(KSEG0); + set_entrylo0(0); + set_entrylo1(0); + BARRIER; + + entry = get_wired(); + + /* Blast 'em all away. */ + while (entry < ntlb_entries()) { + set_index(entry); + BARRIER; + tlb_write_indexed(); + BARRIER; + entry++; + } + BARRIER; + set_entryhi(old_ctx); + __restore_flags(flags); +} + +void flush_tlb_mm(struct mm_struct *mm) +{ + if(mm->context != 0) { + unsigned long flags; + + __save_and_cli(flags); + get_new_mmu_context(mm, asid_cache); + if (mm == current->mm) + set_entryhi(mm->context & 0xff); + __restore_flags(flags); + } +} + +void flush_tlb_range(struct mm_struct *mm, unsigned long start, + unsigned long end) +{ + if(mm->context != 0) { + unsigned long flags; + int size; + + __save_and_cli(flags); + size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT; + size = (size + 1) >> 1; + if (size <= (ntlb_entries() / 2)) { + int oldpid = (get_entryhi() & 0xff); + int newpid = (mm->context & 0xff); + + start &= (PAGE_MASK << 1); + end += ((PAGE_SIZE << 1) - 1); + end &= (PAGE_MASK << 1); + while(start < end) { + int idx; + + set_entryhi(start | newpid); + start += (PAGE_SIZE << 1); + BARRIER; + tlb_probe(); + BARRIER; + idx = get_index(); + set_entrylo0(0); + set_entrylo1(0); + set_entryhi(KSEG0); + BARRIER; + if(idx < 0) + continue; + tlb_write_indexed(); + BARRIER; + } + set_entryhi(oldpid); + } else { + get_new_mmu_context(mm, asid_cache); + if(mm == current->mm) + set_entryhi(mm->context & 0xff); + } + __restore_flags(flags); + } +} + +void flush_tlb_page(struct vm_area_struct *vma, unsigned long page) +{ + if(vma->vm_mm->context != 0) { + unsigned long flags; + int oldpid, newpid, idx; + + newpid = (vma->vm_mm->context & 0xff); + page &= (PAGE_MASK << 1); + __save_and_cli(flags); + oldpid = (get_entryhi() & 0xff); + set_entryhi(page | newpid); + BARRIER; + tlb_probe(); + BARRIER; + idx = get_index(); + set_entrylo0(0); + set_entrylo1(0); + set_entryhi(KSEG0); + if(idx < 0) + goto finish; + BARRIER; + tlb_write_indexed(); + + finish: + BARRIER; + set_entryhi(oldpid); + __restore_flags(flags); + } +} + +void pgd_init(unsigned long page) +{ + unsigned long *p = (unsigned long *) page; + int i; + + for (i = 0; i < USER_PTRS_PER_PGD; i+=8) { + p[i + 0] = (unsigned long) invalid_pte_table; + p[i + 1] = (unsigned long) invalid_pte_table; + p[i + 2] = (unsigned long) invalid_pte_table; + p[i + 3] = (unsigned long) invalid_pte_table; + p[i + 4] = (unsigned long) invalid_pte_table; + p[i + 5] = (unsigned long) invalid_pte_table; + p[i + 6] = (unsigned long) invalid_pte_table; + p[i + 7] = (unsigned long) invalid_pte_table; + } +} + +/* + * We will need multiple versions of update_mmu_cache(), one that just + * updates the TLB with the new pte(s), and another which also checks + * for the R4k "end of page" hardware bug and does the needy. + */ +void update_mmu_cache(struct vm_area_struct * vma, + unsigned long address, pte_t pte) +{ + unsigned long flags; + pgd_t *pgdp; + pmd_t *pmdp; + pte_t *ptep; + int idx, pid; + + /* + * Handle debugger faulting in for debugee. + */ + if (current->active_mm != vma->vm_mm) + return; + + pid = get_entryhi() & 0xff; + + __save_and_cli(flags); + address &= (PAGE_MASK << 1); + set_entryhi(address | (pid)); + pgdp = pgd_offset(vma->vm_mm, address); + BARRIER; + tlb_probe(); + BARRIER; + pmdp = pmd_offset(pgdp, address); + idx = get_index(); + ptep = pte_offset(pmdp, address); + BARRIER; + set_entrylo0(pte_val(*ptep++) >> 6); + set_entrylo1(pte_val(*ptep) >> 6); + set_entryhi(address | (pid)); + BARRIER; + if (idx < 0) { + tlb_write_random(); + } else { + tlb_write_indexed(); + } + BARRIER; + set_entryhi(pid); + BARRIER; + __restore_flags(flags); +} + +void show_regs(struct pt_regs * regs) +{ + /* Saved main processor registers. */ + printk(KERN_INFO "$0 : %08lx %08lx %08lx %08lx\n", + 0UL, regs->regs[1], regs->regs[2], regs->regs[3]); + printk(KERN_INFO "$4 : %08lx %08lx %08lx %08lx\n", + regs->regs[4], regs->regs[5], regs->regs[6], regs->regs[7]); + printk(KERN_INFO "$8 : %08lx %08lx %08lx %08lx\n", + regs->regs[8], regs->regs[9], regs->regs[10], regs->regs[11]); + printk(KERN_INFO "$12: %08lx %08lx %08lx %08lx\n", + regs->regs[12], regs->regs[13], regs->regs[14], regs->regs[15]); + printk(KERN_INFO "$16: %08lx %08lx %08lx %08lx\n", + regs->regs[16], regs->regs[17], regs->regs[18], regs->regs[19]); + printk(KERN_INFO "$20: %08lx %08lx %08lx %08lx\n", + regs->regs[20], regs->regs[21], regs->regs[22], regs->regs[23]); + printk(KERN_INFO "$24: %08lx %08lx\n", + regs->regs[24], regs->regs[25]); + printk(KERN_INFO "$28: %08lx %08lx %08lx %08lx\n", + regs->regs[28], regs->regs[29], regs->regs[30], regs->regs[31]); + + /* Saved cp0 registers. */ + printk(KERN_INFO "epc : %08lx\nStatus: %08lx\nCause : %08lx\n", + regs->cp0_epc, regs->cp0_status, regs->cp0_cause); +} + +void add_wired_entry(unsigned long entrylo0, unsigned long entrylo1, + unsigned long entryhi, unsigned long pagemask) +{ + unsigned long flags; + unsigned long wired; + unsigned long old_pagemask; + unsigned long old_ctx; + + __save_and_cli(flags); + /* Save old context and create impossible VPN2 value */ + old_ctx = (get_entryhi() & 0xff); + old_pagemask = get_pagemask(); + wired = get_wired(); + set_wired (wired + 1); + set_index (wired); + BARRIER; + set_pagemask (pagemask); + set_entryhi(entryhi); + set_entrylo0(entrylo0); + set_entrylo1(entrylo1); + BARRIER; + tlb_write_indexed(); + BARRIER; + + set_entryhi(old_ctx); + BARRIER; + set_pagemask (old_pagemask); + flush_tlb_all(); + __restore_flags(flags); +} + +/* Used for loading TLB entries before trap_init() has started, when we + don't actually want to add a wired entry which remains throughout the + lifetime of the system */ + +static int temp_tlb_entry __initdata; + +__init int add_temporary_entry(unsigned long entrylo0, unsigned long entrylo1, + unsigned long entryhi, unsigned long pagemask) +{ + int ret = 0; + unsigned long flags; + unsigned long wired; + unsigned long old_pagemask; + unsigned long old_ctx; + + __save_and_cli(flags); + /* Save old context and create impossible VPN2 value */ + old_ctx = (get_entryhi() & 0xff); + old_pagemask = get_pagemask(); + wired = get_wired(); + if (--temp_tlb_entry < wired) { + printk(KERN_WARNING "No TLB space left for add_temporary_entry\n"); + ret = -ENOSPC; + goto out; + } + + set_index (temp_tlb_entry); + BARRIER; + set_pagemask (pagemask); + set_entryhi(entryhi); + set_entrylo0(entrylo0); + set_entrylo1(entrylo1); + BARRIER; + tlb_write_indexed(); + BARRIER; + + set_entryhi(old_ctx); + BARRIER; + set_pagemask (old_pagemask); + out: + __restore_flags(flags); + return ret; +} + + + +/* Detect and size the caches. */ +static inline void probe_icache(unsigned long config) +{ + icache_size = 1 << (12 + ((config >> 9) & 7)); + + printk(KERN_INFO "Primary instruction cache %dKiB.\n", icache_size >> 10); +} + +static inline void probe_dcache(unsigned long config) +{ + dcache_size = 1 << (12 + ((config >> 6) & 7)); + + printk(KERN_INFO "Primary data cache %dKiB.\n", dcache_size >> 10); +} + + +/* + * This function is executed in the uncached segment KSEG1. + * It must not touch the stack, because the stack pointer still points + * into KSEG0. + * + * Three options: + * - Write it in assembly and guarantee that we don't use the stack. + * - Disable caching for KSEG0 before calling it. + * - Pray that GCC doesn't randomly start using the stack. + * + * This being Linux, we obviously take the least sane of those options - + * following DaveM's lead in r4xx0.c + * + * It seems we get our kicks from relying on unguaranteed behaviour in GCC + */ +static __init void setup_scache(void) +{ + int register i; + + set_cp0_config(1<<3 /* CONF_SE */); + + set_taglo(0); + set_taghi(0); + + for (i=0; i<scache_size; i+=sc_lsize) { + __asm__ __volatile__ ( + ".set noreorder\n\t" + ".set mips3\n\t" + "cache %1, (%0)\n\t" + ".set mips0\n\t" + ".set reorder" + : + : "r" (KSEG0ADDR(i)), + "i" (Index_Store_Tag_SD)); + } + +} + +static inline void probe_scache(unsigned long config) +{ + void (*func)(void) = KSEG1ADDR(&setup_scache); + + if ((config >> 31) & 1) + return; + + printk(KERN_INFO "Secondary cache %dKiB, linesize %d bytes.\n", + (scache_size >> 10), sc_lsize); + + if ((config >> 3) & 1) + return; + + printk(KERN_INFO "Enabling secondary cache..."); + func(); + printk("Done\n"); +} + +static inline void probe_tcache(unsigned long config) +{ + if ((config >> 17) & 1) + return; + + /* We can't enable the L3 cache yet. There may be board-specific + * magic necessary to turn it on, and blindly asking the CPU to + * start using it would may give cache errors. + * + * Also, board-specific knowledge may allow us to use the + * CACHE Flash_Invalidate_T instruction if the tag RAM supports + * it, and may specify the size of the L3 cache so we don't have + * to probe it. + */ + printk(KERN_INFO "Tertiary cache present, %s enabled\n", + config&(1<<12) ? "already" : "not (yet)"); + + if ((config >> 12) & 1) + rm7k_tcache_enabled = 1; +} + +void __init ld_mmu_rm7k(void) +{ + unsigned long config = read_32bit_cp0_register(CP0_CONFIG); + unsigned long addr; + + printk("CPU revision is: %08x\n", read_32bit_cp0_register(CP0_PRID)); + + change_cp0_config(CONF_CM_CMASK, CONF_CM_UNCACHED); + + /* RM7000 erratum #31. The icache is screwed at startup. */ + set_taglo(0); + set_taghi(0); + for (addr = KSEG0; addr <= KSEG0 + 4096; addr += ic_lsize) { + __asm__ __volatile__ ( + ".set noreorder\n\t" + ".set mips3\n\t" + "cache\t%1, 0(%0)\n\t" + "cache\t%1, 0x1000(%0)\n\t" + "cache\t%1, 0x2000(%0)\n\t" + "cache\t%1, 0x3000(%0)\n\t" + "cache\t%2, 0(%0)\n\t" + "cache\t%2, 0x1000(%0)\n\t" + "cache\t%2, 0x2000(%0)\n\t" + "cache\t%2, 0x3000(%0)\n\t" + "cache\t%1, 0(%0)\n\t" + "cache\t%1, 0x1000(%0)\n\t" + "cache\t%1, 0x2000(%0)\n\t" + "cache\t%1, 0x3000(%0)\n\t" + ".set\tmips0\n\t" + ".set\treorder\n\t" + : + : "r" (addr), "i" (Index_Store_Tag_I), "i" (Fill)); + } + +#ifndef CONFIG_MIPS_UNCACHED + change_cp0_config(CONF_CM_CMASK, CONF_CM_CACHABLE_NONCOHERENT); +#endif + + probe_icache(config); + probe_dcache(config); + probe_scache(config); + probe_tcache(config); + + printk("TLB has %d entries.\n", ntlb_entries()); + + _clear_page = rm7k_clear_page; + _copy_page = rm7k_copy_page; + + _flush_cache_all = rm7k_flush_cache_all_d32i32; + ___flush_cache_all = __flush_cache_all_d32i32; + _flush_cache_mm = rm7k_flush_cache_mm_d32i32; + _flush_cache_range = rm7k_flush_cache_range_d32i32; + _flush_cache_page = rm7k_flush_cache_page_d32i32; + _flush_page_to_ram = rm7k_flush_page_to_ram_d32i32; + _flush_cache_sigtramp = rm7k_flush_cache_sigtramp; + _flush_icache_range = rm7k_flush_icache_range; + _flush_icache_page = rm7k_flush_icache_page; + + _dma_cache_wback_inv = rm7k_dma_cache_wback_inv; + _dma_cache_wback = rm7k_dma_cache_wback; + _dma_cache_inv = rm7k_dma_cache_inv; + + __flush_cache_all_d32i32(); + write_32bit_cp0_register(CP0_WIRED, 0); + temp_tlb_entry = ntlb_entries() - 1; + write_32bit_cp0_register(CP0_PAGEMASK, PM_4K); + flush_tlb_all(); +} diff -u --recursive --new-file v2.4.6/linux/arch/mips/mm/sb1.c linux/arch/mips/mm/sb1.c --- v2.4.6/linux/arch/mips/mm/sb1.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/mm/sb1.c Wed Jul 4 11:50:39 2001 @@ -0,0 +1,436 @@ +/* + * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) + * Copyright (C) 1997, 2001 Ralf Baechle (ralf@gnu.org) + * Copyright (C) 2000 Sibyte + * + * Written by Justin Carlson (carlson@sibyte.com) + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + + +/* + * In this entire file, I'm not sure what the role of the L2 on the sb1250 + * is. Since it is coherent to the system, we should never need to flush + * it...right?...right??? -JDC + */ + +#include <asm/mmu_context.h> + +/* These are probed at ld_mmu time */ +static unsigned int icache_size; +static unsigned int dcache_size; + +static unsigned int icache_line_size; +static unsigned int dcache_line_size; + +static unsigned int icache_assoc; +static unsigned int dcache_assoc; + +static unsigned int icache_sets; +static unsigned int dcache_sets; +static unsigned int tlb_entries; + +void pgd_init(unsigned long page) +{ + unsigned long *p = (unsigned long *) page; + int i; + + for (i = 0; i < USER_PTRS_PER_PGD; i+=8) { + p[i + 0] = (unsigned long) invalid_pte_table; + p[i + 1] = (unsigned long) invalid_pte_table; + p[i + 2] = (unsigned long) invalid_pte_table; + p[i + 3] = (unsigned long) invalid_pte_table; + p[i + 4] = (unsigned long) invalid_pte_table; + p[i + 5] = (unsigned long) invalid_pte_table; + p[i + 6] = (unsigned long) invalid_pte_table; + p[i + 7] = (unsigned long) invalid_pte_table; + } +} + +void flush_tlb_all(void) +{ + unsigned long flags; + unsigned long old_ctx; + int entry; + + __save_and_cli(flags); + /* Save old context and create impossible VPN2 value */ + old_ctx = (get_entryhi() & 0xff); + set_entrylo0(0); + set_entrylo1(0); + for (entry = 0; entry < tlb_entries; entry++) { + set_entryhi(KSEG0 + (PAGE_SIZE << 1) * entry); + set_index(entry); + tlb_write_indexed(); + } + set_entryhi(old_ctx); + __restore_flags(flags); +} + + + +/* These are the functions hooked by the memory management function pointers */ +static void sb1_clear_page(void *page) +{ + /* JDCXXX - This should be bottlenecked by the write buffer, but these + things tend to be mildly unpredictable...should check this on the + performance model */ + + /* We prefetch 4 lines ahead. We're also "cheating" slightly here... + since we know we're on an SB1, we force the assembler to take + 64-bit operands to speed things up */ + __asm__ __volatile__( + ".set push \n" + ".set noreorder \n" + ".set noat \n" + ".set mips4 \n" + " addiu $1, %0, %2 \n" /* Calculate the end of the page to clear */ + " pref 5, 0(%0) \n" /* Prefetch the first 4 lines */ + " pref 5, 32(%0) \n" + " pref 5, 64(%0) \n" + " pref 5, 96(%0) \n" + "1: sd $0, 0(%0) \n" /* Throw out a cacheline of 0's */ + " sd $0, 8(%0) \n" + " sd $0, 16(%0) \n" + " sd $0, 24(%0) \n" + " pref 5,128(%0) \n" /* Prefetch 4 lines ahead */ + " bne $1, %0, 1b \n" + " addiu %0, %0, 32 \n" /* Next cacheline (This instruction better be short piped!) */ + ".set pop \n" + :"=r" (page) + :"0" (page), + "I" (PAGE_SIZE-32) + :"$1","memory"); + +} + +static void sb1_copy_page(void *to, void *from) +{ + + /* This should be optimized in assembly...can't use ld/sd, though, + * because the top 32 bits could be nuked if we took an interrupt + * during the routine. And this is not a good place to be cli()'ing + */ + + /* The pref's used here are using "streaming" hints, which cause the + * copied data to be kicked out of the cache sooner. A page copy often + * ends up copying a lot more data than is commonly used, so this seems + * to make sense in terms of reducing cache pollution, but I've no real + * performance data to back this up + */ + + __asm__ __volatile__( + ".set push \n" + ".set noreorder \n" + ".set noat \n" + ".set mips4 \n" + " addiu $1, %0, %4 \n" /* Calculate the end of the page to copy */ + " pref 4, 0(%0) \n" /* Prefetch the first 3 lines to be read and copied */ + " pref 5, 0(%1) \n" + " pref 4, 32(%0) \n" + " pref 5, 32(%1) \n" + " pref 4, 64(%0) \n" + " pref 5, 64(%1) \n" + "1: lw $2, 0(%0) \n" /* Block copy a cacheline */ + " lw $3, 4(%0) \n" + " lw $4, 8(%0) \n" + " lw $5, 12(%0) \n" + " lw $6, 16(%0) \n" + " lw $7, 20(%0) \n" + " lw $8, 24(%0) \n" + " lw $9, 28(%0) \n" + " pref 4, 96(%0) \n" /* Prefetch ahead */ + " pref 5, 96(%1) \n" + " sw $2, 0(%1) \n" + " sw $3, 4(%1) \n" + " sw $4, 8(%1) \n" + " sw $5, 12(%1) \n" + " sw $6, 16(%1) \n" + " sw $7, 20(%1) \n" + " sw $8, 24(%1) \n" + " sw $9, 28(%1) \n" + " addiu %1, %1, 32 \n" /* Next cacheline */ + " nop \n" /* Force next add to short pipe */ + " nop \n" /* Force next add to short pipe */ + " bne $1, %0, 1b \n" + " addiu %0, %0, 32 \n" /* Next cacheline */ + ".set pop \n" + :"=r" (to), + "=r" (from) + : + "0" (from), + "1" (to), + "I" (PAGE_SIZE-32) + :"$1","$2","$3","$4","$5","$6","$7","$8","$9","memory"); +/* + unsigned long *src = from; + unsigned long *dest = to; + unsigned long *target = (unsigned long *) (((unsigned long)src) + PAGE_SIZE); + while (src != target) { + *dest++ = *src++; + } +*/ +} + +/* + * The dcache is fully coherent to the system, with one + * big caveat: the instruction stream. In other words, + * if we miss in the icache, and have dirty data in the + * L1 dcache, then we'll go out to memory (or the L2) and + * get the not-as-recent data. + * + * So the only time we have to flush the dcache is when + * we're flushing the icache. Since the L2 is fully + * coherent to everything, including I/O, we never have + * to flush it + */ + +static void sb1_flush_cache_all(void) +{ + + /* + * Haven't worried too much about speed here; given that we're flushing + * the icache, the time to invalidate is dwarfed by the time it's going + * to take to refill it. Register usage: + * + * $1 - moving cache index + * $2 - set count + */ + if (icache_sets) { + __asm__ __volatile__ ( + ".set push \n" + ".set noreorder \n" + ".set noat \n" + ".set mips4 \n" + " move $1, %2 \n" /* Start at index 0 */ + "1: cache 0, 0($1) \n" /* Invalidate this index */ + " addiu %1, %1, -1 \n" /* Decrement loop count */ + " bnez %1, 1b \n" /* loop test */ + " addu $1, $1, %0 \n" /* Next address JDCXXX - Should be short piped */ + ".set pop \n" + ::"r" (icache_line_size), + "r" (icache_sets * icache_assoc), + "r" (KSEG0) + :"$1"); + } + if (dcache_sets) { + __asm__ __volatile__ ( + ".set push \n" + ".set noreorder \n" + ".set noat \n" + ".set mips4 \n" + " move $1, %2 \n" /* Start at index 0 */ + "1: cache 0x1, 0($1) \n" /* WB/Invalidate this index */ + " addiu %1, %1, -1 \n" /* Decrement loop count */ + " bnez %1, 1b \n" /* loop test */ + " addu $1, $1, %0 \n" /* Next address JDCXXX - Should be short piped */ + ".set pop \n" + ::"r" (dcache_line_size), + "r" (dcache_sets * dcache_assoc), + "r" (KSEG0) + :"$1"); + } +} + +/* + * When flushing a range in the icache, we have to first writeback + * the dcache for the same range, so new ifetches will see any + * data that was dirty in the dcache + */ + +static void sb1_flush_icache_range(unsigned long start, unsigned long end) +{ + + /* JDCXXX - Implement me! */ + sb1_flush_cache_all(); +} + +static void sb1_flush_cache_mm(struct mm_struct *mm) +{ + /* Don't need to do this, as the dcache is physically tagged */ +} + +static void sb1_flush_cache_range(struct mm_struct *mm, + unsigned long start, + unsigned long end) +{ + /* Don't need to do this, as the dcache is physically tagged */ +} + + +static void sb1_flush_cache_sigtramp(unsigned long page) +{ + /* JDCXXX - Implement me! */ + sb1_flush_cache_all(); +} + + +/* + * This only needs to make sure stores done up to this + * point are visible to other agents outside the CPU. Given + * the coherent nature of the ZBus, all that's required here is + * a sync to make sure the data gets out to the caches and is + * visible to an arbitrary A Phase from an external agent + * + * Actually, I'm not even sure that's necessary; the semantics + * of this function aren't clear. If it's supposed to serve as + * a memory barrier, this is needed. If it's only meant to + * prevent data from being invisible to non-cpu memory accessors + * for some indefinite period of time (e.g. in a non-coherent + * dcache) then this function would be a complete nop. + */ +static void sb1_flush_page_to_ram(struct page *page) +{ + __asm__ __volatile__( + " sync \n" /* Short pipe */ + :::"memory"); +} + + +/* Cribbed from the r2300 code */ +static void sb1_flush_cache_page(struct vm_area_struct *vma, + unsigned long page) +{ + sb1_flush_cache_all(); +#if 0 + struct mm_struct *mm = vma->vm_mm; + unsigned long physpage; + + /* No icache flush needed without context; */ + if (mm->context == 0) + return; + + /* No icache flush needed if the page isn't executable */ + if (!(vma->vm_flags & VM_EXEC)) + return; + + physpage = (unsigned long) page_address(page); + if (physpage) + sb1_flush_icache_range(physpage, physpage + PAGE_SIZE); +#endif +} + + +/* + * Cache set values (from the mips64 spec) + * 0 - 64 + * 1 - 128 + * 2 - 256 + * 3 - 512 + * 4 - 1024 + * 5 - 2048 + * 6 - 4096 + * 7 - Reserved + */ +static unsigned int decode_cache_sets(unsigned int config_field) +{ + if (config_field == 7) { + /* JDCXXX - Find a graceful way to abort. */ + return 0; + } + + return (1<<(config_field + 6)); +} + +/* + * Cache line size values (from the mips64 spec) + * 0 - No cache present. + * 1 - 4 bytes + * 2 - 8 bytes + * 3 - 16 bytes + * 4 - 32 bytes + * 5 - 64 bytes + * 6 - 128 bytes + * 7 - Reserved + */ +static unsigned int decode_cache_line_size(unsigned int config_field) +{ + if (config_field == 0) { + return 0; + } else if (config_field == 7) { + /* JDCXXX - Find a graceful way to abort. */ + return 0; + } + return (1<<(config_field + 1)); +} + +/* + * Relevant bits of the config1 register format (from the MIPS32/MIPS64 specs) + * + * 24:22 Icache sets per way + * 21:19 Icache line size + * 18:16 Icache Associativity + * 15:13 Dcache sets per way + * 12:10 Dcache line size + * 9:7 Dcache Associativity + */ + + +static void probe_cache_sizes(void) +{ + u32 config1; + + __asm__ __volatile__( + ".set push \n" + ".set mips64 \n" + " mfc0 %0, $16, 1 \n" /* Get config1 register */ + ".set pop \n" + :"=r" (config1)); + icache_line_size = decode_cache_line_size((config1 >> 19) & 0x7); + dcache_line_size = decode_cache_line_size((config1 >> 10) & 0x7); + icache_sets = decode_cache_sets((config1 >> 22) & 0x7); + dcache_sets = decode_cache_sets((config1 >> 13) & 0x7); + icache_assoc = ((config1 >> 16) & 0x7) + 1; + dcache_assoc = ((config1 >> 7) & 0x7) + 1; + icache_size = icache_line_size * icache_sets * icache_assoc; + dcache_size = dcache_line_size * dcache_sets * dcache_assoc; + tlb_entries = ((config1 >> 25) & 0x3f) + 1; +} + + +/* This is called from loadmmu.c. We have to set up all the + memory management function pointers, as well as initialize + the caches and tlbs */ +void ld_mmu_sb1(void) +{ + probe_cache_sizes(); + + _clear_page = sb1_clear_page; + _copy_page = sb1_copy_page; + + _flush_cache_all = sb1_flush_cache_all; + _flush_cache_mm = sb1_flush_cache_mm; + _flush_cache_range = sb1_flush_cache_range; + _flush_cache_page = sb1_flush_cache_page; + _flush_cache_sigtramp = sb1_flush_cache_sigtramp; + + _flush_page_to_ram = sb1_flush_page_to_ram; + _flush_icache_page = sb1_flush_cache_page; + _flush_icache_range = sb1_flush_icache_range; + + + /* + * JDCXXX I'm not sure whether these are necessary: is this the right + * place to initialize the tlb? If it is, why is it done + * at this level instead of as common code in loadmmu()? + */ + flush_cache_all(); + flush_tlb_all(); + + /* Turn on caching in kseg0 */ + set_cp0_config(CONF_CM_CMASK, 0); +} diff -u --recursive --new-file v2.4.6/linux/arch/mips/mm/umap.c linux/arch/mips/mm/umap.c --- v2.4.6/linux/arch/mips/mm/umap.c Mon Mar 19 12:35:09 2001 +++ linux/arch/mips/mm/umap.c Wed Jul 4 11:50:39 2001 @@ -1,6 +1,4 @@ /* - * arch/mips/mm/umap.c - * * (C) Copyright 1994 Linus Torvalds * * Changes: @@ -21,6 +19,7 @@ #include <linux/shm.h> #include <linux/errno.h> #include <linux/mman.h> +#include <linux/module.h> #include <linux/string.h> #include <linux/vmalloc.h> #include <linux/swap.h> @@ -106,6 +105,8 @@ up_write (&task->mm->mmap_sem); } +EXPORT_SYMBOL(remove_mapping); + void *vmalloc_uncached (unsigned long size) { return __vmalloc (size, GFP_KERNEL | __GFP_HIGHMEM, @@ -180,7 +181,7 @@ end = PGDIR_SIZE; vaddr -= address; do { - pte_t * pte = pte_alloc(pmd, address); + pte_t * pte = pte_alloc(current->mm, pmd, address); if (!pte) return -ENOMEM; vmap_pte_range(pte, address, end - address, address + vaddr); @@ -202,7 +203,7 @@ dir = pgd_offset(current->mm, from); flush_cache_range(current->mm, beg, end); while (from < end) { - pmd_t *pmd = pmd_alloc(dir, from); + pmd_t *pmd = pmd_alloc(current->mm, dir, from); error = -ENOMEM; if (!pmd) break; diff -u --recursive --new-file v2.4.6/linux/arch/mips64/Makefile linux/arch/mips64/Makefile --- v2.4.6/linux/arch/mips64/Makefile Sun Feb 4 21:48:46 2001 +++ linux/arch/mips64/Makefile Wed Jul 4 11:50:38 2001 @@ -64,6 +64,11 @@ CFLAGS := $(CFLAGS) -mcpu=r8000 -mips4 endif +ifdef CONFIG_MIPS_FPU_EMULATOR +CORE_FILES += arch/mips64/math-emu/fpu_emulator.o +SUBDIRS += arch/mips64/math-emu +endif + # # Board-dependent options and extra files # diff -u --recursive --new-file v2.4.6/linux/arch/mips64/arc/Makefile linux/arch/mips64/arc/Makefile --- v2.4.6/linux/arch/mips64/arc/Makefile Sun Feb 4 21:48:46 2001 +++ linux/arch/mips64/arc/Makefile Wed Jul 4 11:50:39 2001 @@ -3,13 +3,10 @@ # L_TARGET = arclib.a -obj-y := init.o printf.o tree.o env.o cmdline.o misc.o time.o file.o \ - identify.o - -ifndef CONFIG_SGI_IP27 - obj-y += console.o -endif +obj-y := console.o init.o identify.o tree.o env.o cmdline.o misc.o time.o \ + file.o obj-$(CONFIG_ARC_MEMORY) += memory.o +obj-$(CONFIG_ARC_CONSOLE) += arc_con.o include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.4.6/linux/arch/mips64/arc/arc_con.c linux/arch/mips64/arc/arc_con.c --- v2.4.6/linux/arch/mips64/arc/arc_con.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips64/arc/arc_con.c Wed Jul 4 11:50:39 2001 @@ -0,0 +1,78 @@ +/* + * Wrap-around code for a console using the + * ARC io-routines. + * + * Copyright (c) 1998 Harald Koerfgen + * Copyright (c) 2001 Ralf Baechle + */ +#include <linux/tty.h> +#include <linux/major.h> +#include <linux/ptrace.h> +#include <linux/init.h> +#include <linux/console.h> +#include <linux/fs.h> + +#include <asm/sgialib.h> + +extern void prom_printf (char *, ...); + +void prom_putchar(char c) +{ + ULONG cnt; + CHAR it = c; + + ArcWrite(1, &it, 1, &cnt); +} + +static void prom_console_write(struct console *co, const char *s, + unsigned count) +{ + unsigned i; + + /* + * Now, do each character + */ + for (i = 0; i < count; i++) { + if (*s == 10) + prom_printf("%c", 13); + prom_printf("%c", *s++); + } +} + +static int prom_console_wait_key(struct console *co) +{ + return 0; +} + +static int __init prom_console_setup(struct console *co, char *options) +{ + return 0; +} + +static kdev_t prom_console_device(struct console *c) +{ + return MKDEV(TTY_MAJOR, 64 + c->index); +} + +static struct console arc_cons = { + "ttyS", + prom_console_write, + NULL, + prom_console_device, + prom_console_wait_key, + NULL, + prom_console_setup, + CON_PRINTBUFFER, + -1, + 0, + NULL +}; + +/* + * Register console. + */ + +void __init arc_console_init(void) +{ + register_console(&arc_cons); +} diff -u --recursive --new-file v2.4.6/linux/arch/mips64/arc/cmdline.c linux/arch/mips64/arc/cmdline.c --- v2.4.6/linux/arch/mips64/arc/cmdline.c Sat May 13 08:30:17 2000 +++ linux/arch/mips64/arc/cmdline.c Wed Jul 4 11:50:39 2001 @@ -1,5 +1,4 @@ -/* $Id: cmdline.c,v 1.2 1999/10/19 20:51:44 ralf Exp $ - * +/* * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. @@ -30,10 +29,49 @@ "SystemPartition=", "OSLoader=", "OSLoadPartition=", - "OSLoadFilename=" + "OSLoadFilename=", + "OSLoadOptions=" }; #define NENTS(foo) ((sizeof((foo)) / (sizeof((foo[0]))))) +static char *used_arc[][2] = { + { "OSLoadPartition=", "root=" }, + { "OSLoadOptions=", "" } +}; + +static char * __init move_firmware_args(char* cp) +{ + char *s; + int actr, i; + + actr = 1; /* Always ignore argv[0] */ + + while (actr < prom_argc) { + for(i = 0; i < NENTS(used_arc); i++) { + int len = strlen(used_arc[i][0]); + + if (!strncmp(prom_argv(actr), used_arc[i][0], len)) { + /* Ok, we want it. First append the replacement... */ + strcat(cp, used_arc[i][1]); + cp += strlen(used_arc[i][1]); + /* ... and now the argument */ + s = strstr(prom_argv(actr), "="); + if (s) { + s++; + strcpy(cp, s); + cp += strlen(s); + } + *cp++ = ' '; + break; + } + } + actr++; + } + + return cp; +} + + void __init prom_init_cmdline(void) { char *cp; @@ -42,11 +80,17 @@ actr = 1; /* Always ignore argv[0] */ cp = &(arcs_cmdline[0]); - while(actr < prom_argc) { - for(i = 0; i < NENTS(ignored); i++) { + /* + * Move ARC variables to the beginning to make sure they can be + * overridden by later arguments. + */ + cp = move_firmware_args(cp); + + while (actr < prom_argc) { + for (i = 0; i < NENTS(ignored); i++) { int len = strlen(ignored[i]); - if(!strncmp(prom_argv(actr), ignored[i], len)) + if (!strncmp(prom_argv(actr), ignored[i], len)) goto pic_cont; } /* Ok, we want it. */ diff -u --recursive --new-file v2.4.6/linux/arch/mips64/arc/console.c linux/arch/mips64/arc/console.c --- v2.4.6/linux/arch/mips64/arc/console.c Tue Nov 28 21:42:04 2000 +++ linux/arch/mips64/arc/console.c Wed Jul 4 11:50:39 2001 @@ -6,22 +6,28 @@ * Copyright (C) 1996 David S. Miller (dm@sgi.com) */ #include <linux/init.h> +#include <linux/kernel.h> #include <asm/sgialib.h> -void prom_putchar(char c) +static char ppbuf[1024]; + +void prom_printf(char *fmt, ...) { - ULONG cnt; - CHAR it = c; + va_list args; + char ch, *bptr; + int i; - ArcWrite(1, &it, 1, &cnt); -} + va_start(args, fmt); + i = vsprintf(ppbuf, fmt, args); -char __init prom_getchar(void) -{ - ULONG cnt; - CHAR c; + bptr = ppbuf; - ArcRead(0, &c, 1, &cnt); + while((ch = *(bptr++)) != 0) { + if(ch == '\n') + prom_putchar('\r'); - return c; + prom_putchar(ch); + } + va_end(args); + return; } diff -u --recursive --new-file v2.4.6/linux/arch/mips64/arc/identify.c linux/arch/mips64/arc/identify.c --- v2.4.6/linux/arch/mips64/arc/identify.c Sun Jul 9 22:18:15 2000 +++ linux/arch/mips64/arc/identify.c Wed Jul 4 11:50:39 2001 @@ -42,14 +42,11 @@ { int i; - for (i = 0; i < sizeof (mach_table); i++) { + for (i = 0; i < (sizeof (mach_table) / sizeof (mach_table[0])); i++) { if(!strcmp(s, mach_table[i].name)) return &mach_table[i]; } - prom_printf("\nYeee, could not determine architecture type <%s>\n", s); - prom_printf("press a key to reboot\n"); - prom_getchar(); - ArcEnterInteractiveMode(); + panic("\nYeee, could not determine architecture type <%s>", s); return NULL; } diff -u --recursive --new-file v2.4.6/linux/arch/mips64/arc/memory.c linux/arch/mips64/arc/memory.c --- v2.4.6/linux/arch/mips64/arc/memory.c Mon Aug 7 21:02:27 2000 +++ linux/arch/mips64/arc/memory.c Wed Jul 4 11:50:39 2001 @@ -1,11 +1,9 @@ -/* $Id: memory.c,v 1.5 2000/01/27 23:21:57 ralf Exp $ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. +/* + * memory.c: PROM library functions for acquiring/using memory descriptors + * given to us from the ARCS firmware. * * Copyright (C) 1996 by David S. Miller - * Copyright (C) 1999, 2000 by Ralf Baechle + * Copyright (C) 1999, 2000, 2001 by Ralf Baechle * Copyright (C) 1999, 2000 by Silicon Graphics, Inc. * * PROM library functions for acquiring/using memory descriptors given to us @@ -41,7 +39,7 @@ "Free/Contig RAM", "Generic Free RAM", "Bad Memory", - "Standlong Program Pages", + "Standalone Program Pages", "ARCS Temp Storage Area", "ARCS Permanent Storage Area" }; @@ -54,31 +52,25 @@ "LoadedProgram", "FirmwareTemporary", "FirmwarePermanent", - "FreeContigiuous" + "FreeContiguous" }; #define mtypes(a) (prom_flags & PROM_FLAG_ARCS) ? arcs_mtypes[a.arcs] : arc_mtypes[a.arc] #endif -static struct prom_pmemblock pblocks[PROM_MAX_PMEMBLOCKS]; - -#define MEMTYPE_DONTUSE 0 -#define MEMTYPE_PROM 1 -#define MEMTYPE_FREE 2 - static inline int memtype_classify_arcs (union linux_memtypes type) { switch (type.arcs) { case arcs_fcontig: case arcs_free: - return MEMTYPE_FREE; + return BOOT_MEM_RAM; case arcs_atmp: - return MEMTYPE_PROM; + return BOOT_MEM_ROM_DATA; case arcs_eblock: case arcs_rvpage: case arcs_bmem: case arcs_prog: case arcs_aperm: - return MEMTYPE_DONTUSE; + return BOOT_MEM_RESERVED; default: BUG(); } @@ -90,15 +82,15 @@ switch (type.arc) { case arc_free: case arc_fcontig: - return MEMTYPE_FREE; + return BOOT_MEM_RAM; case arc_atmp: - return MEMTYPE_PROM; + return BOOT_MEM_ROM_DATA; case arc_eblock: case arc_rvpage: case arc_bmem: case arc_prog: case arc_aperm: - return MEMTYPE_DONTUSE; + return BOOT_MEM_RESERVED; default: BUG(); } @@ -113,52 +105,18 @@ return memtype_classify_arc(type); } -static inline unsigned long find_max_low_pfn(void) -{ - struct prom_pmemblock *p, *highest; - unsigned long pfn; - - p = pblocks; - highest = 0; - while (p->size != 0) { - if (!highest || p->base > highest->base) - highest = p; - p++; - } - - pfn = (highest->base + highest->size) >> PAGE_SHIFT; -#ifdef DEBUG - prom_printf("find_max_low_pfn: 0x%lx pfns.\n", pfn); -#endif - return pfn; -} - -static inline struct prom_pmemblock *find_largest_memblock(void) -{ - struct prom_pmemblock *p, *largest; - - p = pblocks; - largest = 0; - while (p->size != 0) { - if (!largest || p->size > largest->size) - largest = p; - p++; - } - - return largest; -} - void __init prom_meminit(void) { - struct prom_pmemblock *largest; - unsigned long bootmap_size; struct linux_mdesc *p; - int totram; - int i = 0; #ifdef DEBUG + int i = 0; + prom_printf("ARCS MEMORY DESCRIPTOR dump:\n"); + i=0; + prom_printf ("i=%d\n", i); p = ArcGetMemoryDescriptor(PROM_NULL_MDESC); + prom_printf ("i=%d\n", i); while(p) { prom_printf("[%d,%p]: base<%08lx> pages<%08lx> type<%s>\n", i, p, p->base, p->pages, mtypes(p->type)); @@ -167,56 +125,17 @@ } #endif - totram = 0; - i = 0; p = PROM_NULL_MDESC; while ((p = ArcGetMemoryDescriptor(p))) { - pblocks[i].type = prom_memtype_classify(p->type); - pblocks[i].base = p->base << PAGE_SHIFT; - pblocks[i].size = p->pages << PAGE_SHIFT; - - switch (pblocks[i].type) { - case MEMTYPE_FREE: - totram += pblocks[i].size; -#ifdef DEBUG - prom_printf("free_chunk[%d]: base=%08lx size=%x\n", - i, pblocks[i].base, - pblocks[i].size); -#endif - i++; - break; - case MEMTYPE_PROM: -#ifdef DEBUG - prom_printf("prom_chunk[%d]: base=%08lx size=%x\n", - i, pblocks[i].base, - pblocks[i].size); -#endif - i++; - break; - default: - break; - } - } - pblocks[i].size = 0; + unsigned long base, size; + long type; - max_low_pfn = find_max_low_pfn(); - largest = find_largest_memblock(); - bootmap_size = init_bootmem(largest->base >> PAGE_SHIFT, max_low_pfn); - - for (i = 0; pblocks[i].size; i++) - if (pblocks[i].type == MEMTYPE_FREE) - free_bootmem(pblocks[i].base, pblocks[i].size); - - /* This test is simpleminded. It will fail if the bootmem bitmap - falls into multiple adjacent ARC memory areas. */ - if (bootmap_size > largest->size) { - prom_printf("CRITIAL: overwriting PROM data.\n"); - BUG(); - } - reserve_bootmem(largest->base, bootmap_size); + base = p->base << PAGE_SHIFT; + size = p->pages << PAGE_SHIFT; + type = prom_memtype_classify(p->type); - printk("PROMLIB: Total free ram %dK / %dMB.\n", - totram >> 10, totram >> 20); + add_memory_region(base, size, type); + } } void __init @@ -224,18 +143,19 @@ { struct prom_pmemblock *p; unsigned long freed = 0; - unsigned long addr, end; + unsigned long addr; + int i; - for (p = pblocks; p->size != 0; p++) { - if (p->type != MEMTYPE_PROM) + for (i = 0; i < boot_mem_map.nr_map; i++) { + if (boot_mem_map.map[i].type != BOOT_MEM_ROM_DATA) continue; - addr = PAGE_OFFSET + (unsigned long) (long) p->base; - end = addr + (unsigned long) (long) p->size; - while (addr < end) { - ClearPageReserved(virt_to_page(addr)); - set_page_count(virt_to_page(addr), 1); - free_page(addr); + addr = boot_mem_map.map[i].addr; + while (addr < boot_mem_map.map[i].addr + + boot_mem_map.map[i].size) { + ClearPageReserved(virt_to_page(__va(addr))); + set_page_count(virt_to_page(__va(addr)), 1); + free_page((unsigned long)__va(addr)); addr += PAGE_SIZE; freed += PAGE_SIZE; } diff -u --recursive --new-file v2.4.6/linux/arch/mips64/arc/printf.c linux/arch/mips64/arc/printf.c --- v2.4.6/linux/arch/mips64/arc/printf.c Tue Nov 28 21:42:04 2000 +++ linux/arch/mips64/arc/printf.c Wed Dec 31 16:00:00 1969 @@ -1,37 +0,0 @@ -/* $Id: printf.c,v 1.1 1999/08/20 21:13:33 ralf Exp $ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Putting things on the screen using SGI arcs PROM facilities. - * - * Copyright (C) 1996 David S. Miller (dm@sgi.com) - */ -#include <linux/init.h> -#include <linux/kernel.h> - -#include <asm/sgialib.h> - -static char ppbuf[1024]; - -void prom_printf(char *fmt, ...) -{ - va_list args; - char ch, *bptr; - int i; - - va_start(args, fmt); - i = vsprintf(ppbuf, fmt, args); - - bptr = ppbuf; - - while((ch = *(bptr++)) != 0) { - if(ch == '\n') - prom_putchar('\r'); - - prom_putchar(ch); - } - va_end(args); - return; -} diff -u --recursive --new-file v2.4.6/linux/arch/mips64/arc/tree.c linux/arch/mips64/arc/tree.c --- v2.4.6/linux/arch/mips64/arc/tree.c Sat May 13 08:30:17 2000 +++ linux/arch/mips64/arc/tree.c Wed Jul 4 11:50:39 2001 @@ -123,8 +123,6 @@ dump_component(p); p = ArcGetPeer(p); } - prom_printf("press a key\n"); - prom_getchar(); } #endif /* DEBUG_PROM_TREE */ diff -u --recursive --new-file v2.4.6/linux/arch/mips64/config.in linux/arch/mips64/config.in --- v2.4.6/linux/arch/mips64/config.in Tue Apr 17 17:19:25 2001 +++ linux/arch/mips64/config.in Wed Jul 4 11:50:39 2001 @@ -11,8 +11,10 @@ mainmenu_option next_comment comment 'Machine selection' -bool 'Support for SGI IP22' CONFIG_SGI_IP22 -bool 'Support for SGI IP27' CONFIG_SGI_IP27 +choice 'Machine type' \ + "SGI-IP22,Indy/Indigo2 CONFIG_SGI_IP22 \ + SGI-IP27,Origin200/2000 CONFIG_SGI_IP27 SGI-IP27,Origin200/2000" + if [ "$CONFIG_SGI_IP27" = "y" ]; then bool ' IP27 N-Mode' CONFIG_SGI_SN0_N_MODE bool ' Discontiguous Memory Support' CONFIG_DISCONTIGMEM @@ -47,6 +49,7 @@ define_bool CONFIG_BOARD_SCACHE y define_bool CONFIG_ARC_MEMORY y define_bool CONFIG_SGI y + define_int CONFIG_L1_CACHE_SHIFT 5 fi if [ "$CONFIG_SGI_IP27" = "y" ]; then @@ -55,6 +58,7 @@ define_bool CONFIG_COHERENT_IO y define_bool CONFIG_PCI y define_bool CONFIG_QL_ISP_A64 y + define_int CONFIG_L1_CACHE_SHIFT 7 fi if [ "$CONFIG_ISA" != "y" ]; then @@ -91,6 +95,10 @@ fi bool 'Generate little endian code' CONFIG_CPU_LITTLE_ENDIAN +if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + bool 'Kernel floating-point emulation' CONFIG_MIPS_FPU_EMULATOR +fi + bool 'Networking support' CONFIG_NET source drivers/pci/Config.in @@ -106,6 +114,11 @@ bool 'System V IPC' CONFIG_SYSVIPC bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT bool 'Sysctl support' CONFIG_SYSCTL + +if [ "$CONFIG_ARC32" = "y" ]; then + bool 'ARC console support' CONFIG_ARC_CONSOLE +fi + tristate 'Kernel support for 64-bit ELF binaries' CONFIG_BINFMT_ELF bool 'Kernel support for Linux/MIPS 32-bit binary compatibility' CONFIG_MIPS32_COMPAT if [ "$CONFIG_MIPS32_COMPAT" = "y" ]; then @@ -125,14 +138,12 @@ source drivers/pci/Config.in -if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - bool 'Support for frame buffer devices (EXPERIMENTAL)' CONFIG_FB -fi - endmenu source drivers/mtd/Config.in +source drivers/parport/Config.in + source drivers/block/Config.in source drivers/md/Config.in @@ -166,7 +177,7 @@ fi endmenu -source drivers/i2o/Config.in +source drivers/message/i2o/Config.in if [ "$CONFIG_NET" = "y" ]; then mainmenu_option next_comment @@ -175,16 +186,6 @@ bool 'Network device support' CONFIG_NETDEVICES if [ "$CONFIG_NETDEVICES" = "y" ]; then source drivers/net/Config.in - if [ "$CONFIG_SGI_IP22" = "y" ]; then - bool 'SGI Seeq ethernet controller support' CONFIG_SGISEEQ - fi - if [ "$CONFIG_DECSTATION" = "y" ]; then - bool 'DEC LANCE ethernet controller support' CONFIG_DECLANCE - fi - if [ "$CONFIG_BAGET_MIPS" = "y" ]; then - tristate 'Baget AMD LANCE support' CONFIG_BAGETLANCE - tristate 'Baget Backplane Shared Memory support' CONFIG_BAGETBSM - fi if [ "$CONFIG_ATM" = "y" ]; then source drivers/atm/Config.in fi @@ -227,6 +228,7 @@ if [ "$CONFIG_VT" = "y" ]; then mainmenu_option next_comment comment 'Console drivers' + source drivers/video/Config.in if [ "$CONFIG_SGI_IP22" = "y" ]; then tristate 'SGI Newport Console support' CONFIG_SGI_NEWPORT_CONSOLE if [ "$CONFIG_SGI_NEWPORT_CONSOLE" != "y" ]; then @@ -268,4 +270,7 @@ fi bool 'Remote GDB kernel debugging' CONFIG_REMOTE_DEBUG bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ +if [ "$CONFIG_SMP" != "n" ]; then + bool 'Run uncached' CONFIG_MIPS_UNCACHED +fi endmenu diff -u --recursive --new-file v2.4.6/linux/arch/mips64/defconfig linux/arch/mips64/defconfig --- v2.4.6/linux/arch/mips64/defconfig Fri Apr 13 20:26:07 2001 +++ linux/arch/mips64/defconfig Wed Jul 4 11:50:39 2001 @@ -14,16 +14,19 @@ CONFIG_SGI_IP27=y # CONFIG_SGI_SN0_N_MODE is not set CONFIG_DISCONTIGMEM=y -# CONFIG_NUMA is not set +CONFIG_NUMA=y # CONFIG_MAPPED_KERNEL is not set # CONFIG_REPLICATE_KTEXT is not set # CONFIG_REPLICATE_EXHANDLERS is not set CONFIG_SMP=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set CONFIG_BOOT_ELF64=y CONFIG_ARC64=y CONFIG_COHERENT_IO=y CONFIG_PCI=y CONFIG_QL_ISP_A64=y +CONFIG_L1_CACHE_SHIFT=7 # CONFIG_ISA is not set # CONFIG_EISA is not set # CONFIG_MCA is not set @@ -68,6 +71,11 @@ # CONFIG_MTD is not set # +# Parallel port support +# +# CONFIG_PARPORT is not set + +# # Block devices # # CONFIG_BLK_DEV_FD is not set @@ -95,19 +103,24 @@ # # Networking options # -# CONFIG_PACKET is not set -# CONFIG_NETLINK is not set +CONFIG_PACKET=y +CONFIG_PACKET_MMAP=y +CONFIG_NETLINK=y +CONFIG_RTNETLINK=y +CONFIG_NETLINK_DEV=y # CONFIG_NETFILTER is not set # CONFIG_FILTER is not set CONFIG_UNIX=y CONFIG_INET=y -# CONFIG_IP_MULTICAST is not set +CONFIG_IP_MULTICAST=y # CONFIG_IP_ADVANCED_ROUTER is not set CONFIG_IP_PNP=y -CONFIG_IP_PNP_BOOTP=y +# CONFIG_IP_PNP_DHCP is not set +# CONFIG_IP_PNP_BOOTP is not set # CONFIG_IP_PNP_RARP is not set # CONFIG_NET_IPIP is not set # CONFIG_NET_IPGRE is not set +# CONFIG_IP_MROUTE is not set # CONFIG_INET_ECN is not set # CONFIG_SYN_COOKIES is not set @@ -187,8 +200,6 @@ # CONFIG_SCSI_GENERIC_NCR5380 is not set # CONFIG_SCSI_INITIO is not set # CONFIG_SCSI_INIA100 is not set -# CONFIG_SCSI_PPA is not set -# CONFIG_SCSI_IMM is not set # CONFIG_SCSI_NCR53C406A is not set # CONFIG_SCSI_NCR53C7xx is not set # CONFIG_SCSI_NCR53C8XX is not set @@ -254,7 +265,6 @@ # CONFIG_HAMACHI is not set # CONFIG_SK98LIN is not set # CONFIG_FDDI is not set -# CONFIG_PLIP is not set # CONFIG_PPP is not set # CONFIG_SLIP is not set @@ -302,9 +312,8 @@ CONFIG_SERIAL_CONSOLE=y # CONFIG_SERIAL_EXTENDED is not set # CONFIG_SERIAL_NONSTANDARD is not set -# CONFIG_UNIX98_PTYS is not set -# CONFIG_PRINTER is not set -# CONFIG_PPDEV is not set +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=256 # # I2C support @@ -370,10 +379,12 @@ # CONFIG_EFS_FS is not set # CONFIG_JFFS_FS is not set # CONFIG_CRAMFS is not set +# CONFIG_TMPFS is not set # CONFIG_RAMFS is not set # CONFIG_ISO9660_FS is not set # CONFIG_JOLIET is not set # CONFIG_MINIX_FS is not set +# CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set @@ -381,7 +392,7 @@ # CONFIG_DEVFS_FS is not set # CONFIG_DEVFS_MOUNT is not set # CONFIG_DEVFS_DEBUG is not set -# CONFIG_DEVPTS_FS is not set +CONFIG_DEVPTS_FS=y # CONFIG_QNX4FS_FS is not set # CONFIG_QNX4FS_RW is not set # CONFIG_ROMFS_FS is not set @@ -458,3 +469,4 @@ CONFIG_CROSSCOMPILE=y # CONFIG_REMOTE_DEBUG is not set # CONFIG_MAGIC_SYSRQ is not set +# CONFIG_MIPS_UNCACHED is not set diff -u --recursive --new-file v2.4.6/linux/arch/mips64/defconfig-ip22 linux/arch/mips64/defconfig-ip22 --- v2.4.6/linux/arch/mips64/defconfig-ip22 Fri Apr 13 20:26:07 2001 +++ linux/arch/mips64/defconfig-ip22 Wed Jul 4 11:50:39 2001 @@ -5,18 +5,21 @@ # # Code maturity level options # -# CONFIG_EXPERIMENTAL is not set +CONFIG_EXPERIMENTAL=y # # Machine selection # CONFIG_SGI_IP22=y # CONFIG_SGI_IP27 is not set +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set CONFIG_BOOT_ELF32=y CONFIG_ARC32=y CONFIG_BOARD_SCACHE=y CONFIG_ARC_MEMORY=y CONFIG_SGI=y +CONFIG_L1_CACHE_SHIFT=5 # CONFIG_ISA is not set # CONFIG_EISA is not set # CONFIG_PCI is not set @@ -37,20 +40,25 @@ # General setup # # CONFIG_CPU_LITTLE_ENDIAN is not set +# CONFIG_MIPS_FPU_EMULATOR is not set CONFIG_NET=y # CONFIG_HOTPLUG is not set # CONFIG_PCMCIA is not set CONFIG_SYSVIPC=y # CONFIG_BSD_PROCESS_ACCT is not set CONFIG_SYSCTL=y +# CONFIG_ARC_CONSOLE is not set CONFIG_BINFMT_ELF=y -# CONFIG_MIPS32_COMPAT is not set +CONFIG_MIPS32_COMPAT=y +CONFIG_BINFMT_ELF32=y # CONFIG_BINFMT_MISC is not set # # Loadable module support # -# CONFIG_MODULES is not set +CONFIG_MODULES=y +# CONFIG_MODVERSIONS is not set +CONFIG_KMOD=y # # Memory Technology Devices (MTD) @@ -58,6 +66,11 @@ # CONFIG_MTD is not set # +# Parallel port support +# +# CONFIG_PARPORT is not set + +# # Block devices # # CONFIG_BLK_DEV_FD is not set @@ -85,21 +98,30 @@ # # Networking options # -# CONFIG_PACKET is not set -# CONFIG_NETLINK is not set +CONFIG_PACKET=y +CONFIG_PACKET_MMAP=y +CONFIG_NETLINK=y +CONFIG_RTNETLINK=y +CONFIG_NETLINK_DEV=y # CONFIG_NETFILTER is not set # CONFIG_FILTER is not set CONFIG_UNIX=y CONFIG_INET=y -# CONFIG_IP_MULTICAST is not set +CONFIG_IP_MULTICAST=y # CONFIG_IP_ADVANCED_ROUTER is not set CONFIG_IP_PNP=y +# CONFIG_IP_PNP_DHCP is not set CONFIG_IP_PNP_BOOTP=y # CONFIG_IP_PNP_RARP is not set # CONFIG_NET_IPIP is not set # CONFIG_NET_IPGRE is not set +# CONFIG_IP_MROUTE is not set +# CONFIG_ARPD is not set # CONFIG_INET_ECN is not set # CONFIG_SYN_COOKIES is not set +# CONFIG_IPV6 is not set +# CONFIG_KHTTPD is not set +# CONFIG_ATM is not set # # @@ -108,6 +130,14 @@ # CONFIG_ATALK is not set # CONFIG_DECNET is not set # CONFIG_BRIDGE is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_LLC is not set +# CONFIG_NET_DIVERT is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_FASTROUTE is not set +# CONFIG_NET_HW_FLOWCONTROL is not set # # QoS and/or fair queueing @@ -130,7 +160,66 @@ # # SCSI support # -# CONFIG_SCSI is not set +CONFIG_SCSI=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=y +CONFIG_SD_EXTRA_DEVS=40 +CONFIG_CHR_DEV_ST=y +# CONFIG_CHR_DEV_OSST is not set +CONFIG_BLK_DEV_SR=y +# CONFIG_BLK_DEV_SR_VENDOR is not set +CONFIG_SR_EXTRA_DEVS=2 +# CONFIG_CHR_DEV_SG is not set + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +# CONFIG_SCSI_DEBUG_QUEUES is not set +# CONFIG_SCSI_MULTI_LUN is not set +CONFIG_SCSI_CONSTANTS=y +# CONFIG_SCSI_LOGGING is not set + +# +# SCSI low-level drivers +# +CONFIG_SGIWD93_SCSI=y +# CONFIG_SCSI_7000FASST is not set +# CONFIG_SCSI_ACARD is not set +# CONFIG_SCSI_AHA152X is not set +# CONFIG_SCSI_AHA1542 is not set +# CONFIG_SCSI_AHA1740 is not set +# CONFIG_SCSI_AIC7XXX is not set +# CONFIG_SCSI_AIC7XXX_OLD is not set +# CONFIG_SCSI_ADVANSYS is not set +# CONFIG_SCSI_IN2000 is not set +# CONFIG_SCSI_AM53C974 is not set +# CONFIG_SCSI_MEGARAID is not set +# CONFIG_SCSI_BUSLOGIC is not set +# CONFIG_SCSI_DMX3191D is not set +# CONFIG_SCSI_DTC3280 is not set +# CONFIG_SCSI_EATA is not set +# CONFIG_SCSI_EATA_DMA is not set +# CONFIG_SCSI_EATA_PIO is not set +# CONFIG_SCSI_FUTURE_DOMAIN is not set +# CONFIG_SCSI_GDTH is not set +# CONFIG_SCSI_GENERIC_NCR5380 is not set +# CONFIG_SCSI_INITIO is not set +# CONFIG_SCSI_INIA100 is not set +# CONFIG_SCSI_NCR53C406A is not set +# CONFIG_SCSI_NCR53C7xx is not set +# CONFIG_SCSI_PAS16 is not set +# CONFIG_SCSI_PCI2000 is not set +# CONFIG_SCSI_PCI2220I is not set +# CONFIG_SCSI_PSI240I is not set +# CONFIG_SCSI_QLOGIC_FAS is not set +# CONFIG_SCSI_SIM710 is not set +# CONFIG_SCSI_SYM53C416 is not set +# CONFIG_SCSI_T128 is not set +# CONFIG_SCSI_U14_34F is not set +# CONFIG_SCSI_DEBUG is not set # # I2O device support @@ -154,21 +243,33 @@ # CONFIG_BONDING is not set # CONFIG_EQUALIZER is not set # CONFIG_TUN is not set +# CONFIG_ETHERTAP is not set # CONFIG_NET_SB1000 is not set # # Ethernet (10 or 100Mbit) # -# CONFIG_NET_ETHERNET is not set +CONFIG_NET_ETHERNET=y +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_LANCE is not set +# CONFIG_NET_VENDOR_SMC is not set +# CONFIG_NET_VENDOR_RACAL is not set +# CONFIG_AT1700 is not set +# CONFIG_DEPCA is not set +# CONFIG_NET_ISA is not set +# CONFIG_NET_PCI is not set +# CONFIG_NET_POCKET is not set +CONFIG_SGISEEQ=y # # Ethernet (1000 Mbit) # # CONFIG_ACENIC is not set # CONFIG_HAMACHI is not set +# CONFIG_YELLOWFIN is not set # CONFIG_SK98LIN is not set # CONFIG_FDDI is not set -# CONFIG_PLIP is not set +# CONFIG_HIPPI is not set # CONFIG_PPP is not set # CONFIG_SLIP is not set @@ -182,12 +283,13 @@ # # CONFIG_TR is not set # CONFIG_NET_FC is not set +# CONFIG_RCPCI is not set +# CONFIG_SHAPER is not set # # Wan interfaces # # CONFIG_WAN is not set -CONFIG_SGISEEQ=y # # Amateur Radio support @@ -217,9 +319,8 @@ # CONFIG_SERIAL is not set # CONFIG_SERIAL_EXTENDED is not set # CONFIG_SERIAL_NONSTANDARD is not set -# CONFIG_UNIX98_PTYS is not set -# CONFIG_PRINTER is not set -# CONFIG_PPDEV is not set +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=256 # # I2C support @@ -269,8 +370,8 @@ # File systems # # CONFIG_QUOTA is not set -# CONFIG_AUTOFS_FS is not set -# CONFIG_AUTOFS4_FS is not set +CONFIG_AUTOFS_FS=y +CONFIG_AUTOFS4_FS=y # CONFIG_REISERFS_FS is not set # CONFIG_REISERFS_CHECK is not set # CONFIG_ADFS_FS is not set @@ -285,10 +386,12 @@ # CONFIG_EFS_FS is not set # CONFIG_JFFS_FS is not set # CONFIG_CRAMFS is not set +# CONFIG_TMPFS is not set # CONFIG_RAMFS is not set -# CONFIG_ISO9660_FS is not set +CONFIG_ISO9660_FS=y # CONFIG_JOLIET is not set # CONFIG_MINIX_FS is not set +# CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set @@ -296,7 +399,7 @@ # CONFIG_DEVFS_FS is not set # CONFIG_DEVFS_MOUNT is not set # CONFIG_DEVFS_DEBUG is not set -# CONFIG_DEVPTS_FS is not set +CONFIG_DEVPTS_FS=y # CONFIG_QNX4FS_FS is not set # CONFIG_QNX4FS_RW is not set # CONFIG_ROMFS_FS is not set @@ -315,7 +418,7 @@ CONFIG_NFS_FS=y # CONFIG_NFS_V3 is not set CONFIG_ROOT_NFS=y -# CONFIG_NFSD is not set +CONFIG_NFSD=y # CONFIG_NFSD_V3 is not set CONFIG_SUNRPC=y CONFIG_LOCKD=y @@ -333,14 +436,31 @@ # # Partition Types # -# CONFIG_PARTITION_ADVANCED is not set +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_MINIX_SUBPARTITION is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL is not set CONFIG_SGI_PARTITION=y +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set # CONFIG_SMB_NLS is not set # CONFIG_NLS is not set # # Console drivers # + +# +# Frame-buffer support +# +# CONFIG_FB is not set CONFIG_SGI_NEWPORT_CONSOLE=y CONFIG_FONT_8x16=y CONFIG_KCORE_ELF=y @@ -353,8 +473,10 @@ # # SGI devices # -# CONFIG_SGI_SERIAL is not set +CONFIG_SGI_SERIAL=y +# CONFIG_SERIAL_CONSOLE is not set CONFIG_SGI_DS1286=y +# CONFIG_SGI_NEWPORT_GFX is not set # # USB support @@ -370,5 +492,7 @@ # Kernel hacking # CONFIG_CROSSCOMPILE=y +# CONFIG_MIPS_FPE_MODULE is not set # CONFIG_REMOTE_DEBUG is not set # CONFIG_MAGIC_SYSRQ is not set +# CONFIG_MIPS_UNCACHED is not set diff -u --recursive --new-file v2.4.6/linux/arch/mips64/defconfig-ip27 linux/arch/mips64/defconfig-ip27 --- v2.4.6/linux/arch/mips64/defconfig-ip27 Fri Apr 13 20:26:07 2001 +++ linux/arch/mips64/defconfig-ip27 Wed Jul 4 11:50:39 2001 @@ -14,16 +14,19 @@ CONFIG_SGI_IP27=y # CONFIG_SGI_SN0_N_MODE is not set CONFIG_DISCONTIGMEM=y -# CONFIG_NUMA is not set +CONFIG_NUMA=y # CONFIG_MAPPED_KERNEL is not set # CONFIG_REPLICATE_KTEXT is not set # CONFIG_REPLICATE_EXHANDLERS is not set CONFIG_SMP=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set CONFIG_BOOT_ELF64=y CONFIG_ARC64=y CONFIG_COHERENT_IO=y CONFIG_PCI=y CONFIG_QL_ISP_A64=y +CONFIG_L1_CACHE_SHIFT=7 # CONFIG_ISA is not set # CONFIG_EISA is not set # CONFIG_MCA is not set @@ -68,6 +71,11 @@ # CONFIG_MTD is not set # +# Parallel port support +# +# CONFIG_PARPORT is not set + +# # Block devices # # CONFIG_BLK_DEV_FD is not set @@ -95,19 +103,24 @@ # # Networking options # -# CONFIG_PACKET is not set -# CONFIG_NETLINK is not set +CONFIG_PACKET=y +CONFIG_PACKET_MMAP=y +CONFIG_NETLINK=y +CONFIG_RTNETLINK=y +CONFIG_NETLINK_DEV=y # CONFIG_NETFILTER is not set # CONFIG_FILTER is not set CONFIG_UNIX=y CONFIG_INET=y -# CONFIG_IP_MULTICAST is not set +CONFIG_IP_MULTICAST=y # CONFIG_IP_ADVANCED_ROUTER is not set CONFIG_IP_PNP=y -CONFIG_IP_PNP_BOOTP=y +# CONFIG_IP_PNP_DHCP is not set +# CONFIG_IP_PNP_BOOTP is not set # CONFIG_IP_PNP_RARP is not set # CONFIG_NET_IPIP is not set # CONFIG_NET_IPGRE is not set +# CONFIG_IP_MROUTE is not set # CONFIG_INET_ECN is not set # CONFIG_SYN_COOKIES is not set @@ -187,8 +200,6 @@ # CONFIG_SCSI_GENERIC_NCR5380 is not set # CONFIG_SCSI_INITIO is not set # CONFIG_SCSI_INIA100 is not set -# CONFIG_SCSI_PPA is not set -# CONFIG_SCSI_IMM is not set # CONFIG_SCSI_NCR53C406A is not set # CONFIG_SCSI_NCR53C7xx is not set # CONFIG_SCSI_NCR53C8XX is not set @@ -254,7 +265,6 @@ # CONFIG_HAMACHI is not set # CONFIG_SK98LIN is not set # CONFIG_FDDI is not set -# CONFIG_PLIP is not set # CONFIG_PPP is not set # CONFIG_SLIP is not set @@ -302,9 +312,8 @@ CONFIG_SERIAL_CONSOLE=y # CONFIG_SERIAL_EXTENDED is not set # CONFIG_SERIAL_NONSTANDARD is not set -# CONFIG_UNIX98_PTYS is not set -# CONFIG_PRINTER is not set -# CONFIG_PPDEV is not set +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=256 # # I2C support @@ -370,10 +379,12 @@ # CONFIG_EFS_FS is not set # CONFIG_JFFS_FS is not set # CONFIG_CRAMFS is not set +# CONFIG_TMPFS is not set # CONFIG_RAMFS is not set # CONFIG_ISO9660_FS is not set # CONFIG_JOLIET is not set # CONFIG_MINIX_FS is not set +# CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set @@ -381,7 +392,7 @@ # CONFIG_DEVFS_FS is not set # CONFIG_DEVFS_MOUNT is not set # CONFIG_DEVFS_DEBUG is not set -# CONFIG_DEVPTS_FS is not set +CONFIG_DEVPTS_FS=y # CONFIG_QNX4FS_FS is not set # CONFIG_QNX4FS_RW is not set # CONFIG_ROMFS_FS is not set @@ -458,3 +469,4 @@ CONFIG_CROSSCOMPILE=y # CONFIG_REMOTE_DEBUG is not set # CONFIG_MAGIC_SYSRQ is not set +# CONFIG_MIPS_UNCACHED is not set diff -u --recursive --new-file v2.4.6/linux/arch/mips64/kernel/binfmt_elf32.c linux/arch/mips64/kernel/binfmt_elf32.c --- v2.4.6/linux/arch/mips64/kernel/binfmt_elf32.c Thu Jul 27 18:36:54 2000 +++ linux/arch/mips64/kernel/binfmt_elf32.c Wed Jul 4 11:50:39 2001 @@ -1,8 +1,8 @@ /* * Support for 32-bit Linux/MIPS ELF binaries. * - * Copyright (C) 1999 Ralf Baechle - * Copyright (C) 1999 Silicon Graphics, Inc. + * Copyright (C) 1999, 2001 Ralf Baechle + * Copyright (C) 1999, 2001 Silicon Graphics, Inc. * * Heavily inspired by the 32-bit Sparc compat code which is * Copyright (C) 1995, 1996, 1997, 1998 David S. Miller (davem@redhat.com) @@ -28,7 +28,7 @@ typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG]; #define elf_check_arch(x) \ - ((x)->e_machine == EM_MIPS || (x)->e_machine == EM_MIPS_RS4_BE) + ((x)->e_machine == EM_MIPS) #define TASK32_SIZE 0x80000000UL #undef ELF_ET_DYN_BASE diff -u --recursive --new-file v2.4.6/linux/arch/mips64/kernel/branch.c linux/arch/mips64/kernel/branch.c --- v2.4.6/linux/arch/mips64/kernel/branch.c Sat May 13 08:30:17 2000 +++ linux/arch/mips64/kernel/branch.c Wed Jul 4 11:50:39 2001 @@ -1,5 +1,4 @@ -/* $Id: branch.c,v 1.1 1999/10/09 20:55:05 ralf Exp $ - * +/* * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. @@ -66,7 +65,7 @@ switch (insn.i_format.rt) { case bltz_op: case bltzl_op: - if (regs->regs[insn.i_format.rs] < 0) + if ((long)regs->regs[insn.i_format.rs] < 0) epc = epc + 4 + (insn.i_format.simmediate << 2); else epc += 8; @@ -75,7 +74,7 @@ case bgez_op: case bgezl_op: - if (regs->regs[insn.i_format.rs] >= 0) + if ((long)regs->regs[insn.i_format.rs] >= 0) epc = epc + 4 + (insn.i_format.simmediate << 2); else epc += 8; @@ -85,7 +84,7 @@ case bltzal_op: case bltzall_op: regs->regs[31] = epc + 8; - if (regs->regs[insn.i_format.rs] < 0) + if ((long)regs->regs[insn.i_format.rs] < 0) epc = epc + 4 + (insn.i_format.simmediate << 2); else epc += 8; @@ -95,7 +94,7 @@ case bgezal_op: case bgezall_op: regs->regs[31] = epc + 8; - if (regs->regs[insn.i_format.rs] >= 0) + if ((long)regs->regs[insn.i_format.rs] >= 0) epc = epc + 4 + (insn.i_format.simmediate << 2); else epc += 8; @@ -143,7 +142,7 @@ case blez_op: /* not really i_format */ case blezl_op: /* rt field assumed to be zero */ - if (regs->regs[insn.i_format.rs] <= 0) + if ((long)regs->regs[insn.i_format.rs] <= 0) epc = epc + 4 + (insn.i_format.simmediate << 2); else epc += 8; @@ -153,7 +152,7 @@ case bgtz_op: case bgtzl_op: /* rt field assumed to be zero */ - if (regs->regs[insn.i_format.rs] > 0) + if ((long)regs->regs[insn.i_format.rs] > 0) epc = epc + 4 + (insn.i_format.simmediate << 2); else epc += 8; diff -u --recursive --new-file v2.4.6/linux/arch/mips64/kernel/entry.S linux/arch/mips64/kernel/entry.S --- v2.4.6/linux/arch/mips64/kernel/entry.S Fri Aug 4 16:15:37 2000 +++ linux/arch/mips64/kernel/entry.S Wed Jul 4 11:50:39 2001 @@ -1,5 +1,4 @@ -/* $Id: entry.S,v 1.5 2000/02/23 00:41:00 ralf Exp $ - * +/* * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. diff -u --recursive --new-file v2.4.6/linux/arch/mips64/kernel/head.S linux/arch/mips64/kernel/head.S --- v2.4.6/linux/arch/mips64/kernel/head.S Wed Jul 12 15:14:41 2000 +++ linux/arch/mips64/kernel/head.S Wed Jul 4 11:50:39 2001 @@ -33,6 +33,7 @@ #endif .endm +#ifdef CONFIG_SGI_IP27 /* * outputs the local nasid into t1. */ @@ -42,6 +43,7 @@ and t1, NSRI_NODEID_MASK dsrl t1, NSRI_NODEID_SHFT .endm +#endif /* CONFIG_SGI_IP27 */ /* * inputs are the text nasid in t1, data nasid in t2. @@ -94,9 +96,11 @@ ori sp, 0xf # align stack on 16 byte. xori sp, 0xf +#ifdef CONFIG_SGI_IP27 GET_NASID_ASM move t2, t1 # text and data are here MAPPED_KERNEL_SETUP_TLB +#endif /* IP27 */ ARC64_TWIDDLE_PC @@ -131,6 +135,7 @@ 1: b 1b # just in case ... END(kernel_entry) +#ifdef CONFIG_SGI_IP27 NESTED(bootstrap, 16, sp) GET_NASID_ASM li t0, KLDIR_OFFSET + (KLI_KERN_VARS * KLDIR_ENT_SIZE) + KLDIR_OFF_POINTER + K0BASE @@ -149,6 +154,7 @@ mtc0 t0, CP0_STATUS # thread in copy_thread. jal cboot END(bootstrap) +#endif /* CONFIG_SGI_IP27 */ __FINIT @@ -170,8 +176,6 @@ page swapper_pg_dir, 1 page invalid_pte_table, 0 page invalid_pmd_table, 1 - page empty_bad_page_table, 0 - page empty_bad_pmd_table, 1 page kptbl, KPTBL_PAGE_ORDER .globl ekptbl page kpmdtbl, 0 diff -u --recursive --new-file v2.4.6/linux/arch/mips64/kernel/ioctl32.c linux/arch/mips64/kernel/ioctl32.c --- v2.4.6/linux/arch/mips64/kernel/ioctl32.c Tue Nov 28 21:42:04 2000 +++ linux/arch/mips64/kernel/ioctl32.c Wed Jul 4 11:50:39 2001 @@ -7,6 +7,7 @@ * * Mostly stolen from the sparc64 ioctl32 implementation. */ +#include <linux/config.h> #include <linux/types.h> #include <linux/kernel.h> #include <linux/fs.h> @@ -25,6 +26,7 @@ #include <linux/elevator.h> #include <linux/auto_fs.h> #include <linux/ext2_fs.h> +#include <linux/raid/md_u.h> #include <asm/types.h> #include <asm/uaccess.h> @@ -67,6 +69,24 @@ int tv_usec; }; +static int do_siocgstamp(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + struct timeval32 *up = (struct timeval32 *)arg; + struct timeval ktv; + mm_segment_t old_fs = get_fs(); + int err; + + set_fs(KERNEL_DS); + err = sys_ioctl(fd, cmd, (unsigned long)&ktv); + set_fs(old_fs); + if (!err) { + err = put_user(ktv.tv_sec, &up->tv_sec); + err |= __put_user(ktv.tv_usec, &up->tv_usec); + } + + return err; +} + #define EXT2_IOC32_GETFLAGS _IOR('f', 1, int) #define EXT2_IOC32_SETFLAGS _IOW('f', 2, int) #define EXT2_IOC32_GETVERSION _IOR('v', 1, int) @@ -108,6 +128,8 @@ __kernel_caddr_t32 ifcbuf; }; +#ifdef CONFIG_NET + static int dev_ifname32(unsigned int fd, unsigned int cmd, unsigned long arg) { struct ireq32 *uir32 = (struct ireq32 *)arg; @@ -308,6 +330,8 @@ return ret; } +#endif /* CONFIG_NET */ + static int do_ext2_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) { /* These are just misnamed, they actually get/put from/to user an int */ @@ -364,6 +388,11 @@ return error; } +static int ret_einval(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + return -EINVAL; +} + struct blkpg_ioctl_arg32 { int op; int flags; @@ -634,6 +663,27 @@ IOCTL32_DEFAULT(VT_LOCKSWITCH), IOCTL32_DEFAULT(VT_UNLOCKSWITCH), +#ifdef CONFIG_NET + /* Socket level stuff */ + IOCTL32_DEFAULT(FIOSETOWN), + IOCTL32_DEFAULT(SIOCSPGRP), + IOCTL32_DEFAULT(FIOGETOWN), + IOCTL32_DEFAULT(SIOCGPGRP), + IOCTL32_DEFAULT(SIOCATMARK), + IOCTL32_DEFAULT(SIOCSIFLINK), + IOCTL32_DEFAULT(SIOCSIFENCAP), + IOCTL32_DEFAULT(SIOCGIFENCAP), + IOCTL32_DEFAULT(SIOCSIFBR), + IOCTL32_DEFAULT(SIOCGIFBR), + IOCTL32_DEFAULT(SIOCSARP), + IOCTL32_DEFAULT(SIOCGARP), + IOCTL32_DEFAULT(SIOCDARP), + IOCTL32_DEFAULT(SIOCSRARP), + IOCTL32_DEFAULT(SIOCGRARP), + IOCTL32_DEFAULT(SIOCDRARP), + IOCTL32_DEFAULT(SIOCADDDLCI), + IOCTL32_DEFAULT(SIOCDELDLCI), + IOCTL32_HANDLER(SIOCGIFNAME, dev_ifname32), IOCTL32_HANDLER(SIOCGIFCONF, dev_ifconf), IOCTL32_HANDLER(SIOCGIFFLAGS, dev_ifsioc), @@ -665,6 +715,14 @@ IOCTL32_HANDLER(SIOCSIFTXQLEN, dev_ifsioc), IOCTL32_HANDLER(SIOCADDRT, routing_ioctl), IOCTL32_HANDLER(SIOCDELRT, routing_ioctl), + /* + * Note SIOCRTMSG is no longer, so this is safe and * the user would + * have seen just an -EINVAL anyways. + */ + IOCTL32_HANDLER(SIOCRTMSG, ret_einval), + IOCTL32_HANDLER(SIOCGSTAMP, do_siocgstamp), + +#endif /* CONFIG_NET */ IOCTL32_HANDLER(EXT2_IOC32_GETFLAGS, do_ext2_ioctl), IOCTL32_HANDLER(EXT2_IOC32_SETFLAGS, do_ext2_ioctl), @@ -712,6 +770,34 @@ IOCTL32_HANDLER(BLKPG, blkpg_ioctl_trans), IOCTL32_DEFAULT(BLKELVGET), IOCTL32_DEFAULT(BLKELVSET), + +#ifdef CONFIG_MD + /* status */ + IOCTL32_DEFAULT(RAID_VERSION), + IOCTL32_DEFAULT(GET_ARRAY_INFO), + IOCTL32_DEFAULT(GET_DISK_INFO), + IOCTL32_DEFAULT(PRINT_RAID_DEBUG), + IOCTL32_DEFAULT(RAID_AUTORUN), + + /* configuration */ + IOCTL32_DEFAULT(CLEAR_ARRAY), + IOCTL32_DEFAULT(ADD_NEW_DISK), + IOCTL32_DEFAULT(HOT_REMOVE_DISK), + IOCTL32_DEFAULT(SET_ARRAY_INFO), + IOCTL32_DEFAULT(SET_DISK_INFO), + IOCTL32_DEFAULT(WRITE_RAID_INFO), + IOCTL32_DEFAULT(UNPROTECT_ARRAY), + IOCTL32_DEFAULT(PROTECT_ARRAY), + IOCTL32_DEFAULT(HOT_ADD_DISK), + IOCTL32_DEFAULT(SET_DISK_FAULTY), + + /* usage */ + IOCTL32_DEFAULT(RUN_ARRAY), + IOCTL32_DEFAULT(START_ARRAY), + IOCTL32_DEFAULT(STOP_ARRAY), + IOCTL32_DEFAULT(STOP_ARRAY_RO), + IOCTL32_DEFAULT(RESTART_ARRAY_RW), +#endif /* CONFIG_MD */ IOCTL32_DEFAULT(MTIOCTOP), /* mtio.h ioctls */ IOCTL32_HANDLER(MTIOCGET32, mt_ioctl_trans), diff -u --recursive --new-file v2.4.6/linux/arch/mips64/kernel/linux32.c linux/arch/mips64/kernel/linux32.c --- v2.4.6/linux/arch/mips64/kernel/linux32.c Mon Mar 19 12:35:10 2001 +++ linux/arch/mips64/kernel/linux32.c Wed Jul 4 11:50:39 2001 @@ -742,7 +742,9 @@ set_fs (KERNEL_DS); ret = sys_getrusage(who, &r); set_fs (old_fs); - if (put_rusage (ru, &r)) return -EFAULT; + if (put_rusage (ru, &r)) + return -EFAULT; + return ret; } @@ -752,7 +754,6 @@ return (!access_ok(VERIFY_READ, i, sizeof(*i)) || (__get_user(o->tv_sec, &i->tv_sec) | __get_user(o->tv_usec, &i->tv_usec))); - return ENOSYS; } static inline long @@ -763,7 +764,6 @@ __get_user(o->it_interval.tv_usec, &i->it_interval.tv_usec) | __get_user(o->it_value.tv_sec, &i->it_value.tv_sec) | __get_user(o->it_value.tv_usec, &i->it_value.tv_usec))); - return ENOSYS; } static inline long @@ -777,12 +777,11 @@ static inline long put_it32(struct itimerval32 *o, struct itimerval *i) { - return (!access_ok(VERIFY_WRITE, i, sizeof(*i)) || + return (!access_ok(VERIFY_WRITE, o, sizeof(*o)) || (__put_user(i->it_interval.tv_sec, &o->it_interval.tv_sec) | __put_user(i->it_interval.tv_usec, &o->it_interval.tv_usec) | __put_user(i->it_value.tv_sec, &o->it_value.tv_sec) | __put_user(i->it_value.tv_usec, &o->it_value.tv_usec))); - return ENOSYS; } extern int do_getitimer(int which, struct itimerval *value); @@ -839,6 +838,7 @@ /* And we'd better return too much than too little anyway */ if (it_old.it_value.tv_usec) oldalarm++; + return oldalarm; } diff -u --recursive --new-file v2.4.6/linux/arch/mips64/kernel/mips64_ksyms.c linux/arch/mips64/kernel/mips64_ksyms.c --- v2.4.6/linux/arch/mips64/kernel/mips64_ksyms.c Fri Mar 2 11:15:47 2001 +++ linux/arch/mips64/kernel/mips64_ksyms.c Wed Jul 4 11:50:39 2001 @@ -5,8 +5,8 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1996, 1997, 1998, 1999, 2000 by Ralf Baechle - * Copyright (C) 1999, 2000 Silicon Graphics, Inc. + * Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001 by Ralf Baechle + * Copyright (C) 1999, 2000, 2001 Silicon Graphics, Inc. */ #include <linux/config.h> #include <linux/module.h> @@ -90,16 +90,11 @@ EXPORT_SYMBOL(invalid_pte_table); /* - * Semaphore stuff - */ -EXPORT_SYMBOL(__down_read); -EXPORT_SYMBOL(__down_write); -EXPORT_SYMBOL(__rwsem_wake); - -/* * Base address of ports for Intel style I/O. */ +#if defined (CONFIG_PCI) || defined (CONFIG_ISA) EXPORT_SYMBOL(mips_io_port_base); +#endif /* * Kernel hacking ... @@ -121,4 +116,4 @@ #endif EXPORT_SYMBOL(get_wchan); -EXPORT_SYMBOL(flush_tlb_page); +EXPORT_SYMBOL(_flush_tlb_page); diff -u --recursive --new-file v2.4.6/linux/arch/mips64/kernel/proc.c linux/arch/mips64/kernel/proc.c --- v2.4.6/linux/arch/mips64/kernel/proc.c Tue Nov 28 21:42:04 2000 +++ linux/arch/mips64/kernel/proc.c Wed Jul 4 11:50:39 2001 @@ -26,67 +26,50 @@ * Currently /proc/cpuinfo is being abused to print data about the * number of date/instruction cacheflushes. */ -int get_cpuinfo(char *buffer, char **start, off_t offset, int count) +int get_cpuinfo(char *buffer) { char fmt [64]; - struct cpuinfo_mips *c = cpu_data; - size_t len = 0; - int n; + size_t len; - for (n = 0; n < smp_num_cpus; n++, c++) { - len += sprintf(buffer + len, "processor\t\t: %d\n", n); - len += sprintf(buffer + len, "vendor_id\t\t: MIPS\n"); - len += sprintf(buffer + len, "model name\t\t: R10000\n"); -/* len += sprintf(buffer + len, "cpu model\t\t: %s V%d.%d\n", + len = sprintf(buffer, "cpu\t\t\t: MIPS\n"); +#if 0 + len += sprintf(buffer + len, "cpu model\t\t: %s V%d.%d\n", cpu_name[mips_cputype <= CPU_LAST ? mips_cputype : CPU_UNKNOWN], (version >> 4) & 0x0f, version & 0x0f); - len += sprintf(buffer + len, "system type\t\t: %s %s\n", + len += sprintf(buffer + len, "system type\t\t: %s %s\n", mach_group_names[mips_machgroup], mach_group_to_name[mips_machgroup][mips_machtype]); -*/ - len += sprintf(buffer + len, "BogoMIPS\t\t: %lu.%02lu\n", - (loops_per_sec + 2500) / 500000, - ((loops_per_sec + 2500) / 5000) % 100); -/* len += sprintf(buffer + len, "Number of cpus\t\t: %d\n", smp_num_cpus);*/ +#endif + len += sprintf(buffer + len, "BogoMIPS\t\t: %lu.%02lu\n", + (loops_per_jiffy + 2500) / (500000/HZ), + ((loops_per_jiffy + 2500) / (5000/HZ)) % 100); + len += sprintf(buffer + len, "Number of cpus\t\t: %d\n", smp_num_cpus); #if defined (__MIPSEB__) - len += sprintf(buffer + len, "byteorder\t\t: big endian\n"); + len += sprintf(buffer + len, "byteorder\t\t: big endian\n"); #endif #if defined (__MIPSEL__) - len += sprintf(buffer + len, "byteorder\t\t: little endian\n"); + len += sprintf(buffer + len, "byteorder\t\t: little endian\n"); #endif - len += sprintf(buffer + len, "unaligned accesses\t: %lu\n", + len += sprintf(buffer + len, "unaligned accesses\t: %lu\n", unaligned_instructions); - len += sprintf(buffer + len, "wait instruction\t: %s\n", + len += sprintf(buffer + len, "wait instruction\t: %s\n", wait_available ? "yes" : "no"); - len += sprintf(buffer + len, "microsecond timers\t: %s\n", + len += sprintf(buffer + len, "microsecond timers\t: %s\n", cyclecounter_available ? "yes" : "no"); - len += sprintf(buffer + len, "extra interrupt vector\t: %s\n", + len += sprintf(buffer + len, "extra interrupt vector\t: %s\n", dedicated_iv_available ? "yes" : "no"); - len += sprintf(buffer + len, "hardware watchpoint\t: %s\n", + len += sprintf(buffer + len, "hardware watchpoint\t: %s\n", watch_available ? "yes" : "no"); - sprintf(fmt, "VCE%%c exceptions\t\t: %s\n", + sprintf(fmt, "VCE%%c exceptions\t\t: %s\n", vce_available ? "%d" : "not available"); - len += sprintf(buffer + len, fmt, 'D', vced_count); - len += sprintf(buffer + len, fmt, 'I', vcei_count); - len += sprintf(buffer + len, "\n"); - - if (len < offset) - offset -= len, len = 0; - else if (len >= offset + count) - goto leave_loop; - } - -leave_loop: - *start = buffer + offset; - len -= offset; - if (len < 0) - len = 0; - return len > count ? count : len; + len += sprintf(buffer + len, fmt, 'D', vced_count); + len += sprintf(buffer + len, fmt, 'I', vcei_count); + return len; } void init_irq_proc(void) diff -u --recursive --new-file v2.4.6/linux/arch/mips64/kernel/ptrace.c linux/arch/mips64/kernel/ptrace.c --- v2.4.6/linux/arch/mips64/kernel/ptrace.c Tue Nov 28 21:42:04 2000 +++ linux/arch/mips64/kernel/ptrace.c Fri Jul 20 12:39:55 2001 @@ -62,32 +62,7 @@ goto out_tsk; if (request == PTRACE_ATTACH) { - if (child == current) - goto out_tsk; - if ((!child->dumpable || - (current->uid != child->euid) || - (current->uid != child->suid) || - (current->uid != child->uid) || - (current->gid != child->egid) || - (current->gid != child->sgid) || - (!cap_issubset(child->cap_permitted, current->cap_permitted)) || - (current->gid != child->gid)) && !capable(CAP_SYS_PTRACE)) - goto out_tsk; - /* the same process cannot be attached many times */ - if (child->ptrace & PT_PTRACED) - goto out_tsk; - child->ptrace |= PT_PTRACED; - - write_lock_irq(&tasklist_lock); - if (child->p_pptr != current) { - REMOVE_LINKS(child); - child->p_pptr = current; - SET_LINKS(child); - } - write_unlock_irq(&tasklist_lock); - - send_sig(SIGSTOP, child, 1); - ret = 0; + ret = ptrace_attach(child); goto out_tsk; } ret = -ESRCH; @@ -336,32 +311,7 @@ goto out; if (request == PTRACE_ATTACH) { - if (child == current) - goto out_tsk; - if ((!child->dumpable || - (current->uid != child->euid) || - (current->uid != child->suid) || - (current->uid != child->uid) || - (current->gid != child->egid) || - (current->gid != child->sgid) || - (!cap_issubset(child->cap_permitted, current->cap_permitted)) || - (current->gid != child->gid)) && !capable(CAP_SYS_PTRACE)) - goto out_tsk; - /* the same process cannot be attached many times */ - if (child->ptrace & PT_PTRACED) - goto out_tsk; - child->ptrace |= PT_PTRACED; - - write_lock_irq(&tasklist_lock); - if (child->p_pptr != current) { - REMOVE_LINKS(child); - child->p_pptr = current; - SET_LINKS(child); - } - write_unlock_irq(&tasklist_lock); - - send_sig(SIGSTOP, child, 1); - ret = 0; + ret = ptrace_attach(child); goto out_tsk; } ret = -ESRCH; diff -u --recursive --new-file v2.4.6/linux/arch/mips64/kernel/r4k_fpu.S linux/arch/mips64/kernel/r4k_fpu.S --- v2.4.6/linux/arch/mips64/kernel/r4k_fpu.S Sat May 13 08:30:17 2000 +++ linux/arch/mips64/kernel/r4k_fpu.S Wed Jul 4 11:50:39 2001 @@ -1,17 +1,16 @@ -/* $Id: r4k_fpu.S,v 1.1 1999/09/27 16:01:38 ralf Exp $ - * +/* * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. * * Save/restore floating point context for signal handlers. * - * Copyright (C) 1996, 1998, 1999 by Ralf Baechle + * Copyright (C) 1996, 1998, 1999, 2001 by Ralf Baechle * * Multi-arch abstraction and asm macros for easier reading: * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) * - * Copyright (C) 1999 Silicon Graphics, Inc. + * Copyright (C) 1999, 2001 Silicon Graphics, Inc. */ #include <asm/asm.h> #include <asm/errno.h> @@ -33,11 +32,11 @@ .set noreorder /* Save floating point context */ LEAF(save_fp_context) - mfc0 t1,CP0_STATUS - sll t2,t1,5 + mfc0 t1, CP0_STATUS + sll t2, t1,5 - bgez t2,1f - cfc1 t1,fcr31 + bgez t2, 1f + cfc1 t1, fcr31 /* Store the 16 odd double precision registers */ EX sdc1 $f1, SC_FPREGS+8(a0) EX sdc1 $f3, SC_FPREGS+24(a0) @@ -75,8 +74,8 @@ EX sdc1 $f28, SC_FPREGS+224(a0) EX sdc1 $f30, SC_FPREGS+240(a0) EX sw t1, SC_FPC_CSR(a0) - cfc1 t0,$0 # implementation/version - EX sw t0,SC_FPC_EIR(a0) + cfc1 t0, $0 # implementation/version + EX sw t0, SC_FPC_EIR(a0) jr ra li v0, 0 # success @@ -93,8 +92,8 @@ */ LEAF(restore_fp_context) mfc0 t1, CP0_STATUS - sll t0,t1,5 - bgez t0,1f + sll t0, t1,5 + bgez t0, 1f EX lw t0, SC_FPC_CSR(a0) /* Restore the 16 odd double precision registers only @@ -137,13 +136,13 @@ EX ldc1 $f26, SC_FPREGS+208(a0) EX ldc1 $f28, SC_FPREGS+224(a0) EX ldc1 $f30, SC_FPREGS+240(a0) - ctc1 t0,fcr31 + ctc1 t0, fcr31 jr ra li v0, 0 # success END(restore_fp_context) .type fault@function .ent fault -fault: li v0, -EFAULT - jr ra +fault: jr ra + li v0, -EFAULT # failure .end fault diff -u --recursive --new-file v2.4.6/linux/arch/mips64/kernel/r4k_tlb.S linux/arch/mips64/kernel/r4k_tlb.S --- v2.4.6/linux/arch/mips64/kernel/r4k_tlb.S Wed Jul 12 15:14:41 2000 +++ linux/arch/mips64/kernel/r4k_tlb.S Wed Jul 4 11:50:39 2001 @@ -24,7 +24,7 @@ .macro LOAD_PTE2, ptr, tmp #ifdef CONFIG_SMP - mfc0 \tmp, CP0_CONTEXT + dmfc0 \tmp, CP0_CONTEXT dla \ptr, pgd_current dsrl \tmp, 23 daddu \ptr, \tmp @@ -96,9 +96,6 @@ */ dmfc0 k0, CP0_BADVADDR dli k1, VMALLOC_START - sltu k1, k0, k1 - bne k1, zero, not_vmalloc - dli k1, VMALLOC_START /* * Now find offset into kptbl. @@ -114,20 +111,16 @@ */ dla k0, ekptbl sltu k0, k1, k0 - beq k0, zero, not_vmalloc + beqz k0, not_vmalloc /* * Load cp0 registers. */ ld k0, 0(k1) # get even pte ld k1, 8(k1) # get odd pte -1: + +not_vmalloc: PTE_RELOAD k0 k1 nop tlbwr eret -not_vmalloc: - daddu k0, zero, zero - daddu k1, zero, zero - j 1b - nop diff -u --recursive --new-file v2.4.6/linux/arch/mips64/kernel/scall_64.S linux/arch/mips64/kernel/scall_64.S --- v2.4.6/linux/arch/mips64/kernel/scall_64.S Tue Nov 28 21:42:04 2000 +++ linux/arch/mips64/kernel/scall_64.S Wed Jul 4 11:50:39 2001 @@ -63,8 +63,14 @@ 1: sd v0, PT_R2(sp) # result FEXPORT(ret_from_sys_call_64) - lw t0, irq_stat # softirq_active - lw t1, irq_stat+4 # softirq_mask. unused delay slot + la t1, irq_stat # softirq_active +#ifdef CONFIG_SMP + lwu t0, TASK_PROCESSOR($28) + dsll t0, t0, 5 + daddu t1, t0 +#endif + lw t0, 0(t1) # softirq_active + lw t1, 4(t1) # softirq_mask. unused delay slot and t0, t1 bnez t0, handle_softirq_64 @@ -131,217 +137,217 @@ END(handle_sys64) sys_call_table: - PTR sys_syscall /* 4000 */ + PTR sys_syscall /* 5000 */ PTR sys_exit PTR sys_fork PTR sys_read PTR sys_write - PTR sys_open /* 4005 */ + PTR sys_open /* 5005 */ PTR sys_close PTR sys_waitpid PTR sys_creat PTR sys_link - PTR sys_unlink /* 4010 */ + PTR sys_unlink /* 5010 */ PTR sys_execve PTR sys_chdir PTR sys_time PTR sys_mknod - PTR sys_chmod /* 4015 */ + PTR sys_chmod /* 5015 */ PTR sys_lchown PTR sys_ni_syscall PTR sys_stat PTR sys_lseek - PTR sys_getpid /* 4020 */ + PTR sys_getpid /* 5020 */ PTR sys_mount PTR sys_oldumount PTR sys_setuid PTR sys_getuid - PTR sys_stime /* 4025 */ + PTR sys_stime /* 5025 */ PTR sys_ni_syscall /* ptrace */ PTR sys_alarm PTR sys_fstat PTR sys_pause - PTR sys_utime /* 4030 */ + PTR sys_utime /* 5030 */ PTR sys_ni_syscall PTR sys_ni_syscall PTR sys_access PTR sys_nice - PTR sys_ni_syscall /* 4035 */ + PTR sys_ni_syscall /* 5035 */ PTR sys_sync PTR sys_kill PTR sys_rename PTR sys_mkdir - PTR sys_rmdir /* 4040 */ + PTR sys_rmdir /* 5040 */ PTR sys_dup PTR sys_pipe PTR sys_times PTR sys_ni_syscall - PTR sys_brk /* 4045 */ + PTR sys_brk /* 5045 */ PTR sys_setgid PTR sys_getgid PTR sys_ni_syscall /* was signal 2 */ PTR sys_geteuid - PTR sys_getegid /* 4050 */ + PTR sys_getegid /* 5050 */ PTR sys_acct PTR sys_umount PTR sys_ni_syscall PTR sys_ioctl - PTR sys_fcntl /* 4055 */ + PTR sys_fcntl /* 5055 */ PTR sys_ni_syscall PTR sys_setpgid PTR sys_ni_syscall PTR sys_ni_syscall - PTR sys_umask /* 4060 */ + PTR sys_umask /* 5060 */ PTR sys_chroot PTR sys_ustat PTR sys_dup2 PTR sys_getppid - PTR sys_getpgrp /* 4065 */ + PTR sys_getpgrp /* 5065 */ PTR sys_setsid PTR sys_sigaction PTR sys_sgetmask PTR sys_ssetmask - PTR sys_setreuid /* 4070 */ + PTR sys_setreuid /* 5070 */ PTR sys_setregid PTR sys_sigsuspend PTR sys_sigpending PTR sys_sethostname - PTR sys_setrlimit /* 4075 */ + PTR sys_setrlimit /* 5075 */ PTR sys_getrlimit PTR sys_getrusage PTR sys_gettimeofday PTR sys_settimeofday - PTR sys_getgroups /* 4080 */ + PTR sys_getgroups /* 5080 */ PTR sys_setgroups PTR sys_ni_syscall /* old_select */ PTR sys_symlink PTR sys_lstat - PTR sys_readlink /* 4085 */ + PTR sys_readlink /* 5085 */ PTR sys_uselib PTR sys_swapon PTR sys_reboot PTR sys_ni_syscall /* old_readdir */ - PTR sys_mmap /* 4090 */ + PTR sys_mmap /* 5090 */ PTR sys_munmap PTR sys_truncate PTR sys_ftruncate PTR sys_fchmod - PTR sys_fchown /* 4095 */ + PTR sys_fchown /* 5095 */ PTR sys_getpriority PTR sys_setpriority PTR sys_ni_syscall PTR sys_statfs - PTR sys_fstatfs /* 4100 */ + PTR sys_fstatfs /* 5100 */ PTR sys_ni_syscall /* sys_ioperm */ PTR sys_socketcall PTR sys_syslog PTR sys_setitimer - PTR sys_getitimer /* 4105 */ + PTR sys_getitimer /* 5105 */ PTR sys_newstat PTR sys_newlstat PTR sys_newfstat PTR sys_ni_syscall - PTR sys_ni_syscall /* sys_ioperm *//* 4110 */ + PTR sys_ni_syscall /* sys_ioperm *//* 5110 */ PTR sys_vhangup PTR sys_ni_syscall /* was sys_idle */ PTR sys_ni_syscall /* sys_vm86 */ PTR sys_wait4 - PTR sys_swapoff /* 4115 */ + PTR sys_swapoff /* 5115 */ PTR sys_sysinfo PTR sys_ipc PTR sys_fsync PTR sys_sigreturn - PTR sys_clone /* 4120 */ + PTR sys_clone /* 5120 */ PTR sys_setdomainname PTR sys_newuname PTR sys_ni_syscall /* sys_modify_ldt */ PTR sys_adjtimex - PTR sys_mprotect /* 4125 */ + PTR sys_mprotect /* 5125 */ PTR sys_sigprocmask PTR sys_create_module PTR sys_init_module PTR sys_delete_module - PTR sys_get_kernel_syms /* 4130 */ + PTR sys_get_kernel_syms /* 5130 */ PTR sys_quotactl PTR sys_getpgid PTR sys_fchdir PTR sys_bdflush - PTR sys_sysfs /* 4135 */ + PTR sys_sysfs /* 5135 */ PTR sys_personality PTR sys_ni_syscall /* for afs_syscall */ PTR sys_setfsuid PTR sys_setfsgid - PTR sys_llseek /* 4140 */ + PTR sys_llseek /* 5140 */ PTR sys_getdents PTR sys_select PTR sys_flock PTR sys_msync - PTR sys_readv /* 4145 */ + PTR sys_readv /* 5145 */ PTR sys_writev PTR sys_cacheflush PTR sys_cachectl PTR sys_sysmips - PTR sys_ni_syscall /* 4150 */ + PTR sys_ni_syscall /* 5150 */ PTR sys_getsid PTR sys_fdatasync PTR sys_sysctl PTR sys_mlock - PTR sys_munlock /* 4155 */ + PTR sys_munlock /* 5155 */ PTR sys_mlockall PTR sys_munlockall PTR sys_sched_setparam PTR sys_sched_getparam - PTR sys_sched_setscheduler /* 4160 */ + PTR sys_sched_setscheduler /* 5160 */ PTR sys_sched_getscheduler PTR sys_sched_yield PTR sys_sched_get_priority_max PTR sys_sched_get_priority_min - PTR sys_sched_rr_get_interval /* 4165 */ + PTR sys_sched_rr_get_interval /* 5165 */ PTR sys_nanosleep PTR sys_mremap PTR sys_accept PTR sys_bind - PTR sys_connect /* 4170 */ + PTR sys_connect /* 5170 */ PTR sys_getpeername PTR sys_getsockname PTR sys_getsockopt PTR sys_listen - PTR sys_recv /* 4175 */ + PTR sys_recv /* 5175 */ PTR sys_recvfrom PTR sys_recvmsg PTR sys_send PTR sys_sendmsg - PTR sys_sendto /* 4180 */ + PTR sys_sendto /* 5180 */ PTR sys_setsockopt PTR sys_shutdown PTR sys_socket PTR sys_socketpair - PTR sys_setresuid /* 4185 */ + PTR sys_setresuid /* 5185 */ PTR sys_getresuid PTR sys_query_module PTR sys_poll PTR sys_nfsservctl - PTR sys_setresgid /* 4190 */ + PTR sys_setresgid /* 5190 */ PTR sys_getresgid PTR sys_prctl PTR sys_rt_sigreturn PTR sys_rt_sigaction - PTR sys_rt_sigprocmask /* 4195 */ + PTR sys_rt_sigprocmask /* 5195 */ PTR sys_rt_sigpending PTR sys_rt_sigtimedwait PTR sys_rt_sigqueueinfo PTR sys_rt_sigsuspend - PTR sys_pread /* 4200 */ + PTR sys_pread /* 5200 */ PTR sys_pwrite PTR sys_chown PTR sys_getcwd PTR sys_capget - PTR sys_capset /* 4205 */ + PTR sys_capset /* 5205 */ PTR sys_sigaltstack PTR sys_sendfile PTR sys_ni_syscall PTR sys_ni_syscall - PTR sys_pivot_root /* 4210 */ + PTR sys_pivot_root /* 5210 */ PTR sys_mincore PTR sys_madvise PTR sys_getdents64 diff -u --recursive --new-file v2.4.6/linux/arch/mips64/kernel/scall_o32.S linux/arch/mips64/kernel/scall_o32.S --- v2.4.6/linux/arch/mips64/kernel/scall_o32.S Tue Nov 28 21:42:04 2000 +++ linux/arch/mips64/kernel/scall_o32.S Wed Jul 4 11:50:39 2001 @@ -76,8 +76,14 @@ 1: sd v0, PT_R2(sp) # result FEXPORT(o32_ret_from_sys_call) - lw t0, irq_stat # softirq_active - lw t1, irq_stat+4 # softirq_mask. unused delay slot + la t1, irq_stat # softirq_active +#ifdef CONFIG_SMP + lwu t0, TASK_PROCESSOR($28) + dsll t0, t0, 5 + daddu t1, t0 +#endif + lw t0, 0(t1) # softirq_active + lw t1, 4(t1) # softirq_mask. unused delay slot and t0, t1 bnez t0, o32_handle_softirq diff -u --recursive --new-file v2.4.6/linux/arch/mips64/kernel/setup.c linux/arch/mips64/kernel/setup.c --- v2.4.6/linux/arch/mips64/kernel/setup.c Fri Feb 9 11:29:44 2001 +++ linux/arch/mips64/kernel/setup.c Wed Jul 4 11:50:39 2001 @@ -31,7 +31,6 @@ #include <asm/bootinfo.h> #include <asm/cachectl.h> #include <asm/cpu.h> -#include <asm/io.h> #include <asm/stackframe.h> #include <asm/system.h> #include <asm/pgalloc.h> @@ -56,8 +55,6 @@ */ char cyclecounter_available; -unsigned long loops_per_sec; - /* * Set if box has EISA slots. */ @@ -89,8 +86,9 @@ unsigned long mips_machtype = MACH_UNKNOWN; unsigned long mips_machgroup = MACH_GROUP_UNKNOWN; +struct boot_mem_map boot_mem_map; + unsigned char aux_device_present; -extern int _end; extern void load_mmu(void); @@ -98,15 +96,6 @@ char saved_command_line[CL_SIZE]; extern char arcs_cmdline[CL_SIZE]; -/* - * mips_io_port_base is the begin of the address space to which x86 style - * I/O ports are mapped. - */ -#ifdef CONFIG_SGI_IP27 -/* XXX Origin garbage has no business in this file */ -unsigned long mips_io_port_base = IO_BASE; -#endif - extern void ip22_setup(void); extern void ip27_setup(void); @@ -137,6 +126,7 @@ mips_cputype = CPU_R8000; break; case PRID_IMP_R10000: + case PRID_IMP_R12000: mips_cputype = CPU_R10000; break; default: @@ -146,14 +136,6 @@ void __init setup_arch(char **cmdline_p) { -#ifdef CONFIG_BLK_DEV_INITRD - unsigned long tmp; - unsigned long *initrd_header; -#endif - int i; - pmd_t *pmd = kpmdtbl; - pte_t *pte = kptbl; - cpu_probe(); load_mmu(); @@ -164,37 +146,15 @@ ip27_setup(); #endif - strncpy (command_line, arcs_cmdline, CL_SIZE); +#ifdef CONFIG_ARC_MEMORY + bootmem_init (); +#endif + + strncpy(command_line, arcs_cmdline, CL_SIZE); memcpy(saved_command_line, command_line, CL_SIZE); saved_command_line[CL_SIZE-1] = '\0'; *cmdline_p = command_line; -#ifdef CONFIG_BLK_DEV_INITRD -#error "Initrd is broken, please fit it." - tmp = (((unsigned long)&_end + PAGE_SIZE-1) & PAGE_MASK) - 8; - if (tmp < (unsigned long)&_end) - tmp += PAGE_SIZE; - initrd_header = (unsigned long *)tmp; - if (initrd_header[0] == 0x494E5244) { - initrd_start = (unsigned long)&initrd_header[2]; - initrd_end = initrd_start + initrd_header[1]; - initrd_below_start_ok = 1; - if (initrd_end > memory_end) { - printk("initrd extends beyond end of memory " - "(0x%08lx > 0x%08lx)\ndisabling initrd\n", - initrd_end,memory_end); - initrd_start = 0; - } else - *memory_start_p = initrd_end; - } -#endif - paging_init(); - - memset((void *)kptbl, 0, PAGE_SIZE << KPTBL_PAGE_ORDER); - memset((void *)kpmdtbl, 0, PAGE_SIZE); - pgd_set(swapper_pg_dir, kpmdtbl); - for (i = 0; i < (1 << KPTBL_PAGE_ORDER); pmd++,i++,pte+=PTRS_PER_PTE) - pmd_val(*pmd) = (unsigned long)pte; } diff -u --recursive --new-file v2.4.6/linux/arch/mips64/kernel/smp.c linux/arch/mips64/kernel/smp.c --- v2.4.6/linux/arch/mips64/kernel/smp.c Sun Feb 4 21:48:46 2001 +++ linux/arch/mips64/kernel/smp.c Wed Jul 4 11:50:39 2001 @@ -12,6 +12,7 @@ #include <asm/hardirq.h> #include <asm/softirq.h> #include <asm/mmu_context.h> +#include <asm/irq.h> #ifdef CONFIG_SGI_IP27 @@ -24,8 +25,6 @@ #define DORESCHED 0xab #define DOCALL 0xbc -#define IRQ_TO_SWLEVEL(i) i + 7 /* Delete this from here */ - static void sendintr(int destid, unsigned char status) { int irq; @@ -44,7 +43,7 @@ * with the CPU we want to send the interrupt to. */ REMOTE_HUB_SEND_INTR(COMPACT_TO_NASID_NODEID(cputocnode(destid)), - IRQ_TO_SWLEVEL(irq)); + FAST_IRQ_TO_LEVEL(irq)); #else << Bomb! Must redefine this for more than 2 CPUS. >> #endif diff -u --recursive --new-file v2.4.6/linux/arch/mips64/kernel/traps.c linux/arch/mips64/kernel/traps.c --- v2.4.6/linux/arch/mips64/kernel/traps.c Sun Dec 3 17:48:19 2000 +++ linux/arch/mips64/kernel/traps.c Wed Jul 4 11:50:39 2001 @@ -264,7 +264,7 @@ epc = (unsigned int *) (unsigned long) regs->cp0_epc; if (regs->cp0_cause & CAUSEF_BD) - epc += 4; + epc++; if (verify_area(VERIFY_READ, epc, 4)) { force_sig(SIGSEGV, current); diff -u --recursive --new-file v2.4.6/linux/arch/mips64/kernel/unaligned.c linux/arch/mips64/kernel/unaligned.c --- v2.4.6/linux/arch/mips64/kernel/unaligned.c Tue Nov 28 21:42:04 2000 +++ linux/arch/mips64/kernel/unaligned.c Wed Jul 4 11:50:39 2001 @@ -82,6 +82,7 @@ #include <asm/byteorder.h> #include <asm/inst.h> #include <asm/uaccess.h> +#include <asm/system.h> #define STR(x) __STR(x) #define __STR(x) #x @@ -364,12 +365,15 @@ return; } + die_if_kernel ("Unhandled kernel unaligned access", regs); send_sig(SIGSEGV, current, 1); return; sigbus: + die_if_kernel ("Unhandled kernel unaligned access", regs); send_sig(SIGBUS, current, 1); return; sigill: + die_if_kernel ("Unhandled kernel unaligned access or invalid instruction", regs); send_sig(SIGILL, current, 1); return; } @@ -400,5 +404,6 @@ return; sigbus: + die_if_kernel ("Kernel unaligned instruction access", regs); force_sig(SIGBUS, current); } diff -u --recursive --new-file v2.4.6/linux/arch/mips64/lib/memcpy.S linux/arch/mips64/lib/memcpy.S --- v2.4.6/linux/arch/mips64/lib/memcpy.S Tue Dec 5 23:15:12 2000 +++ linux/arch/mips64/lib/memcpy.S Wed Jul 4 11:50:39 2001 @@ -238,8 +238,10 @@ andi ta2, a2, 0x40 move_128bytes: +#if (_MIPS_ISA == _MIPS_ISA_MIPS4) pref 0, 2*128(a0) pref 1, 2*128(a1) +#endif MOVE_BIGGERCHUNK(a1, a0, 0x00, ta0, ta1, ta3, t0) MOVE_BIGGERCHUNK(a1, a0, 0x40, ta0, ta1, ta3, t0) dsubu t8, t8, 0x01 diff -u --recursive --new-file v2.4.6/linux/arch/mips64/lib/memset.S linux/arch/mips64/lib/memset.S --- v2.4.6/linux/arch/mips64/lib/memset.S Tue Dec 5 23:15:12 2000 +++ linux/arch/mips64/lib/memset.S Wed Jul 4 11:50:39 2001 @@ -52,6 +52,7 @@ 1: FEXPORT(__bzero) + .type __bzero, @function sltiu t0, a2, 8 /* very small region? */ bnez t0, small_memset andi t0, a0, 7 /* aligned? */ diff -u --recursive --new-file v2.4.6/linux/arch/mips64/lib/rtc-no.c linux/arch/mips64/lib/rtc-no.c --- v2.4.6/linux/arch/mips64/lib/rtc-no.c Sun Feb 4 21:48:46 2001 +++ linux/arch/mips64/lib/rtc-no.c Wed Jul 4 11:50:39 2001 @@ -9,7 +9,6 @@ * Copyright (C) 1998, 2001 by Ralf Baechle */ #include <linux/kernel.h> -#include <linux/spinlock.h> #include <linux/mc146818rtc.h> static unsigned char no_rtc_read_data(unsigned long addr) diff -u --recursive --new-file v2.4.6/linux/arch/mips64/lib/rtc-std.c linux/arch/mips64/lib/rtc-std.c --- v2.4.6/linux/arch/mips64/lib/rtc-std.c Sun Feb 4 21:48:46 2001 +++ linux/arch/mips64/lib/rtc-std.c Wed Jul 4 11:50:39 2001 @@ -7,7 +7,6 @@ * * Copyright (C) 1998 by Ralf Baechle */ -#include <linux/spinlock.h> #include <linux/mc146818rtc.h> #include <asm/io.h> diff -u --recursive --new-file v2.4.6/linux/arch/mips64/lib/watch.S linux/arch/mips64/lib/watch.S --- v2.4.6/linux/arch/mips64/lib/watch.S Sat May 13 08:30:17 2000 +++ linux/arch/mips64/lib/watch.S Wed Jul 4 11:50:39 2001 @@ -1,5 +1,4 @@ -/* $Id: watch.S,v 1.1 1999/08/21 21:43:01 ralf Exp $ - * +/* * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. @@ -7,7 +6,7 @@ * Kernel debug stuff to use the Watch registers. * Useful to find stack overflows, dangling pointers etc. * - * Copyright (C) 1995, 1996, 1999 by Ralf Baechle + * Copyright (C) 1995, 1996, 1999, 2001 by Ralf Baechle */ #include <asm/asm.h> #include <asm/mipsregs.h> @@ -15,23 +14,21 @@ .set noreorder /* - * Parameter: a0 - logic address to watch - * Currently only KSEG0 addresses are allowed! + * Parameter: a0 - physical address to watch * a1 - set bit #1 to trap on load references * bit #0 to trap on store references * Results : none */ LEAF(__watch_set) - li t0,0x80000000 - subu a0,t0 - ori a0,7 - xori a0,7 - or a0,a1 - mtc0 a0,CP0_WATCHLO - sw a0,watch_savelo + ori a0, 7 + xori a0, 7 + or a0, a1 + mtc0 a0, CP0_WATCHLO + sd a0, watch_savelo + dsrl32 a0, a0, 0 jr ra - mtc0 zero,CP0_WATCHHI + mtc0 zero, CP0_WATCHHI END(__watch_set) /* @@ -40,7 +37,7 @@ */ LEAF(__watch_clear) jr ra - mtc0 zero,CP0_WATCHLO + mtc0 zero, CP0_WATCHLO END(__watch_clear) /* @@ -48,14 +45,13 @@ * Results : none */ LEAF(__watch_reenable) - lw t0,watch_savelo + ld t0, watch_savelo jr ra - mtc0 t0,CP0_WATCHLO + mtc0 t0, CP0_WATCHLO END(__watch_reenable) /* * Saved value of the c0_watchlo register for watch_reenable() */ - .data -watch_savelo: .word 0 - .text + .local watch_savelo + .comm watch_savelo, 8, 8 diff -u --recursive --new-file v2.4.6/linux/arch/mips64/mm/andes.c linux/arch/mips64/mm/andes.c --- v2.4.6/linux/arch/mips64/mm/andes.c Tue Nov 28 21:42:04 2000 +++ linux/arch/mips64/mm/andes.c Wed Jul 4 11:50:39 2001 @@ -284,8 +284,8 @@ if((pid != (CPU_CONTEXT(smp_processor_id(), vma->vm_mm) & 0xff)) || (CPU_CONTEXT(smp_processor_id(), vma->vm_mm) == 0)) { - printk("update_mmu_cache: Wheee, bogus tlbpid mmpid=%d - tlbpid=%d\n", (int) (CPU_CONTEXT(smp_processor_id(), + printk("update_mmu_cache: Wheee, bogus tlbpid mmpid=%d " + "tlbpid=%d\n", (int) (CPU_CONTEXT(smp_processor_id(), vma->vm_mm) & 0xff), pid); } diff -u --recursive --new-file v2.4.6/linux/arch/mips64/mm/extable.c linux/arch/mips64/mm/extable.c --- v2.4.6/linux/arch/mips64/mm/extable.c Sat May 13 08:30:17 2000 +++ linux/arch/mips64/mm/extable.c Wed Jul 4 11:50:39 2001 @@ -9,6 +9,7 @@ */ #include <linux/config.h> #include <linux/module.h> +#include <linux/spinlock.h> #include <asm/uaccess.h> extern const struct exception_table_entry __start___ex_table[]; @@ -35,26 +36,32 @@ return 0; } +extern spinlock_t modlist_lock; + unsigned long search_exception_table(unsigned long addr) { - unsigned long ret; - + unsigned long ret = 0; + unsigned long flags; + #ifndef CONFIG_MODULES /* There is only the kernel to search. */ ret = search_one_table(__start___ex_table, __stop___ex_table-1, addr); - if (ret) return ret; + return ret; #else /* The kernel is the last "module" -- no need to treat it special. */ struct module *mp; + + spin_lock_irqsave(&modlist_lock, flags); for (mp = module_list; mp != NULL; mp = mp->next) { if (mp->ex_table_start == NULL) continue; ret = search_one_table(mp->ex_table_start, mp->ex_table_end - 1, addr); - if (ret) return ret; + if (ret) + break; } + spin_unlock_irqrestore(&modlist_lock, flags); + return ret; #endif - - return 0; } diff -u --recursive --new-file v2.4.6/linux/arch/mips64/mm/fault.c linux/arch/mips64/mm/fault.c --- v2.4.6/linux/arch/mips64/mm/fault.c Mon Mar 19 12:35:10 2001 +++ linux/arch/mips64/mm/fault.c Wed Jul 4 11:50:39 2001 @@ -6,6 +6,7 @@ * Copyright (C) 1995 - 2000 by Ralf Baechle * Copyright (C) 1999, 2000 by Silicon Graphics, Inc. */ +#include <linux/config.h> #include <linux/signal.h> #include <linux/sched.h> #include <linux/interrupt.h> @@ -31,6 +32,7 @@ #define development_version (LINUX_VERSION_CODE & 0x100) extern void die(char *, struct pt_regs *, unsigned long write); +extern int console_loglevel; /* * Macro for exception fixup code to access integer registers. @@ -57,17 +59,34 @@ printk("Got exception 0x%lx at 0x%lx\n", retaddr, regs.cp0_epc); } -extern spinlock_t console_lock, timerlist_lock; +extern spinlock_t timerlist_lock; /* * Unlock any spinlocks which will prevent us from getting the - * message out (timerlist_lock is acquired through the + * message out (timerlist_lock is aquired through the * console unblank code) */ -void bust_spinlocks(void) +void bust_spinlocks(int yes) { - spin_lock_init(&console_lock); spin_lock_init(&timerlist_lock); + if (yes) { + oops_in_progress = 1; +#ifdef CONFIG_SMP + global_irq_lock = 0; /* Many serial drivers do __global_cli() */ +#endif + } else { + int loglevel_save = console_loglevel; + unblank_screen(); + oops_in_progress = 0; + /* + * OK, the message is on the console. Now we call printk() + * without oops_in_progress set so that printk will give klogd + * a poke. Hold onto your hats... + */ + console_loglevel = 15; /* NMI oopser may have shut the console up */ + printk(" "); + console_loglevel = loglevel_save; + } } /* @@ -84,6 +103,18 @@ unsigned long fixup; siginfo_t info; + /* + * We fault-in kernel-space virtual memory on-demand. The + * 'reference' page table is init_mm.pgd. + * + * NOTE! We MUST NOT take any locks for this case. We may + * be in an interrupt or a critical region, and should + * only copy the information from the master page table, + * nothing more. + */ + if (address >= TASK_SIZE) + goto vmalloc_fault; + info.si_code = SEGV_MAPERR; /* * If we're in an interrupt or have no user @@ -148,13 +179,7 @@ bad_area: up_read(&mm->mmap_sem); - /* - * Quickly check for vmalloc range faults. - */ - if ((!vma) && (address >= VMALLOC_START) && (address < VMALLOC_END)) { - printk("Fix vmalloc invalidate fault\n"); - while(1); - } +bad_area_nosemaphore: if (user_mode(regs)) { tsk->thread.cp0_badvaddr = address; tsk->thread.error_code = write; @@ -195,7 +220,7 @@ * terminate things with extreme prejudice. */ - bust_spinlocks(); + bust_spinlocks(1); printk(KERN_ALERT "Cpu %d Unable to handle kernel paging request at " "address %08lx, epc == %08x, ra == %08x\n", @@ -203,6 +228,7 @@ (unsigned int) regs->regs[31]); die("Oops", regs, write); do_exit(SIGKILL); + bust_spinlocks(0); /* * We ran out of memory, or some other thing happened to us that made @@ -232,4 +258,9 @@ /* Kernel mode? Handle exceptions or die */ if (!user_mode(regs)) goto no_context; + + return; + +vmalloc_fault: + panic("Pagefault for kernel virtual memory"); } diff -u --recursive --new-file v2.4.6/linux/arch/mips64/mm/init.c linux/arch/mips64/mm/init.c --- v2.4.6/linux/arch/mips64/mm/init.c Mon Oct 16 12:58:51 2000 +++ linux/arch/mips64/mm/init.c Wed Jul 4 11:50:39 2001 @@ -1,5 +1,4 @@ -/* $Id: init.c,v 1.13 2000/02/23 00:41:00 ralf Exp $ - * +/* * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. @@ -37,27 +36,11 @@ #include <asm/sgialib.h> #endif #include <asm/mmu_context.h> +#include <asm/tlb.h> -unsigned long totalram_pages; - -void __bad_pte_kernel(pmd_t *pmd) -{ - printk("Bad pmd in pte_alloc_kernel: %08lx\n", pmd_val(*pmd)); - pmd_set(pmd, BAD_PAGETABLE); -} - -void __bad_pte(pmd_t *pmd) -{ - printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd)); - pmd_set(pmd, BAD_PAGETABLE); -} +mmu_gather_t mmu_gathers[NR_CPUS]; -/* Fixme, we need something like BAD_PMDTABLE ... */ -void __bad_pmd(pgd_t *pgd) -{ - printk("Bad pgd in pmd_alloc: %08lx\n", pgd_val(*pgd)); - pgd_set(pgd, empty_bad_pmd_table); -} +unsigned long totalram_pages; void pgd_init(unsigned long page) { @@ -113,72 +96,6 @@ } } -pmd_t *get_pmd_slow(pgd_t *pgd, unsigned long offset) -{ - pmd_t *pmd; - - pmd = (pmd_t *) __get_free_pages(GFP_KERNEL, 1); - if (pgd_none(*pgd)) { - if (pmd) { - pmd_init((unsigned long)pmd, (unsigned long)invalid_pte_table); - pgd_set(pgd, pmd); - return pmd + offset; - } - pgd_set(pgd, BAD_PMDTABLE); - return NULL; - } - free_page((unsigned long)pmd); - if (pgd_bad(*pgd)) { - __bad_pmd(pgd); - return NULL; - } - return (pmd_t *) pgd_page(*pgd) + offset; -} - -pte_t *get_pte_kernel_slow(pmd_t *pmd, unsigned long offset) -{ - pte_t *page; - - page = (pte_t *) __get_free_pages(GFP_USER, 1); - if (pmd_none(*pmd)) { - if (page) { - clear_page(page); - pmd_set(pmd, page); - return page + offset; - } - pmd_set(pmd, BAD_PAGETABLE); - return NULL; - } - free_page((unsigned long)page); - if (pmd_bad(*pmd)) { - __bad_pte_kernel(pmd); - return NULL; - } - return (pte_t *) pmd_page(*pmd) + offset; -} - -pte_t *get_pte_slow(pmd_t *pmd, unsigned long offset) -{ - pte_t *page; - - page = (pte_t *) __get_free_pages(GFP_KERNEL, 0); - if (pmd_none(*pmd)) { - if (page) { - clear_page(page); - pmd_val(*pmd) = (unsigned long)page; - return page + offset; - } - pmd_set(pmd, BAD_PAGETABLE); - return NULL; - } - free_pages((unsigned long)page, 0); - if (pmd_bad(*pmd)) { - __bad_pte(pmd); - return NULL; - } - return (pte_t *) pmd_page(*pmd) + offset; -} - int do_check_pgt_cache(int low, int high) { int freed = 0; @@ -205,7 +122,7 @@ } /* - * We have upto 8 empty zeroed pages so we can map one of the right colour + * We have up to 8 empty zeroed pages so we can map one of the right colour * when needed. This is necessary only on R4000 / R4400 SC and MC versions * where we have to avoid VCED / VECI exceptions for good performance at * any price. Since page is never written to after the initialization we @@ -247,32 +164,155 @@ return 1UL << order; } -/* - * BAD_PAGE is the page that is used for page faults when linux - * is out-of-memory. Older versions of linux just did a - * do_exit(), but using this instead means there is less risk - * for a process dying in kernel mode, possibly leaving a inode - * unused etc.. - * - * BAD_PAGETABLE is the accompanying page-table: it is initialized - * to point to BAD_PAGE entries. - * - * ZERO_PAGE is a special page that is used for zero-initialized - * data and COW. - */ -pmd_t * __bad_pmd_table(void) +void __init add_memory_region(unsigned long start, unsigned long size, + long type) { - return empty_bad_pmd_table; -} + int x = boot_mem_map.nr_map; -pte_t * __bad_pagetable(void) -{ - return empty_bad_page_table; + if (x == BOOT_MEM_MAP_MAX) { + printk("Ooops! Too many entries in the memory map!\n"); + return; + } + + boot_mem_map.map[x].addr = start; + boot_mem_map.map[x].size = size; + boot_mem_map.map[x].type = type; + boot_mem_map.nr_map++; +} + +static void __init print_memory_map(void) +{ + int i; + + for (i = 0; i < boot_mem_map.nr_map; i++) { + printk(" memory: %08lx @ %08lx ", + boot_mem_map.map[i].size, boot_mem_map.map[i].addr); + switch (boot_mem_map.map[i].type) { + case BOOT_MEM_RAM: + printk("(usable)\n"); + break; + case BOOT_MEM_ROM_DATA: + printk("(ROM data)\n"); + break; + case BOOT_MEM_RESERVED: + printk("(reserved)\n"); + break; + default: + printk("type %lu\n", boot_mem_map.map[i].type); + break; + } + } } -pte_t __bad_page(void) -{ - return __pte(0); +void bootmem_init(void) { +#ifdef CONFIG_BLK_DEV_INITRD + unsigned long tmp; + unsigned long *initrd_header; +#endif + unsigned long bootmap_size; + unsigned long start_pfn, max_pfn; + int i; + extern int _end; + +#define PFN_UP(x) (((x) + PAGE_SIZE - 1) >> PAGE_SHIFT) +#define PFN_DOWN(x) ((x) >> PAGE_SHIFT) +#define PFN_PHYS(x) ((x) << PAGE_SHIFT) + + /* + * Partially used pages are not usable - thus + * we are rounding upwards. + */ + start_pfn = PFN_UP(__pa(&_end)); + + /* Find the highest page frame number we have available. */ + max_pfn = 0; + for (i = 0; i < boot_mem_map.nr_map; i++) { + unsigned long start, end; + + if (boot_mem_map.map[i].type != BOOT_MEM_RAM) + continue; + + start = PFN_UP(boot_mem_map.map[i].addr); + end = PFN_DOWN(boot_mem_map.map[i].addr + + boot_mem_map.map[i].size); + + if (start >= end) + continue; + if (end > max_pfn) + max_pfn = end; + } + + /* Initialize the boot-time allocator. */ + bootmap_size = init_bootmem(start_pfn, max_pfn); + + /* + * Register fully available low RAM pages with the bootmem allocator. + */ + for (i = 0; i < boot_mem_map.nr_map; i++) { + unsigned long curr_pfn, last_pfn, size; + + /* + * Reserve usable memory. + */ + if (boot_mem_map.map[i].type != BOOT_MEM_RAM) + continue; + + /* + * We are rounding up the start address of usable memory: + */ + curr_pfn = PFN_UP(boot_mem_map.map[i].addr); + if (curr_pfn >= max_pfn) + continue; + if (curr_pfn < start_pfn) + curr_pfn = start_pfn; + + /* + * ... and at the end of the usable range downwards: + */ + last_pfn = PFN_DOWN(boot_mem_map.map[i].addr + + boot_mem_map.map[i].size); + + if (last_pfn > max_pfn) + last_pfn = max_pfn; + + /* + * ... finally, did all the rounding and playing + * around just make the area go away? + */ + if (last_pfn <= curr_pfn) + continue; + + size = last_pfn - curr_pfn; + free_bootmem(PFN_PHYS(curr_pfn), PFN_PHYS(size)); + } + + /* Reserve the bootmap memory. */ + reserve_bootmem(PFN_PHYS(start_pfn), bootmap_size); + +#ifdef CONFIG_BLK_DEV_INITRD +#error "Initrd is broken, please fit it." + tmp = (((unsigned long)&_end + PAGE_SIZE-1) & PAGE_MASK) - 8; + if (tmp < (unsigned long)&_end) + tmp += PAGE_SIZE; + initrd_header = (unsigned long *)tmp; + if (initrd_header[0] == 0x494E5244) { + initrd_start = (unsigned long)&initrd_header[2]; + initrd_end = initrd_start + initrd_header[1]; + initrd_below_start_ok = 1; + if (initrd_end > memory_end) { + printk("initrd extends beyond end of memory " + "(0x%08lx > 0x%08lx)\ndisabling initrd\n", + initrd_end,memory_end); + initrd_start = 0; + } else + *memory_start_p = initrd_end; + } +#endif + +#undef PFN_UP +#undef PFN_DOWN +#undef PFN_PHYS + } void show_mem(void) @@ -312,27 +352,39 @@ void __init paging_init(void) { + pmd_t *pmd = kpmdtbl; + pte_t *pte = kptbl; + unsigned long zones_size[MAX_NR_ZONES] = {0, 0, 0}; unsigned long max_dma, low; + int i; /* Initialize the entire pgd. */ pgd_init((unsigned long)swapper_pg_dir); pmd_init((unsigned long)invalid_pmd_table, (unsigned long)invalid_pte_table); memset((void *)invalid_pte_table, 0, sizeof(pte_t) * PTRS_PER_PTE); - pmd_init((unsigned long)empty_bad_pmd_table, (unsigned long)empty_bad_page_table); - memset((void *)empty_bad_page_table, 0, sizeof(pte_t) * PTRS_PER_PTE); max_dma = virt_to_phys((char *)MAX_DMA_ADDRESS) >> PAGE_SHIFT; low = max_low_pfn; +#if defined(CONFIG_PCI) || defined(CONFIG_ISA) if (low < max_dma) zones_size[ZONE_DMA] = low; else { zones_size[ZONE_DMA] = max_dma; zones_size[ZONE_NORMAL] = low - max_dma; } +#else + zones_size[ZONE_DMA] = low; +#endif free_area_init(zones_size); + + memset((void *)kptbl, 0, PAGE_SIZE << KPTBL_PAGE_ORDER); + memset((void *)kpmdtbl, 0, PAGE_SIZE); + pgd_set(swapper_pg_dir, kpmdtbl); + for (i = 0; i < (1 << KPTBL_PAGE_ORDER); pmd++,i++,pte+=PTRS_PER_PTE) + pmd_val(*pmd) = (unsigned long)pte; } extern int page_is_ram(unsigned long pagenr); @@ -411,7 +463,7 @@ si_meminfo(struct sysinfo *val) { val->totalram = totalram_pages; - val->sharedram = 0; + val->sharedram = atomic_read(&shmem_nrpages); val->freeram = nr_free_pages(); val->bufferram = atomic_read(&buffermem_pages); val->totalhigh = 0; diff -u --recursive --new-file v2.4.6/linux/arch/mips64/mm/r4xx0.c linux/arch/mips64/mm/r4xx0.c --- v2.4.6/linux/arch/mips64/mm/r4xx0.c Sun Feb 4 21:48:46 2001 +++ linux/arch/mips64/mm/r4xx0.c Wed Jul 4 11:50:39 2001 @@ -6,7 +6,7 @@ * r4xx0.c: R4000 processor variant specific MMU/Cache routines. * * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) - * Copyright (C) 1997, 1998, 1999, 2000 Ralf Baechle (ralf@gnu.org) + * Copyright (C) 1997, 1998, 1999, 2000, 2001 Ralf Baechle (ralf@gnu.org) * Copyright (C) 1999, 2000 Silicon Graphics, Inc. */ #include <linux/init.h> @@ -377,7 +377,7 @@ "ld\t%3,-8(%1)\n\t" "sd\t%2,-16(%0)\n\t" "bne\t$1,%0,1b\n\t" - " sd\t%4,-8(%0)\n\t" + " sd\t%3,-8(%0)\n\t" ".set\tat\n\t" ".set\treorder" :"=r" (dummy1), "=r" (dummy2), "=&r" (reg1), "=&r" (reg2) @@ -1017,7 +1017,7 @@ struct vm_area_struct *vma; unsigned long flags; - if (CPU_CONTEXT(smp_processor_id(), mm) != 0) { + if (CPU_CONTEXT(smp_processor_id(), mm) != 0) return; start &= PAGE_MASK; @@ -1747,15 +1747,15 @@ unsigned long end, a; unsigned int flags; - if (size >= dcache_size) { + if (size >= (unsigned long)dcache_size) { flush_cache_l1(); } else { /* Workaround for R4600 bug. See comment above. */ __save_and_cli(flags); *(volatile unsigned long *)KSEG1; - a = addr & ~(dc_lsize - 1); - end = (addr + size) & ~(dc_lsize - 1); + a = addr & ~((unsigned long)dc_lsize - 1); + end = (addr + size) & ~((unsigned long)dc_lsize - 1); while (1) { flush_dcache_line(a); /* Hit_Writeback_Inv_D */ if (a == end) break; @@ -1771,13 +1771,13 @@ { unsigned long end, a; - if (size >= scache_size) { + if (size >= (unsigned long)scache_size) { flush_cache_l1(); return; } - a = addr & ~(sc_lsize - 1); - end = (addr + size) & ~(sc_lsize - 1); + a = addr & ~((unsigned long)sc_lsize - 1); + end = (addr + size) & ~((unsigned long)sc_lsize - 1); while (1) { flush_scache_line(a); /* Hit_Writeback_Inv_SD */ if (a == end) break; @@ -1791,15 +1791,15 @@ unsigned long end, a; unsigned int flags; - if (size >= dcache_size) { + if (size >= (unsigned long)dcache_size) { flush_cache_l1(); } else { /* Workaround for R4600 bug. See comment above. */ __save_and_cli(flags); *(volatile unsigned long *)KSEG1; - a = addr & ~(dc_lsize - 1); - end = (addr + size) & ~(dc_lsize - 1); + a = addr & ~((unsigned long)dc_lsize - 1); + end = (addr + size) & ~((unsigned long)dc_lsize - 1); while (1) { flush_dcache_line(a); /* Hit_Writeback_Inv_D */ if (a == end) break; @@ -1816,13 +1816,13 @@ { unsigned long end, a; - if (size >= scache_size) { + if (size >= (unsigned long)scache_size) { flush_cache_l1(); return; } - a = addr & ~(sc_lsize - 1); - end = (addr + size) & ~(sc_lsize - 1); + a = addr & ~((unsigned long)sc_lsize - 1); + end = (addr + size) & ~((unsigned long)sc_lsize - 1); while (1) { flush_scache_line(a); /* Hit_Writeback_Inv_SD */ if (a == end) break; @@ -1845,11 +1845,11 @@ { unsigned long daddr, iaddr; - daddr = addr & ~(dc_lsize - 1); + daddr = addr & ~((unsigned long)dc_lsize - 1); __asm__ __volatile__("nop;nop;nop;nop"); /* R4600 V1.7 */ protected_writeback_dcache_line(daddr); protected_writeback_dcache_line(daddr + dc_lsize); - iaddr = addr & ~(ic_lsize - 1); + iaddr = addr & ~((unsigned long)ic_lsize - 1); protected_flush_icache_line(iaddr); protected_flush_icache_line(iaddr + ic_lsize); } @@ -1859,7 +1859,7 @@ unsigned long daddr, iaddr; unsigned int flags; - daddr = addr & ~(dc_lsize - 1); + daddr = addr & ~((unsigned long)dc_lsize - 1); __save_and_cli(flags); /* Clear internal cache refill buffer */ @@ -1867,7 +1867,7 @@ protected_writeback_dcache_line(daddr); protected_writeback_dcache_line(daddr + dc_lsize); - iaddr = addr & ~(ic_lsize - 1); + iaddr = addr & ~((unsigned long)ic_lsize - 1); protected_flush_icache_line(iaddr); protected_flush_icache_line(iaddr + ic_lsize); __restore_flags(flags); @@ -2384,7 +2384,11 @@ printk("CPU revision is: %08x\n", read_32bit_cp0_register(CP0_PRID)); +#ifdef CONFIG_MIPS_UNCACHED + set_cp0_config(CONF_CM_CMASK, CONF_CM_UNCACHED); +#else set_cp0_config(CONF_CM_CMASK, CONF_CM_CACHABLE_NONCOHERENT); +#endif /* UNCACHED */ probe_icache(config); probe_dcache(config); diff -u --recursive --new-file v2.4.6/linux/arch/mips64/mm/umap.c linux/arch/mips64/mm/umap.c --- v2.4.6/linux/arch/mips64/mm/umap.c Mon Mar 19 12:35:10 2001 +++ linux/arch/mips64/mm/umap.c Wed Jul 4 11:50:39 2001 @@ -1,11 +1,11 @@ -/* $Id: umap.c,v 1.4 2000/01/29 01:41:59 ralf Exp $ - * +/* * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. * * Copyright (C) 1994 Linus Torvalds * Copyright (C) 1997 Miguel de Icaza + * Copyright (C) 2001 Ralf Baechle */ #include <linux/stat.h> #include <linux/sched.h> @@ -16,6 +16,7 @@ #include <linux/shm.h> #include <linux/errno.h> #include <linux/mman.h> +#include <linux/module.h> #include <linux/string.h> #include <linux/vmalloc.h> #include <linux/swap.h> @@ -101,9 +102,12 @@ up_write (&task->mm->mmap_sem); } +EXPORT_SYMBOL(remove_mapping); + void *vmalloc_uncached (unsigned long size) { - return vmalloc_prot (size, PAGE_KERNEL_UNCACHED); + return __vmalloc (size, GFP_KERNEL | __GFP_HIGHMEM, + PAGE_KERNEL_UNCACHED); } static inline void free_pte(pte_t page) diff -u --recursive --new-file v2.4.6/linux/arch/parisc/kernel/ptrace.c linux/arch/parisc/kernel/ptrace.c --- v2.4.6/linux/arch/parisc/kernel/ptrace.c Tue Dec 5 12:29:39 2000 +++ linux/arch/parisc/kernel/ptrace.c Fri Jul 20 12:39:55 2001 @@ -61,32 +61,7 @@ goto out_tsk; if (request == PTRACE_ATTACH) { - if (child == current) - goto out_tsk; - if ((!child->dumpable || - (current->uid != child->euid) || - (current->uid != child->suid) || - (current->uid != child->uid) || - (current->gid != child->egid) || - (current->gid != child->sgid) || - (!cap_issubset(child->cap_permitted, current->cap_permitted)) || - (current->gid != child->gid)) && !capable(CAP_SYS_PTRACE)) - goto out_tsk; - /* the same process cannot be attached many times */ - if (child->ptrace & PT_PTRACED) - goto out_tsk; - child->ptrace |= PT_PTRACED; - if (child->p_pptr != current) { - unsigned long flags; - - write_lock_irqsave(&tasklist_lock, flags); - REMOVE_LINKS(child); - child->p_pptr = current; - SET_LINKS(child); - write_unlock_irqrestore(&tasklist_lock, flags); - } - send_sig(SIGSTOP, child, 1); - ret = 0; + ret = ptrace_attach(child); goto out_tsk; } ret = -ESRCH; diff -u --recursive --new-file v2.4.6/linux/arch/ppc/Makefile linux/arch/ppc/Makefile --- v2.4.6/linux/arch/ppc/Makefile Thu May 24 15:02:06 2001 +++ linux/arch/ppc/Makefile Wed Jul 18 07:14:01 2001 @@ -1,4 +1,4 @@ -# BK Id: SCCS/s.Makefile 1.13 05/21/01 00:48:24 cort +# BK Id: SCCS/s.Makefile 1.18 07/07/01 13:37:26 paulus # # This file is included by the global makefile so that you can add your own # architecture-specific flags and dependencies. Remember to do have actions @@ -52,12 +52,10 @@ ARCH_SUBDIRS = arch/ppc/kernel arch/ppc/mm arch/ppc/lib SUBDIRS := $(SUBDIRS) $(ARCH_SUBDIRS) -ARCHIVES := arch/ppc/kernel/kernel.o arch/ppc/mm/mm.o arch/ppc/lib/lib.o $(ARCHIVES) CORE_FILES := arch/ppc/kernel/kernel.o arch/ppc/mm/mm.o arch/ppc/lib/lib.o $(CORE_FILES) ifdef CONFIG_MATH_EMULATION SUBDIRS += arch/ppc/math-emu -ARCHIVES += arch/ppc/math-emu/math-emu.o CORE_FILES += arch/ppc/math-emu/math-emu.o endif @@ -80,7 +78,6 @@ ifdef CONFIG_APUS SUBDIRS += arch/ppc/amiga -ARCHIVES += arch/ppc/amiga/amiga.o CORE_FILES += arch/ppc/amiga/amiga.o endif @@ -103,4 +100,4 @@ archmrproper: archdep: - $(MAKEBOOT) dep + $(MAKEBOOT) fastdep diff -u --recursive --new-file v2.4.6/linux/arch/ppc/boot/Makefile linux/arch/ppc/boot/Makefile --- v2.4.6/linux/arch/ppc/boot/Makefile Thu May 24 15:02:06 2001 +++ linux/arch/ppc/boot/Makefile Wed Jul 18 07:14:01 2001 @@ -10,17 +10,6 @@ # modified by Cort (cort@cs.nmt.edu) # -.c.s: - $(CC) $(CFLAGS) -S -o $*.s $< -.s.o: - $(AS) -o $*.o $< -.c.o: - $(CC) $(CFLAGS) -c -o $*.o $< -.S.s: - $(CPP) $(AFLAGS) -traditional -o $*.o $< -.S.o: - $(CC) $(AFLAGS) -traditional -c -o $*.o $< - GZIP_FLAGS = -v9f CFLAGS := $(CPPFLAGS) -O2 -DSTDC_HEADERS -fno-builtin -D__BOOTER__ \ @@ -34,33 +23,41 @@ TFTPSIMAGE=/tftpboot/sImage endif - lib/zlib.a: $(MAKE) -C lib images/vmlinux.gz: $(TOPDIR)/vmlinux $(MAKE) -C images vmlinux.gz -# Since gemini doesn't need/have it's own directory, we do znetboot* here -ifdef CONFIG_GEMINI -BOOT_TARGETS = zImage zImage.initrd -else -BOOT_TARGETS = zImage zImage.initrd znetboot znetboot.initrd -endif - -# We go into the utils dir by hand to ensure HOSTCC builds -$(BOOT_TARGETS): sImage vmapus lib/zlib.a images/vmlinux.gz -ifneq ("xx$(CONFIG_8260)$(CONFIG_8xx)","xx") - $(MAKE) -C mbx $@ -endif -ifdef CONFIG_ALL_PPC - $(MAKE) -C utils addnote piggyback mknote hack-coff mkprep - $(MAKE) -C chrp $@ - $(MAKE) -C pmac $@ - $(MAKE) -C prep $@ -endif -ifdef CONFIG_4xx - $(MAKE) -C tree $@ +# Subdirs and tools needed for each. +subdir-y := lib images common +subdir-$(CONFIG_ALL_PPC) += chrp pmac prep +tools-$(CONFIG_ALL_PPC) := addnote piggyback mknote hack-coff mkprep +subdir-$(CONFIG_4xx) += tree +subdir-$(CONFIG_8xx) += mbx +subdir-$(CONFIG_8260) += mbx +tools-$(CONFIG_GEMINI) := mksimage + +# These are dirs we don't want to go into on BOOT_TARGETS +NONBOOT := lib images common + +# These are the subdirs we want to use +BOOTDIRS = $(filter-out $(NONBOOT), $(subdir-y)) + +# This will make the tools we need. We do it like this to ensure that we use +# HOSTCC. -- Tom +maketools: + $(MAKE) -C utils $(tools-y) + +# The targets all boards support for boot images. +BOOT_TARGETS = zImage +ifndef CONFIG_GEMINI +BOOT_TARGETS += zImage.initrd znetboot znetboot.initrd +endif + +$(BOOT_TARGETS): sImage vmapus lib/zlib.a images/vmlinux.gz maketools +ifneq ($(BOOTDIRS),) + for d in $(BOOTDIRS); do $(MAKE) -C $$d $@; done endif sImage: $(TOPDIR)/vmlinux @@ -79,18 +76,11 @@ cp images/sImage $(TFTPSIMAGE) endif -# Do the dirs +# Clean up after ourselves. We have to do it like this since only some dirs +# need to be gone into. -- Tom clean: $(MAKE) -C images clean $(MAKE) -C tree clean $(MAKE) -C utils clean - -dep: - $(MAKE) -C mbx fastdep - $(MAKE) -C chrp fastdep - $(MAKE) -C common fastdep - $(MAKE) -C pmac fastdep - $(MAKE) -C prep fastdep - $(MAKE) -C common fastdep include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.4.6/linux/arch/ppc/boot/chrp/Makefile linux/arch/ppc/boot/chrp/Makefile --- v2.4.6/linux/arch/ppc/boot/chrp/Makefile Thu May 24 15:02:06 2001 +++ linux/arch/ppc/boot/chrp/Makefile Thu Jul 19 18:11:13 2001 @@ -1,4 +1,4 @@ -# BK Id: SCCS/s.Makefile 1.8 05/18/01 06:20:29 patch +# BK Id: SCCS/s.Makefile 1.10 07/19/01 09:11:27 trini # # Makefile for making ELF bootable images for booting on CHRP # using Open Firmware. @@ -13,6 +13,8 @@ else MSIZE= endif + +CFLAGS += -fno-builtin .c.o: $(CC) $(CFLAGS) -DKERNELBASE=$(KERNELBASE) -c -o $*.o $< diff -u --recursive --new-file v2.4.6/linux/arch/ppc/boot/common/misc-common.c linux/arch/ppc/boot/common/misc-common.c --- v2.4.6/linux/arch/ppc/boot/common/misc-common.c Tue Jul 3 17:08:18 2001 +++ linux/arch/ppc/boot/common/misc-common.c Wed Jul 18 18:01:03 2001 @@ -74,11 +74,11 @@ void _vprintk(void(*)(const char), const char *, va_list); #if defined(CONFIG_SERIAL_CONSOLE) -struct NS16550 *com_port; +extern unsigned long com_port; -int serial_tstc(volatile struct NS16550 *); -unsigned char serial_getc(volatile struct NS16550 *); -void serial_putc(volatile struct NS16550 *, unsigned char); +extern int serial_tstc(volatile unsigned long com_port); +extern unsigned char serial_getc(volatile unsigned long com_port); +extern void serial_putc(volatile unsigned long com_port, unsigned char c); #endif void pause(void) diff -u --recursive --new-file v2.4.6/linux/arch/ppc/boot/mbx/misc.c linux/arch/ppc/boot/mbx/misc.c --- v2.4.6/linux/arch/ppc/boot/mbx/misc.c Thu May 24 15:02:06 2001 +++ linux/arch/ppc/boot/mbx/misc.c Wed Jul 18 18:01:03 2001 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.misc.c 1.9 05/18/01 07:54:04 patch + * BK Id: SCCS/s.misc.c 1.11 07/18/01 15:46:50 trini */ /* * Adapted for PowerPC by Gary Thomas @@ -56,6 +56,9 @@ */ char cmd_buf[256]; char *cmd_line = cmd_buf; + +/* We need to pass along a 'dummy' com_port. */ +unsigned long com_port = 0; /* This is the default cmdline that will be given to the user at boot time.. * If none was specified at compile time, we'll give it one that should work. diff -u --recursive --new-file v2.4.6/linux/arch/ppc/boot/pmac/Makefile linux/arch/ppc/boot/pmac/Makefile --- v2.4.6/linux/arch/ppc/boot/pmac/Makefile Tue Jul 3 17:08:18 2001 +++ linux/arch/ppc/boot/pmac/Makefile Thu Jul 19 18:11:13 2001 @@ -1,4 +1,4 @@ -# BK Id: SCCS/s.Makefile 1.10 06/05/01 20:22:51 paulus +# BK Id: SCCS/s.Makefile 1.12 07/19/01 09:11:28 trini # # Makefile for making XCOFF bootable images for booting on PowerMacs # using Open Firmware. @@ -16,6 +16,8 @@ COFFOBJS = ../common/coffcrt0.o $(COMMONOBJS) coffmain.o CHRPOBJS = ../common/crt0.o $(COMMONOBJS) chrpmain.o LIBS = $(TOPDIR)/lib/lib.a ../lib/zlib.a + +CFLAGS += -fno-builtin MKNOTE := ../utils/mknote SIZE := ../utils/size diff -u --recursive --new-file v2.4.6/linux/arch/ppc/boot/prep/Makefile linux/arch/ppc/boot/prep/Makefile --- v2.4.6/linux/arch/ppc/boot/prep/Makefile Tue Jul 3 17:08:18 2001 +++ linux/arch/ppc/boot/prep/Makefile Thu Jul 19 18:11:13 2001 @@ -1,4 +1,4 @@ -# BK Id: SCCS/s.Makefile 1.17 06/12/01 16:47:44 paulus +# BK Id: SCCS/s.Makefile 1.19 07/19/01 09:11:28 trini # # arch/ppc/boot/Makefile # @@ -15,41 +15,30 @@ # modified by Cort (cort@cs.nmt.edu) # -.c.s: - $(CC) $(CFLAGS) -S -o $*.s $< -.s.o: - $(AS) -o $*.o $< -.c.o: - $(CC) $(CFLAGS) -c -o $*.o $< -.S.s: - $(CPP) $(AFLAGS) -traditional -o $*.o $< -.S.o: - $(CC) $(AFLAGS) -traditional -c -o $*.o $< +USE_STANDARD_AS_RULE := true + +CFLAGS += -fno-builtin ifeq ($(CONFIG_SMP),y) -TFTPIMAGE=/tftpboot/zImage.prep.smp +TFTPIMAGE = /tftpboot/zImage.prep.smp else -TFTPIMAGE=/tftpboot/zImage.prep +TFTPIMAGE = /tftpboot/zImage.prep endif -ZLINKFLAGS = -T $(TOPDIR)/arch/$(ARCH)/vmlinux.lds -Ttext 0x00800000 -OBJECTS := head.o misc.o ../common/misc-common.o \ - ../common/string.o of1275.o -OBJCOPY_ARGS = -O elf32-powerpc -LIBS = ../lib/zlib.a - -ifeq ($(CONFIG_SERIAL_CONSOLE),y) -OBJECTS += ns16550.o -endif +ZLINKFLAGS = -T $(TOPDIR)/arch/$(ARCH)/vmlinux.lds \ + -Ttext 0x00800000 +obj-y := head.o misc.o ../common/misc-common.o \ + ../common/string.o of1275.o +OBJCOPY_ARGS = -O elf32-powerpc +LIBS = ../lib/zlib.a -ifeq ($(CONFIG_VGA_CONSOLE),y) -OBJECTS += vreset.o kbd.o -endif +obj-$(CONFIG_SERIAL_CONSOLE) += ns16550.o +obj-$(CONFIG_VGA_CONSOLE) += vreset.o kbd.o # Tools -MKPREP := ../utils/mkprep -SIZE := ../utils/size -OFFSET := ../utils/offset +MKPREP := ../utils/mkprep +SIZE := ../utils/size +OFFSET := ../utils/offset all: zImage @@ -61,7 +50,7 @@ $(CC) $(CFLAGS) -DIOOFFSET=0x80000000 -c -o $@ ../common/$*.c zvmlinux.initrd: zvmlinux ../images/vmlinux.gz - $(LD) $(ZLINKFLAGS) -o $@.tmp $(OBJECTS) $(LIBS) + $(LD) $(ZLINKFLAGS) -o $@.tmp $(obj-y) $(LIBS) $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment \ --add-section=initrd=../images/ramdisk.image.gz \ --add-section=image=../images/vmlinux.gz \ @@ -71,7 +60,7 @@ -DZIMAGE_OFFSET=`sh $(OFFSET) $(OBJDUMP) $@ image` \ -DZIMAGE_SIZE=`sh $(SIZE) $(OBJDUMP) $@ image` \ -c -o misc.o misc.c - $(LD) $(ZLINKFLAGS) -o $@.tmp $(OBJECTS) $(LIBS) + $(LD) $(ZLINKFLAGS) -o $@.tmp $(obj-y) $(LIBS) $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment \ --add-section=initrd=../images/ramdisk.image.gz \ --add-section=image=../images/vmlinux.gz \ @@ -86,12 +75,12 @@ $(MKPREP) -pbp zvmlinux.initrd ../images/$@.prep rm -f zvmlinux.initrd -zvmlinux: $(OBJECTS) $(LIBS) ../images/vmlinux.gz +zvmlinux: $(obj-y) $(LIBS) ../images/vmlinux.gz # # build the boot loader image and then compute the offset into it # for the kernel image # - $(LD) $(ZLINKFLAGS) -o zvmlinux.tmp $(OBJECTS) $(LIBS) + $(LD) $(ZLINKFLAGS) -o zvmlinux.tmp $(obj-y) $(LIBS) $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment \ --add-section=image=../images/vmlinux.gz zvmlinux.tmp $@ # @@ -101,7 +90,7 @@ -DZIMAGE_OFFSET=`sh $(OFFSET) $(OBJDUMP) zvmlinux image` \ -DZIMAGE_SIZE=`sh $(SIZE) $(OBJDUMP) zvmlinux image` \ -c -o misc.o misc.c - $(LD) $(ZLINKFLAGS) -o zvmlinux.tmp $(OBJECTS) $(LIBS) + $(LD) $(ZLINKFLAGS) -o zvmlinux.tmp $(obj-y) $(LIBS) $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment \ --add-section=image=../images/vmlinux.gz $@.tmp $@ rm $@.tmp diff -u --recursive --new-file v2.4.6/linux/arch/ppc/boot/utils/Makefile linux/arch/ppc/boot/utils/Makefile --- v2.4.6/linux/arch/ppc/boot/utils/Makefile Thu May 24 15:02:07 2001 +++ linux/arch/ppc/boot/utils/Makefile Wed Jul 18 07:14:01 2001 @@ -7,6 +7,8 @@ HOSTCFLAGS += -I$(TOPDIR)/arch/$(ARCH)/boot/include +all: dummy + # Simple programs with 1 file and no extra CFLAGS UTILS = addnote hack-coff mkprep mksimage mknote piggyback mkpmon mkbugboot diff -u --recursive --new-file v2.4.6/linux/arch/ppc/config.in linux/arch/ppc/config.in --- v2.4.6/linux/arch/ppc/config.in Tue Jul 3 17:08:18 2001 +++ linux/arch/ppc/config.in Wed Jul 18 07:14:01 2001 @@ -1,4 +1,4 @@ -# BK Id: SCCS/s.config.in 1.30 06/27/01 14:49:58 trini +# BK Id: SCCS/s.config.in 1.34 07/08/01 11:39:11 trini # # For a description of the syntax of this configuration file, # see Documentation/kbuild/config-language.txt. @@ -85,7 +85,7 @@ if [ "$CONFIG_6xx" = "y" -a "$CONFIG_8260" = "n" ]; then choice 'Machine Type' \ "CHRP/PowerMac/PReP CONFIG_ALL_PPC \ - Amgia-APUS CONFIG_APUS \ + Amiga-APUS CONFIG_APUS \ Synergy-Gemini CONFIG_GEMINI" CHRP/PowerMac/PReP fi @@ -165,7 +165,7 @@ source drivers/parport/Config.in -if [ "$CONFIG_4xx" != "y" -a "$CONFIG_8xx" != "y" ]; then +if [ "$CONFIG_4xx" != "y" ]; then if [ "$CONFIG_APUS" != "y" ]; then tristate 'Support for /dev/rtc' CONFIG_PPC_RTC else @@ -178,10 +178,11 @@ bool 'Support for RTAS (RunTime Abstraction Services) in /proc' CONFIG_PPC_RTAS bool 'Support for early boot text console (BootX or OpenFirmware only)' CONFIG_BOOTX_TEXT bool 'Support for PReP Residual Data' CONFIG_PREP_RESIDUAL - bool 'Default bootloader kernel arguments' CONFIG_CMDLINE_BOOL - if [ "$CONFIG_CMDLINE_BOOL" = "y" ] ; then - string 'Initial kernel command string' CONFIG_CMDLINE "console=ttyS0,9600 console=tty0 root=/dev/sda2" - fi +fi + +bool 'Default bootloader kernel arguments' CONFIG_CMDLINE_BOOL +if [ "$CONFIG_CMDLINE_BOOL" = "y" ] ; then + string 'Initial kernel command string' CONFIG_CMDLINE "console=ttyS0,9600 console=tty0 root=/dev/sda2" fi if [ "$CONFIG_APUS" = "y" ]; then diff -u --recursive --new-file v2.4.6/linux/arch/ppc/configs/IVMS8_defconfig linux/arch/ppc/configs/IVMS8_defconfig --- v2.4.6/linux/arch/ppc/configs/IVMS8_defconfig Mon May 21 17:04:46 2001 +++ linux/arch/ppc/configs/IVMS8_defconfig Wed Jul 18 07:14:01 2001 @@ -45,8 +45,6 @@ # CONFIG_ALL_PPC is not set # CONFIG_SMP is not set CONFIG_MATH_EMULATION=y -CONFIG_SASH=y -CONFIG_SASH_PATH="/bin/sash" # # General setup @@ -125,6 +123,7 @@ # CONFIG_IP_MULTICAST is not set # CONFIG_IP_ADVANCED_ROUTER is not set CONFIG_IP_PNP=y +# CONFIG_IP_PNP_DHCP is not set # CONFIG_IP_PNP_BOOTP is not set # CONFIG_IP_PNP_RARP is not set # CONFIG_NET_IPIP is not set @@ -218,23 +217,26 @@ # CONFIG_EQUALIZER is not set # CONFIG_TUN is not set # CONFIG_ETHERTAP is not set -# CONFIG_NET_SB1000 is not set # # Ethernet (10 or 100Mbit) # CONFIG_NET_ETHERNET=y +# CONFIG_ARM_AM79C961A is not set # CONFIG_MACE is not set # CONFIG_BMAC is not set # CONFIG_GMAC is not set # CONFIG_NCR885E is not set # CONFIG_OAKNET is not set +# CONFIG_SUNLANCE is not set +# CONFIG_SUNBMAC is not set +# CONFIG_SUNQE is not set +# CONFIG_SUNLANCE is not set +# CONFIG_SUNGEM is not set # CONFIG_NET_VENDOR_3COM is not set # CONFIG_LANCE is not set # CONFIG_NET_VENDOR_SMC is not set # CONFIG_NET_VENDOR_RACAL is not set -# CONFIG_AT1700 is not set -# CONFIG_DEPCA is not set # CONFIG_NET_ISA is not set # CONFIG_NET_PCI is not set # CONFIG_NET_POCKET is not set @@ -243,11 +245,14 @@ # Ethernet (1000 Mbit) # # CONFIG_ACENIC is not set +# CONFIG_ACENIC_OMIT_TIGON_I is not set +# CONFIG_MYRI_SBUS is not set # CONFIG_HAMACHI is not set # CONFIG_YELLOWFIN is not set # CONFIG_SK98LIN is not set # CONFIG_FDDI is not set # CONFIG_HIPPI is not set +# CONFIG_PLIP is not set # CONFIG_PPP is not set # CONFIG_SLIP is not set @@ -348,6 +353,7 @@ # CONFIG_DTLK is not set # CONFIG_R3964 is not set # CONFIG_APPLICOM is not set +# CONFIG_SONYPI is not set # # Ftape, the floppy tape device driver @@ -386,6 +392,7 @@ CONFIG_ISO9660_FS=y # CONFIG_JOLIET is not set # CONFIG_MINIX_FS is not set +# CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set @@ -399,7 +406,6 @@ # CONFIG_ROMFS_FS is not set CONFIG_EXT2_FS=y # CONFIG_SYSV_FS is not set -# CONFIG_SYSV_FS_WRITE is not set # CONFIG_UDF_FS is not set # CONFIG_UDF_RW is not set # CONFIG_UFS_FS is not set @@ -469,6 +475,11 @@ # USB support # # CONFIG_USB is not set + +# +# Bluetooth support +# +# CONFIG_BLUEZ is not set # # Kernel hacking diff -u --recursive --new-file v2.4.6/linux/arch/ppc/configs/SM850_defconfig linux/arch/ppc/configs/SM850_defconfig --- v2.4.6/linux/arch/ppc/configs/SM850_defconfig Mon May 21 17:04:46 2001 +++ linux/arch/ppc/configs/SM850_defconfig Wed Jul 18 07:14:01 2001 @@ -46,8 +46,6 @@ # CONFIG_ALL_PPC is not set # CONFIG_SMP is not set CONFIG_MATH_EMULATION=y -CONFIG_SASH=y -CONFIG_SASH_PATH="/bin/sash" # # General setup @@ -126,6 +124,7 @@ # CONFIG_IP_MULTICAST is not set # CONFIG_IP_ADVANCED_ROUTER is not set CONFIG_IP_PNP=y +# CONFIG_IP_PNP_DHCP is not set # CONFIG_IP_PNP_BOOTP is not set # CONFIG_IP_PNP_RARP is not set # CONFIG_NET_IPIP is not set @@ -183,23 +182,26 @@ # CONFIG_EQUALIZER is not set # CONFIG_TUN is not set # CONFIG_ETHERTAP is not set -# CONFIG_NET_SB1000 is not set # # Ethernet (10 or 100Mbit) # CONFIG_NET_ETHERNET=y +# CONFIG_ARM_AM79C961A is not set # CONFIG_MACE is not set # CONFIG_BMAC is not set # CONFIG_GMAC is not set # CONFIG_NCR885E is not set # CONFIG_OAKNET is not set +# CONFIG_SUNLANCE is not set +# CONFIG_SUNBMAC is not set +# CONFIG_SUNQE is not set +# CONFIG_SUNLANCE is not set +# CONFIG_SUNGEM is not set # CONFIG_NET_VENDOR_3COM is not set # CONFIG_LANCE is not set # CONFIG_NET_VENDOR_SMC is not set # CONFIG_NET_VENDOR_RACAL is not set -# CONFIG_AT1700 is not set -# CONFIG_DEPCA is not set # CONFIG_NET_ISA is not set # CONFIG_NET_PCI is not set # CONFIG_NET_POCKET is not set @@ -208,11 +210,14 @@ # Ethernet (1000 Mbit) # # CONFIG_ACENIC is not set +# CONFIG_ACENIC_OMIT_TIGON_I is not set +# CONFIG_MYRI_SBUS is not set # CONFIG_HAMACHI is not set # CONFIG_YELLOWFIN is not set # CONFIG_SK98LIN is not set # CONFIG_FDDI is not set # CONFIG_HIPPI is not set +# CONFIG_PLIP is not set # CONFIG_PPP is not set # CONFIG_SLIP is not set @@ -313,6 +318,7 @@ # CONFIG_DTLK is not set # CONFIG_R3964 is not set # CONFIG_APPLICOM is not set +# CONFIG_SONYPI is not set # # Ftape, the floppy tape device driver @@ -351,6 +357,7 @@ # CONFIG_ISO9660_FS is not set # CONFIG_JOLIET is not set # CONFIG_MINIX_FS is not set +# CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set @@ -364,7 +371,6 @@ # CONFIG_ROMFS_FS is not set # CONFIG_EXT2_FS is not set # CONFIG_SYSV_FS is not set -# CONFIG_SYSV_FS_WRITE is not set # CONFIG_UDF_FS is not set # CONFIG_UDF_RW is not set # CONFIG_UFS_FS is not set @@ -437,6 +443,11 @@ # USB support # # CONFIG_USB is not set + +# +# Bluetooth support +# +# CONFIG_BLUEZ is not set # # Kernel hacking diff -u --recursive --new-file v2.4.6/linux/arch/ppc/configs/SPD823TS_defconfig linux/arch/ppc/configs/SPD823TS_defconfig --- v2.4.6/linux/arch/ppc/configs/SPD823TS_defconfig Mon May 21 17:04:46 2001 +++ linux/arch/ppc/configs/SPD823TS_defconfig Wed Jul 18 07:14:01 2001 @@ -45,8 +45,6 @@ # CONFIG_ALL_PPC is not set # CONFIG_SMP is not set CONFIG_MATH_EMULATION=y -CONFIG_SASH=y -CONFIG_SASH_PATH="/bin/sash" # # General setup @@ -125,6 +123,7 @@ # CONFIG_IP_MULTICAST is not set # CONFIG_IP_ADVANCED_ROUTER is not set CONFIG_IP_PNP=y +# CONFIG_IP_PNP_DHCP is not set # CONFIG_IP_PNP_BOOTP is not set # CONFIG_IP_PNP_RARP is not set # CONFIG_NET_IPIP is not set @@ -182,23 +181,26 @@ # CONFIG_EQUALIZER is not set # CONFIG_TUN is not set # CONFIG_ETHERTAP is not set -# CONFIG_NET_SB1000 is not set # # Ethernet (10 or 100Mbit) # CONFIG_NET_ETHERNET=y +# CONFIG_ARM_AM79C961A is not set # CONFIG_MACE is not set # CONFIG_BMAC is not set # CONFIG_GMAC is not set # CONFIG_NCR885E is not set # CONFIG_OAKNET is not set +# CONFIG_SUNLANCE is not set +# CONFIG_SUNBMAC is not set +# CONFIG_SUNQE is not set +# CONFIG_SUNLANCE is not set +# CONFIG_SUNGEM is not set # CONFIG_NET_VENDOR_3COM is not set # CONFIG_LANCE is not set # CONFIG_NET_VENDOR_SMC is not set # CONFIG_NET_VENDOR_RACAL is not set -# CONFIG_AT1700 is not set -# CONFIG_DEPCA is not set # CONFIG_NET_ISA is not set # CONFIG_NET_PCI is not set # CONFIG_NET_POCKET is not set @@ -207,11 +209,14 @@ # Ethernet (1000 Mbit) # # CONFIG_ACENIC is not set +# CONFIG_ACENIC_OMIT_TIGON_I is not set +# CONFIG_MYRI_SBUS is not set # CONFIG_HAMACHI is not set # CONFIG_YELLOWFIN is not set # CONFIG_SK98LIN is not set # CONFIG_FDDI is not set # CONFIG_HIPPI is not set +# CONFIG_PLIP is not set # CONFIG_PPP is not set # CONFIG_SLIP is not set @@ -312,6 +317,7 @@ # CONFIG_DTLK is not set # CONFIG_R3964 is not set # CONFIG_APPLICOM is not set +# CONFIG_SONYPI is not set # # Ftape, the floppy tape device driver @@ -350,6 +356,7 @@ # CONFIG_ISO9660_FS is not set # CONFIG_JOLIET is not set # CONFIG_MINIX_FS is not set +# CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set @@ -363,7 +370,6 @@ # CONFIG_ROMFS_FS is not set # CONFIG_EXT2_FS is not set # CONFIG_SYSV_FS is not set -# CONFIG_SYSV_FS_WRITE is not set # CONFIG_UDF_FS is not set # CONFIG_UDF_RW is not set # CONFIG_UFS_FS is not set @@ -436,6 +442,11 @@ # USB support # # CONFIG_USB is not set + +# +# Bluetooth support +# +# CONFIG_BLUEZ is not set # # Kernel hacking diff -u --recursive --new-file v2.4.6/linux/arch/ppc/configs/TQM823L_defconfig linux/arch/ppc/configs/TQM823L_defconfig --- v2.4.6/linux/arch/ppc/configs/TQM823L_defconfig Mon May 21 17:04:46 2001 +++ linux/arch/ppc/configs/TQM823L_defconfig Wed Jul 18 07:14:01 2001 @@ -46,8 +46,6 @@ # CONFIG_ALL_PPC is not set # CONFIG_SMP is not set CONFIG_MATH_EMULATION=y -CONFIG_SASH=y -CONFIG_SASH_PATH="/bin/sash" # # General setup @@ -126,6 +124,7 @@ # CONFIG_IP_MULTICAST is not set # CONFIG_IP_ADVANCED_ROUTER is not set CONFIG_IP_PNP=y +# CONFIG_IP_PNP_DHCP is not set # CONFIG_IP_PNP_BOOTP is not set # CONFIG_IP_PNP_RARP is not set # CONFIG_NET_IPIP is not set @@ -183,23 +182,26 @@ # CONFIG_EQUALIZER is not set # CONFIG_TUN is not set # CONFIG_ETHERTAP is not set -# CONFIG_NET_SB1000 is not set # # Ethernet (10 or 100Mbit) # CONFIG_NET_ETHERNET=y +# CONFIG_ARM_AM79C961A is not set # CONFIG_MACE is not set # CONFIG_BMAC is not set # CONFIG_GMAC is not set # CONFIG_NCR885E is not set # CONFIG_OAKNET is not set +# CONFIG_SUNLANCE is not set +# CONFIG_SUNBMAC is not set +# CONFIG_SUNQE is not set +# CONFIG_SUNLANCE is not set +# CONFIG_SUNGEM is not set # CONFIG_NET_VENDOR_3COM is not set # CONFIG_LANCE is not set # CONFIG_NET_VENDOR_SMC is not set # CONFIG_NET_VENDOR_RACAL is not set -# CONFIG_AT1700 is not set -# CONFIG_DEPCA is not set # CONFIG_NET_ISA is not set # CONFIG_NET_PCI is not set # CONFIG_NET_POCKET is not set @@ -208,11 +210,14 @@ # Ethernet (1000 Mbit) # # CONFIG_ACENIC is not set +# CONFIG_ACENIC_OMIT_TIGON_I is not set +# CONFIG_MYRI_SBUS is not set # CONFIG_HAMACHI is not set # CONFIG_YELLOWFIN is not set # CONFIG_SK98LIN is not set # CONFIG_FDDI is not set # CONFIG_HIPPI is not set +# CONFIG_PLIP is not set # CONFIG_PPP is not set # CONFIG_SLIP is not set @@ -313,6 +318,7 @@ # CONFIG_DTLK is not set # CONFIG_R3964 is not set # CONFIG_APPLICOM is not set +# CONFIG_SONYPI is not set # # Ftape, the floppy tape device driver @@ -351,6 +357,7 @@ # CONFIG_ISO9660_FS is not set # CONFIG_JOLIET is not set # CONFIG_MINIX_FS is not set +# CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set @@ -364,7 +371,6 @@ # CONFIG_ROMFS_FS is not set # CONFIG_EXT2_FS is not set # CONFIG_SYSV_FS is not set -# CONFIG_SYSV_FS_WRITE is not set # CONFIG_UDF_FS is not set # CONFIG_UDF_RW is not set # CONFIG_UFS_FS is not set @@ -437,6 +443,11 @@ # USB support # # CONFIG_USB is not set + +# +# Bluetooth support +# +# CONFIG_BLUEZ is not set # # Kernel hacking diff -u --recursive --new-file v2.4.6/linux/arch/ppc/configs/TQM850L_defconfig linux/arch/ppc/configs/TQM850L_defconfig --- v2.4.6/linux/arch/ppc/configs/TQM850L_defconfig Mon May 21 17:04:46 2001 +++ linux/arch/ppc/configs/TQM850L_defconfig Wed Jul 18 07:14:01 2001 @@ -46,8 +46,6 @@ # CONFIG_ALL_PPC is not set # CONFIG_SMP is not set CONFIG_MATH_EMULATION=y -CONFIG_SASH=y -CONFIG_SASH_PATH="/bin/sash" # # General setup @@ -126,6 +124,7 @@ # CONFIG_IP_MULTICAST is not set # CONFIG_IP_ADVANCED_ROUTER is not set CONFIG_IP_PNP=y +# CONFIG_IP_PNP_DHCP is not set # CONFIG_IP_PNP_BOOTP is not set # CONFIG_IP_PNP_RARP is not set # CONFIG_NET_IPIP is not set @@ -183,23 +182,26 @@ # CONFIG_EQUALIZER is not set # CONFIG_TUN is not set # CONFIG_ETHERTAP is not set -# CONFIG_NET_SB1000 is not set # # Ethernet (10 or 100Mbit) # CONFIG_NET_ETHERNET=y +# CONFIG_ARM_AM79C961A is not set # CONFIG_MACE is not set # CONFIG_BMAC is not set # CONFIG_GMAC is not set # CONFIG_NCR885E is not set # CONFIG_OAKNET is not set +# CONFIG_SUNLANCE is not set +# CONFIG_SUNBMAC is not set +# CONFIG_SUNQE is not set +# CONFIG_SUNLANCE is not set +# CONFIG_SUNGEM is not set # CONFIG_NET_VENDOR_3COM is not set # CONFIG_LANCE is not set # CONFIG_NET_VENDOR_SMC is not set # CONFIG_NET_VENDOR_RACAL is not set -# CONFIG_AT1700 is not set -# CONFIG_DEPCA is not set # CONFIG_NET_ISA is not set # CONFIG_NET_PCI is not set # CONFIG_NET_POCKET is not set @@ -208,11 +210,14 @@ # Ethernet (1000 Mbit) # # CONFIG_ACENIC is not set +# CONFIG_ACENIC_OMIT_TIGON_I is not set +# CONFIG_MYRI_SBUS is not set # CONFIG_HAMACHI is not set # CONFIG_YELLOWFIN is not set # CONFIG_SK98LIN is not set # CONFIG_FDDI is not set # CONFIG_HIPPI is not set +# CONFIG_PLIP is not set # CONFIG_PPP is not set # CONFIG_SLIP is not set @@ -313,6 +318,7 @@ # CONFIG_DTLK is not set # CONFIG_R3964 is not set # CONFIG_APPLICOM is not set +# CONFIG_SONYPI is not set # # Ftape, the floppy tape device driver @@ -351,6 +357,7 @@ # CONFIG_ISO9660_FS is not set # CONFIG_JOLIET is not set # CONFIG_MINIX_FS is not set +# CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set @@ -364,7 +371,6 @@ # CONFIG_ROMFS_FS is not set # CONFIG_EXT2_FS is not set # CONFIG_SYSV_FS is not set -# CONFIG_SYSV_FS_WRITE is not set # CONFIG_UDF_FS is not set # CONFIG_UDF_RW is not set # CONFIG_UFS_FS is not set @@ -437,6 +443,11 @@ # USB support # # CONFIG_USB is not set + +# +# Bluetooth support +# +# CONFIG_BLUEZ is not set # # Kernel hacking diff -u --recursive --new-file v2.4.6/linux/arch/ppc/configs/TQM860L_defconfig linux/arch/ppc/configs/TQM860L_defconfig --- v2.4.6/linux/arch/ppc/configs/TQM860L_defconfig Mon May 21 17:04:46 2001 +++ linux/arch/ppc/configs/TQM860L_defconfig Wed Jul 18 07:14:01 2001 @@ -46,8 +46,6 @@ # CONFIG_ALL_PPC is not set # CONFIG_SMP is not set CONFIG_MATH_EMULATION=y -CONFIG_SASH=y -CONFIG_SASH_PATH="/bin/sash" # # General setup @@ -126,6 +124,7 @@ # CONFIG_IP_MULTICAST is not set # CONFIG_IP_ADVANCED_ROUTER is not set CONFIG_IP_PNP=y +# CONFIG_IP_PNP_DHCP is not set # CONFIG_IP_PNP_BOOTP is not set # CONFIG_IP_PNP_RARP is not set # CONFIG_NET_IPIP is not set @@ -183,23 +182,26 @@ # CONFIG_EQUALIZER is not set # CONFIG_TUN is not set # CONFIG_ETHERTAP is not set -# CONFIG_NET_SB1000 is not set # # Ethernet (10 or 100Mbit) # CONFIG_NET_ETHERNET=y +# CONFIG_ARM_AM79C961A is not set # CONFIG_MACE is not set # CONFIG_BMAC is not set # CONFIG_GMAC is not set # CONFIG_NCR885E is not set # CONFIG_OAKNET is not set +# CONFIG_SUNLANCE is not set +# CONFIG_SUNBMAC is not set +# CONFIG_SUNQE is not set +# CONFIG_SUNLANCE is not set +# CONFIG_SUNGEM is not set # CONFIG_NET_VENDOR_3COM is not set # CONFIG_LANCE is not set # CONFIG_NET_VENDOR_SMC is not set # CONFIG_NET_VENDOR_RACAL is not set -# CONFIG_AT1700 is not set -# CONFIG_DEPCA is not set # CONFIG_NET_ISA is not set # CONFIG_NET_PCI is not set # CONFIG_NET_POCKET is not set @@ -208,11 +210,14 @@ # Ethernet (1000 Mbit) # # CONFIG_ACENIC is not set +# CONFIG_ACENIC_OMIT_TIGON_I is not set +# CONFIG_MYRI_SBUS is not set # CONFIG_HAMACHI is not set # CONFIG_YELLOWFIN is not set # CONFIG_SK98LIN is not set # CONFIG_FDDI is not set # CONFIG_HIPPI is not set +# CONFIG_PLIP is not set # CONFIG_PPP is not set # CONFIG_SLIP is not set @@ -313,6 +318,7 @@ # CONFIG_DTLK is not set # CONFIG_R3964 is not set # CONFIG_APPLICOM is not set +# CONFIG_SONYPI is not set # # Ftape, the floppy tape device driver @@ -351,6 +357,7 @@ # CONFIG_ISO9660_FS is not set # CONFIG_JOLIET is not set # CONFIG_MINIX_FS is not set +# CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set @@ -364,7 +371,6 @@ # CONFIG_ROMFS_FS is not set # CONFIG_EXT2_FS is not set # CONFIG_SYSV_FS is not set -# CONFIG_SYSV_FS_WRITE is not set # CONFIG_UDF_FS is not set # CONFIG_UDF_RW is not set # CONFIG_UFS_FS is not set @@ -437,6 +443,11 @@ # USB support # # CONFIG_USB is not set + +# +# Bluetooth support +# +# CONFIG_BLUEZ is not set # # Kernel hacking diff -u --recursive --new-file v2.4.6/linux/arch/ppc/configs/apus_defconfig linux/arch/ppc/configs/apus_defconfig --- v2.4.6/linux/arch/ppc/configs/apus_defconfig Mon May 21 17:04:46 2001 +++ linux/arch/ppc/configs/apus_defconfig Wed Jul 18 07:14:01 2001 @@ -28,8 +28,8 @@ # CONFIG_8xx is not set # CONFIG_8260 is not set # CONFIG_ALL_PPC is not set -# CONFIG_GEMINI is not set CONFIG_APUS=y +# CONFIG_GEMINI is not set # CONFIG_PPC601_SYNC_FIX is not set # CONFIG_SMP is not set # CONFIG_ALTIVEC is not set @@ -42,6 +42,7 @@ # CONFIG_EISA is not set # CONFIG_SBUS is not set # CONFIG_MCA is not set +CONFIG_PCI_PERMEDIA=y CONFIG_PCI=y CONFIG_NET=y CONFIG_SYSCTL=y @@ -343,7 +344,6 @@ CONFIG_WARPENGINE_SCSI=y CONFIG_BLZ603EPLUS_SCSI=y CONFIG_OKTAGON_SCSI=y -CONFIG_CYBERSTORMIII_SCSI=y # # IEEE 1394 (FireWire) support @@ -364,12 +364,12 @@ # CONFIG_EQUALIZER is not set CONFIG_TUN=m # CONFIG_ETHERTAP is not set -# CONFIG_NET_SB1000 is not set # # Ethernet (10 or 100Mbit) # CONFIG_NET_ETHERNET=y +# CONFIG_ARM_AM79C961A is not set # CONFIG_MACE is not set # CONFIG_BMAC is not set # CONFIG_GMAC is not set @@ -379,12 +379,16 @@ CONFIG_NE2K_ZORRO=y CONFIG_A2065=y CONFIG_HYDRA=y +# CONFIG_SUNLANCE is not set +# CONFIG_HAPPYMEAL is not set +# CONFIG_SUNBMAC is not set +# CONFIG_SUNQE is not set +# CONFIG_SUNLANCE is not set +# CONFIG_SUNGEM is not set # CONFIG_NET_VENDOR_3COM is not set # CONFIG_LANCE is not set # CONFIG_NET_VENDOR_SMC is not set # CONFIG_NET_VENDOR_RACAL is not set -# CONFIG_AT1700 is not set -# CONFIG_DEPCA is not set # CONFIG_HP100 is not set # CONFIG_NET_ISA is not set # CONFIG_NET_PCI is not set @@ -394,6 +398,8 @@ # Ethernet (1000 Mbit) # # CONFIG_ACENIC is not set +# CONFIG_ACENIC_OMIT_TIGON_I is not set +# CONFIG_MYRI_SBUS is not set # CONFIG_HAMACHI is not set # CONFIG_YELLOWFIN is not set # CONFIG_SK98LIN is not set @@ -541,6 +547,7 @@ # CONFIG_SERIAL is not set # CONFIG_SERIAL_EXTENDED is not set # CONFIG_SERIAL_NONSTANDARD is not set +CONFIG_A2232=y CONFIG_UNIX98_PTYS=y CONFIG_UNIX98_PTY_COUNT=256 CONFIG_PRINTER=m @@ -584,6 +591,7 @@ # CONFIG_DTLK is not set # CONFIG_R3964 is not set # CONFIG_APPLICOM is not set +# CONFIG_SONYPI is not set # # Ftape, the floppy tape device driver @@ -622,6 +630,7 @@ CONFIG_ISO9660_FS=y CONFIG_JOLIET=y CONFIG_MINIX_FS=y +# CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set @@ -635,7 +644,6 @@ CONFIG_ROMFS_FS=y CONFIG_EXT2_FS=y # CONFIG_SYSV_FS is not set -# CONFIG_SYSV_FS_WRITE is not set # CONFIG_UDF_FS is not set # CONFIG_UDF_RW is not set # CONFIG_UFS_FS is not set @@ -747,6 +755,7 @@ # CONFIG_SOUND_MSNDCLAS is not set # CONFIG_SOUND_MSNDPIN is not set # CONFIG_SOUND_VIA82CXXX is not set +# CONFIG_MIDI_VIA82CXXX is not set CONFIG_SOUND_OSS=m CONFIG_SOUND_TRACEINIT=y CONFIG_SOUND_DMAP=y @@ -783,6 +792,11 @@ # USB support # # CONFIG_USB is not set + +# +# Bluetooth support +# +# CONFIG_BLUEZ is not set # # Kernel hacking diff -u --recursive --new-file v2.4.6/linux/arch/ppc/configs/bseip_defconfig linux/arch/ppc/configs/bseip_defconfig --- v2.4.6/linux/arch/ppc/configs/bseip_defconfig Mon May 21 17:04:46 2001 +++ linux/arch/ppc/configs/bseip_defconfig Wed Jul 18 07:14:01 2001 @@ -122,6 +122,7 @@ CONFIG_IP_MULTICAST=y # CONFIG_IP_ADVANCED_ROUTER is not set CONFIG_IP_PNP=y +# CONFIG_IP_PNP_DHCP is not set CONFIG_IP_PNP_BOOTP=y # CONFIG_IP_PNP_RARP is not set # CONFIG_NET_IPIP is not set @@ -180,23 +181,26 @@ # CONFIG_EQUALIZER is not set # CONFIG_TUN is not set # CONFIG_ETHERTAP is not set -# CONFIG_NET_SB1000 is not set # # Ethernet (10 or 100Mbit) # CONFIG_NET_ETHERNET=y +# CONFIG_ARM_AM79C961A is not set # CONFIG_MACE is not set # CONFIG_BMAC is not set # CONFIG_GMAC is not set # CONFIG_NCR885E is not set # CONFIG_OAKNET is not set +# CONFIG_SUNLANCE is not set +# CONFIG_SUNBMAC is not set +# CONFIG_SUNQE is not set +# CONFIG_SUNLANCE is not set +# CONFIG_SUNGEM is not set # CONFIG_NET_VENDOR_3COM is not set # CONFIG_LANCE is not set # CONFIG_NET_VENDOR_SMC is not set # CONFIG_NET_VENDOR_RACAL is not set -# CONFIG_AT1700 is not set -# CONFIG_DEPCA is not set # CONFIG_NET_ISA is not set # CONFIG_NET_PCI is not set # CONFIG_NET_POCKET is not set @@ -205,11 +209,14 @@ # Ethernet (1000 Mbit) # # CONFIG_ACENIC is not set +# CONFIG_ACENIC_OMIT_TIGON_I is not set +# CONFIG_MYRI_SBUS is not set # CONFIG_HAMACHI is not set # CONFIG_YELLOWFIN is not set # CONFIG_SK98LIN is not set # CONFIG_FDDI is not set # CONFIG_HIPPI is not set +# CONFIG_PLIP is not set # CONFIG_PPP is not set # CONFIG_SLIP is not set @@ -310,6 +317,7 @@ # CONFIG_DTLK is not set # CONFIG_R3964 is not set # CONFIG_APPLICOM is not set +# CONFIG_SONYPI is not set # # Ftape, the floppy tape device driver @@ -348,6 +356,7 @@ # CONFIG_ISO9660_FS is not set # CONFIG_JOLIET is not set # CONFIG_MINIX_FS is not set +# CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set @@ -361,7 +370,6 @@ # CONFIG_ROMFS_FS is not set CONFIG_EXT2_FS=y # CONFIG_SYSV_FS is not set -# CONFIG_SYSV_FS_WRITE is not set # CONFIG_UDF_FS is not set # CONFIG_UDF_RW is not set # CONFIG_UFS_FS is not set @@ -434,6 +442,11 @@ # USB support # # CONFIG_USB is not set + +# +# Bluetooth support +# +# CONFIG_BLUEZ is not set # # Kernel hacking diff -u --recursive --new-file v2.4.6/linux/arch/ppc/configs/common_defconfig linux/arch/ppc/configs/common_defconfig --- v2.4.6/linux/arch/ppc/configs/common_defconfig Wed May 16 09:57:20 2001 +++ linux/arch/ppc/configs/common_defconfig Wed Jul 18 07:14:01 2001 @@ -28,8 +28,8 @@ # CONFIG_8xx is not set # CONFIG_8260 is not set CONFIG_ALL_PPC=y -# CONFIG_GEMINI is not set # CONFIG_APUS is not set +# CONFIG_GEMINI is not set CONFIG_PPC601_SYNC_FIX=y # CONFIG_SMP is not set CONFIG_ALTIVEC=y @@ -301,7 +301,8 @@ # CONFIG_SCSI_AHA1740 is not set CONFIG_SCSI_AIC7XXX=m CONFIG_AIC7XXX_CMDS_PER_DEVICE=253 -CONFIG_AIC7XXX_RESET_DELAY=5000 +CONFIG_AIC7XXX_RESET_DELAY_MS=15000 +# CONFIG_AIC7XXX_BUILD_FIRMWARE is not set CONFIG_SCSI_AIC7XXX_OLD=m # CONFIG_AIC7XXX_OLD_TCQ_ON_BY_DEFAULT is not set CONFIG_AIC7XXX_OLD_CMDS_PER_DEVICE=8 @@ -375,24 +376,28 @@ # CONFIG_EQUALIZER is not set # CONFIG_TUN is not set # CONFIG_ETHERTAP is not set -# CONFIG_NET_SB1000 is not set # # Ethernet (10 or 100Mbit) # CONFIG_NET_ETHERNET=y +# CONFIG_ARM_AM79C961A is not set CONFIG_MACE=y # CONFIG_MACE_AAUI_PORT is not set CONFIG_BMAC=y CONFIG_GMAC=y # CONFIG_NCR885E is not set # CONFIG_OAKNET is not set +# CONFIG_SUNLANCE is not set +# CONFIG_HAPPYMEAL is not set +# CONFIG_SUNBMAC is not set +# CONFIG_SUNQE is not set +# CONFIG_SUNLANCE is not set +# CONFIG_SUNGEM is not set # CONFIG_NET_VENDOR_3COM is not set # CONFIG_LANCE is not set # CONFIG_NET_VENDOR_SMC is not set # CONFIG_NET_VENDOR_RACAL is not set -# CONFIG_AT1700 is not set -# CONFIG_DEPCA is not set # CONFIG_HP100 is not set # CONFIG_NET_ISA is not set CONFIG_NET_PCI=y @@ -401,12 +406,14 @@ # CONFIG_APRICOT is not set # CONFIG_CS89x0 is not set CONFIG_TULIP=y +# CONFIG_TULIP_MWI is not set +CONFIG_TULIP_MMIO=y CONFIG_DE4X5=m # CONFIG_DGRS is not set # CONFIG_DM9102 is not set # CONFIG_EEPRO100 is not set -# CONFIG_EEPRO100_PM is not set # CONFIG_LNE390 is not set +# CONFIG_FEALNX is not set # CONFIG_NATSEMI is not set # CONFIG_NE2K_PCI is not set # CONFIG_NE3210 is not set @@ -421,18 +428,20 @@ # CONFIG_TLAN is not set # CONFIG_VIA_RHINE is not set # CONFIG_WINBOND_840 is not set -# CONFIG_HAPPYMEAL is not set # CONFIG_NET_POCKET is not set # # Ethernet (1000 Mbit) # # CONFIG_ACENIC is not set +# CONFIG_ACENIC_OMIT_TIGON_I is not set +# CONFIG_MYRI_SBUS is not set # CONFIG_HAMACHI is not set # CONFIG_YELLOWFIN is not set # CONFIG_SK98LIN is not set # CONFIG_FDDI is not set # CONFIG_HIPPI is not set +# CONFIG_PLIP is not set CONFIG_PPP=y CONFIG_PPP_MULTILINK=y # CONFIG_PPP_FILTER is not set @@ -606,6 +615,7 @@ # CONFIG_DTLK is not set # CONFIG_R3964 is not set # CONFIG_APPLICOM is not set +# CONFIG_SONYPI is not set # # Ftape, the floppy tape device driver @@ -644,6 +654,7 @@ CONFIG_ISO9660_FS=y # CONFIG_JOLIET is not set # CONFIG_MINIX_FS is not set +# CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set @@ -657,7 +668,6 @@ # CONFIG_ROMFS_FS is not set CONFIG_EXT2_FS=y # CONFIG_SYSV_FS is not set -# CONFIG_SYSV_FS_WRITE is not set # CONFIG_UDF_FS is not set # CONFIG_UDF_RW is not set # CONFIG_UFS_FS is not set @@ -767,6 +777,7 @@ # CONFIG_SOUND_MSNDCLAS is not set # CONFIG_SOUND_MSNDPIN is not set # CONFIG_SOUND_VIA82CXXX is not set +# CONFIG_MIDI_VIA82CXXX is not set # CONFIG_SOUND_OSS is not set # CONFIG_SOUND_TVMIXER is not set @@ -817,6 +828,8 @@ # # CONFIG_USB_IBMCAM is not set # CONFIG_USB_OV511 is not set +# CONFIG_USB_PWC is not set +# CONFIG_USB_SE401 is not set # CONFIG_USB_DSBR is not set # CONFIG_USB_DABUSB is not set @@ -825,6 +838,7 @@ # # CONFIG_USB_PLUSB is not set # CONFIG_USB_PEGASUS is not set +# CONFIG_USB_CATC is not set # CONFIG_USB_NET1080 is not set # @@ -847,12 +861,19 @@ # CONFIG_USB_SERIAL_KEYSPAN_PDA is not set # CONFIG_USB_SERIAL_KEYSPAN is not set # CONFIG_USB_SERIAL_MCT_U232 is not set +# CONFIG_USB_SERIAL_PL2303 is not set +# CONFIG_USB_SERIAL_CYBERJACK is not set # CONFIG_USB_SERIAL_OMNINET is not set # # USB misc drivers # # CONFIG_USB_RIO500 is not set + +# +# Bluetooth support +# +# CONFIG_BLUEZ is not set # # Kernel hacking diff -u --recursive --new-file v2.4.6/linux/arch/ppc/configs/est8260_defconfig linux/arch/ppc/configs/est8260_defconfig --- v2.4.6/linux/arch/ppc/configs/est8260_defconfig Mon May 21 17:04:46 2001 +++ linux/arch/ppc/configs/est8260_defconfig Wed Jul 18 07:14:01 2001 @@ -109,6 +109,7 @@ CONFIG_IP_MULTICAST=y # CONFIG_IP_ADVANCED_ROUTER is not set CONFIG_IP_PNP=y +# CONFIG_IP_PNP_DHCP is not set CONFIG_IP_PNP_BOOTP=y # CONFIG_IP_PNP_RARP is not set # CONFIG_NET_IPIP is not set @@ -167,23 +168,26 @@ # CONFIG_EQUALIZER is not set # CONFIG_TUN is not set # CONFIG_ETHERTAP is not set -# CONFIG_NET_SB1000 is not set # # Ethernet (10 or 100Mbit) # CONFIG_NET_ETHERNET=y +# CONFIG_ARM_AM79C961A is not set # CONFIG_MACE is not set # CONFIG_BMAC is not set # CONFIG_GMAC is not set # CONFIG_NCR885E is not set # CONFIG_OAKNET is not set +# CONFIG_SUNLANCE is not set +# CONFIG_SUNBMAC is not set +# CONFIG_SUNQE is not set +# CONFIG_SUNLANCE is not set +# CONFIG_SUNGEM is not set # CONFIG_NET_VENDOR_3COM is not set # CONFIG_LANCE is not set # CONFIG_NET_VENDOR_SMC is not set # CONFIG_NET_VENDOR_RACAL is not set -# CONFIG_AT1700 is not set -# CONFIG_DEPCA is not set # CONFIG_NET_ISA is not set # CONFIG_NET_PCI is not set # CONFIG_NET_POCKET is not set @@ -192,11 +196,14 @@ # Ethernet (1000 Mbit) # # CONFIG_ACENIC is not set +# CONFIG_ACENIC_OMIT_TIGON_I is not set +# CONFIG_MYRI_SBUS is not set # CONFIG_HAMACHI is not set # CONFIG_YELLOWFIN is not set # CONFIG_SK98LIN is not set # CONFIG_FDDI is not set # CONFIG_HIPPI is not set +# CONFIG_PLIP is not set # CONFIG_PPP is not set # CONFIG_SLIP is not set @@ -298,6 +305,7 @@ # CONFIG_DTLK is not set # CONFIG_R3964 is not set # CONFIG_APPLICOM is not set +# CONFIG_SONYPI is not set # # Ftape, the floppy tape device driver @@ -336,6 +344,7 @@ # CONFIG_ISO9660_FS is not set # CONFIG_JOLIET is not set # CONFIG_MINIX_FS is not set +# CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set @@ -349,7 +358,6 @@ # CONFIG_ROMFS_FS is not set CONFIG_EXT2_FS=y # CONFIG_SYSV_FS is not set -# CONFIG_SYSV_FS_WRITE is not set # CONFIG_UDF_FS is not set # CONFIG_UDF_RW is not set # CONFIG_UFS_FS is not set @@ -409,6 +417,11 @@ # USB support # # CONFIG_USB is not set + +# +# Bluetooth support +# +# CONFIG_BLUEZ is not set # # Kernel hacking diff -u --recursive --new-file v2.4.6/linux/arch/ppc/configs/gemini_defconfig linux/arch/ppc/configs/gemini_defconfig --- v2.4.6/linux/arch/ppc/configs/gemini_defconfig Mon May 21 17:04:46 2001 +++ linux/arch/ppc/configs/gemini_defconfig Wed Jul 18 07:14:01 2001 @@ -28,8 +28,8 @@ # CONFIG_8xx is not set # CONFIG_8260 is not set # CONFIG_ALL_PPC is not set -CONFIG_GEMINI=y # CONFIG_APUS is not set +CONFIG_GEMINI=y # CONFIG_PPC601_SYNC_FIX is not set # CONFIG_SMP is not set CONFIG_ALTIVEC=y @@ -258,23 +258,27 @@ # CONFIG_EQUALIZER is not set # CONFIG_TUN is not set # CONFIG_ETHERTAP is not set -# CONFIG_NET_SB1000 is not set # # Ethernet (10 or 100Mbit) # CONFIG_NET_ETHERNET=y +# CONFIG_ARM_AM79C961A is not set # CONFIG_MACE is not set # CONFIG_BMAC is not set # CONFIG_GMAC is not set CONFIG_NCR885E=y # CONFIG_OAKNET is not set +# CONFIG_SUNLANCE is not set +# CONFIG_HAPPYMEAL is not set +# CONFIG_SUNBMAC is not set +# CONFIG_SUNQE is not set +# CONFIG_SUNLANCE is not set +# CONFIG_SUNGEM is not set # CONFIG_NET_VENDOR_3COM is not set # CONFIG_LANCE is not set # CONFIG_NET_VENDOR_SMC is not set # CONFIG_NET_VENDOR_RACAL is not set -# CONFIG_AT1700 is not set -# CONFIG_DEPCA is not set # CONFIG_HP100 is not set # CONFIG_NET_ISA is not set # CONFIG_NET_PCI is not set @@ -284,11 +288,14 @@ # Ethernet (1000 Mbit) # # CONFIG_ACENIC is not set +# CONFIG_ACENIC_OMIT_TIGON_I is not set +# CONFIG_MYRI_SBUS is not set # CONFIG_HAMACHI is not set # CONFIG_YELLOWFIN is not set # CONFIG_SK98LIN is not set # CONFIG_FDDI is not set # CONFIG_HIPPI is not set +# CONFIG_PLIP is not set # CONFIG_PPP is not set # CONFIG_SLIP is not set @@ -392,6 +399,7 @@ # CONFIG_DTLK is not set # CONFIG_R3964 is not set # CONFIG_APPLICOM is not set +# CONFIG_SONYPI is not set # # Ftape, the floppy tape device driver @@ -430,6 +438,7 @@ CONFIG_ISO9660_FS=y # CONFIG_JOLIET is not set # CONFIG_MINIX_FS is not set +# CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set @@ -443,7 +452,6 @@ # CONFIG_ROMFS_FS is not set CONFIG_EXT2_FS=y # CONFIG_SYSV_FS is not set -# CONFIG_SYSV_FS_WRITE is not set # CONFIG_UDF_FS is not set # CONFIG_UDF_RW is not set # CONFIG_UFS_FS is not set @@ -500,6 +508,11 @@ # USB support # # CONFIG_USB is not set + +# +# Bluetooth support +# +# CONFIG_BLUEZ is not set # # Kernel hacking diff -u --recursive --new-file v2.4.6/linux/arch/ppc/configs/ibmchrp_defconfig linux/arch/ppc/configs/ibmchrp_defconfig --- v2.4.6/linux/arch/ppc/configs/ibmchrp_defconfig Wed May 16 09:57:20 2001 +++ linux/arch/ppc/configs/ibmchrp_defconfig Wed Jul 18 07:14:01 2001 @@ -28,8 +28,8 @@ # CONFIG_8xx is not set # CONFIG_8260 is not set CONFIG_ALL_PPC=y -# CONFIG_GEMINI is not set # CONFIG_APUS is not set +# CONFIG_GEMINI is not set # CONFIG_PPC601_SYNC_FIX is not set # CONFIG_SMP is not set # CONFIG_ALTIVEC is not set @@ -286,23 +286,27 @@ # CONFIG_EQUALIZER is not set # CONFIG_TUN is not set # CONFIG_ETHERTAP is not set -# CONFIG_NET_SB1000 is not set # # Ethernet (10 or 100Mbit) # CONFIG_NET_ETHERNET=y +# CONFIG_ARM_AM79C961A is not set # CONFIG_MACE is not set # CONFIG_BMAC is not set # CONFIG_GMAC is not set # CONFIG_NCR885E is not set # CONFIG_OAKNET is not set +# CONFIG_SUNLANCE is not set +# CONFIG_HAPPYMEAL is not set +# CONFIG_SUNBMAC is not set +# CONFIG_SUNQE is not set +# CONFIG_SUNLANCE is not set +# CONFIG_SUNGEM is not set # CONFIG_NET_VENDOR_3COM is not set # CONFIG_LANCE is not set # CONFIG_NET_VENDOR_SMC is not set # CONFIG_NET_VENDOR_RACAL is not set -# CONFIG_AT1700 is not set -# CONFIG_DEPCA is not set # CONFIG_HP100 is not set # CONFIG_NET_ISA is not set CONFIG_NET_PCI=y @@ -311,12 +315,14 @@ # CONFIG_APRICOT is not set # CONFIG_CS89x0 is not set # CONFIG_TULIP is not set +# CONFIG_TULIP_MWI is not set +# CONFIG_TULIP_MMIO is not set CONFIG_DE4X5=y # CONFIG_DGRS is not set # CONFIG_DM9102 is not set # CONFIG_EEPRO100 is not set -# CONFIG_EEPRO100_PM is not set # CONFIG_LNE390 is not set +# CONFIG_FEALNX is not set # CONFIG_NATSEMI is not set # CONFIG_NE2K_PCI is not set # CONFIG_NE3210 is not set @@ -331,18 +337,20 @@ # CONFIG_TLAN is not set # CONFIG_VIA_RHINE is not set # CONFIG_WINBOND_840 is not set -# CONFIG_HAPPYMEAL is not set # CONFIG_NET_POCKET is not set # # Ethernet (1000 Mbit) # # CONFIG_ACENIC is not set +# CONFIG_ACENIC_OMIT_TIGON_I is not set +# CONFIG_MYRI_SBUS is not set # CONFIG_HAMACHI is not set # CONFIG_YELLOWFIN is not set # CONFIG_SK98LIN is not set # CONFIG_FDDI is not set # CONFIG_HIPPI is not set +# CONFIG_PLIP is not set # CONFIG_PPP is not set # CONFIG_SLIP is not set @@ -507,6 +515,7 @@ # CONFIG_DTLK is not set # CONFIG_R3964 is not set # CONFIG_APPLICOM is not set +# CONFIG_SONYPI is not set # # Ftape, the floppy tape device driver @@ -545,6 +554,7 @@ CONFIG_ISO9660_FS=y # CONFIG_JOLIET is not set # CONFIG_MINIX_FS is not set +# CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set @@ -558,7 +568,6 @@ # CONFIG_ROMFS_FS is not set CONFIG_EXT2_FS=y # CONFIG_SYSV_FS is not set -# CONFIG_SYSV_FS_WRITE is not set # CONFIG_UDF_FS is not set # CONFIG_UDF_RW is not set # CONFIG_UFS_FS is not set @@ -656,6 +665,11 @@ # USB support # # CONFIG_USB is not set + +# +# Bluetooth support +# +# CONFIG_BLUEZ is not set # # Kernel hacking diff -u --recursive --new-file v2.4.6/linux/arch/ppc/configs/mbx_defconfig linux/arch/ppc/configs/mbx_defconfig --- v2.4.6/linux/arch/ppc/configs/mbx_defconfig Mon May 21 17:04:46 2001 +++ linux/arch/ppc/configs/mbx_defconfig Wed Jul 18 07:14:01 2001 @@ -118,6 +118,7 @@ # CONFIG_IP_MULTICAST is not set # CONFIG_IP_ADVANCED_ROUTER is not set CONFIG_IP_PNP=y +# CONFIG_IP_PNP_DHCP is not set CONFIG_IP_PNP_BOOTP=y # CONFIG_IP_PNP_RARP is not set # CONFIG_NET_IPIP is not set @@ -174,23 +175,26 @@ # CONFIG_BONDING is not set # CONFIG_EQUALIZER is not set # CONFIG_TUN is not set -# CONFIG_NET_SB1000 is not set # # Ethernet (10 or 100Mbit) # CONFIG_NET_ETHERNET=y +# CONFIG_ARM_AM79C961A is not set # CONFIG_MACE is not set # CONFIG_BMAC is not set # CONFIG_GMAC is not set # CONFIG_NCR885E is not set # CONFIG_OAKNET is not set +# CONFIG_SUNLANCE is not set +# CONFIG_SUNBMAC is not set +# CONFIG_SUNQE is not set +# CONFIG_SUNLANCE is not set +# CONFIG_SUNGEM is not set # CONFIG_NET_VENDOR_3COM is not set # CONFIG_LANCE is not set # CONFIG_NET_VENDOR_SMC is not set # CONFIG_NET_VENDOR_RACAL is not set -# CONFIG_AT1700 is not set -# CONFIG_DEPCA is not set # CONFIG_NET_ISA is not set # CONFIG_NET_PCI is not set # CONFIG_NET_POCKET is not set @@ -199,11 +203,14 @@ # Ethernet (1000 Mbit) # # CONFIG_ACENIC is not set +# CONFIG_ACENIC_OMIT_TIGON_I is not set +# CONFIG_MYRI_SBUS is not set # CONFIG_HAMACHI is not set # CONFIG_YELLOWFIN is not set # CONFIG_SK98LIN is not set # CONFIG_FDDI is not set # CONFIG_HIPPI is not set +# CONFIG_PLIP is not set # CONFIG_PPP is not set # CONFIG_SLIP is not set @@ -303,6 +310,7 @@ # CONFIG_DTLK is not set # CONFIG_R3964 is not set # CONFIG_APPLICOM is not set +# CONFIG_SONYPI is not set # # Ftape, the floppy tape device driver @@ -341,6 +349,7 @@ # CONFIG_ISO9660_FS is not set # CONFIG_JOLIET is not set # CONFIG_MINIX_FS is not set +# CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set @@ -354,7 +363,6 @@ # CONFIG_ROMFS_FS is not set CONFIG_EXT2_FS=y # CONFIG_SYSV_FS is not set -# CONFIG_SYSV_FS_WRITE is not set # CONFIG_UDF_FS is not set # CONFIG_UDF_RW is not set # CONFIG_UFS_FS is not set @@ -427,6 +435,11 @@ # USB support # # CONFIG_USB is not set + +# +# Bluetooth support +# +# CONFIG_BLUEZ is not set # # Kernel hacking diff -u --recursive --new-file v2.4.6/linux/arch/ppc/configs/oak_defconfig linux/arch/ppc/configs/oak_defconfig --- v2.4.6/linux/arch/ppc/configs/oak_defconfig Mon May 21 17:04:46 2001 +++ linux/arch/ppc/configs/oak_defconfig Wed Jul 18 07:14:01 2001 @@ -106,6 +106,7 @@ CONFIG_IP_MULTICAST=y # CONFIG_IP_ADVANCED_ROUTER is not set CONFIG_IP_PNP=y +# CONFIG_IP_PNP_DHCP is not set CONFIG_IP_PNP_BOOTP=y CONFIG_IP_PNP_RARP=y # CONFIG_NET_IPIP is not set @@ -163,23 +164,26 @@ # CONFIG_BONDING is not set # CONFIG_EQUALIZER is not set # CONFIG_TUN is not set -# CONFIG_NET_SB1000 is not set # # Ethernet (10 or 100Mbit) # CONFIG_NET_ETHERNET=y +# CONFIG_ARM_AM79C961A is not set # CONFIG_MACE is not set # CONFIG_BMAC is not set # CONFIG_GMAC is not set # CONFIG_NCR885E is not set CONFIG_OAKNET=y +# CONFIG_SUNLANCE is not set +# CONFIG_SUNBMAC is not set +# CONFIG_SUNQE is not set +# CONFIG_SUNLANCE is not set +# CONFIG_SUNGEM is not set # CONFIG_NET_VENDOR_3COM is not set # CONFIG_LANCE is not set # CONFIG_NET_VENDOR_SMC is not set # CONFIG_NET_VENDOR_RACAL is not set -# CONFIG_AT1700 is not set -# CONFIG_DEPCA is not set # CONFIG_NET_ISA is not set # CONFIG_NET_PCI is not set # CONFIG_NET_POCKET is not set @@ -188,11 +192,14 @@ # Ethernet (1000 Mbit) # # CONFIG_ACENIC is not set +# CONFIG_ACENIC_OMIT_TIGON_I is not set +# CONFIG_MYRI_SBUS is not set # CONFIG_HAMACHI is not set # CONFIG_YELLOWFIN is not set # CONFIG_SK98LIN is not set # CONFIG_FDDI is not set # CONFIG_HIPPI is not set +# CONFIG_PLIP is not set # CONFIG_PPP is not set # CONFIG_SLIP is not set @@ -293,6 +300,7 @@ # CONFIG_DTLK is not set # CONFIG_R3964 is not set # CONFIG_APPLICOM is not set +# CONFIG_SONYPI is not set # # Ftape, the floppy tape device driver @@ -331,6 +339,7 @@ # CONFIG_ISO9660_FS is not set # CONFIG_JOLIET is not set # CONFIG_MINIX_FS is not set +# CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set @@ -344,7 +353,6 @@ # CONFIG_ROMFS_FS is not set CONFIG_EXT2_FS=y # CONFIG_SYSV_FS is not set -# CONFIG_SYSV_FS_WRITE is not set # CONFIG_UDF_FS is not set # CONFIG_UDF_RW is not set # CONFIG_UFS_FS is not set @@ -389,6 +397,11 @@ # USB support # # CONFIG_USB is not set + +# +# Bluetooth support +# +# CONFIG_BLUEZ is not set # # Kernel hacking diff -u --recursive --new-file v2.4.6/linux/arch/ppc/configs/power3_defconfig linux/arch/ppc/configs/power3_defconfig --- v2.4.6/linux/arch/ppc/configs/power3_defconfig Wed May 16 09:57:20 2001 +++ linux/arch/ppc/configs/power3_defconfig Wed Jul 18 07:14:01 2001 @@ -262,23 +262,27 @@ # CONFIG_EQUALIZER is not set # CONFIG_TUN is not set # CONFIG_ETHERTAP is not set -# CONFIG_NET_SB1000 is not set # # Ethernet (10 or 100Mbit) # CONFIG_NET_ETHERNET=y +# CONFIG_ARM_AM79C961A is not set # CONFIG_MACE is not set # CONFIG_BMAC is not set # CONFIG_GMAC is not set # CONFIG_NCR885E is not set # CONFIG_OAKNET is not set +# CONFIG_SUNLANCE is not set +# CONFIG_HAPPYMEAL is not set +# CONFIG_SUNBMAC is not set +# CONFIG_SUNQE is not set +# CONFIG_SUNLANCE is not set +# CONFIG_SUNGEM is not set # CONFIG_NET_VENDOR_3COM is not set # CONFIG_LANCE is not set # CONFIG_NET_VENDOR_SMC is not set # CONFIG_NET_VENDOR_RACAL is not set -# CONFIG_AT1700 is not set -# CONFIG_DEPCA is not set # CONFIG_HP100 is not set # CONFIG_NET_ISA is not set CONFIG_NET_PCI=y @@ -287,12 +291,14 @@ # CONFIG_APRICOT is not set # CONFIG_CS89x0 is not set # CONFIG_TULIP is not set +# CONFIG_TULIP_MWI is not set +# CONFIG_TULIP_MMIO is not set # CONFIG_DE4X5 is not set # CONFIG_DGRS is not set # CONFIG_DM9102 is not set # CONFIG_EEPRO100 is not set -# CONFIG_EEPRO100_PM is not set # CONFIG_LNE390 is not set +# CONFIG_FEALNX is not set # CONFIG_NATSEMI is not set # CONFIG_NE2K_PCI is not set # CONFIG_NE3210 is not set @@ -307,13 +313,14 @@ # CONFIG_TLAN is not set # CONFIG_VIA_RHINE is not set # CONFIG_WINBOND_840 is not set -# CONFIG_HAPPYMEAL is not set # CONFIG_NET_POCKET is not set # # Ethernet (1000 Mbit) # # CONFIG_ACENIC is not set +# CONFIG_ACENIC_OMIT_TIGON_I is not set +# CONFIG_MYRI_SBUS is not set # CONFIG_HAMACHI is not set # CONFIG_YELLOWFIN is not set # CONFIG_SK98LIN is not set @@ -493,6 +500,7 @@ # CONFIG_DTLK is not set # CONFIG_R3964 is not set # CONFIG_APPLICOM is not set +# CONFIG_SONYPI is not set # # Ftape, the floppy tape device driver @@ -531,6 +539,7 @@ CONFIG_ISO9660_FS=y CONFIG_JOLIET=y # CONFIG_MINIX_FS is not set +# CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set @@ -544,7 +553,6 @@ # CONFIG_ROMFS_FS is not set CONFIG_EXT2_FS=y # CONFIG_SYSV_FS is not set -# CONFIG_SYSV_FS_WRITE is not set # CONFIG_UDF_FS is not set # CONFIG_UDF_RW is not set # CONFIG_UFS_FS is not set @@ -641,6 +649,7 @@ # CONFIG_SOUND_MSNDCLAS is not set # CONFIG_SOUND_MSNDPIN is not set # CONFIG_SOUND_VIA82CXXX is not set +# CONFIG_MIDI_VIA82CXXX is not set CONFIG_SOUND_OSS=y CONFIG_SOUND_TRACEINIT=y # CONFIG_SOUND_DMAP is not set @@ -677,6 +686,11 @@ # USB support # # CONFIG_USB is not set + +# +# Bluetooth support +# +# CONFIG_BLUEZ is not set # # Kernel hacking diff -u --recursive --new-file v2.4.6/linux/arch/ppc/configs/rpxcllf_defconfig linux/arch/ppc/configs/rpxcllf_defconfig --- v2.4.6/linux/arch/ppc/configs/rpxcllf_defconfig Mon May 21 17:04:46 2001 +++ linux/arch/ppc/configs/rpxcllf_defconfig Wed Jul 18 07:14:01 2001 @@ -122,6 +122,7 @@ CONFIG_IP_MULTICAST=y # CONFIG_IP_ADVANCED_ROUTER is not set CONFIG_IP_PNP=y +# CONFIG_IP_PNP_DHCP is not set CONFIG_IP_PNP_BOOTP=y # CONFIG_IP_PNP_RARP is not set # CONFIG_NET_IPIP is not set @@ -180,23 +181,26 @@ # CONFIG_EQUALIZER is not set # CONFIG_TUN is not set # CONFIG_ETHERTAP is not set -# CONFIG_NET_SB1000 is not set # # Ethernet (10 or 100Mbit) # CONFIG_NET_ETHERNET=y +# CONFIG_ARM_AM79C961A is not set # CONFIG_MACE is not set # CONFIG_BMAC is not set # CONFIG_GMAC is not set # CONFIG_NCR885E is not set # CONFIG_OAKNET is not set +# CONFIG_SUNLANCE is not set +# CONFIG_SUNBMAC is not set +# CONFIG_SUNQE is not set +# CONFIG_SUNLANCE is not set +# CONFIG_SUNGEM is not set # CONFIG_NET_VENDOR_3COM is not set # CONFIG_LANCE is not set # CONFIG_NET_VENDOR_SMC is not set # CONFIG_NET_VENDOR_RACAL is not set -# CONFIG_AT1700 is not set -# CONFIG_DEPCA is not set # CONFIG_NET_ISA is not set # CONFIG_NET_PCI is not set # CONFIG_NET_POCKET is not set @@ -205,11 +209,14 @@ # Ethernet (1000 Mbit) # # CONFIG_ACENIC is not set +# CONFIG_ACENIC_OMIT_TIGON_I is not set +# CONFIG_MYRI_SBUS is not set # CONFIG_HAMACHI is not set # CONFIG_YELLOWFIN is not set # CONFIG_SK98LIN is not set # CONFIG_FDDI is not set # CONFIG_HIPPI is not set +# CONFIG_PLIP is not set # CONFIG_PPP is not set # CONFIG_SLIP is not set @@ -310,6 +317,7 @@ # CONFIG_DTLK is not set # CONFIG_R3964 is not set # CONFIG_APPLICOM is not set +# CONFIG_SONYPI is not set # # Ftape, the floppy tape device driver @@ -348,6 +356,7 @@ # CONFIG_ISO9660_FS is not set # CONFIG_JOLIET is not set # CONFIG_MINIX_FS is not set +# CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set @@ -361,7 +370,6 @@ # CONFIG_ROMFS_FS is not set CONFIG_EXT2_FS=y # CONFIG_SYSV_FS is not set -# CONFIG_SYSV_FS_WRITE is not set # CONFIG_UDF_FS is not set # CONFIG_UDF_RW is not set # CONFIG_UFS_FS is not set @@ -435,6 +443,11 @@ # USB support # # CONFIG_USB is not set + +# +# Bluetooth support +# +# CONFIG_BLUEZ is not set # # Kernel hacking diff -u --recursive --new-file v2.4.6/linux/arch/ppc/configs/rpxlite_defconfig linux/arch/ppc/configs/rpxlite_defconfig --- v2.4.6/linux/arch/ppc/configs/rpxlite_defconfig Mon May 21 17:04:46 2001 +++ linux/arch/ppc/configs/rpxlite_defconfig Wed Jul 18 07:14:01 2001 @@ -122,6 +122,7 @@ CONFIG_IP_MULTICAST=y # CONFIG_IP_ADVANCED_ROUTER is not set CONFIG_IP_PNP=y +# CONFIG_IP_PNP_DHCP is not set CONFIG_IP_PNP_BOOTP=y # CONFIG_IP_PNP_RARP is not set # CONFIG_NET_IPIP is not set @@ -180,23 +181,26 @@ # CONFIG_EQUALIZER is not set # CONFIG_TUN is not set # CONFIG_ETHERTAP is not set -# CONFIG_NET_SB1000 is not set # # Ethernet (10 or 100Mbit) # CONFIG_NET_ETHERNET=y +# CONFIG_ARM_AM79C961A is not set # CONFIG_MACE is not set # CONFIG_BMAC is not set # CONFIG_GMAC is not set # CONFIG_NCR885E is not set # CONFIG_OAKNET is not set +# CONFIG_SUNLANCE is not set +# CONFIG_SUNBMAC is not set +# CONFIG_SUNQE is not set +# CONFIG_SUNLANCE is not set +# CONFIG_SUNGEM is not set # CONFIG_NET_VENDOR_3COM is not set # CONFIG_LANCE is not set # CONFIG_NET_VENDOR_SMC is not set # CONFIG_NET_VENDOR_RACAL is not set -# CONFIG_AT1700 is not set -# CONFIG_DEPCA is not set # CONFIG_NET_ISA is not set # CONFIG_NET_PCI is not set # CONFIG_NET_POCKET is not set @@ -205,11 +209,14 @@ # Ethernet (1000 Mbit) # # CONFIG_ACENIC is not set +# CONFIG_ACENIC_OMIT_TIGON_I is not set +# CONFIG_MYRI_SBUS is not set # CONFIG_HAMACHI is not set # CONFIG_YELLOWFIN is not set # CONFIG_SK98LIN is not set # CONFIG_FDDI is not set # CONFIG_HIPPI is not set +# CONFIG_PLIP is not set # CONFIG_PPP is not set # CONFIG_SLIP is not set @@ -310,6 +317,7 @@ # CONFIG_DTLK is not set # CONFIG_R3964 is not set # CONFIG_APPLICOM is not set +# CONFIG_SONYPI is not set # # Ftape, the floppy tape device driver @@ -348,6 +356,7 @@ # CONFIG_ISO9660_FS is not set # CONFIG_JOLIET is not set # CONFIG_MINIX_FS is not set +# CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set @@ -361,7 +370,6 @@ # CONFIG_ROMFS_FS is not set CONFIG_EXT2_FS=y # CONFIG_SYSV_FS is not set -# CONFIG_SYSV_FS_WRITE is not set # CONFIG_UDF_FS is not set # CONFIG_UDF_RW is not set # CONFIG_UFS_FS is not set @@ -432,6 +440,11 @@ # USB support # # CONFIG_USB is not set + +# +# Bluetooth support +# +# CONFIG_BLUEZ is not set # # Kernel hacking diff -u --recursive --new-file v2.4.6/linux/arch/ppc/configs/walnut_defconfig linux/arch/ppc/configs/walnut_defconfig --- v2.4.6/linux/arch/ppc/configs/walnut_defconfig Mon May 21 17:04:46 2001 +++ linux/arch/ppc/configs/walnut_defconfig Wed Jul 18 07:14:01 2001 @@ -106,6 +106,7 @@ CONFIG_IP_MULTICAST=y # CONFIG_IP_ADVANCED_ROUTER is not set CONFIG_IP_PNP=y +# CONFIG_IP_PNP_DHCP is not set CONFIG_IP_PNP_BOOTP=y CONFIG_IP_PNP_RARP=y # CONFIG_NET_IPIP is not set @@ -163,23 +164,26 @@ # CONFIG_BONDING is not set # CONFIG_EQUALIZER is not set # CONFIG_TUN is not set -# CONFIG_NET_SB1000 is not set # # Ethernet (10 or 100Mbit) # CONFIG_NET_ETHERNET=y +# CONFIG_ARM_AM79C961A is not set # CONFIG_MACE is not set # CONFIG_BMAC is not set # CONFIG_GMAC is not set # CONFIG_NCR885E is not set # CONFIG_OAKNET is not set +# CONFIG_SUNLANCE is not set +# CONFIG_SUNBMAC is not set +# CONFIG_SUNQE is not set +# CONFIG_SUNLANCE is not set +# CONFIG_SUNGEM is not set # CONFIG_NET_VENDOR_3COM is not set # CONFIG_LANCE is not set # CONFIG_NET_VENDOR_SMC is not set # CONFIG_NET_VENDOR_RACAL is not set -# CONFIG_AT1700 is not set -# CONFIG_DEPCA is not set # CONFIG_NET_ISA is not set # CONFIG_NET_PCI is not set # CONFIG_NET_POCKET is not set @@ -188,11 +192,14 @@ # Ethernet (1000 Mbit) # # CONFIG_ACENIC is not set +# CONFIG_ACENIC_OMIT_TIGON_I is not set +# CONFIG_MYRI_SBUS is not set # CONFIG_HAMACHI is not set # CONFIG_YELLOWFIN is not set # CONFIG_SK98LIN is not set # CONFIG_FDDI is not set # CONFIG_HIPPI is not set +# CONFIG_PLIP is not set # CONFIG_PPP is not set # CONFIG_SLIP is not set @@ -296,6 +303,7 @@ # CONFIG_DTLK is not set # CONFIG_R3964 is not set # CONFIG_APPLICOM is not set +# CONFIG_SONYPI is not set # # Ftape, the floppy tape device driver @@ -334,6 +342,7 @@ # CONFIG_ISO9660_FS is not set # CONFIG_JOLIET is not set # CONFIG_MINIX_FS is not set +# CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set @@ -347,7 +356,6 @@ # CONFIG_ROMFS_FS is not set CONFIG_EXT2_FS=y # CONFIG_SYSV_FS is not set -# CONFIG_SYSV_FS_WRITE is not set # CONFIG_UDF_FS is not set # CONFIG_UDF_RW is not set # CONFIG_UFS_FS is not set @@ -392,6 +400,11 @@ # USB support # # CONFIG_USB is not set + +# +# Bluetooth support +# +# CONFIG_BLUEZ is not set # # Kernel hacking diff -u --recursive --new-file v2.4.6/linux/arch/ppc/defconfig linux/arch/ppc/defconfig --- v2.4.6/linux/arch/ppc/defconfig Wed May 16 09:57:20 2001 +++ linux/arch/ppc/defconfig Wed Jul 18 07:14:01 2001 @@ -28,8 +28,8 @@ # CONFIG_8xx is not set # CONFIG_8260 is not set CONFIG_ALL_PPC=y -# CONFIG_GEMINI is not set # CONFIG_APUS is not set +# CONFIG_GEMINI is not set CONFIG_PPC601_SYNC_FIX=y # CONFIG_SMP is not set CONFIG_ALTIVEC=y @@ -299,10 +299,14 @@ # CONFIG_SCSI_AHA152X is not set # CONFIG_SCSI_AHA1542 is not set # CONFIG_SCSI_AHA1740 is not set -CONFIG_SCSI_AIC7XXX=y +CONFIG_SCSI_AIC7XXX=m CONFIG_AIC7XXX_CMDS_PER_DEVICE=253 CONFIG_AIC7XXX_RESET_DELAY_MS=15000 -# CONFIG_SCSI_AIC7XXX_OLD is not set +# CONFIG_AIC7XXX_BUILD_FIRMWARE is not set +CONFIG_SCSI_AIC7XXX_OLD=m +# CONFIG_AIC7XXX_OLD_TCQ_ON_BY_DEFAULT is not set +CONFIG_AIC7XXX_OLD_CMDS_PER_DEVICE=8 +CONFIG_AIC7XXX_OLD_PROC_STATS=y # CONFIG_SCSI_ADVANSYS is not set # CONFIG_SCSI_IN2000 is not set # CONFIG_SCSI_AM53C974 is not set @@ -372,24 +376,28 @@ # CONFIG_EQUALIZER is not set # CONFIG_TUN is not set # CONFIG_ETHERTAP is not set -# CONFIG_NET_SB1000 is not set # # Ethernet (10 or 100Mbit) # CONFIG_NET_ETHERNET=y +# CONFIG_ARM_AM79C961A is not set CONFIG_MACE=y # CONFIG_MACE_AAUI_PORT is not set CONFIG_BMAC=y CONFIG_GMAC=y # CONFIG_NCR885E is not set # CONFIG_OAKNET is not set +# CONFIG_SUNLANCE is not set +# CONFIG_HAPPYMEAL is not set +# CONFIG_SUNBMAC is not set +# CONFIG_SUNQE is not set +# CONFIG_SUNLANCE is not set +# CONFIG_SUNGEM is not set # CONFIG_NET_VENDOR_3COM is not set # CONFIG_LANCE is not set # CONFIG_NET_VENDOR_SMC is not set # CONFIG_NET_VENDOR_RACAL is not set -# CONFIG_AT1700 is not set -# CONFIG_DEPCA is not set # CONFIG_HP100 is not set # CONFIG_NET_ISA is not set CONFIG_NET_PCI=y @@ -398,12 +406,14 @@ # CONFIG_APRICOT is not set # CONFIG_CS89x0 is not set CONFIG_TULIP=y +# CONFIG_TULIP_MWI is not set +CONFIG_TULIP_MMIO=y CONFIG_DE4X5=m # CONFIG_DGRS is not set # CONFIG_DM9102 is not set # CONFIG_EEPRO100 is not set -# CONFIG_EEPRO100_PM is not set # CONFIG_LNE390 is not set +# CONFIG_FEALNX is not set # CONFIG_NATSEMI is not set # CONFIG_NE2K_PCI is not set # CONFIG_NE3210 is not set @@ -418,18 +428,20 @@ # CONFIG_TLAN is not set # CONFIG_VIA_RHINE is not set # CONFIG_WINBOND_840 is not set -# CONFIG_HAPPYMEAL is not set # CONFIG_NET_POCKET is not set # # Ethernet (1000 Mbit) # # CONFIG_ACENIC is not set +# CONFIG_ACENIC_OMIT_TIGON_I is not set +# CONFIG_MYRI_SBUS is not set # CONFIG_HAMACHI is not set # CONFIG_YELLOWFIN is not set # CONFIG_SK98LIN is not set # CONFIG_FDDI is not set # CONFIG_HIPPI is not set +# CONFIG_PLIP is not set CONFIG_PPP=y CONFIG_PPP_MULTILINK=y # CONFIG_PPP_FILTER is not set @@ -603,6 +615,7 @@ # CONFIG_DTLK is not set # CONFIG_R3964 is not set # CONFIG_APPLICOM is not set +# CONFIG_SONYPI is not set # # Ftape, the floppy tape device driver @@ -641,6 +654,7 @@ CONFIG_ISO9660_FS=y # CONFIG_JOLIET is not set # CONFIG_MINIX_FS is not set +# CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set @@ -654,7 +668,6 @@ # CONFIG_ROMFS_FS is not set CONFIG_EXT2_FS=y # CONFIG_SYSV_FS is not set -# CONFIG_SYSV_FS_WRITE is not set # CONFIG_UDF_FS is not set # CONFIG_UDF_RW is not set # CONFIG_UFS_FS is not set @@ -764,6 +777,7 @@ # CONFIG_SOUND_MSNDCLAS is not set # CONFIG_SOUND_MSNDPIN is not set # CONFIG_SOUND_VIA82CXXX is not set +# CONFIG_MIDI_VIA82CXXX is not set # CONFIG_SOUND_OSS is not set # CONFIG_SOUND_TVMIXER is not set @@ -814,6 +828,8 @@ # # CONFIG_USB_IBMCAM is not set # CONFIG_USB_OV511 is not set +# CONFIG_USB_PWC is not set +# CONFIG_USB_SE401 is not set # CONFIG_USB_DSBR is not set # CONFIG_USB_DABUSB is not set @@ -822,6 +838,7 @@ # # CONFIG_USB_PLUSB is not set # CONFIG_USB_PEGASUS is not set +# CONFIG_USB_CATC is not set # CONFIG_USB_NET1080 is not set # @@ -844,12 +861,19 @@ # CONFIG_USB_SERIAL_KEYSPAN_PDA is not set # CONFIG_USB_SERIAL_KEYSPAN is not set # CONFIG_USB_SERIAL_MCT_U232 is not set +# CONFIG_USB_SERIAL_PL2303 is not set +# CONFIG_USB_SERIAL_CYBERJACK is not set # CONFIG_USB_SERIAL_OMNINET is not set # # USB misc drivers # # CONFIG_USB_RIO500 is not set + +# +# Bluetooth support +# +# CONFIG_BLUEZ is not set # # Kernel hacking diff -u --recursive --new-file v2.4.6/linux/arch/ppc/kernel/Makefile linux/arch/ppc/kernel/Makefile --- v2.4.6/linux/arch/ppc/kernel/Makefile Tue Jul 3 17:08:18 2001 +++ linux/arch/ppc/kernel/Makefile Wed Jul 18 07:14:01 2001 @@ -1,4 +1,4 @@ -# BK Id: SCCS/s.Makefile 1.22 06/28/01 08:01:06 trini +# BK Id: SCCS/s.Makefile 1.24 07/10/01 12:12:22 trini # # # Makefile for the linux kernel. @@ -76,9 +76,11 @@ include $(TOPDIR)/Rules.make entry.o: entry.S ppc_defs.h +misc.o: misc.S ppc_defs.h head.o: head.S ppc_defs.h head_4xx.o: head_4xx.S ppc_defs.h head_8xx.o: head_8xx.S ppc_defs.h +gemini_prom.o: gemini_prom.S ppc_defs.h ppc_defs.h: mk_defs.c ppc_defs.head \ $(TOPDIR)/include/asm/mmu.h \ diff -u --recursive --new-file v2.4.6/linux/arch/ppc/kernel/chrp_setup.c linux/arch/ppc/kernel/chrp_setup.c --- v2.4.6/linux/arch/ppc/kernel/chrp_setup.c Tue Jul 3 17:08:18 2001 +++ linux/arch/ppc/kernel/chrp_setup.c Wed Jul 18 07:14:01 2001 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.chrp_setup.c 1.20 06/05/01 21:22:02 paulus + * BK Id: SCCS/s.chrp_setup.c 1.22 07/18/01 22:56:39 paulus */ /* * linux/arch/ppc/kernel/setup.c @@ -96,8 +96,6 @@ extern unsigned long loops_per_jiffy; extern int bootx_text_mapped; static int max_width; - -unsigned long empty_zero_page[1024]; static const char *gg2_memtypes[4] = { "FPM", "SDRAM", "EDO", "BEDO" diff -u --recursive --new-file v2.4.6/linux/arch/ppc/kernel/entry.S linux/arch/ppc/kernel/entry.S --- v2.4.6/linux/arch/ppc/kernel/entry.S Tue Jul 3 17:08:18 2001 +++ linux/arch/ppc/kernel/entry.S Thu Jul 19 09:39:44 2001 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.entry.S 1.17 06/19/01 22:40:51 paulus + * BK Id: SCCS/s.entry.S 1.20 07/19/01 23:02:48 paulus */ /* * PowerPC version @@ -191,15 +191,15 @@ * state of one is saved on its kernel stack. Then the state * of the other is restored from its kernel stack. The memory * management hardware is updated to the second process's state. - * Finally, we can return to the second process, via ret_from_except. + * Finally, we can return to the second process. * On entry, r3 points to the THREAD for the current task, r4 * points to the THREAD for the new task. * * Note: there are two ways to get to the "going out" portion * of this code; either by coming in via the entry (_switch) * or via "fork" which must set up an environment equivalent - * to the "_switch" path. If you change this (or in particular, the - * SAVE_REGS macro), you'll have to change the fork code also. + * to the "_switch" path. If you change this , you'll have to + * change the fork code also. * * The code which creates the new task context is in 'copy_thread' * in arch/ppc/kernel/process.c @@ -220,6 +220,8 @@ oris r0,r0,MSR_VEC@h #endif /* CONFIG_ALTIVEC */ andc r22,r22,r0 + mtmsr r22 + isync stw r20,_NIP(r1) stw r22,_MSR(r1) stw r20,_LINK(r1) @@ -232,6 +234,7 @@ li r0,0x0ff0 stw r0,TRAP(r1) stw r1,KSP(r3) /* Set old stack pointer */ + tophys(r0,r4) CLR_TOP32(r0) mtspr SPRG3,r0 /* Update current THREAD phys addr */ @@ -254,51 +257,24 @@ /* save the old current 'last' for return value */ mr r3,r2 addi r2,r4,-THREAD /* Update current */ - lwz r9,_MSR(r1) /* Returning to user mode? */ - andi. r9,r9,MSR_PR - beq+ 10f /* if not, don't adjust kernel stack */ -8: addi r4,r1,INT_FRAME_SIZE /* size of frame */ - stw r4,THREAD+KSP(r2) /* save kernel stack pointer */ - tophys(r9,r1) - CLR_TOP32(r9) - mtspr SPRG2,r9 /* phys exception stack pointer */ -10: lwz r2,_CTR(r1) - lwz r0,_LINK(r1) - mtctr r2 - mtlr r0 - lwz r2,_XER(r1) lwz r0,_CCR(r1) - mtspr XER,r2 mtcrf 0xFF,r0 /* r3-r13 are destroyed -- Cort */ - REST_GPR(14, r1) - REST_8GPRS(15, r1) - REST_8GPRS(23, r1) - REST_GPR(31, r1) - lwz r2,_NIP(r1) /* Restore environment */ - /* - * We need to hard disable here even if RTL is active since - * being interrupted after here trashes SRR{0,1} - * -- Cort - */ - mfmsr r0 /* Get current interrupt state */ - rlwinm r0,r0,0,17,15 /* clear MSR_EE in r0 */ - SYNC /* Some chip revs have problems here... */ - mtmsr r0 /* Update machine state */ - - lwz r0,_MSR(r1) - mtspr SRR0,r2 - FIX_SRR1(r0,r2) - mtspr SRR1,r0 - lwz r0,GPR0(r1) - lwz r2,GPR2(r1) - lwz r1,GPR1(r1) - SYNC - RFI + REST_2GPRS(14, r1) + REST_8GPRS(16, r1) + REST_8GPRS(24, r1) + + lwz r4,_NIP(r1) /* Return to _switch caller in new task */ + mtlr r4 + addi r1,r1,INT_FRAME_SIZE + blr .globl ret_from_fork ret_from_fork: bl schedule_tail + lwz r0,TASK_PTRACE(r2) + andi. r0,r0,PT_TRACESYS + bnel- syscall_trace b ret_from_except .globl ret_from_intercept diff -u --recursive --new-file v2.4.6/linux/arch/ppc/kernel/head.S linux/arch/ppc/kernel/head.S --- v2.4.6/linux/arch/ppc/kernel/head.S Tue Jul 3 17:08:18 2001 +++ linux/arch/ppc/kernel/head.S Thu Jul 19 09:39:44 2001 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.head.S 1.23 06/28/01 15:50:16 paulus + * BK Id: SCCS/s.head.S 1.25 07/07/01 17:08:44 paulus */ /* * PowerPC version @@ -1307,6 +1307,7 @@ mtspr SPRG3,r4 li r3,0 mtspr SPRG2,r3 /* 0 => r1 has kernel sp */ + stw r3,PT_REGS(r4) /* set thread.regs to 0 for kernel thread */ /* enable MMU and jump to start_secondary */ li r4,MSR_KERNEL diff -u --recursive --new-file v2.4.6/linux/arch/ppc/kernel/irq.c linux/arch/ppc/kernel/irq.c --- v2.4.6/linux/arch/ppc/kernel/irq.c Tue Jul 3 17:08:18 2001 +++ linux/arch/ppc/kernel/irq.c Thu Jul 19 09:40:04 2001 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.irq.c 1.28 06/28/01 16:15:56 paulus + * BK Id: SCCS/s.irq.c 1.30 07/19/01 16:51:32 paulus */ /* * arch/ppc/kernel/irq.c @@ -65,8 +65,8 @@ #include "local_irq.h" -atomic_t ipi_recv; -atomic_t ipi_sent; +extern atomic_t ipi_recv; +extern atomic_t ipi_sent; void enable_irq(unsigned int irq_nr); void disable_irq(unsigned int irq_nr); diff -u --recursive --new-file v2.4.6/linux/arch/ppc/kernel/m8260_setup.c linux/arch/ppc/kernel/m8260_setup.c --- v2.4.6/linux/arch/ppc/kernel/m8260_setup.c Mon May 21 17:04:47 2001 +++ linux/arch/ppc/kernel/m8260_setup.c Wed Jul 18 07:14:01 2001 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.m8260_setup.c 1.15 05/17/01 18:14:21 cort + * BK Id: SCCS/s.m8260_setup.c 1.20 07/18/01 22:56:39 paulus */ /* * linux/arch/ppc/kernel/setup.c @@ -66,7 +66,6 @@ extern unsigned long loops_per_jiffy; unsigned char __res[sizeof(bd_t)]; -unsigned long empty_zero_page[1024]; extern char saved_command_line[256]; diff -u --recursive --new-file v2.4.6/linux/arch/ppc/kernel/m8xx_setup.c linux/arch/ppc/kernel/m8xx_setup.c --- v2.4.6/linux/arch/ppc/kernel/m8xx_setup.c Tue Jul 3 17:08:18 2001 +++ linux/arch/ppc/kernel/m8xx_setup.c Wed Jul 18 07:14:01 2001 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.m8xx_setup.c 1.20 06/27/01 14:49:58 trini + * BK Id: SCCS/s.m8xx_setup.c 1.23 07/18/01 22:56:39 paulus */ /* * linux/arch/ppc/kernel/setup.c @@ -54,7 +54,6 @@ void m8xx_calibrate_decr(void); unsigned char __res[sizeof(bd_t)]; -unsigned long empty_zero_page[1024]; #if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) #ifdef CONFIG_BLK_DEV_MPC8xx_IDE @@ -261,7 +260,7 @@ return(0); } -unsigned long __init +unsigned long m8xx_get_rtc_time(void) { /* Get time from the RTC. diff -u --recursive --new-file v2.4.6/linux/arch/ppc/kernel/misc.S linux/arch/ppc/kernel/misc.S --- v2.4.6/linux/arch/ppc/kernel/misc.S Tue Jul 3 17:08:18 2001 +++ linux/arch/ppc/kernel/misc.S Thu Jul 19 09:39:44 2001 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.misc.S 1.19 06/15/01 13:56:56 paulus + * BK Id: SCCS/s.misc.S 1.21 07/07/01 17:00:08 paulus */ /* * This file contains miscellaneous low-level functions. @@ -1093,6 +1093,8 @@ bnelr /* return if parent */ li r0,0 /* clear out p->thread.regs */ stw r0,THREAD+PT_REGS(r2) /* since we don't have user ctx */ + addi r1,r2,TASK_UNION_SIZE-STACK_FRAME_OVERHEAD + stw r0,0(r1) mtlr r6 /* fn addr in lr */ mr r3,r4 /* load arg and call fn */ blrl diff -u --recursive --new-file v2.4.6/linux/arch/ppc/kernel/pmac_pci.c linux/arch/ppc/kernel/pmac_pci.c --- v2.4.6/linux/arch/ppc/kernel/pmac_pci.c Tue Jul 3 17:08:18 2001 +++ linux/arch/ppc/kernel/pmac_pci.c Wed Jul 4 11:50:39 2001 @@ -249,7 +249,7 @@ out_le32(bp->cfg_addr, (1UL << BANDIT_DEVNUM) + PCI_VENDOR_ID); udelay(2); vendev = in_le32((volatile unsigned int *)bp->cfg_data); - if (vendev == (PCI_VENDOR_ID_APPLE_BANDIT << 16) + + if (vendev == (PCI_DEVICE_ID_APPLE_BANDIT << 16) + PCI_VENDOR_ID_APPLE) { /* read the revision id */ out_le32(bp->cfg_addr, diff -u --recursive --new-file v2.4.6/linux/arch/ppc/kernel/ppc_asm.h linux/arch/ppc/kernel/ppc_asm.h --- v2.4.6/linux/arch/ppc/kernel/ppc_asm.h Mon May 21 17:04:47 2001 +++ linux/arch/ppc/kernel/ppc_asm.h Thu Jul 19 09:39:44 2001 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.ppc_asm.h 1.10 05/17/01 18:14:21 cort + * BK Id: SCCS/s.ppc_asm.h 1.14 07/02/01 22:08:05 paulus */ /* * arch/ppc/kernel/ppc_asm.h @@ -76,6 +76,14 @@ #else #define SYNC #endif + +#ifndef CONFIG_SMP +#define TLBSYNC +#else /* CONFIG_SMP */ +#define TLBSYNC \ + tlbsync; \ + sync +#endif /* CONFIG_SMP */ /* * This instruction is not implemented on the PPC 603 or 601; however, on diff -u --recursive --new-file v2.4.6/linux/arch/ppc/kernel/prep_setup.c linux/arch/ppc/kernel/prep_setup.c --- v2.4.6/linux/arch/ppc/kernel/prep_setup.c Mon May 21 17:04:47 2001 +++ linux/arch/ppc/kernel/prep_setup.c Wed Jul 18 07:14:01 2001 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.prep_setup.c 1.20 05/21/01 09:19:50 trini + * BK Id: SCCS/s.prep_setup.c 1.23 07/18/01 22:56:39 paulus */ /* * linux/arch/ppc/kernel/setup.c @@ -99,7 +99,6 @@ kdev_t boot_dev; /* used in nasty hack for sound - see prep_setup_arch() -- Cort */ long ppc_cs4232_dma, ppc_cs4232_dma2; -unsigned long empty_zero_page[1024]; extern PTE *Hash, *Hash_end; extern unsigned long Hash_size, Hash_mask; diff -u --recursive --new-file v2.4.6/linux/arch/ppc/kernel/process.c linux/arch/ppc/kernel/process.c --- v2.4.6/linux/arch/ppc/kernel/process.c Tue Jul 3 17:08:18 2001 +++ linux/arch/ppc/kernel/process.c Thu Jul 19 09:39:44 2001 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.process.c 1.19 06/15/01 13:56:56 paulus + * BK Id: SCCS/s.process.c 1.23 07/19/01 23:02:48 paulus */ /* * linux/arch/ppc/kernel/process.c @@ -62,8 +62,8 @@ char *sysmap = NULL; unsigned long sysmap_size = 0; -#undef SHOW_TASK_SWITCHES 1 -#undef CHECK_STACK 1 +#undef SHOW_TASK_SWITCHES +#undef CHECK_STACK #if defined(CHECK_STACK) unsigned long @@ -163,7 +163,6 @@ #else giveup_altivec(last_task_used_altivec); #endif /* __SMP __ */ - printk("MSR_VEC in enable_altivec_kernel\n"); } #endif /* CONFIG_ALTIVEC */ @@ -203,12 +202,6 @@ check_stack(new); #endif -#ifdef SHOW_TASK_SWITCHES - printk("%s/%d -> %s/%d NIP %08lx cpu %d root %x/%x\n", - prev->comm,prev->pid, - new->comm,new->pid,new->thread.regs->nip,new->processor, - new->fs->root,prev->fs->root); -#endif #ifdef CONFIG_SMP /* avoid complexity of lazy save/restore of fpu * by just saving it every time we switch out if @@ -241,7 +234,7 @@ /* Avoid the trap. On smp this this never happens since * we don't set last_task_used_altivec -- Cort */ - if ( last_task_used_altivec == new ) + if (new->thread.regs && last_task_used_altivec == new) new->thread.regs->msr |= MSR_VEC; new_thread = &new->thread; old_thread = ¤t->thread; @@ -329,39 +322,42 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long usp, unsigned long unused, - struct task_struct * p, struct pt_regs * regs) + struct task_struct *p, struct pt_regs *regs) { unsigned long msr; - struct pt_regs * childregs, *kregs; + struct pt_regs *childregs, *kregs; extern void ret_from_fork(void); - + unsigned long sp = (unsigned long)p + sizeof(union task_union); + unsigned long childframe; + /* Copy registers */ - childregs = ((struct pt_regs *) - ((unsigned long)p + sizeof(union task_union) - - STACK_FRAME_OVERHEAD)) - 2; + sp -= sizeof(struct pt_regs); + childregs = (struct pt_regs *) sp; *childregs = *regs; - if ((childregs->msr & MSR_PR) == 0) - childregs->gpr[2] = (unsigned long) p; /* `current' in new task */ + if ((childregs->msr & MSR_PR) == 0) { + /* for kernel thread, set `current' and stackptr in new task */ + childregs->gpr[1] = sp + sizeof(struct pt_regs); + childregs->gpr[2] = (unsigned long) p; + } childregs->gpr[3] = 0; /* Result from fork() */ p->thread.regs = childregs; - p->thread.ksp = (unsigned long) childregs - STACK_FRAME_OVERHEAD; - p->thread.ksp -= sizeof(struct pt_regs ) + STACK_FRAME_OVERHEAD; - kregs = (struct pt_regs *)(p->thread.ksp + STACK_FRAME_OVERHEAD); + sp -= STACK_FRAME_OVERHEAD; + childframe = sp; + + /* + * The way this works is that at some point in the future + * some task will call _switch to switch to the new task. + * That will pop off the stack frame created below and start + * the new task running at ret_from_fork. The new task will + * do some house keeping and then return from the fork or clone + * system call, using the stack frame created above. + */ + sp -= sizeof(struct pt_regs); + kregs = (struct pt_regs *) sp; + sp -= STACK_FRAME_OVERHEAD; + p->thread.ksp = sp; kregs->nip = (unsigned long)ret_from_fork; - asm volatile("mfmsr %0" : "=r" (msr):); - kregs->msr = msr; - kregs->gpr[1] = (unsigned long)childregs - STACK_FRAME_OVERHEAD; - kregs->gpr[2] = (unsigned long)p; - - if (usp >= (unsigned long) regs) { - /* Stack is in kernel space - must adjust */ - childregs->gpr[1] = (unsigned long)(childregs + 1); - } else { - /* Provided stack is in user space */ - childregs->gpr[1] = usp; - } - p->thread.last_syscall = -1; - + /* * copy fpu info - assume lazy fpu switch now always * -- Cort @@ -379,12 +375,13 @@ */ if (regs->msr & MSR_VEC) giveup_altivec(current); - memcpy(&p->thread.vr, ¤t->thread.vr, sizeof(p->thread.vr)); p->thread.vscr = current->thread.vscr; childregs->msr &= ~MSR_VEC; #endif /* CONFIG_ALTIVEC */ + p->thread.last_syscall = -1; + return 0; } @@ -394,6 +391,8 @@ void start_thread(struct pt_regs *regs, unsigned long nip, unsigned long sp) { set_fs(USER_DS); + memset(regs->gpr, 0, sizeof(regs->gpr)); + memset(®s->ctr, 0, 5 * sizeof(regs->ctr)); regs->nip = nip; regs->gpr[1] = sp; regs->msr = MSR_USER; @@ -407,38 +406,13 @@ int sys_clone(int p1, int p2, int p3, int p4, int p5, int p6, struct pt_regs *regs) { - unsigned long clone_flags = p1; - int res; - lock_kernel(); - res = do_fork(clone_flags, regs->gpr[1], regs, 0); -#ifdef CONFIG_SMP - /* When we clone the idle task we keep the same pid but - * the return value of 0 for both causes problems. - * -- Cort - */ - if ((current->pid == 0) && (current == &init_task)) - res = 1; -#endif /* CONFIG_SMP */ - unlock_kernel(); - return res; + return do_fork(p1, regs->gpr[1], regs, 0); } int sys_fork(int p1, int p2, int p3, int p4, int p5, int p6, struct pt_regs *regs) { - - int res; - - res = do_fork(SIGCHLD, regs->gpr[1], regs, 0); -#ifdef CONFIG_SMP - /* When we clone the idle task we keep the same pid but - * the return value of 0 for both causes problems. - * -- Cort - */ - if ((current->pid == 0) && (current == &init_task)) - res = 1; -#endif /* CONFIG_SMP */ - return res; + return do_fork(SIGCHLD, regs->gpr[1], regs, 0); } int sys_vfork(int p1, int p2, int p3, int p4, int p5, int p6, diff -u --recursive --new-file v2.4.6/linux/arch/ppc/kernel/prom.c linux/arch/ppc/kernel/prom.c --- v2.4.6/linux/arch/ppc/kernel/prom.c Tue Jul 3 17:08:18 2001 +++ linux/arch/ppc/kernel/prom.c Sun Jul 8 13:17:30 2001 @@ -116,8 +116,11 @@ unsigned int rtas_size; unsigned int old_rtas; -/* Set for a newworld machine */ +/* Set for a newworld or CHRP machine */ int use_of_interrupt_tree; +struct device_node *dflt_interrupt_controller; +int num_interrupt_controllers; + int pmac_newworld; static struct device_node *allnodes; @@ -1153,7 +1156,19 @@ *prev_propp = PTRUNRELOC(pp); prev_propp = &pp->next; } - *prev_propp = 0; + if (np->node != NULL) { + /* Add a "linux,phandle" property" */ + pp = (struct property *) mem_start; + *prev_propp = PTRUNRELOC(pp); + prev_propp = &pp->next; + namep = (char *) (pp + 1); + pp->name = PTRUNRELOC(namep); + strcpy(namep, RELOC("linux,phandle")); + mem_start = ALIGN((unsigned long)namep + strlen(namep) + 1); + pp->value = (unsigned char *) PTRUNRELOC(&np->node); + pp->length = sizeof(np->node); + } + *prev_propp = NULL; /* get the node's full name */ l = (int) call_prom(RELOC("package-to-path"), 3, 1, node, @@ -1186,19 +1201,46 @@ finish_device_tree(void) { unsigned long mem = (unsigned long) klimit; + struct device_node *np; - /* All newworld machines now use the interrupt tree */ - struct device_node *np = allnodes; - - while(np && (_machine == _MACH_Pmac)) { + /* All newworld pmac machines and CHRPs now use the interrupt tree */ + for (np = allnodes; np != NULL; np = np->allnext) { if (get_property(np, "interrupt-parent", 0)) { - pmac_newworld = 1; + use_of_interrupt_tree = 1; break; } - np = np->allnext; } - if ((_machine == _MACH_chrp) || (boot_infos == 0 && pmac_newworld)) - use_of_interrupt_tree = 1; + if (_machine == _MACH_Pmac && use_of_interrupt_tree) + pmac_newworld = 1; + +#ifdef CONFIG_BOOTX_TEXT + if (boot_infos && pmac_newworld) { + prom_print("WARNING ! BootX/miBoot booting is not supported on this machine\n"); + prom_print(" You should use an Open Firmware bootloader\n"); + } +#endif /* CONFIG_BOOTX_TEXT */ + + if (use_of_interrupt_tree) { + /* + * We want to find out here how many interrupt-controller + * nodes there are, and if we are booted from BootX, + * we need a pointer to the first (and hopefully only) + * such node. But we can't use find_devices here since + * np->name has not been set yet. -- paulus + */ + int n = 0; + char *name; + + for (np = allnodes; np != NULL; np = np->allnext) { + if ((name = get_property(np, "name", NULL)) == NULL + || strcmp(name, "interrupt-controller") != 0) + continue; + if (n == 0) + dflt_interrupt_controller = np; + ++n; + } + num_interrupt_controllers = n; + } mem = finish_node(allnodes, mem, NULL, 1, 1); dev_tree_size = mem - (unsigned long) allnodes; @@ -1240,9 +1282,8 @@ if (ifunc != NULL) { mem_start = ifunc(np, mem_start, naddrc, nsizec); } - if (use_of_interrupt_tree) { + if (use_of_interrupt_tree) mem_start = finish_node_interrupts(np, mem_start); - } /* Look for #address-cells and #size-cells properties. */ ip = (int *) get_property(np, "#address-cells", 0); @@ -1298,141 +1339,210 @@ return mem_start; } -/* This routine walks the interrupt tree for a given device node and gather - * all necessary informations according to the draft interrupt mapping - * for CHRP. The current version was only tested on Apple "Core99" machines - * and may not handle cascaded controllers correctly. +/* + * Find the interrupt parent of a node. + */ +static struct device_node *intr_parent(struct device_node *p) +{ + phandle *parp; + + parp = (phandle *) get_property(p, "interrupt-parent", NULL); + if (parp == NULL) + return p->parent; + p = find_phandle(*parp); + if (p != NULL) + return p; + /* + * On a powermac booted with BootX, we don't get to know the + * phandles for any nodes, so find_phandle will return NULL. + * Fortunately these machines only have one interrupt controller + * so there isn't in fact any ambiguity. -- paulus + */ + if (num_interrupt_controllers == 1) + p = dflt_interrupt_controller; + return p; +} + +/* + * Find out the size of each entry of the interrupts property + * for a node. */ -__init -static unsigned long -finish_node_interrupts(struct device_node *np, unsigned long mem_start) +static int +prom_n_intr_cells(struct device_node *np) { - /* Finish this node */ - unsigned int *isizep, *asizep, *interrupts, *map, *map_mask, *reg; - phandle *parent; - struct device_node *node, *parent_node; - int l, isize, ipsize, asize, map_size, regpsize; - - /* Currently, we don't look at all nodes with no "interrupts" property */ - interrupts = (unsigned int *)get_property(np, "interrupts", &l); - if (interrupts == NULL) - return mem_start; - ipsize = l>>2; + struct device_node *p; + unsigned int *icp; - reg = (unsigned int *)get_property(np, "reg", &l); - regpsize = l>>2; + for (p = np; (p = intr_parent(p)) != NULL; ) { + icp = (unsigned int *) + get_property(p, "#interrupt-cells", NULL); + if (icp != NULL) + return *icp; + if (get_property(p, "interrupt-controller", NULL) != NULL + || get_property(p, "interrupt-map", NULL) != NULL) { + printk("oops, node %s doesn't have #interrupt-cells\n", + p->full_name); + return 1; + } + } + printk("prom_n_intr_cells failed for %s\n", np->full_name); + return 1; +} - /* We assume default interrupt cell size is 1 (bugus ?) */ - isize = 1; - node = np; - - do { - /* We adjust the cell size if the current parent contains an #interrupt-cells - * property */ - isizep = (unsigned int *)get_property(node, "#interrupt-cells", &l); - if (isizep) - isize = *isizep; - - /* We don't do interrupt cascade (ISA) for now, we stop on the first - * controller found - */ - if (get_property(node, "interrupt-controller", &l)) { - int i,j; - int cvt_irq; - - /* XXX on chrp, offset interrupt numbers for the - 8259 by 0, those for the openpic by 16 */ - cvt_irq = _machine == _MACH_chrp - && get_property(node, "interrupt-parent", NULL) == 0; - np->intrs = (struct interrupt_info *) mem_start; - np->n_intrs = ipsize / isize; - mem_start += np->n_intrs * sizeof(struct interrupt_info); - for (i = 0; i < np->n_intrs; ++i) { - np->intrs[i].line = *interrupts++; - if (cvt_irq) - np->intrs[i].line = openpic_to_irq(np->intrs[i].line); - np->intrs[i].sense = 1; - if (isize > 1) - np->intrs[i].sense = *interrupts++; - for (j=2; j<isize; j++) - interrupts++; +/* + * Map an interrupt from a device up to the platform interrupt + * descriptor. + */ +static int +map_interrupt(unsigned int **irq, struct device_node **ictrler, + struct device_node *np, unsigned int *ints, int nintrc) +{ + struct device_node *p, *ipar; + unsigned int *imap, *imask, *ip; + int i, imaplen, match; + int newintrc, newaddrc; + unsigned int *reg; + int naddrc; + + reg = (unsigned int *) get_property(np, "reg", NULL); + naddrc = prom_n_addr_cells(np); + p = intr_parent(np); + while (p != NULL) { + if (get_property(p, "interrupt-controller", NULL) != NULL) + /* this node is an interrupt controller, stop here */ + break; + imap = (unsigned int *) + get_property(p, "interrupt-map", &imaplen); + if (imap == NULL) { + p = intr_parent(p); + continue; } + imask = (unsigned int *) + get_property(p, "interrupt-map-mask", NULL); + if (imask == NULL) { + printk("oops, %s has interrupt-map but no mask\n", + p->full_name); + return 0; + } + imaplen /= sizeof(unsigned int); + match = 0; + ipar = NULL; + while (imaplen > 0 && !match) { + /* check the child-interrupt field */ + match = 1; + for (i = 0; i < naddrc && match; ++i) + match = ((reg[i] ^ imap[i]) & imask[i]) == 0; + for (; i < naddrc + nintrc && match; ++i) + match = ((ints[i-naddrc] ^ imap[i]) & imask[i]) == 0; + imap += naddrc + nintrc; + imaplen -= naddrc + nintrc; + /* grab the interrupt parent */ + ipar = find_phandle((phandle) *imap++); + --imaplen; + if (ipar == NULL && num_interrupt_controllers == 1) + /* cope with BootX not giving us phandles */ + ipar = dflt_interrupt_controller; + if (ipar == NULL) { + printk("oops, no int parent %x in map of %s\n", + imap[-1], p->full_name); + return 0; + } + /* find the parent's # addr and intr cells */ + ip = (unsigned int *) + get_property(ipar, "#interrupt-cells", NULL); + if (ip == NULL) { + printk("oops, no #interrupt-cells on %s\n", + ipar->full_name); + return 0; + } + newintrc = *ip; + ip = (unsigned int *) + get_property(ipar, "#address-cells", NULL); + newaddrc = (ip == NULL)? 0: *ip; + imap += newaddrc + newintrc; + imaplen -= newaddrc + newintrc; + } + if (imaplen < 0) { + printk("oops, error decoding int-map on %s, len=%d\n", + p->full_name, imaplen); + return 0; + } + if (!match) { + printk("oops, no match in %s int-map for %s\n", + p->full_name, np->full_name); + return 0; + } + p = ipar; + naddrc = newaddrc; + nintrc = newintrc; + ints = imap - nintrc; + reg = ints - naddrc; + } + if (p == NULL) + printk("hmmm, int tree for %s doesn't have ctrler\n", + np->full_name); + *irq = ints; + *ictrler = p; + return nintrc; +} + +/* + * New version of finish_node_interrupts. + */ +static unsigned long +finish_node_interrupts(struct device_node *np, unsigned long mem_start) +{ + unsigned int *ints; + int intlen, intrcells; + int i, j, n, offset; + unsigned int *irq; + struct device_node *ic; + + ints = (unsigned int *) get_property(np, "interrupts", &intlen); + if (ints == NULL) return mem_start; - } - /* We lookup for an interrupt-map. This code can only handle one interrupt - * per device in the map. We also don't handle #address-cells in the parent - * I skip the pci node itself here, may not be necessary but I don't like it's - * reg property. - */ - if (np != node) - map = (unsigned int *)get_property(node, "interrupt-map", &l); - else - map = NULL; - if (map && l) { - int i, found, temp_isize; - map_size = l>>2; - map_mask = (unsigned int *)get_property(node, "interrupt-map-mask", &l); - asizep = (unsigned int *)get_property(node, "#address-cells", &l); - if (asizep && l == sizeof(unsigned int)) - asize = *asizep; - else - asize = 0; - found = 0; - while(map_size>0 && !found) { - found = 1; - for (i=0; i<asize; i++) { - unsigned int mask = map_mask ? map_mask[i] : 0xffffffff; - if (!reg || (i>=regpsize) || ((mask & *map) != (mask & reg[i]))) - found = 0; - map++; - map_size--; - } - for (i=0; i<isize; i++) { - unsigned int mask = map_mask ? map_mask[i+asize] : 0xffffffff; - if ((mask & *map) != (mask & interrupts[i])) - found = 0; - map++; - map_size--; - } - parent = *((phandle *)(map)); - map+=1; map_size-=1; - parent_node = find_phandle(parent); - temp_isize = isize; - if (parent_node) { - isizep = (unsigned int *)get_property(parent_node, "#interrupt-cells", &l); - if (isizep) - temp_isize = *isizep; - } - if (!found) { - map += temp_isize; - map_size-=temp_isize; - } - } - if (found) { - node = parent_node; - reg = NULL; - regpsize = 0; - interrupts = (unsigned int *)map; - ipsize = temp_isize*1; - continue; - } - } - /* We look for an explicit interrupt-parent. - */ - parent = (phandle *)get_property(node, "interrupt-parent", &l); - if (parent && (l == sizeof(phandle)) && - (parent_node = find_phandle(*parent))) { - node = parent_node; - continue; - } - /* Default, get real parent */ - node = node->parent; - } while(node); + intrcells = prom_n_intr_cells(np); + intlen /= intrcells * sizeof(unsigned int); + np->n_intrs = intlen; + np->intrs = (struct interrupt_info *) mem_start; + mem_start += intlen * sizeof(struct interrupt_info); + + for (i = 0; i < intlen; ++i) { + np->intrs[i].line = 0; + np->intrs[i].sense = 1; + n = map_interrupt(&irq, &ic, np, ints, intrcells); + if (n <= 0) + continue; + offset = 0; + /* + * On a CHRP we have an 8259 which is subordinate to + * the openpic in the interrupt tree, but we want the + * openpic's interrupt numbers offsetted, not the 8259's. + * So we apply the offset if the controller is at the + * root of the interrupt tree, i.e. has no interrupt-parent. + * This doesn't cope with the general case of multiple + * cascaded interrupt controllers, but then neither will + * irq.c at the moment either. -- paulus + */ + if (num_interrupt_controllers > 1 && ic != NULL + && get_property(ic, "interrupt-parent", NULL) == NULL) + offset = 16; + np->intrs[i].line = irq[0] + offset; + if (n > 1) + np->intrs[i].sense = irq[1]; + if (n > 2) { + printk("hmmm, got %d intr cells for %s:", n, + np->full_name); + for (j = 0; j < n; ++j) + printk(" %d", irq[j]); + printk("\n"); + } + ints += intrcells; + } return mem_start; } - /* * When BootX makes a copy of the device tree from the MacOS * Name Registry, it is in the format we use but all of the pointers @@ -1475,7 +1585,7 @@ ip = (int *) get_property(np, "#address-cells", 0); if (ip != NULL) return *ip; - } while(np->parent); + } while (np->parent); /* No #address-cells property for the root node, default to 1 */ return 1; } @@ -1490,7 +1600,7 @@ ip = (int *) get_property(np, "#size-cells", 0); if (ip != NULL) return *ip; - } while(np->parent); + } while (np->parent); /* No #size-cells property for the root node, default to 1 */ return 1; } @@ -1502,8 +1612,7 @@ { struct address_range *adr; struct pci_reg_property *pci_addrs; - int i, l, *ip, ml; - struct pci_intr_map *imp; + int i, l, *ip; pci_addrs = (struct pci_reg_property *) get_property(np, "assigned-addresses", &l); @@ -1525,44 +1634,6 @@ if (use_of_interrupt_tree) return mem_start; - /* - * If the pci host bridge has an interrupt-map property, - * look for our node in it. - */ - if (np->parent != 0 && pci_addrs != 0 - && (imp = (struct pci_intr_map *) - get_property(np->parent, "interrupt-map", &ml)) != 0 - && (ip = (int *) get_property(np, "interrupts", &l)) != 0) { - unsigned int devfn = pci_addrs[0].addr.a_hi & 0xff00; - unsigned int cell_size; - struct device_node* np2; - /* This is hackish, but is only used for BootX booting */ - cell_size = sizeof(struct pci_intr_map); - np2 = np->parent; - while(np2) { - if (device_is_compatible(np2, "uni-north")) { - cell_size += 4; - break; - } - np2 = np2->parent; - } - np->n_intrs = 0; - np->intrs = (struct interrupt_info *) mem_start; - for (i = 0; (ml -= cell_size) >= 0; ++i) { - if (imp->addr.a_hi == devfn) { - np->intrs[np->n_intrs].line = imp->intr; - np->intrs[np->n_intrs].sense = 1; /* FIXME */ - ++np->n_intrs; - } - imp = (struct pci_intr_map *)(((unsigned int)imp) - + cell_size); - } - if (np->n_intrs == 0) - np->intrs = 0; - mem_start += np->n_intrs * sizeof(struct interrupt_info); - return mem_start; - } - ip = (int *) get_property(np, "AAPL,interrupts", &l); if (ip == 0 && np->parent) ip = (int *) get_property(np->parent, "AAPL,interrupts", &l); @@ -1677,26 +1748,10 @@ ip = (int *) get_property(np, "AAPL,interrupts", &l); if (ip != 0) { np->intrs = (struct interrupt_info *) mem_start; - if (_machine == _MACH_Pmac) { - /* for the iMac */ - np->n_intrs = l / sizeof(int); - /* Hack for BootX on Core99 */ - if (keylargo) - np->n_intrs = np->n_intrs/2; - for (i = 0; i < np->n_intrs; ++i) { - np->intrs[i].line = *ip++; - if (keylargo) - np->intrs[i].sense = *ip++; - else - np->intrs[i].sense = 1; - } - } else { - /* CHRP machines */ - np->n_intrs = l / (2 * sizeof(int)); - for (i = 0; i < np->n_intrs; ++i) { - np->intrs[i].line = openpic_to_irq(*ip++); - np->intrs[i].sense = *ip++; - } + np->n_intrs = l / sizeof(int); + for (i = 0; i < np->n_intrs; ++i) { + np->intrs[i].line = *ip++; + np->intrs[i].sense = 1; } mem_start += np->n_intrs * sizeof(struct interrupt_info); } @@ -1978,13 +2033,12 @@ { struct property *pp; - for (pp = np->properties; pp != 0; pp = pp->next) { + for (pp = np->properties; pp != 0; pp = pp->next) if (pp->name != NULL && strcmp(pp->name, name) == 0) { if (lenp != 0) *lenp = pp->length; return pp->value; } - } return 0; } diff -u --recursive --new-file v2.4.6/linux/arch/ppc/kernel/ptrace.c linux/arch/ppc/kernel/ptrace.c --- v2.4.6/linux/arch/ppc/kernel/ptrace.c Mon May 21 17:04:47 2001 +++ linux/arch/ppc/kernel/ptrace.c Fri Jul 20 12:39:55 2001 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.ptrace.c 1.5 05/17/01 18:14:22 cort + * BK Id: SCCS/s.ptrace.c 1.8 07/07/01 17:00:08 paulus */ /* * linux/arch/ppc/kernel/ptrace.c @@ -49,7 +49,8 @@ */ static inline unsigned long get_reg(struct task_struct *task, int regno) { - if (regno < sizeof(struct pt_regs) / sizeof(unsigned long)) + if (regno < sizeof(struct pt_regs) / sizeof(unsigned long) + && task->thread.regs != NULL) return ((unsigned long *)task->thread.regs)[regno]; return (0); } @@ -60,7 +61,7 @@ static inline int put_reg(struct task_struct *task, int regno, unsigned long data) { - if (regno <= PT_MQ) { + if (regno <= PT_MQ && task->thread.regs != NULL) { if (regno == PT_MSR) data = (data & MSR_DEBUGCHANGE) | (task->thread.regs->msr & ~MSR_DEBUGCHANGE); @@ -74,14 +75,18 @@ set_single_step(struct task_struct *task) { struct pt_regs *regs = task->thread.regs; - regs->msr |= MSR_SE; + + if (regs != NULL) + regs->msr |= MSR_SE; } static inline void clear_single_step(struct task_struct *task) { struct pt_regs *regs = task->thread.regs; - regs->msr &= ~MSR_SE; + + if (regs != NULL) + regs->msr &= ~MSR_SE; } int sys_ptrace(long request, long pid, long addr, long data) @@ -113,33 +118,7 @@ goto out_tsk; if (request == PTRACE_ATTACH) { - if (child == current) - goto out_tsk; - if ((!child->dumpable || - (current->uid != child->euid) || - (current->uid != child->suid) || - (current->uid != child->uid) || - (current->gid != child->egid) || - (current->gid != child->sgid) || - (!cap_issubset(child->cap_permitted, current->cap_permitted)) || - (current->gid != child->gid)) - && !capable(CAP_SYS_PTRACE)) - goto out_tsk; - /* the same process cannot be attached many times */ - if (child->ptrace & PT_PTRACED) - goto out_tsk; - child->ptrace |= PT_PTRACED; - - write_lock_irq(&tasklist_lock); - if (child->p_pptr != current) { - REMOVE_LINKS(child); - child->p_pptr = current; - SET_LINKS(child); - } - write_unlock_irq(&tasklist_lock); - - send_sig(SIGSTOP, child, 1); - ret = 0; + ret = ptrace_attach(child); goto out_tsk; } ret = -ESRCH; @@ -181,7 +160,8 @@ if (index < PT_FPR0) { tmp = get_reg(child, (int) index); } else { - if (child->thread.regs->msr & MSR_FP) + if (child->thread.regs != NULL + && child->thread.regs->msr & MSR_FP) giveup_fpu(child); tmp = ((unsigned long *)child->thread.fpr)[index - PT_FPR0]; } @@ -214,7 +194,8 @@ if (index < PT_FPR0) { ret = put_reg(child, index, data); } else { - if (child->thread.regs->msr & MSR_FP) + if (child->thread.regs != NULL + && child->thread.regs->msr & MSR_FP) giveup_fpu(child); ((unsigned long *)child->thread.fpr)[index - PT_FPR0] = data; ret = 0; diff -u --recursive --new-file v2.4.6/linux/arch/s390/kernel/entry.S linux/arch/s390/kernel/entry.S --- v2.4.6/linux/arch/s390/kernel/entry.S Wed Apr 11 19:02:27 2001 +++ linux/arch/s390/kernel/entry.S Wed Jul 4 11:50:39 2001 @@ -668,7 +668,7 @@ la %r2,SP_PTREGS(%r15) # address of register-save area srl %r3,2 cl %r3,BASED(.Lc4) # protection-exception ? - bne BASED(pgm_go) # if not, + bne BASED(pgm_per) # if not, l %r5,SP_PSW+4(15) # load psw addr sr %r5,%r7 # substract ilc from psw st %r5,SP_PSW+4(15) # store corrected psw addr diff -u --recursive --new-file v2.4.6/linux/arch/s390/kernel/head.S linux/arch/s390/kernel/head.S --- v2.4.6/linux/arch/s390/kernel/head.S Wed Apr 11 19:02:27 2001 +++ linux/arch/s390/kernel/head.S Wed Jul 4 11:50:39 2001 @@ -262,8 +262,7 @@ la %r2,IPL_BS # load start address bas %r14,.Lloader # load rest of ipl image l %r12,.Lparm # pointer to parameter area - st %r1,__LC_IPLDEV # store ipl device number - st %r1,IPL_DEVICE-PARMAREA(%r12) + st %r1,IPL_DEVICE-PARMAREA(%r12) # store ipl device number # # load parameter file from ipl device @@ -463,7 +462,9 @@ startup:basr %r13,0 # get base .LPG1: lctl %c0,%c15,.Lctl-.LPG1(%r13) # load control registers l %r12,.Lparm1-.LPG1(%r13) # pointer to parameter area - + # move IPL device to lowcore + mvc __LC_IPLDEV(4),IPL_DEVICE-PARMAREA(%r12) + # # find out memory size. # diff -u --recursive --new-file v2.4.6/linux/arch/s390/kernel/irq.c linux/arch/s390/kernel/irq.c --- v2.4.6/linux/arch/s390/kernel/irq.c Wed Apr 11 19:02:27 2001 +++ linux/arch/s390/kernel/irq.c Wed Jul 4 11:50:39 2001 @@ -386,8 +386,11 @@ /* For now, nothing... */ } +#ifdef CONFIG_SMP EXPORT_SYMBOL(__global_cli); EXPORT_SYMBOL(__global_sti); EXPORT_SYMBOL(__global_save_flags); EXPORT_SYMBOL(__global_restore_flags); +#endif + EXPORT_SYMBOL(global_bh_lock); diff -u --recursive --new-file v2.4.6/linux/arch/s390/kernel/ptrace.c linux/arch/s390/kernel/ptrace.c --- v2.4.6/linux/arch/s390/kernel/ptrace.c Wed Apr 11 19:02:28 2001 +++ linux/arch/s390/kernel/ptrace.c Fri Jul 20 12:39:55 2001 @@ -233,31 +233,7 @@ goto out; if (request == PTRACE_ATTACH) { - if (child == current) - goto out; - if ((!child->dumpable || - (current->uid != child->euid) || - (current->uid != child->suid) || - (current->uid != child->uid) || - (current->gid != child->egid) || - (current->gid != child->sgid)) && !capable(CAP_SYS_PTRACE)) - goto out; - /* the same process cannot be attached many times */ - if (child->ptrace & PT_PTRACED) - goto out; - child->ptrace |= PT_PTRACED; - - write_lock_irqsave(&tasklist_lock, flags); - if (child->p_pptr != current) - { - REMOVE_LINKS(child); - child->p_pptr = current; - SET_LINKS(child); - } - write_unlock_irqrestore(&tasklist_lock, flags); - - send_sig(SIGSTOP, child, 1); - ret = 0; + ret = ptrace_attach(child); goto out; } ret = -ESRCH; diff -u --recursive --new-file v2.4.6/linux/arch/s390/kernel/reipl.S linux/arch/s390/kernel/reipl.S --- v2.4.6/linux/arch/s390/kernel/reipl.S Tue Feb 13 14:13:43 2001 +++ linux/arch/s390/kernel/reipl.S Wed Jul 4 11:50:39 2001 @@ -55,7 +55,7 @@ .Ldispsw: .long 0x000a0000,0x00000000 .Liplccws: .long 0x02000000,0x60000018 .long 0x08000008,0x20000001 -.Liplorb: .long 0x0049504c,0x0000ff80 +.Liplorb: .long 0x0049504c,0x0040ff80 .long 0x00000000+.Liplccws .Lschib: .long 0x00000000,0x00000000 .long 0x00000000,0x00000000 diff -u --recursive --new-file v2.4.6/linux/arch/s390/kernel/smp.c linux/arch/s390/kernel/smp.c --- v2.4.6/linux/arch/s390/kernel/smp.c Wed Apr 11 19:02:28 2001 +++ linux/arch/s390/kernel/smp.c Wed Jul 4 11:50:39 2001 @@ -420,6 +420,7 @@ void smp_ptlb_all(void) { smp_ext_call_others(smp_ptlb_callback, NULL, 1); + local_flush_tlb(); } /* @@ -522,8 +523,7 @@ */ { if (atomic_read(&smp_commenced) != 0) - smp_ext_call_others(func, info, 1); - (func)(info); + smp_ext_call_others(func, info, wait); return 0; } @@ -776,3 +776,4 @@ EXPORT_SYMBOL(kernel_flag); EXPORT_SYMBOL(smp_ctl_set_bit); EXPORT_SYMBOL(smp_ctl_clear_bit); +EXPORT_SYMBOL(smp_num_cpus); diff -u --recursive --new-file v2.4.6/linux/arch/s390x/kernel/entry.S linux/arch/s390x/kernel/entry.S --- v2.4.6/linux/arch/s390x/kernel/entry.S Wed Apr 11 19:02:29 2001 +++ linux/arch/s390x/kernel/entry.S Wed Jul 4 11:50:39 2001 @@ -632,8 +632,6 @@ * we just ignore the PER event (FIXME: is there anything we have to do * for LPSW?). */ - stmg %r14,%r15,__LC_SAVE_AREA - stam %a2,%a4,__LC_SAVE_AREA+16 tm __LC_PGM_INT_CODE+1,0x80 # check whether we got a per exception jz pgm_sv # skip if not tm __LC_PGM_OLD_PSW,0x40 # test if per event recording is on @@ -642,29 +640,10 @@ clc __LC_PGM_OLD_PSW(16),__LC_SVC_NEW_PSW je pgm_svcper # no interesting special case, ignore PER event - lm %r13,%r15,__LC_SAVE_AREA lpswe __LC_PGM_OLD_PSW # it was a single stepped SVC that is causing all the trouble pgm_svcper: - tm __LC_SVC_OLD_PSW+1,0x01 # test problem state bit - jz 0f # skip stack & access regs setup - lg %r15,__LC_KERNEL_STACK # problem state -> load ksp - slr %r14,%r14 - sar %a2,%r14 # set ac.reg. 2 to primary space - lhi %r14,1 - sar %a4,%r14 # and access reg. 4 to home space -0: aghi %r15,-SP_SIZE # make room for registers & psw - nill %r15,0xfff8 # align stack pointer to 8 - stmg %r0,%r14,SP_R0(%r15) # store gprs 0-14 to kernel stack - stg %r2,SP_ORIG_R2(%r15) # store original content of gpr 2 - mvc SP_R14(16,%r15),__LC_SAVE_AREA # move R14-R15 to stack - stam %a0,%a15,SP_AREGS(%r15) # store access registers to kst. - mvc SP_AREGS+8(12,%r15),__LC_SAVE_AREA+16 # store ac. regs - mvc SP_PSW(16,%r15),__LC_PGM_OLD_PSW # move user PSW to stack - lhi %r0,__LC_SVC_OLD_PSW # store trap indication - st %r0,SP_TRAP(%r15) - xc 0(8,%r15),0(%r15) # clear back chain - + SAVE_ALL __LC_SVC_OLD_PSW mvc SP_PGM_OLD_ILC(4,%r15),__LC_PGM_ILC # save program check information j pgm_system_call # now do the svc pgm_svcret: @@ -674,24 +653,7 @@ mvi SP_PGM_OLD_ILC(%r15),1 # mark PGM_OLD_ILC as invalid j pgm_no_sv pgm_sv: - tm __LC_PGM_OLD_PSW+1,0x01 # test problem state bit - jz 1f # skip stack setup save - lg %r15,__LC_KERNEL_STACK # problem state -> load ksp - slr %r14,%r14 - sar %a2,%r14 # set ac.reg. 2 to primary space - lhi %r14,1 - sar %a4,%r14 # set access reg. 4 to home space -1: aghi %r15,-SP_SIZE # make room for registers & psw - nill %r15,0xfff8 # align stack pointer to 8 - stmg %r0,%r14,SP_R0(%r15) # store gprs 0-14 to kernel stack - stg %r2,SP_ORIG_R2(%r15) # store original content of gpr 2 - mvc SP_R14(16,%r15),__LC_SAVE_AREA # move R14-R15 to stack - stam %a0,%a15,SP_AREGS(%r15) # store access registers to kst. - mvc SP_AREGS+8(12,%r15),__LC_SAVE_AREA+16 # store ac. regs - mvc SP_PSW(16,%r15),__LC_PGM_OLD_PSW # move user PSW to stack - lhi %r0,__LC_PGM_OLD_PSW # store trap indication - st %r0,SP_TRAP(%r15) - xc 0(8,%r15),0(%r15) # clear back chain + SAVE_ALL __LC_PGM_OLD_PSW mvi SP_PGM_OLD_ILC(%r15),1 # mark PGM_OLD_ILC as invalid llgh %r7,__LC_PGM_ILC # load instruction length GET_CURRENT @@ -823,8 +785,10 @@ .globl restart_int_handler restart_int_handler: lg %r15,__LC_KERNEL_STACK # load ksp - lctlg %c0,%c15,__LC_CREGS_SAVE_AREA # get new ctl regs - lam %a0,%a15,__LC_AREGS_SAVE_AREA + lhi %r10,__LC_CREGS_SAVE_AREA + lctlg %c0,%c15,0(%r10) # get new ctl regs + lhi %r10,__LC_AREGS_SAVE_AREA + lam %a0,%a15,0(%r10) stosm 0(%r15),0x04 # now we can turn dat on lmg %r6,%r15,48(%r15) # load registers from clone jg start_secondary diff -u --recursive --new-file v2.4.6/linux/arch/s390x/kernel/head.S linux/arch/s390x/kernel/head.S --- v2.4.6/linux/arch/s390x/kernel/head.S Wed Apr 11 19:02:29 2001 +++ linux/arch/s390x/kernel/head.S Wed Jul 4 11:50:39 2001 @@ -262,8 +262,7 @@ la %r2,IPL_BS # load start address bas %r14,.Lloader # load rest of ipl image l %r12,.Lparm # pointer to parameter area - st %r1,__LC_IPLDEV # store ipl device number - st %r1,IPL_DEVICE+4-PARMAREA(%r12) + st %r1,IPL_DEVICE+4-PARMAREA(%r12) # store ipl device number # # load parameter file from ipl device @@ -467,6 +466,8 @@ sam64 # switch to 64 bit mode lctlg %c0,%c15,.Lctl-.LPG1(%r13) # load control registers lg %r12,.Lparm1-.LPG1(%r13) # pointer to parameter area + # move IPL device to lowcore + mvc __LC_IPLDEV(4),IPL_DEVICE+4-PARMAREA(%r12) # # find out memory size. diff -u --recursive --new-file v2.4.6/linux/arch/s390x/kernel/irq.c linux/arch/s390x/kernel/irq.c --- v2.4.6/linux/arch/s390x/kernel/irq.c Wed Apr 11 19:02:29 2001 +++ linux/arch/s390x/kernel/irq.c Wed Jul 4 11:50:39 2001 @@ -380,8 +380,11 @@ /* For now, nothing... */ } +#ifdef CONFIG_SMP EXPORT_SYMBOL(__global_cli); EXPORT_SYMBOL(__global_sti); EXPORT_SYMBOL(__global_save_flags); EXPORT_SYMBOL(__global_restore_flags); +#endif + EXPORT_SYMBOL(global_bh_lock); diff -u --recursive --new-file v2.4.6/linux/arch/s390x/kernel/linux32.c linux/arch/s390x/kernel/linux32.c --- v2.4.6/linux/arch/s390x/kernel/linux32.c Thu Apr 26 14:10:16 2001 +++ linux/arch/s390x/kernel/linux32.c Wed Jul 4 11:50:39 2001 @@ -897,24 +897,24 @@ return sys32_fcntl(fd, cmd, arg); } -struct dqblk32 { - __u32 dqb_bhardlimit; - __u32 dqb_bsoftlimit; - __u32 dqb_curblocks; +struct mem_dqblk32 { __u32 dqb_ihardlimit; __u32 dqb_isoftlimit; __u32 dqb_curinodes; + __u32 dqb_bhardlimit; + __u32 dqb_bsoftlimit; + __u64 dqb_curspace; __kernel_time_t32 dqb_btime; __kernel_time_t32 dqb_itime; }; -extern asmlinkage int sys_quotactl(int cmd, const char *special, int id, caddr_t addr); +extern asmlinkage long sys_quotactl(int cmd, const char *special, int id, __kernel_caddr_t addr); asmlinkage int sys32_quotactl(int cmd, const char *special, int id, unsigned long addr) { int cmds = cmd >> SUBCMDSHIFT; int err; - struct dqblk d; + struct mem_dqblk d; mm_segment_t old_fs; char *spec; @@ -924,33 +924,35 @@ case Q_SETQUOTA: case Q_SETUSE: case Q_SETQLIM: - if (copy_from_user (&d, (struct dqblk32 *)addr, - sizeof (struct dqblk32))) + if (copy_from_user (&d, (struct mem_dqblk32 *)addr, + sizeof (struct mem_dqblk32))) return -EFAULT; - d.dqb_itime = ((struct dqblk32 *)&d)->dqb_itime; - d.dqb_btime = ((struct dqblk32 *)&d)->dqb_btime; + d.dqb_itime = ((struct mem_dqblk32 *)&d)->dqb_itime; + d.dqb_btime = ((struct mem_dqblk32 *)&d)->dqb_btime; break; default: return sys_quotactl(cmd, special, - id, (caddr_t)addr); + id, (__kernel_caddr_t)addr); } spec = getname (special); err = PTR_ERR(spec); if (IS_ERR(spec)) return err; old_fs = get_fs (); set_fs (KERNEL_DS); - err = sys_quotactl(cmd, (const char *)spec, id, (caddr_t)&d); + err = sys_quotactl(cmd, (const char *)spec, id, (__kernel_caddr_t)&d); set_fs (old_fs); putname (spec); + if (err) + return err; if (cmds == Q_GETQUOTA) { __kernel_time_t b = d.dqb_btime, i = d.dqb_itime; - ((struct dqblk32 *)&d)->dqb_itime = i; - ((struct dqblk32 *)&d)->dqb_btime = b; - if (copy_to_user ((struct dqblk32 *)addr, &d, - sizeof (struct dqblk32))) + ((struct mem_dqblk32 *)&d)->dqb_itime = i; + ((struct mem_dqblk32 *)&d)->dqb_btime = b; + if (copy_to_user ((struct mem_dqblk32 *)addr, &d, + sizeof (struct mem_dqblk32))) return -EFAULT; } - return err; + return 0; } static inline int put_statfs (struct statfs32 *ubuf, struct statfs *kbuf) diff -u --recursive --new-file v2.4.6/linux/arch/s390x/kernel/ptrace.c linux/arch/s390x/kernel/ptrace.c --- v2.4.6/linux/arch/s390x/kernel/ptrace.c Wed Apr 11 19:02:29 2001 +++ linux/arch/s390x/kernel/ptrace.c Fri Jul 20 12:39:55 2001 @@ -247,31 +247,7 @@ goto out; if (request == PTRACE_ATTACH) { - if (child == current) - goto out; - if ((!child->dumpable || - (current->uid != child->euid) || - (current->uid != child->suid) || - (current->uid != child->uid) || - (current->gid != child->egid) || - (current->gid != child->sgid)) && !capable(CAP_SYS_PTRACE)) - goto out; - /* the same process cannot be attached many times */ - if (child->ptrace & PT_PTRACED) - goto out; - child->ptrace |= PT_PTRACED; - - write_lock_irqsave(&tasklist_lock, flags); - if (child->p_pptr != current) - { - REMOVE_LINKS(child); - child->p_pptr = current; - SET_LINKS(child); - } - write_unlock_irqrestore(&tasklist_lock, flags); - - send_sig(SIGSTOP, child, 1); - ret = 0; + ret = ptrace_attach(child); goto out; } ret = -ESRCH; @@ -433,31 +409,7 @@ goto out; if (request == PTRACE_ATTACH) { - if (child == current) - goto out; - if ((!child->dumpable || - (current->uid != child->euid) || - (current->uid != child->suid) || - (current->uid != child->uid) || - (current->gid != child->egid) || - (current->gid != child->sgid)) && !capable(CAP_SYS_PTRACE)) - goto out; - /* the same process cannot be attached many times */ - if (child->ptrace & PT_PTRACED) - goto out; - child->ptrace |= PT_PTRACED; - - write_lock_irqsave(&tasklist_lock, flags); - if (child->p_pptr != current) - { - REMOVE_LINKS(child); - child->p_pptr = current; - SET_LINKS(child); - } - write_unlock_irqrestore(&tasklist_lock, flags); - - send_sig(SIGSTOP, child, 1); - ret = 0; + ret = ptrace_attach(child); goto out; } ret = -ESRCH; diff -u --recursive --new-file v2.4.6/linux/arch/s390x/kernel/reipl.S linux/arch/s390x/kernel/reipl.S --- v2.4.6/linux/arch/s390x/kernel/reipl.S Tue Feb 13 14:13:44 2001 +++ linux/arch/s390x/kernel/reipl.S Wed Jul 4 11:50:39 2001 @@ -73,7 +73,7 @@ .quad 0x0000000000000000 .Liplccws: .long 0x02000000,0x60000018 .long 0x08000008,0x20000001 -.Liplorb: .long 0x0049504c,0x0000ff80 +.Liplorb: .long 0x0049504c,0x0040ff80 .long 0x00000000+.Liplccws .Lschib: .long 0x00000000,0x00000000 .long 0x00000000,0x00000000 diff -u --recursive --new-file v2.4.6/linux/arch/s390x/kernel/smp.c linux/arch/s390x/kernel/smp.c --- v2.4.6/linux/arch/s390x/kernel/smp.c Wed Apr 11 19:02:29 2001 +++ linux/arch/s390x/kernel/smp.c Wed Jul 4 11:50:39 2001 @@ -510,8 +510,7 @@ */ { if (atomic_read(&smp_commenced) != 0) - smp_ext_call_others(func, info, 1); - (func)(info); + smp_ext_call_others(func, info, wait); return 0; } diff -u --recursive --new-file v2.4.6/linux/arch/s390x/mm/fault.c linux/arch/s390x/mm/fault.c --- v2.4.6/linux/arch/s390x/mm/fault.c Thu Apr 26 14:10:16 2001 +++ linux/arch/s390x/mm/fault.c Wed Jul 4 11:50:39 2001 @@ -33,6 +33,34 @@ extern void die(const char *,struct pt_regs *,long); +extern spinlock_t timerlist_lock; + +/* + * Unlock any spinlocks which will prevent us from getting the + * message out + */ +void bust_spinlocks(int yes) +{ + spin_lock_init(&timerlist_lock); + if (yes) { + oops_in_progress = 1; +#ifdef CONFIG_SMP + atomic_set(&global_irq_lock,0); +#endif + } else { + int loglevel_save = console_loglevel; + oops_in_progress = 0; + /* + * OK, the message is on the console. Now we call printk() + * without oops_in_progress set so that printk will give klogd + * a poke. Hold onto your hats... + */ + console_loglevel = 15; /* NMI oopser may have shut the console up */ + printk(" "); + console_loglevel = loglevel_save; + } +} + /* * This routine handles page faults. It determines the address, * and the problem, and then passes it off to one of the appropriate diff -u --recursive --new-file v2.4.6/linux/arch/sh/kernel/ptrace.c linux/arch/sh/kernel/ptrace.c --- v2.4.6/linux/arch/sh/kernel/ptrace.c Wed Apr 11 21:24:52 2001 +++ linux/arch/sh/kernel/ptrace.c Fri Jul 20 12:39:55 2001 @@ -173,34 +173,7 @@ goto out_tsk; if (request == PTRACE_ATTACH) { - if (child == tsk) - goto out_tsk; - if(((tsk->uid != child->euid) || - (tsk->uid != child->suid) || - (tsk->uid != child->uid) || - (tsk->gid != child->egid) || - (tsk->gid != child->sgid) || - (!cap_issubset(child->cap_permitted, tsk->cap_permitted)) || - (tsk->gid != child->gid)) && !capable(CAP_SYS_PTRACE)) - goto out_tsk; - rmb(); - if (!child->dumpable && !capable(CAP_SYS_PTRACE)) - goto out_tsk; - /* the same process cannot be attached many times */ - if (child->ptrace & PT_PTRACED) - goto out_tsk; - child->ptrace |= PT_PTRACED; - - write_lock_irq(&tasklist_lock); - if (child->p_pptr != tsk) { - REMOVE_LINKS(child); - child->p_pptr = tsk; - SET_LINKS(child); - } - write_unlock_irq(&tasklist_lock); - - send_sig(SIGSTOP, child, 1); - ret = 0; + ret = ptrace_attach(child); goto out_tsk; } ret = -ESRCH; diff -u --recursive --new-file v2.4.6/linux/arch/sparc/defconfig linux/arch/sparc/defconfig --- v2.4.6/linux/arch/sparc/defconfig Wed May 16 10:31:27 2001 +++ linux/arch/sparc/defconfig Thu Jul 19 18:11:13 2001 @@ -38,6 +38,8 @@ CONFIG_SUN_CONSOLE=y CONFIG_SUN_AUXIO=y CONFIG_SUN_IO=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set # CONFIG_SUN4 is not set # CONFIG_PCI is not set CONFIG_SUN_OPENPROMFS=m @@ -68,6 +70,7 @@ CONFIG_FB=y CONFIG_DUMMY_CONSOLE=y # CONFIG_FB_CYBER2000 is not set +# CONFIG_FB_E1355 is not set CONFIG_FB_SBUS=y CONFIG_FB_CGSIX=y CONFIG_FB_BWTWO=y @@ -194,7 +197,7 @@ CONFIG_BLK_DEV_SD=y CONFIG_SD_EXTRA_DEVS=40 CONFIG_CHR_DEV_ST=y -CONFIG_ST_EXTRA_DEVS=2 +# CONFIG_CHR_DEV_OSST is not set CONFIG_BLK_DEV_SR=y CONFIG_BLK_DEV_SR_VENDOR=y CONFIG_SR_EXTRA_DEVS=2 @@ -278,10 +281,12 @@ CONFIG_EFS_FS=m # CONFIG_JFFS_FS is not set # CONFIG_CRAMFS is not set +# CONFIG_TMPFS is not set # CONFIG_RAMFS is not set CONFIG_ISO9660_FS=m # CONFIG_JOLIET is not set CONFIG_MINIX_FS=m +# CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_RW is not set CONFIG_HPFS_FS=m @@ -295,7 +300,6 @@ CONFIG_ROMFS_FS=m CONFIG_EXT2_FS=y CONFIG_SYSV_FS=m -# CONFIG_SYSV_FS_WRITE is not set # CONFIG_UDF_FS is not set # CONFIG_UDF_RW is not set CONFIG_UFS_FS=m @@ -352,11 +356,13 @@ # CONFIG_NLS_CODEPAGE_865 is not set # CONFIG_NLS_CODEPAGE_866 is not set # CONFIG_NLS_CODEPAGE_869 is not set -# CONFIG_NLS_CODEPAGE_874 is not set -# CONFIG_NLS_CODEPAGE_932 is not set # CONFIG_NLS_CODEPAGE_936 is not set -# CONFIG_NLS_CODEPAGE_949 is not set # CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set # CONFIG_NLS_ISO8859_1 is not set # CONFIG_NLS_ISO8859_2 is not set # CONFIG_NLS_ISO8859_3 is not set @@ -364,12 +370,18 @@ # CONFIG_NLS_ISO8859_5 is not set # CONFIG_NLS_ISO8859_6 is not set # CONFIG_NLS_ISO8859_7 is not set -# CONFIG_NLS_ISO8859_8 is not set # CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set # CONFIG_NLS_ISO8859_14 is not set # CONFIG_NLS_ISO8859_15 is not set # CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set # CONFIG_NLS_UTF8 is not set + +# +# Bluetooth support +# +# CONFIG_BLUEZ is not set # # Watchdog diff -u --recursive --new-file v2.4.6/linux/arch/sparc/kernel/irq.c linux/arch/sparc/kernel/irq.c --- v2.4.6/linux/arch/sparc/kernel/irq.c Tue May 1 20:59:24 2001 +++ linux/arch/sparc/kernel/irq.c Thu Jul 19 18:11:13 2001 @@ -1,4 +1,4 @@ -/* $Id: irq.c,v 1.112 2001/04/27 07:02:42 davem Exp $ +/* $Id: irq.c,v 1.113 2001/07/17 16:17:33 anton Exp $ * arch/sparc/kernel/irq.c: Interrupt request handling routines. On the * Sparc the IRQ's are basically 'cast in stone' * and you are supposed to probe the prom's device @@ -424,6 +424,8 @@ } while (action); enable_pil_irq(irq); irq_exit(cpu, irq); + if (softirq_pending(cpu)) + do_softirq(); } #ifdef CONFIG_BLK_DEV_FD @@ -439,6 +441,8 @@ floppy_interrupt(irq, dev_id, regs); irq_exit(cpu, irq); enable_pil_irq(irq); + if (softirq_pending(cpu)) + do_softirq(); } #endif diff -u --recursive --new-file v2.4.6/linux/arch/sparc/kernel/ptrace.c linux/arch/sparc/kernel/ptrace.c --- v2.4.6/linux/arch/sparc/kernel/ptrace.c Sun Mar 25 18:14:21 2001 +++ linux/arch/sparc/kernel/ptrace.c Fri Jul 20 12:39:55 2001 @@ -320,38 +320,10 @@ || (current->personality != PER_SUNOS && request == PTRACE_ATTACH)) { unsigned long flags; - if(child == current) { - /* Try this under SunOS/Solaris, bwa haha - * You'll never be able to kill the process. ;-) - */ + if (ptrace_attach(child)) { pt_error_return(regs, EPERM); goto out_tsk; } - if((!child->dumpable || - (current->uid != child->euid) || - (current->uid != child->uid) || - (current->uid != child->suid) || - (current->gid != child->egid) || - (current->gid != child->sgid) || - (!cap_issubset(child->cap_permitted, current->cap_permitted)) || - (current->gid != child->gid)) && !capable(CAP_SYS_PTRACE)) { - pt_error_return(regs, EPERM); - goto out_tsk; - } - /* the same process cannot be attached many times */ - if (child->ptrace & PT_PTRACED) { - pt_error_return(regs, EPERM); - goto out_tsk; - } - child->ptrace |= PT_PTRACED; - write_lock_irqsave(&tasklist_lock, flags); - if(child->p_pptr != current) { - REMOVE_LINKS(child); - child->p_pptr = current; - SET_LINKS(child); - } - write_unlock_irqrestore(&tasklist_lock, flags); - send_sig(SIGSTOP, child, 1); pt_succ_return(regs, 0); goto out_tsk; } diff -u --recursive --new-file v2.4.6/linux/arch/sparc/kernel/rtrap.S linux/arch/sparc/kernel/rtrap.S --- v2.4.6/linux/arch/sparc/kernel/rtrap.S Tue Jul 3 17:08:19 2001 +++ linux/arch/sparc/kernel/rtrap.S Thu Jul 19 18:11:13 2001 @@ -1,4 +1,4 @@ -/* $Id: rtrap.S,v 1.56 2001/06/05 09:56:06 davem Exp $ +/* $Id: rtrap.S,v 1.57 2001/07/17 16:17:33 anton Exp $ * rtrap.S: Return from Sparc trap low-level code. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -48,17 +48,6 @@ .globl rtrap_patch3, rtrap_patch4, rtrap_patch5 .globl C_LABEL(ret_trap_lockless_ipi) ret_trap_entry: - ld [%curptr + AOFF_task_processor], %l3 - sll %l3, 5, %l3 - sethi %hi(C_LABEL(irq_stat)), %l4 ! &softirq_active - add %l4, %l3, %l4 - ld [%l4 + %lo(C_LABEL(irq_stat))], %g5 ! softirq_pending - cmp %g5, 0 - be C_LABEL(ret_trap_lockless_ipi) - nop - call C_LABEL(do_softirq) - nop - C_LABEL(ret_trap_lockless_ipi): andcc %t_psr, PSR_PS, %g0 be 1f diff -u --recursive --new-file v2.4.6/linux/arch/sparc/kernel/sparc_ksyms.c linux/arch/sparc/kernel/sparc_ksyms.c --- v2.4.6/linux/arch/sparc/kernel/sparc_ksyms.c Mon Jan 22 13:30:20 2001 +++ linux/arch/sparc/kernel/sparc_ksyms.c Thu Jul 19 18:11:13 2001 @@ -1,4 +1,4 @@ -/* $Id: sparc_ksyms.c,v 1.106 2001/01/11 15:07:09 davem Exp $ +/* $Id: sparc_ksyms.c,v 1.107 2001/07/17 16:17:33 anton Exp $ * arch/sparc/kernel/ksyms.c: Sparc specific ksyms support. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -116,11 +116,6 @@ EXPORT_SYMBOL(__down); EXPORT_SYMBOL(__down_trylock); EXPORT_SYMBOL(__down_interruptible); -/* rw semaphores */ -EXPORT_SYMBOL_NOVERS(___down_read); -EXPORT_SYMBOL_NOVERS(___down_write); -EXPORT_SYMBOL_NOVERS(___up_read); -EXPORT_SYMBOL_NOVERS(___up_write); EXPORT_SYMBOL(sparc_valid_addr_bitmap); @@ -132,8 +127,6 @@ EXPORT_SYMBOL_PRIVATE(_set_bit); EXPORT_SYMBOL_PRIVATE(_clear_bit); EXPORT_SYMBOL_PRIVATE(_change_bit); -EXPORT_SYMBOL_PRIVATE(_set_le_bit); -EXPORT_SYMBOL_PRIVATE(_clear_le_bit); #ifdef CONFIG_SMP /* Kernel wide locking */ diff -u --recursive --new-file v2.4.6/linux/arch/sparc/kernel/sun4d_irq.c linux/arch/sparc/kernel/sun4d_irq.c --- v2.4.6/linux/arch/sparc/kernel/sun4d_irq.c Sun Feb 18 19:49:54 2001 +++ linux/arch/sparc/kernel/sun4d_irq.c Thu Jul 19 18:11:13 2001 @@ -1,4 +1,4 @@ -/* $Id: sun4d_irq.c,v 1.27 2001/02/13 01:16:43 davem Exp $ +/* $Id: sun4d_irq.c,v 1.28 2001/07/17 16:17:33 anton Exp $ * arch/sparc/kernel/sun4d_irq.c: * SS1000/SC2000 interrupt handling. * @@ -237,6 +237,8 @@ } } irq_exit(cpu, irq); + if (softirq_pending(cpu)) + do_softirq(); } unsigned int sun4d_build_irq(struct sbus_dev *sdev, int irq) diff -u --recursive --new-file v2.4.6/linux/arch/sparc/lib/bitops.S linux/arch/sparc/lib/bitops.S --- v2.4.6/linux/arch/sparc/lib/bitops.S Mon May 8 22:00:01 2000 +++ linux/arch/sparc/lib/bitops.S Thu Jul 19 18:11:13 2001 @@ -107,62 +107,5 @@ jmpl %o7, %g0 mov %g4, %o7 - /* Now the little endian versions. */ - .globl ___set_le_bit -___set_le_bit: - rd %psr, %g3 - nop; nop; nop - or %g3, PSR_PIL, %g5 - wr %g5, 0x0, %psr - nop; nop; nop -#ifdef CONFIG_SMP - set C_LABEL(bitops_spinlock), %g5 -2: ldstub [%g5], %g7 ! Spin on the byte lock for SMP. - orcc %g7, 0x0, %g0 ! Did we get it? - bne 2b ! Nope... -#endif - ldub [%g1], %g7 - or %g7, %g2, %g5 - and %g7, %g2, %g2 -#ifdef CONFIG_SMP - stb %g5, [%g1] - set C_LABEL(bitops_spinlock), %g5 - stb %g0, [%g5] -#else - stb %g5, [%g1] -#endif - wr %g3, 0x0, %psr - nop; nop; nop - jmpl %o7, %g0 - mov %g4, %o7 - - .globl ___clear_le_bit -___clear_le_bit: - rd %psr, %g3 - nop; nop; nop - or %g3, PSR_PIL, %g5 - wr %g5, 0x0, %psr - nop; nop; nop -#ifdef CONFIG_SMP - set C_LABEL(bitops_spinlock), %g5 -2: ldstub [%g5], %g7 ! Spin on the byte lock for SMP. - orcc %g7, 0x0, %g0 ! Did we get it? - bne 2b ! Nope... -#endif - ldub [%g1], %g7 - andn %g7, %g2, %g5 - and %g7, %g2, %g2 -#ifdef CONFIG_SMP - stb %g5, [%g1] - set C_LABEL(bitops_spinlock), %g5 - stb %g0, [%g5] -#else - stb %g5, [%g1] -#endif - wr %g3, 0x0, %psr - nop; nop; nop - jmpl %o7, %g0 - mov %g4, %o7 - .globl __bitops_end __bitops_end: diff -u --recursive --new-file v2.4.6/linux/arch/sparc/mm/generic.c linux/arch/sparc/mm/generic.c --- v2.4.6/linux/arch/sparc/mm/generic.c Thu Apr 12 12:10:25 2001 +++ linux/arch/sparc/mm/generic.c Thu Jul 19 18:11:13 2001 @@ -1,4 +1,4 @@ -/* $Id: generic.c,v 1.12 2001/04/09 21:40:46 davem Exp $ +/* $Id: generic.c,v 1.13 2001/07/17 16:17:33 anton Exp $ * generic.c: Generic Sparc mm routines that are not dependent upon * MMU type but are Sparc specific. * @@ -8,6 +8,7 @@ #include <linux/kernel.h> #include <linux/mm.h> #include <linux/swap.h> +#include <linux/pagemap.h> #include <asm/pgalloc.h> #include <asm/pgtable.h> @@ -64,12 +65,10 @@ end = PGDIR_SIZE; offset -= address; do { - pte_t * pte = pte_alloc(pmd, address); + pte_t * pte = pte_alloc(current->mm, pmd, address); if (!pte) return -ENOMEM; - spin_lock(¤t->mm->page_table_lock); io_remap_pte_range(pte, address, end - address, address + offset, prot, space); - spin_unlock(¤t->mm->page_table_lock); address = (address + PMD_SIZE) & PMD_MASK; pmd++; } while (address < end); @@ -82,13 +81,16 @@ pgd_t * dir; unsigned long beg = from; unsigned long end = from + size; + struct mm_struct *mm = current->mm; prot = __pgprot(pg_iobits); offset -= from; - dir = pgd_offset(current->mm, from); - flush_cache_range(current->mm, beg, end); + dir = pgd_offset(mm, from); + flush_cache_range(mm, beg, end); + + spin_lock(&mm->page_table_lock); while (from < end) { - pmd_t *pmd = pmd_alloc(dir, from); + pmd_t *pmd = pmd_alloc(current->mm, dir, from); error = -ENOMEM; if (!pmd) break; @@ -98,6 +100,8 @@ from = (from + PGDIR_SIZE) & PGDIR_MASK; dir++; } + spin_unlock(&mm->page_table_lock); + flush_tlb_range(current->mm, beg, end); return error; } diff -u --recursive --new-file v2.4.6/linux/arch/sparc/mm/init.c linux/arch/sparc/mm/init.c --- v2.4.6/linux/arch/sparc/mm/init.c Thu Apr 19 08:38:48 2001 +++ linux/arch/sparc/mm/init.c Thu Jul 19 18:11:13 2001 @@ -1,4 +1,4 @@ -/* $Id: init.c,v 1.98 2001/04/14 21:13:45 davem Exp $ +/* $Id: init.c,v 1.99 2001/07/17 16:17:33 anton Exp $ * linux/arch/sparc/mm/init.c * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -54,32 +54,6 @@ unsigned long highstart_pfn, highend_pfn; unsigned long totalram_pages; unsigned long totalhigh_pages; - -/* - * BAD_PAGE is the page that is used for page faults when linux - * is out-of-memory. Older versions of linux just did a - * do_exit(), but using this instead means there is less risk - * for a process dying in kernel mode, possibly leaving an inode - * unused etc.. - * - * BAD_PAGETABLE is the accompanying page-table: it is initialized - * to point to BAD_PAGE entries. - * - * ZERO_PAGE is a special page that is used for zero-initialized - * data and COW. - */ -pte_t *__bad_pagetable(void) -{ - memset((void *) &empty_bad_page_table, 0, PAGE_SIZE); - return (pte_t *) &empty_bad_page_table; -} - -pte_t __bad_page(void) -{ - memset((void *) &empty_bad_page, 0, PAGE_SIZE); - return pte_mkdirty(mk_pte_phys((unsigned long)__pa(&empty_bad_page) + phys_base, - PAGE_SHARED)); -} pte_t *kmap_pte; pgprot_t kmap_prot; diff -u --recursive --new-file v2.4.6/linux/arch/sparc/mm/srmmu.c linux/arch/sparc/mm/srmmu.c --- v2.4.6/linux/arch/sparc/mm/srmmu.c Thu Apr 19 08:38:48 2001 +++ linux/arch/sparc/mm/srmmu.c Thu Jul 19 18:11:13 2001 @@ -1,4 +1,4 @@ -/* $Id: srmmu.c,v 1.229 2001/04/14 21:13:45 davem Exp $ +/* $Id: srmmu.c,v 1.230 2001/07/17 16:17:33 anton Exp $ * srmmu.c: SRMMU specific routines for memory management. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -365,7 +365,7 @@ flush_tlb_all(); } -static inline pgd_t *srmmu_pgd_alloc(void) +static inline pgd_t *srmmu_get_pgd_fast(void) { pgd_t *pgd = NULL; @@ -380,100 +380,32 @@ return pgd; } -static void srmmu_pgd_free(pgd_t *pgd) +static void srmmu_free_pgd_fast(pgd_t *pgd) { srmmu_free_nocache((unsigned long)pgd, SRMMU_PGD_TABLE_SIZE); } -pmd_t *empty_bad_pmd_table; -pte_t *empty_bad_pte_table; - -/* - * We init them before every return and make them writable-shared. - * This guarantees we get out of the kernel in some more or less sane - * way. - */ -static pmd_t * get_bad_pmd_table(void) -{ - int i; - - for (i = 0; i < PAGE_SIZE/sizeof(pmd_t); i++) - srmmu_pmd_set(&(empty_bad_pmd_table[i]), empty_bad_pte_table); - - return empty_bad_pmd_table; -} - -static pte_t * get_bad_pte_table(void) +static pte_t *srmmu_pte_alloc_one_fast(struct mm_struct *mm, unsigned long address) { - pte_t v; - int i; - - memset((void *)&empty_bad_page, 0, PAGE_SIZE); - - v = srmmu_pte_mkdirty(srmmu_mk_pte_phys(__pa(&empty_bad_page) + phys_base, PAGE_SHARED)); - - for (i = 0; i < PAGE_SIZE/sizeof(pte_t); i++) - srmmu_set_pte(&(empty_bad_pte_table[i]), v); - - return empty_bad_pte_table; + return (pte_t *)srmmu_get_nocache(SRMMU_PTE_TABLE_SIZE, SRMMU_PTE_TABLE_SIZE); } -void __handle_bad_pgd(pgd_t *pgd) +static pte_t *srmmu_pte_alloc_one(struct mm_struct *mm, unsigned long address) { - pgd_ERROR(*pgd); - srmmu_pgd_set(pgd, get_bad_pmd_table()); + BUG(); } -void __handle_bad_pmd(pmd_t *pmd) -{ - pmd_ERROR(*pmd); - srmmu_pmd_set(pmd, get_bad_pte_table()); -} - -static pte_t *srmmu_pte_alloc(pmd_t * pmd, unsigned long address) -{ - address = (address >> PAGE_SHIFT) & (SRMMU_PTRS_PER_PTE - 1); - if(srmmu_pmd_none(*pmd)) { - pte_t *page = (pte_t *)srmmu_get_nocache(SRMMU_PTE_TABLE_SIZE, SRMMU_PTE_TABLE_SIZE); - if(page) { - srmmu_pmd_set(pmd, page); - return page + address; - } - srmmu_pmd_set(pmd, get_bad_pte_table()); - return NULL; - } - if(srmmu_pmd_bad(*pmd)) { - __handle_bad_pmd(pmd); - return NULL; - } - return ((pte_t *) pmd_page(*pmd)) + address; -} - -static inline void srmmu_pte_free(pte_t *pte) +static void srmmu_free_pte_fast(pte_t *pte) { srmmu_free_nocache((unsigned long)pte, SRMMU_PTE_TABLE_SIZE); } -static pmd_t *srmmu_pmd_alloc(pgd_t * pgd, unsigned long address) +static pmd_t *srmmu_pmd_alloc_one_fast(struct mm_struct *mm, unsigned long address) { - address = (address >> SRMMU_PMD_SHIFT) & (SRMMU_PTRS_PER_PMD - 1); - if(srmmu_pgd_none(*pgd)) { - pmd_t *page = (pmd_t *)srmmu_get_nocache(SRMMU_PMD_TABLE_SIZE, SRMMU_PMD_TABLE_SIZE); - if(page) { - srmmu_pgd_set(pgd, page); - return page + address; - } - srmmu_pgd_set(pgd, get_bad_pmd_table()); - return NULL; - } - if(srmmu_pgd_bad(*pgd)) { - __handle_bad_pgd(pgd); - return NULL; - } - return (pmd_t *) srmmu_pgd_page(*pgd) + address; + return (pmd_t *)srmmu_get_nocache(SRMMU_PMD_TABLE_SIZE, SRMMU_PMD_TABLE_SIZE); } -static void srmmu_pmd_free(pmd_t * pmd) +static void srmmu_free_pmd_fast(pmd_t * pmd) { srmmu_free_nocache((unsigned long)pmd, SRMMU_PMD_TABLE_SIZE); } @@ -1242,9 +1174,6 @@ flush_cache_all(); flush_tlb_all(); - empty_bad_pmd_table = (pte_t *)srmmu_get_nocache(SRMMU_PMD_TABLE_SIZE, SRMMU_PMD_TABLE_SIZE); - empty_bad_pte_table = (pte_t *)srmmu_get_nocache(SRMMU_PTE_TABLE_SIZE, SRMMU_PTE_TABLE_SIZE); - /* * This does not logically belong here, but we need to * call it at the moment we are able to use the bootmem @@ -2114,16 +2043,13 @@ BTFIXUPSET_INT(pte_modify_mask, SRMMU_CHG_MASK); BTFIXUPSET_CALL(pmd_offset, srmmu_pmd_offset, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(pte_offset, srmmu_pte_offset, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(pte_free_kernel, srmmu_pte_free, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(pmd_free_kernel, srmmu_pmd_free, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(pte_alloc_kernel, srmmu_pte_alloc, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(pmd_alloc_kernel, srmmu_pmd_alloc, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(pte_free, srmmu_pte_free, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(pte_alloc, srmmu_pte_alloc, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(pmd_free, srmmu_pmd_free, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(pmd_alloc, srmmu_pmd_alloc, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(pgd_free, srmmu_pgd_free, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(pgd_alloc, srmmu_pgd_alloc, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(free_pte_fast, srmmu_free_pte_fast, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(pte_alloc_one_fast, srmmu_pte_alloc_one_fast, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(pte_alloc_one, srmmu_pte_alloc_one, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(free_pmd_fast, srmmu_free_pmd_fast, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(pmd_alloc_one_fast, srmmu_pmd_alloc_one_fast, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(free_pgd_fast, srmmu_free_pgd_fast, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(get_pgd_fast, srmmu_get_pgd_fast, BTFIXUPCALL_NORM); BTFIXUPSET_HALF(pte_writei, SRMMU_WRITE); BTFIXUPSET_HALF(pte_dirtyi, SRMMU_DIRTY); diff -u --recursive --new-file v2.4.6/linux/arch/sparc/mm/sun4c.c linux/arch/sparc/mm/sun4c.c --- v2.4.6/linux/arch/sparc/mm/sun4c.c Thu Apr 19 08:38:48 2001 +++ linux/arch/sparc/mm/sun4c.c Thu Jul 19 18:11:13 2001 @@ -1,4 +1,4 @@ -/* $Id: sun4c.c,v 1.206 2001/04/14 21:13:45 davem Exp $ +/* $Id: sun4c.c,v 1.207 2001/07/17 16:17:33 anton Exp $ * sun4c.c: Doing in software what should be done in hardware. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -2178,7 +2178,7 @@ } /* to find an entry in a page-table-directory */ -extern inline pgd_t *sun4c_pgd_offset(struct mm_struct * mm, unsigned long address) +static inline pgd_t *sun4c_pgd_offset(struct mm_struct * mm, unsigned long address) { return mm->pgd + (address >> SUN4C_PGDIR_SHIFT); } @@ -2195,41 +2195,6 @@ return (pte_t *) sun4c_pmd_page(*dir) + ((address >> PAGE_SHIFT) & (SUN4C_PTRS_PER_PTE - 1)); } -/* Please take special note on the foo_kernel() routines below, our - * fast in window fault handler wants to get at the pte's for vmalloc - * area with traps off, therefore they _MUST_ be locked down to prevent - * a watchdog from happening. It only takes 4 pages of pte's to lock - * down the maximum vmalloc space possible on sun4c so we statically - * allocate these page table pieces in the kernel image. Therefore - * we should never have to really allocate or free any kernel page - * table information. - */ - -/* Allocate and free page tables. The xxx_kernel() versions are - * used to allocate a kernel page table - this turns on ASN bits - * if any, and marks the page tables reserved. - */ -static void sun4c_pte_free_kernel(pte_t *pte) -{ - /* This should never get called. */ - panic("sun4c_pte_free_kernel called, can't happen..."); -} - -static pte_t *sun4c_pte_alloc_kernel(pmd_t *pmd, unsigned long address) -{ - if (address >= SUN4C_LOCK_VADDR) - return NULL; - address = (address >> PAGE_SHIFT) & (SUN4C_PTRS_PER_PTE - 1); - if (sun4c_pmd_none(*pmd)) - panic("sun4c_pmd_none for kernel pmd, can't happen..."); - if (sun4c_pmd_bad(*pmd)) { - printk("Bad pmd in pte_alloc_kernel: %08lx\n", pmd_val(*pmd)); - *pmd = __pmd(PGD_TABLE | (unsigned long) BAD_PAGETABLE); - return NULL; - } - return (pte_t *) sun4c_pmd_page(*pmd) + address; -} - static void sun4c_free_pte_slow(pte_t *pte) { free_page((unsigned long)pte); @@ -2240,20 +2205,7 @@ free_page((unsigned long)pgd); } -/* - * allocating and freeing a pmd is trivial: the 1-entry pmd is - * inside the pgd, so has no extra memory associated with it. - */ -static void sun4c_pmd_free_kernel(pmd_t *pmd) -{ -} - -static pmd_t *sun4c_pmd_alloc_kernel(pgd_t *pgd, unsigned long address) -{ - return (pmd_t *) pgd; -} - -extern __inline__ pgd_t *sun4c_get_pgd_fast(void) +static pgd_t *sun4c_get_pgd_fast(void) { unsigned long *ret; @@ -2273,14 +2225,22 @@ return (pgd_t *)ret; } -extern __inline__ void sun4c_free_pgd_fast(pgd_t *pgd) +static void sun4c_free_pgd_fast(pgd_t *pgd) { *(unsigned long *)pgd = (unsigned long) pgd_quicklist; pgd_quicklist = (unsigned long *) pgd; pgtable_cache_size++; } -extern __inline__ pte_t *sun4c_get_pte_fast(void) +static pte_t *sun4c_pte_alloc_one(struct mm_struct *mm, unsigned long address) +{ + pte_t *pte = (pte_t *)__get_free_page(GFP_KERNEL); + if (pte) + memset(pte, 0, PAGE_SIZE); + return pte; +} + +pte_t *sun4c_pte_alloc_one_fast(struct mm_struct *mm, unsigned long address) { unsigned long *ret; @@ -2292,68 +2252,25 @@ return (pte_t *)ret; } -extern __inline__ void sun4c_free_pte_fast(pte_t *pte) +static __inline__ void sun4c_free_pte_fast(pte_t *pte) { *(unsigned long *)pte = (unsigned long) pte_quicklist; pte_quicklist = (unsigned long *) pte; pgtable_cache_size++; } -static void sun4c_pte_free(pte_t *pte) -{ - sun4c_free_pte_fast(pte); -} - -static pte_t *sun4c_pte_alloc(pmd_t * pmd, unsigned long address) -{ - address = (address >> PAGE_SHIFT) & (SUN4C_PTRS_PER_PTE - 1); - if (sun4c_pmd_none(*pmd)) { - pte_t *page = (pte_t *) sun4c_get_pte_fast(); - - if (page) { - *pmd = __pmd(PGD_TABLE | (unsigned long) page); - return page + address; - } - page = (pte_t *) get_free_page(GFP_KERNEL); - if (sun4c_pmd_none(*pmd)) { - if (page) { - *pmd = __pmd(PGD_TABLE | (unsigned long) page); - return page + address; - } - *pmd = __pmd(PGD_TABLE | (unsigned long) BAD_PAGETABLE); - return NULL; - } - free_page((unsigned long) page); - } - if (sun4c_pmd_bad(*pmd)) { - printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd)); - *pmd = __pmd(PGD_TABLE | (unsigned long) BAD_PAGETABLE); - return NULL; - } - return (pte_t *) sun4c_pmd_page(*pmd) + address; -} - /* * allocating and freeing a pmd is trivial: the 1-entry pmd is * inside the pgd, so has no extra memory associated with it. */ -static void sun4c_pmd_free(pmd_t * pmd) -{ -} - -static pmd_t *sun4c_pmd_alloc(pgd_t * pgd, unsigned long address) +static pmd_t *sun4c_pmd_alloc_one_fast(struct mm_struct *mm, unsigned long address) { - return (pmd_t *) pgd; + BUG(); + return NULL; } -static void sun4c_pgd_free(pgd_t *pgd) +static void sun4c_free_pmd_fast(pmd_t * pmd) { - sun4c_free_pgd_fast(pgd); -} - -static pgd_t *sun4c_pgd_alloc(void) -{ - return sun4c_get_pgd_fast(); } static int sun4c_check_pgt_cache(int low, int high) @@ -2363,13 +2280,8 @@ do { if (pgd_quicklist) sun4c_free_pgd_slow(sun4c_get_pgd_fast()), freed++; - /* Only two level page tables at the moment, sun4 3 level mmu is not supported - Anton */ -#if 0 - if (pmd_quicklist) - sun4c_free_pmd_slow(sun4c_get_pmd_fast()), freed++; -#endif if (pte_quicklist) - sun4c_free_pte_slow(sun4c_get_pte_fast()), freed++; + sun4c_free_pte_slow(sun4c_pte_alloc_one_fast(NULL, 0)), freed++; } while (pgtable_cache_size > low); } return freed; @@ -2615,16 +2527,13 @@ BTFIXUPSET_INT(pte_modify_mask, _SUN4C_PAGE_CHG_MASK); BTFIXUPSET_CALL(pmd_offset, sun4c_pmd_offset, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(pte_offset, sun4c_pte_offset, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(pte_free_kernel, sun4c_pte_free_kernel, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(pmd_free_kernel, sun4c_pmd_free_kernel, BTFIXUPCALL_NOP); - BTFIXUPSET_CALL(pte_alloc_kernel, sun4c_pte_alloc_kernel, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(pmd_alloc_kernel, sun4c_pmd_alloc_kernel, BTFIXUPCALL_RETO0); - BTFIXUPSET_CALL(pte_free, sun4c_pte_free, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(pte_alloc, sun4c_pte_alloc, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(pmd_free, sun4c_pmd_free, BTFIXUPCALL_NOP); - BTFIXUPSET_CALL(pmd_alloc, sun4c_pmd_alloc, BTFIXUPCALL_RETO0); - BTFIXUPSET_CALL(pgd_free, sun4c_pgd_free, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(pgd_alloc, sun4c_pgd_alloc, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(free_pte_fast, sun4c_free_pte_fast, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(pte_alloc_one, sun4c_pte_alloc_one, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(pte_alloc_one_fast, sun4c_pte_alloc_one_fast, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(free_pmd_fast, sun4c_free_pmd_fast, BTFIXUPCALL_NOP); + BTFIXUPSET_CALL(pmd_alloc_one_fast, sun4c_pmd_alloc_one_fast, BTFIXUPCALL_RETO0); + BTFIXUPSET_CALL(free_pgd_fast, sun4c_free_pgd_fast, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(get_pgd_fast, sun4c_get_pgd_fast, BTFIXUPCALL_NORM); BTFIXUPSET_HALF(pte_writei, _SUN4C_PAGE_WRITE); BTFIXUPSET_HALF(pte_dirtyi, _SUN4C_PAGE_MODIFIED); diff -u --recursive --new-file v2.4.6/linux/arch/sparc64/config.in linux/arch/sparc64/config.in --- v2.4.6/linux/arch/sparc64/config.in Tue Jul 3 17:08:19 2001 +++ linux/arch/sparc64/config.in Fri Jul 20 12:50:24 2001 @@ -1,4 +1,4 @@ -# $Id: config.in,v 1.146 2001/06/16 04:15:26 davem Exp $ +# $Id: config.in,v 1.148 2001/07/20 07:10:35 davem Exp $ # For a description of the syntax of this configuration file, # see the Configure script. # @@ -208,27 +208,9 @@ source drivers/fc4/Config.in -if [ "$CONFIG_PCI" = "y" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then - mainmenu_option next_comment - comment 'IEEE 1394 (FireWire) support' - - dep_tristate 'IEEE 1394 (FireWire) support (EXPERIMENTAL)' CONFIG_IEEE1394 $CONFIG_PCI - - if [ "$CONFIG_IEEE1394" != "n" ]; then - dep_tristate 'Texas Instruments PCILynx support' CONFIG_IEEE1394_PCILYNX $CONFIG_IEEE1394 - if [ "$CONFIG_IEEE1394_PCILYNX" != "n" ]; then - bool ' Use PCILynx local RAM' CONFIG_IEEE1394_PCILYNX_LOCALRAM - bool ' Support for non-IEEE1394 local ports' CONFIG_IEEE1394_PCILYNX_PORTS - fi - - dep_tristate 'OHCI (Open Host Controller Interface) support' CONFIG_IEEE1394_OHCI1394 $CONFIG_IEEE1394 - - dep_tristate 'Raw IEEE1394 I/O support' CONFIG_IEEE1394_RAWIO $CONFIG_IEEE1394 - - bool 'Excessive debugging output' CONFIG_IEEE1394_VERBOSEDEBUG - fi - endmenu -fi +source drivers/message/fusion/Config.in + +source drivers/ieee1394/Config.in if [ "$CONFIG_NET" = "y" ]; then mainmenu_option next_comment diff -u --recursive --new-file v2.4.6/linux/arch/sparc64/defconfig linux/arch/sparc64/defconfig --- v2.4.6/linux/arch/sparc64/defconfig Tue Jul 3 17:08:19 2001 +++ linux/arch/sparc64/defconfig Fri Jul 20 12:50:24 2001 @@ -63,6 +63,8 @@ # CONFIG_PARPORT=m CONFIG_PARPORT_PC=m +CONFIG_PARPORT_PC_CML1=m +# CONFIG_PARPORT_SERIAL is not set CONFIG_PARPORT_PC_FIFO=y # CONFIG_PARPORT_PC_SUPERIO is not set # CONFIG_PARPORT_AMIGA is not set @@ -94,6 +96,8 @@ # CONFIG_FB_PM2_FIFO_DISCONNECT is not set CONFIG_FB_PM2_PCI=y # CONFIG_FB_CYBER2000 is not set +# CONFIG_FB_PVR2 is not set +# CONFIG_FB_PVR2_DEBUG is not set # CONFIG_FB_E1355 is not set # CONFIG_FB_MATROX is not set CONFIG_FB_ATY=y @@ -346,13 +350,37 @@ CONFIG_SCSI_FCAL=m # -# IEEE 1394 (FireWire) support +# Fusion MPT device support +# +CONFIG_FUSION=m +# CONFIG_FUSION_BOOT is not set + +# +# (ability to boot linux kernel from Fusion device is DISABLED!) +# +CONFIG_FUSION_ISENSE=m +CONFIG_FUSION_CTL=m +CONFIG_FUSION_LAN=m +CONFIG_NET_FC=y + +# +# IEEE 1394 (FireWire) support (EXPERIMENTAL) # CONFIG_IEEE1394=m + +# +# Device Drivers +# CONFIG_IEEE1394_PCILYNX=m # CONFIG_IEEE1394_PCILYNX_LOCALRAM is not set # CONFIG_IEEE1394_PCILYNX_PORTS is not set CONFIG_IEEE1394_OHCI1394=m + +# +# Protocol Drivers +# +# CONFIG_IEEE1394_VIDEO1394 is not set +CONFIG_IEEE1394_SBP2=m CONFIG_IEEE1394_RAWIO=m # CONFIG_IEEE1394_VERBOSEDEBUG is not set @@ -420,9 +448,9 @@ # CONFIG_8139TOO_PIO is not set # CONFIG_8139TOO_TUNE_TWISTER is not set # CONFIG_8139TOO_8129 is not set -# CONFIG_SIS900 is not set +CONFIG_SIS900=m CONFIG_EPIC100=m -# CONFIG_SUNDANCE is not set +CONFIG_SUNDANCE=m # CONFIG_TLAN is not set CONFIG_VIA_RHINE=m CONFIG_WINBOND_840=m @@ -433,10 +461,12 @@ # CONFIG_ACENIC=m # CONFIG_ACENIC_OMIT_TIGON_I is not set +CONFIG_DL2K=m CONFIG_MYRI_SBUS=m -# CONFIG_HAMACHI is not set -# CONFIG_YELLOWFIN is not set +CONFIG_HAMACHI=m +CONFIG_YELLOWFIN=m CONFIG_SK98LIN=m +# CONFIG_TIGON3 is not set CONFIG_FDDI=y # CONFIG_DEFXX is not set CONFIG_SKFP=m @@ -465,7 +495,8 @@ # Token Ring devices # # CONFIG_TR is not set -# CONFIG_NET_FC is not set +CONFIG_NET_FC=y +# CONFIG_IPHASE5526 is not set # CONFIG_RCPCI is not set # CONFIG_SHAPER is not set @@ -531,7 +562,7 @@ CONFIG_ISO9660_FS=m CONFIG_JOLIET=y CONFIG_MINIX_FS=m -CONFIG_VXFS_FS=m +# CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_RW is not set CONFIG_HPFS_FS=m @@ -545,7 +576,6 @@ CONFIG_ROMFS_FS=m CONFIG_EXT2_FS=y CONFIG_SYSV_FS=m -CONFIG_SYSV_FS_WRITE=y CONFIG_UDF_FS=m CONFIG_UDF_RW=y CONFIG_UFS_FS=m @@ -643,6 +673,7 @@ # CONFIG_SOUND_MSNDCLAS is not set # CONFIG_SOUND_MSNDPIN is not set # CONFIG_SOUND_VIA82CXXX is not set +# CONFIG_MIDI_VIA82CXXX is not set # CONFIG_SOUND_OSS is not set # CONFIG_SOUND_TVMIXER is not set diff -u --recursive --new-file v2.4.6/linux/arch/sparc64/kernel/binfmt_aout32.c linux/arch/sparc64/kernel/binfmt_aout32.c --- v2.4.6/linux/arch/sparc64/kernel/binfmt_aout32.c Sun Mar 25 18:14:21 2001 +++ linux/arch/sparc64/kernel/binfmt_aout32.c Thu Jul 19 20:38:52 2001 @@ -77,7 +77,7 @@ * Currently only a stub-function. * * Note that setuid/setgid files won't make a core-dump if the uid/gid - * changed due to the set[u|g]id. It's enforced by the "current->dumpable" + * changed due to the set[u|g]id. It's enforced by the "current->mm->dumpable" * field, which also makes sure the core-dumps won't be recursive if the * dumping of the process results in another error.. */ diff -u --recursive --new-file v2.4.6/linux/arch/sparc64/kernel/ptrace.c linux/arch/sparc64/kernel/ptrace.c --- v2.4.6/linux/arch/sparc64/kernel/ptrace.c Sun Mar 25 18:14:21 2001 +++ linux/arch/sparc64/kernel/ptrace.c Fri Jul 20 12:39:56 2001 @@ -170,38 +170,10 @@ || (current->personality != PER_SUNOS && request == PTRACE_ATTACH)) { unsigned long flags; - if (child == current) { - /* Try this under SunOS/Solaris, bwa haha - * You'll never be able to kill the process. ;-) - */ + if (ptrace_attach(child)) { pt_error_return(regs, EPERM); goto out_tsk; } - if ((!child->dumpable || - (current->uid != child->euid) || - (current->uid != child->uid) || - (current->uid != child->suid) || - (current->gid != child->egid) || - (current->gid != child->sgid) || - (!cap_issubset(child->cap_permitted, current->cap_permitted)) || - (current->gid != child->gid)) && !capable(CAP_SYS_PTRACE)) { - pt_error_return(regs, EPERM); - goto out_tsk; - } - /* the same process cannot be attached many times */ - if (child->ptrace & PT_PTRACED) { - pt_error_return(regs, EPERM); - goto out_tsk; - } - child->ptrace |= PT_PTRACED; - write_lock_irqsave(&tasklist_lock, flags); - if (child->p_pptr != current) { - REMOVE_LINKS(child); - child->p_pptr = current; - SET_LINKS(child); - } - write_unlock_irqrestore(&tasklist_lock, flags); - send_sig(SIGSTOP, child, 1); pt_succ_return(regs, 0); goto out_tsk; } diff -u --recursive --new-file v2.4.6/linux/drivers/Makefile linux/drivers/Makefile --- v2.4.6/linux/drivers/Makefile Tue Jul 3 17:08:19 2001 +++ linux/drivers/Makefile Sun Jul 15 16:15:44 2001 @@ -6,9 +6,9 @@ # -mod-subdirs := dio mtd sbus video macintosh usb input telephony sgi i2o ide \ - scsi md ieee1394 pnp isdn atm fc4 net/hamradio i2c acpi \ - bluetooth +mod-subdirs := dio mtd sbus video macintosh usb input telephony sgi ide \ + i2o message/fusion scsi md ieee1394 pnp isdn atm \ + fc4 net/hamradio i2c acpi bluetooth subdir-y := parport char block net sound misc media cdrom subdir-m := $(subdir-y) @@ -32,6 +32,7 @@ subdir-$(CONFIG_IDE) += ide subdir-$(CONFIG_SCSI) += scsi subdir-$(CONFIG_I2O) += i2o +subdir-$(CONFIG_FUSION) += message/fusion subdir-$(CONFIG_MD) += md subdir-$(CONFIG_IEEE1394) += ieee1394 subdir-$(CONFIG_PNP) += pnp diff -u --recursive --new-file v2.4.6/linux/drivers/atm/nicstar.c linux/drivers/atm/nicstar.c --- v2.4.6/linux/drivers/atm/nicstar.c Tue Jul 3 17:08:19 2001 +++ linux/drivers/atm/nicstar.c Sun Jul 15 16:15:44 2001 @@ -214,8 +214,8 @@ static u32 ns_read_sram(ns_dev *card, u32 sram_address); static void ns_write_sram(ns_dev *card, u32 sram_address, u32 *value, int count); -static int ns_init_card(int i, struct pci_dev *pcidev); -static void ns_init_card_error(ns_dev *card, int error); +static int __init ns_init_card(int i, struct pci_dev *pcidev); +static void __init ns_init_card_error(ns_dev *card, int error); static scq_info *get_scq(int size, u32 scd); static void free_scq(scq_info *scq, struct atm_vcc *vcc); static void push_rxbufs(ns_dev *card, u32 type, u32 handle1, u32 addr1, @@ -277,7 +277,7 @@ #ifdef MODULE -int init_module(void) +int __init init_module(void) { int i; unsigned error = 0; /* Initialized to remove compile warning */ @@ -511,7 +511,7 @@ } -static int ns_init_card(int i, struct pci_dev *pcidev) +static int __init ns_init_card(int i, struct pci_dev *pcidev) { int j; struct ns_dev *card = NULL; @@ -1007,7 +1007,7 @@ -static void ns_init_card_error(ns_dev *card, int error) +static void __init ns_init_card_error(ns_dev *card, int error) { if (error >= 17) { diff -u --recursive --new-file v2.4.6/linux/drivers/block/elevator.c linux/drivers/block/elevator.c --- v2.4.6/linux/drivers/block/elevator.c Thu Feb 15 16:58:34 2001 +++ linux/drivers/block/elevator.c Thu Jul 19 20:59:41 2001 @@ -92,7 +92,7 @@ if (__rq->elevator_sequence-- <= 0) break; - if (__rq->sem) + if (__rq->waiting) continue; if (__rq->rq_dev != bh->b_rdev) continue; @@ -162,7 +162,7 @@ continue; if (__rq->nr_sectors + count > max_sectors) continue; - if (__rq->sem) + if (__rq->waiting) continue; if (__rq->sector + __rq->nr_sectors == bh->b_rsector) { *req = __rq; diff -u --recursive --new-file v2.4.6/linux/drivers/block/genhd.c linux/drivers/block/genhd.c --- v2.4.6/linux/drivers/block/genhd.c Wed May 16 14:01:32 2001 +++ linux/drivers/block/genhd.c Thu Jul 19 17:48:15 2001 @@ -21,13 +21,15 @@ #ifdef CONFIG_BLK_DEV_DAC960 extern void DAC960_Initialize(void); #endif +#ifdef CONFIG_FUSION_BOOT +extern int fusion_init(void); +#endif extern int net_dev_init(void); extern void console_map_init(void); extern int soc_probe(void); extern int atmdev_init(void); extern int i2o_init(void); extern int cpqarray_init(void); -extern void ieee1394_init(void); int __init device_init(void) { @@ -39,12 +41,12 @@ #ifdef CONFIG_BLK_DEV_DAC960 DAC960_Initialize(); #endif +#ifdef CONFIG_FUSION_BOOT + fusion_init(); +#endif #ifdef CONFIG_FC4_SOC /* This has to be done before scsi_dev_init */ soc_probe(); -#endif -#ifdef CONFIG_IEEE1394 - ieee1394_init(); #endif #ifdef CONFIG_BLK_CPQ_DA cpqarray_init(); diff -u --recursive --new-file v2.4.6/linux/drivers/block/ll_rw_blk.c linux/drivers/block/ll_rw_blk.c --- v2.4.6/linux/drivers/block/ll_rw_blk.c Tue Jul 3 17:08:19 2001 +++ linux/drivers/block/ll_rw_blk.c Thu Jul 19 20:51:23 2001 @@ -22,6 +22,7 @@ #include <linux/swap.h> #include <linux/init.h> #include <linux/smp_lock.h> +#include <linux/completion.h> #include <asm/system.h> #include <asm/io.h> @@ -365,6 +366,11 @@ */ for (i = 0; i < queue_nr_requests; i++) { rq = kmem_cache_alloc(request_cachep, SLAB_KERNEL); + if (rq == NULL) { + /* We'll get a `leaked requests' message from blk_cleanup_queue */ + printk(KERN_EMERG "blk_init_free_list: error allocating requests\n"); + break; + } memset(rq, 0, sizeof(struct request)); rq->rq_status = RQ_INACTIVE; list_add(&rq->table, &q->request_freelist[i & 1]); @@ -621,7 +627,7 @@ if (req->cmd != next->cmd || req->rq_dev != next->rq_dev || req->nr_sectors + next->nr_sectors > max_sectors - || next->sem) + || next->waiting) return; /* * If we are not allowed to merge these requests, then @@ -806,7 +812,7 @@ req->nr_segments = 1; /* Always 1 for a new request. */ req->nr_hw_segments = 1; /* Always 1 for a new request. */ req->buffer = bh->b_data; - req->sem = NULL; + req->waiting = NULL; req->bh = bh; req->bhtail = bh; req->rq_dev = bh->b_rdev; @@ -955,15 +961,6 @@ } } -/* - * Default IO end handler, used by "ll_rw_block()". - */ -static void end_buffer_io_sync(struct buffer_head *bh, int uptodate) -{ - mark_buffer_uptodate(bh, uptodate); - unlock_buffer(bh); -} - /** * ll_rw_block: low-level access to block devices * @rw: whether to %READ or %WRITE or maybe %READA (readahead) @@ -1050,6 +1047,7 @@ continue; /* We have the buffer lock */ + atomic_inc(&bh->b_count); bh->b_end_io = end_buffer_io_sync; switch(rw) { @@ -1143,8 +1141,8 @@ void end_that_request_last(struct request *req) { - if (req->sem != NULL) - up(req->sem); + if (req->waiting != NULL) + complete(req->waiting); blkdev_release_request(req); } diff -u --recursive --new-file v2.4.6/linux/drivers/block/ps2esdi.c linux/drivers/block/ps2esdi.c --- v2.4.6/linux/drivers/block/ps2esdi.c Tue Jul 3 17:08:19 2001 +++ linux/drivers/block/ps2esdi.c Tue Jul 10 16:18:51 2001 @@ -117,6 +117,7 @@ static char ps2esdi_valid[MAX_HD]; static int ps2esdi_sizes[MAX_HD << 6]; static int ps2esdi_blocksizes[MAX_HD << 6]; +static int ps2esdi_maxsect[MAX_HD << 6]; static int ps2esdi_drives; static struct hd_struct ps2esdi[MAX_HD << 6]; static u_short io_base; @@ -414,8 +415,11 @@ ps2esdi_gendisk.nr_real = ps2esdi_drives; - for (i = 0; i < (MAX_HD << 6); i++) + /* 128 was old default, maybe maxsect=255 is ok too? - Paul G. */ + for (i = 0; i < (MAX_HD << 6); i++) { + ps2esdi_maxsect[i] = 128; ps2esdi_blocksizes[i] = 1024; + } request_dma(dma_arb_level, "ed"); request_region(io_base, 4, "ed"); diff -u --recursive --new-file v2.4.6/linux/drivers/block/rd.c linux/drivers/block/rd.c --- v2.4.6/linux/drivers/block/rd.c Fri Feb 9 11:30:22 2001 +++ linux/drivers/block/rd.c Sun Jul 15 16:15:44 2001 @@ -466,7 +466,7 @@ * romfs * gzip */ -int __init +static int __init identify_ramdisk_image(kdev_t device, struct file *fp, int start_block) { const int size = 512; @@ -570,8 +570,9 @@ char *buf; unsigned short rotate = 0; unsigned short devblocks = 0; +#if !defined(CONFIG_ARCH_S390) && !defined(CONFIG_PPC_ISERIES) char rotator[4] = { '|' , '/' , '-' , '\\' }; - +#endif ram_device = MKDEV(MAJOR_NR, unit); if ((inode = get_empty_inode()) == NULL) @@ -672,7 +673,7 @@ } infile.f_op->read(&infile, buf, BLOCK_SIZE, &infile.f_pos); outfile.f_op->write(&outfile, buf, BLOCK_SIZE, &outfile.f_pos); -#if !defined(CONFIG_ARCH_S390) +#if !defined(CONFIG_ARCH_S390) && !defined(CONFIG_PPC_ISERIES) if (!(i % 16)) { printk("%c\b", rotator[rotate & 0x3]); rotate++; diff -u --recursive --new-file v2.4.6/linux/drivers/cdrom/cdrom.c linux/drivers/cdrom/cdrom.c --- v2.4.6/linux/drivers/cdrom/cdrom.c Fri May 4 15:09:23 2001 +++ linux/drivers/cdrom/cdrom.c Wed Jul 11 14:55:41 2001 @@ -331,6 +331,7 @@ #endif /* CONFIG_SYSCTL */ static struct cdrom_device_info *topCdromPtr; static devfs_handle_t devfs_handle; +static struct unique_numspace cdrom_numspace = UNIQUE_NUMBERSPACE_INITIALISER; struct block_device_operations cdrom_fops = { @@ -354,7 +355,6 @@ struct cdrom_device_ops *cdo = cdi->ops; int *change_capability = (int *)&cdo->capability; /* hack */ char vname[16]; - static unsigned int cdrom_counter; cdinfo(CD_OPEN, "entering register_cdrom\n"); @@ -395,7 +395,8 @@ if (!devfs_handle) devfs_handle = devfs_mk_dir (NULL, "cdroms", NULL); - sprintf (vname, "cdrom%u", cdrom_counter++); + cdi->number = devfs_alloc_unique_number (&cdrom_numspace); + sprintf (vname, "cdrom%d", cdi->number); if (cdi->de) { int pos; devfs_handle_t slave; @@ -450,6 +451,7 @@ topCdromPtr = cdi->next; cdi->ops->n_minors--; devfs_unregister (cdi->de); + devfs_dealloc_unique_number (&cdrom_numspace, cdi->number); cdinfo(CD_REG_UNREG, "drive \"/dev/%s\" unregistered\n", cdi->name); return 0; } diff -u --recursive --new-file v2.4.6/linux/drivers/cdrom/mcd.c linux/drivers/cdrom/mcd.c --- v2.4.6/linux/drivers/cdrom/mcd.c Sun Feb 4 10:05:29 2001 +++ linux/drivers/cdrom/mcd.c Wed Jul 4 11:50:39 2001 @@ -105,17 +105,17 @@ #define mcd_port mcd /* for compatible parameter passing with "insmod" */ #include "mcd.h" -static int mcd_blocksizes[1] = { 0, }; +static int mcd_blocksizes[1]; /* I added A flag to drop to 1x speed if too many errors 0 = 1X ; 1 = 2X */ -static int mcdDouble = 0; +static int mcdDouble; /* How many sectors to hold at 1x speed counter */ -static int mcd1xhold = 0; +static int mcd1xhold; /* Is the drive connected properly and responding?? */ -static int mcdPresent = 0; +static int mcdPresent; #if 0 #define TEST1 /* <int-..> */ @@ -162,7 +162,7 @@ #define WORK_AROUND_MITSUMI_BUG_92 #define WORK_AROUND_MITSUMI_BUG_93 #ifdef WORK_AROUND_MITSUMI_BUG_93 -int mitsumi_bug_93_wait = 0; +int mitsumi_bug_93_wait; #endif /* WORK_AROUND_MITSUMI_BUG_93 */ static short mcd_port = CONFIG_MCD_BASE; /* used as "mcd" by "insmod" */ diff -u --recursive --new-file v2.4.6/linux/drivers/cdrom/sbpcd.c linux/drivers/cdrom/sbpcd.c --- v2.4.6/linux/drivers/cdrom/sbpcd.c Thu May 24 15:14:08 2001 +++ linux/drivers/cdrom/sbpcd.c Mon Jul 16 15:13:32 2001 @@ -4308,7 +4308,7 @@ i=verify_area(VERIFY_READ, (void *) arg, sizeof(struct cdrom_read_audio)); if (i) RETURN_UP(i); copy_from_user(&read_audio, (void *) arg, sizeof(struct cdrom_read_audio)); - if (read_audio.nframes>D_S[d].sbp_audsiz) RETURN_UP(-EINVAL); + if (read_audio.nframes < 0 || read_audio.nframes>D_S[d].sbp_audsiz) RETURN_UP(-EINVAL); i=verify_area(VERIFY_WRITE, read_audio.buf, read_audio.nframes*CD_FRAMESIZE_RAW); if (i) RETURN_UP(i); diff -u --recursive --new-file v2.4.6/linux/drivers/char/Config.in linux/drivers/char/Config.in --- v2.4.6/linux/drivers/char/Config.in Tue Jul 3 17:08:19 2001 +++ linux/drivers/char/Config.in Wed Jul 4 14:41:33 2001 @@ -42,8 +42,8 @@ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then dep_tristate ' Multi-Tech multiport card support (EXPERIMENTAL)' CONFIG_ISI m fi - dep_tristate ' Microgate SyncLink card support' CONFIG_SYNCLINK m - dep_tristate ' HDLC line discipline support' CONFIG_N_HDLC m + tristate ' Microgate SyncLink card support' CONFIG_SYNCLINK + tristate ' HDLC line discipline support' CONFIG_N_HDLC tristate ' SDL RISCom/8 card support' CONFIG_RISCOM8 tristate ' Specialix IO8+ card support' CONFIG_SPECIALIX if [ "$CONFIG_SPECIALIX" != "n" ]; then @@ -60,6 +60,9 @@ tristate ' Stallion EC8/64, ONboard, Brumby support' CONFIG_ISTALLION fi fi +if [ "$CONFIG_EXPERIMENTAL" = "y" -a "$CONFIG_ZORRO" = "y" ]; then + tristate 'Commodore A2232 serial support (EXPERIMENTAL)' CONFIG_A2232 +fi if [ "$CONFIG_FOOTBRIDGE" = "y" ]; then bool 'DC21285 serial port support' CONFIG_SERIAL_21285 if [ "$CONFIG_SERIAL_21285" = "y" ]; then @@ -135,6 +138,7 @@ tristate ' Acquire SBC Watchdog Timer' CONFIG_ACQUIRE_WDT tristate ' Advantech SBC Watchdog Timer' CONFIG_ADVANTECH_WDT tristate ' SBC-60XX Watchdog Timer' CONFIG_60XX_WDT + tristate ' W83877F (EMACS) Watchdog Timer' CONFIG_W83877F_WDT tristate ' Mixcom Watchdog' CONFIG_MIXCOMWD tristate ' Intel i810 TCO timer / Watchdog' CONFIG_I810_TCO if [ "$CONFIG_FOOTBRIDGE" = "y" ]; then @@ -169,6 +173,9 @@ tristate 'Double Talk PC internal speech card support' CONFIG_DTLK tristate 'Siemens R3964 line discipline' CONFIG_R3964 tristate 'Applicom intelligent fieldbus card support' CONFIG_APPLICOM +if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + tristate 'Sony Vaio Programmable I/O Control Device support' CONFIG_SONYPI $CONFIG_PCI +fi mainmenu_option next_comment comment 'Ftape, the floppy tape device driver' diff -u --recursive --new-file v2.4.6/linux/drivers/char/Makefile linux/drivers/char/Makefile --- v2.4.6/linux/drivers/char/Makefile Wed May 16 10:27:02 2001 +++ linux/drivers/char/Makefile Wed Jul 4 14:41:33 2001 @@ -23,7 +23,7 @@ export-objs := busmouse.o console.o keyboard.o sysrq.o \ misc.o pty.o random.o selection.o serial.o \ - tty_io.o + sonypi.o tty_io.o tty_ioctl.o mod-subdirs := joystick ftape drm pcmcia @@ -48,6 +48,20 @@ SERIAL = endif +ifeq ($(ARCH),s390) + KEYMAP = + KEYBD = + CONSOLE = + SERIAL = +endif + +ifeq ($(ARCH),s390x) + KEYMAP = + KEYBD = + CONSOLE = + SERIAL = +endif + ifeq ($(ARCH),m68k) ifdef CONFIG_AMIGA KEYBD = amikeyb.o @@ -139,6 +153,7 @@ obj-$(CONFIG_N_HDLC) += n_hdlc.o obj-$(CONFIG_SPECIALIX) += specialix.o obj-$(CONFIG_AMIGA_BUILTIN_SERIAL) += amiserial.o +obj-$(CONFIG_A2232) += ser_a2232.o generic_serial.o obj-$(CONFIG_SX) += sx.o generic_serial.o obj-$(CONFIG_RIO) += rio/rio.o generic_serial.o obj-$(CONFIG_SH_SCI) += sh-sci.o generic_serial.o @@ -162,6 +177,7 @@ obj-$(CONFIG_DTLK) += dtlk.o obj-$(CONFIG_R3964) += n_r3964.o obj-$(CONFIG_APPLICOM) += applicom.o +obj-$(CONFIG_SONYPI) += sonypi.o obj-$(CONFIG_MS_BUSMOUSE) += msbusmouse.o obj-$(CONFIG_82C710_MOUSE) += qpmouse.o obj-$(CONFIG_AMIGAMOUSE) += amigamouse.o diff -u --recursive --new-file v2.4.6/linux/drivers/char/drm/bufs.c linux/drivers/char/drm/bufs.c --- v2.4.6/linux/drivers/char/drm/bufs.c Mon Mar 19 12:35:08 2001 +++ linux/drivers/char/drm/bufs.c Mon Jul 16 15:13:32 2001 @@ -202,6 +202,12 @@ return -ENOMEM; /* May only call once for each order */ } + if(count < 0 || count > 4096) + { + up(&dev->struct_sem); + return -EINVAL; + } + entry->buflist = drm_alloc(count * sizeof(*entry->buflist), DRM_MEM_BUFS); if (!entry->buflist) { diff -u --recursive --new-file v2.4.6/linux/drivers/char/drm/i810_bufs.c linux/drivers/char/drm/i810_bufs.c --- v2.4.6/linux/drivers/char/drm/i810_bufs.c Tue Aug 29 14:09:15 2000 +++ linux/drivers/char/drm/i810_bufs.c Mon Jul 16 15:13:32 2001 @@ -87,7 +87,14 @@ atomic_dec(&dev->buf_alloc); return -ENOMEM; /* May only call once for each order */ } - + + if(count < 0 || count > 4096) + { + up(&dev->struct_sem); + atomic_dec(&dev->buf_alloc); + return -EINVAL; + } + entry->buflist = drm_alloc(count * sizeof(*entry->buflist), DRM_MEM_BUFS); if (!entry->buflist) { diff -u --recursive --new-file v2.4.6/linux/drivers/char/drm/i810_dma.c linux/drivers/char/drm/i810_dma.c --- v2.4.6/linux/drivers/char/drm/i810_dma.c Tue Jul 3 17:08:19 2001 +++ linux/drivers/char/drm/i810_dma.c Mon Jul 16 15:13:32 2001 @@ -1416,6 +1416,11 @@ buf_priv = buf->dev_private; if (buf_priv->currently_mapped != I810_BUF_MAPPED) return -EPERM; + /* Stopping end users copying their data to the entire kernel + is good.. */ + if (d.used < 0 || d.used > buf->total) + return -EINVAL; + if (copy_from_user(buf_priv->virtual, d.address, d.used)) return -EFAULT; diff -u --recursive --new-file v2.4.6/linux/drivers/char/drm/ioctl.c linux/drivers/char/drm/ioctl.c --- v2.4.6/linux/drivers/char/drm/ioctl.c Tue Aug 29 14:09:15 2000 +++ linux/drivers/char/drm/ioctl.c Mon Jul 16 15:13:32 2001 @@ -82,7 +82,7 @@ if (copy_from_user(&u, (drm_unique_t *)arg, sizeof(u))) return -EFAULT; - if (!u.unique_len) + if (!u.unique_len || u.unique_len > 1024) return -EINVAL; dev->unique_len = u.unique_len; diff -u --recursive --new-file v2.4.6/linux/drivers/char/drm/mga_bufs.c linux/drivers/char/drm/mga_bufs.c --- v2.4.6/linux/drivers/char/drm/mga_bufs.c Mon Mar 19 12:35:08 2001 +++ linux/drivers/char/drm/mga_bufs.c Mon Jul 16 15:13:32 2001 @@ -97,7 +97,17 @@ atomic_dec(&dev->buf_alloc); return -ENOMEM; /* May only call once for each order */ } - + + /* This isnt neccessarily a good limit, but we have to stop a dumb + 32 bit overflow problem below */ + + if ( count < 0 || count > 4096) + { + up(&dev->struct_sem); + atomic_dec(&dev->buf_alloc); + return -EINVAL; + } + entry->buflist = drm_alloc(count * sizeof(*entry->buflist), DRM_MEM_BUFS); if (!entry->buflist) { @@ -248,6 +258,13 @@ up(&dev->struct_sem); atomic_dec(&dev->buf_alloc); return -ENOMEM; /* May only call once for each order */ + } + + if(count < 0 || count > 4096) + { + up(&dev->struct_sem); + atomic_dec(&dev->buf_alloc); + return -EINVAL; } entry->buflist = drm_alloc(count * sizeof(*entry->buflist), diff -u --recursive --new-file v2.4.6/linux/drivers/char/drm/r128_bufs.c linux/drivers/char/drm/r128_bufs.c --- v2.4.6/linux/drivers/char/drm/r128_bufs.c Mon Mar 19 12:35:08 2001 +++ linux/drivers/char/drm/r128_bufs.c Mon Jul 16 15:13:32 2001 @@ -103,6 +103,16 @@ return -ENOMEM; /* May only call once for each order */ } + /* Might be a poor limit, but take that up with XFree86 + if its a problem */ + + if(count < 0 || count > 4096) + { + up(&dev->struct_sem); + atomic_dec(&dev->buf_alloc); + return -EINVAL; + } + entry->buflist = drm_alloc(count * sizeof(*entry->buflist), DRM_MEM_BUFS); if (!entry->buflist) { diff -u --recursive --new-file v2.4.6/linux/drivers/char/drm/radeon_bufs.c linux/drivers/char/drm/radeon_bufs.c --- v2.4.6/linux/drivers/char/drm/radeon_bufs.c Tue Jul 3 17:08:19 2001 +++ linux/drivers/char/drm/radeon_bufs.c Mon Jul 16 15:13:32 2001 @@ -100,6 +100,15 @@ return -ENOMEM; /* May only call once for each order */ } + /* Might be too low a limit. XFree folks need to fix this properly */ + + if(count < 0 || count > 4096) + { + up(&dev->struct_sem); + atomic_dec(&dev->buf_alloc); + return -EINVAL; + } + entry->buflist = drm_alloc(count * sizeof(*entry->buflist), DRM_MEM_BUFS); if (!entry->buflist) { diff -u --recursive --new-file v2.4.6/linux/drivers/char/dsp56k.c linux/drivers/char/dsp56k.c --- v2.4.6/linux/drivers/char/dsp56k.c Fri Mar 2 18:38:37 2001 +++ linux/drivers/char/dsp56k.c Sun Jul 15 16:15:44 2001 @@ -64,7 +64,7 @@ #define wait_some(n) \ { \ - current->state = TASK_INTERRUPTIBLE; \ + set_current_state(TASK_INTERRUPTIBLE); \ schedule_timeout(n); \ } @@ -149,7 +149,7 @@ static struct dsp56k_device { - int in_use; + long in_use; long maxio, timeout; int tx_wsize, rx_wsize; } dsp56k; @@ -451,10 +451,9 @@ { case DSP56K_DEV_56001: - if (dsp56k.in_use) + if (test_and_set_bit(0, &dsp56k.in_use)) return -EBUSY; - dsp56k.in_use = 1; dsp56k.timeout = TIMEOUT; dsp56k.maxio = MAXIO; dsp56k.rx_wsize = dsp56k.tx_wsize = 4; @@ -469,8 +468,7 @@ break; default: - printk(KERN_ERR "DSP56k driver: Unknown minor device: %d\n", dev); - return -ENXIO; + return -ENODEV; } return 0; @@ -483,11 +481,7 @@ switch(dev) { case DSP56K_DEV_56001: - - lock_kernel(); - dsp56k.in_use = 0; - unlock_kernel(); - + clear_bit(0, &dsp56k.in_use); break; default: printk(KERN_ERR "DSP56k driver: Unknown minor device: %d\n", dev); diff -u --recursive --new-file v2.4.6/linux/drivers/char/dtlk.c linux/drivers/char/dtlk.c --- v2.4.6/linux/drivers/char/dtlk.c Fri Feb 16 16:02:35 2001 +++ linux/drivers/char/dtlk.c Wed Jul 4 14:41:33 2001 @@ -128,7 +128,7 @@ { unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev); char ch; - int retval, i = 0, retries; + int i = 0, retries; /* Can't seek (pread) on the DoubleTalk. */ if (ppos != &file->f_pos) @@ -144,8 +144,8 @@ while (i < count && dtlk_readable()) { ch = dtlk_read_lpc(); /* printk("dtlk_read() reads 0x%02x\n", ch); */ - if ((retval = put_user(ch, buf++))) - return retval; + if (put_user(ch, buf++)) + return -EFAULT; i++; } if (i) @@ -163,7 +163,7 @@ static ssize_t dtlk_write(struct file *file, const char *buf, size_t count, loff_t * ppos) { - int i = 0, retries = 0, err, ch; + int i = 0, retries = 0, ch; TRACE_TEXT("(dtlk_write"); #ifdef TRACING @@ -171,7 +171,8 @@ { int i, ch; for (i = 0; i < count; i++) { - err = get_user(ch, buf + i); + if (get_user(ch, buf + i)) + return -EFAULT; if (' ' <= ch && ch <= '~') printk("%c", ch); else @@ -189,7 +190,7 @@ return -EINVAL; while (1) { - while (i < count && (err = get_user(ch, buf)) == 0 && + while (i < count && !get_user(ch, buf) && (ch == DTLK_CLEAR || dtlk_writeable())) { dtlk_write_tts(ch); buf++; @@ -279,7 +280,6 @@ unsigned long arg) { struct dtlk_settings *sp; - int err; char portval; TRACE_TEXT(" dtlk_ioctl"); @@ -287,9 +287,8 @@ case DTLK_INTERROGATE: sp = dtlk_interrogate(); - err = copy_to_user((char *) arg, (char *) sp, - sizeof(struct dtlk_settings)); - if (err) + if (copy_to_user((char *) arg, (char *) sp, + sizeof(struct dtlk_settings))) return -EINVAL; return 0; diff -u --recursive --new-file v2.4.6/linux/drivers/char/dz.c linux/drivers/char/dz.c --- v2.4.6/linux/drivers/char/dz.c Fri Mar 2 18:38:37 2001 +++ linux/drivers/char/dz.c Wed Jul 4 14:41:33 2001 @@ -14,6 +14,8 @@ * after patches by harald to irq code. * [09-JAN-99] triemer minor fix for schedule - due to removal of timeout * field from "current" - somewhere between 2.1.121 and 2.1.131 +Qua Jun 27 15:02:26 BRT 2001 + * [27-JUN-2001] Arnaldo Carvalho de Melo <acme@conectiva.com.br> - cleanups * * Parts (C) 1999 David Airlie, airlied@linux.ie * [07-SEP-99] Bugfixes @@ -835,7 +837,7 @@ tmp.close_delay = info->close_delay; tmp.closing_wait = info->closing_wait; - return copy_to_user (retinfo, &tmp, sizeof(*retinfo)); + return copy_to_user(retinfo, &tmp, sizeof(*retinfo)) ? -EFAULT : 0; } static int set_serial_info (struct dz_serial *info, struct serial_struct *new_info) @@ -919,9 +921,9 @@ restore_flags (flags); } -static int dz_ioctl (struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg) +static int dz_ioctl (struct tty_struct *tty, struct file *file, + unsigned int cmd, unsigned long arg) { - int error; struct dz_serial * info = (struct dz_serial *)tty->driver_data; int retval; @@ -951,41 +953,26 @@ return 0; case TIOCGSOFTCAR: - error = verify_area (VERIFY_WRITE, (void *)arg, sizeof(long)); - if (error) - return error; - put_user (C_CLOCAL(tty) ? 1 : 0, (unsigned long *)arg); - return 0; + return put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned long *)arg); case TIOCSSOFTCAR: - error = get_user (arg, (unsigned long *)arg); - if (error) - return error; + if (get_user (arg, (unsigned long *)arg)) + return -EFAULT; tty->termios->c_cflag = ((tty->termios->c_cflag & ~CLOCAL) | (arg ? CLOCAL : 0)); return 0; case TIOCGSERIAL: - error = verify_area (VERIFY_WRITE, (void *)arg, sizeof(struct serial_struct)); - if (error) - return error; return get_serial_info (info, (struct serial_struct *)arg); case TIOCSSERIAL: return set_serial_info (info, (struct serial_struct *) arg); case TIOCSERGETLSR: /* Get line status register */ - error = verify_area (VERIFY_WRITE, (void *)arg, sizeof(unsigned int)); - if (error) - return error; - else - return get_lsr_info (info, (unsigned int *)arg); + return get_lsr_info (info, (unsigned int *)arg); case TIOCSERGSTRUCT: - error = verify_area (VERIFY_WRITE, (void *)arg, sizeof(struct dz_serial)); - if (error) - return error; - copy_to_user((struct dz_serial *)arg, info, sizeof(struct dz_serial)); - return 0; + return copy_to_user((struct dz_serial *)arg, info, + sizeof(struct dz_serial)) ? -EFAULT : 0; default: return -ENOIOCTLCMD; @@ -1436,7 +1423,7 @@ * dz_console_print () * * dz_console_print is registered for printk. - * The console_lock must be held when we get here. + * The console must be locked when we get here. * ------------------------------------------------------------------- */ static void dz_console_print (struct console *cons, diff -u --recursive --new-file v2.4.6/linux/drivers/char/esp.c linux/drivers/char/esp.c --- v2.4.6/linux/drivers/char/esp.c Tue Jul 3 17:08:19 2001 +++ linux/drivers/char/esp.c Sun Jul 15 16:15:44 2001 @@ -32,6 +32,9 @@ * Support for PIO mode. This allows the driver to work properly with * multiport cards. * + * Arnaldo Carvalho de Melo <acme@conectiva.com.br> - + * several cleanups, use module_init/module_exit, etc + * * This module exports the following rs232 io functions: * * int espserial_init(void); @@ -100,8 +103,8 @@ #define WAKEUP_CHARS 1024 -static char *serial_name = "ESP serial driver"; -static char *serial_version = "2.2"; +static char serial_name[] __initdata = "ESP serial driver"; +static char serial_version[] __initdata = "2.2"; static DECLARE_TASK_QUEUE(tq_esp); @@ -174,9 +177,9 @@ kdev_t device, const char *routine) { #ifdef SERIAL_PARANOIA_CHECK - static const char *badmagic = + static const char badmagic[] = KERN_WARNING "Warning: bad magic number for serial struct (%s) in %s\n"; - static const char *badinfo = + static const char badinfo[] = KERN_WARNING "Warning: null esp_struct for (%s) in %s\n"; if (!info) { @@ -285,8 +288,7 @@ buf = free_pio_buf; free_pio_buf = buf->next; } else { - buf = (struct esp_pio_buffer *) - kmalloc(sizeof(struct esp_pio_buffer), GFP_ATOMIC); + buf = kmalloc(sizeof(struct esp_pio_buffer), GFP_ATOMIC); } return buf; @@ -887,17 +889,14 @@ save_flags(flags); cli(); - if (info->flags & ASYNC_INITIALIZED) { - restore_flags(flags); - return retval; - } + if (info->flags & ASYNC_INITIALIZED) + goto out; if (!info->xmit_buf) { info->xmit_buf = (unsigned char *)get_free_page(GFP_KERNEL); - if (!info->xmit_buf) { - restore_flags(flags); - return -ENOMEM; - } + retval = -ENOMEM; + if (!info->xmit_buf) + goto out; } #ifdef SERIAL_DEBUG_OPEN @@ -944,9 +943,7 @@ &info->tty->flags); retval = 0; } - - restore_flags(flags); - return retval; + goto out; } if (!(info->stat_flags & ESP_STAT_USE_PIO) && !dma_buffer) { @@ -1003,8 +1000,9 @@ change_speed(info); info->flags |= ASYNC_INITIALIZED; - restore_flags(flags); - return 0; + retval = 0; +out: restore_flags(flags); + return retval; } /* @@ -1500,10 +1498,7 @@ tmp.pio_threshold = info->config.pio_threshold; tmp.dma_channel = (info->stat_flags & ESP_STAT_NEVER_DMA ? 0 : dma); - if (copy_to_user(retinfo,&tmp,sizeof(*retinfo))) - return -EFAULT; - - return 0; + return copy_to_user(retinfo, &tmp, sizeof(*retinfo)) ? -EFAULT : 0; } static int set_serial_info(struct esp_struct * info, @@ -1803,12 +1798,10 @@ static int set_modem_info(struct esp_struct * info, unsigned int cmd, unsigned int *value) { - int error; unsigned int arg; - error = get_user(arg, value); - if (error) - return error; + if (get_user(arg, value)) + return -EFAULT; switch (cmd) { case TIOCMBIS: @@ -1866,7 +1859,6 @@ static int rs_ioctl(struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg) { - int error; struct esp_struct * info = (struct esp_struct *)tty->driver_data; struct async_icount cprev, cnow; /* kernel counter temps */ struct serial_icounter_struct *p_cuser; /* user space */ @@ -1929,13 +1921,19 @@ cli(); cnow = info->icount; /* atomic copy */ sti(); - if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr && - cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) + if (cnow.rng == cprev.rng && + cnow.dsr == cprev.dsr && + cnow.dcd == cprev.dcd && + cnow.cts == cprev.cts) return -EIO; /* no change => error */ - if ( ((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) || - ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) || - ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) || - ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts)) ) { + if (((arg & TIOCM_RNG) && + (cnow.rng != cprev.rng)) || + ((arg & TIOCM_DSR) && + (cnow.dsr != cprev.dsr)) || + ((arg & TIOCM_CD) && + (cnow.dcd != cprev.dcd)) || + ((arg & TIOCM_CTS) && + (cnow.cts != cprev.cts)) ) { return 0; } cprev = cnow; @@ -1953,22 +1951,17 @@ cnow = info->icount; sti(); p_cuser = (struct serial_icounter_struct *) arg; - if ((error = put_user(cnow.cts, &p_cuser->cts))) - return error; - if ((error = put_user(cnow.dsr, &p_cuser->dsr))) - return error; - if ((error = put_user(cnow.rng, &p_cuser->rng))) - return error; - if ((error = put_user(cnow.dcd, &p_cuser->dcd))) - return error; + if (put_user(cnow.cts, &p_cuser->cts) || + put_user(cnow.dsr, &p_cuser->dsr) || + put_user(cnow.rng, &p_cuser->rng) || + put_user(cnow.dcd, &p_cuser->dcd)) + return -EFAULT; return 0; case TIOCGHAYESESP: - return (get_esp_config(info, - (struct hayes_esp_config *)arg)); + return (get_esp_config(info, (struct hayes_esp_config *)arg)); case TIOCSHAYESESP: - return (set_esp_config(info, - (struct hayes_esp_config *)arg)); + return (set_esp_config(info, (struct hayes_esp_config *)arg)); default: return -ENOIOCTLCMD; @@ -2050,9 +2043,7 @@ if (tty_hung_up_p(filp)) { DBG_CNT("before DEC-hung"); - MOD_DEC_USE_COUNT; - restore_flags(flags); - return; + goto out; } #ifdef SERIAL_DEBUG_OPEN @@ -2077,9 +2068,7 @@ } if (info->count) { DBG_CNT("before DEC-2"); - MOD_DEC_USE_COUNT; - restore_flags(flags); - return; + goto out; } info->flags |= ASYNC_CLOSING; /* @@ -2140,7 +2129,7 @@ info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE| ASYNC_CLOSING); wake_up_interruptible(&info->close_wait); - MOD_DEC_USE_COUNT; +out: MOD_DEC_USE_COUNT; restore_flags(flags); } @@ -2360,7 +2349,6 @@ { struct esp_struct *info; int retval, line; - unsigned long page; line = MINOR(tty->device) - tty->driver.minor_start; if ((line < 0) || (line >= NR_PORTS)) @@ -2388,13 +2376,9 @@ info->tty = tty; if (!tmp_buf) { - page = get_free_page(GFP_KERNEL); - if (!page) + tmp_buf = (unsigned char *) get_free_page(GFP_KERNEL); + if (!tmp_buf) return -ENOMEM; - if (tmp_buf) - free_page(page); - else - tmp_buf = (unsigned char *) page; } /* @@ -2613,8 +2597,7 @@ return 1; } - info = (struct esp_struct *)kmalloc(sizeof(struct esp_struct), - GFP_KERNEL); + info = kmalloc(sizeof(struct esp_struct), GFP_KERNEL); if (!info) { @@ -2685,8 +2668,7 @@ if (!dma) info->stat_flags |= ESP_STAT_NEVER_DMA; - info = (struct esp_struct *)kmalloc(sizeof(struct esp_struct), - GFP_KERNEL); + info = kmalloc(sizeof(struct esp_struct), GFP_KERNEL); if (!info) { printk(KERN_ERR "Couldn't allocate memory for esp serial device information\n"); @@ -2714,14 +2696,7 @@ return 0; } -#ifdef MODULE - -int init_module(void) -{ - return espserial_init(); -} - -void cleanup_module(void) +static void __exit espserial_exit(void) { unsigned long flags; int e1, e2; @@ -2782,4 +2757,6 @@ free_pio_buf = pio_buf; } } -#endif /* MODULE */ + +module_init(espserial_init); +module_exit(espserial_exit); diff -u --recursive --new-file v2.4.6/linux/drivers/char/generic_serial.c linux/drivers/char/generic_serial.c --- v2.4.6/linux/drivers/char/generic_serial.c Fri Dec 29 14:35:47 2000 +++ linux/drivers/char/generic_serial.c Wed Jul 4 14:41:33 2001 @@ -344,7 +344,7 @@ struct gs_port *port = ptr; long end_jiffies; int jiffies_to_transmit, charsleft = 0, rv = 0; - int to, rcib; + int rcib; func_enter(); @@ -368,6 +368,7 @@ return rv; } /* stop trying: now + twice the time it would normally take + seconds */ + if (timeout == 0) timeout = MAX_SCHEDULE_TIMEOUT; end_jiffies = jiffies; if (timeout != MAX_SCHEDULE_TIMEOUT) end_jiffies += port->baud?(2 * rcib * 10 * HZ / port->baud):0; @@ -376,11 +377,9 @@ gs_dprintk (GS_DEBUG_FLUSH, "now=%lx, end=%lx (%ld).\n", jiffies, end_jiffies, end_jiffies-jiffies); - to = 100; /* the expression is actually jiffies < end_jiffies, but that won't work around the wraparound. Tricky eh? */ - while (to-- && - (charsleft = gs_real_chars_in_buffer (port->tty)) && + while ((charsleft = gs_real_chars_in_buffer (port->tty)) && time_after (end_jiffies, jiffies)) { /* Units check: chars * (bits/char) * (jiffies /sec) / (bits/sec) = jiffies! @@ -1059,6 +1058,19 @@ copy_to_user(sp, &sio, sizeof(struct serial_struct)); } + +void gs_got_break(struct gs_port *port) +{ + if (port->flags & ASYNC_SAK) { + do_SAK (port->tty); + } + *(port->tty->flip.flag_buf_ptr) = TTY_BREAK; + port->tty->flip.flag_buf_ptr++; + port->tty->flip.char_buf_ptr++; + port->tty->flip.count++; +} + + EXPORT_SYMBOL(gs_put_char); EXPORT_SYMBOL(gs_write); EXPORT_SYMBOL(gs_write_room); @@ -1075,4 +1087,4 @@ EXPORT_SYMBOL(gs_init_port); EXPORT_SYMBOL(gs_setserial); EXPORT_SYMBOL(gs_getserial); - +EXPORT_SYMBOL(gs_got_break); diff -u --recursive --new-file v2.4.6/linux/drivers/char/h8.c linux/drivers/char/h8.c --- v2.4.6/linux/drivers/char/h8.c Wed Jul 12 21:58:42 2000 +++ linux/drivers/char/h8.c Wed Jul 4 14:41:33 2001 @@ -54,9 +54,9 @@ /* * Forward declarations. */ -static int h8_init(void); -int h8_display_blank(void); -int h8_display_unblank(void); +static int h8_init(void); +static int h8_display_blank(void); +static int h8_display_unblank(void); static void h8_intr(int irq, void *dev_id, struct pt_regs *regs); @@ -106,10 +106,10 @@ static char driver_version[] = "X0.0";/* no spaces */ -union intr_buf intrbuf; -int intr_buf_ptr; -union intr_buf xx; -u_char last_temp; +static union intr_buf intrbuf; +static int intr_buf_ptr; +static union intr_buf xx; +static u_char last_temp; /* * I/O Macros for register reads and writes. @@ -122,40 +122,40 @@ #define WRITE_DATA(d) H8_WRITE((d), h8_base + H8_DATA_REG_OFF) #define WRITE_CMD(d) H8_WRITE((d), h8_base + H8_CMD_REG_OFF) -unsigned int h8_base = H8_BASE_ADDR; -unsigned int h8_irq = H8_IRQ; -unsigned int h8_state = H8_IDLE; -unsigned int h8_index = -1; -unsigned int h8_enabled = 0; - -LIST_HEAD(h8_actq); -LIST_HEAD(h8_cmdq); -LIST_HEAD(h8_freeq); +static unsigned int h8_base = H8_BASE_ADDR; +static unsigned int h8_irq = H8_IRQ; +static unsigned int h8_state = H8_IDLE; +static unsigned int h8_index = -1; +static unsigned int h8_enabled = 0; + +static LIST_HEAD(h8_actq); +static LIST_HEAD(h8_cmdq); +static LIST_HEAD(h8_freeq); /* * Globals used in thermal control of Alphabook1. */ -int cpu_speed_divisor = -1; -int h8_event_mask = 0; -DECLARE_WAIT_QUEUE_HEAD(h8_monitor_wait); -unsigned int h8_command_mask = 0; -int h8_uthermal_threshold = DEFAULT_UTHERMAL_THRESHOLD; -int h8_uthermal_window = UTH_HYSTERESIS; -int h8_debug = 0xfffffdfc; -int h8_ldamp = MHZ_115; -int h8_udamp = MHZ_57; -u_char h8_current_temp = 0; -u_char h8_system_temp = 0; -int h8_sync_channel = 0; -DECLARE_WAIT_QUEUE_HEAD(h8_sync_wait); -int h8_init_performed; +static int cpu_speed_divisor = -1; +static int h8_event_mask = 0; +static DECLARE_WAIT_QUEUE_HEAD(h8_monitor_wait); +static unsigned int h8_command_mask = 0; +static int h8_uthermal_threshold = DEFAULT_UTHERMAL_THRESHOLD; +static int h8_uthermal_window = UTH_HYSTERESIS; +static int h8_debug = 0xfffffdfc; +static int h8_ldamp = MHZ_115; +static int h8_udamp = MHZ_57; +static u_char h8_current_temp = 0; +static u_char h8_system_temp = 0; +static int h8_sync_channel = 0; +static DECLARE_WAIT_QUEUE_HEAD(h8_sync_wait); +static int h8_init_performed; /* CPU speeds and clock divisor values */ -int speed_tab[6] = {230, 153, 115, 57, 28, 14}; +static int speed_tab[6] = {230, 153, 115, 57, 28, 14}; /* * H8 interrupt handler - */ + */ static void h8_intr(int irq, void *dev_id, struct pt_regs *regs) { u_char stat_reg, data_reg; @@ -377,7 +377,7 @@ } /* Called from console driver -- must make sure h8_enabled. */ -int h8_display_blank(void) +static int h8_display_blank(void) { #ifdef CONFIG_H8_DISPLAY_BLANK int error; @@ -393,7 +393,7 @@ } /* Called from console driver -- must make sure h8_enabled. */ -int h8_display_unblank(void) +static int h8_display_unblank(void) { #ifdef CONFIG_H8_DISPLAY_BLANK int error; @@ -408,8 +408,7 @@ return 0; } -int -h8_alloc_queues(void) +static int h8_alloc_queues(void) { h8_cmd_q_t *qp; unsigned long flags; @@ -419,7 +418,7 @@ GFP_KERNEL); if (!qp) { - printk("H8: could not allocate memory for command queue\n"); + printk(KERN_ERR "H8: could not allocate memory for command queue\n"); return(0); } /* add to the free queue */ @@ -560,14 +559,14 @@ { if(h8_debug & 0x200) - printk("h8_read_event_status: value 0x%x\n", intrbuf.word); + printk(KERN_DEBUG "h8_read_event_status: value 0x%x\n", intrbuf.word); /* * Power related items */ if (intrbuf.word & H8_DC_CHANGE) { if(h8_debug & 0x4) - printk("h8_read_event_status: DC_CHANGE\n"); + printk(KERN_DEBUG "h8_read_event_status: DC_CHANGE\n"); /* see if dc added or removed, set batt/dc flag, send event */ h8_set_event_mask(H8_MANAGE_BATTERY); @@ -575,7 +574,7 @@ } if (intrbuf.word & H8_POWER_BUTTON) { - printk("Power switch pressed - please wait - preparing to power + printk(KERN_CRIT "Power switch pressed - please wait - preparing to power off\n"); h8_set_event_mask(H8_POWER_BUTTON); wake_up(&h8_monitor_wait); @@ -586,7 +585,7 @@ */ if (intrbuf.word & H8_THERMAL_THRESHOLD) { if(h8_debug & 0x4) - printk("h8_read_event_status: THERMAL_THRESHOLD\n"); + printk(KERN_DEBUG "h8_read_event_status: THERMAL_THRESHOLD\n"); h8_set_event_mask(H8_MANAGE_UTHERM); wake_up(&h8_monitor_wait); } @@ -596,67 +595,67 @@ */ if (intrbuf.word & H8_DOCKING_STATION_STATUS) { if(h8_debug & 0x4) - printk("h8_read_event_status: DOCKING_STATION_STATUS\n"); + printk(KERN_DEBUG "h8_read_event_status: DOCKING_STATION_STATUS\n"); /* read_ext_status */ } if (intrbuf.word & H8_EXT_BATT_STATUS) { if(h8_debug & 0x4) - printk("h8_read_event_status: EXT_BATT_STATUS\n"); + printk(KERN_DEBUG "h8_read_event_status: EXT_BATT_STATUS\n"); } if (intrbuf.word & H8_EXT_BATT_CHARGE_STATE) { if(h8_debug & 0x4) - printk("h8_read_event_status: EXT_BATT_CHARGE_STATE\n"); + printk(KERN_DEBUG "h8_read_event_status: EXT_BATT_CHARGE_STATE\n"); } if (intrbuf.word & H8_BATT_CHANGE_OVER) { if(h8_debug & 0x4) - printk("h8_read_event_status: BATT_CHANGE_OVER\n"); + printk(KERN_DEBUG "h8_read_event_status: BATT_CHANGE_OVER\n"); } if (intrbuf.word & H8_WATCHDOG) { if(h8_debug & 0x4) - printk("h8_read_event_status: WATCHDOG\n"); + printk(KERN_DEBUG "h8_read_event_status: WATCHDOG\n"); /* nop */ } if (intrbuf.word & H8_SHUTDOWN) { if(h8_debug & 0x4) - printk("h8_read_event_status: SHUTDOWN\n"); + printk(KERN_DEBUG "h8_read_event_status: SHUTDOWN\n"); /* nop */ } if (intrbuf.word & H8_KEYBOARD) { if(h8_debug & 0x4) - printk("h8_read_event_status: KEYBOARD\n"); + printk(KERN_DEBUG "h8_read_event_status: KEYBOARD\n"); /* nop */ } if (intrbuf.word & H8_EXT_MOUSE_OR_CASE_SWITCH) { if(h8_debug & 0x4) - printk("h8_read_event_status: EXT_MOUSE_OR_CASE_SWITCH\n"); + printk(KERN_DEBUG "h8_read_event_status: EXT_MOUSE_OR_CASE_SWITCH\n"); /* read_ext_status*/ } if (intrbuf.word & H8_INT_BATT_LOW) { if(h8_debug & 0x4) - printk("h8_read_event_status: INT_BATT_LOW\n"); - /* post event, warn user */ + printk(KERN_DEBUG "h8_read_event_status: INT_BATT_LOW\n"); post + /* event, warn user */ } if (intrbuf.word & H8_INT_BATT_CHARGE_STATE) { if(h8_debug & 0x4) - printk("h8_read_event_status: INT_BATT_CHARGE_STATE\n"); + printk(KERN_DEBUG "h8_read_event_status: INT_BATT_CHARGE_STATE\n"); /* nop - happens often */ } if (intrbuf.word & H8_INT_BATT_STATUS) { if(h8_debug & 0x4) - printk("h8_read_event_status: INT_BATT_STATUS\n"); + printk(KERN_DEBUG "h8_read_event_status: INT_BATT_STATUS\n"); } if (intrbuf.word & H8_INT_BATT_CHARGE_THRESHOLD) { if(h8_debug & 0x4) - printk("h8_read_event_status: INT_BATT_CHARGE_THRESHOLD\n"); + printk(KERN_DEBUG "h8_read_event_status: INT_BATT_CHARGE_THRESHOLD\n"); /* nop - happens often */ } if (intrbuf.word & H8_EXT_BATT_LOW) { if(h8_debug & 0x4) - printk("h8_read_event_status: EXT_BATT_LOW\n"); + printk(KERN_DEBUG "h8_read_event_status: EXT_BATT_LOW\n"); /*if no internal, post event, warn user */ /* else nop */ } @@ -667,7 +666,7 @@ /* * Function called when H8 has performed requested command. */ -void +static void h8_cmd_done(h8_cmd_q_t *qp) { @@ -675,14 +674,14 @@ switch (qp->cmdbuf[0]) { case H8_SYNC: if (h8_debug & 0x40000) - printk("H8: Sync command done - byte returned was 0x%x\n", + printk(KERN_DEBUG "H8: Sync command done - byte returned was 0x%x\n", qp->rcvbuf[0]); list_add(&qp->link, &h8_freeq); break; case H8_RD_SN: case H8_RD_ENET_ADDR: - printk("H8: read Ethernet address: command done - address: %x - %x - %x - %x - %x - %x \n", + printk(KERN_DEBUG "H8: read Ethernet address: command done - address: %x - %x - %x - %x - %x - %x \n", qp->rcvbuf[0], qp->rcvbuf[1], qp->rcvbuf[2], qp->rcvbuf[3], qp->rcvbuf[4], qp->rcvbuf[5]); list_add(&qp->link, &h8_freeq); @@ -691,13 +690,13 @@ case H8_RD_HW_VER: case H8_RD_MIC_VER: case H8_RD_MAX_TEMP: - printk("H8: Max recorded CPU temp %d, Sys temp %d\n", + printk(KERN_DEBUG "H8: Max recorded CPU temp %d, Sys temp %d\n", qp->rcvbuf[0], qp->rcvbuf[1]); list_add(&qp->link, &h8_freeq); break; case H8_RD_MIN_TEMP: - printk("H8: Min recorded CPU temp %d, Sys temp %d\n", + printk(KERN_DEBUG "H8: Min recorded CPU temp %d, Sys temp %d\n", qp->rcvbuf[0], qp->rcvbuf[1]); list_add(&qp->link, &h8_freeq); break; @@ -712,11 +711,11 @@ case H8_RD_SYS_VARIENT: case H8_RD_PWR_ON_CYCLES: - printk(" H8: RD_PWR_ON_CYCLES command done\n"); + printk(KERN_DEBUG " H8: RD_PWR_ON_CYCLES command done\n"); break; case H8_RD_PWR_ON_SECS: - printk("H8: RD_PWR_ON_SECS command done\n"); + printk(KERN_DEBUG "H8: RD_PWR_ON_SECS command done\n"); break; case H8_RD_RESET_STATUS: @@ -741,7 +740,7 @@ case H8_RD_NEW_BUSY_SPEED: case H8_RD_CONFIG_INTERFACE: case H8_RD_INT_BATT_STATUS: - printk("H8: Read int batt status cmd done - returned was %x %x %x\n", + printk(KERN_DEBUG "H8: Read int batt status cmd done - returned was %x %x %x\n", qp->rcvbuf[0], qp->rcvbuf[1], qp->rcvbuf[2]); list_add(&qp->link, &h8_freeq); break; @@ -752,7 +751,7 @@ case H8_CTL_EMU_BITPORT: case H8_DEVICE_CONTROL: if(h8_debug & 0x20000) { - printk("H8: Device control cmd done - byte returned was 0x%x\n", + printk(KERN_DEBUG "H8: Device control cmd done - byte returned was 0x%x\n", qp->rcvbuf[0]); } list_add(&qp->link, &h8_freeq); @@ -767,7 +766,7 @@ case H8_CTL_MOUSE_SENSITIVITY: case H8_CTL_DIAG_MODE: case H8_CTL_IDLE_AND_BUSY_SPDS: - printk("H8: Idle and busy speed command done\n"); + printk(KERN_DEBUG "H8: Idle and busy speed command done\n"); break; case H8_CTL_TFT_BRT_BATT: @@ -808,7 +807,7 @@ case H8_BQ_RD_REG: case H8_BQ_WRT_REG: case H8_PWR_OFF: - printk ("H8: misc command completed\n"); + printk (KERN_DEBUG "H8: misc command completed\n"); break; } return; @@ -948,7 +947,7 @@ */ h8_get_curr_temp(curr_temp); - printk("H8: Initial CPU temp: %d\n", curr_temp[0]); + printk(KERN_INFO "H8: Initial CPU temp: %d\n", curr_temp[0]); if(curr_temp[0] >= h8_uthermal_threshold) { h8_set_event_mask(H8_MANAGE_UTHERM); @@ -965,7 +964,7 @@ sleep_on(&h8_monitor_wait); if(h8_debug & 0x2) - printk("h8_monitor_thread awakened, mask:%x\n", + printk(KERN_DEBUG "h8_monitor_thread awakened, mask:%x\n", h8_event_mask); if (h8_event_mask & (H8_MANAGE_UTHERM|H8_MANAGE_LTHERM)) { @@ -1008,7 +1007,7 @@ if(h8_event_mask & H8_MANAGE_UTHERM) { /* Upper thermal interrupt received, need to cool down. */ if(h8_debug & 0x10) - printk("H8: Thermal threshold %d F reached\n", + printk(KERN_WARNING "H8: Thermal threshold %d F reached\n", h8_uthermal_threshold); h8_set_cpu_speed(h8_udamp); h8_clear_event_mask(H8_MANAGE_UTHERM); @@ -1027,7 +1026,7 @@ h8_set_upper_therm_thold(h8_uthermal_threshold); h8_set_cpu_speed(h8_ldamp); /* adjustable */ if(h8_debug & 0x10) - printk("H8: CPU cool, applying cpu_divisor: %d \n", + printk(KERN_WARNING "H8: CPU cool, applying cpu_divisor: %d \n", h8_ldamp); h8_clear_event_mask(H8_MANAGE_LTHERM); } @@ -1082,7 +1081,7 @@ #endif /* NOT_YET */ if(h8_debug & 0x8) - printk("H8: Setting CPU speed to %d MHz\n", + printk(KERN_DEBUG "H8: Setting CPU speed to %d MHz\n", speed_tab[speed_divisor]); /* Make the actual speed change */ @@ -1125,7 +1124,7 @@ break; } if(h8_debug & 0x8) - printk("H8: CPU speed current setting: %d MHz\n", speed); + printk(KERN_DEBUG "H8: CPU speed current setting: %d MHz\n", speed); #endif /* NOT_YET */ return speed; } diff -u --recursive --new-file v2.4.6/linux/drivers/char/i810-tco.c linux/drivers/char/i810-tco.c --- v2.4.6/linux/drivers/char/i810-tco.c Tue Jul 3 17:08:19 2001 +++ linux/drivers/char/i810-tco.c Wed Jul 11 14:50:47 2001 @@ -261,11 +261,13 @@ */ pci_for_each_dev(dev) { - if (pci_match_device(i810tco_pci_tbl, dev)) + if (pci_match_device(i810tco_pci_tbl, dev)) { + i810tco_pci = dev; break; + } } - if ((i810tco_pci = dev)) { + if (i810tco_pci) { /* * Find the ACPI base I/O address which is the base * for the TCO registers (TCOBASE=ACPIBASE + 0x60) diff -u --recursive --new-file v2.4.6/linux/drivers/char/ip2/i2cmd.c linux/drivers/char/ip2/i2cmd.c --- v2.4.6/linux/drivers/char/ip2/i2cmd.c Mon Apr 24 13:39:35 2000 +++ linux/drivers/char/ip2/i2cmd.c Wed Jul 4 14:41:33 2001 @@ -139,7 +139,7 @@ //static UCHAR ct86[]={ 2, BTH, 0x56,0 }; // RCV_ENABLE static UCHAR ct87[] = { 1, BYP, 0x57 }; // HW_TEST //static UCHAR ct88[]={ 3, BTH, 0x58,0,0 }; // RCV_THRESHOLD -static UCHAR ct89[]={ 1, BYP, 0x59 }; // DSS_NOW +//static UCHAR ct89[]={ 1, BYP, 0x59 }; // DSS_NOW //static UCHAR ct90[]={ 3, BYP, 0x5A,0,0 }; // Set SILO //static UCHAR ct91[]={ 2, BYP, 0x5B,0 }; // timed break diff -u --recursive --new-file v2.4.6/linux/drivers/char/istallion.c linux/drivers/char/istallion.c --- v2.4.6/linux/drivers/char/istallion.c Fri Mar 2 11:12:07 2001 +++ linux/drivers/char/istallion.c Sun Jul 15 16:15:44 2001 @@ -2075,13 +2075,10 @@ (unsigned int *) arg); break; case TIOCSSOFTCAR: - if ((rc = verify_area(VERIFY_READ, (void *) arg, - sizeof(unsigned int))) == 0) { - get_user(ival, (unsigned int *) arg); + if ((rc = get_user(ival, (unsigned int *) arg)) == 0) tty->termios->c_cflag = (tty->termios->c_cflag & ~CLOCAL) | (ival ? CLOCAL : 0); - } break; case TIOCMGET: if ((rc = verify_area(VERIFY_WRITE, (void *) arg, @@ -2094,9 +2091,7 @@ } break; case TIOCMBIS: - if ((rc = verify_area(VERIFY_READ, (void *) arg, - sizeof(unsigned int))) == 0) { - get_user(ival, (unsigned int *) arg); + if ((rc = get_user(ival, (unsigned int *) arg)) == 0) { stli_mkasysigs(&portp->asig, ((ival & TIOCM_DTR) ? 1 : -1), ((ival & TIOCM_RTS) ? 1 : -1)); @@ -2105,9 +2100,7 @@ } break; case TIOCMBIC: - if ((rc = verify_area(VERIFY_READ, (void *) arg, - sizeof(unsigned int))) == 0) { - get_user(ival, (unsigned int *) arg); + if ((rc = get_user(ival, (unsigned int *) arg)) == 0) { stli_mkasysigs(&portp->asig, ((ival & TIOCM_DTR) ? 0 : -1), ((ival & TIOCM_RTS) ? 0 : -1)); @@ -2116,9 +2109,7 @@ } break; case TIOCMSET: - if ((rc = verify_area(VERIFY_READ, (void *) arg, - sizeof(unsigned int))) == 0) { - get_user(ival, (unsigned int *) arg); + if ((rc = get_user(ival, (unsigned int *) arg)) == 0) { stli_mkasysigs(&portp->asig, ((ival & TIOCM_DTR) ? 1 : 0), ((ival & TIOCM_RTS) ? 1 : 0)); @@ -2137,16 +2128,11 @@ rc = stli_setserial(portp, (struct serial_struct *)arg); break; case STL_GETPFLAG: - if ((rc = verify_area(VERIFY_WRITE, (void *) arg, - sizeof(unsigned long))) == 0) - put_user(portp->pflag, (unsigned int *) arg); + rc = put_user(portp->pflag, (unsigned int *) arg); break; case STL_SETPFLAG: - if ((rc = verify_area(VERIFY_READ, (void *) arg, - sizeof(unsigned long))) == 0) { - get_user(portp->pflag, (unsigned int *) arg); + if ((rc = get_user(portp->pflag, (unsigned int *) arg)) == 0) stli_setport(portp); - } break; case COM_GETPORTSTATS: if ((rc = verify_area(VERIFY_WRITE, (void *) arg, @@ -2357,7 +2343,7 @@ stliport_t *portp; #if DEBUG - printk("stli_dohangup(portp=%x)\n", (int) arg); + printk(KERN_DEBUG "stli_dohangup(portp=%x)\n", (int) arg); #endif /* @@ -2390,7 +2376,7 @@ unsigned long flags; #if DEBUG - printk("stli_hangup(tty=%x)\n", (int) tty); + printk(KERN_DEBUG "stli_hangup(tty=%x)\n", (int) tty); #endif if (tty == (struct tty_struct *) NULL) @@ -2448,7 +2434,7 @@ unsigned long ftype, flags; #if DEBUG - printk("stli_flushbuffer(tty=%x)\n", (int) tty); + printk(KERN_DEBUG "stli_flushbuffer(tty=%x)\n", (int) tty); #endif if (tty == (struct tty_struct *) NULL) @@ -2498,7 +2484,7 @@ /* long savestate, savetime; */ #if DEBUG - printk("stli_breakctl(tty=%x,state=%d)\n", (int) tty, state); + printk(KERN_DEBUG "stli_breakctl(tty=%x,state=%d)\n", (int) tty, state); #endif if (tty == (struct tty_struct *) NULL) @@ -2537,7 +2523,7 @@ unsigned long tend; #if DEBUG - printk("stli_waituntilsent(tty=%x,timeout=%x)\n", (int) tty, timeout); + printk(KERN_DEBUG "stli_waituntilsent(tty=%x,timeout=%x)\n", (int) tty, timeout); #endif if (tty == (struct tty_struct *) NULL) @@ -2568,7 +2554,7 @@ asyctrl_t actrl; #if DEBUG - printk("stli_sendxchar(tty=%x,ch=%x)\n", (int) tty, ch); + printk(KERN_DEBUG "stli_sendxchar(tty=%x,ch=%x)\n", (int) tty, ch); #endif if (tty == (struct tty_struct *) NULL) @@ -2675,7 +2661,7 @@ char *pos; #if DEBUG - printk("stli_readproc(page=%x,start=%x,off=%x,count=%d,eof=%x," + printk(KERN_DEBUG "stli_readproc(page=%x,start=%x,off=%x,count=%d,eof=%x," "data=%x\n", (int) page, (int) start, (int) off, count, (int) eof, (int) data); #endif @@ -2751,7 +2737,7 @@ unsigned long flags; #if DEBUG - printk("stli_sendcmd(brdp=%x,portp=%x,cmd=%x,arg=%x,size=%d," + printk(KERN_DEBUG "stli_sendcmd(brdp=%x,portp=%x,cmd=%x,arg=%x,size=%d," "copyback=%d)\n", (int) brdp, (int) portp, (int) cmd, (int) arg, size, copyback); #endif @@ -2760,7 +2746,8 @@ cli(); if (test_bit(ST_CMDING, &portp->state)) { - printk("STALLION: command already busy, cmd=%x!\n", (int) cmd); + printk(KERN_ERR "STALLION: command already busy, cmd=%x!\n", + (int) cmd); restore_flags(flags); return; } @@ -2804,7 +2791,8 @@ unsigned int len, stlen; #if DEBUG - printk("stli_read(brdp=%x,portp=%d)\n", (int) brdp, (int) portp); + printk(KERN_DEBUG "stli_read(brdp=%x,portp=%d)\n", + (int) brdp, (int) portp); #endif if (test_bit(ST_RXSTOP, &portp->state)) @@ -2920,7 +2908,8 @@ int rc, donerx; #if DEBUG - printk("stli_hostcmd(brdp=%x,channr=%d)\n", (int) brdp, channr); + printk(KERN_DEBUG "stli_hostcmd(brdp=%x,channr=%d)\n", + (int) brdp, channr); #endif ap = (volatile cdkasy_t *) EBRDGETMEMPTR(brdp, portp->addr); @@ -3177,7 +3166,7 @@ static void stli_mkasyport(stliport_t *portp, asyport_t *pp, struct termios *tiosp) { #if DEBUG - printk("stli_mkasyport(portp=%x,pp=%x,tiosp=%d)\n", + printk(KERN_DEBUG "stli_mkasyport(portp=%x,pp=%x,tiosp=%d)\n", (int) portp, (int) pp, (int) tiosp); #endif @@ -3300,7 +3289,8 @@ static void stli_mkasysigs(asysigs_t *sp, int dtr, int rts) { #if DEBUG - printk("stli_mkasysigs(sp=%x,dtr=%d,rts=%d)\n", (int) sp, dtr, rts); + printk(KERN_DEBUG "stli_mkasysigs(sp=%x,dtr=%d,rts=%d)\n", + (int) sp, dtr, rts); #endif memset(sp, 0, sizeof(asysigs_t)); @@ -3326,7 +3316,7 @@ long tiocm; #if DEBUG - printk("stli_mktiocm(sigvalue=%x)\n", (int) sigvalue); + printk(KERN_DEBUG "stli_mktiocm(sigvalue=%x)\n", (int) sigvalue); #endif tiocm = 0; @@ -3352,7 +3342,7 @@ int i, panelnr, panelport; #if DEBUG - printk("stli_initports(brdp=%x)\n", (int) brdp); + printk(KERN_DEBUG "stli_initports(brdp=%x)\n", (int) brdp); #endif for (i = 0, panelnr = 0, panelport = 0; (i < brdp->nrports); i++) { @@ -3399,7 +3389,7 @@ unsigned long memconf; #if DEBUG - printk("stli_ecpinit(brdp=%d)\n", (int) brdp); + printk(KERN_DEBUG "stli_ecpinit(brdp=%d)\n", (int) brdp); #endif outb(ECP_ATSTOP, (brdp->iobase + ECP_ATCONFR)); @@ -3416,7 +3406,7 @@ static void stli_ecpenable(stlibrd_t *brdp) { #if DEBUG - printk("stli_ecpenable(brdp=%x)\n", (int) brdp); + printk(KERN_DEBUG "stli_ecpenable(brdp=%x)\n", (int) brdp); #endif outb(ECP_ATENABLE, (brdp->iobase + ECP_ATCONFR)); } @@ -3426,7 +3416,7 @@ static void stli_ecpdisable(stlibrd_t *brdp) { #if DEBUG - printk("stli_ecpdisable(brdp=%x)\n", (int) brdp); + printk(KERN_DEBUG "stli_ecpdisable(brdp=%x)\n", (int) brdp); #endif outb(ECP_ATDISABLE, (brdp->iobase + ECP_ATCONFR)); } @@ -3439,14 +3429,14 @@ unsigned char val; #if DEBUG - printk("stli_ecpgetmemptr(brdp=%x,offset=%x)\n", (int) brdp, + printk(KERN_DEBUG "stli_ecpgetmemptr(brdp=%x,offset=%x)\n", (int) brdp, (int) offset); #endif if (offset > brdp->memsize) { - printk("STALLION: shared memory pointer=%x out of range at " - "line=%d(%d), brd=%d\n", (int) offset, line, - __LINE__, brdp->brdnr); + printk(KERN_ERR "STALLION: shared memory pointer=%x out of " + "range at line=%d(%d), brd=%d\n", + (int) offset, line, __LINE__, brdp->brdnr); ptr = 0; val = 0; } else { @@ -3462,7 +3452,7 @@ static void stli_ecpreset(stlibrd_t *brdp) { #if DEBUG - printk("stli_ecpreset(brdp=%x)\n", (int) brdp); + printk(KERN_DEBUG "stli_ecpreset(brdp=%x)\n", (int) brdp); #endif outb(ECP_ATSTOP, (brdp->iobase + ECP_ATCONFR)); @@ -3476,7 +3466,7 @@ static void stli_ecpintr(stlibrd_t *brdp) { #if DEBUG - printk("stli_ecpintr(brdp=%x)\n", (int) brdp); + printk(KERN_DEBUG "stli_ecpintr(brdp=%x)\n", (int) brdp); #endif outb(0x1, brdp->iobase); } @@ -3492,7 +3482,7 @@ unsigned long memconf; #if DEBUG - printk("stli_ecpeiinit(brdp=%x)\n", (int) brdp); + printk(KERN_DEBUG "stli_ecpeiinit(brdp=%x)\n", (int) brdp); #endif outb(0x1, (brdp->iobase + ECP_EIBRDENAB)); @@ -3529,14 +3519,14 @@ unsigned char val; #if DEBUG - printk("stli_ecpeigetmemptr(brdp=%x,offset=%x,line=%d)\n", + printk(KERN_DEBUG "stli_ecpeigetmemptr(brdp=%x,offset=%x,line=%d)\n", (int) brdp, (int) offset, line); #endif if (offset > brdp->memsize) { - printk("STALLION: shared memory pointer=%x out of range at " - "line=%d(%d), brd=%d\n", (int) offset, line, - __LINE__, brdp->brdnr); + printk(KERN_ERR "STALLION: shared memory pointer=%x out of " + "range at line=%d(%d), brd=%d\n", + (int) offset, line, __LINE__, brdp->brdnr); ptr = 0; val = 0; } else { @@ -3586,9 +3576,9 @@ unsigned char val; if (offset > brdp->memsize) { - printk("STALLION: shared memory pointer=%x out of range at " - "line=%d(%d), brd=%d\n", (int) offset, line, - __LINE__, brdp->brdnr); + printk(KERN_ERR "STALLION: shared memory pointer=%x out of " + "range at line=%d(%d), brd=%d\n", + (int) offset, line, __LINE__, brdp->brdnr); ptr = 0; val = 0; } else { @@ -3618,7 +3608,7 @@ static void stli_ecppciinit(stlibrd_t *brdp) { #if DEBUG - printk("stli_ecppciinit(brdp=%x)\n", (int) brdp); + printk(KERN_DEBUG "stli_ecppciinit(brdp=%x)\n", (int) brdp); #endif outb(ECP_PCISTOP, (brdp->iobase + ECP_PCICONFR)); @@ -3635,14 +3625,14 @@ unsigned char val; #if DEBUG - printk("stli_ecppcigetmemptr(brdp=%x,offset=%x,line=%d)\n", + printk(KERN_DEBUG "stli_ecppcigetmemptr(brdp=%x,offset=%x,line=%d)\n", (int) brdp, (int) offset, line); #endif if (offset > brdp->memsize) { - printk("STALLION: shared memory pointer=%x out of range at " - "line=%d(%d), board=%d\n", (int) offset, line, - __LINE__, brdp->brdnr); + printk(KERN_ERR "STALLION: shared memory pointer=%x out of " + "range at line=%d(%d), board=%d\n", + (int) offset, line, __LINE__, brdp->brdnr); ptr = 0; val = 0; } else { @@ -3674,7 +3664,7 @@ unsigned long memconf; #if DEBUG - printk("stli_onbinit(brdp=%d)\n", (int) brdp); + printk(KERN_DEBUG "stli_onbinit(brdp=%d)\n", (int) brdp); #endif outb(ONB_ATSTOP, (brdp->iobase + ONB_ATCONFR)); @@ -3693,7 +3683,7 @@ static void stli_onbenable(stlibrd_t *brdp) { #if DEBUG - printk("stli_onbenable(brdp=%x)\n", (int) brdp); + printk(KERN_DEBUG "stli_onbenable(brdp=%x)\n", (int) brdp); #endif outb((brdp->enabval | ONB_ATENABLE), (brdp->iobase + ONB_ATCONFR)); } @@ -3703,7 +3693,7 @@ static void stli_onbdisable(stlibrd_t *brdp) { #if DEBUG - printk("stli_onbdisable(brdp=%x)\n", (int) brdp); + printk(KERN_DEBUG "stli_onbdisable(brdp=%x)\n", (int) brdp); #endif outb((brdp->enabval | ONB_ATDISABLE), (brdp->iobase + ONB_ATCONFR)); } @@ -3715,14 +3705,14 @@ void *ptr; #if DEBUG - printk("stli_onbgetmemptr(brdp=%x,offset=%x)\n", (int) brdp, + printk(KERN_DEBUG "stli_onbgetmemptr(brdp=%x,offset=%x)\n", (int) brdp, (int) offset); #endif if (offset > brdp->memsize) { - printk("STALLION: shared memory pointer=%x out of range at " - "line=%d(%d), brd=%d\n", (int) offset, line, - __LINE__, brdp->brdnr); + printk(KERN_ERR "STALLION: shared memory pointer=%x out of " + "range at line=%d(%d), brd=%d\n", + (int) offset, line, __LINE__, brdp->brdnr); ptr = 0; } else { ptr = brdp->membase + (offset % ONB_ATPAGESIZE); @@ -3736,7 +3726,7 @@ { #if DEBUG - printk("stli_onbreset(brdp=%x)\n", (int) brdp); + printk(KERN_DEBUG "stli_onbreset(brdp=%x)\n", (int) brdp); #endif outb(ONB_ATSTOP, (brdp->iobase + ONB_ATCONFR)); @@ -3756,7 +3746,7 @@ unsigned long memconf; #if DEBUG - printk("stli_onbeinit(brdp=%d)\n", (int) brdp); + printk(KERN_DEBUG "stli_onbeinit(brdp=%d)\n", (int) brdp); #endif outb(0x1, (brdp->iobase + ONB_EIBRDENAB)); @@ -3778,7 +3768,7 @@ static void stli_onbeenable(stlibrd_t *brdp) { #if DEBUG - printk("stli_onbeenable(brdp=%x)\n", (int) brdp); + printk(KERN_DEBUG "stli_onbeenable(brdp=%x)\n", (int) brdp); #endif outb(ONB_EIENABLE, (brdp->iobase + ONB_EICONFR)); } @@ -3788,7 +3778,7 @@ static void stli_onbedisable(stlibrd_t *brdp) { #if DEBUG - printk("stli_onbedisable(brdp=%x)\n", (int) brdp); + printk(KERN_DEBUG "stli_onbedisable(brdp=%x)\n", (int) brdp); #endif outb(ONB_EIDISABLE, (brdp->iobase + ONB_EICONFR)); } @@ -3801,14 +3791,14 @@ unsigned char val; #if DEBUG - printk("stli_onbegetmemptr(brdp=%x,offset=%x,line=%d)\n", + printk(KERN_DEBUG "stli_onbegetmemptr(brdp=%x,offset=%x,line=%d)\n", (int) brdp, (int) offset, line); #endif if (offset > brdp->memsize) { - printk("STALLION: shared memory pointer=%x out of range at " - "line=%d(%d), brd=%d\n", (int) offset, line, - __LINE__, brdp->brdnr); + printk(KERN_ERR "STALLION: shared memory pointer=%x out of " + "range at line=%d(%d), brd=%d\n", + (int) offset, line, __LINE__, brdp->brdnr); ptr = 0; val = 0; } else { @@ -3828,7 +3818,7 @@ { #if DEBUG - printk("stli_onbereset(brdp=%x)\n", (int) brdp); + printk(KERN_ERR "stli_onbereset(brdp=%x)\n", (int) brdp); #endif outb(ONB_EISTOP, (brdp->iobase + ONB_EICONFR)); @@ -3847,7 +3837,7 @@ { #if DEBUG - printk("stli_bbyinit(brdp=%d)\n", (int) brdp); + printk(KERN_ERR "stli_bbyinit(brdp=%d)\n", (int) brdp); #endif outb(BBY_ATSTOP, (brdp->iobase + BBY_ATCONFR)); @@ -3866,14 +3856,14 @@ unsigned char val; #if DEBUG - printk("stli_bbygetmemptr(brdp=%x,offset=%x)\n", (int) brdp, + printk(KERN_ERR "stli_bbygetmemptr(brdp=%x,offset=%x)\n", (int) brdp, (int) offset); #endif if (offset > brdp->memsize) { - printk("STALLION: shared memory pointer=%x out of range at " - "line=%d(%d), brd=%d\n", (int) offset, line, - __LINE__, brdp->brdnr); + printk(KERN_ERR "STALLION: shared memory pointer=%x out of " + "range at line=%d(%d), brd=%d\n", + (int) offset, line, __LINE__, brdp->brdnr); ptr = 0; val = 0; } else { @@ -3890,7 +3880,7 @@ { #if DEBUG - printk("stli_bbyreset(brdp=%x)\n", (int) brdp); + printk(KERN_DEBUG "stli_bbyreset(brdp=%x)\n", (int) brdp); #endif outb(BBY_ATSTOP, (brdp->iobase + BBY_ATCONFR)); @@ -3909,7 +3899,7 @@ { #if DEBUG - printk("stli_stalinit(brdp=%d)\n", (int) brdp); + printk(KERN_DEBUG "stli_stalinit(brdp=%d)\n", (int) brdp); #endif outb(0x1, brdp->iobase); @@ -3923,14 +3913,14 @@ void *ptr; #if DEBUG - printk("stli_stalgetmemptr(brdp=%x,offset=%x)\n", (int) brdp, + printk(KERN_DEBUG "stli_stalgetmemptr(brdp=%x,offset=%x)\n", (int) brdp, (int) offset); #endif if (offset > brdp->memsize) { - printk("STALLION: shared memory pointer=%x out of range at " - "line=%d(%d), brd=%d\n", (int) offset, line, - __LINE__, brdp->brdnr); + printk(KERN_ERR "STALLION: shared memory pointer=%x out of " + "range at line=%d(%d), brd=%d\n", + (int) offset, line, __LINE__, brdp->brdnr); ptr = 0; } else { ptr = brdp->membase + (offset % STAL_PAGESIZE); @@ -3945,7 +3935,7 @@ volatile unsigned long *vecp; #if DEBUG - printk("stli_stalreset(brdp=%x)\n", (int) brdp); + printk(KERN_DEBUG "stli_stalreset(brdp=%x)\n", (int) brdp); #endif vecp = (volatile unsigned long *) (brdp->membase + 0x30); @@ -3970,7 +3960,7 @@ int panelnr, nrports; #if DEBUG - printk("stli_initecp(brdp=%x)\n", (int) brdp); + printk(KERN_DEBUG "stli_initecp(brdp=%x)\n", (int) brdp); #endif /* @@ -3981,8 +3971,9 @@ brdp->iosize = ECP_IOSIZE; if (check_region(brdp->iobase, brdp->iosize)) - printk("STALLION: Warning, board %d I/O address %x conflicts " - "with another device\n", brdp->brdnr, brdp->iobase); + printk(KERN_ERR "STALLION: Warning, board %d I/O address %x " + "conflicts with another device\n", + brdp->brdnr, brdp->iobase); /* * Based on the specific board type setup the common vars to access @@ -4123,7 +4114,7 @@ int i; #if DEBUG - printk("stli_initonb(brdp=%x)\n", (int) brdp); + printk(KERN_DEBUG "stli_initonb(brdp=%x)\n", (int) brdp); #endif /* @@ -4134,8 +4125,9 @@ brdp->iosize = ONB_IOSIZE; if (check_region(brdp->iobase, brdp->iosize)) - printk("STALLION: Warning, board %d I/O address %x conflicts " - "with another device\n", brdp->brdnr, brdp->iobase); + printk(KERN_ERR "STALLION: Warning, board %d I/O address %x " + "conflicts with another device\n", + brdp->brdnr, brdp->iobase); /* * Based on the specific board type setup the common vars to access @@ -4284,7 +4276,7 @@ int portnr, nrdevs, i, rc; #if DEBUG - printk("stli_startbrd(brdp=%x)\n", (int) brdp); + printk(KERN_DEBUG "stli_startbrd(brdp=%x)\n", (int) brdp); #endif rc = 0; @@ -4304,8 +4296,8 @@ #endif if (nrdevs < (brdp->nrports + 1)) { - printk("STALLION: slave failed to allocate memory for all " - "devices, devices=%d\n", nrdevs); + printk(KERN_ERR "STALLION: slave failed to allocate memory for " + "all devices, devices=%d\n", nrdevs); brdp->nrports = nrdevs - 1; } brdp->nrdevs = nrdevs; @@ -4314,13 +4306,13 @@ brdp->bitsize = (nrdevs + 7) / 8; memp = (volatile cdkmem_t *) hdrp->memp; if (((unsigned long) memp) > brdp->memsize) { - printk("STALLION: corrupted shared memory region?\n"); + printk(KERN_ERR "STALLION: corrupted shared memory region?\n"); rc = -EIO; goto stli_donestartup; } memp = (volatile cdkmem_t *) EBRDGETMEMPTR(brdp, (unsigned long) memp); if (memp->dtype != TYP_ASYNCTRL) { - printk("STALLION: no slave control device found\n"); + printk(KERN_ERR "STALLION: no slave control device found\n"); goto stli_donestartup; } memp++; @@ -4390,7 +4382,7 @@ static int __init stli_brdinit(stlibrd_t *brdp) { #if DEBUG - printk("stli_brdinit(brdp=%x)\n", (int) brdp); + printk(KERN_DEBUG "stli_brdinit(brdp=%x)\n", (int) brdp); #endif stli_brds[brdp->brdnr] = brdp; @@ -4418,24 +4410,25 @@ case BRD_ECH: case BRD_ECHMC: case BRD_ECHPCI: - printk("STALLION: %s board type not supported in this driver\n", - stli_brdnames[brdp->brdtype]); + printk(KERN_ERR "STALLION: %s board type not supported in " + "this driver\n", stli_brdnames[brdp->brdtype]); return(ENODEV); default: - printk("STALLION: board=%d is unknown board type=%d\n", - brdp->brdnr, brdp->brdtype); + printk(KERN_ERR "STALLION: board=%d is unknown board " + "type=%d\n", brdp->brdnr, brdp->brdtype); return(ENODEV); } if ((brdp->state & BST_FOUND) == 0) { - printk("STALLION: %s board not found, board=%d io=%x mem=%x\n", + printk(KERN_ERR "STALLION: %s board not found, board=%d " + "io=%x mem=%x\n", stli_brdnames[brdp->brdtype], brdp->brdnr, brdp->iobase, (int) brdp->memaddr); return(ENODEV); } stli_initports(brdp); - printk("STALLION: %s found, board=%d io=%x mem=%x " + printk(KERN_INFO "STALLION: %s found, board=%d io=%x mem=%x " "nrpanels=%d nrports=%d\n", stli_brdnames[brdp->brdtype], brdp->brdnr, brdp->iobase, (int) brdp->memaddr, brdp->nrpanels, brdp->nrports); @@ -4456,7 +4449,7 @@ int i, foundit; #if DEBUG - printk("stli_eisamemprobe(brdp=%x)\n", (int) brdp); + printk(KERN_DEBUG "stli_eisamemprobe(brdp=%x)\n", (int) brdp); #endif /* @@ -4533,9 +4526,9 @@ if (! foundit) { brdp->memaddr = 0; brdp->membase = 0; - printk("STALLION: failed to probe shared memory region for " - "%s in EISA slot=%d\n", stli_brdnames[brdp->brdtype], - (brdp->iobase >> 12)); + printk(KERN_ERR "STALLION: failed to probe shared memory " + "region for %s in EISA slot=%d\n", + stli_brdnames[brdp->brdtype], (brdp->iobase >> 12)); return(-ENODEV); } return(0); @@ -4560,7 +4553,7 @@ int i; #if DEBUG - printk("stli_findeisabrds()\n"); + printk(KERN_DEBUG "stli_findeisabrds()\n"); #endif /* @@ -4656,8 +4649,8 @@ stlibrd_t *brdp; #if DEBUG - printk("stli_initpcibrd(brdtype=%d,busnr=%x,devnr=%x)\n", brdtype, - dev->bus->number, dev->devfn); + printk(KERN_DEBUG "stli_initpcibrd(brdtype=%d,busnr=%x,devnr=%x)\n", + brdtype, dev->bus->number, dev->devfn); #endif if (pci_enable_device(devp)) @@ -4665,14 +4658,14 @@ if ((brdp = stli_allocbrd()) == (stlibrd_t *) NULL) return(-ENOMEM); if ((brdp->brdnr = stli_getbrdnr()) < 0) { - printk("STALLION: too many boards found, " + printk(KERN_INFO "STALLION: too many boards found, " "maximum supported %d\n", STL_MAXBRDS); return(0); } brdp->brdtype = brdtype; #if DEBUG - printk("%s(%d): BAR[]=%lx,%lx,%lx,%lx\n", __FILE__, __LINE__, + printk(KERN_DEBUG "%s(%d): BAR[]=%lx,%lx,%lx,%lx\n", __FILE__, __LINE__, pci_resource_start(devp, 0), pci_resource_start(devp, 1), pci_resource_start(devp, 2), @@ -4732,8 +4725,8 @@ brdp = (stlibrd_t *) stli_memalloc(sizeof(stlibrd_t)); if (brdp == (stlibrd_t *) NULL) { - printk("STALLION: failed to allocate memory (size=%d)\n", - sizeof(stlibrd_t)); + printk(KERN_ERR "STALLION: failed to allocate memory " + "(size=%d)\n", sizeof(stlibrd_t)); return((stlibrd_t *) NULL); } @@ -4756,12 +4749,12 @@ int i, j; #if DEBUG - printk("stli_initbrds()\n"); + printk(KERN_DEBUG "stli_initbrds()\n"); #endif if (stli_nrbrds > STL_MAXBRDS) { - printk("STALLION: too many boards in configuration table, " - "truncating to %d\n", STL_MAXBRDS); + printk(KERN_INFO "STALLION: too many boards in configuration " + "table, truncating to %d\n", STL_MAXBRDS); stli_nrbrds = STL_MAXBRDS; } @@ -4854,8 +4847,8 @@ int brdnr, size, n; #if DEBUG - printk("stli_memread(fp=%x,buf=%x,count=%x,offp=%x)\n", (int) fp, - (int) buf, count, (int) offp); + printk(KERN_DEBUG "stli_memread(fp=%x,buf=%x,count=%x,offp=%x)\n", + (int) fp, (int) buf, count, (int) offp); #endif brdnr = MINOR(fp->f_dentry->d_inode->i_rdev); @@ -4905,8 +4898,8 @@ int brdnr, size, n; #if DEBUG - printk("stli_memwrite(fp=%x,buf=%x,count=%x,offp=%x)\n", (int) fp, - (int) buf, count, (int) offp); + printk(KERN_DEBUG "stli_memwrite(fp=%x,buf=%x,count=%x,offp=%x)\n", + (int) fp, (int) buf, count, (int) offp); #endif brdnr = MINOR(fp->f_dentry->d_inode->i_rdev); @@ -4951,7 +4944,8 @@ stlibrd_t *brdp; int i; - copy_from_user(&stli_brdstats, bp, sizeof(combrd_t)); + if (copy_from_user(&stli_brdstats, bp, sizeof(combrd_t))) + return -EFAULT; if (stli_brdstats.brd >= STL_MAXBRDS) return(-ENODEV); brdp = stli_brds[stli_brdstats.brd]; @@ -4973,7 +4967,8 @@ stli_brdstats.panels[i].nrports = brdp->panels[i]; } - copy_to_user(bp, &stli_brdstats, sizeof(combrd_t)); + if (copy_to_user(bp, &stli_brdstats, sizeof(combrd_t))) + return -EFAULT; return(0); } @@ -5089,7 +5084,8 @@ int rc; if (portp == (stliport_t *) NULL) { - copy_from_user(&stli_comstats, cp, sizeof(comstats_t)); + if (copy_from_user(&stli_comstats, cp, sizeof(comstats_t))) + return -EFAULT; portp = stli_getport(stli_comstats.brd, stli_comstats.panel, stli_comstats.port); if (portp == (stliport_t *) NULL) @@ -5103,8 +5099,8 @@ if ((rc = stli_portcmdstats(portp)) < 0) return(rc); - copy_to_user(cp, &stli_comstats, sizeof(comstats_t)); - return(0); + return copy_to_user(cp, &stli_comstats, sizeof(comstats_t)) ? + -EFAULT : 0; } /*****************************************************************************/ @@ -5119,7 +5115,8 @@ int rc; if (portp == (stliport_t *) NULL) { - copy_from_user(&stli_comstats, cp, sizeof(comstats_t)); + if (copy_from_user(&stli_comstats, cp, sizeof(comstats_t))) + return -EFAULT; portp = stli_getport(stli_comstats.brd, stli_comstats.panel, stli_comstats.port); if (portp == (stliport_t *) NULL) @@ -5140,7 +5137,8 @@ stli_comstats.panel = portp->panelnr; stli_comstats.port = portp->portnr; - copy_to_user(cp, &stli_comstats, sizeof(comstats_t)); + if (copy_to_user(cp, &stli_comstats, sizeof(comstats_t))) + return -EFAULT; return(0); } @@ -5154,12 +5152,14 @@ { stliport_t *portp; - copy_from_user(&stli_dummyport, (void *) arg, sizeof(stliport_t)); + if (copy_from_user(&stli_dummyport, (void *)arg, sizeof(stliport_t))) + return -EFAULT; portp = stli_getport(stli_dummyport.brdnr, stli_dummyport.panelnr, stli_dummyport.portnr); if (portp == (stliport_t *) NULL) return(-ENODEV); - copy_to_user((void *) arg, portp, sizeof(stliport_t)); + if (copy_to_user((void *) arg, portp, sizeof(stliport_t))) + return -EFAULT; return(0); } @@ -5173,13 +5173,15 @@ { stlibrd_t *brdp; - copy_from_user(&stli_dummybrd, (void *) arg, sizeof(stlibrd_t)); + if (copy_from_user(&stli_dummybrd, (void *)arg, sizeof(stlibrd_t))) + return -EFAULT; if ((stli_dummybrd.brdnr < 0) || (stli_dummybrd.brdnr >= STL_MAXBRDS)) return(-ENODEV); brdp = stli_brds[stli_dummybrd.brdnr]; if (brdp == (stlibrd_t *) NULL) return(-ENODEV); - copy_to_user((void *) arg, brdp, sizeof(stlibrd_t)); + if (copy_to_user((void *) arg, brdp, sizeof(stlibrd_t))) + return -EFAULT; return(0); } @@ -5197,8 +5199,8 @@ int brdnr, rc, done; #if DEBUG - printk("stli_memioctl(ip=%x,fp=%x,cmd=%x,arg=%x)\n", (int) ip, - (int) fp, cmd, (int) arg); + printk(KERN_DEBUG "stli_memioctl(ip=%x,fp=%x,cmd=%x,arg=%x)\n", + (int) ip, (int) fp, cmd, (int) arg); #endif /* @@ -5209,39 +5211,25 @@ switch (cmd) { case COM_GETPORTSTATS: - if ((rc = verify_area(VERIFY_WRITE, (void *) arg, - sizeof(comstats_t))) == 0) - rc = stli_getportstats((stliport_t *) NULL, - (comstats_t *) arg); + rc = stli_getportstats((stliport_t *)NULL, (comstats_t *)arg); done++; break; case COM_CLRPORTSTATS: - if ((rc = verify_area(VERIFY_WRITE, (void *) arg, - sizeof(comstats_t))) == 0) - rc = stli_clrportstats((stliport_t *) NULL, - (comstats_t *) arg); + rc = stli_clrportstats((stliport_t *)NULL, (comstats_t *)arg); done++; break; case COM_GETBRDSTATS: - if ((rc = verify_area(VERIFY_WRITE, (void *) arg, - sizeof(combrd_t))) == 0) - rc = stli_getbrdstats((combrd_t *) arg); + rc = stli_getbrdstats((combrd_t *) arg); done++; break; case COM_READPORT: - if ((rc = verify_area(VERIFY_WRITE, (void *) arg, - sizeof(stliport_t))) == 0) - rc = stli_getportstruct(arg); + rc = stli_getportstruct(arg); done++; break; case COM_READBOARD: - if ((rc = verify_area(VERIFY_WRITE, (void *) arg, - sizeof(stlibrd_t))) == 0) - rc = stli_getbrdstruct(arg); + rc = stli_getbrdstruct(arg); done++; break; - default: - break; } if (done) @@ -5299,19 +5287,20 @@ */ stli_tmpwritebuf = (char *) stli_memalloc(STLI_TXBUFSIZE); if (stli_tmpwritebuf == (char *) NULL) - printk("STALLION: failed to allocate memory (size=%d)\n", - STLI_TXBUFSIZE); - stli_txcookbuf = (char *) stli_memalloc(STLI_TXBUFSIZE); + printk(KERN_ERR "STALLION: failed to allocate memory " + "(size=%d)\n", STLI_TXBUFSIZE); + stli_txcookbuf = stli_memalloc(STLI_TXBUFSIZE); if (stli_txcookbuf == (char *) NULL) - printk("STALLION: failed to allocate memory (size=%d)\n", - STLI_TXBUFSIZE); + printk(KERN_ERR "STALLION: failed to allocate memory " + "(size=%d)\n", STLI_TXBUFSIZE); /* * Set up a character driver for the shared memory region. We need this * to down load the slave code image. Also it is a useful debugging tool. */ if (devfs_register_chrdev(STL_SIOMEMMAJOR, "staliomem", &stli_fsiomem)) - printk("STALLION: failed to register serial memory device\n"); + printk(KERN_ERR "STALLION: failed to register serial memory " + "device\n"); devfs_handle = devfs_mk_dir (NULL, "staliomem", NULL); devfs_register_series (devfs_handle, "%u", 4, DEVFS_FL_DEFAULT, @@ -5366,9 +5355,9 @@ stli_callout.read_proc = 0; if (tty_register_driver(&stli_serial)) - printk("STALLION: failed to register serial driver\n"); + printk(KERN_ERR "STALLION: failed to register serial driver\n"); if (tty_register_driver(&stli_callout)) - printk("STALLION: failed to register callout driver\n"); + printk(KERN_ERR "STALLION: failed to register callout driver\n"); return(0); } diff -u --recursive --new-file v2.4.6/linux/drivers/char/lp.c linux/drivers/char/lp.c --- v2.4.6/linux/drivers/char/lp.c Mon Mar 26 15:41:19 2001 +++ linux/drivers/char/lp.c Wed Jul 18 07:14:01 2001 @@ -609,8 +609,6 @@ /* --- initialisation code ------------------------------------- */ -#ifdef MODULE - static int parport_nr[LP_NO] = { [0 ... LP_NO-1] = LP_PARPORT_UNSPEC }; static char *parport[LP_NO] = { NULL, }; static int reset = 0; @@ -618,21 +616,19 @@ MODULE_PARM(parport, "1-" __MODULE_STRING(LP_NO) "s"); MODULE_PARM(reset, "i"); -#else - -static int parport_nr[LP_NO] = { [0 ... LP_NO-1] = LP_PARPORT_UNSPEC }; -static int reset = 0; - -static int parport_ptr = 0; - -void __init lp_setup(char *str, int *ints) +#ifndef MODULE +static int __init lp_setup (char *str) { - if (!str) { - if (ints[0] == 0 || ints[1] == 0) { + static int parport_ptr; // initially zero + int x; + + if (get_option (&str, &x)) { + if (x == 0) { /* disable driver on "lp=" or "lp=0" */ parport_nr[0] = LP_PARPORT_OFF; } else { - printk(KERN_WARNING "warning: 'lp=0x%x' is deprecated, ignored\n", ints[1]); + printk(KERN_WARNING "warning: 'lp=0x%x' is deprecated, ignored\n", x); + return 0; } } else if (!strncmp(str, "parport", 7)) { int n = simple_strtoul(str+7, NULL, 10); @@ -648,8 +644,8 @@ } else if (!strcmp(str, "reset")) { reset = 1; } + return 1; } - #endif static int lp_register(int nr, struct parport *port) @@ -782,8 +778,7 @@ return 0; } -#ifdef MODULE -int init_module(void) +static int __init lp_init_module (void) { if (parport[0]) { /* The user gave some parameters. Let's see what they were. */ @@ -811,7 +806,7 @@ return lp_init(); } -void cleanup_module(void) +static void lp_cleanup_module (void) { unsigned int offset; @@ -829,4 +824,7 @@ parport_unregister_device(lp_table[offset].dev); } } -#endif + +__setup("lp=", lp_setup); +module_init(lp_init_module); +module_exit(lp_cleanup_module); diff -u --recursive --new-file v2.4.6/linux/drivers/char/machzwd.c linux/drivers/char/machzwd.c --- v2.4.6/linux/drivers/char/machzwd.c Tue May 22 10:23:16 2001 +++ linux/drivers/char/machzwd.c Wed Jul 4 14:41:33 2001 @@ -124,6 +124,7 @@ static int zf_is_open = 0; static int zf_expect_close = 0; static spinlock_t zf_lock; +static spinlock_t zf_port_lock; static struct timer_list zf_timer; static unsigned long next_heartbeat = 0; @@ -140,7 +141,7 @@ #ifndef ZF_DEBUG # define dprintk(format, args...) #else -# define dprintk(format, args...) printk(KERN_DEBUG PFX ":" __FUNCTION__ ":%d: " format, __LINE__ , ## args) +# define dprintk(format, args...) printk(KERN_DEBUG PFX; ":" __FUNCTION__ ":%d: " format, __LINE__ , ## args) #endif @@ -175,7 +176,7 @@ * Just get current counter value */ -inline unsigned short zf_get_timer(unsigned char n) +static inline unsigned short zf_get_timer(unsigned char n) { switch(n){ case WD1: @@ -209,17 +210,20 @@ static void zf_timer_off(void) { unsigned int ctrl_reg = 0; + unsigned long flags; /* stop internal ping */ - del_timer(&zf_timer); + del_timer_sync(&zf_timer); + spin_lock_irqsave(&zf_port_lock, flags); /* stop watchdog timer */ ctrl_reg = zf_get_control(); ctrl_reg |= (ENABLE_WD1|ENABLE_WD2); /* disable wd1 and wd2 */ ctrl_reg &= ~(ENABLE_WD1|ENABLE_WD2); zf_set_control(ctrl_reg); + spin_unlock_irqrestore(&zf_port_lock, flags); - printk(PFX ": Watchdog timer is now disabled\n"); + printk(KERN_INFO PFX ": Watchdog timer is now disabled\n"); } @@ -229,6 +233,9 @@ static void zf_timer_on(void) { unsigned int ctrl_reg = 0; + unsigned long flags; + + spin_lock_irqsave(&zf_port_lock, flags); zf_writeb(PULSE_LEN, 0xff); @@ -246,15 +253,17 @@ ctrl_reg = zf_get_control(); ctrl_reg |= (ENABLE_WD1|zf_action); zf_set_control(ctrl_reg); + spin_unlock_irqrestore(&zf_port_lock, flags); - printk(PFX ": Watchdog timer is now enabled\n"); + printk(KERN_INFO PFX ": Watchdog timer is now enabled\n"); } static void zf_ping(unsigned long data) { unsigned int ctrl_reg = 0; - + unsigned long flags; + zf_writeb(COUNTER_2, 0xff); if(time_before(jiffies, next_heartbeat)){ @@ -265,6 +274,8 @@ * reset event is activated by transition from 0 to 1 on * RESET_WD1 bit and we assume that it is already zero... */ + + spin_lock_irqsave(&zf_port_lock, flags); ctrl_reg = zf_get_control(); ctrl_reg |= RESET_WD1; zf_set_control(ctrl_reg); @@ -272,11 +283,12 @@ /* ...and nothing changes until here */ ctrl_reg &= ~(RESET_WD1); zf_set_control(ctrl_reg); + spin_unlock_irqrestore(&zf_port_lock, flags); zf_timer.expires = jiffies + ZF_HW_TIMEO; add_timer(&zf_timer); }else{ - printk(PFX ": I will reset your machine\n"); + printk(KERN_CRIT PFX ": I will reset your machine\n"); } } @@ -396,7 +408,7 @@ zf_timer_off(); } else { del_timer(&zf_timer); - printk(PFX ": device file closed unexpectedly. Will not stop the WDT!\n"); + printk(KERN_ERR PFX ": device file closed unexpectedly. Will not stop the WDT!\n"); } spin_lock(&zf_lock); @@ -427,9 +439,7 @@ static struct file_operations zf_fops = { -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,34) owner: THIS_MODULE, -#endif read: zf_read, write: zf_write, ioctl: zf_ioctl, @@ -458,19 +468,19 @@ { char *str[] = { "RESET", "SMI", "NMI", "SCI" }; - printk(PFX ": Watchdog using action = %s\n", str[act]); + printk(KERN_INFO PFX ": Watchdog using action = %s\n", str[act]); } -int __init zf_init(void) +static int __init zf_init(void) { int ret; - printk(PFX ": MachZ ZF-Logic Watchdog driver initializing.\n"); + printk(KERN_INFO PFX ": MachZ ZF-Logic Watchdog driver initializing.\n"); ret = zf_get_ZFL_version(); printk("%#x\n", ret); if((!ret) || (ret != 0xffff)){ - printk(PFX ": no ZF-Logic found\n"); + printk(KERN_WARNING PFX ": no ZF-Logic found\n"); return -ENODEV; } @@ -482,6 +492,7 @@ zf_show_action(action); spin_lock_init(&zf_lock); + spin_lock_init(&zf_port_lock); ret = misc_register(&zf_miscdev); if (ret){ @@ -490,22 +501,12 @@ goto out; } -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,3) - if(check_region(ZF_IOBASE, 3)){ -#else if(!request_region(ZF_IOBASE, 3, "MachZ ZFL WDT")){ -#endif - printk(KERN_ERR "cannot reserve I/O ports at %d\n", ZF_IOBASE); ret = -EBUSY; goto no_region; } - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,3) - request_region(ZF_IOBASE, 3, "MachZ ZFL WDT"); -#define __exit -#endif ret = register_reboot_notifier(&zf_notifier); if(ret){ diff -u --recursive --new-file v2.4.6/linux/drivers/char/mem.c linux/drivers/char/mem.c --- v2.4.6/linux/drivers/char/mem.c Sat May 19 18:11:36 2001 +++ linux/drivers/char/mem.c Tue Jul 10 16:07:46 2001 @@ -626,9 +626,6 @@ mda_console_init(); #endif tty_init(); -#ifdef CONFIG_PRINTER - lp_init(); -#endif #ifdef CONFIG_M68K_PRINTER lp_m68k_init(); #endif diff -u --recursive --new-file v2.4.6/linux/drivers/char/moxa.c linux/drivers/char/moxa.c --- v2.4.6/linux/drivers/char/moxa.c Tue May 22 10:23:16 2001 +++ linux/drivers/char/moxa.c Wed Jul 4 14:41:33 2001 @@ -2916,6 +2916,8 @@ unsigned long baseAddr; int i; + if(len > sizeof(moxaBuff)) + return -EINVAL; if(copy_from_user(moxaBuff, tmp, len)) return -EFAULT; baseAddr = moxaBaseAddr[cardno]; diff -u --recursive --new-file v2.4.6/linux/drivers/char/rio/linux_compat.h linux/drivers/char/rio/linux_compat.h --- v2.4.6/linux/drivers/char/rio/linux_compat.h Fri Aug 11 14:51:33 2000 +++ linux/drivers/char/rio/linux_compat.h Wed Jul 4 14:41:33 2001 @@ -16,11 +16,13 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include <asm/hardirq.h> + #define disable(oldspl) save_flags (oldspl) #define restore(oldspl) restore_flags (oldspl) -#define sysbrk(x) kmalloc ((x), GFP_KERNEL) +#define sysbrk(x) kmalloc ((x),in_interrupt()? GFP_ATOMIC : GFP_KERNEL) #define sysfree(p,size) kfree ((p)) #define WBYTE(p,v) writeb(v, &p) diff -u --recursive --new-file v2.4.6/linux/drivers/char/rio/rio_linux.c linux/drivers/char/rio/rio_linux.c --- v2.4.6/linux/drivers/char/rio/rio_linux.c Fri Apr 13 20:26:07 2001 +++ linux/drivers/char/rio/rio_linux.c Wed Jul 4 14:41:33 2001 @@ -58,6 +58,7 @@ #include <linux/pci.h> #include <linux/slab.h> #include <linux/miscdevice.h> +#include <linux/init.h> #include <linux/compatmac.h> #include <linux/generic_serial.h> @@ -165,7 +166,7 @@ /* startuptime */ HZ*2, /* how long to wait for card to run */ /* slowcook */ 0, /* TRUE -> always use line disc. */ /* intrpolltime */ 1, /* The frequency of OUR polls */ - /* breakinterval */ 25, /* x10 mS */ + /* breakinterval */ 25, /* x10 mS XXX: units seem to be 1ms not 10! -- REW*/ /* timer */ 10, /* mS */ /* RtaLoadBase */ 0x7000, /* HostLoadBase */ 0x7C00, @@ -203,11 +204,8 @@ unsigned int cmd, unsigned long arg); static int rio_init_drivers(void); - void my_hd (void *addr, int len); - - static struct tty_driver rio_driver, rio_callout_driver; static struct tty_driver rio_driver2, rio_callout_driver2; @@ -248,14 +246,12 @@ long rio_irqmask = -1; #ifndef TWO_ZERO -#ifdef MODULE MODULE_AUTHOR("Rogier Wolff <R.E.Wolff@bitwizard.nl>, Patrick van de Lageweg <patrick@bitwizard.nl>"); MODULE_DESCRIPTION("RIO driver"); MODULE_PARM(rio_poll, "i"); MODULE_PARM(rio_debug, "i"); MODULE_PARM(rio_irqmask, "i"); #endif -#endif static struct real_driver rio_real_driver = { rio_disable_tx_interrupts, @@ -383,8 +379,8 @@ int rio_ismodem (kdev_t device) { - return (MAJOR (device) != RIO_NORMAL_MAJOR0) && - (MAJOR (device) != RIO_NORMAL_MAJOR1); + return (MAJOR (device) == RIO_NORMAL_MAJOR0) || + (MAJOR (device) == RIO_NORMAL_MAJOR1); } @@ -455,7 +451,6 @@ func_enter (); HostP = (struct Host*)ptr; /* &p->RIOHosts[(long)ptr]; */ - rio_dprintk (RIO_DEBUG_IFLOW, "rio: enter rio_interrupt (%d/%d)\n", irq, HostP->Ivec); @@ -624,8 +619,12 @@ /* Nothing special here... */ static void rio_shutdown_port (void * ptr) { + struct Port *PortP; + func_enter(); + PortP = (struct Port *)ptr; + PortP->gs.tty = NULL; #if 0 port->gs.flags &= ~ GS_ACTIVE; if (!port->gs.tty) { @@ -654,8 +653,14 @@ exit minicom. I expect an "oops". -- REW */ static void rio_hungup (void *ptr) { - func_enter (); + struct Port *PortP; + + func_enter(); + + PortP = (struct Port *)ptr; + PortP->gs.tty = NULL; rio_dec_mod_count (); + func_exit (); } @@ -679,9 +684,8 @@ PortP->gs.count = 0; } - + PortP->gs.tty = NULL; rio_dec_mod_count (); - func_exit (); } @@ -700,24 +704,28 @@ return rc; } +extern int RIOShortCommand(struct rio_info *p, struct Port *PortP, + int command, int len, int arg); static int rio_ioctl (struct tty_struct * tty, struct file * filp, unsigned int cmd, unsigned long arg) { -#if 0 int rc; - struct rio_port *port = tty->driver_data; + struct Port *PortP; int ival; - /* func_enter2(); */ + func_enter(); + PortP = (struct Port *)tty->driver_data; rc = 0; switch (cmd) { +#if 0 case TIOCGSOFTCAR: rc = Put_user(((tty->termios->c_cflag & CLOCAL) ? 1 : 0), (unsigned int *) arg); break; +#endif case TIOCSSOFTCAR: if ((rc = verify_area(VERIFY_READ, (void *) arg, sizeof(int))) == 0) { @@ -730,13 +738,39 @@ case TIOCGSERIAL: if ((rc = verify_area(VERIFY_WRITE, (void *) arg, sizeof(struct serial_struct))) == 0) - gs_getserial(&port->gs, (struct serial_struct *) arg); + gs_getserial(&PortP->gs, (struct serial_struct *) arg); + break; + case TCSBRK: + if ( PortP->State & RIO_DELETED ) { + rio_dprintk (RIO_DEBUG_TTY, "BREAK on deleted RTA\n"); + rc = -EIO; + } else { + if (RIOShortCommand(p, PortP, SBREAK, 2, 250) == RIO_FAIL) { + rio_dprintk (RIO_DEBUG_INTR, "SBREAK RIOShortCommand failed\n"); + rc = -EIO; + } + } + break; + case TCSBRKP: + if ( PortP->State & RIO_DELETED ) { + rio_dprintk (RIO_DEBUG_TTY, "BREAK on deleted RTA\n"); + rc = -EIO; + } else { + int l; + l = arg?arg*100:250; + if (l > 255) l = 255; + if (RIOShortCommand(p, PortP, SBREAK, 2, arg?arg*100:250) == RIO_FAIL) { + rio_dprintk (RIO_DEBUG_INTR, "SBREAK RIOShortCommand failed\n"); + rc = -EIO; + } + } break; case TIOCSSERIAL: if ((rc = verify_area(VERIFY_READ, (void *) arg, sizeof(struct serial_struct))) == 0) - rc = gs_setserial(&port->gs, (struct serial_struct *) arg); + rc = gs_setserial(&PortP->gs, (struct serial_struct *) arg); break; +#if 0 case TIOCMGET: if ((rc = verify_area(VERIFY_WRITE, (void *) arg, sizeof(unsigned int))) == 0) { @@ -768,17 +802,13 @@ ((ival & TIOCM_RTS) ? 1 : 0)); } break; - +#endif default: rc = -ENOIOCTLCMD; break; } - /* func_exit(); */ + func_exit(); return rc; -#else - return -ENOIOCTLCMD; -#endif - } @@ -1029,17 +1059,15 @@ free4:kfree (rio_termios); free3:kfree (p->RIOPortp); free2:kfree (p->RIOHosts); - free1:kfree (p); - free0: - if (p) { - rio_dprintk (RIO_DEBUG_INIT, "Not enough memory! %p %p %p %p %p\n", + free1: + rio_dprintk (RIO_DEBUG_INIT, "Not enough memory! %p %p %p %p %p\n", p, p->RIOHosts, p->RIOPortp, rio_termios, rio_termios); - } + kfree(p); + free0: return -ENOMEM; } -#ifdef MODULE -static void rio_release_drivers(void) +static void __exit rio_release_drivers(void) { func_enter(); tty_unregister_driver (&rio_callout_driver2); @@ -1048,7 +1076,6 @@ tty_unregister_driver (&rio_driver); func_exit(); } -#endif #ifdef TWO_ZERO #define PDEV unsigned char pci_bus, unsigned pci_fun @@ -1101,11 +1128,7 @@ #endif -#ifdef MODULE -#define rio_init init_module -#endif - -int rio_init(void) +static int __init rio_init(void) { int found = 0; int i; @@ -1255,6 +1278,7 @@ hp->Type = RIO_PCI; hp->Copy = rio_pcicopy; hp->Mode = RIO_PCI_BOOT_FROM_RAM; + hp->HostLock = SPIN_LOCK_UNLOCKED; rio_dprintk (RIO_DEBUG_PROBE, "Ivec: %x\n", hp->Ivec); rio_dprintk (RIO_DEBUG_PROBE, "Mode: %x\n", hp->Mode); @@ -1310,6 +1334,7 @@ * Moreover, the ISA card will work with the * special PCI copy anyway. -- REW */ hp->Mode = 0; + hp->HostLock = SPIN_LOCK_UNLOCKED; vpdp = get_VPD_PROM (hp); rio_dprintk (RIO_DEBUG_PROBE, "Got VPD ROM\n"); @@ -1388,8 +1413,7 @@ } -#ifdef MODULE -void cleanup_module(void) +static void __exit rio_exit (void) { int i; struct Host *hp; @@ -1424,9 +1448,9 @@ func_exit(); } -#endif - +module_init(rio_init); +module_exit(rio_exit); /* * Anybody who knows why this doesn't work for me, please tell me -- REW. diff -u --recursive --new-file v2.4.6/linux/drivers/char/rio/rio_linux.h linux/drivers/char/rio/rio_linux.h --- v2.4.6/linux/drivers/char/rio/rio_linux.h Mon Dec 11 12:50:43 2000 +++ linux/drivers/char/rio/rio_linux.h Wed Jul 4 14:41:33 2001 @@ -95,28 +95,27 @@ #if 1 #define rio_spin_lock_irqsave(sem, flags) do { \ rio_dprintk (RIO_DEBUG_SPINLOCK, "spinlockirqsave: %p %s:%d\n", \ - sem, __FILE__, __LINE__);\ - spin_lock_irqsave(sem, flags);\ - } while (0) + sem, __FILE__, __LINE__);\ + spin_lock_irqsave(sem, flags);\ + } while (0) #define rio_spin_unlock_irqrestore(sem, flags) do { \ rio_dprintk (RIO_DEBUG_SPINLOCK, "spinunlockirqrestore: %p %s:%d\n",\ - sem, __FILE__, __LINE__);\ - spin_unlock_irqrestore(sem, flags);\ - } while (0) - + sem, __FILE__, __LINE__);\ + spin_unlock_irqrestore(sem, flags);\ + } while (0) #define rio_spin_lock(sem) do { \ rio_dprintk (RIO_DEBUG_SPINLOCK, "spinlock: %p %s:%d\n",\ - sem, __FILE__, __LINE__);\ - spin_lock(sem);\ - } while (0) + sem, __FILE__, __LINE__);\ + spin_lock(sem);\ + } while (0) #define rio_spin_unlock(sem) do { \ rio_dprintk (RIO_DEBUG_SPINLOCK, "spinunlock: %p %s:%d\n",\ - sem, __FILE__, __LINE__);\ - spin_unlock(sem);\ - } while (0) + sem, __FILE__, __LINE__);\ + spin_unlock(sem);\ + } while (0) #else #define rio_spin_lock_irqsave(sem, flags) \ spin_lock_irqsave(sem, flags) @@ -165,7 +164,7 @@ #define rio_memcpy_fromio memcpy_fromio #endif -#define DEBUG +#define DEBUG 1 /* diff -u --recursive --new-file v2.4.6/linux/drivers/char/rio/rioboot.c linux/drivers/char/rio/rioboot.c --- v2.4.6/linux/drivers/char/rio/rioboot.c Fri Feb 9 11:30:23 2001 +++ linux/drivers/char/rio/rioboot.c Wed Jul 4 14:41:33 2001 @@ -38,6 +38,7 @@ #include <linux/module.h> #include <linux/slab.h> #include <linux/errno.h> +#include <linux/interrupt.h> #include <asm/io.h> #include <asm/system.h> #include <asm/string.h> diff -u --recursive --new-file v2.4.6/linux/drivers/char/rio/riocmd.c linux/drivers/char/rio/riocmd.c --- v2.4.6/linux/drivers/char/rio/riocmd.c Fri Feb 9 11:30:23 2001 +++ linux/drivers/char/rio/riocmd.c Wed Jul 4 14:41:33 2001 @@ -474,17 +474,18 @@ rio_spin_lock_irqsave(&PortP->portSem, flags); switch( RBYTE(PktCmdP->Command) ) { case BREAK_RECEIVED: - rio_dprintk (RIO_DEBUG_CMD, "Received a break!\n"); + rio_dprintk (RIO_DEBUG_CMD, "Received a break!\n"); /* If the current line disc. is not multi-threading and the current processor is not the default, reset rup_intr and return FALSE to ensure that the command packet is not freed. */ /* Call tmgr HANGUP HERE */ /* Fix this later when every thing works !!!! RAMRAJ */ + gs_got_break (PortP); break; case COMPLETE: - rio_dprintk (RIO_DEBUG_CMD, "Command complete on phb %d host %d\n", + rio_dprintk (RIO_DEBUG_CMD, "Command complete on phb %d host %d\n", RBYTE(PktCmdP->PhbNum), HostP-p->RIOHosts); subCommand = 1; switch (RBYTE(PktCmdP->SubCommand)) { @@ -549,6 +550,8 @@ */ if (PortP->gs.tty == NULL) break; + if (PortP->gs.tty->termios == NULL) + break; if (!(PortP->gs.tty->termios->c_cflag & CLOCAL) && ((PortP->State & (RIO_MOPEN|RIO_WOPEN)))) { @@ -623,7 +626,8 @@ struct CmdBlk *CmdBlkP; CmdBlkP = (struct CmdBlk *)sysbrk(sizeof(struct CmdBlk)); - bzero(CmdBlkP, sizeof(struct CmdBlk)); + if (CmdBlkP) + bzero(CmdBlkP, sizeof(struct CmdBlk)); return CmdBlkP; } diff -u --recursive --new-file v2.4.6/linux/drivers/char/rio/riodrvr.h linux/drivers/char/rio/riodrvr.h --- v2.4.6/linux/drivers/char/rio/riodrvr.h Wed May 10 16:56:44 2000 +++ linux/drivers/char/rio/riodrvr.h Wed Jul 4 14:41:33 2001 @@ -33,12 +33,13 @@ #ifndef __riodrvr_h #define __riodrvr_h +#include <asm/param.h> /* for HZ */ + #ifdef SCCS_LABELS static char *_riodrvr_h_sccs_ = "@(#)riodrvr.h 1.3"; #endif #define MEMDUMP_SIZE 32 -#define HZ 100 #define MOD_DISABLE (RIO_NOREAD|RIO_NOWRITE|RIO_NOXPRINT) diff -u --recursive --new-file v2.4.6/linux/drivers/char/rio/rioinit.c linux/drivers/char/rio/rioinit.c --- v2.4.6/linux/drivers/char/rio/rioinit.c Fri Feb 9 11:30:23 2001 +++ linux/drivers/char/rio/rioinit.c Wed Jul 4 14:41:33 2001 @@ -1446,7 +1446,7 @@ } RIODefaultName(p, HostP, rup); } - HostP->UnixRups[rup].RupLock = -1; + HostP->UnixRups[rup].RupLock = SPIN_LOCK_UNLOCKED; } } } diff -u --recursive --new-file v2.4.6/linux/drivers/char/rio/riotable.c linux/drivers/char/rio/riotable.c --- v2.4.6/linux/drivers/char/rio/riotable.c Fri Feb 16 16:02:36 2001 +++ linux/drivers/char/rio/riotable.c Wed Jul 4 14:41:33 2001 @@ -37,6 +37,8 @@ #include <linux/module.h> #include <linux/slab.h> #include <linux/errno.h> +#include <linux/interrupt.h> + #include <asm/io.h> #include <asm/system.h> #include <asm/string.h> @@ -499,7 +501,7 @@ struct Map *HostMapP; struct Port *PortP; int work_done = 0; - unsigned long flags; + unsigned long lock_flags, sem_flags; rio_dprintk (RIO_DEBUG_TABLE, "Delete entry on host %x, rta %x\n", MapP->HostUniqueNum, MapP->RtaUniqueNum); @@ -507,10 +509,10 @@ for ( host=0; host < p->RIONumHosts; host++ ) { HostP = &p->RIOHosts[host]; - rio_spin_lock_irqsave( &HostP->HostLock, flags ); + rio_spin_lock_irqsave( &HostP->HostLock, lock_flags ); if ( (HostP->Flags & RUN_STATE) != RC_RUNNING ) { - rio_spin_unlock_irqrestore(&HostP->HostLock, flags); + rio_spin_unlock_irqrestore(&HostP->HostLock, lock_flags); continue; } @@ -527,7 +529,7 @@ if ( HostMapP->Topology[link].Unit != ROUTE_DISCONNECT ) { rio_dprintk (RIO_DEBUG_TABLE, "Entry is in use and cannot be deleted!\n"); p->RIOError.Error = UNIT_IS_IN_USE; - rio_spin_unlock_irqrestore( &HostP->HostLock, flags); + rio_spin_unlock_irqrestore( &HostP->HostLock, lock_flags); return EBUSY; } } @@ -542,7 +544,7 @@ PortP = p->RIOPortp[port]; rio_dprintk (RIO_DEBUG_TABLE, "Unmap port\n"); - rio_spin_lock_irqsave( &PortP->portSem, flags ); + rio_spin_lock_irqsave( &PortP->portSem, sem_flags ); PortP->Mapped = 0; @@ -600,7 +602,7 @@ WWORD(PortP->PhbP->destination, dest_unit + (dest_port << 8)); } - rio_spin_unlock_irqrestore(&PortP->portSem, flags); + rio_spin_unlock_irqrestore(&PortP->portSem, sem_flags); } } rio_dprintk (RIO_DEBUG_TABLE, "Entry nulled.\n"); @@ -608,7 +610,7 @@ work_done++; } } - rio_spin_unlock_irqrestore(&HostP->HostLock, flags); + rio_spin_unlock_irqrestore(&HostP->HostLock, lock_flags); } /* XXXXX lock me up */ diff -u --recursive --new-file v2.4.6/linux/drivers/char/rio/riotty.c linux/drivers/char/rio/riotty.c --- v2.4.6/linux/drivers/char/rio/riotty.c Fri Feb 9 11:30:23 2001 +++ linux/drivers/char/rio/riotty.c Wed Jul 4 14:41:33 2001 @@ -96,7 +96,7 @@ #endif static void RIOClearUp(struct Port *PortP); -static int RIOShortCommand(struct rio_info *p, struct Port *PortP, +int RIOShortCommand(struct rio_info *p, struct Port *PortP, int command, int len, int arg); @@ -452,8 +452,11 @@ PortP->gs.tty->termios->c_state |= WOPEN; */ PortP->State |= RIO_WOPEN; + rio_spin_unlock_irqrestore(&PortP->portSem, flags); + if (RIODelay (PortP, HUNDRED_MS) == RIO_FAIL) #if 0 if ( sleep((caddr_t)&tp->tm.c_canqo, TTIPRI|PCATCH)) +#endif { /* ** ACTION: verify that this is a good thing @@ -471,7 +474,6 @@ func_exit (); return -EINTR; } -#endif } PortP->State &= ~RIO_WOPEN; } @@ -527,8 +529,10 @@ #endif struct Port *PortP =ptr; /* pointer to the port structure */ int deleted = 0; - int try = 25; - int repeat_this = 0xff; + int try = -1; /* Disable the timeouts by setting them to -1 */ + int repeat_this = -1; /* Congrats to those having 15 years of + uptime! (You get to break the driver.) */ + long end_time; struct tty_struct * tty; unsigned long flags; int Modem; @@ -541,6 +545,12 @@ /* tp = PortP->TtyP;*/ /* Get tty */ tty = PortP->gs.tty; rio_dprintk (RIO_DEBUG_TTY, "TTY is at address 0x%x\n",(int)tty); + + if (PortP->gs.closing_wait) + end_time = jiffies + PortP->gs.closing_wait; + else + end_time = jiffies + MAX_SCHEDULE_TIMEOUT; + Modem = rio_ismodem(tty->device); #if 0 /* What F.CKING cache? Even then, a higly idle multiprocessor, @@ -573,7 +583,8 @@ ** clear the open bits for this device */ PortP->State &= (Modem ? ~RIO_MOPEN : ~RIO_LOPEN); - + PortP->State &= ~RIO_CARR_ON; + PortP->ModemState &= ~MSVR1_CD; /* ** If the device was open as both a Modem and a tty line ** then we need to wimp out here, as the port has not really @@ -605,7 +616,6 @@ */ rio_dprintk (RIO_DEBUG_TTY, "Timeout 1 starts\n"); -#if 0 if (!deleted) while ( (PortP->InUse != NOT_INUSE) && !p->RIOHalted && (PortP->TxBufferIn != PortP->TxBufferOut) ) { @@ -626,7 +636,7 @@ } rio_spin_lock_irqsave(&PortP->portSem, flags); } -#endif + PortP->TxBufferIn = PortP->TxBufferOut = 0; repeat_this = 0xff; @@ -662,7 +672,7 @@ if (!deleted) while (try && (PortP->PortState & PORT_ISOPEN)) { try--; - if (try == 0) { + if (time_after (jiffies, end_time)) { rio_dprintk (RIO_DEBUG_TTY, "Run out of tries - force the bugger shut!\n" ); RIOPreemptiveCmd(p, PortP,FCLOSE); break; @@ -674,7 +684,11 @@ RIOClearUp( PortP ); goto close_end; } - RIODelay_ni(PortP, HUNDRED_MS); + if (RIODelay(PortP, HUNDRED_MS) == RIO_FAIL) { + rio_dprintk (RIO_DEBUG_TTY, "RTA EINTR in delay \n"); + RIOPreemptiveCmd(p, PortP,FCLOSE); + break; + } } rio_spin_lock_irqsave(&PortP->portSem, flags); rio_dprintk (RIO_DEBUG_TTY, "Close: try was %d on completion\n", try ); @@ -779,7 +793,7 @@ ** Other values of len aren't allowed, and will cause ** a panic. */ -static int RIOShortCommand(struct rio_info *p, struct Port *PortP, +int RIOShortCommand(struct rio_info *p, struct Port *PortP, int command, int len, int arg) { PKT *PacketP; diff -u --recursive --new-file v2.4.6/linux/drivers/char/ser_a2232.c linux/drivers/char/ser_a2232.c --- v2.4.6/linux/drivers/char/ser_a2232.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/ser_a2232.c Wed Jul 4 14:41:33 2001 @@ -0,0 +1,880 @@ +/* drivers/char/ser_a2232.c */ + +/* $Id: ser_a2232.c,v 0.4 2000/01/25 12:00:00 ehaase Exp $ */ + +/* Linux serial driver for the Amiga A2232 board */ + +/* This driver is MAINTAINED. Before applying any changes, please contact + * the author. + */ + +/* Copyright (c) 2000-2001 Enver Haase <ehaase@inf.fu-berlin.de> + * alias The A2232 driver project <A2232@gmx.net> + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ +/***************************** Documentation ************************/ +/* + * This driver is in EXPERIMENTAL state. That means I could not find + * someone with five A2232 boards with 35 ports running at 19200 bps + * at the same time and test the machine's behaviour. + * However, I know that you can performance-tweak this driver (see + * the source code). + * One thing to consider is the time this driver consumes during the + * Amiga's vertical blank interrupt. Everything that is to be done + * _IS DONE_ when entering the vertical blank interrupt handler of + * this driver. + * However, it would be more sane to only do the job for only ONE card + * instead of ALL cards at a time; or, more generally, to handle only + * SOME ports instead of ALL ports at a time. + * However, as long as no-one runs into problems I guess I shouldn't + * change the driver as it runs fine for me :) . + * + * Version history of this file: + * 0.4 Resolved licensing issues. + * 0.3 Inclusion in the Linux/m68k tree, small fixes. + * 0.2 Added documentation, minor typo fixes. + * 0.1 Initial release. + * + * TO DO: + * - Handle incoming BREAK events. I guess "Stevens: Advanced + * Programming in the UNIX(R) Environment" is a good reference + * on what is to be done. + * - When installing as a module, don't simply 'printk' text, but + * send it to the TTY used by the user. + * + * THANKS TO: + * - Jukka Marin (65EC02 code). + * - The other NetBSD developers on whose A2232 driver I had a + * pretty close look. However, I didn't copy any code so it + * is okay to put my code under the GPL and include it into + * Linux. + */ +/***************************** End of Documentation *****************/ + +/***************************** Defines ******************************/ +/* + * Enables experimental 115200 (normal) 230400 (turbo) baud rate. + * The A2232 specification states it can only operate at speeds up to + * 19200 bits per second, and I was not able to send a file via + * "sz"/"rz" and a null-modem cable from one A2232 port to another + * at 115200 bits per second. + * However, this might work for you. + */ +#undef A2232_SPEEDHACK +/* + * Default is not to use RTS/CTS so you could be talked to death. + */ +#define A2232_SUPPRESS_RTSCTS_WARNING +/************************* End of Defines ***************************/ + +/***************************** Includes *****************************/ +#include <linux/module.h> + +#include <linux/types.h> +#include <linux/sched.h> +#include <linux/interrupt.h> +#include <linux/kernel.h> +#include <linux/errno.h> + +#include <asm/setup.h> +#include <asm/amigaints.h> +#include <asm/amigahw.h> +#include <linux/zorro.h> +#include <asm/irq.h> +#include <asm/semaphore.h> + +#include <linux/delay.h> + +#include <linux/serial.h> +#include <linux/generic_serial.h> + +#include "ser_a2232.h" +#include "ser_a2232fw.h" +/************************* End of Includes **************************/ + +/***************************** Prototypes ***************************/ +/* Helper functions */ +static __inline__ volatile struct a2232status *a2232stat(unsigned int board, + unsigned int portonboard); +static __inline__ volatile struct a2232memory *a2232mem (unsigned int board); +static __inline__ void a2232_receive_char( struct a2232_port *port, + int ch, int err ); +/* The interrupt service routine */ +static void a2232_vbl_inter(int irq, void *data, struct pt_regs *fp); +/* Initialize the port structures */ +static void a2232_init_portstructs(void); +/* Initialize and register TTY drivers. */ +/* returns 0 IFF successful */ +static int a2232_init_drivers(void); +/* Initialize all A2232 boards; main entry point. */ +int a2232board_init(void); + +/* BEGIN GENERIC_SERIAL PROTOTYPES */ +static void a2232_disable_tx_interrupts(void *ptr); +static void a2232_enable_tx_interrupts(void *ptr); +static void a2232_disable_rx_interrupts(void *ptr); +static void a2232_enable_rx_interrupts(void *ptr); +static int a2232_get_CD(void *ptr); +static void a2232_shutdown_port(void *ptr); +static int a2232_set_real_termios(void *ptr); +static int a2232_chars_in_buffer(void *ptr); +static void a2232_close(void *ptr); +static void a2232_hungup(void *ptr); +/* static void a2232_getserial (void *ptr, struct serial_struct *sp); */ +/* END GENERIC_SERIAL PROTOTYPES */ + +/* Functions that the TTY driver struct expects */ +static int a2232_ioctl(struct tty_struct *tty, struct file *file, + unsigned int cmd, unsigned long arg); +static void a2232_throttle(struct tty_struct *tty); +static void a2232_unthrottle(struct tty_struct *tty); +static int a2232_open(struct tty_struct * tty, struct file * filp); +/************************* End of Prototypes ************************/ + +/***************************** Global variables *********************/ +/*--------------------------------------------------------------------------- + * Interface from generic_serial.c back here + *--------------------------------------------------------------------------*/ +static struct real_driver a2232_real_driver = { + a2232_disable_tx_interrupts, + a2232_enable_tx_interrupts, + a2232_disable_rx_interrupts, + a2232_enable_rx_interrupts, + a2232_get_CD, + a2232_shutdown_port, + a2232_set_real_termios, + a2232_chars_in_buffer, + a2232_close, + a2232_hungup, + NULL /* a2232_getserial */ +}; + +static void *a2232_driver_ID = &a2232_driver_ID; // Some memory address WE own. + +/* Ports structs */ +static struct a2232_port a2232_ports[MAX_A2232_BOARDS*NUMLINES]; + +/* TTY driver structs */ +static struct tty_driver a2232_driver; +static struct tty_driver a2232_callout_driver; + +/* Variables used by the TTY driver */ +static int a2232_refcount; +static struct tty_struct *a2232_table[MAX_A2232_BOARDS*NUMLINES] = { NULL, }; +static struct termios *a2232_termios[MAX_A2232_BOARDS*NUMLINES]; +static struct termios *a2232_termios_locked[MAX_A2232_BOARDS*NUMLINES]; + +/* nr of cards completely (all ports) and correctly configured */ +static int nr_a2232; + +/* zorro_dev structs for the A2232's */ +static struct zorro_dev *zd_a2232[MAX_A2232_BOARDS]; +/***************************** End of Global variables **************/ + +/***************************** Functions ****************************/ +/*** BEGIN OF REAL_DRIVER FUNCTIONS ***/ + +static void a2232_disable_tx_interrupts(void *ptr) +{ + struct a2232_port *port; + volatile struct a2232status *stat; + unsigned long flags; + + port = ptr; + stat = a2232stat(port->which_a2232, port->which_port_on_a2232); + stat->OutDisable = -1; + + /* Does this here really have to be? */ + save_flags(flags); + cli(); + port->gs.flags &= ~GS_TX_INTEN; + restore_flags(flags); +} + +static void a2232_enable_tx_interrupts(void *ptr) +{ + struct a2232_port *port; + volatile struct a2232status *stat; + unsigned long flags; + + port = ptr; + stat = a2232stat(port->which_a2232, port->which_port_on_a2232); + stat->OutDisable = 0; + + /* Does this here really have to be? */ + save_flags(flags); + cli(); + port->gs.flags |= GS_TX_INTEN; + restore_flags(flags); +} + +static void a2232_disable_rx_interrupts(void *ptr) +{ + struct a2232_port *port; + port = ptr; + port->disable_rx = -1; +} + +static void a2232_enable_rx_interrupts(void *ptr) +{ + struct a2232_port *port; + port = ptr; + port->disable_rx = 0; +} + +static int a2232_get_CD(void *ptr) +{ + return ((struct a2232_port *) ptr)->cd_status; +} + +static void a2232_shutdown_port(void *ptr) +{ + struct a2232_port *port; + volatile struct a2232status *stat; + unsigned long flags; + + port = ptr; + stat = a2232stat(port->which_a2232, port->which_port_on_a2232); + + save_flags(flags); + cli(); + + port->gs.flags &= ~GS_ACTIVE; + + if (port->gs.tty && port->gs.tty->termios->c_cflag & HUPCL) { + /* Set DTR and RTS to Low, flush output. + The NetBSD driver "msc.c" does it this way. */ + stat->Command = ( (stat->Command & ~A2232CMD_CMask) | + A2232CMD_Close ); + stat->OutFlush = -1; + stat->Setup = -1; + } + + restore_flags(flags); + + /* After analyzing control flow, I think a2232_shutdown_port + is actually the last call from the system when at application + level someone issues a "echo Hello >>/dev/ttyY0". + Therefore I think the MOD_DEC_USE_COUNT should be here and + not in "a2232_close()". See the comment in "sx.c", too. + If you run into problems, compile this driver into the + kernel instead of compiling it as a module. */ + MOD_DEC_USE_COUNT; +} + +static int a2232_set_real_termios(void *ptr) +{ + unsigned int cflag, baud, chsize, stopb, parity, softflow; + int rate; + int a2232_param, a2232_cmd; + unsigned long flags; + unsigned int i; + struct a2232_port *port = ptr; + volatile struct a2232status *status; + volatile struct a2232memory *mem; + + if (!port->gs.tty || !port->gs.tty->termios) return 0; + + status = a2232stat(port->which_a2232, port->which_port_on_a2232); + mem = a2232mem(port->which_a2232); + + a2232_param = a2232_cmd = 0; + + // get baud rate + baud = port->gs.baud; + if (baud == 0) { + /* speed == 0 -> drop DTR, do nothing else */ + save_flags(flags); + cli(); + // Clear DTR (and RTS... mhhh). + status->Command = ( (status->Command & ~A2232CMD_CMask) | + A2232CMD_Close ); + status->OutFlush = -1; + status->Setup = -1; + + restore_flags(flags); + return 0; + } + + rate = A2232_BAUD_TABLE_NOAVAIL; + for (i=0; i < A2232_BAUD_TABLE_NUM_RATES * 3; i += 3){ + if (a2232_baud_table[i] == baud){ + if (mem->Common.Crystal == A2232_TURBO) rate = a2232_baud_table[i+2]; + else rate = a2232_baud_table[i+1]; + } + } + if (rate == A2232_BAUD_TABLE_NOAVAIL){ + printk("a2232: Board %d Port %d unsupported baud rate: %d baud. Using another.\n",port->which_a2232,port->which_port_on_a2232,baud); + // This is useful for both (turbo or normal) Crystal versions. + rate = A2232PARAM_B9600; + } + a2232_param |= rate; + + cflag = port->gs.tty->termios->c_cflag; + + // get character size + chsize = cflag & CSIZE; + switch (chsize){ + case CS8: a2232_param |= A2232PARAM_8Bit; break; + case CS7: a2232_param |= A2232PARAM_7Bit; break; + case CS6: a2232_param |= A2232PARAM_6Bit; break; + case CS5: a2232_param |= A2232PARAM_5Bit; break; + default: printk("a2232: Board %d Port %d unsupported character size: %d. Using 8 data bits.\n", + port->which_a2232,port->which_port_on_a2232,chsize); + a2232_param |= A2232PARAM_8Bit; break; + } + + // get number of stop bits + stopb = cflag & CSTOPB; + if (stopb){ // two stop bits instead of one + printk("a2232: Board %d Port %d 2 stop bits unsupported. Using 1 stop bit.\n", + port->which_a2232,port->which_port_on_a2232); + } + + // Warn if RTS/CTS not wanted + if (!(cflag & CRTSCTS)){ +#ifndef A2232_SUPPRESS_RTSCTS_WARNING + printk("a2232: Board %d Port %d cannot switch off firmware-implemented RTS/CTS hardware flow control.\n", + port->which_a2232,port->which_port_on_a2232); +#endif + } + + /* I think this is correct. + However, IXOFF means _input_ flow control and I wonder + if one should care about IXON _output_ flow control, + too. If this makes problems, one should turn the A2232 + firmware XON/XOFF "SoftFlow" flow control off and use + the conventional way of inserting START/STOP characters + by hand in throttle()/unthrottle(). + */ + softflow = !!( port->gs.tty->termios->c_iflag & IXOFF ); + + // get Parity (Enabled/Disabled? If Enabled, Odd or Even?) + parity = cflag & (PARENB | PARODD); + if (parity & PARENB){ + if (parity & PARODD){ + a2232_cmd |= A2232CMD_OddParity; + } + else{ + a2232_cmd |= A2232CMD_EvenParity; + } + } + else a2232_cmd |= A2232CMD_NoParity; + + + /* Hmm. Maybe an own a2232_port structure + member would be cleaner? */ + if (cflag & CLOCAL) + port->gs.flags &= ~ASYNC_CHECK_CD; + else + port->gs.flags |= ASYNC_CHECK_CD; + + + /* Now we have all parameters and can go to set them: */ + save_flags(flags); + cli(); + + status->Param = a2232_param | A2232PARAM_RcvBaud; + status->Command = a2232_cmd | A2232CMD_Open | A2232CMD_Enable; + status->SoftFlow = softflow; + status->OutDisable = 0; + status->Setup = -1; + + restore_flags(flags); + return 0; +} + +static int a2232_chars_in_buffer(void *ptr) +{ + struct a2232_port *port; + volatile struct a2232status *status; + unsigned char ret; /* we need modulo-256 arithmetics */ + port = ptr; + status = a2232stat(port->which_a2232, port->which_port_on_a2232); +#if A2232_IOBUFLEN != 256 +#error "Re-Implement a2232_chars_in_buffer()!" +#endif + ret = (status->OutHead - status->OutTail); + return ret; +} + +static void a2232_close(void *ptr) +{ + a2232_disable_tx_interrupts(ptr); + a2232_disable_rx_interrupts(ptr); + /* see the comment in a2232_shutdown_port above. */ + /* MOD_DEC_USE_COUNT; */ +} + +static void a2232_hungup(void *ptr) +{ + a2232_close(ptr); +} +/*** END OF REAL_DRIVER FUNCTIONS ***/ + +/*** BEGIN FUNCTIONS EXPECTED BY TTY DRIVER STRUCTS ***/ +static int a2232_ioctl( struct tty_struct *tty, struct file *file, + unsigned int cmd, unsigned long arg) +{ + return -ENOIOCTLCMD; +} + +static void a2232_throttle(struct tty_struct *tty) +{ +/* Throttle: System cannot take another chars: Drop RTS or + send the STOP char or whatever. + The A2232 firmware does RTS/CTS anyway, and XON/XOFF + if switched on. So the only thing we can do at this + layer here is not taking any characters out of the + A2232 buffer any more. */ + struct a2232_port *port = (struct a2232_port *) tty->driver_data; + port->throttle_input = -1; +} + +static void a2232_unthrottle(struct tty_struct *tty) +{ +/* Unthrottle: dual to "throttle()" above. */ + struct a2232_port *port = (struct a2232_port *) tty->driver_data; + port->throttle_input = 0; +} + +static int a2232_open(struct tty_struct * tty, struct file * filp) +{ +/* More or less stolen from other drivers. */ + int line; + int retval; + struct a2232_port *port; + + line = MINOR(tty->device); + port = &a2232_ports[line]; + + tty->driver_data = port; + port->gs.tty = tty; + port->gs.count++; + retval = gs_init_port(&port->gs); + if (retval) { + port->gs.count--; + return retval; + } + port->gs.flags |= GS_ACTIVE; + if (port->gs.count == 1) { + MOD_INC_USE_COUNT; + } + retval = gs_block_til_ready(port, filp); + + if (retval) { + MOD_DEC_USE_COUNT; + port->gs.count--; + return retval; + } + + if ((port->gs.count == 1) && (port->gs.flags & ASYNC_SPLIT_TERMIOS)){ + if (tty->driver.subtype == A2232_TTY_SUBTYPE_NORMAL) + *tty->termios = port->gs.normal_termios; + else + *tty->termios = port->gs.callout_termios; + a2232_set_real_termios (port); + } + + port->gs.session = current->session; + port->gs.pgrp = current->pgrp; + + a2232_enable_rx_interrupts(port); + + return 0; +} +/*** END OF FUNCTIONS EXPECTED BY TTY DRIVER STRUCTS ***/ + +static __inline__ volatile struct a2232status *a2232stat(unsigned int board, unsigned int portonboard) +{ + volatile struct a2232memory *mem = a2232mem(board); + return &(mem->Status[portonboard]); +} + +static __inline__ volatile struct a2232memory *a2232mem (unsigned int board) +{ + return (volatile struct a2232memory *) ZTWO_VADDR( zd_a2232[board]->resource.start ); +} + +static __inline__ void a2232_receive_char( struct a2232_port *port, + int ch, int err ) +{ +/* Mostly stolen from other drivers. + Maybe one could implement a more efficient version by not only + transferring one character at a time. +*/ + struct tty_struct *tty = port->gs.tty; + + if (tty->flip.count >= TTY_FLIPBUF_SIZE) + return; + + tty->flip.count++; + +#if 0 + switch(err) { + case TTY_BREAK: + break; + case TTY_PARITY: + break; + case TTY_OVERRUN: + break; + case TTY_FRAME: + break; + } +#endif + + *tty->flip.flag_buf_ptr++ = err; + *tty->flip.char_buf_ptr++ = ch; + tty_flip_buffer_push(tty); +} + +static void a2232_vbl_inter(int irq, void *data, struct pt_regs *fp) +{ +#if A2232_IOBUFLEN != 256 +#error "Re-Implement a2232_vbl_inter()!" +#endif + +struct a2232_port *port; +volatile struct a2232memory *mem; +volatile struct a2232status *status; +unsigned char newhead; +unsigned char bufpos; /* Must be unsigned char. We need the modulo-256 arithmetics */ +unsigned char ncd, ocd, ccd; /* names consistent with the NetBSD driver */ +volatile u_char *ibuf, *cbuf, *obuf; +int ch, err, n, p; + for (n = 0; n < nr_a2232; n++){ /* for every completely initialized A2232 board */ + mem = a2232mem(n); + for (p = 0; p < NUMLINES; p++){ /* for every port on this board */ + err = 0; + port = &a2232_ports[n*NUMLINES+p]; + if ( port->gs.flags & GS_ACTIVE ){ /* if the port is used */ + + status = a2232stat(n,p); + + if (!port->disable_rx && !port->throttle_input){ /* If input is not disabled */ + newhead = status->InHead; /* 65EC02 write pointer */ + bufpos = status->InTail; + + /* check for input for this port */ + if (newhead != bufpos) { + /* buffer for input chars/events */ + ibuf = mem->InBuf[p]; + + /* data types of bytes in ibuf */ + cbuf = mem->InCtl[p]; + + /* do for all chars */ + while (bufpos != newhead) { + /* which type of input data? */ + switch (cbuf[bufpos]) { + /* switch on input event (CD, BREAK, etc.) */ + case A2232INCTL_EVENT: + switch (ibuf[bufpos++]) { + case A2232EVENT_Break: + /* TODO: Handle BREAK signal */ + break; + /* A2232EVENT_CarrierOn and A2232EVENT_CarrierOff are + handled in a separate queue and should not occur here. */ + case A2232EVENT_Sync: + printk("A2232: 65EC02 software sent SYNC event, don't know what to do. Ignoring."); + break; + default: + printk("A2232: 65EC02 software broken, unknown event type %d occured.\n",ibuf[bufpos-1]); + } /* event type switch */ + break; + case A2232INCTL_CHAR: + /* Receive incoming char */ + a2232_receive_char(port, ibuf[bufpos], err); + bufpos++; + break; + default: + printk("A2232: 65EC02 software broken, unknown data type %d occured.\n",cbuf[bufpos]); + bufpos++; + } /* switch on input data type */ + } /* while there's something in the buffer */ + + status->InTail = bufpos; /* tell 65EC02 what we've read */ + + } /* if there was something in the buffer */ + } /* If input is not disabled */ + + /* Now check if there's something to output */ + obuf = mem->OutBuf[p]; + bufpos = status->OutHead; + while ( (port->gs.xmit_cnt > 0) && + (!port->gs.tty->stopped) && + (!port->gs.tty->hw_stopped) ){ /* While there are chars to transmit */ + if (((bufpos+1) & A2232_IOBUFLENMASK) != status->OutTail) { /* If the A2232 buffer is not full */ + ch = port->gs.xmit_buf[port->gs.xmit_tail]; /* get the next char to transmit */ + port->gs.xmit_tail = (port->gs.xmit_tail+1) & (SERIAL_XMIT_SIZE-1); /* modulo-addition for the gs.xmit_buf ring-buffer */ + obuf[bufpos++] = ch; /* put it into the A2232 buffer */ + port->gs.xmit_cnt--; + } + else{ /* If A2232 the buffer is full */ + break; /* simply stop filling it. */ + } + } + status->OutHead = bufpos; + + /* WakeUp if output buffer runs low */ + if ((port->gs.xmit_cnt <= port->gs.wakeup_chars) && port->gs.tty) { + if ((port->gs.tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && port->gs.tty->ldisc.write_wakeup){ + (port->gs.tty->ldisc.write_wakeup)(port->gs.tty); + } + wake_up_interruptible(&port->gs.tty->write_wait); + } + } // if the port is used + } // for every port on the board + + /* Now check the CD message queue */ + newhead = mem->Common.CDHead; + bufpos = mem->Common.CDTail; + if (newhead != bufpos){ /* There are CD events in queue */ + ocd = mem->Common.CDStatus; /* get old status bits */ + while (newhead != bufpos){ /* read all events */ + ncd = mem->CDBuf[bufpos++]; /* get one event */ + ccd = ncd ^ ocd; /* mask of changed lines */ + ocd = ncd; /* save new status bits */ + for(p=0; p < NUMLINES; p++){ /* for all ports */ + if (ccd & 1){ /* this one changed */ + + struct a2232_port *port = &a2232_ports[n*7+p]; + port->cd_status = !(ncd & 1); /* ncd&1 <=> CD is now off */ + + if (!(port->gs.flags & ASYNC_CHECK_CD)) + ; /* Don't report DCD changes */ + else if (port->cd_status) { // if DCD on: DCD went UP! + if (~(port->gs.flags & ASYNC_NORMAL_ACTIVE) || + ~(port->gs.flags & ASYNC_CALLOUT_ACTIVE)) { + /* Are we blocking in open?*/ + wake_up_interruptible(&port->gs.open_wait); + } + } + else { // if DCD off: DCD went DOWN! + if (!((port->gs.flags & ASYNC_CALLOUT_ACTIVE) && + (port->gs.flags & ASYNC_CALLOUT_NOHUP))) { + if (port->gs.tty) + tty_hangup (port->gs.tty); + } + } + + } // if CD changed for this port + ccd >>= 1; + ncd >>= 1; /* Shift bits for next line */ + } // for every port + } // while CD events in queue + mem->Common.CDStatus = ocd; /* save new status */ + mem->Common.CDTail = bufpos; /* remove events */ + } // if events in CD queue + + } // for every completely initialized A2232 board +} + +static void a2232_init_portstructs(void) +{ + struct a2232_port *port; + int i; + + for (i = 0; i < MAX_A2232_BOARDS*NUMLINES; i++) { + port = a2232_ports + i; + port->which_a2232 = i/NUMLINES; + port->which_port_on_a2232 = i%NUMLINES; + port->disable_rx = port->throttle_input = port->cd_status = 0; + port->gs.callout_termios = tty_std_termios; + port->gs.normal_termios = tty_std_termios; + port->gs.magic = A2232_MAGIC; + port->gs.close_delay = HZ/2; + port->gs.closing_wait = 30 * HZ; + port->gs.rd = &a2232_real_driver; +#ifdef NEW_WRITE_LOCKING + init_MUTEX(&(port->gs.port_write_sem)); +#endif + init_waitqueue_head(&port->gs.open_wait); + init_waitqueue_head(&port->gs.close_wait); + } +} + +static int a2232_init_drivers(void) +{ + int error; + + memset(&a2232_driver, 0, sizeof(a2232_driver)); + a2232_driver.magic = TTY_DRIVER_MAGIC; + a2232_driver.driver_name = "commodore_a2232"; + a2232_driver.name = "ttyY"; + a2232_driver.major = A2232_NORMAL_MAJOR; + a2232_driver.num = NUMLINES * nr_a2232; + a2232_driver.type = TTY_DRIVER_TYPE_SERIAL; + a2232_driver.subtype = A2232_TTY_SUBTYPE_NORMAL; + a2232_driver.init_termios = tty_std_termios; + a2232_driver.init_termios.c_cflag = + B9600 | CS8 | CREAD | HUPCL | CLOCAL; + a2232_driver.flags = TTY_DRIVER_REAL_RAW; + a2232_driver.refcount = &a2232_refcount; + a2232_driver.table = a2232_table; + a2232_driver.termios = a2232_termios; + a2232_driver.termios_locked = a2232_termios_locked; + + a2232_driver.open = a2232_open; + a2232_driver.close = gs_close; + a2232_driver.write = gs_write; + a2232_driver.put_char = gs_put_char; + a2232_driver.flush_chars = gs_flush_chars; + a2232_driver.write_room = gs_write_room; + a2232_driver.chars_in_buffer = gs_chars_in_buffer; + a2232_driver.flush_buffer = gs_flush_buffer; + a2232_driver.ioctl = a2232_ioctl; + a2232_driver.throttle = a2232_throttle; + a2232_driver.unthrottle = a2232_unthrottle; + a2232_driver.set_termios = gs_set_termios; + a2232_driver.stop = gs_stop; + a2232_driver.start = gs_start; + a2232_driver.hangup = gs_hangup; + + a2232_callout_driver = a2232_driver; + a2232_callout_driver.name = "cuy"; + a2232_callout_driver.major = A2232_CALLOUT_MAJOR; + a2232_callout_driver.subtype = A2232_TTY_SUBTYPE_CALLOUT; + + if ((error = tty_register_driver(&a2232_driver))) { + printk(KERN_ERR "A2232: Couldn't register A2232 driver, error = %d\n", + error); + return 1; + } + if ((error = tty_register_driver(&a2232_callout_driver))) { + tty_unregister_driver(&a2232_driver); + printk(KERN_ERR "A2232: Couldn't register A2232 callout driver, error = %d\n", + error); + return 1; + } + return 0; +} + +int a2232board_init(void) +{ + struct zorro_dev *z; + + unsigned int boardaddr; + int bcount; + short start; + u_char *from; + volatile u_char *to; + volatile struct a2232memory *mem; + +#ifdef __SMP__ + return -ENODEV; /* This driver is not SMP aware. Is there an SMP ZorroII-bus-machine? */ +#endif + + if (!MACH_IS_AMIGA){ + return -ENODEV; + } + + printk("Commodore A2232 driver initializing.\n"); /* Say that we're alive. */ + + z = NULL; + nr_a2232 = 0; + while ( (z = zorro_find_device(ZORRO_WILDCARD, z)) ){ + if ( (z->id != ZORRO_PROD_CBM_A2232_PROTOTYPE) && + (z->id != ZORRO_PROD_CBM_A2232) ){ + continue; // The board found was no A2232 + } + if (!zorro_request_device(z,"A2232 driver")) + continue; + + printk("Commodore A2232 found (#%d).\n",nr_a2232); + + zd_a2232[nr_a2232] = z; + + boardaddr = ZTWO_VADDR( z->resource.start ); + printk("Board is located at address 0x%x, size is 0x%x.\n", boardaddr, (unsigned int) ((z->resource.end+1) - (z->resource.start))); + + mem = (volatile struct a2232memory *) boardaddr; + + (void) mem->Enable6502Reset; /* copy the code across to the board */ + to = (u_char *)mem; from = a2232_65EC02code; bcount = sizeof(a2232_65EC02code) - 2; + start = *(short *)from; + from += sizeof(start); + to += start; + while(bcount--) *to++ = *from++; + printk("65EC02 software uploaded to the A2232 memory.\n"); + + mem->Common.Crystal = A2232_UNKNOWN; /* use automatic speed check */ + + /* start 6502 running */ + (void) mem->ResetBoard; + printk("A2232's 65EC02 CPU up and running.\n"); + + /* wait until speed detector has finished */ + for (bcount = 0; bcount < 2000; bcount++) { + udelay(1000); + if (mem->Common.Crystal) + break; + } + printk((mem->Common.Crystal?"A2232 oscillator crystal detected by 65EC02 software: ":"65EC02 software could not determine A2232 oscillator crystal: ")); + switch (mem->Common.Crystal){ + case A2232_UNKNOWN: + printk("Unknown crystal.\n"); + break; + case A2232_NORMAL: + printk ("Normal crystal.\n"); + break; + case A2232_TURBO: + printk ("Turbo crystal.\n"); + break; + default: + printk ("0x%x. Huh?\n",mem->Common.Crystal); + } + + nr_a2232++; + + } + + printk("Total: %d A2232 boards initialized.\n.", nr_a2232); /* Some status report if no card was found */ + + a2232_init_portstructs(); + + /* + a2232_init_drivers also registers the drivers. Must be here because all boards + have to be detected first. + */ + if (a2232_init_drivers()) return -ENODEV; // maybe we should use a different -Exxx? + + request_irq(IRQ_AMIGA_VERTB, a2232_vbl_inter, 0, "A2232 serial VBL", a2232_driver_ID); + return 0; +} + +#ifdef MODULE +int init_module(void) +{ + return a2232board_init(); +} + +void cleanup_module(void) +{ + int i; + + for (i = 0; i < nr_a2232; i++) { + zorro_release_device(zd_a2232[i]); + } + + tty_unregister_driver(&a2232_driver); + tty_unregister_driver(&a2232_callout_driver); + free_irq(IRQ_AMIGA_VERTB, a2232_driver_ID); +} +#endif +/***************************** End of Functions *********************/ diff -u --recursive --new-file v2.4.6/linux/drivers/char/ser_a2232.h linux/drivers/char/ser_a2232.h --- v2.4.6/linux/drivers/char/ser_a2232.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/ser_a2232.h Wed Jul 4 14:41:33 2001 @@ -0,0 +1,206 @@ +/* drivers/char/ser_a2232.h */ + +/* $Id: ser_a2232.h,v 0.4 2000/01/25 12:00:00 ehaase Exp $ */ + +/* Linux serial driver for the Amiga A2232 board */ + +/* This driver is MAINTAINED. Before applying any changes, please contact + * the author. + */ + +/* Copyright (c) 2000-2001 Enver Haase <ehaase@inf.fu-berlin.de> + * alias The A2232 driver project <A2232@gmx.net> + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef _SER_A2232_H_ +#define _SER_A2232_H_ + +/* + How many boards are to be supported at maximum; + "up to five A2232 Multiport Serial Cards may be installed in a + single Amiga 2000" states the A2232 User's Guide. If you have + more slots available, you might want to change the value below. +*/ +#define MAX_A2232_BOARDS 5 + +#ifndef A2232_NORMAL_MAJOR +/* This allows overriding on the compiler commandline, or in a "major.h" + include or something like that */ +#define A2232_NORMAL_MAJOR 224 /* /dev/ttyY* */ +#define A2232_CALLOUT_MAJOR 225 /* /dev/cuy* */ +#endif + +/* Some magic is always good - Who knows :) */ +#define A2232_MAGIC 0x000a2232 + +/* for the tty_struct subtype field */ +#define A2232_TTY_SUBTYPE_NORMAL 1 +#define A2232_TTY_SUBTYPE_CALLOUT 2 + +/* A2232 port structure to keep track of the + status of every single line used */ +struct a2232_port{ + struct gs_port gs; + unsigned int which_a2232; + unsigned int which_port_on_a2232; + short disable_rx; + short throttle_input; + short cd_status; +}; + +#define NUMLINES 7 /* number of lines per board */ +#define A2232_IOBUFLEN 256 /* number of bytes per buffer */ +#define A2232_IOBUFLENMASK 0xff /* mask for maximum number of bytes */ + + +#define A2232_UNKNOWN 0 /* crystal not known */ +#define A2232_NORMAL 1 /* normal A2232 (1.8432 MHz oscillator) */ +#define A2232_TURBO 2 /* turbo A2232 (3.6864 MHz oscillator) */ + + +struct a2232common { + char Crystal; /* normal (1) or turbo (2) board? */ + u_char Pad_a; + u_char TimerH; /* timer value after speed check */ + u_char TimerL; + u_char CDHead; /* head pointer for CD message queue */ + u_char CDTail; /* tail pointer for CD message queue */ + u_char CDStatus; + u_char Pad_b; +}; + +struct a2232status { + u_char InHead; /* input queue head */ + u_char InTail; /* input queue tail */ + u_char OutDisable; /* disables output */ + u_char OutHead; /* output queue head */ + u_char OutTail; /* output queue tail */ + u_char OutCtrl; /* soft flow control character to send */ + u_char OutFlush; /* flushes output buffer */ + u_char Setup; /* causes reconfiguration */ + u_char Param; /* parameter byte - see A2232PARAM */ + u_char Command; /* command byte - see A2232CMD */ + u_char SoftFlow; /* enables xon/xoff flow control */ + /* private 65EC02 fields: */ + u_char XonOff; /* stores XON/XOFF enable/disable */ +}; + +#define A2232_MEMPAD1 \ + (0x0200 - NUMLINES * sizeof(struct a2232status) - \ + sizeof(struct a2232common)) +#define A2232_MEMPAD2 (0x2000 - NUMLINES * A2232_IOBUFLEN - A2232_IOBUFLEN) + +struct a2232memory { + struct a2232status Status[NUMLINES]; /* 0x0000-0x006f status areas */ + struct a2232common Common; /* 0x0070-0x0077 common flags */ + u_char Dummy1[A2232_MEMPAD1]; /* 0x00XX-0x01ff */ + u_char OutBuf[NUMLINES][A2232_IOBUFLEN];/* 0x0200-0x08ff output bufs */ + u_char InBuf[NUMLINES][A2232_IOBUFLEN]; /* 0x0900-0x0fff input bufs */ + u_char InCtl[NUMLINES][A2232_IOBUFLEN]; /* 0x1000-0x16ff control data */ + u_char CDBuf[A2232_IOBUFLEN]; /* 0x1700-0x17ff CD event buffer */ + u_char Dummy2[A2232_MEMPAD2]; /* 0x1800-0x2fff */ + u_char Code[0x1000]; /* 0x3000-0x3fff code area */ + u_short InterruptAck; /* 0x4000 intr ack */ + u_char Dummy3[0x3ffe]; /* 0x4002-0x7fff */ + u_short Enable6502Reset; /* 0x8000 Stop board, */ + /* 6502 RESET line held low */ + u_char Dummy4[0x3ffe]; /* 0x8002-0xbfff */ + u_short ResetBoard; /* 0xc000 reset board & run, */ + /* 6502 RESET line held high */ +}; + +#undef A2232_MEMPAD1 +#undef A2232_MEMPAD2 + +#define A2232INCTL_CHAR 0 /* corresponding byte in InBuf is a character */ +#define A2232INCTL_EVENT 1 /* corresponding byte in InBuf is an event */ + +#define A2232EVENT_Break 1 /* break set */ +#define A2232EVENT_CarrierOn 2 /* carrier raised */ +#define A2232EVENT_CarrierOff 3 /* carrier dropped */ +#define A2232EVENT_Sync 4 /* don't know, defined in 2232.ax */ + +#define A2232CMD_Enable 0x1 /* enable/DTR bit */ +#define A2232CMD_Close 0x2 /* close the device */ +#define A2232CMD_Open 0xb /* open the device */ +#define A2232CMD_CMask 0xf /* command mask */ +#define A2232CMD_RTSOff 0x0 /* turn off RTS */ +#define A2232CMD_RTSOn 0x8 /* turn on RTS */ +#define A2232CMD_Break 0xd /* transmit a break */ +#define A2232CMD_RTSMask 0xc /* mask for RTS stuff */ +#define A2232CMD_NoParity 0x00 /* don't use parity */ +#define A2232CMD_OddParity 0x20 /* odd parity */ +#define A2232CMD_EvenParity 0x60 /* even parity */ +#define A2232CMD_ParityMask 0xe0 /* parity mask */ + +#define A2232PARAM_B115200 0x0 /* baud rates */ +#define A2232PARAM_B50 0x1 +#define A2232PARAM_B75 0x2 +#define A2232PARAM_B110 0x3 +#define A2232PARAM_B134 0x4 +#define A2232PARAM_B150 0x5 +#define A2232PARAM_B300 0x6 +#define A2232PARAM_B600 0x7 +#define A2232PARAM_B1200 0x8 +#define A2232PARAM_B1800 0x9 +#define A2232PARAM_B2400 0xa +#define A2232PARAM_B3600 0xb +#define A2232PARAM_B4800 0xc +#define A2232PARAM_B7200 0xd +#define A2232PARAM_B9600 0xe +#define A2232PARAM_B19200 0xf +#define A2232PARAM_BaudMask 0xf /* baud rate mask */ +#define A2232PARAM_RcvBaud 0x10 /* enable receive baud rate */ +#define A2232PARAM_8Bit 0x00 /* numbers of bits */ +#define A2232PARAM_7Bit 0x20 +#define A2232PARAM_6Bit 0x40 +#define A2232PARAM_5Bit 0x60 +#define A2232PARAM_BitMask 0x60 /* numbers of bits mask */ + + +/* Standard speeds tables, -1 means unavailable, -2 means 0 baud: switch off line */ +#define A2232_BAUD_TABLE_NOAVAIL -1 +#define A2232_BAUD_TABLE_NUM_RATES (18) +static int a2232_baud_table[A2232_BAUD_TABLE_NUM_RATES*3] = { + //Baud //Normal //Turbo + 50, A2232PARAM_B50, A2232_BAUD_TABLE_NOAVAIL, + 75, A2232PARAM_B75, A2232_BAUD_TABLE_NOAVAIL, + 110, A2232PARAM_B110, A2232_BAUD_TABLE_NOAVAIL, + 134, A2232PARAM_B134, A2232_BAUD_TABLE_NOAVAIL, + 150, A2232PARAM_B150, A2232PARAM_B75, + 200, A2232_BAUD_TABLE_NOAVAIL, A2232_BAUD_TABLE_NOAVAIL, + 300, A2232PARAM_B300, A2232PARAM_B150, + 600, A2232PARAM_B600, A2232PARAM_B300, + 1200, A2232PARAM_B1200, A2232PARAM_B600, + 1800, A2232PARAM_B1800, A2232_BAUD_TABLE_NOAVAIL, + 2400, A2232PARAM_B2400, A2232PARAM_B1200, + 4800, A2232PARAM_B4800, A2232PARAM_B2400, + 9600, A2232PARAM_B9600, A2232PARAM_B4800, + 19200, A2232PARAM_B19200, A2232PARAM_B9600, + 38400, A2232_BAUD_TABLE_NOAVAIL, A2232PARAM_B19200, + 57600, A2232_BAUD_TABLE_NOAVAIL, A2232_BAUD_TABLE_NOAVAIL, +#ifdef A2232_SPEEDHACK + 115200, A2232PARAM_B115200, A2232_BAUD_TABLE_NOAVAIL, + 230400, A2232_BAUD_TABLE_NOAVAIL, A2232PARAM_B115200 +#else + 115200, A2232_BAUD_TABLE_NOAVAIL, A2232_BAUD_TABLE_NOAVAIL, + 230400, A2232_BAUD_TABLE_NOAVAIL, A2232_BAUD_TABLE_NOAVAIL +#endif +}; +#endif diff -u --recursive --new-file v2.4.6/linux/drivers/char/ser_a2232fw.ax linux/drivers/char/ser_a2232fw.ax --- v2.4.6/linux/drivers/char/ser_a2232fw.ax Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/ser_a2232fw.ax Wed Jul 4 14:41:33 2001 @@ -0,0 +1,529 @@ +;.lib "axm" +; +;begin +;title "A2232 serial board driver" +; +;set modules "2232" +;set executable "2232.bin" +; +;;;;set nolink +; +;set temporary directory "t:" +; +;set assembly options "-m6502 -l60:t:list" +;set link options "bin"; loadadr" +;;;bin2c 2232.bin msc6502.h msc6502code +;end +; +; +; ### Commodore A2232 serial board driver for NetBSD by JM v1.3 ### +; +; - Created 950501 by JM - +; +; +; Serial board driver software. +; +; +% Copyright (c) 1995 Jukka Marin <jmarin@jmp.fi>. +% All rights reserved. +% +% Redistribution and use in source and binary forms, with or without +% modification, are permitted provided that the following conditions +% are met: +% 1. Redistributions of source code must retain the above copyright +% notice, and the entire permission notice in its entirety, +% including the disclaimer of warranties. +% 2. Redistributions in binary form must reproduce the above copyright +% notice, this list of conditions and the following disclaimer in the +% documentation and/or other materials provided with the distribution. +% 3. The name of the author may not be used to endorse or promote +% products derived from this software without specific prior +% written permission. +% +% ALTERNATIVELY, this product may be distributed under the terms of +% the GNU General Public License, in which case the provisions of the +% GPL are required INSTEAD OF the above restrictions. (This clause is +% necessary due to a potential bad interaction between the GPL and +% the restrictions contained in a BSD-style copyright.) +% +% 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. +; +; +; Bugs: +; +; - Can't send a break yet +; +; +; +; Edited: +; +; - 950501 by JM -> v0.1 - Created this file. +; - 951029 by JM -> v1.3 - Carrier Detect events now queued in a separate +; queue. +; +; + + +CODE equ $3800 ; start address for program code + + +CTL_CHAR equ $00 ; byte in ibuf is a character +CTL_EVENT equ $01 ; byte in ibuf is an event + +EVENT_BREAK equ $01 +EVENT_CDON equ $02 +EVENT_CDOFF equ $03 +EVENT_SYNC equ $04 + +XON equ $11 +XOFF equ $13 + + +VARBASE macro *starting_address ; was VARINIT +_varbase set \1 + endm + +VARDEF macro *name space_needs +\1 equ _varbase +_varbase set _varbase+\2 + endm + + +stz macro * address + db $64,\1 + endm + +stzax macro * address + db $9e,<\1,>\1 + endm + + +biti macro * immediate value + db $89,\1 + endm + +smb0 macro * address + db $87,\1 + endm +smb1 macro * address + db $97,\1 + endm +smb2 macro * address + db $a7,\1 + endm +smb3 macro * address + db $b7,\1 + endm +smb4 macro * address + db $c7,\1 + endm +smb5 macro * address + db $d7,\1 + endm +smb6 macro * address + db $e7,\1 + endm +smb7 macro * address + db $f7,\1 + endm + + + +;-----------------------------------------------------------------------; +; ; +; stuff common for all ports, non-critical (run once / loop) ; +; ; +DO_SLOW macro * port_number ; + .local ; ; + lda CIA+C_PA ; check all CD inputs ; + cmp CommonCDo ; changed from previous accptd? ; + beq =over ; nope, do nothing else here ; + ; ; + cmp CommonCDb ; bouncing? ; + beq =nobounce ; nope -> ; + ; ; + sta CommonCDb ; save current state ; + lda #64 ; reinitialize counter ; + sta CommonCDc ; ; + jmp =over ; skip CD save ; + ; ; +=nobounce dec CommonCDc ; no, decrement bounce counter ; + bpl =over ; not done yet, so skip CD save ; + ; ; +=saveCD ldx CDHead ; get write index ; + sta cdbuf,x ; save status in buffer ; + inx ; ; + cpx CDTail ; buffer full? ; + .if ne ; no: preserve status: ; + stx CDHead ; update index in RAM ; + sta CommonCDo ; save state for the next check ; + .end ; ; +=over .end local ; + endm ; + ; +;-----------------------------------------------------------------------; + + +; port specific stuff (no data transfer) + +DO_PORT macro * port_number + .local ; ; + lda SetUp\1 ; reconfiguration request? ; + .if ne ; yes: ; + lda SoftFlow\1 ; get XON/XOFF flag ; + sta XonOff\1 ; save it ; + lda Param\1 ; get parameter ; + ora #%00010000 ; use baud generator for Rx ; + sta ACIA\1+A_CTRL ; store in control register ; + stz OutDisable\1 ; enable transmit output ; + stz SetUp\1 ; no reconfiguration no more ; + .end ; ; + ; ; + lda InHead\1 ; get write index ; + sbc InTail\1 ; buffer full soon? ; + cmp #200 ; 200 chars or more in buffer? ; + lda Command\1 ; get Command reg value ; + and #%11110011 ; turn RTS OFF by default ; + .if cc ; still room in buffer: ; + ora #%00001000 ; turn RTS ON ; + .end ; ; + sta ACIA\1+A_CMD ; set/clear RTS ; + ; ; + lda OutFlush\1 ; request to flush output buffer; + .if ne ; yessh! ; + lda OutHead\1 ; get head ; + sta OutTail\1 ; save as tail ; + stz OutDisable\1 ; enable transmit output ; + stz OutFlush\1 ; clear request ; + .end + .end local + endm + + +DO_DATA macro * port number + .local + lda ACIA\1+A_SR ; read ACIA status register ; + biti [1<<3] ; something received? ; + .if ne ; yes: ; + biti [1<<1] ; framing error? ; + .if ne ; yes: ; + lda ACIA\1+A_DATA ; read received character ; + bne =SEND ; not break -> ignore it ; + ldx InHead\1 ; get write pointer ; + lda #CTL_EVENT ; get type of byte ; + sta ictl\1,x ; save it in InCtl buffer ; + lda #EVENT_BREAK ; event code ; + sta ibuf\1,x ; save it as well ; + inx ; ; + cpx InTail\1 ; still room in buffer? ; + .if ne ; absolutely: ; + stx InHead\1 ; update index in memory ; + .end ; ; + jmp =SEND ; go check if anything to send ; + .end ; ; + ; normal char received: ; + ldx InHead\1 ; get write index ; + lda ACIA\1+A_DATA ; read received character ; + sta ibuf\1,x ; save char in buffer ; + stzax ictl\1 ; set type to CTL_CHAR ; + inx ; ; + cpx InTail\1 ; buffer full? ; + .if ne ; no: preserve character: ; + stx InHead\1 ; update index in RAM ; + .end ; ; + and #$7f ; mask off parity if any ; + cmp #XOFF ; XOFF from remote host? ; + .if eq ; yes: ; + lda XonOff\1 ; if XON/XOFF handshaking.. ; + sta OutDisable\1 ; ..disable transmitter ; + .end ; ; + .end ; ; + ; ; + ; BUFFER FULL CHECK WAS HERE ; + ; ; +=SEND lda ACIA\1+A_SR ; transmit register empty? ; + and #[1<<4] ; ; + .if ne ; yes: ; + ldx OutCtrl\1 ; sending out XON/XOFF? ; + .if ne ; yes: ; + lda CIA+C_PB ; check CTS signal ; + and #[1<<\1] ; (for this port only) ; + bne =DONE ; not allowed to send -> done ; + stx ACIA\1+A_DATA ; transmit control char ; + stz OutCtrl\1 ; clear flag ; + jmp =DONE ; and we're done ; + .end ; ; + ; ; + ldx OutTail\1 ; anything to transmit? ; + cpx OutHead\1 ; ; + .if ne ; yes: ; + lda OutDisable\1 ; allowed to transmit? ; + .if eq ; yes: ; + lda CIA+C_PB ; check CTS signal ; + and #[1<<\1] ; (for this port only) ; + bne =DONE ; not allowed to send -> done ; + lda obuf\1,x ; get a char from buffer ; + sta ACIA\1+A_DATA ; send it away ; + inc OutTail\1 ; update read index ; + .end ; ; + .end ; ; + .end ; ; +=DONE .end local + endm + + + +PORTVAR macro * port number + VARDEF InHead\1 1 + VARDEF InTail\1 1 + VARDEF OutDisable\1 1 + VARDEF OutHead\1 1 + VARDEF OutTail\1 1 + VARDEF OutCtrl\1 1 + VARDEF OutFlush\1 1 + VARDEF SetUp\1 1 + VARDEF Param\1 1 + VARDEF Command\1 1 + VARDEF SoftFlow\1 1 + ; private: + VARDEF XonOff\1 1 + endm + + + VARBASE 0 ; start variables at address $0000 + PORTVAR 0 ; define variables for port 0 + PORTVAR 1 ; define variables for port 1 + PORTVAR 2 ; define variables for port 2 + PORTVAR 3 ; define variables for port 3 + PORTVAR 4 ; define variables for port 4 + PORTVAR 5 ; define variables for port 5 + PORTVAR 6 ; define variables for port 6 + + + + VARDEF Crystal 1 ; 0 = unknown, 1 = normal, 2 = turbo + VARDEF Pad_a 1 + VARDEF TimerH 1 + VARDEF TimerL 1 + VARDEF CDHead 1 + VARDEF CDTail 1 + VARDEF CDStatus 1 + VARDEF Pad_b 1 + + VARDEF CommonCDo 1 ; for carrier detect optimization + VARDEF CommonCDc 1 ; for carrier detect debouncing + VARDEF CommonCDb 1 ; for carrier detect debouncing + + + VARBASE $0200 + VARDEF obuf0 256 ; output data (characters only) + VARDEF obuf1 256 + VARDEF obuf2 256 + VARDEF obuf3 256 + VARDEF obuf4 256 + VARDEF obuf5 256 + VARDEF obuf6 256 + + VARDEF ibuf0 256 ; input data (characters, events etc - see ictl) + VARDEF ibuf1 256 + VARDEF ibuf2 256 + VARDEF ibuf3 256 + VARDEF ibuf4 256 + VARDEF ibuf5 256 + VARDEF ibuf6 256 + + VARDEF ictl0 256 ; input control information (type of data in ibuf) + VARDEF ictl1 256 + VARDEF ictl2 256 + VARDEF ictl3 256 + VARDEF ictl4 256 + VARDEF ictl5 256 + VARDEF ictl6 256 + + VARDEF cdbuf 256 ; CD event queue + + +ACIA0 equ $4400 +ACIA1 equ $4c00 +ACIA2 equ $5400 +ACIA3 equ $5c00 +ACIA4 equ $6400 +ACIA5 equ $6c00 +ACIA6 equ $7400 + +A_DATA equ $00 +A_SR equ $02 +A_CMD equ $04 +A_CTRL equ $06 +; 00 write transmit data read received data +; 02 reset ACIA read status register +; 04 write command register read command register +; 06 write control register read control register + +CIA equ $7c00 ; 8520 CIA +C_PA equ $00 ; port A data register +C_PB equ $02 ; port B data register +C_DDRA equ $04 ; data direction register for port A +C_DDRB equ $06 ; data direction register for port B +C_TAL equ $08 ; timer A +C_TAH equ $0a +C_TBL equ $0c ; timer B +C_TBH equ $0e +C_TODL equ $10 ; TOD LSB +C_TODM equ $12 ; TOD middle byte +C_TODH equ $14 ; TOD MSB +C_DATA equ $18 ; serial data register +C_INTCTRL equ $1a ; interrupt control register +C_CTRLA equ $1c ; control register A +C_CTRLB equ $1e ; control register B + + + + + + section main,code,CODE-2 + + db >CODE,<CODE + +;-----------------------------------------------------------------------; +; here's the initialization code: ; +; ; +R_RESET ldx #$ff ; + txs ; initialize stack pointer ; + cld ; in case a 6502 is used... ; + ldx #0 ; ; + lda #0 ; ; + ldy #Crystal ; this many bytes to clear ; +clr_loop sta 0,x ; clear zero page variables ; + inx ; ; + dey ; ; + bne clr_loop ; ; + ; ; + stz CommonCDo ; force CD test at boot ; + stz CommonCDb ; ; + stz CDHead ; clear queue ; + stz CDTail ; ; + ; ; + lda #0 ; ; + sta Pad_a ; ; + lda #170 ; test cmp ; + cmp #100 ; ; + .if cs ; ; + inc Pad_a ; C was set ; + .end ; ; + ; +;-----------------------------------------------------------------------; +; Speed check ; +;-----------------------------------------------------------------------; + ; + lda Crystal ; speed already set? ; + beq DoSpeedy ; ; + jmp LOOP ; yes, skip speed test ; + ; ; +DoSpeedy lda #%10011000 ; 8N1, 1200/2400 bps ; + sta ACIA0+A_CTRL ; ; + lda #%00001011 ; enable DTR ; + sta ACIA0+A_CMD ; ; + lda ACIA0+A_SR ; read status register ; + ; ; + lda #%10000000 ; disable all ints (unnecessary); + sta CIA+C_INTCTRL ; ; + lda #255 ; program the timer ; + sta CIA+C_TAL ; ; + sta CIA+C_TAH ; ; + ; ; + ldx #0 ; ; + stx ACIA0+A_DATA ; transmit a zero ; + nop ; ; + nop ; ; + lda ACIA0+A_SR ; read status ; + nop ; ; + nop ; ; + stx ACIA0+A_DATA ; transmit a zero ; +Speedy1 lda ACIA0+A_SR ; read status ; + and #[1<<4] ; transmit data reg empty? ; + beq Speedy1 ; not yet, wait more ; + ; ; + lda #%00010001 ; load & start the timer ; + stx ACIA0+A_DATA ; transmit one more zero ; + sta CIA+C_CTRLA ; ; +Speedy2 lda ACIA0+A_SR ; read status ; + and #[1<<4] ; transmit data reg empty? ; + beq Speedy2 ; not yet, wait more ; + stx CIA+C_CTRLA ; stop the timer ; + ; ; + lda CIA+C_TAL ; copy timer value for 68k ; + sta TimerL ; ; + lda CIA+C_TAH ; ; + sta TimerH ; ; + cmp #$d0 ; turbo or normal? ; + .if cs ; ; + lda #2 ; turbo! :-) ; + .else ; ; + lda #1 ; normal :-( ; + .end ; ; + sta Crystal ; ; + lda #0 ; ; + sta ACIA0+A_SR ; ; + sta ACIA0+A_CTRL ; reset UART ; + sta ACIA0+A_CMD ; ; + ; + jmp LOOP ; + ; +; ; +;-----------------------------------------------------------------------; +; ; +; The Real Thing: ; +; ; +LOOP DO_SLOW ; do non-critical things ; + jsr do_input ; check for received data + DO_PORT 0 + jsr do_input + DO_PORT 1 + jsr do_input + DO_PORT 2 + jsr do_input + DO_PORT 3 + jsr do_input + DO_PORT 4 + jsr do_input + DO_PORT 5 + jsr do_input + DO_PORT 6 + jsr do_input + jmp LOOP + + +do_input DO_DATA 0 + DO_DATA 1 + DO_DATA 2 + DO_DATA 3 + DO_DATA 4 + DO_DATA 5 + DO_DATA 6 + rts + + +;-----------------------------------------------------------------------; + section vectors,data,$3ffa + dw $d0d0 + dw R_RESET + dw $c0ce +;-----------------------------------------------------------------------; + + + + end + + + diff -u --recursive --new-file v2.4.6/linux/drivers/char/ser_a2232fw.h linux/drivers/char/ser_a2232fw.h --- v2.4.6/linux/drivers/char/ser_a2232fw.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/ser_a2232fw.h Wed Jul 4 14:41:33 2001 @@ -0,0 +1,306 @@ +/* drivers/char/ser_a2232fw.h */ + +/* $Id: ser_a2232fw.h,v 0.4 2000/01/25 12:00:00 ehaase Exp $ */ + +/* + * Copyright (c) 1995 Jukka Marin <jmarin@jmp.fi>. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, and the entire permission notice in its entirety, + * including the disclaimer of warranties. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * ALTERNATIVELY, this product may be distributed under the terms of + * the GNU Public License, in which case the provisions of the GPL are + * required INSTEAD OF the above restrictions. (This clause is + * necessary due to a potential bad interaction between the GPL and + * the restrictions contained in a BSD-style copyright.) + * + * 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. + * + */ + +/* This is the 65EC02 code by Jukka Marin that is executed by + the A2232's 65EC02 processor (base address: 0x3800) + Source file: ser_a2232fw.ax + Version: 1.3 (951029) + Known Bugs: Cannot send a break yet +*/ +static unsigned char a2232_65EC02code[] = { + 0x38, 0x00, 0xA2, 0xFF, 0x9A, 0xD8, 0xA2, 0x00, + 0xA9, 0x00, 0xA0, 0x54, 0x95, 0x00, 0xE8, 0x88, + 0xD0, 0xFA, 0x64, 0x5C, 0x64, 0x5E, 0x64, 0x58, + 0x64, 0x59, 0xA9, 0x00, 0x85, 0x55, 0xA9, 0xAA, + 0xC9, 0x64, 0x90, 0x02, 0xE6, 0x55, 0xA5, 0x54, + 0xF0, 0x03, 0x4C, 0x92, 0x38, 0xA9, 0x98, 0x8D, + 0x06, 0x44, 0xA9, 0x0B, 0x8D, 0x04, 0x44, 0xAD, + 0x02, 0x44, 0xA9, 0x80, 0x8D, 0x1A, 0x7C, 0xA9, + 0xFF, 0x8D, 0x08, 0x7C, 0x8D, 0x0A, 0x7C, 0xA2, + 0x00, 0x8E, 0x00, 0x44, 0xEA, 0xEA, 0xAD, 0x02, + 0x44, 0xEA, 0xEA, 0x8E, 0x00, 0x44, 0xAD, 0x02, + 0x44, 0x29, 0x10, 0xF0, 0xF9, 0xA9, 0x11, 0x8E, + 0x00, 0x44, 0x8D, 0x1C, 0x7C, 0xAD, 0x02, 0x44, + 0x29, 0x10, 0xF0, 0xF9, 0x8E, 0x1C, 0x7C, 0xAD, + 0x08, 0x7C, 0x85, 0x57, 0xAD, 0x0A, 0x7C, 0x85, + 0x56, 0xC9, 0xD0, 0x90, 0x05, 0xA9, 0x02, 0x4C, + 0x82, 0x38, 0xA9, 0x01, 0x85, 0x54, 0xA9, 0x00, + 0x8D, 0x02, 0x44, 0x8D, 0x06, 0x44, 0x8D, 0x04, + 0x44, 0x4C, 0x92, 0x38, 0xAD, 0x00, 0x7C, 0xC5, + 0x5C, 0xF0, 0x1F, 0xC5, 0x5E, 0xF0, 0x09, 0x85, + 0x5E, 0xA9, 0x40, 0x85, 0x5D, 0x4C, 0xB8, 0x38, + 0xC6, 0x5D, 0x10, 0x0E, 0xA6, 0x58, 0x9D, 0x00, + 0x17, 0xE8, 0xE4, 0x59, 0xF0, 0x04, 0x86, 0x58, + 0x85, 0x5C, 0x20, 0x23, 0x3A, 0xA5, 0x07, 0xF0, + 0x0F, 0xA5, 0x0A, 0x85, 0x0B, 0xA5, 0x08, 0x09, + 0x10, 0x8D, 0x06, 0x44, 0x64, 0x02, 0x64, 0x07, + 0xA5, 0x00, 0xE5, 0x01, 0xC9, 0xC8, 0xA5, 0x09, + 0x29, 0xF3, 0xB0, 0x02, 0x09, 0x08, 0x8D, 0x04, + 0x44, 0xA5, 0x06, 0xF0, 0x08, 0xA5, 0x03, 0x85, + 0x04, 0x64, 0x02, 0x64, 0x06, 0x20, 0x23, 0x3A, + 0xA5, 0x13, 0xF0, 0x0F, 0xA5, 0x16, 0x85, 0x17, + 0xA5, 0x14, 0x09, 0x10, 0x8D, 0x06, 0x4C, 0x64, + 0x0E, 0x64, 0x13, 0xA5, 0x0C, 0xE5, 0x0D, 0xC9, + 0xC8, 0xA5, 0x15, 0x29, 0xF3, 0xB0, 0x02, 0x09, + 0x08, 0x8D, 0x04, 0x4C, 0xA5, 0x12, 0xF0, 0x08, + 0xA5, 0x0F, 0x85, 0x10, 0x64, 0x0E, 0x64, 0x12, + 0x20, 0x23, 0x3A, 0xA5, 0x1F, 0xF0, 0x0F, 0xA5, + 0x22, 0x85, 0x23, 0xA5, 0x20, 0x09, 0x10, 0x8D, + 0x06, 0x54, 0x64, 0x1A, 0x64, 0x1F, 0xA5, 0x18, + 0xE5, 0x19, 0xC9, 0xC8, 0xA5, 0x21, 0x29, 0xF3, + 0xB0, 0x02, 0x09, 0x08, 0x8D, 0x04, 0x54, 0xA5, + 0x1E, 0xF0, 0x08, 0xA5, 0x1B, 0x85, 0x1C, 0x64, + 0x1A, 0x64, 0x1E, 0x20, 0x23, 0x3A, 0xA5, 0x2B, + 0xF0, 0x0F, 0xA5, 0x2E, 0x85, 0x2F, 0xA5, 0x2C, + 0x09, 0x10, 0x8D, 0x06, 0x5C, 0x64, 0x26, 0x64, + 0x2B, 0xA5, 0x24, 0xE5, 0x25, 0xC9, 0xC8, 0xA5, + 0x2D, 0x29, 0xF3, 0xB0, 0x02, 0x09, 0x08, 0x8D, + 0x04, 0x5C, 0xA5, 0x2A, 0xF0, 0x08, 0xA5, 0x27, + 0x85, 0x28, 0x64, 0x26, 0x64, 0x2A, 0x20, 0x23, + 0x3A, 0xA5, 0x37, 0xF0, 0x0F, 0xA5, 0x3A, 0x85, + 0x3B, 0xA5, 0x38, 0x09, 0x10, 0x8D, 0x06, 0x64, + 0x64, 0x32, 0x64, 0x37, 0xA5, 0x30, 0xE5, 0x31, + 0xC9, 0xC8, 0xA5, 0x39, 0x29, 0xF3, 0xB0, 0x02, + 0x09, 0x08, 0x8D, 0x04, 0x64, 0xA5, 0x36, 0xF0, + 0x08, 0xA5, 0x33, 0x85, 0x34, 0x64, 0x32, 0x64, + 0x36, 0x20, 0x23, 0x3A, 0xA5, 0x43, 0xF0, 0x0F, + 0xA5, 0x46, 0x85, 0x47, 0xA5, 0x44, 0x09, 0x10, + 0x8D, 0x06, 0x6C, 0x64, 0x3E, 0x64, 0x43, 0xA5, + 0x3C, 0xE5, 0x3D, 0xC9, 0xC8, 0xA5, 0x45, 0x29, + 0xF3, 0xB0, 0x02, 0x09, 0x08, 0x8D, 0x04, 0x6C, + 0xA5, 0x42, 0xF0, 0x08, 0xA5, 0x3F, 0x85, 0x40, + 0x64, 0x3E, 0x64, 0x42, 0x20, 0x23, 0x3A, 0xA5, + 0x4F, 0xF0, 0x0F, 0xA5, 0x52, 0x85, 0x53, 0xA5, + 0x50, 0x09, 0x10, 0x8D, 0x06, 0x74, 0x64, 0x4A, + 0x64, 0x4F, 0xA5, 0x48, 0xE5, 0x49, 0xC9, 0xC8, + 0xA5, 0x51, 0x29, 0xF3, 0xB0, 0x02, 0x09, 0x08, + 0x8D, 0x04, 0x74, 0xA5, 0x4E, 0xF0, 0x08, 0xA5, + 0x4B, 0x85, 0x4C, 0x64, 0x4A, 0x64, 0x4E, 0x20, + 0x23, 0x3A, 0x4C, 0x92, 0x38, 0xAD, 0x02, 0x44, + 0x89, 0x08, 0xF0, 0x3B, 0x89, 0x02, 0xF0, 0x1B, + 0xAD, 0x00, 0x44, 0xD0, 0x32, 0xA6, 0x00, 0xA9, + 0x01, 0x9D, 0x00, 0x10, 0xA9, 0x01, 0x9D, 0x00, + 0x09, 0xE8, 0xE4, 0x01, 0xF0, 0x02, 0x86, 0x00, + 0x4C, 0x65, 0x3A, 0xA6, 0x00, 0xAD, 0x00, 0x44, + 0x9D, 0x00, 0x09, 0x9E, 0x00, 0x10, 0xE8, 0xE4, + 0x01, 0xF0, 0x02, 0x86, 0x00, 0x29, 0x7F, 0xC9, + 0x13, 0xD0, 0x04, 0xA5, 0x0B, 0x85, 0x02, 0xAD, + 0x02, 0x44, 0x29, 0x10, 0xF0, 0x2C, 0xA6, 0x05, + 0xF0, 0x0F, 0xAD, 0x02, 0x7C, 0x29, 0x01, 0xD0, + 0x21, 0x8E, 0x00, 0x44, 0x64, 0x05, 0x4C, 0x98, + 0x3A, 0xA6, 0x04, 0xE4, 0x03, 0xF0, 0x13, 0xA5, + 0x02, 0xD0, 0x0F, 0xAD, 0x02, 0x7C, 0x29, 0x01, + 0xD0, 0x08, 0xBD, 0x00, 0x02, 0x8D, 0x00, 0x44, + 0xE6, 0x04, 0xAD, 0x02, 0x4C, 0x89, 0x08, 0xF0, + 0x3B, 0x89, 0x02, 0xF0, 0x1B, 0xAD, 0x00, 0x4C, + 0xD0, 0x32, 0xA6, 0x0C, 0xA9, 0x01, 0x9D, 0x00, + 0x11, 0xA9, 0x01, 0x9D, 0x00, 0x0A, 0xE8, 0xE4, + 0x0D, 0xF0, 0x02, 0x86, 0x0C, 0x4C, 0xDA, 0x3A, + 0xA6, 0x0C, 0xAD, 0x00, 0x4C, 0x9D, 0x00, 0x0A, + 0x9E, 0x00, 0x11, 0xE8, 0xE4, 0x0D, 0xF0, 0x02, + 0x86, 0x0C, 0x29, 0x7F, 0xC9, 0x13, 0xD0, 0x04, + 0xA5, 0x17, 0x85, 0x0E, 0xAD, 0x02, 0x4C, 0x29, + 0x10, 0xF0, 0x2C, 0xA6, 0x11, 0xF0, 0x0F, 0xAD, + 0x02, 0x7C, 0x29, 0x02, 0xD0, 0x21, 0x8E, 0x00, + 0x4C, 0x64, 0x11, 0x4C, 0x0D, 0x3B, 0xA6, 0x10, + 0xE4, 0x0F, 0xF0, 0x13, 0xA5, 0x0E, 0xD0, 0x0F, + 0xAD, 0x02, 0x7C, 0x29, 0x02, 0xD0, 0x08, 0xBD, + 0x00, 0x03, 0x8D, 0x00, 0x4C, 0xE6, 0x10, 0xAD, + 0x02, 0x54, 0x89, 0x08, 0xF0, 0x3B, 0x89, 0x02, + 0xF0, 0x1B, 0xAD, 0x00, 0x54, 0xD0, 0x32, 0xA6, + 0x18, 0xA9, 0x01, 0x9D, 0x00, 0x12, 0xA9, 0x01, + 0x9D, 0x00, 0x0B, 0xE8, 0xE4, 0x19, 0xF0, 0x02, + 0x86, 0x18, 0x4C, 0x4F, 0x3B, 0xA6, 0x18, 0xAD, + 0x00, 0x54, 0x9D, 0x00, 0x0B, 0x9E, 0x00, 0x12, + 0xE8, 0xE4, 0x19, 0xF0, 0x02, 0x86, 0x18, 0x29, + 0x7F, 0xC9, 0x13, 0xD0, 0x04, 0xA5, 0x23, 0x85, + 0x1A, 0xAD, 0x02, 0x54, 0x29, 0x10, 0xF0, 0x2C, + 0xA6, 0x1D, 0xF0, 0x0F, 0xAD, 0x02, 0x7C, 0x29, + 0x04, 0xD0, 0x21, 0x8E, 0x00, 0x54, 0x64, 0x1D, + 0x4C, 0x82, 0x3B, 0xA6, 0x1C, 0xE4, 0x1B, 0xF0, + 0x13, 0xA5, 0x1A, 0xD0, 0x0F, 0xAD, 0x02, 0x7C, + 0x29, 0x04, 0xD0, 0x08, 0xBD, 0x00, 0x04, 0x8D, + 0x00, 0x54, 0xE6, 0x1C, 0xAD, 0x02, 0x5C, 0x89, + 0x08, 0xF0, 0x3B, 0x89, 0x02, 0xF0, 0x1B, 0xAD, + 0x00, 0x5C, 0xD0, 0x32, 0xA6, 0x24, 0xA9, 0x01, + 0x9D, 0x00, 0x13, 0xA9, 0x01, 0x9D, 0x00, 0x0C, + 0xE8, 0xE4, 0x25, 0xF0, 0x02, 0x86, 0x24, 0x4C, + 0xC4, 0x3B, 0xA6, 0x24, 0xAD, 0x00, 0x5C, 0x9D, + 0x00, 0x0C, 0x9E, 0x00, 0x13, 0xE8, 0xE4, 0x25, + 0xF0, 0x02, 0x86, 0x24, 0x29, 0x7F, 0xC9, 0x13, + 0xD0, 0x04, 0xA5, 0x2F, 0x85, 0x26, 0xAD, 0x02, + 0x5C, 0x29, 0x10, 0xF0, 0x2C, 0xA6, 0x29, 0xF0, + 0x0F, 0xAD, 0x02, 0x7C, 0x29, 0x08, 0xD0, 0x21, + 0x8E, 0x00, 0x5C, 0x64, 0x29, 0x4C, 0xF7, 0x3B, + 0xA6, 0x28, 0xE4, 0x27, 0xF0, 0x13, 0xA5, 0x26, + 0xD0, 0x0F, 0xAD, 0x02, 0x7C, 0x29, 0x08, 0xD0, + 0x08, 0xBD, 0x00, 0x05, 0x8D, 0x00, 0x5C, 0xE6, + 0x28, 0xAD, 0x02, 0x64, 0x89, 0x08, 0xF0, 0x3B, + 0x89, 0x02, 0xF0, 0x1B, 0xAD, 0x00, 0x64, 0xD0, + 0x32, 0xA6, 0x30, 0xA9, 0x01, 0x9D, 0x00, 0x14, + 0xA9, 0x01, 0x9D, 0x00, 0x0D, 0xE8, 0xE4, 0x31, + 0xF0, 0x02, 0x86, 0x30, 0x4C, 0x39, 0x3C, 0xA6, + 0x30, 0xAD, 0x00, 0x64, 0x9D, 0x00, 0x0D, 0x9E, + 0x00, 0x14, 0xE8, 0xE4, 0x31, 0xF0, 0x02, 0x86, + 0x30, 0x29, 0x7F, 0xC9, 0x13, 0xD0, 0x04, 0xA5, + 0x3B, 0x85, 0x32, 0xAD, 0x02, 0x64, 0x29, 0x10, + 0xF0, 0x2C, 0xA6, 0x35, 0xF0, 0x0F, 0xAD, 0x02, + 0x7C, 0x29, 0x10, 0xD0, 0x21, 0x8E, 0x00, 0x64, + 0x64, 0x35, 0x4C, 0x6C, 0x3C, 0xA6, 0x34, 0xE4, + 0x33, 0xF0, 0x13, 0xA5, 0x32, 0xD0, 0x0F, 0xAD, + 0x02, 0x7C, 0x29, 0x10, 0xD0, 0x08, 0xBD, 0x00, + 0x06, 0x8D, 0x00, 0x64, 0xE6, 0x34, 0xAD, 0x02, + 0x6C, 0x89, 0x08, 0xF0, 0x3B, 0x89, 0x02, 0xF0, + 0x1B, 0xAD, 0x00, 0x6C, 0xD0, 0x32, 0xA6, 0x3C, + 0xA9, 0x01, 0x9D, 0x00, 0x15, 0xA9, 0x01, 0x9D, + 0x00, 0x0E, 0xE8, 0xE4, 0x3D, 0xF0, 0x02, 0x86, + 0x3C, 0x4C, 0xAE, 0x3C, 0xA6, 0x3C, 0xAD, 0x00, + 0x6C, 0x9D, 0x00, 0x0E, 0x9E, 0x00, 0x15, 0xE8, + 0xE4, 0x3D, 0xF0, 0x02, 0x86, 0x3C, 0x29, 0x7F, + 0xC9, 0x13, 0xD0, 0x04, 0xA5, 0x47, 0x85, 0x3E, + 0xAD, 0x02, 0x6C, 0x29, 0x10, 0xF0, 0x2C, 0xA6, + 0x41, 0xF0, 0x0F, 0xAD, 0x02, 0x7C, 0x29, 0x20, + 0xD0, 0x21, 0x8E, 0x00, 0x6C, 0x64, 0x41, 0x4C, + 0xE1, 0x3C, 0xA6, 0x40, 0xE4, 0x3F, 0xF0, 0x13, + 0xA5, 0x3E, 0xD0, 0x0F, 0xAD, 0x02, 0x7C, 0x29, + 0x20, 0xD0, 0x08, 0xBD, 0x00, 0x07, 0x8D, 0x00, + 0x6C, 0xE6, 0x40, 0xAD, 0x02, 0x74, 0x89, 0x08, + 0xF0, 0x3B, 0x89, 0x02, 0xF0, 0x1B, 0xAD, 0x00, + 0x74, 0xD0, 0x32, 0xA6, 0x48, 0xA9, 0x01, 0x9D, + 0x00, 0x16, 0xA9, 0x01, 0x9D, 0x00, 0x0F, 0xE8, + 0xE4, 0x49, 0xF0, 0x02, 0x86, 0x48, 0x4C, 0x23, + 0x3D, 0xA6, 0x48, 0xAD, 0x00, 0x74, 0x9D, 0x00, + 0x0F, 0x9E, 0x00, 0x16, 0xE8, 0xE4, 0x49, 0xF0, + 0x02, 0x86, 0x48, 0x29, 0x7F, 0xC9, 0x13, 0xD0, + 0x04, 0xA5, 0x53, 0x85, 0x4A, 0xAD, 0x02, 0x74, + 0x29, 0x10, 0xF0, 0x2C, 0xA6, 0x4D, 0xF0, 0x0F, + 0xAD, 0x02, 0x7C, 0x29, 0x40, 0xD0, 0x21, 0x8E, + 0x00, 0x74, 0x64, 0x4D, 0x4C, 0x56, 0x3D, 0xA6, + 0x4C, 0xE4, 0x4B, 0xF0, 0x13, 0xA5, 0x4A, 0xD0, + 0x0F, 0xAD, 0x02, 0x7C, 0x29, 0x40, 0xD0, 0x08, + 0xBD, 0x00, 0x08, 0x8D, 0x00, 0x74, 0xE6, 0x4C, + 0x60, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xD0, 0xD0, 0x00, 0x38, + 0xCE, 0xC0, +}; diff -u --recursive --new-file v2.4.6/linux/drivers/char/serial.c linux/drivers/char/serial.c --- v2.4.6/linux/drivers/char/serial.c Sun May 20 12:11:38 2001 +++ linux/drivers/char/serial.c Sun Jul 8 13:14:37 2001 @@ -59,8 +59,8 @@ * */ -static char *serial_version = "5.05a"; -static char *serial_revdate = "2001-03-20"; +static char *serial_version = "5.05c"; +static char *serial_revdate = "2001-07-08"; /* * Serial driver configuration section. Here are the various options: @@ -3512,7 +3512,7 @@ struct serial_state *state, unsigned long flags) { - unsigned char scratch, scratch2, scratch3; + unsigned char scratch, scratch2, scratch3, scratch4; /* * First we check to see if it's an Oxford Semiconductor UART. @@ -3556,17 +3556,32 @@ * XR16C854. * */ + + /* Save the DLL and DLM */ + serial_outp(info, UART_LCR, UART_LCR_DLAB); + scratch3 = serial_inp(info, UART_DLL); + scratch4 = serial_inp(info, UART_DLM); + serial_outp(info, UART_DLL, 0); serial_outp(info, UART_DLM, 0); - state->revision = serial_inp(info, UART_DLL); + scratch2 = serial_inp(info, UART_DLL); scratch = serial_inp(info, UART_DLM); serial_outp(info, UART_LCR, 0); + if (scratch == 0x10 || scratch == 0x14) { + if (scratch == 0x10) + state->revision = scratch2; state->type = PORT_16850; return; } + /* Restore the DLL and DLM */ + + serial_outp(info, UART_LCR, UART_LCR_DLAB); + serial_outp(info, UART_DLL, scratch3); + serial_outp(info, UART_DLM, scratch4); + serial_outp(info, UART_LCR, 0); /* * We distinguish between the '654 and the '650 by counting * how many bytes are in the FIFO. I'm using this for now, @@ -3917,14 +3932,14 @@ if (PREPARE_FUNC(dev) && (PREPARE_FUNC(dev))(dev) < 0) { printk("serial: PNP device '"); - printk_pnp_dev_id(board->vendor, board->device); + printk_pnp_dev_id(dev->vendor, dev->device); printk("' prepare failed\n"); return; } if (ACTIVATE_FUNC(dev) && (ACTIVATE_FUNC(dev))(dev) < 0) { printk("serial: PNP device '"); - printk_pnp_dev_id(board->vendor, board->device); + printk_pnp_dev_id(dev->vendor, dev->device); printk("' activate failed\n"); return; } @@ -3979,10 +3994,7 @@ * seems to be mainly needed on card using the PLX which also use I/O * mapped memory. */ -static int -#ifndef MODULE -__devinit -#endif +static int __devinit pci_plx9050_fn(struct pci_dev *dev, struct pci_board *board, int enable) { u8 data, *p, irq_config; @@ -4046,10 +4058,7 @@ #define PCI_DEVICE_ID_SIIG_1S_10x (PCI_DEVICE_ID_SIIG_1S_10x_550 & 0xfffc) #define PCI_DEVICE_ID_SIIG_2S_10x (PCI_DEVICE_ID_SIIG_2S_10x_550 & 0xfff8) -static int -#ifndef MODULE -__devinit -#endif +static int __devinit pci_siig10x_fn(struct pci_dev *dev, struct pci_board *board, int enable) { u16 data, *p; @@ -4078,10 +4087,7 @@ #define PCI_DEVICE_ID_SIIG_2S_20x (PCI_DEVICE_ID_SIIG_2S_20x_550 & 0xfffc) #define PCI_DEVICE_ID_SIIG_2S1P_20x (PCI_DEVICE_ID_SIIG_2S1P_20x_550 & 0xfffc) -static int -#ifndef MODULE -__devinit -#endif +static int __devinit pci_siig20x_fn(struct pci_dev *dev, struct pci_board *board, int enable) { u8 data; @@ -4102,17 +4108,14 @@ } /* Added for EKF Intel i960 serial boards */ -static int -#ifndef MODULE -__devinit -#endif +static int __devinit pci_inteli960ni_fn(struct pci_dev *dev, struct pci_board *board, int enable) { unsigned long oldval; - if (!(board->subdevice & 0x1000)) + if (!(pci_get_subdevice(dev) & 0x1000)) return(-1); if (!enable) /* is there something to deinit? */ @@ -4163,10 +4166,7 @@ { 0, 0 } }; -static int -#ifndef MODULE -__devinit -#endif +static int __devinit pci_timedia_fn(struct pci_dev *dev, struct pci_board *board, int enable) { int i, j; @@ -4178,7 +4178,7 @@ for (i=0; timedia_data[i].num; i++) { ids = timedia_data[i].ids; for (j=0; ids[j]; j++) { - if (pci_get_subvendor(dev) == ids[j]) { + if (pci_get_subdevice(dev) == ids[j]) { board->num_ports = timedia_data[i].num; return 0; } @@ -4187,530 +4187,658 @@ return 0; } +static int __devinit +pci_xircom_fn(struct pci_dev *dev, struct pci_board *board, int enable) +{ + __set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(HZ/10); + return 0; +} /* * This is the configuration table for all of the PCI serial boards - * which we support. - */ + * which we support. It is directly indexed by the pci_board_num_t enum + * value, which is encoded in the pci_device_id PCI probe table's + * driver_data member. + */ +enum pci_board_num_t { + pbn_b0_1_115200, + pbn_default = 0, + + pbn_b0_2_115200, + pbn_b0_4_115200, + + pbn_b0_1_921600, + pbn_b0_2_921600, + pbn_b0_4_921600, + + pbn_b0_bt_1_115200, + pbn_b0_bt_2_115200, + pbn_b0_bt_1_460800, + pbn_b0_bt_2_460800, + + pbn_b1_1_115200, + pbn_b1_2_115200, + pbn_b1_4_115200, + pbn_b1_8_115200, + + pbn_b1_2_921600, + pbn_b1_4_921600, + pbn_b1_8_921600, + + pbn_b1_2_1382400, + pbn_b1_4_1382400, + pbn_b1_8_1382400, + + pbn_b2_8_115200, + pbn_b2_4_460800, + pbn_b2_8_460800, + pbn_b2_16_460800, + pbn_b2_4_921600, + pbn_b2_8_921600, + + pbn_b2_bt_1_115200, + pbn_b2_bt_2_115200, + pbn_b2_bt_4_115200, + pbn_b2_bt_2_921600, + + pbn_panacom, + pbn_panacom2, + pbn_panacom4, + pbn_plx_romulus, + pbn_oxsemi, + pbn_timedia, + pbn_intel_i960, + pbn_sgi_ioc3, +#ifdef CONFIG_DDB5074 + pbn_nec_nile4, +#endif +#if 0 + pbn_dci_pccom8, +#endif + pbn_xircom_combo, + + pbn_siig10x_0, + pbn_siig10x_1, + pbn_siig10x_2, + pbn_siig10x_4, + pbn_siig20x_0, + pbn_siig20x_2, + pbn_siig20x_4, + + pbn_computone_4, + pbn_computone_6, + pbn_computone_8, +}; + static struct pci_board pci_boards[] __devinitdata = { /* - * Vendor ID, Device ID, - * Subvendor ID, Subdevice ID, * PCI Flags, Number of Ports, Base (Maximum) Baud Rate, * Offset to get to next UART's registers, * Register shift to use for memory-mapped I/O, * Initialization function, first UART offset */ + + /* Generic serial board, pbn_b0_1_115200, pbn_default */ + { SPCI_FL_BASE0, 1, 115200 }, /* pbn_b0_1_115200, + pbn_default */ + + { SPCI_FL_BASE0, 2, 115200 }, /* pbn_b0_2_115200 */ + { SPCI_FL_BASE0, 4, 115200 }, /* pbn_b0_4_115200 */ + + { SPCI_FL_BASE0, 1, 921600 }, /* pbn_b0_1_921600 */ + { SPCI_FL_BASE0, 2, 921600 }, /* pbn_b0_2_921600 */ + { SPCI_FL_BASE0, 4, 921600 }, /* pbn_b0_4_921600 */ + + { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 1, 115200 }, /* pbn_b0_bt_1_115200 */ + { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 115200 }, /* pbn_b0_bt_2_115200 */ + { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 1, 460800 }, /* pbn_b0_bt_1_460800 */ + { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 460800 }, /* pbn_b0_bt_2_460800 */ + + { SPCI_FL_BASE1, 1, 115200 }, /* pbn_b1_1_115200 */ + { SPCI_FL_BASE1, 2, 115200 }, /* pbn_b1_2_115200 */ + { SPCI_FL_BASE1, 4, 115200 }, /* pbn_b1_4_115200 */ + { SPCI_FL_BASE1, 8, 115200 }, /* pbn_b1_8_115200 */ + + { SPCI_FL_BASE1, 2, 921600 }, /* pbn_b1_2_921600 */ + { SPCI_FL_BASE1, 4, 921600 }, /* pbn_b1_4_921600 */ + { SPCI_FL_BASE1, 8, 921600 }, /* pbn_b1_8_921600 */ + + { SPCI_FL_BASE1, 2, 1382400 }, /* pbn_b1_2_1382400 */ + { SPCI_FL_BASE1, 4, 1382400 }, /* pbn_b1_4_1382400 */ + { SPCI_FL_BASE1, 8, 1382400 }, /* pbn_b1_8_1382400 */ + + { SPCI_FL_BASE2, 8, 115200 }, /* pbn_b2_8_115200 */ + { SPCI_FL_BASE2, 4, 460800 }, /* pbn_b2_4_460800 */ + { SPCI_FL_BASE2, 8, 460800 }, /* pbn_b2_8_460800 */ + { SPCI_FL_BASE2, 16, 460800 }, /* pbn_b2_16_460800 */ + { SPCI_FL_BASE2, 4, 921600 }, /* pbn_b2_4_921600 */ + { SPCI_FL_BASE2, 8, 921600 }, /* pbn_b2_8_921600 */ + + { SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 1, 115200 }, /* pbn_b2_bt_1_115200 */ + { SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 115200 }, /* pbn_b2_bt_2_115200 */ + { SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 4, 115200 }, /* pbn_b2_bt_4_115200 */ + { SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 921600 }, /* pbn_b2_bt_2_921600 */ + + { SPCI_FL_BASE2, 2, 921600, /* IOMEM */ /* pbn_panacom */ + 0x400, 7, pci_plx9050_fn }, + { SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 921600, /* pbn_panacom2 */ + 0x400, 7, pci_plx9050_fn }, + { SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 4, 921600, /* pbn_panacom4 */ + 0x400, 7, pci_plx9050_fn }, + { SPCI_FL_BASE2, 4, 921600, /* pbn_plx_romulus */ + 0x20, 2, pci_plx9050_fn, 0x03 }, + /* This board uses the size of PCI Base region 0 to + * signal now many ports are available */ + { SPCI_FL_BASE0 | SPCI_FL_REGION_SZ_CAP, 32, 115200 }, /* pbn_oxsemi */ + { SPCI_FL_BASE_TABLE, 1, 921600, /* pbn_timedia */ + 0, 0, pci_timedia_fn }, + /* EKF addition for i960 Boards form EKF with serial port */ + { SPCI_FL_BASE0, 32, 921600, /* max 256 ports */ /* pbn_intel_i960 */ + 8<<2, 2, pci_inteli960ni_fn, 0x10000}, + { SPCI_FL_BASE0 | SPCI_FL_IRQRESOURCE, /* pbn_sgi_ioc3 */ + 1, 458333, 0, 0, 0, 0x20178 }, +#ifdef CONFIG_DDB5074 + /* + * NEC Vrc-5074 (Nile 4) builtin UART. + * Conditionally compiled in since this is a motherboard device. + */ + { SPCI_FL_BASE0, 1, 520833, /* pbn_nec_nile4 */ + 64, 3, NULL, 0x300 }, +#endif +#if 0 /* PCI_DEVICE_ID_DCI_PCCOM8 ? */ /* pbn_dci_pccom8 */ + { SPCI_FL_BASE3, 8, 115200, 8 }, +#endif + { SPCI_FL_BASE0, 1, 115200, /* pbn_xircom_combo */ + 0, 0, pci_xircom_fn }, + + { SPCI_FL_BASE2, 1, 460800, /* pbn_siig10x_0 */ + 0, 0, pci_siig10x_fn }, + { SPCI_FL_BASE2, 1, 921600, /* pbn_siig10x_1 */ + 0, 0, pci_siig10x_fn }, + { SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 921600, /* pbn_siig10x_2 */ + 0, 0, pci_siig10x_fn }, + { SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 4, 921600, /* pbn_siig10x_4 */ + 0, 0, pci_siig10x_fn }, + { SPCI_FL_BASE0, 1, 921600, /* pbn_siix20x_0 */ + 0, 0, pci_siig20x_fn }, + { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 921600, /* pbn_siix20x_2 */ + 0, 0, pci_siig20x_fn }, + { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 4, 921600, /* pbn_siix20x_4 */ + 0, 0, pci_siig20x_fn }, + + { SPCI_FL_BASE0, 4, 921600, /* IOMEM */ /* pbn_computone_4 */ + 0x40, 2, NULL, 0x200 }, + { SPCI_FL_BASE0, 6, 921600, /* IOMEM */ /* pbn_computone_6 */ + 0x40, 2, NULL, 0x200 }, + { SPCI_FL_BASE0, 8, 921600, /* IOMEM */ /* pbn_computone_8 */ + 0x40, 2, NULL, 0x200 }, +}; + +/* + * Given a complete unknown PCI device, try to use some heuristics to + * guess what the configuration might be, based on the pitiful PCI + * serial specs. Returns 0 on success, 1 on failure. + */ +static int __devinit serial_pci_guess_board(struct pci_dev *dev, + struct pci_board *board) +{ + int num_iomem = 0, num_port = 0, first_port = -1; + int i; + + /* + * If it is not a communications device or the programming + * interface is greater than 6, give up. + * + * (Should we try to make guesses for multiport serial devices + * later?) + */ + if ((((dev->class >> 8) != PCI_CLASS_COMMUNICATION_SERIAL) && + ((dev->class >> 8) != PCI_CLASS_COMMUNICATION_MODEM)) || + (dev->class & 0xff) > 6) + return 1; + + for (i=0; i < 6; i++) { + if (IS_PCI_REGION_IOPORT(dev, i)) { + num_port++; + if (first_port == -1) + first_port = i; + } + if (IS_PCI_REGION_IOMEM(dev, i)) + num_iomem++; + } + + /* + * If there is 1 or 0 iomem regions, and exactly one port, use + * it. + */ + if (num_iomem <= 1 && num_port == 1) { + board->flags = first_port; + return 0; + } + return 1; +} + +static int __devinit serial_init_one(struct pci_dev *dev, + const struct pci_device_id *ent) +{ + struct pci_board *board, tmp; + int rc; + + board = &pci_boards[ent->driver_data]; + + rc = pci_enable_device(dev); + if (rc) return rc; + + if (ent->driver_data == pbn_default && + serial_pci_guess_board(dev, board)) + return -ENODEV; + else if (serial_pci_guess_board(dev, &tmp) == 0) { + printk(KERN_INFO "Redundant entry in serial pci_table. " + "Please send the output of\n" + "lspci -vv, this message (%d,%d,%d,%d)\n" + "and the manufacturer and name of " + "serial board or modem board\n" + "to serial-pci-info@lists.sourceforge.net.\n", + dev->vendor, dev->device, + pci_get_subvendor(dev), pci_get_subdevice(dev)); + } + + start_pci_pnp_board(dev, board); + + return 0; +} + +static void __devexit serial_remove_one(struct pci_dev *dev) +{ + int i; + + /* + * Iterate through all of the ports finding those that belong + * to this PCI device. + */ + for(i = 0; i < NR_PORTS; i++) { + if (rs_table[i].dev != dev) + continue; + unregister_serial(i); + rs_table[i].dev = 0; + } + /* + * Now execute any board-specific shutdown procedure + */ + for (i=0; i < NR_PCI_BOARDS; i++) { + struct pci_board_inst *brd = &serial_pci_board[i]; + + if (serial_pci_board[i].dev != dev) + continue; + if (brd->board.init_fn) + (brd->board.init_fn)(brd->dev, &brd->board, 0); + if (DEACTIVATE_FUNC(brd->dev)) + (DEACTIVATE_FUNC(brd->dev))(brd->dev); + serial_pci_board[i].dev = 0; + } +} + + +static struct pci_device_id serial_pci_tbl[] __devinitdata = { { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960, PCI_SUBVENDOR_ID_CONNECT_TECH, - PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_232, - SPCI_FL_BASE1, 8, 1382400 }, + PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_232, 0, 0, + pbn_b1_8_1382400 }, { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960, PCI_SUBVENDOR_ID_CONNECT_TECH, - PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_232, - SPCI_FL_BASE1, 4, 1382400 }, + PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_232, 0, 0, + pbn_b1_4_1382400 }, { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960, PCI_SUBVENDOR_ID_CONNECT_TECH, - PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_232, - SPCI_FL_BASE1, 2, 1382400 }, + PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_232, 0, 0, + pbn_b1_2_1382400 }, { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351, PCI_SUBVENDOR_ID_CONNECT_TECH, - PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_232, - SPCI_FL_BASE1, 8, 1382400 }, + PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_232, 0, 0, + pbn_b1_8_1382400 }, { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351, PCI_SUBVENDOR_ID_CONNECT_TECH, - PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_232, - SPCI_FL_BASE1, 4, 1382400 }, + PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_232, 0, 0, + pbn_b1_4_1382400 }, { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351, PCI_SUBVENDOR_ID_CONNECT_TECH, - PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_232, - SPCI_FL_BASE1, 2, 1382400 }, + PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_232, 0, 0, + pbn_b1_2_1382400 }, { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351, PCI_SUBVENDOR_ID_CONNECT_TECH, - PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485, - SPCI_FL_BASE1, 8, 921600 }, + PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485, 0, 0, + pbn_b1_8_921600 }, { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351, PCI_SUBVENDOR_ID_CONNECT_TECH, - PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485_4_4, - SPCI_FL_BASE1, 8, 921600 }, + PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485_4_4, 0, 0, + pbn_b1_8_921600 }, { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351, PCI_SUBVENDOR_ID_CONNECT_TECH, - PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_485, - SPCI_FL_BASE1, 4, 921600 }, + PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_485, 0, 0, + pbn_b1_4_921600 }, { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351, PCI_SUBVENDOR_ID_CONNECT_TECH, - PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_485_2_2, - SPCI_FL_BASE1, 4, 921600 }, + PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_485_2_2, 0, 0, + pbn_b1_4_921600 }, { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351, PCI_SUBVENDOR_ID_CONNECT_TECH, - PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_485, - SPCI_FL_BASE1, 2, 921600 }, + PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_485, 0, 0, + pbn_b1_2_921600 }, { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351, PCI_SUBVENDOR_ID_CONNECT_TECH, - PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485_2_6, - SPCI_FL_BASE1, 8, 921600 }, + PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485_2_6, 0, 0, + pbn_b1_8_921600 }, { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351, PCI_SUBVENDOR_ID_CONNECT_TECH, - PCI_SUBDEVICE_ID_CONNECT_TECH_BH081101V1, - SPCI_FL_BASE1, 8, 921600 }, + PCI_SUBDEVICE_ID_CONNECT_TECH_BH081101V1, 0, 0, + pbn_b1_8_921600 }, { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351, PCI_SUBVENDOR_ID_CONNECT_TECH, - PCI_SUBDEVICE_ID_CONNECT_TECH_BH041101V1, - SPCI_FL_BASE1, 4, 921600 }, + PCI_SUBDEVICE_ID_CONNECT_TECH_BH041101V1, 0, 0, + pbn_b1_4_921600 }, + { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_U530, - PCI_ANY_ID, PCI_ANY_ID, - SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 1, 115200 }, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b2_bt_1_115200 }, { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_UCOMM2, - PCI_ANY_ID, PCI_ANY_ID, - SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 115200 }, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b2_bt_2_115200 }, { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_UCOMM422, - PCI_ANY_ID, PCI_ANY_ID, - SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 4, 115200 }, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b2_bt_4_115200 }, { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_UCOMM232, - PCI_ANY_ID, PCI_ANY_ID, - SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 115200 }, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b2_bt_2_115200 }, { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_COMM4, - PCI_ANY_ID, PCI_ANY_ID, - SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 4, 115200 }, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b2_bt_4_115200 }, { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_COMM8, - PCI_ANY_ID, PCI_ANY_ID, - SPCI_FL_BASE2, 8, 115200 }, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b2_8_115200 }, + { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_GTEK_SERIAL2, - PCI_ANY_ID, PCI_ANY_ID, - SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 115200 }, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b2_bt_2_115200 }, { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_SPCOM200, - PCI_ANY_ID, PCI_ANY_ID, - SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 921600 }, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b2_bt_2_921600 }, /* VScom SPCOM800, from sl@s.pl */ { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_SPCOM800, - PCI_ANY_ID, PCI_ANY_ID, - SPCI_FL_BASE2, 8, 921600 }, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b2_8_921600 }, { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_1077, - PCI_ANY_ID, PCI_ANY_ID, - SPCI_FL_BASE2, 4, 921600 }, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b2_4_921600 }, { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, PCI_SUBVENDOR_ID_KEYSPAN, - PCI_SUBDEVICE_ID_KEYSPAN_SX2, - SPCI_FL_BASE2, 2, 921600, /* IOMEM */ - 0x400, 7, pci_plx9050_fn }, + PCI_SUBDEVICE_ID_KEYSPAN_SX2, 0, 0, + pbn_panacom }, { PCI_VENDOR_ID_PANACOM, PCI_DEVICE_ID_PANACOM_QUADMODEM, - PCI_ANY_ID, PCI_ANY_ID, - SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 4, 921600, - 0x400, 7, pci_plx9050_fn }, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_panacom4 }, { PCI_VENDOR_ID_PANACOM, PCI_DEVICE_ID_PANACOM_DUALMODEM, - PCI_ANY_ID, PCI_ANY_ID, - SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 921600, - 0x400, 7, pci_plx9050_fn }, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_panacom2 }, { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, PCI_SUBVENDOR_ID_CHASE_PCIFAST, - PCI_SUBDEVICE_ID_CHASE_PCIFAST4, - SPCI_FL_BASE2, 4, 460800 }, + PCI_SUBDEVICE_ID_CHASE_PCIFAST4, 0, 0, + pbn_b2_4_460800 }, { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, PCI_SUBVENDOR_ID_CHASE_PCIFAST, - PCI_SUBDEVICE_ID_CHASE_PCIFAST8, - SPCI_FL_BASE2, 8, 460800 }, + PCI_SUBDEVICE_ID_CHASE_PCIFAST8, 0, 0, + pbn_b2_8_460800 }, { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, PCI_SUBVENDOR_ID_CHASE_PCIFAST, - PCI_SUBDEVICE_ID_CHASE_PCIFAST16, - SPCI_FL_BASE2, 16, 460800 }, + PCI_SUBDEVICE_ID_CHASE_PCIFAST16, 0, 0, + pbn_b2_16_460800 }, { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, PCI_SUBVENDOR_ID_CHASE_PCIFAST, - PCI_SUBDEVICE_ID_CHASE_PCIFAST16FMC, - SPCI_FL_BASE2, 16, 460800 }, + PCI_SUBDEVICE_ID_CHASE_PCIFAST16FMC, 0, 0, + pbn_b2_16_460800 }, { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, PCI_SUBVENDOR_ID_CHASE_PCIRAS, - PCI_SUBDEVICE_ID_CHASE_PCIRAS4, - SPCI_FL_BASE2, 4, 460800 }, + PCI_SUBDEVICE_ID_CHASE_PCIRAS4, 0, 0, + pbn_b2_4_460800 }, { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, PCI_SUBVENDOR_ID_CHASE_PCIRAS, - PCI_SUBDEVICE_ID_CHASE_PCIRAS8, - SPCI_FL_BASE2, 8, 460800 }, + PCI_SUBDEVICE_ID_CHASE_PCIRAS8, 0, 0, + pbn_b2_8_460800 }, /* Megawolf Romulus PCI Serial Card, from Mike Hudson */ /* (Exoray@isys.ca) */ { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_ROMULUS, - 0x10b5, 0x106a, - SPCI_FL_BASE2, 4, 921600, - 0x20, 2, pci_plx9050_fn, 0x03 }, + 0x10b5, 0x106a, 0, 0, + pbn_plx_romulus }, { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_QSC100, - PCI_ANY_ID, PCI_ANY_ID, - SPCI_FL_BASE1, 4, 115200 }, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b1_4_115200 }, { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_DSC100, - PCI_ANY_ID, PCI_ANY_ID, - SPCI_FL_BASE1, 2, 115200 }, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b1_2_115200 }, { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_ESC100D, - PCI_ANY_ID, PCI_ANY_ID, - SPCI_FL_BASE1, 8, 115200 }, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b1_8_115200 }, { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_ESC100M, - PCI_ANY_ID, PCI_ANY_ID, - SPCI_FL_BASE1, 8, 115200 }, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b1_8_115200 }, { PCI_VENDOR_ID_SPECIALIX, PCI_DEVICE_ID_OXSEMI_16PCI954, - PCI_VENDOR_ID_SPECIALIX, PCI_SUBDEVICE_ID_SPECIALIX_SPEED4, - SPCI_FL_BASE0 , 4, 921600 }, + PCI_VENDOR_ID_SPECIALIX, PCI_SUBDEVICE_ID_SPECIALIX_SPEED4, 0, 0, + pbn_b0_4_921600 }, { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI954, - PCI_ANY_ID, PCI_ANY_ID, - SPCI_FL_BASE0 , 4, 115200 }, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b0_4_115200 }, { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI952, - PCI_ANY_ID, PCI_ANY_ID, - SPCI_FL_BASE0 , 2, 115200 }, - /* This board uses the size of PCI Base region 0 to - * signal now many ports are available */ - { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI95N, - PCI_ANY_ID, PCI_ANY_ID, - SPCI_FL_BASE0 | SPCI_FL_REGION_SZ_CAP, 32, 115200 }, - { PCI_VENDOR_ID_TIMEDIA, PCI_DEVICE_ID_TIMEDIA_1889, - PCI_VENDOR_ID_TIMEDIA, PCI_ANY_ID, - SPCI_FL_BASE_TABLE, 1, 921600, - 0, 0, pci_timedia_fn }, - { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_DSERIAL, - PCI_ANY_ID, PCI_ANY_ID, - SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 115200 }, - { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUATRO_A, - PCI_ANY_ID, PCI_ANY_ID, - SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 115200 }, - { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUATRO_B, - PCI_ANY_ID, PCI_ANY_ID, - SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 115200 }, - { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_PORT_PLUS, - PCI_ANY_ID, PCI_ANY_ID, - SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 460800 }, - { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUAD_A, - PCI_ANY_ID, PCI_ANY_ID, - SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 460800 }, - { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUAD_B, - PCI_ANY_ID, PCI_ANY_ID, - SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 460800 }, - { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_SSERIAL, - PCI_ANY_ID, PCI_ANY_ID, - SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 1, 115200 }, - { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_PORT_650, - PCI_ANY_ID, PCI_ANY_ID, - SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 1, 460800 }, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b0_2_115200 }, + + /* Digitan DS560-558, from jimd@esoft.com */ + { PCI_VENDOR_ID_ATT, PCI_DEVICE_ID_ATT_VENUS_MODEM, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b1_1_115200 }, + + /* 3Com US Robotics 56k Voice Internal PCI model 5610 */ + { PCI_VENDOR_ID_USR, 0x1008, + PCI_ANY_ID, PCI_ANY_ID, }, + + /* Titan Electronic cards */ + { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_100, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b0_1_921600 }, + { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b0_2_921600 }, + { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_400, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b0_4_921600 }, + { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800B, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b0_4_921600 }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_10x_550, - PCI_ANY_ID, PCI_ANY_ID, - SPCI_FL_BASE2, 1, 460800, - 0, 0, pci_siig10x_fn }, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_siig10x_0 }, { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_10x_650, - PCI_ANY_ID, PCI_ANY_ID, - SPCI_FL_BASE2, 1, 460800, - 0, 0, pci_siig10x_fn }, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_siig10x_0 }, { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_10x_850, - PCI_ANY_ID, PCI_ANY_ID, - SPCI_FL_BASE2, 1, 460800, - 0, 0, pci_siig10x_fn }, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_siig10x_0 }, { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_10x_550, - PCI_ANY_ID, PCI_ANY_ID, - SPCI_FL_BASE2, 1, 921600, - 0, 0, pci_siig10x_fn }, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_siig10x_1 }, { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_10x_650, - PCI_ANY_ID, PCI_ANY_ID, - SPCI_FL_BASE2, 1, 921600, - 0, 0, pci_siig10x_fn }, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_siig10x_1 }, { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_10x_850, - PCI_ANY_ID, PCI_ANY_ID, - SPCI_FL_BASE2, 1, 921600, - 0, 0, pci_siig10x_fn }, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_siig10x_1 }, { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_10x_550, - PCI_ANY_ID, PCI_ANY_ID, - SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 921600, - 0, 0, pci_siig10x_fn }, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_siig10x_2 }, { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_10x_650, - PCI_ANY_ID, PCI_ANY_ID, - SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 921600, - 0, 0, pci_siig10x_fn }, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_siig10x_2 }, { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_10x_850, - PCI_ANY_ID, PCI_ANY_ID, - SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 921600, - 0, 0, pci_siig10x_fn }, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_siig10x_2 }, { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_10x_550, - PCI_ANY_ID, PCI_ANY_ID, - SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 921600, - 0, 0, pci_siig10x_fn }, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_siig10x_2 }, { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_10x_650, - PCI_ANY_ID, PCI_ANY_ID, - SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 921600, - 0, 0, pci_siig10x_fn }, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_siig10x_2 }, { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_10x_850, - PCI_ANY_ID, PCI_ANY_ID, - SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 921600, - 0, 0, pci_siig10x_fn }, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_siig10x_2 }, { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_10x_550, - PCI_ANY_ID, PCI_ANY_ID, - SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 4, 921600, - 0, 0, pci_siig10x_fn }, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_siig10x_4 }, { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_10x_650, - PCI_ANY_ID, PCI_ANY_ID, - SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 4, 921600, - 0, 0, pci_siig10x_fn }, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_siig10x_4 }, { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_10x_850, - PCI_ANY_ID, PCI_ANY_ID, - SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 4, 921600, - 0, 0, pci_siig10x_fn }, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_siig10x_4 }, { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_20x_550, - PCI_ANY_ID, PCI_ANY_ID, - SPCI_FL_BASE0, 1, 921600, - 0, 0, pci_siig20x_fn }, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_siig20x_0 }, { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_20x_650, - PCI_ANY_ID, PCI_ANY_ID, - SPCI_FL_BASE0, 1, 921600, - 0, 0, pci_siig20x_fn }, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_siig20x_0 }, { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_20x_850, - PCI_ANY_ID, PCI_ANY_ID, - SPCI_FL_BASE0, 1, 921600, - 0, 0, pci_siig20x_fn }, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_siig20x_0 }, { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_20x_550, - PCI_ANY_ID, PCI_ANY_ID, - SPCI_FL_BASE0, 1, 921600, - 0, 0, pci_siig20x_fn }, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_siig20x_0 }, { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_20x_650, - PCI_ANY_ID, PCI_ANY_ID, - SPCI_FL_BASE0, 1, 921600, - 0, 0, pci_siig20x_fn }, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_siig20x_0 }, { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_20x_850, - PCI_ANY_ID, PCI_ANY_ID, - SPCI_FL_BASE0, 1, 921600, - 0, 0, pci_siig20x_fn }, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_siig20x_0 }, { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P1S_20x_550, - PCI_ANY_ID, PCI_ANY_ID, - SPCI_FL_BASE0, 1, 921600, - 0, 0, pci_siig20x_fn }, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_siig20x_0 }, { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P1S_20x_650, - PCI_ANY_ID, PCI_ANY_ID, - SPCI_FL_BASE0, 1, 921600, - 0, 0, pci_siig20x_fn }, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_siig20x_0 }, { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P1S_20x_850, - PCI_ANY_ID, PCI_ANY_ID, - SPCI_FL_BASE0, 1, 921600, - 0, 0, pci_siig20x_fn }, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_siig20x_0 }, { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_20x_550, - PCI_ANY_ID, PCI_ANY_ID, - SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 921600, - 0, 0, pci_siig20x_fn }, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_siig20x_2 }, { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_20x_650, - PCI_ANY_ID, PCI_ANY_ID, - SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 921600, - 0, 0, pci_siig20x_fn }, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_siig20x_2 }, { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_20x_850, - PCI_ANY_ID, PCI_ANY_ID, - SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 921600, - 0, 0, pci_siig20x_fn }, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_siig20x_2 }, { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_20x_550, - PCI_ANY_ID, PCI_ANY_ID, - SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 921600, - 0, 0, pci_siig20x_fn }, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_siig20x_2 }, { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_20x_650, - PCI_ANY_ID, PCI_ANY_ID, - SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 921600, - 0, 0, pci_siig20x_fn }, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_siig20x_2 }, { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_20x_850, - PCI_ANY_ID, PCI_ANY_ID, - SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 921600, - 0, 0, pci_siig20x_fn }, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_siig20x_2 }, { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_20x_550, - PCI_ANY_ID, PCI_ANY_ID, - SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 4, 921600, - 0, 0, pci_siig20x_fn }, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_siig20x_4 }, { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_20x_650, - PCI_ANY_ID, PCI_ANY_ID, - SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 4, 921600, - 0, 0, pci_siig20x_fn }, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_siig20x_4 }, { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_20x_850, - PCI_ANY_ID, PCI_ANY_ID, - SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 4, 921600, - 0, 0, pci_siig20x_fn }, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_siig20x_4 }, + /* Computone devices submitted by Doug McNash dmcnash@computone.com */ { PCI_VENDOR_ID_COMPUTONE, PCI_DEVICE_ID_COMPUTONE_PG, PCI_SUBVENDOR_ID_COMPUTONE, PCI_SUBDEVICE_ID_COMPUTONE_PG4, - SPCI_FL_BASE0, 4, 921600, /* IOMEM */ - 0x40, 2, NULL, 0x200 }, + 0, 0, pbn_computone_4 }, { PCI_VENDOR_ID_COMPUTONE, PCI_DEVICE_ID_COMPUTONE_PG, PCI_SUBVENDOR_ID_COMPUTONE, PCI_SUBDEVICE_ID_COMPUTONE_PG8, - SPCI_FL_BASE0, 8, 921600, /* IOMEM */ - 0x40, 2, NULL, 0x200 }, + 0, 0, pbn_computone_8 }, { PCI_VENDOR_ID_COMPUTONE, PCI_DEVICE_ID_COMPUTONE_PG, PCI_SUBVENDOR_ID_COMPUTONE, PCI_SUBDEVICE_ID_COMPUTONE_PG6, - SPCI_FL_BASE0, 6, 921600, /* IOMEM */ - 0x40, 2, NULL, 0x200 }, - /* Digitan DS560-558, from jimd@esoft.com */ - { PCI_VENDOR_ID_ATT, PCI_DEVICE_ID_ATT_VENUS_MODEM, - PCI_ANY_ID, PCI_ANY_ID, - SPCI_FL_BASE1, 1, 115200 }, - /* 3Com US Robotics 56k Voice Internal PCI model 5610 */ - { PCI_VENDOR_ID_USR, 0x1008, - PCI_ANY_ID, PCI_ANY_ID, - SPCI_FL_BASE0, 1, 115200 }, - /* Titan Electronic cards */ - { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_100, - PCI_ANY_ID, PCI_ANY_ID, - SPCI_FL_BASE0, 1, 921600 }, - { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200, - PCI_ANY_ID, PCI_ANY_ID, - SPCI_FL_BASE0, 2, 921600 }, - { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_400, - PCI_ANY_ID, PCI_ANY_ID, - SPCI_FL_BASE0, 4, 921600 }, - { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800B, - PCI_ANY_ID, PCI_ANY_ID, - SPCI_FL_BASE0, 4, 921600 }, - /* EKF addition for i960 Boards form EKF with serial port */ - { PCI_VENDOR_ID_INTEL, 0x1960, - 0xE4BF, PCI_ANY_ID, - SPCI_FL_BASE0, 32, 921600, /* max 256 ports */ - 8<<2, 2, pci_inteli960ni_fn, 0x10000}, + 0, 0, pbn_computone_6 }, + + { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI95N, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_oxsemi }, + { PCI_VENDOR_ID_TIMEDIA, PCI_DEVICE_ID_TIMEDIA_1889, + PCI_VENDOR_ID_TIMEDIA, PCI_ANY_ID, 0, 0, pbn_timedia }, + + { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_DSERIAL, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b0_bt_2_115200 }, + { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUATRO_A, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b0_bt_2_115200 }, + { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUATRO_B, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b0_bt_2_115200 }, + { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_PORT_PLUS, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b0_bt_2_460800 }, + { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUAD_A, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b0_bt_2_460800 }, + { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUAD_B, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b0_bt_2_460800 }, + { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_SSERIAL, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b0_bt_1_115200 }, + { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_PORT_650, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b0_bt_1_460800 }, + /* RAStel 2 port modem, gerg@moreton.com.au */ { PCI_VENDOR_ID_MORETON, PCI_DEVICE_ID_RASTEL_2PORT, - PCI_ANY_ID, PCI_ANY_ID, - SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 115200 }, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b2_bt_2_115200 }, + + /* EKF addition for i960 Boards form EKF with serial port */ + { PCI_VENDOR_ID_INTEL, 0x1960, + 0xE4BF, PCI_ANY_ID, 0, 0, + pbn_intel_i960 }, + + /* Xircom Cardbus/Ethernet combos */ + { PCI_VENDOR_ID_XIRCOM, PCI_DEVICE_ID_XIRCOM_X3201_MDM, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_xircom_combo }, + /* * Untested PCI modems, sent in from various folks... */ + /* Elsa Model 56K PCI Modem, from Andreas Rath <arh@01019freenet.de> */ { PCI_VENDOR_ID_ROCKWELL, 0x1004, - 0x1048, 0x1500, - SPCI_FL_BASE1, 1, 115200 }, + 0x1048, 0x1500, 0, 0, + pbn_b1_1_115200 }, + { PCI_VENDOR_ID_SGI, PCI_DEVICE_ID_SGI_IOC3, - 0xFF00, 0, SPCI_FL_BASE0 | SPCI_FL_IRQRESOURCE, - 1, 458333, 0, 0, 0, 0x20178 }, -#if CONFIG_DDB5074 + 0xFF00, 0, 0, 0, + pbn_sgi_ioc3 }, + +#ifdef CONFIG_DDB5074 /* * NEC Vrc-5074 (Nile 4) builtin UART. * Conditionally compiled in since this is a motherboard device. */ { PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_NILE4, - PCI_ANY_ID, PCI_ANY_ID, - SPCI_FL_BASE0, 1, 520833, - 64, 3, NULL, 0x300 }, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_nec_nile4 }, #endif + #if 0 /* PCI_DEVICE_ID_DCI_PCCOM8 ? */ { PCI_VENDOR_ID_DCI, PCI_DEVICE_ID_DCI_PCCOM8, - PCI_ANY_ID, PCI_ANY_ID, - SPCI_FL_BASE3, 8, 115200, - 8 }, -#endif - /* Generic serial board */ - { 0, 0, - 0, 0, - SPCI_FL_BASE0, 1, 115200 }, -}; - -/* - * Given a complete unknown PCI device, try to use some heuristics to - * guess what the configuration might be, based on the pitiful PCI - * serial specs. Returns 0 on success, 1 on failure. - */ -static int _INLINE_ serial_pci_guess_board(struct pci_dev *dev, - struct pci_board *board) -{ - int num_iomem = 0, num_port = 0, first_port = -1; - int i; - - /* - * If it is not a communications device or the programming - * interface is greater than 6, give up. - * - * (Should we try to make guesses for multiport serial devices - * later?) - */ - if ((((dev->class >> 8) != PCI_CLASS_COMMUNICATION_SERIAL) && - ((dev->class >> 8) != PCI_CLASS_COMMUNICATION_MODEM)) || - (dev->class & 0xff) > 6) - return 1; - - for (i=0; i < 6; i++) { - if (IS_PCI_REGION_IOPORT(dev, i)) { - num_port++; - if (first_port == -1) - first_port = i; - } - if (IS_PCI_REGION_IOMEM(dev, i)) - num_iomem++; - } - - /* - * If there is 1 or 0 iomem regions, and exactly one port, use - * it. - */ - if (num_iomem <= 1 && num_port == 1) { - board->flags = first_port; - return 0; - } - return 1; -} - -static int __devinit serial_init_one(struct pci_dev *dev, - const struct pci_device_id *ent) -{ - struct pci_board *board, tmp; - int rc; - - for (board = pci_boards; board->vendor; board++) { - if (board->vendor != (unsigned short) PCI_ANY_ID && - dev->vendor != board->vendor) - continue; - if (board->device != (unsigned short) PCI_ANY_ID && - dev->device != board->device) - continue; - if (board->subvendor != (unsigned short) PCI_ANY_ID && - pci_get_subvendor(dev) != board->subvendor) - continue; - if (board->subdevice != (unsigned short) PCI_ANY_ID && - pci_get_subdevice(dev) != board->subdevice) - continue; - break; - } - - rc = pci_enable_device(dev); - if (rc) return rc; - - if (board->vendor == 0 && serial_pci_guess_board(dev, board)) - return -ENODEV; - else if (serial_pci_guess_board(dev, &tmp) == 0) { - printk(KERN_INFO "Redundant entry in serial pci_table. " - "Please send the output of\n" - "lspci -vv, this message (%d,%d,%d,%d)\n" - "and the manufacturer and name of " - "serial board or modem board\n" - "to serial-pci-info@lists.sourceforge.net.\n", - dev->vendor, dev->device, - pci_get_subvendor(dev), pci_get_subdevice(dev)); - } - - start_pci_pnp_board(dev, board); - - return 0; -} - -static void __devexit serial_remove_one(struct pci_dev *dev) -{ - int i; - - /* - * Iterate through all of the ports finding those that belong - * to this PCI device. - */ - for(i = 0; i < NR_PORTS; i++) { - if (rs_table[i].dev != dev) - continue; - unregister_serial(i); - rs_table[i].dev = 0; - } - /* - * Now execute any board-specific shutdown procedure - */ - for (i=0; i < NR_PCI_BOARDS; i++) { - struct pci_board_inst *brd = &serial_pci_board[i]; - - if (serial_pci_board[i].dev != dev) - continue; - if (brd->board.init_fn) - (brd->board.init_fn)(brd->dev, &brd->board, 0); - if (DEACTIVATE_FUNC(brd->dev)) - (DEACTIVATE_FUNC(brd->dev))(brd->dev); - serial_pci_board[i].dev = 0; - } -} - + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_dci_pccom8 }, +#endif -static struct pci_device_id serial_pci_tbl[] __devinitdata = { { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_COMMUNICATION_SERIAL << 8, 0xffff00, }, { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, @@ -4746,7 +4874,7 @@ * not to attempt to unregister the driver later */ if (pci_module_init (&serial_pci_driver) != 0) - serial_pci_driver.name[0] = 0; + serial_pci_driver.name = ""; #ifdef SERIAL_DEBUG_PCI printk(KERN_DEBUG "Leaving probe_serial_pci() (probe finished)\n"); @@ -5153,11 +5281,9 @@ break; if (pnp_board->vendor) { - board.vendor = pnp_board->vendor; - board.device = pnp_board->device; /* Special case that's more efficient to hardcode */ - if ((board.vendor == ISAPNP_VENDOR('A', 'K', 'Y') && - board.device == ISAPNP_DEVICE(0x1021))) + if ((pnp_board->vendor == ISAPNP_VENDOR('A', 'K', 'Y') && + pnp_board->device == ISAPNP_DEVICE(0x1021))) board.flags |= SPCI_FL_NO_SHIRQ; } else { if (serial_pnp_guess_board(dev, &board)) diff -u --recursive --new-file v2.4.6/linux/drivers/char/sonypi.c linux/drivers/char/sonypi.c --- v2.4.6/linux/drivers/char/sonypi.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/sonypi.c Wed Jul 4 14:41:33 2001 @@ -0,0 +1,716 @@ +/* + * Sony Programmable I/O Control Device driver for VAIO + * + * Copyright (C) 2001 Stelian Pop <stelian.pop@fr.alcove.com>, Alcôve + * + * Copyright (C) 2001 Michael Ashley <m.ashley@unsw.edu.au> + * + * Copyright (C) 2001 Junichi Morita <jun1m@mars.dti.ne.jp> + * + * Copyright (C) 2000 Takaya Kinjo <t-kinjo@tc4.so-net.ne.jp> + * + * Copyright (C) 2000 Andrew Tridgell <tridge@valinux.com> + * + * Earlier work by Werner Almesberger, Paul `Rusty' Russell and Paul Mackerras. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/pci.h> +#include <linux/sched.h> +#include <linux/init.h> +#include <linux/miscdevice.h> +#include <linux/poll.h> +#include <linux/delay.h> +#include <asm/uaccess.h> +#include <asm/io.h> + +#include "sonypi.h" +#include <linux/sonypi.h> + +static struct sonypi_device sonypi_device; +static int minor = -1; +static int verbose; /* = 0 */ +static int fnkeyinit; /* = 0 */ +static int camera; /* = 0 */ + +/* Inits the queue */ +static inline void sonypi_initq(void) { + sonypi_device.queue.head = sonypi_device.queue.tail = 0; + sonypi_device.queue.len = 0; + sonypi_device.queue.s_lock = (spinlock_t)SPIN_LOCK_UNLOCKED; + init_waitqueue_head(&sonypi_device.queue.proc_list); +} + +/* Pulls an event from the queue */ +static inline unsigned char sonypi_pullq(void) { + unsigned char result; + unsigned long flags; + + spin_lock_irqsave(&sonypi_device.queue.s_lock, flags); + if (!sonypi_device.queue.len) { + spin_unlock_irqrestore(&sonypi_device.queue.s_lock, flags); + return 0; + } + result = sonypi_device.queue.buf[sonypi_device.queue.head]; + sonypi_device.queue.head++; + sonypi_device.queue.head &= (SONYPI_BUF_SIZE - 1); + sonypi_device.queue.len--; + spin_unlock_irqrestore(&sonypi_device.queue.s_lock, flags); + return result; +} + +/* Pushes an event into the queue */ +static inline void sonypi_pushq(unsigned char event) { + unsigned long flags; + + spin_lock_irqsave(&sonypi_device.queue.s_lock, flags); + if (sonypi_device.queue.len == SONYPI_BUF_SIZE) { + /* remove the first element */ + sonypi_device.queue.head++; + sonypi_device.queue.head &= (SONYPI_BUF_SIZE - 1); + sonypi_device.queue.len--; + } + sonypi_device.queue.buf[sonypi_device.queue.tail] = event; + sonypi_device.queue.tail++; + sonypi_device.queue.tail &= (SONYPI_BUF_SIZE - 1); + sonypi_device.queue.len++; + + kill_fasync(&sonypi_device.queue.fasync, SIGIO, POLL_IN); + wake_up_interruptible(&sonypi_device.queue.proc_list); + spin_unlock_irqrestore(&sonypi_device.queue.s_lock, flags); +} + +/* Tests if the queue is empty */ +static inline int sonypi_emptyq(void) { + int result; + unsigned long flags; + + spin_lock_irqsave(&sonypi_device.queue.s_lock, flags); + result = (sonypi_device.queue.len == 0); + spin_unlock_irqrestore(&sonypi_device.queue.s_lock, flags); + return result; +} + +static void sonypi_ecrset(u16 addr, u16 value) { + int n = 100; + + while (n-- && (inw_p(SONYPI_CST_IOPORT) & 3)) + udelay(1); + outw_p(0x81, SONYPI_CST_IOPORT); + while (inw_p(SONYPI_CST_IOPORT) & 2) + udelay(1); + outw_p(addr, SONYPI_DATA_IOPORT); + while (inw_p(SONYPI_CST_IOPORT) & 2) + udelay(1); + outw_p(value, SONYPI_DATA_IOPORT); + while (inw_p(SONYPI_CST_IOPORT) & 2) + udelay(1); +} + +static u16 sonypi_ecrget(u16 addr) { + int n = 100; + + while (n-- && (inw_p(SONYPI_CST_IOPORT) & 3)) + udelay(1); + outw_p(0x80, SONYPI_CST_IOPORT); + while (inw_p(SONYPI_CST_IOPORT) & 2) + udelay(1); + outw_p(addr, SONYPI_DATA_IOPORT); + while (inw_p(SONYPI_CST_IOPORT) & 2) + udelay(1); + return inw_p(SONYPI_DATA_IOPORT); +} + +/* Initializes the device - this comes from the AML code in the ACPI bios */ +static void __devinit sonypi_normal_srs(void) { + u32 v; + + pci_read_config_dword(sonypi_device.dev, SONYPI_G10A, &v); + v = (v & 0xFFFF0000) | ((u32)sonypi_device.ioport1); + pci_write_config_dword(sonypi_device.dev, SONYPI_G10A, v); + + pci_read_config_dword(sonypi_device.dev, SONYPI_G10A, &v); + v = (v & 0xFFF0FFFF) | + (((u32)sonypi_device.ioport1 ^ sonypi_device.ioport2) << 16); + pci_write_config_dword(sonypi_device.dev, SONYPI_G10A, v); + + v = inl(SONYPI_IRQ_PORT); + v &= ~(((u32)0x3) << SONYPI_IRQ_SHIFT); + v |= (((u32)sonypi_device.bits) << SONYPI_IRQ_SHIFT); + outl(v, SONYPI_IRQ_PORT); + + pci_read_config_dword(sonypi_device.dev, SONYPI_G10A, &v); + v = (v & 0xFF1FFFFF) | 0x00C00000; + pci_write_config_dword(sonypi_device.dev, SONYPI_G10A, v); +} + +static void __devinit sonypi_r505_srs(void) { + sonypi_ecrset(SONYPI_SHIB, (sonypi_device.ioport1 & 0xFF00) >> 8); + sonypi_ecrset(SONYPI_SLOB, sonypi_device.ioport1 & 0x00FF); + sonypi_ecrset(SONYPI_SIRQ, sonypi_device.bits); + udelay(10); +} + +/* Disables the device - this comes from the AML code in the ACPI bios */ +static void __devexit sonypi_normal_dis(void) { + u32 v; + + pci_read_config_dword(sonypi_device.dev, SONYPI_G10A, &v); + v = v & 0xFF3FFFFF; + pci_write_config_dword(sonypi_device.dev, SONYPI_G10A, v); + + v = inl(SONYPI_IRQ_PORT); + v |= (0x3 << SONYPI_IRQ_SHIFT); + outl(v, SONYPI_IRQ_PORT); +} + +static void __devexit sonypi_r505_dis(void) { + sonypi_ecrset(SONYPI_SHIB, 0); + sonypi_ecrset(SONYPI_SLOB, 0); + sonypi_ecrset(SONYPI_SIRQ, 0); +} + +static u8 sonypi_call1(u8 dev) { + u8 v1, v2; + + while (inb_p(sonypi_device.ioport2) & 2) + udelay(1); + outb(dev, sonypi_device.ioport2); + v1 = inb_p(sonypi_device.ioport2); + v2 = inb_p(sonypi_device.ioport1); + return v2; +} + +static u8 sonypi_call2(u8 dev, u8 fn) { + u8 v1; + + while (inb_p(sonypi_device.ioport2) & 2) + udelay(1); + outb(dev, sonypi_device.ioport2); + + while (inb_p(sonypi_device.ioport2) & 2) + udelay(1); + outb(fn, sonypi_device.ioport1); + + v1 = inb_p(sonypi_device.ioport1); + return v1; +} + +static u8 sonypi_call3(u8 dev, u8 fn, u8 v) { + u8 v1; + + while (inb_p(sonypi_device.ioport2) & 2) + udelay(1); + outb(dev, sonypi_device.ioport2); + + while (inb_p(sonypi_device.ioport2) & 2) + udelay(1); + outb(fn, sonypi_device.ioport1); + + while (inb_p(sonypi_device.ioport2) & 2) + udelay(1); + outb(v, sonypi_device.ioport1); + + v1 = inb_p(sonypi_device.ioport1); + return v1; +} + +static u8 sonypi_read(u8 fn) { + u8 v1, v2; + int n = 100; + + while (n--) { + v1 = sonypi_call2(0x8f, fn); + v2 = sonypi_call2(0x8f, fn); + if (v1 == v2 && v1 != 0xff) + return v1; + } + return 0xff; +} + +/* Set brightness, hue etc */ +static void sonypi_set(u8 fn, u8 v) { + int n = 100; + + while (n--) + if (sonypi_call3(0x90, fn, v) == 0) + break; +} + +/* Tests if the camera is ready */ +static int sonypi_camera_ready(void) { + u8 v; + + v = sonypi_call2(0x8f, SONYPI_CAMERA_STATUS); + return (v != 0xff && (v & SONYPI_CAMERA_STATUS_READY)); +} + +/* Turns the camera off */ +static void sonypi_camera_off(void) { + + sonypi_set(SONYPI_CAMERA_PICTURE, SONYPI_CAMERA_MUTE_MASK); + + if (!sonypi_device.camera_power) + return; + + sonypi_call2(0x91, 0); + sonypi_device.camera_power = 0; +} + +/* Turns the camera on */ +static void sonypi_camera_on(void) { + int i, j; + + if (sonypi_device.camera_power) + return; + + for (j = 5; j > 0; j--) { + + while (sonypi_call2(0x91, 0x1) != 0) { + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(1); + } + sonypi_call1(0x93); + + for (i = 400; i > 0; i--) { + if (sonypi_camera_ready()) + break; + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(1); + } + if (i != 0) + break; + } + + if (j == 0) { + printk(KERN_WARNING "sonypi: failed to power on camera\n"); + return; + } + + sonypi_set(0x10, 0x5a); + sonypi_device.camera_power = 1; +} + +/* 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; + + if (sonypi_device.model == SONYPI_DEVICE_MODEL_R505) { + sonypi_jogger_ev = SONYPI_R505_JOGGER_EV; + sonypi_fnkey_ev = SONYPI_R505_FNKEY_EV; + } + else { + sonypi_jogger_ev = SONYPI_NORMAL_JOGGER_EV; + sonypi_fnkey_ev = SONYPI_NORMAL_FNKEY_EV; + } + + v1 = inb_p(sonypi_device.ioport1); + v2 = inb_p(sonypi_device.ioport2); + + if ((v2 & sonypi_jogger_ev) == sonypi_jogger_ev) { + for (i = 0; sonypi_joggerev[i].event; i++) + if (sonypi_joggerev[i].data == v1) { + event = sonypi_joggerev[i].event; + goto found; + } + } + 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; + goto found; + } + } + if ((v2 & sonypi_fnkey_ev) == sonypi_fnkey_ev) { + for (i = 0; sonypi_fnkeyev[i].event; i++) + if (sonypi_fnkeyev[i].data == v1) { + event = sonypi_fnkeyev[i].event; + goto found; + } + } + 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; + goto found; + } + } + if (verbose) + printk(KERN_WARNING + "sonypi: unknown event port1=0x%x,port2=0x%x\n",v1,v2); + return; + +found: + sonypi_pushq(event); +} + +/* External camera command (exported to the motion eye v4l driver) */ +u8 sonypi_camera_command(int command, u8 value) { + u8 ret = 0; + + if (!camera) + return 0; + + down(&sonypi_device.lock); + + switch(command) { + case SONYPI_COMMAND_GETCAMERA: + ret = sonypi_camera_ready(); + break; + case SONYPI_COMMAND_SETCAMERA: + if (value) + sonypi_camera_on(); + else + sonypi_camera_off(); + break; + case SONYPI_COMMAND_GETCAMERABRIGHTNESS: + ret = sonypi_read(SONYPI_CAMERA_BRIGHTNESS); + break; + case SONYPI_COMMAND_SETCAMERABRIGHTNESS: + sonypi_set(SONYPI_CAMERA_BRIGHTNESS, value); + break; + case SONYPI_COMMAND_GETCAMERACONTRAST: + ret = sonypi_read(SONYPI_CAMERA_CONTRAST); + break; + case SONYPI_COMMAND_SETCAMERACONTRAST: + sonypi_set(SONYPI_CAMERA_CONTRAST, value); + break; + case SONYPI_COMMAND_GETCAMERAHUE: + ret = sonypi_read(SONYPI_CAMERA_HUE); + break; + case SONYPI_COMMAND_SETCAMERAHUE: + sonypi_set(SONYPI_CAMERA_HUE, value); + break; + case SONYPI_COMMAND_GETCAMERACOLOR: + ret = sonypi_read(SONYPI_CAMERA_COLOR); + break; + case SONYPI_COMMAND_SETCAMERACOLOR: + sonypi_set(SONYPI_CAMERA_COLOR, value); + break; + case SONYPI_COMMAND_GETCAMERASHARPNESS: + ret = sonypi_read(SONYPI_CAMERA_SHARPNESS); + break; + case SONYPI_COMMAND_SETCAMERASHARPNESS: + sonypi_set(SONYPI_CAMERA_SHARPNESS, value); + break; + case SONYPI_COMMAND_GETCAMERAPICTURE: + ret = sonypi_read(SONYPI_CAMERA_PICTURE); + break; + case SONYPI_COMMAND_SETCAMERAPICTURE: + sonypi_set(SONYPI_CAMERA_PICTURE, value); + break; + case SONYPI_COMMAND_GETCAMERAAGC: + ret = sonypi_read(SONYPI_CAMERA_AGC); + break; + case SONYPI_COMMAND_SETCAMERAAGC: + sonypi_set(SONYPI_CAMERA_AGC, value); + break; + case SONYPI_COMMAND_GETCAMERADIRECTION: + ret = sonypi_read(SONYPI_CAMERA_STATUS); + ret &= SONYPI_DIRECTION_BACKWARDS; + break; + case SONYPI_COMMAND_GETCAMERAROMVERSION: + ret = sonypi_read(SONYPI_CAMERA_ROMVERSION); + break; + case SONYPI_COMMAND_GETCAMERAREVISION: + ret = sonypi_read(SONYPI_CAMERA_REVISION); + break; + } + up(&sonypi_device.lock); + return ret; +} + +static int sonypi_misc_fasync(int fd, struct file *filp, int on) { + int retval; + + retval = fasync_helper(fd, filp, on, &sonypi_device.queue.fasync); + if (retval < 0) + return retval; + return 0; +} + +static int sonypi_misc_release(struct inode * inode, struct file * file) { + sonypi_misc_fasync(-1, file, 0); + down(&sonypi_device.lock); + sonypi_device.open_count--; + up(&sonypi_device.lock); + return 0; +} + +static int sonypi_misc_open(struct inode * inode, struct file * file) { + down(&sonypi_device.lock); + if (sonypi_device.open_count) + goto out; + sonypi_device.open_count++; + /* Flush input queue */ + sonypi_initq(); +out: + up(&sonypi_device.lock); + return 0; +} + +static ssize_t sonypi_misc_read(struct file * file, char * buf, + size_t count, loff_t *pos) { + DECLARE_WAITQUEUE(wait, current); + ssize_t i = count; + unsigned char c; + + if (sonypi_emptyq()) { + if (file->f_flags & O_NONBLOCK) + return -EAGAIN; + add_wait_queue(&sonypi_device.queue.proc_list, &wait); +repeat: + set_current_state(TASK_INTERRUPTIBLE); + if (sonypi_emptyq() && !signal_pending(current)) { + schedule(); + goto repeat; + } + current->state = TASK_RUNNING; + remove_wait_queue(&sonypi_device.queue.proc_list, &wait); + } + while (i > 0 && !sonypi_emptyq()) { + c = sonypi_pullq(); + put_user(c, buf++); + i--; + } + if (count - i) { + file->f_dentry->d_inode->i_atime = CURRENT_TIME; + return count-i; + } + if (signal_pending(current)) + return -ERESTARTSYS; + return 0; +} + +static unsigned int sonypi_misc_poll(struct file *file, poll_table * wait) { + poll_wait(file, &sonypi_device.queue.proc_list, wait); + if (!sonypi_emptyq()) + return POLLIN | POLLRDNORM; + return 0; +} + +static int sonypi_misc_ioctl(struct inode *ip, struct file *fp, + unsigned int cmd, unsigned long arg) { + int ret = 0; + u8 val; + + 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; + default: + ret = -EINVAL; + } +out: + up(&sonypi_device.lock); + return ret; +} + +static struct file_operations sonypi_misc_fops = { + owner: THIS_MODULE, + read: sonypi_misc_read, + poll: sonypi_misc_poll, + open: sonypi_misc_open, + release: sonypi_misc_release, + fasync: sonypi_misc_fasync, + ioctl: sonypi_misc_ioctl, +}; + +struct miscdevice sonypi_misc_device = { + -1, "sonypi", &sonypi_misc_fops +}; + +static int __devinit sonypi_probe(struct pci_dev *pcidev, + const struct pci_device_id *ent) { + int i, ret; + struct sonypi_ioport_list *ioport_list; + struct sonypi_irq_list *irq_list; + + if (sonypi_device.dev) { + printk(KERN_ERR "sonypi: only one device allowed!\n"), + ret = -EBUSY; + goto out1; + } + sonypi_device.dev = pcidev; + sonypi_device.model = (int)ent->driver_data; + sonypi_initq(); + init_MUTEX(&sonypi_device.lock); + + if (pci_enable_device(pcidev)) { + printk(KERN_ERR "sonypi: pci_enable_device failed\n"); + ret = -EIO; + goto out1; + } + + sonypi_misc_device.minor = (minor == -1) ? + MISC_DYNAMIC_MINOR : minor; + if ((ret = misc_register(&sonypi_misc_device))) { + printk(KERN_ERR "sonypi: misc_register failed\n"); + goto out1; + } + + if (sonypi_device.model == SONYPI_DEVICE_MODEL_R505) { + ioport_list = sonypi_r505_ioport_list; + sonypi_device.region_size = SONYPI_R505_REGION_SIZE; + irq_list = sonypi_r505_irq_list; + } + else { + ioport_list = sonypi_normal_ioport_list; + sonypi_device.region_size = SONYPI_NORMAL_REGION_SIZE; + irq_list = sonypi_normal_irq_list; + } + + for (i = 0; ioport_list[i].port1; i++) { + if (request_region(ioport_list[i].port1, + sonypi_device.region_size, + "Sony Programable I/O Device")) { + /* get the ioport */ + sonypi_device.ioport1 = ioport_list[i].port1; + sonypi_device.ioport2 = ioport_list[i].port2; + break; + } + } + if (!sonypi_device.ioport1) { + printk(KERN_ERR "sonypi: request_region failed\n"); + ret = -ENODEV; + goto out2; + } + + for (i = 0; irq_list[i].irq; i++) { + if (!request_irq(irq_list[i].irq, sonypi_irq, + SA_INTERRUPT, "sonypi", sonypi_irq)) { + sonypi_device.irq = irq_list[i].irq; + sonypi_device.bits = irq_list[i].bits; + break; + } + } + if (!sonypi_device.irq ) { + printk(KERN_ERR "sonypi: request_irq failed\n"); + ret = -ENODEV; + goto out3; + } + + if (fnkeyinit) + outb(0xf0, 0xb2); + + if (sonypi_device.model == SONYPI_DEVICE_MODEL_R505) + sonypi_r505_srs(); + else + sonypi_normal_srs(); + + sonypi_call1(0x82); + sonypi_call2(0x81, 0xff); + sonypi_call1(0x92); + + printk(KERN_INFO "sonypi: Sony Programmable I/O Controller Driver v%d.%d.\n", + SONYPI_DRIVER_MAJORVERSION, + SONYPI_DRIVER_MINORVERSION); + printk(KERN_INFO "sonypi: detected %s model, camera = %s\n", + (sonypi_device.model == SONYPI_DEVICE_MODEL_NORMAL) ? + "normal" : "R505", + camera ? "on" : "off"); + printk(KERN_INFO "sonypi: enabled at irq=%d, port1=0x%x, port2=0x%x\n", + sonypi_device.irq, + sonypi_device.ioport1, sonypi_device.ioport2); + if (minor == -1) + printk(KERN_INFO "sonypi: device allocated minor is %d\n", + sonypi_misc_device.minor); + + return 0; + +out3: + release_region(sonypi_device.ioport1, sonypi_device.region_size); +out2: + misc_deregister(&sonypi_misc_device); +out1: + return ret; +} + +static void __devexit sonypi_remove(struct pci_dev *pcidev) { + sonypi_call2(0x81, 0); /* make sure we don't get any more events */ + if (camera) + sonypi_camera_off(); + if (sonypi_device.model == SONYPI_DEVICE_MODEL_R505) + sonypi_r505_dis(); + else + sonypi_normal_dis(); + free_irq(sonypi_device.irq, sonypi_irq); + release_region(sonypi_device.ioport1, sonypi_device.region_size); + misc_deregister(&sonypi_misc_device); + printk(KERN_INFO "sonypi: removed.\n"); +} + +static struct pci_device_id sonypi_id_tbl[] __devinitdata = { + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + (unsigned long) SONYPI_DEVICE_MODEL_NORMAL }, + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_10, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + (unsigned long) SONYPI_DEVICE_MODEL_R505 }, + { } +}; + +MODULE_DEVICE_TABLE(pci, sonypi_id_tbl); + +static struct pci_driver sonypi_driver = { + name: "sonypi", + id_table: sonypi_id_tbl, + probe: sonypi_probe, + remove: sonypi_remove, +}; + +static int __init sonypi_init_module(void) { + return pci_module_init(&sonypi_driver); +} + +static void __exit sonypi_cleanup_module(void) { + pci_unregister_driver(&sonypi_driver); +} + +/* Module entry points */ +module_init(sonypi_init_module); +module_exit(sonypi_cleanup_module); + +MODULE_AUTHOR("Stelian Pop <stelian.pop@fr.alcove.com>"); +MODULE_DESCRIPTION("Sony Programmable I/O Control Device driver"); + +MODULE_PARM(minor,"i"); +MODULE_PARM_DESC(minor, "minor number of the misc device, default is -1 (automatic)"); +MODULE_PARM(verbose,"i"); +MODULE_PARM_DESC(verbose, "be verbose, default is 0 (no)"); +MODULE_PARM(fnkeyinit,"i"); +MODULE_PARM_DESC(fnkeyinit, "set this if your Fn keys do not generate any event"); +MODULE_PARM(camera,"i"); +MODULE_PARM_DESC(camera, "set this if you have a MotionEye camera (PictureBook series)"); + +EXPORT_SYMBOL(sonypi_camera_command); diff -u --recursive --new-file v2.4.6/linux/drivers/char/sonypi.h linux/drivers/char/sonypi.h --- v2.4.6/linux/drivers/char/sonypi.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/sonypi.h Wed Jul 4 14:41:33 2001 @@ -0,0 +1,228 @@ +/* + * Sony Programmable I/O Control Device driver for VAIO + * + * Copyright (C) 2001 Stelian Pop <stelian.pop@fr.alcove.com>, Alcôve + * + * Copyright (C) 2001 Michael Ashley <m.ashley@unsw.edu.au> + * + * Copyright (C) 2001 Junichi Morita <jun1m@mars.dti.ne.jp> + * + * Copyright (C) 2000 Takaya Kinjo <t-kinjo@tc4.so-net.ne.jp> + * + * Copyright (C) 2000 Andrew Tridgell <tridge@valinux.com> + * + * Earlier work by Werner Almesberger, Paul `Rusty' Russell and Paul Mackerras. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef _SONYPI_PRIV_H_ +#define _SONYPI_PRIV_H_ + +#ifdef __KERNEL__ + +#define SONYPI_DRIVER_MAJORVERSION 1 +#define SONYPI_DRIVER_MINORVERSION 2 + +#include <linux/types.h> +#include <linux/pci.h> +#include "linux/sonypi.h" + +/* Normal models use those */ +#define SONYPI_IRQ_PORT 0x8034 +#define SONYPI_IRQ_SHIFT 22 +#define SONYPI_BASE 0x50 +#define SONYPI_G10A (SONYPI_BASE+0x14) +#define SONYPI_NORMAL_REGION_SIZE 0x08 + +/* R505 series specifics */ +#define SONYPI_SIRQ 0x9b +#define SONYPI_SLOB 0x9c +#define SONYPI_SHIB 0x9d +#define SONYPI_R505_REGION_SIZE 0x20 + +/* ioports used for brightness and R505 events */ +#define SONYPI_DATA_IOPORT 0x62 +#define SONYPI_CST_IOPORT 0x66 + +/* The set of possible ioports */ +struct sonypi_ioport_list { + u16 port1; + u16 port2; +}; + +static struct sonypi_ioport_list sonypi_normal_ioport_list[] = { + { 0x10c0, 0x10c4 }, /* looks like the default on C1Vx */ + { 0x1080, 0x1084 }, + { 0x1090, 0x1094 }, + { 0x10a0, 0x10a4 }, + { 0x10b0, 0x10b4 }, + { 0x0, 0x0 } +}; + +static struct sonypi_ioport_list sonypi_r505_ioport_list[] = { + { 0x1080, 0x1084 }, + { 0x10a0, 0x10a4 }, + { 0x10c0, 0x10c4 }, + { 0x10e0, 0x10e4 }, + { 0x0, 0x0 } +}; + +/* The set of possible interrupts */ +struct sonypi_irq_list { + u16 irq; + u16 bits; +}; + +static struct sonypi_irq_list sonypi_normal_irq_list[] = { + { 11, 0x2 }, /* IRQ 11, GO22=0,GO23=1 in AML */ + { 10, 0x1 }, /* IRQ 10, GO22=1,GO23=0 in AML */ + { 5, 0x0 }, /* IRQ 5, GO22=0,GO23=0 in AML */ + { 0, 0x3 } /* no IRQ, GO22=1,GO23=1 in AML */ +}; + +static struct sonypi_irq_list sonypi_r505_irq_list[] = { + { 11, 0x80 }, /* IRQ 11, 0x80 in SIRQ in AML */ + { 10, 0x40 }, /* IRQ 10, 0x40 in SIRQ in AML */ + { 9, 0x20 }, /* IRQ 9, 0x20 in SIRQ in AML */ + { 6, 0x10 }, /* IRQ 6, 0x10 in SIRQ in AML */ + { 0, 0x00 } /* no IRQ, 0x00 in SIRQ in AML */ +}; + +#define SONYPI_CAMERA_BRIGHTNESS 0 +#define SONYPI_CAMERA_CONTRAST 1 +#define SONYPI_CAMERA_HUE 2 +#define SONYPI_CAMERA_COLOR 3 +#define SONYPI_CAMERA_SHARPNESS 4 + +#define SONYPI_CAMERA_PICTURE 5 +#define SONYPI_CAMERA_EXPOSURE_MASK 0xC +#define SONYPI_CAMERA_WHITE_BALANCE_MASK 0x3 +#define SONYPI_CAMERA_PICTURE_MODE_MASK 0x30 +#define SONYPI_CAMERA_MUTE_MASK 0x40 + +/* the rest don't need a loop until not 0xff */ +#define SONYPI_CAMERA_AGC 6 +#define SONYPI_CAMERA_AGC_MASK 0x30 +#define SONYPI_CAMERA_SHUTTER_MASK 0x7 + +#define SONYPI_CAMERA_SHUTDOWN_REQUEST 7 +#define SONYPI_CAMERA_CONTROL 0x10 + +#define SONYPI_CAMERA_STATUS 7 +#define SONYPI_CAMERA_STATUS_READY 0x2 +#define SONYPI_CAMERA_STATUS_POSITION 0x4 + +#define SONYPI_DIRECTION_BACKWARDS 0x4 + +#define SONYPI_CAMERA_REVISION 8 +#define SONYPI_CAMERA_ROMVERSION 9 + +/* key press event data (ioport2) */ +#define SONYPI_NORMAL_JOGGER_EV 0x10 +#define SONYPI_R505_JOGGER_EV 0x08 +#define SONYPI_CAPTURE_EV 0x60 +#define SONYPI_NORMAL_FNKEY_EV 0x20 +#define SONYPI_R505_FNKEY_EV 0x08 +#define SONYPI_BLUETOOTH_EV 0x30 + +struct sonypi_event { + u8 data; + u8 event; +}; + +/* The set of possible jogger events */ +static struct sonypi_event sonypi_joggerev[] = { + { 0x1f, SONYPI_EVENT_JOGDIAL_UP }, + { 0x01, SONYPI_EVENT_JOGDIAL_DOWN }, + { 0x5f, SONYPI_EVENT_JOGDIAL_UP_PRESSED }, + { 0x41, SONYPI_EVENT_JOGDIAL_DOWN_PRESSED }, + { 0x40, SONYPI_EVENT_JOGDIAL_PRESSED }, + { 0x00, SONYPI_EVENT_JOGDIAL_RELEASED }, + { 0x00, 0x00 } +}; + +/* The set of possible capture button events */ +static struct sonypi_event sonypi_captureev[] = { + { 0x05, SONYPI_EVENT_CAPTURE_PARTIALPRESSED }, + { 0x07, SONYPI_EVENT_CAPTURE_PRESSED }, + { 0x01, SONYPI_EVENT_CAPTURE_PARTIALRELEASED }, + { 0x00, SONYPI_EVENT_CAPTURE_RELEASED }, + { 0x00, 0x00 } +}; + +/* The set of possible fnkeys events */ +static struct sonypi_event sonypi_fnkeyev[] = { + { 0x10, SONYPI_EVENT_FNKEY_ESC }, + { 0x11, SONYPI_EVENT_FNKEY_F1 }, + { 0x12, SONYPI_EVENT_FNKEY_F2 }, + { 0x13, SONYPI_EVENT_FNKEY_F3 }, + { 0x14, SONYPI_EVENT_FNKEY_F4 }, + { 0x15, SONYPI_EVENT_FNKEY_F5 }, + { 0x16, SONYPI_EVENT_FNKEY_F6 }, + { 0x17, SONYPI_EVENT_FNKEY_F7 }, + { 0x18, SONYPI_EVENT_FNKEY_F8 }, + { 0x19, SONYPI_EVENT_FNKEY_F9 }, + { 0x1a, SONYPI_EVENT_FNKEY_F10 }, + { 0x1b, SONYPI_EVENT_FNKEY_F11 }, + { 0x1c, SONYPI_EVENT_FNKEY_F12 }, + { 0x21, SONYPI_EVENT_FNKEY_1 }, + { 0x22, SONYPI_EVENT_FNKEY_2 }, + { 0x31, SONYPI_EVENT_FNKEY_D }, + { 0x32, SONYPI_EVENT_FNKEY_E }, + { 0x33, SONYPI_EVENT_FNKEY_F }, + { 0x34, SONYPI_EVENT_FNKEY_S }, + { 0x35, SONYPI_EVENT_FNKEY_B }, + { 0x00, 0x00 } +}; + +/* The set of possible bluetooth events */ +static struct sonypi_event sonypi_blueev[] = { + { 0x55, SONYPI_EVENT_BLUETOOTH_PRESSED }, + { 0x00, 0x00 } +}; + +#define SONYPI_BUF_SIZE 128 +struct sonypi_queue { + unsigned long head; + unsigned long tail; + unsigned long len; + spinlock_t s_lock; + wait_queue_head_t proc_list; + struct fasync_struct *fasync; + unsigned char buf[SONYPI_BUF_SIZE]; +}; + +#define SONYPI_DEVICE_MODEL_NORMAL 1 +#define SONYPI_DEVICE_MODEL_R505 2 + +struct sonypi_device { + struct pci_dev *dev; + u16 irq; + u16 bits; + u16 ioport1; + u16 ioport2; + u16 region_size; + int camera_power; + struct semaphore lock; + struct sonypi_queue queue; + int open_count; + int model; +}; + +#endif /* __KERNEL__ */ + +#endif /* _SONYPI_PRIV_H_ */ diff -u --recursive --new-file v2.4.6/linux/drivers/char/sx.c linux/drivers/char/sx.c --- v2.4.6/linux/drivers/char/sx.c Tue Jul 3 17:08:19 2001 +++ linux/drivers/char/sx.c Wed Jul 4 14:41:33 2001 @@ -918,7 +918,6 @@ SP_DCEN); sx_write_channel_byte (port, hi_break, - I_OTHER(port->gs.tty) ? 0: (I_IGNBRK(port->gs.tty)?BR_IGN:0 | I_BRKINT(port->gs.tty)?BR_INT:0)); @@ -1140,9 +1139,7 @@ sx_dprintk (SX_DEBUG_MODEMSIGNALS, "got a break.\n"); sx_write_channel_byte (port, hi_state, hi_state); - if (port->gs.flags & ASYNC_SAK) { - do_SAK (port->gs.tty); - } + gs_got_break (port); } if (hi_state & ST_DCD) { hi_state &= ~ST_DCD; diff -u --recursive --new-file v2.4.6/linux/drivers/char/tty_io.c linux/drivers/char/tty_io.c --- v2.4.6/linux/drivers/char/tty_io.c Tue Jul 3 17:08:19 2001 +++ linux/drivers/char/tty_io.c Sun Jul 15 16:15:44 2001 @@ -211,9 +211,9 @@ const char *routine) { #ifdef TTY_PARANOIA_CHECK - static const char *badmagic = + static const char badmagic[] = KERN_WARNING "Warning: bad magic number for tty struct (%s) in %s\n"; - static const char *badtty = + static const char badtty[] = KERN_WARNING "Warning: null TTY for (%s) in %s\n"; if (!tty) { @@ -245,7 +245,8 @@ tty->link && tty->link->count) count++; if (tty->count != count) { - printk("Warning: dev (%s) tty->count(%d) != #fd's(%d) in %s\n", + printk(KERN_WARNING "Warning: dev (%s) tty->count(%d) " + "!= #fd's(%d) in %s\n", kdevname(tty->device), tty->count, count, routine); return count; } @@ -356,7 +357,7 @@ if (current->tty != tty) return 0; if (tty->pgrp <= 0) { - printk("tty_check_change: tty->pgrp <= 0!\n"); + printk(KERN_WARNING "tty_check_change: tty->pgrp <= 0!\n"); return 0; } if (current->pgrp == tty->pgrp) @@ -494,8 +495,8 @@ if (tty->ldisc.open) { int i = (tty->ldisc.open)(tty); if (i < 0) - printk("do_tty_hangup: N_TTY open: error %d\n", - -i); + printk(KERN_ERR "do_tty_hangup: N_TTY open: " + "error %d\n", -i); } } @@ -537,7 +538,7 @@ #ifdef TTY_DEBUG_HANGUP char buf[64]; - printk("%s hangup...\n", tty_name(tty, buf)); + printk(KERN_DEBUG "%s hangup...\n", tty_name(tty, buf)); #endif schedule_task(&tty->tq_hangup); } @@ -547,7 +548,7 @@ #ifdef TTY_DEBUG_HANGUP char buf[64]; - printk("%s vhangup...\n", tty_name(tty, buf)); + printk(KERN_DEBUG "%s vhangup...\n", tty_name(tty, buf)); #endif do_tty_hangup((void *) tty); } @@ -999,7 +1000,8 @@ /* call the tty release_mem routine to clean out this slot */ release_mem_out: - printk("init_dev: ldisc open failed, clearing slot %d\n", idx); + printk(KERN_INFO "init_dev: ldisc open failed, " + "clearing slot %d\n", idx); release_mem(tty, idx); goto end_init; } @@ -1022,6 +1024,7 @@ } o_tty->magic = 0; (*o_tty->driver.refcount)--; + list_del(&o_tty->tty_files); free_tty_struct(o_tty); } @@ -1033,6 +1036,7 @@ } tty->magic = 0; (*tty->driver.refcount)--; + list_del(&tty->tty_files); free_tty_struct(tty); } @@ -1066,23 +1070,23 @@ #ifdef TTY_PARANOIA_CHECK if (idx < 0 || idx >= tty->driver.num) { - printk("release_dev: bad idx when trying to free (%s)\n", - kdevname(tty->device)); + printk(KERN_DEBUG "release_dev: bad idx when trying to " + "free (%s)\n", kdevname(tty->device)); return; } if (tty != tty->driver.table[idx]) { - printk("release_dev: driver.table[%d] not tty for (%s)\n", - idx, kdevname(tty->device)); + printk(KERN_DEBUG "release_dev: driver.table[%d] not tty " + "for (%s)\n", idx, kdevname(tty->device)); return; } if (tty->termios != tty->driver.termios[idx]) { - printk("release_dev: driver.termios[%d] not termios " + printk(KERN_DEBUG "release_dev: driver.termios[%d] not termios " "for (%s)\n", idx, kdevname(tty->device)); return; } if (tty->termios_locked != tty->driver.termios_locked[idx]) { - printk("release_dev: driver.termios_locked[%d] not " + printk(KERN_DEBUG "release_dev: driver.termios_locked[%d] not " "termios_locked for (%s)\n", idx, kdevname(tty->device)); return; @@ -1090,33 +1094,33 @@ #endif #ifdef TTY_DEBUG_HANGUP - printk("release_dev of %s (tty count=%d)...", tty_name(tty, buf), - tty->count); + printk(KERN_DEBUG "release_dev of %s (tty count=%d)...", + tty_name(tty, buf), tty->count); #endif #ifdef TTY_PARANOIA_CHECK if (tty->driver.other) { if (o_tty != tty->driver.other->table[idx]) { - printk("release_dev: other->table[%d] not o_tty for (" - "%s)\n", + printk(KERN_DEBUG "release_dev: other->table[%d] " + "not o_tty for (%s)\n", idx, kdevname(tty->device)); return; } if (o_tty->termios != tty->driver.other->termios[idx]) { - printk("release_dev: other->termios[%d] not o_termios " - "for (%s)\n", + printk(KERN_DEBUG "release_dev: other->termios[%d] " + "not o_termios for (%s)\n", idx, kdevname(tty->device)); return; } if (o_tty->termios_locked != tty->driver.other->termios_locked[idx]) { - printk("release_dev: other->termios_locked[%d] not " - "o_termios_locked for (%s)\n", + printk(KERN_DEBUG "release_dev: other->termios_locked[" + "%d] not o_termios_locked for (%s)\n", idx, kdevname(tty->device)); return; } if (o_tty->link != tty) { - printk("release_dev: bad pty pointers\n"); + printk(KERN_DEBUG "release_dev: bad pty pointers\n"); return; } } @@ -1171,8 +1175,8 @@ if (!do_sleep) break; - printk("release_dev: %s: read/write wait queue active!\n", - tty_name(tty, buf)); + printk(KERN_WARNING "release_dev: %s: read/write wait queue " + "active!\n", tty_name(tty, buf)); schedule(); } @@ -1183,13 +1187,14 @@ */ if (pty_master) { if (--o_tty->count < 0) { - printk("release_dev: bad pty slave count (%d) for %s\n", + printk(KERN_WARNING "release_dev: bad pty slave count " + "(%d) for %s\n", o_tty->count, tty_name(o_tty, buf)); o_tty->count = 0; } } if (--tty->count < 0) { - printk("release_dev: bad tty->count (%d) for %s\n", + printk(KERN_WARNING "release_dev: bad tty->count (%d) for %s\n", tty->count, tty_name(tty, buf)); tty->count = 0; } @@ -1198,7 +1203,7 @@ * We've decremented tty->count, so we should zero out * filp->private_data, to break the link between the tty and * the file descriptor. Otherwise if filp_close() blocks before - * the the file descriptor is removed from the inuse_filp + * the file descriptor is removed from the inuse_filp * list, check_tty_count() could observe a discrepancy and * printk a warning message to the user. */ @@ -1240,7 +1245,7 @@ return; #ifdef TTY_DEBUG_HANGUP - printk("freeing tty structure..."); + printk(KERN_DEBUG "freeing tty structure..."); #endif /* @@ -1368,7 +1373,7 @@ tty->driver.subtype == PTY_TYPE_MASTER) noctty = 1; #ifdef TTY_DEBUG_HANGUP - printk("opening %s...", tty_name(tty, buf)); + printk(KERN_DEBUG "opening %s...", tty_name(tty, buf)); #endif if (tty->driver.open) retval = tty->driver.open(tty, filp); @@ -1381,7 +1386,7 @@ if (retval) { #ifdef TTY_DEBUG_HANGUP - printk("error %d in opening %s...", retval, + printk(KERN_DEBUG "error %d in opening %s...", retval, tty_name(tty, buf)); #endif @@ -1605,7 +1610,8 @@ (current->tty != real_tty) || (real_tty->session != current->session)) return -ENOTTY; - get_user(pgrp, (pid_t *) arg); + if (get_user(pgrp, (pid_t *) arg)) + return -EFAULT; if (pgrp < 0) return -EINVAL; if (session_of_pgrp(pgrp) != current->session) @@ -1636,11 +1642,10 @@ static int tiocsetd(struct tty_struct *tty, int *arg) { - int retval, ldisc; + int ldisc; - retval = get_user(ldisc, arg); - if (retval) - return retval; + if (get_user(ldisc, arg)) + return -EFAULT; return tty_set_ldisc(tty, ldisc); } @@ -1953,7 +1958,8 @@ } if (i==15 && tty->alt_speed) { if (!tty->warned) { - printk("Use of setserial/setrocket to set SPD_* flags is deprecated\n"); + printk(KERN_WARNING "Use of setserial/setrocket to " + "set SPD_* flags is deprecated\n"); tty->warned = 1; } return(tty->alt_speed); @@ -2360,5 +2366,8 @@ #endif #ifdef CONFIG_HWC hwc_tty_init(); +#endif +#ifdef CONFIG_A2232 + a2232board_init(); #endif } diff -u --recursive --new-file v2.4.6/linux/drivers/char/w83877f_wdt.c linux/drivers/char/w83877f_wdt.c --- v2.4.6/linux/drivers/char/w83877f_wdt.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/w83877f_wdt.c Wed Jul 4 14:41:33 2001 @@ -0,0 +1,347 @@ +/* + * W83877F Computer Watchdog Timer driver for Linux 2.4.x + * + * Based on acquirewdt.c by Alan Cox, + * and sbc60xxwdt.c by Jakob Oestergaard <jakob@ostenfeld.dk> + * + * 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. + * + * The authors do NOT admit liability nor provide warranty for + * any of this software. This material is provided "AS-IS" in + * the hope that it may be useful for others. + * + * (c) Copyright 2001 Scott Jennings <management@oro.net> + * + * 4/19 - 2001 [Initial revision] + * + * + * Theory of operation: + * 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 WDT driver + * via the /proc/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. + * + * This WDT driver is different from most other Linux WDT + * drivers in that the driver will ping the watchdog by itself, + * because this particular WDT has a very short timeout (1.6 + * seconds) and it would be insane to count on any userspace + * daemon always getting scheduled within that time frame. + */ + +#include <linux/module.h> +#include <linux/version.h> +#include <linux/types.h> +#include <linux/errno.h> +#include <linux/kernel.h> +#include <linux/timer.h> +#include <linux/sched.h> +#include <linux/miscdevice.h> +#include <linux/watchdog.h> +#include <linux/slab.h> +#include <linux/ioport.h> +#include <linux/fcntl.h> +#include <linux/smp_lock.h> +#include <asm/io.h> +#include <asm/uaccess.h> +#include <asm/system.h> +#include <linux/notifier.h> +#include <linux/reboot.h> +#include <linux/init.h> + +#define OUR_NAME "w83877f_wdt" + +#define ENABLE_W83877F_PORT 0x3F0 +#define ENABLE_W83877F 0x87 +#define DISABLE_W83877F 0xAA +#define WDT_PING 0x443 +#define WDT_REGISTER 0x14 +#define WDT_ENABLE 0x9C +#define WDT_DISABLE 0x8C + +/* + * The W83877F seems to be fixed at 1.6s timeout (at least on the + * EMACS PC-104 board I'm using). If we reset the watchdog every + * ~250ms we should be safe. */ + +#define WDT_INTERVAL (HZ/4+1) + +/* + * We must not require too good response from the userspace daemon. + * Here we require the userspace daemon to send us a heartbeat + * char to /dev/watchdog every 30 seconds. + */ + +#define WDT_HEARTBEAT (HZ * 30) + +static void wdt_timer_ping(unsigned long); +static struct timer_list timer; +static unsigned long next_heartbeat; +static int wdt_is_open; +static int wdt_expect_close; + +/* + * Whack the dog + */ + +static void wdt_timer_ping(unsigned long data) +{ + /* If we got a heartbeat pulse within the WDT_US_INTERVAL + * we agree to ping the WDT + */ + if(time_before(jiffies, next_heartbeat)) + { + /* Ping the WDT by reading from WDT_PING */ + inb_p(WDT_PING); + /* Re-set the timer interval */ + timer.expires = jiffies + WDT_INTERVAL; + add_timer(&timer); + } else { + printk(OUR_NAME ": Heartbeat lost! Will not ping the watchdog\n"); + } +} + +/* + * Utility routines + */ + +static void wdt_change(int writeval) +{ + /* buy some time */ + inb_p(WDT_PING); + + /* make W83877F available */ + outb_p(ENABLE_W83877F,ENABLE_W83877F_PORT); + outb_p(ENABLE_W83877F,ENABLE_W83877F_PORT); + + /* enable watchdog */ + outb_p(WDT_REGISTER,ENABLE_W83877F_PORT); + outb_p(writeval,ENABLE_W83877F_PORT+1); + + /* lock the W8387FF away */ + outb_p(DISABLE_W83877F,ENABLE_W83877F_PORT); +} + +static void wdt_startup(void) +{ + next_heartbeat = jiffies + WDT_HEARTBEAT; + + /* Start the timer */ + timer.expires = jiffies + WDT_INTERVAL; + add_timer(&timer); + + wdt_change(WDT_ENABLE); + + printk(OUR_NAME ": Watchdog timer is now enabled.\n"); +} + +static void wdt_turnoff(void) +{ + /* Stop the timer */ + del_timer(&timer); + + wdt_change(WDT_DISABLE); + + printk(OUR_NAME ": Watchdog timer is now disabled...\n"); +} + + +/* + * /dev/watchdog handling + */ + +static ssize_t fop_write(struct file * file, const char * buf, size_t count, loff_t * ppos) +{ + /* We can't seek */ + if(ppos != &file->f_pos) + return -ESPIPE; + + /* See if we got the magic character */ + if(count) + { + size_t ofs; + + /* note: just in case someone wrote the magic character + * five months ago... */ + wdt_expect_close = 0; + + /* now scan */ + for(ofs = 0; ofs != count; ofs++) + if(buf[ofs] == 'V') + wdt_expect_close = 1; + + /* someone wrote to us, we should restart timer */ + next_heartbeat = jiffies + WDT_HEARTBEAT; + return 1; + }; + return 0; +} + +static ssize_t fop_read(struct file * file, char * buf, size_t count, loff_t * ppos) +{ + /* No can do */ + return -EINVAL; +} + +static int fop_open(struct inode * inode, struct file * file) +{ + switch(MINOR(inode->i_rdev)) + { + case WATCHDOG_MINOR: + /* Just in case we're already talking to someone... */ + if(wdt_is_open) + return -EBUSY; + /* Good, fire up the show */ + wdt_is_open = 1; + wdt_startup(); + return 0; + + default: + return -ENODEV; + } +} + +static int fop_close(struct inode * inode, struct file * file) +{ + lock_kernel(); + if(MINOR(inode->i_rdev) == WATCHDOG_MINOR) + { + if(wdt_expect_close) + wdt_turnoff(); + else { + del_timer(&timer); + printk(OUR_NAME ": device file closed unexpectedly. Will not stop the WDT!\n"); + } + } + wdt_is_open = 0; + unlock_kernel(); + return 0; +} + +static long long fop_llseek(struct file *file, long long offset, int origin) +{ + return -ESPIPE; +} + +static int fop_ioctl(struct inode *inode, struct file *file, unsigned int cmd, + unsigned long arg) +{ + static struct watchdog_info ident= + { + 0, + 1, + "W83877F" + }; + + switch(cmd) + { + default: + return -ENOIOCTLCMD; + case WDIOC_GETSUPPORT: + return copy_to_user((struct watchdog_info *)arg, &ident, sizeof(ident))?-EFAULT:0; + case WDIOC_KEEPALIVE: + next_heartbeat = jiffies + WDT_HEARTBEAT; + return 0; + } +} + +static struct file_operations wdt_fops = { + owner: THIS_MODULE, + llseek: fop_llseek, + read: fop_read, + write: fop_write, + open: fop_open, + release: fop_close, + ioctl: fop_ioctl +}; + +static struct miscdevice wdt_miscdev = { + WATCHDOG_MINOR, + "watchdog", + &wdt_fops +}; + +/* + * Notifier for system down + */ + +static int wdt_notify_sys(struct notifier_block *this, unsigned long code, + void *unused) +{ + if(code==SYS_DOWN || code==SYS_HALT) + wdt_turnoff(); + return NOTIFY_DONE; +} + +/* + * The WDT needs to learn about soft shutdowns in order to + * turn the timebomb registers off. + */ + +static struct notifier_block wdt_notifier= +{ + wdt_notify_sys, + 0, + 0 +}; + +static void __exit w83877f_wdt_unload(void) +{ + wdt_turnoff(); + + /* Deregister */ + misc_deregister(&wdt_miscdev); + + unregister_reboot_notifier(&wdt_notifier); + release_region(WDT_PING,1); + release_region(ENABLE_W83877F_PORT,2); +} + +static int __init w83877f_wdt_init(void) +{ + int rc = -EBUSY; + + if (!request_region(ENABLE_W83877F_PORT, 2, "W83877F WDT")) + goto err_out; + if (!request_region(WDT_PING, 1, "W8387FF WDT")) + goto err_out_region1; + + init_timer(&timer); + timer.function = wdt_timer_ping; + timer.data = 0; + + rc = misc_register(&wdt_miscdev); + if (rc) + goto err_out_region2; + + rc = register_reboot_notifier(&wdt_notifier); + if (rc) + goto err_out_miscdev; + + printk(KERN_INFO OUR_NAME ": WDT driver for W83877F initialised.\n"); + + return 0; + +err_out_miscdev: + misc_deregister(&wdt_miscdev); +err_out_region2: + release_region(WDT_PING,1); +err_out_region1: + release_region(ENABLE_W83877F_PORT,2); +err_out: + return rc; +} + +module_init(w83877f_wdt_init); +module_exit(w83877f_wdt_unload); diff -u --recursive --new-file v2.4.6/linux/drivers/i2c/i2c-dev.c linux/drivers/i2c/i2c-dev.c --- v2.4.6/linux/drivers/i2c/i2c-dev.c Fri Feb 9 11:30:23 2001 +++ linux/drivers/i2c/i2c-dev.c Mon Jul 16 15:13:32 2001 @@ -241,6 +241,9 @@ sizeof(rdwr_arg))) return -EFAULT; + if(rdwr_arg.nmsgs > 2048) + return -EINVAL; + rdwr_pa = (struct i2c_msg *) kmalloc(rdwr_arg.nmsgs * sizeof(struct i2c_msg), GFP_KERNEL); diff -u --recursive --new-file v2.4.6/linux/drivers/i2o/i2o_block.c linux/drivers/i2o/i2o_block.c --- v2.4.6/linux/drivers/i2o/i2o_block.c Tue May 1 16:12:51 2001 +++ linux/drivers/i2o/i2o_block.c Thu Jul 19 20:48:39 2001 @@ -1012,7 +1012,7 @@ */ req->errors = 0; blkdev_dequeue_request(req); - req->sem = NULL; + req->waiting = NULL; ireq = i2ob_queues[dev->unit]->i2ob_qhead; i2ob_queues[dev->unit]->i2ob_qhead = ireq->next; diff -u --recursive --new-file v2.4.6/linux/drivers/ide/ali14xx.c linux/drivers/ide/ali14xx.c --- v2.4.6/linux/drivers/ide/ali14xx.c Thu Apr 13 22:54:26 2000 +++ linux/drivers/ide/ali14xx.c Sun Jul 15 16:22:23 2001 @@ -81,9 +81,9 @@ {0x2d, 0x32, 0x2e, 0x33}, /* drive 3 */ }; -static int basePort = 0; /* base port address */ -static int regPort = 0; /* port for register number */ -static int dataPort = 0; /* port for register data */ +static int basePort; /* base port address */ +static int regPort; /* port for register number */ +static int dataPort; /* port for register data */ static byte regOn; /* output to base port to access registers */ static byte regOff; /* output to base port to close registers */ diff -u --recursive --new-file v2.4.6/linux/drivers/ide/alim15x3.c linux/drivers/ide/alim15x3.c --- v2.4.6/linux/drivers/ide/alim15x3.c Sat May 19 17:43:06 2001 +++ linux/drivers/ide/alim15x3.c Sun Jul 15 16:22:23 2001 @@ -679,19 +679,21 @@ hwif->drives[0].autotune = 1; hwif->drives[1].autotune = 1; hwif->speedproc = &ali15x3_tune_chipset; -#ifndef CONFIG_BLK_DEV_IDEDMA - hwif->autodma = 0; - return; -#endif /* CONFIG_BLK_DEV_IDEDMA */ +#ifdef CONFIG_BLK_DEV_IDEDMA if ((hwif->dma_base) && (m5229_revision >= 0x20)) { /* * M1543C or newer for DMAing */ hwif->dmaproc = &ali15x3_dmaproc; - if (!noautodma) - hwif->autodma = 1; + hwif->autodma = 1; } + + if (noautodma) + hwif->autodma = 0; +#else + hwif->autodma = 0; +#endif /* CONFIG_BLK_DEV_IDEDMA */ } void __init ide_dmacapable_ali15x3 (ide_hwif_t *hwif, unsigned long dmabase) diff -u --recursive --new-file v2.4.6/linux/drivers/ide/buddha.c linux/drivers/ide/buddha.c --- v2.4.6/linux/drivers/ide/buddha.c Mon Nov 27 17:57:34 2000 +++ linux/drivers/ide/buddha.c Sun Jul 15 16:22:23 2001 @@ -87,7 +87,7 @@ * Board information */ -static u_long buddha_board = 0; +static u_long buddha_board; static int buddha_num_hwifs = -1; diff -u --recursive --new-file v2.4.6/linux/drivers/ide/ide-cd.c linux/drivers/ide/ide-cd.c --- v2.4.6/linux/drivers/ide/ide-cd.c Fri May 25 12:44:11 2001 +++ linux/drivers/ide/ide-cd.c Thu Jul 19 21:04:55 2001 @@ -254,7 +254,7 @@ * They will disappear later when I get the time to * do it cleanly. * - Minimize the TOC reading - only do it when we - * know a media change has occured. + * know a media change has occurred. * - Moved all the CDROMREADx ioctls to the Uniform layer. * - Heiko Eissfeldt <heiko@colossus.escape.de> supplied * some fixes for CDI. @@ -307,6 +307,7 @@ #include <linux/errno.h> #include <linux/cdrom.h> #include <linux/ide.h> +#include <linux/completion.h> #include <asm/irq.h> #include <asm/io.h> @@ -512,7 +513,7 @@ } static void cdrom_queue_request_sense(ide_drive_t *drive, - struct semaphore *sem, + struct completion *wait, struct request_sense *sense, struct packet_command *failed_command) { @@ -534,7 +535,7 @@ ide_init_drive_cmd(rq); rq->cmd = REQUEST_SENSE_COMMAND; rq->buffer = (char *) pc; - rq->sem = sem; + rq->waiting = wait; (void) ide_do_drive_cmd(drive, rq, ide_preempt); } @@ -596,7 +597,7 @@ } else if (rq->cmd == PACKET_COMMAND) { /* All other functions, except for READ. */ - struct semaphore *sem = NULL; + struct completion *wait = NULL; pc = (struct packet_command *) rq->buffer; /* Check for tray open. */ @@ -622,15 +623,15 @@ command request to the request sense request. */ if ((stat & ERR_STAT) != 0) { - sem = rq->sem; - rq->sem = NULL; + wait = rq->waiting; + rq->waiting = NULL; } pc->stat = 1; cdrom_end_request (1, drive); if ((stat & ERR_STAT) != 0) - cdrom_queue_request_sense(drive, sem, pc->sense, pc); + cdrom_queue_request_sense(drive, wait, pc->sense, pc); } else { /* Handle errors from READ and WRITE requests. */ diff -u --recursive --new-file v2.4.6/linux/drivers/ide/ide-pmac.c linux/drivers/ide/ide-pmac.c --- v2.4.6/linux/drivers/ide/ide-pmac.c Thu Feb 15 17:22:08 2001 +++ linux/drivers/ide/ide-pmac.c Sun Jul 15 16:22:23 2001 @@ -176,7 +176,8 @@ if (pmac_ide[ix].dma_regs && pmac_ide[ix].dma_table) { ide_hwifs[ix].dmaproc = &pmac_ide_dmaproc; #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC_AUTO - ide_hwifs[ix].autodma = 1; + if (!noautodma) + ide_hwifs[ix].autodma = 1; #endif } } @@ -676,7 +677,8 @@ ide_hwifs[ix].dmaproc = &pmac_ide_dmaproc; #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC_AUTO - ide_hwifs[ix].autodma = 1; + if (!noautodma) + ide_hwifs[ix].autodma = 1; #endif } diff -u --recursive --new-file v2.4.6/linux/drivers/ide/ide-tape.c linux/drivers/ide/ide-tape.c --- v2.4.6/linux/drivers/ide/ide-tape.c Tue Jul 3 17:08:19 2001 +++ linux/drivers/ide/ide-tape.c Fri Jul 20 12:41:02 2001 @@ -419,6 +419,7 @@ #include <linux/pci.h> #include <linux/ide.h> #include <linux/smp_lock.h> +#include <linux/completion.h> #include <asm/byteorder.h> #include <asm/irq.h> @@ -978,7 +979,7 @@ int logical_blk_num; /* logical block number */ __u16 wrt_pass_cntr; /* write pass counter */ __u32 update_frame_cntr; /* update frame counter */ - struct semaphore *sem; + struct completion *waiting; int onstream_write_error; /* write error recovery active */ int header_ok; /* header frame verified ok */ int linux_media; /* reading linux-specifc media */ @@ -1454,7 +1455,7 @@ case IDETAPE_WRITE_FILEMARK_CMD: return("WRITE_FILEMARK_CMD"); case IDETAPE_SPACE_CMD: return("SPACE_CMD"); case IDETAPE_INQUIRY_CMD: return("INQUIRY_CMD"); - case IDETAPE_ERASE_CMD: return("ERASE_CMD") + case IDETAPE_ERASE_CMD: return("ERASE_CMD"); case IDETAPE_MODE_SENSE_CMD: return("MODE_SENSE_CMD"); case IDETAPE_MODE_SELECT_CMD: return("MODE_SELECT_CMD"); case IDETAPE_LOAD_UNLOAD_CMD: return("LOAD_UNLOAD_CMD"); @@ -1886,8 +1887,8 @@ printk("ide-tape: %s: skipping over config parition..\n", tape->name); #endif tape->onstream_write_error = OS_PART_ERROR; - if (tape->sem) - up(tape->sem); + if (tape->waiting) + complete(tape->waiting); } } remove_stage = 1; @@ -1903,8 +1904,8 @@ tape->nr_pending_stages++; tape->next_stage = tape->first_stage; rq->current_nr_sectors = rq->nr_sectors; - if (tape->sem) - up(tape->sem); + if (tape->waiting) + complete(tape->waiting); } } } else if (rq->cmd == IDETAPE_READ_RQ) { @@ -3064,15 +3065,15 @@ } /* - * idetape_wait_for_request installs a semaphore in a pending request + * idetape_wait_for_request installs a completion in a pending request * and sleeps until it is serviced. * * The caller should ensure that the request will not be serviced - * before we install the semaphore (usually by disabling interrupts). + * before we install the completion (usually by disabling interrupts). */ static void idetape_wait_for_request (ide_drive_t *drive, struct request *rq) { - DECLARE_MUTEX_LOCKED(sem); + DECLARE_COMPLETION(wait); idetape_tape_t *tape = drive->driver_data; #if IDETAPE_DEBUG_BUGS @@ -3081,12 +3082,12 @@ return; } #endif /* IDETAPE_DEBUG_BUGS */ - rq->sem = &sem; - tape->sem = &sem; + rq->waiting = &wait; + tape->waiting = &wait; spin_unlock(&tape->spinlock); - down(&sem); - rq->sem = NULL; - tape->sem = NULL; + wait_for_completion(&wait); + rq->waiting = NULL; + tape->waiting = NULL; spin_lock_irq(&tape->spinlock); } diff -u --recursive --new-file v2.4.6/linux/drivers/ide/ide.c linux/drivers/ide/ide.c --- v2.4.6/linux/drivers/ide/ide.c Tue May 1 16:05:00 2001 +++ linux/drivers/ide/ide.c Thu Jul 19 21:02:28 2001 @@ -148,6 +148,7 @@ #include <linux/delay.h> #include <linux/ide.h> #include <linux/devfs_fs_kernel.h> +#include <linux/completion.h> #include <asm/byteorder.h> #include <asm/irq.h> @@ -1700,7 +1701,7 @@ ide_hwgroup_t *hwgroup = HWGROUP(drive); unsigned int major = HWIF(drive)->major; struct list_head *queue_head = &drive->queue.queue_head; - DECLARE_MUTEX_LOCKED(sem); + DECLARE_COMPLETION(wait); #ifdef CONFIG_BLK_DEV_PDC4030 if (HWIF(drive)->chipset == ide_pdc4030 && rq->buffer != NULL) @@ -1710,7 +1711,7 @@ rq->rq_status = RQ_ACTIVE; rq->rq_dev = MKDEV(major,(drive->select.b.unit)<<PARTN_BITS); if (action == ide_wait) - rq->sem = &sem; + rq->waiting = &wait; spin_lock_irqsave(&io_request_lock, flags); if (list_empty(queue_head) || action == ide_preempt) { if (action == ide_preempt) @@ -1725,7 +1726,7 @@ ide_do_request(hwgroup, 0); spin_unlock_irqrestore(&io_request_lock, flags); if (action == ide_wait) { - down(&sem); /* wait for it to be serviced */ + wait_for_completion(&wait); /* wait for it to be serviced */ return rq->errors ? -EIO : 0; /* return -EIO if errors */ } return 0; diff -u --recursive --new-file v2.4.6/linux/drivers/ide/pdc4030.c linux/drivers/ide/pdc4030.c --- v2.4.6/linux/drivers/ide/pdc4030.c Tue Mar 6 19:44:34 2001 +++ linux/drivers/ide/pdc4030.c Tue Jul 17 18:53:55 2001 @@ -367,7 +367,7 @@ #ifdef DEBUG_READ printk(KERN_DEBUG "%s: promise_read: waiting for" "interrupt\n", drive->name); -#endif +#endif return ide_started; } printk(KERN_ERR "%s: Eeek! promise_read_intr: sectors left " @@ -457,8 +457,8 @@ #ifdef DEBUG_WRITE printk(KERN_DEBUG "%s: promise_write: sectors(%ld-%ld), " - "buffer=0x%08x\n", drive->name, rq->sector, - rq->sector + rq->nr_sectors - 1, (unsigned int)rq->buffer); + "buffer=%p\n", drive->name, rq->sector, + rq->sector + rq->nr_sectors - 1, rq->buffer); #endif /* diff -u --recursive --new-file v2.4.6/linux/drivers/ide/pdc4030.h linux/drivers/ide/pdc4030.h --- v2.4.6/linux/drivers/ide/pdc4030.h Sat Feb 26 20:32:14 2000 +++ linux/drivers/ide/pdc4030.h Tue Jul 17 18:53:55 2001 @@ -41,4 +41,4 @@ u8 pad[SECTOR_WORDS*4 - 32]; }; -#endif IDE_PROMISE_H +#endif /* IDE_PROMISE_H */ diff -u --recursive --new-file v2.4.6/linux/drivers/ide/piix.c linux/drivers/ide/piix.c --- v2.4.6/linux/drivers/ide/piix.c Tue Jul 3 17:08:19 2001 +++ linux/drivers/ide/piix.c Sun Jul 15 16:22:23 2001 @@ -516,7 +516,8 @@ hwif->autodma = 0; #else /* CONFIG_BLK_DEV_IDEDMA */ #ifdef CONFIG_PIIX_TUNING - hwif->autodma = 1; + if (!noautodma) + hwif->autodma = 1; hwif->dmaproc = &piix_dmaproc; hwif->speedproc = &piix_tune_chipset; #endif /* CONFIG_PIIX_TUNING */ diff -u --recursive --new-file v2.4.6/linux/drivers/ide/slc90e66.c linux/drivers/ide/slc90e66.c --- v2.4.6/linux/drivers/ide/slc90e66.c Sat May 19 17:43:06 2001 +++ linux/drivers/ide/slc90e66.c Sun Jul 15 16:22:23 2001 @@ -349,11 +349,11 @@ { #if 1 byte reg47 = 0, ata66 = 0; - byte mask = hwif->channel ? 0x02 : 0x01; + byte mask = hwif->channel ? 0x01 : 0x02; /* bit0:Primary */ pci_read_config_byte(hwif->pci_dev, 0x47, ®47); - ata66 = (reg47 & mask) ? 1 : 0; + ata66 = (reg47 & mask) ? 0 : 1; /* bit[0(1)]: 0:80, 1:40 */ #else byte ata66 = 0; #endif diff -u --recursive --new-file v2.4.6/linux/drivers/ieee1394/Config.in linux/drivers/ieee1394/Config.in --- v2.4.6/linux/drivers/ieee1394/Config.in Wed Oct 11 16:49:47 2000 +++ linux/drivers/ieee1394/Config.in Thu Jul 19 17:48:15 2001 @@ -2,25 +2,24 @@ if [ "$CONFIG_PCI" = "y" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then mainmenu_option next_comment - comment 'IEEE 1394 (FireWire) support' + comment 'IEEE 1394 (FireWire) support (EXPERIMENTAL)' dep_tristate 'IEEE 1394 (FireWire) support (EXPERIMENTAL)' CONFIG_IEEE1394 $CONFIG_PCI if [ "$CONFIG_IEEE1394" != "n" ]; then - dep_tristate 'Texas Instruments PCILynx support' CONFIG_IEEE1394_PCILYNX $CONFIG_IEEE1394 + comment "Device Drivers" + dep_tristate ' Texas Instruments PCILynx support' CONFIG_IEEE1394_PCILYNX $CONFIG_IEEE1394 if [ "$CONFIG_IEEE1394_PCILYNX" != "n" ]; then - bool ' Use PCILynx local RAM' CONFIG_IEEE1394_PCILYNX_LOCALRAM - bool ' Support for non-IEEE1394 local ports' CONFIG_IEEE1394_PCILYNX_PORTS + bool ' Use PCILynx local RAM' CONFIG_IEEE1394_PCILYNX_LOCALRAM + bool ' Support for non-IEEE1394 local ports' CONFIG_IEEE1394_PCILYNX_PORTS fi + dep_tristate ' OHCI-1394 support' CONFIG_IEEE1394_OHCI1394 $CONFIG_IEEE1394 -# this driver is unsupported now: -# dep_tristate 'Adaptec AIC-5800 (AHA-89xx) support' CONFIG_IEEE1394_AIC5800 $CONFIG_IEEE1394 - - dep_tristate 'OHCI (Open Host Controller Interface) support' CONFIG_IEEE1394_OHCI1394 $CONFIG_IEEE1394 - dep_tristate 'Video1394 support' CONFIG_IEEE1394_VIDEO1394 $CONFIG_IEEE1394_OHCI1394 - - dep_tristate 'Raw IEEE1394 I/O support' CONFIG_IEEE1394_RAWIO $CONFIG_IEEE1394 + comment "Protocol Drivers" + dep_tristate ' OHCI-1394 Video support' CONFIG_IEEE1394_VIDEO1394 $CONFIG_IEEE1394_OHCI1394 + dep_tristate ' SBP-2 support (Harddisks etc.)' CONFIG_IEEE1394_SBP2 $CONFIG_SCSI $CONFIG_IEEE1394 + dep_tristate ' Raw IEEE1394 I/O support' CONFIG_IEEE1394_RAWIO $CONFIG_IEEE1394 bool 'Excessive debugging output' CONFIG_IEEE1394_VERBOSEDEBUG fi diff -u --recursive --new-file v2.4.6/linux/drivers/ieee1394/Makefile linux/drivers/ieee1394/Makefile --- v2.4.6/linux/drivers/ieee1394/Makefile Tue Jan 2 16:45:37 2001 +++ linux/drivers/ieee1394/Makefile Fri Jul 20 12:47:31 2001 @@ -1,12 +1,6 @@ # # Makefile for the Linux IEEE 1394 implementation # -# Note! Dependencies are done automagically by 'make dep', which also -# removes any old dependencies. DON'T put your own dependencies here -# unless it's something special (not a .c file). -# -# Note 2! The CFLAGS definitions are now in the main makefile. -# O_TARGET := ieee1394drv.o @@ -14,14 +8,14 @@ list-multi := ieee1394.o ieee1394-objs := ieee1394_core.o ieee1394_transactions.o hosts.o \ - highlevel.o csr.o guid.o ieee1394_syms.o + highlevel.o csr.o nodemgr.o ieee1394_syms.o obj-$(CONFIG_IEEE1394) += ieee1394.o obj-$(CONFIG_IEEE1394_PCILYNX) += pcilynx.o -obj-$(CONFIG_IEEE1394_AIC5800) += aic5800.o obj-$(CONFIG_IEEE1394_OHCI1394) += ohci1394.o obj-$(CONFIG_IEEE1394_VIDEO1394) += video1394.o obj-$(CONFIG_IEEE1394_RAWIO) += raw1394.o +obj-$(CONFIG_IEEE1394_SBP2) += sbp2.o include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.4.6/linux/drivers/ieee1394/aic5800.c linux/drivers/ieee1394/aic5800.c --- v2.4.6/linux/drivers/ieee1394/aic5800.c Fri Mar 2 18:38:38 2001 +++ linux/drivers/ieee1394/aic5800.c Wed Dec 31 16:00:00 1969 @@ -1,902 +0,0 @@ -/* - * +++ THIS DRIVER IS ORPHANED AND UNSUPPORTED +++ - * - * aic5800.c - Adaptec AIC-5800 PCI-IEEE1394 chip driver - * Copyright (C)1999 Emanuel Pirker <epirker@edu.uni-klu.ac.at> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#include <linux/kernel.h> -#include <linux/slab.h> -#include <linux/interrupt.h> -#include <linux/wait.h> -#include <linux/errno.h> -#include <linux/module.h> -#include <linux/pci.h> -#include <linux/fs.h> -#include <linux/poll.h> -#include <linux/delay.h> -#include <asm/byteorder.h> -#include <asm/atomic.h> -#include <asm/io.h> -#include <asm/uaccess.h> - -#include "ieee1394_types.h" -#include "hosts.h" -#include "ieee1394_core.h" -#include "ieee1394.h" -#include "aic5800.h" - - - -/// print general (card independent) information -#define PRINT_G(level, fmt, args...) printk(level "aic5800: " fmt "\n" , ## args) -/// print card specific information -#define PRINT(level, card, fmt, args...) printk(level "aic5800-%d: " fmt "\n" , card , ## args) - -/// card array -static struct aic5800 cards[MAX_AIC5800_CARDS]; -/// holds the number of installed aic5800 cards -static int num_of_cards = 0; - -static int add_card(struct pci_dev *dev); -static void remove_card(struct aic5800 *aic); -static int init_driver(void); - - -/***************************************************************** - * Auxiliary functions needed to read the EEPROM - * Daniel Minitti - *****************************************************************/ -#define SEEPDOUT 0x1 -#define SEEPDIN 0x02 -#define SEEPSK 0x04 -#define SEEPCS 0x08 -#define SEEPCYC 0x10 -#define SEEPBUSY 0x20 - -#define CLOCK_PULSE() {\ - int cnt=200;\ - while(cnt-->0 && reg_read(aic, misc_SEEPCTL) & SEEPBUSY);\ - if (reg_read(aic, misc_SEEPCTL) & SEEPBUSY) printk("BUSY ");\ - } - -static inline unsigned short read_seeprom_word(struct aic5800 *aic, - int offset) -{ - int i; - unsigned char temp; - unsigned char read_cmd[3] = {1,1,0}; - unsigned short rd; - - // send chip select for one clock cycle. - reg_write(aic, misc_SEEPCTL, SEEPSK|SEEPCS); - CLOCK_PULSE(); - - // write start bit (1) & READ op-code (10b) - for (i=0; i<sizeof(read_cmd); i++) { - temp = SEEPCS | SEEPCYC | read_cmd[i]; - reg_write(aic, misc_SEEPCTL, temp); - CLOCK_PULSE(); - temp = temp ^ SEEPSK; - reg_write(aic, misc_SEEPCTL, temp); - CLOCK_PULSE(); - } - // write 8 bit address (MSB --> LSB) - for (i=7; i>=0; i--) { - temp = offset; - temp = (temp >> i) & 1; - temp = SEEPCS | SEEPCYC | temp; - reg_write(aic, misc_SEEPCTL, temp); - CLOCK_PULSE(); - temp = temp ^ SEEPSK; - reg_write(aic, misc_SEEPCTL, temp); - CLOCK_PULSE(); - } - // read 16 bit (MSB --> LSB) - rd = 0; - for (i=0; i<=16; i++) { - temp = SEEPCS | SEEPCYC; - reg_write(aic, misc_SEEPCTL, temp); - CLOCK_PULSE(); - temp = temp ^ SEEPSK; - rd = (rd << 1) | (unsigned short)((reg_read(aic, misc_SEEPCTL) -& SEEPDIN)>>1); - reg_write(aic, misc_SEEPCTL, temp); - CLOCK_PULSE(); - } - - // reset chip select for the next command cycle - reg_write(aic, misc_SEEPCTL, SEEPCYC); - CLOCK_PULSE(); - reg_write(aic, misc_SEEPCTL, SEEPCYC | SEEPSK); - CLOCK_PULSE(); - reg_write(aic, misc_SEEPCTL, SEEPCYC); - CLOCK_PULSE(); - - reg_write(aic, misc_SEEPCTL, 0); - CLOCK_PULSE(); - - return rd; -} - -#undef DEBUG_SEEPROM - -/** Read 64-bit GUID (Global Unique ID) from SEEPROM - * - * It works well on AHA-8945. - * On AHA-8920 it works well only on first time, It returns ffff... on - * the other times. - *****************************************************************/ -static unsigned long long read_guid(struct aic5800 *aic) -{ - int i; - unsigned long long guid; - -#ifdef DEBUG_SEEPROM - printk("\n"); - printk("SEEPCTL value = 0x%x\n", reg_read(aic, misc_SEEPCTL)); -#endif - - /* read GUID */ - guid = 0; - for (i=0x10; i<0x14; i++) - guid = (guid << 16) | read_seeprom_word(aic,i); - -#ifdef DEBUG_SEEPROM - for (i=0; i<3; i++) - printk("%x ", (unsigned int) read_seeprom_word(aic,i)); - printk("\nGUID = "); - for (i=3; i>=0; i--) - printk("%x ", (unsigned int)(guid>>(16*i))&0xffff); - - printk("\nSEEPCTL value = 0x%x\n", reg_read(aic, misc_SEEPCTL)); -#endif - return guid; -} - -#undef CLOCK_PULSE() - -static int aic_detect(struct hpsb_host_template *tmpl) -{ - struct hpsb_host *host; - int i; - - init_driver(); - - for (i = 0; i < num_of_cards; i++) { - host = hpsb_get_host(tmpl, 0); - if (host == NULL) { - /* simply don't init more after out of mem */ - return i; - } - host->hostdata = &cards[i]; - cards[i].host = host; - } - - return num_of_cards; -} - -static int aic_devctl(struct hpsb_host *host, enum devctl_cmd cmd, int arg) -{ - struct aic5800 *aic = host->hostdata; - int retval = 0; - unsigned long flags; - struct hpsb_packet *packet, *lastpacket; - - switch (cmd) { - case RESET_BUS: - reg_write(aic, misc_PhyControl, 0x00004140 ); - break; - - case GET_CYCLE_COUNTER: - arg = reg_read(aic, misc_CycleTimer); - break; - - case SET_CYCLE_COUNTER: - reg_write(aic, misc_CycleTimer, arg); - break; - - case SET_BUS_ID: - reg_clear_bits(aic, misc_NodeID, 0xFFC0); - reg_set_bits(aic, misc_NodeID, (arg<<6)); - break; - - case ACT_CYCLE_MASTER: - if (arg) { - /* enable cycleMaster */ - reg_set_bits(aic, misc_Control, 0x20000); - } else { - /* disable cycleMaster */ - reg_clear_bits(aic, misc_Control, 0x20000); - }; - break; - - case CANCEL_REQUESTS: - spin_lock_irqsave(&aic->async_queue_lock, flags); - /* stop any chip activity */ - reg_write( aic, AT_ChannelControl, 0x80000000); - packet = aic->async_queue; - aic->async_queue = NULL; - spin_unlock_irqrestore(&aic->async_queue_lock, flags); - - while (packet != NULL) { - lastpacket = packet; - packet = packet->xnext; - hpsb_packet_sent(host, lastpacket, ACKX_ABORTED); - } - - break; - - case MODIFY_USAGE: - if (arg) { - MOD_INC_USE_COUNT; - } else { - MOD_DEC_USE_COUNT; - } - break; - -#if 0 - case DEBUG_DUMPINFO: - PRINT(KERN_INFO, aic->id, AIC5800_DRIVER_NAME); - PRINT(KERN_INFO, aic->id, " Register MMIO base: 0x%p\n", - aic->registers); - PRINT(KERN_INFO, aic->id, " NodeID: 0x%x\n", - reg_read(aic, misc_NodeID) ); - PRINT(KERN_INFO,aic->id, " #Intr: %lu BusResets: %lu\n", - aic->NumInterrupts, aic->NumBusResets); - PRINT(KERN_INFO, aic->id, " TxPackets: %lu RxPackets: %lu\n", - aic->TxPackets, aic->RxPackets); - PRINT(KERN_INFO,aic->id, " TxRdy: %lu ATErr: %lu HdrErr: %lu TcodeErr: %lu SendRej: %lu\n", - aic->TxRdy, aic->ATError, aic->HdrErr, - aic->TCodeErr, aic->SendRej); - break; -#endif - - default: - PRINT(KERN_ERR, aic->id, "unknown devctl command %d", cmd); - retval = -1; - } - - return retval; - -} - -/** Initialize the host adapter chip and corresponding data - structures. We reset the chip, enable transmitter, receiver, - the physical DMA units, cycle timer, cycle source, reception - of selfid packets and initialize several other registers. */ -static int aic_initialize(struct hpsb_host *host) -{ - int i; - struct aic5800 *aic = host->hostdata; - - /* Reset data structures */ - aic->async_queue = NULL; - spin_lock_init(&aic->async_queue_lock); - - /* Reset the chip */ - reg_write( aic, misc_Reset, 0x37); - udelay(10); // FIXME - reg_write( aic, misc_Reset, 0); - - /* Enable Transmitter/Receiver, enable physDMA, - * enable CycleTimer, cycleSource */ - reg_write( aic, misc_Control, 0x82050003); - - /* Enable reception of SelfID packets */ - reg_set_bits(aic, misc_PacketControl, 0x20); - - reg_write(aic, AT_InterruptSelect, 0x00F0001); - reg_write(aic, AT_BranchSelect, 0x0100010); - reg_write(aic, AT_WaitSelect, 0x00F0001); - reg_write(aic, misc_ATRetries, reg_read(aic, misc_ATRetries) | 0x7); - - /* initialize AR DMA */ - - /* unset run bit */ - reg_write( aic, AR_ChannelControl, 0x80000000); - - /* here we should have 0 iterations because of the code - in the DmaAR handler. However, to be sure we do it */ - i = 0; - while (reg_read(aic, AR_ChannelStatus) & 0x400) { - i++; - if (i>100000) { - PRINT(KERN_ERR, aic->id, - "Huh! Can't set AR_ChannelControl... card can not receive!"); - break; - } - } - - (aic->AR_program)->control = ( DMA_CMD_INPUTLAST | DMA_KEY_STREAM0 - | DMA_INTR_ALWAYS | DMA_BRANCH_ALWAYS) - + AIC5800_ARFIFO_SIZE; - (aic->AR_program)->address = virt_to_bus(aic->rcv_page); - (aic->AR_program)->branchAddress = virt_to_bus(aic->AR_program); - (aic->AR_program)->status = AIC5800_ARFIFO_SIZE; - - (aic->AR_program+1)->control = DMA_CMD_STOP; - (aic->AR_program+1)->address = 0; - (aic->AR_program+1)->branchAddress = 0; - (aic->AR_program+1)->status = 0; - - reg_write( aic, AR_CommandPtr, (u32) virt_to_bus(aic->AR_program)); - reg_write( aic, AR_ChannelControl, 0x80008000); - - /* Enable Interrupts */ - reg_write(aic, misc_InterruptClear, 0xFFFFFFFF); - reg_write(aic, misc_InterruptMask, 0xFFFFFFFF); - /*reg_write(aic, misc_InterruptMask, 0x00F1F03F);*/ - - return 1; -} - -static void aic_release(struct hpsb_host *host) -{ - struct aic5800 *aic; - - if (host != NULL) { - aic = host->hostdata; - remove_card(aic); - } -} - -/* This must be called with the async_queue_lock held. */ -static void send_next_async(struct aic5800 *aic) -{ - int i; - struct hpsb_packet *packet = aic->async_queue; - - /* stop the channel program if it's still running */ - reg_write( aic, AT_ChannelControl, 0x80000000); - - /* re-format packet header for AIC-5800 chip */ - packet->header[1] = (packet->header[1] & 0xFFFF) | - (packet->header[0] & 0xFFFF0000); - packet->header[0] = (packet->header[0] & 0xFFFF); - -#ifndef __BIG_ENDIAN - /* Packet must be byte-swapped in non-big-endian environments, - * see AIC-5800 specification... - */ - { u32 i; - for ( i = 0 ; i < packet->header_size/sizeof(u32) ; i++ ) - packet->header[i] = cpu_to_be32( packet->header[i] ); - for ( i = 0 ; i < packet->data_size/sizeof(u32) ; i++ ) - packet->data[i] = cpu_to_be32( packet->data[i] ); - } - -#endif - - /* typically we use only a few iterations here */ - i = 0; - while (reg_read(aic, AT_ChannelStatus) & 0x400) { - i++; - if (i>5000) { - PRINT(KERN_ERR, aic->id, - "runaway loop 1 in send_next_async() - bailing out..."); - break; - }; - }; - - /* set data buffer address and packet length */ - memset(aic->AT_program, 0, MAX_AT_PROGRAM_SIZE * sizeof(struct dma_cmd)); - - if (packet->data_size) { - aic->AT_program[0].control = ( DMA_CMD_OUTPUTMORE | DMA_KEY_STREAM0 ) + - packet -> header_size; - aic->AT_program[0].address = virt_to_bus( packet->header ); - aic->AT_program[1].control = ( DMA_CMD_OUTPUTLAST | DMA_KEY_STREAM0 - | DMA_INTR_ALWAYS ) - + packet -> data_size; - aic->AT_program[1].address = virt_to_bus( packet->data ); - - aic->AT_program[2].control = DMA_CMD_STOP; - - } else { - aic->AT_program[0].control = ( DMA_CMD_OUTPUTLAST | DMA_INTR_ALWAYS | - DMA_KEY_STREAM0 ) + - packet -> header_size; - aic->AT_program[0].address = virt_to_bus( packet->header ); - - aic->AT_program[1].control = DMA_CMD_STOP; - }; - - /* set program start address */ - reg_write(aic, AT_CommandPtr, (unsigned int) virt_to_bus(aic->AT_program)); - - /* typically we use only a few iterations here */ - i = 0; - while (reg_read(aic, AT_CommandPtr) != (unsigned int) - virt_to_bus(aic->AT_program)) { - i++; - if (i>5000) { - PRINT(KERN_ERR, aic->id, - "runaway loop 2 in send_next_async() - bailing out..."); - break; - }; - }; - - /* run program */ - reg_write( aic, AT_ChannelControl, 0x80008000); -} - - -static int aic_transmit(struct hpsb_host *host, struct hpsb_packet *packet) -{ - struct aic5800 *aic = host->hostdata; - struct hpsb_packet *p; - unsigned long flags; - - if (packet->data_size >= 4096) { - PRINT(KERN_ERR, aic->id, "transmit packet data too big (%d)", - packet->data_size); - return 0; - } - - packet->xnext = NULL; - - spin_lock_irqsave(&aic->async_queue_lock, flags); - - if (aic->async_queue == NULL) { - aic->async_queue = packet; - send_next_async(aic); - } else { - p = aic->async_queue; - while (p->xnext != NULL) { - p = p->xnext; - } - - p->xnext = packet; - } - - spin_unlock_irqrestore(&aic->async_queue_lock, flags); - - return 1; -} - -static int get_phy_reg(struct aic5800 *aic, int addr) -{ - int retval; - int i = 0; - - /* sanity check */ - if (addr > 15) { - PRINT(KERN_ERR, aic->id, __FUNCTION__ - ": PHY register address %d out of range", addr); - return -1; - } - - /* request data from PHY */ - reg_write(aic, misc_PhyControl, LINK_PHY_READ | LINK_PHY_ADDR(addr)); - - /* read data from PhyControl register */ - /* note that we have to wait until the register is updated */ - do { - retval = reg_read(aic, misc_PhyControl); - - if (i > 10000) { - PRINT(KERN_ERR, aic->id, __FUNCTION__ - ": runaway loop, aborting"); - retval = -1; - break; - } - i++; - } while ((retval & 0xf000000) != LINK_PHY_RADDR(addr)); - - /* we don't want a PhyInt interrupt */ - reg_write(aic, misc_InterruptClear, INT_PhyInt); - - if (retval != -1) { - return ((retval & 0xff0000)>>16); - } else { - return -1; - } -} - -static quadlet_t generate_own_selfid(struct aic5800 *aic, int phyid) -{ - quadlet_t lsid; - char phyreg[7]; - int i; - - for (i = 1; i < 7; i++) { - phyreg[i] = get_phy_reg(aic, i); - } - - /* Standard PHY register map */ - lsid = 0x80400000 | (phyid << 24); - lsid |= (phyreg[1] & 0x3f) << 16; /* gap count */ - lsid |= (phyreg[2] & 0xc0) << 8; /* max speed */ - lsid |= (phyreg[6] & 0x01) << 11; /* contender (phy dep) */ - lsid |= (phyreg[6] & 0x10) >> 3; /* initiated reset */ - - for (i = 0; i < (phyreg[2] & 0x1f); i++) { /* ports */ - if (phyreg[3 + i] & 0x4) { - lsid |= (((phyreg[3 + i] & 0x8) | 0x10) >> 3) - << (6 - i*2); - } else { - lsid |= 1 << (6 - i*2); - } - } - - return lsid; -}; - -/* moved out to make interrupt routine more readable */ -inline static void handle_selfid(struct aic5800 *aic, struct hpsb_host *host, - int phyid, int isroot, size_t size) -{ - quadlet_t *q = aic->rcv_page; - quadlet_t lsid; - - /* we need our own self-id packet */ - lsid = generate_own_selfid(aic, phyid); - - /* unconnected state? only begin and end marker in rcv_page */ - if (size==8) { - hpsb_selfid_received(host, lsid); - } - - /* process buffer... AIC's FIFO often contains some strangenesses */ - while (size > 0) { - if (q[0] == 0xe0) { - /* marker */ - q += 1; - size -= 4; - continue; - }; - if (q[0] == 0x1) { - /* marker */ - q += 1; - size -= 4; - break; - }; - - if (q[0] == ~q[1]) { - /* correct self-id */ - - if ((q[0] & 0x3f800000) == ((phyid + 1) << 24)) { - /* its our turn now! */ - //PRINT(KERN_INFO, - // aic->id, "selfid packet 0x%x included", lsid); - - hpsb_selfid_received(host, lsid); - } - - //PRINT(KERN_INFO, aic->id, "selfid packet 0x%x rcvd", q[0]); - hpsb_selfid_received(host, q[0]); - q += 2; - size -= 8; - continue; - }; - } - - /* if we are root, our self-id packet is last */ - if (isroot && phyid != 0) { - hpsb_selfid_received(host, lsid); - } - - hpsb_selfid_complete(host, phyid, isroot); -} - -static void aic_irq_handler(int irq, void *dev_id, struct pt_regs *regs) -{ - struct aic5800 *aic = (struct aic5800 *)dev_id; - struct hpsb_host *host = aic->host; - quadlet_t *q = aic->rcv_page; - - int phyid = -1, isroot = 0; - - u32 interruptEvent = reg_read(aic, misc_InterruptEvents); - reg_write(aic, misc_InterruptClear, interruptEvent); - - //printk("InterruptEvent 0x%x\n", interruptEvent); - if ( (interruptEvent & 0x3f) == 0x3f ) { - PRINT(KERN_INFO, aic->id, "Dma Engine Error"); - }; - - if ( interruptEvent & INT_DmaAT ) { - if (aic->AT_program[0].status & 0xFFFF) - PRINT(KERN_INFO, aic->id, "AT: could not transfer %d bytes", - aic->AT_program[0].status & 0xFFFF); - }; - - if ( interruptEvent & INT_PhyInt) { - PRINT(KERN_INFO, aic->id, "PhyInt"); - }; - - if ( interruptEvent & INT_DmaAR ) { - int rcv_bytes; - int i; - - /* we calculate the number of received bytes from the - residual count field */ - rcv_bytes = AIC5800_ARFIFO_SIZE - (aic->AR_program->status & 0xFFFF); - - //PRINT(KERN_INFO, aic->id, "AR_status 0x%x, %d bytes read", aic->AR_program->status, rcv_bytes); - - if ((aic->AR_program->status & 0x84000000) - && (aic->AR_program->status & 0xFFFF) >= 8 ) { - -#ifndef __BIG_ENDIAN - /* we have to do byte-swapping on non-bigendian architectures */ - for (i=0; i< (rcv_bytes / sizeof(quadlet_t)); i++) { - *q = be32_to_cpu(*q); - q++; - }; - q = aic->rcv_page; -#endif - - if (*q == 0xe0) { - phyid = reg_read(aic, misc_NodeID); - isroot = phyid & 0x800000; - phyid = phyid & 0x3F; - handle_selfid(aic, host, phyid, isroot, rcv_bytes); - } else { - hpsb_packet_received(host, aic->rcv_page, rcv_bytes, 0); - }; - } else { - PRINT(KERN_ERR, aic->id, - "AR DMA program status value 0x%x is incorrect!", - aic->AR_program->status); - }; - } - if ( interruptEvent & INT_BusReset ) { - PRINT(KERN_INFO, aic->id, "bus reset occurred"); - if (!host->in_bus_reset) { - hpsb_bus_reset(host); - } - reg_set_bits(aic, misc_Control, 0x1); - aic->NumBusResets++; - }; - - if (interruptEvent & INT_RcvData ) { - aic->RxPackets++; - }; - - if (interruptEvent & INT_TxRdy) { - /* async packet sent - transmitter ready */ - u32 ack; - struct hpsb_packet *packet; - - if (aic->async_queue) { - - spin_lock(&aic->async_queue_lock); - - - ack = reg_read(aic, AT_ChannelStatus) & 0xF; - - packet = aic->async_queue; - aic->async_queue = packet->xnext; - - if (aic->async_queue != NULL) { - send_next_async(aic); - } - spin_unlock(&aic->async_queue_lock); - PRINT(KERN_INFO,aic->id,"packet sent with ack code %d",ack); - hpsb_packet_sent(host, packet, ack); - } // else - //PRINT(KERN_INFO,aic->id,"packet sent without async_queue (self-id?)"); - - aic->TxRdy++; - }; - if (interruptEvent & INT_ATError ) { - PRINT(KERN_INFO,aic->id,"ATError"); - aic->ATError++; - }; - if (interruptEvent & INT_SendRej ) { - aic->SendRej++; - }; - if (interruptEvent & INT_HdrErr ) { - aic->HdrErr++; - }; - if (interruptEvent & INT_TCodeErr ) { - PRINT(KERN_INFO,aic->id,"TCodeErr"); - aic->TCodeErr++; - }; - - aic->NumInterrupts++; - -} - -inline static void * quadquadalign(void *buf) -{ - if ((unsigned int) buf % 0x10 != 0) { - return (void *)(((unsigned int)buf + 0x10) & 0xFFFFFFF0); - } else { - return buf; - }; -} - -static int add_card(struct pci_dev *dev) -{ -#define FAIL(fmt, args...) do {\ - PRINT_G(KERN_ERR, fmt , ## args); \ - num_of_cards--; \ - remove_card(aic); \ - return 1; } while (0) - - struct aic5800 *aic; /* shortcut to currently handled device */ - unsigned long page; - - if (pci_enable_device(dev)) - return 1; - - if (num_of_cards == MAX_AIC5800_CARDS) { - PRINT_G(KERN_WARNING, "cannot handle more than %d cards. " - "Adjust MAX_AIC5800_CARDS in aic5800.h.", - MAX_AIC5800_CARDS); - return 1; - } - - aic = &cards[num_of_cards++]; - - aic->id = num_of_cards-1; - aic->dev = dev; - - if (!request_irq(dev->irq, aic_irq_handler, SA_SHIRQ, - AIC5800_DRIVER_NAME, aic)) { - PRINT(KERN_INFO, aic->id, "allocated interrupt %d", dev->irq); - } else { - FAIL("failed to allocate shared interrupt %d", dev->irq); - } - - page = get_free_page(GFP_KERNEL); - if (page != 0) { - aic->rcv_page = phys_to_virt(page); - } else { - FAIL("failed to allocate receive buffer"); - } - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,13) - aic->registers = ioremap_nocache(dev->base_address[0], - AIC5800_REGSPACE_SIZE); -#else - aic->registers = ioremap_nocache(dev->resource[0].start, - AIC5800_REGSPACE_SIZE); -#endif - - if (aic->registers == NULL) { - FAIL("failed to remap registers - card not accessible"); - } - - PRINT(KERN_INFO, aic->id, "remapped memory space reg 0x%p", - aic->registers); - - aic->pbuf = kmalloc(AIC5800_PBUF_SIZE, GFP_KERNEL); - - if (!aic->pbuf) { - FAIL("failed to allocate program buffer"); - } - - aic->AT_program = quadquadalign(aic->pbuf); - aic->AT_program[2].control = DMA_CMD_STOP; - - aic->AR_program = aic->AT_program + MAX_AT_PROGRAM_SIZE * - sizeof(struct dma_cmd); - - return 0; -#undef FAIL -} - -static void remove_card(struct aic5800 *aic) -{ - /* Disable interrupts of this controller */ - reg_write(aic, misc_InterruptMask, 0); - /* Free AR buffer */ - free_page(virt_to_phys(aic->rcv_page)); - /* Free channel program buffer */ - kfree(aic->pbuf); - /* Free interrupt request */ - free_irq(aic->dev->irq, aic); - /* Unmap register space */ - iounmap(aic->registers); -} - -static int init_driver() -{ - struct pci_dev *dev = NULL; - int success = 0; - - if (num_of_cards) { - PRINT_G(KERN_DEBUG, __PRETTY_FUNCTION__ " called again"); - return 0; - } - - while ((dev = pci_find_device(PCI_VENDOR_ID_ADAPTEC, - PCI_DEVICE_ID_ADAPTEC_5800, dev)) - != NULL) { - if (add_card(dev) == 0) { - success = 1; - } - } - - if (success == 0) { - PRINT_G(KERN_WARNING, "no operable AIC-5800 based cards found"); - return -ENXIO; - } - - return 0; -} - -/** Prepare our local CSR ROM. This is done by using the software-stored - ROM and inserting the GUID read from the EEPROM */ -static size_t get_aic_rom(struct hpsb_host *host, const quadlet_t **ptr) -{ - struct aic5800 *aic = host -> hostdata; - u64 guid; - - /* Read the GUID from the card's EEPROM and put it into the right - place in the CONFIG ROM. */ - guid = read_guid(aic); - aic5800_csr_rom[15] = (u32) (guid >> 32); - aic5800_csr_rom[16] = (u32) (guid & 0xFFFF); - - *ptr = aic5800_csr_rom; - - return sizeof(aic5800_csr_rom); -} - -struct hpsb_host_template *get_aic_template(void) -{ - static struct hpsb_host_template tmpl; - static int initialized = 0; - - if (!initialized) { - /* Initialize by field names so that a template structure - * reorganization does not influence this code. */ - tmpl.name = "aic5800"; - - tmpl.detect_hosts = aic_detect; - tmpl.initialize_host = aic_initialize; - tmpl.release_host = aic_release; - tmpl.get_rom = get_aic_rom; - tmpl.transmit_packet = aic_transmit; - tmpl.devctl = aic_devctl; - - initialized = 1; - } - - return &tmpl; -} - -#ifdef MODULE - -/* EXPORT_NO_SYMBOLS; */ - -MODULE_AUTHOR("Emanuel Pirker <epirker@edu.uni-klu.ac.at>"); -MODULE_DESCRIPTION("Adaptec AIC-5800 PCI-to-IEEE1394 controller driver"); -MODULE_SUPPORTED_DEVICE("aic5800"); - -void cleanup_module(void) -{ - hpsb_unregister_lowlevel(get_aic_template()); - PRINT_G(KERN_INFO, "removed " AIC5800_DRIVER_NAME " module"); -} - -int init_module(void) -{ - if (hpsb_register_lowlevel(get_aic_template())) { - PRINT_G(KERN_ERR, "registering failed"); - return -ENXIO; - } else { - return 0; - } -} - -#endif /* MODULE */ diff -u --recursive --new-file v2.4.6/linux/drivers/ieee1394/aic5800.h linux/drivers/ieee1394/aic5800.h --- v2.4.6/linux/drivers/ieee1394/aic5800.h Thu Jan 13 16:49:22 2000 +++ linux/drivers/ieee1394/aic5800.h Wed Dec 31 16:00:00 1969 @@ -1,292 +0,0 @@ -/* -** aic5800.h - Adaptec AIC-5800 PCI-IEEE1394 chip driver header file -** Copyright (C)1999 Emanuel Pirker <epirker@edu.uni-klu.ac.at> -** -** This program is free software; you can redistribute it and/or modify -** it under the terms of the GNU General Public License as published by -** the Free Software Foundation; either version 2 of the License, or -** (at your option) any later version. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -** -** You should have received a copy of the GNU General Public License -** along with this program; if not, write to the Free Software -** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -** -*/ - -#ifndef AIC5800_H -#define AIC5800_H - -#define AIC5800_DRIVER_NAME "aic5800" - -#define MAX_AIC5800_CARDS 4 -#define AIC5800_REGSPACE_SIZE 512 -#define AIC5800_PBUF_SIZE 512 - -#define MAX_AT_PROGRAM_SIZE 10 -#define AIC5800_ARFIFO_SIZE 128 - -struct dma_cmd { - u32 control; - u32 address; - u32 branchAddress; - u32 status; -}; - -struct aic5800 { - int id; /* sequential card number */ - - struct pci_dev *dev; - - /* remapped memory spaces */ - void *registers; - - struct hpsb_host *host; - - int phyid, isroot; - - void *rcv_page; - void *pbuf; - - struct dma_cmd *AT_program; - u32 *AT_status; - struct dma_cmd *AR_program; - u32 *AR_status; - int AR_active; - - struct hpsb_packet *async_queue; - spinlock_t async_queue_lock; - - unsigned long NumInterrupts, NumBusResets; - unsigned long TxPackets, RxPackets; - unsigned long TxErrors, RxErrors; - unsigned long TxRdy, ATError, HdrErr, TCodeErr, SendRej; - -}; - - -/* - * Register read and write helper functions. - */ -inline static void reg_write(const struct aic5800 *aic, int offset, u32 data) -{ - writel(data, aic->registers + offset); -} - -inline static u32 reg_read(const struct aic5800 *aic, int offset) -{ - return readl(aic->registers + offset); -} - -inline static void reg_set_bits(const struct aic5800 *aic, int offset, - u32 mask) -{ - reg_write(aic, offset, (reg_read(aic, offset) | mask)); -} - -inline static void reg_clear_bits(const struct aic5800 *aic, int offset, - u32 mask) -{ - reg_write(aic, offset, (reg_read(aic, offset) & ~mask)); -} - - -/* AIC-5800 Registers */ - -#define AT_ChannelControl 0x0 -#define AT_ChannelStatus 0x4 -#define AT_CommandPtr 0xC -#define AT_InterruptSelect 0x10 -#define AT_BranchSelect 0x14 -#define AT_WaitSelect 0x18 - -/* Asynchronous receive */ -#define AR_ChannelControl 0x20 -#define AR_ChannelStatus 0x24 -#define AR_CommandPtr 0x2C - -/* ITA */ -#define ITA_ChannelControl 0x40 -#define ITA_ChannelStatus 0x44 -#define ITA_CommandPtr 0x4C - -/* ITB */ -#define ITB_ChannelControl 0x60 -#define ITB_ChannelStatus 0x64 -#define ITB_CommandPtr 0x6C - -/* IRA */ -#define IRA_ChannelControl 0x80 -#define IRA_ChannelStatus 0x84 -#define IRA_CommandPtr 0x8C - -/* IRB */ -#define IRB_ChannelControl 0xA0 -#define IRB_ChannelStatus 0xA4 -#define IRB_CommandPtr 0xAC - -/* miscellaneous */ -#define misc_Version 0x100 -#define misc_Control 0x104 -#define misc_NodeID 0x108 -#define misc_Reset 0x10C -#define misc_PacketControl 0x110 -#define misc_Diagnostic 0x114 -#define misc_PhyControl 0x118 -#define misc_ATRetries 0x11C -#define misc_SSNinterface 0x120 -#define misc_CycleTimer 0x124 - -/* ITA */ -#define ITA_EventCycle 0x130 -#define ITA_Configuration 0x134 -#define ITA_Bandwidth 0x138 - -/* ITB */ -#define ITB_EventCycle 0x140 -#define ITB_Configuration 0x144 -#define ITB_Bandwidth 0x148 - -/* IRA */ -#define IRA_EventCycle 0x150 -#define IRA_Configuration 0x154 - -/* IRB */ -#define IRB_EventCycle 0x160 -#define IRB_Configuration 0x164 - -/* RSU */ -#define RSU_Enable 0x170 -#define RSU_Interrupt 0x174 -#define RSU_TablePtr 0x178 -#define RSU_InterruptSet 0x17C - -/* misc */ -#define misc_InterruptEvents 0x180 -#define misc_InterruptMask 0x184 -#define misc_InterruptClear 0x188 -#define misc_CardBusEvent 0x1E0 -#define misc_CardBusMask 0x1E4 -#define misc_CardBusState 0x1E8 -#define misc_CardBusForce 0x1EC -#define misc_SEEPCTL 0x1F0 - -/* Interrupts */ -#define INT_DmaAT 1 -#define INT_DmaAR (1<<1) -#define INT_DmaITA (1<<2) -#define INT_DmaITB (1<<3) -#define INT_DmaIRA (1<<4) -#define INT_DmaIRB (1<<5) -#define INT_PERResponse (1<<7) -#define INT_CycleEventITA (1<<8) -#define INT_CycleEventITB (1<<9) -#define INT_CycleEventIRA (1<<10) -#define INT_CycleEventIRB (1<<11) -#define INT_BusReset (1<<12) -#define INT_CmdReset (1<<13) -#define INT_PhyInt (1<<14) -#define INT_RcvData (1<<15) -#define INT_TxRdy (1<<16) -#define INT_CycleStart (1<<17) -#define INT_CycleSeconds (1<<18) -#define INT_CycleLost (1<<19) -#define INT_ATError (1<<20) -#define INT_SendRej (1<<21) -#define INT_HdrErr (1<<22) -#define INT_TCodeErr (1<<23) -#define INT_PRQUxferErr (1<<24) -#define INT_PWQUxferErr (1<<25) -#define INT_RSUxferErr (1<<26) -#define INT_RSDone (1<<27) -#define INT_PSOutOfRetries (1<<28) -#define INT_cycleTooLong (1<<29) - -/* DB DMA constants */ -#define DMA_CMD_OUTPUTMORE 0 -#define DMA_CMD_OUTPUTLAST 0x10000000 -#define DMA_CMD_INPUTMORE 0x20000000 -#define DMA_CMD_INPUTLAST 0x30000000 -#define DMA_CMD_STOREQUAD 0x40000000 -#define DMA_CMD_LOADQUAD 0x50000000 -#define DMA_CMD_NOP 0x60000000 -#define DMA_CMD_STOP 0x70000000 - -#define DMA_KEY_STREAM0 0 -#define DMA_KEY_STREAM1 (1<<24) -#define DMA_KEY_STREAM2 (2<<24) -#define DMA_KEY_STREAM3 (3<<24) -#define DMA_KEY_REGS (5<<24) -#define DMA_KEY_SYSTEM (6<<24) -#define DMA_KEY_DEVICE (7<<24) - -#define DMA_INTR_NEVER 0 -#define DMA_INTR_TRUE (1<<20) -#define DMA_INTR_FALSE (2<<20) -#define DMA_INTR_ALWAYS (3<<20) -#define DMA_WAIT_NEVER 0 -#define DMA_WAIT_TRUE (1<<16) -#define DMA_WAIT_FALSE (2<<16) -#define DMA_WAIT_ALWAYS (3<<16) -#define DMA_BRANCH_NEVER 0 -#define DMA_BRANCH_TRUE (1<<18) -#define DMA_BRANCH_FALSE (2<<18) -#define DMA_BRANCH_ALWAYS (3<<18) - -#define DMA_SPEED_100 0 -#define DMA_SPEED_200 (1<<16) -#define DMA_SPEED_400 (2<<16) - -/* PHY access */ -#define LINK_PHY_READ (1<<15) -#define LINK_PHY_WRITE (1<<14) -#define LINK_PHY_ADDR(addr) (addr<<8) -#define LINK_PHY_WDATA(data) (data) -#define LINK_PHY_RADDR(addr) (addr<<24) - -quadlet_t aic5800_csr_rom[] = { - /* bus info block */ - 0x041ffb82, // length of bus info block, CRC - 0x31333934, // 1394 designator - 0xf005a000, // various capabilites - 0x0000d189, // node_vendor_id, chip_id_hi - 0x401010fc, // chip_id_lo - /* root directory */ - 0x00040e54, // length of root directory, CRC - 0x030000d1, // module_vendor_id - 0x0c008000, // various capabilities - 0x8d000006, // offset of node unique id leaf - 0xd1000001, // offset of unit directory - /* unit directory */ - 0x0003e60d, // length of unit directory, CRC - 0x12000000, // unit_spec_id - 0x13000000, // unit_sw_version - 0xd4000004, // offset of unit dependent directory - /* node unique id leaf */ - 0x00026ba7, // length of leaf, CRC - 0x0000d189, // node_vendor_id, chip_id_hi - 0x401010fc, // chip_id_lo - /* unit dependent directory */ - 0x0002ae47, // length of directory, CRC - 0x81000002, // offset of vendor name leaf - 0x82000006, // offset of model name leaf - /* vendor name leaf */ - 0x000486a3, // length of leaf, CRC - 0x00000000, - 0x00000000, - 0x41444150, // ADAP - 0x54454300, // TEC - /* model name leaf */ - 0x0004f420, // length of leaf, CRC - 0x00000000, - 0x00000000, - 0x4148412d, // AHA- - 0x38393430 // 8940 -}; - -#endif - diff -u --recursive --new-file v2.4.6/linux/drivers/ieee1394/csr.c linux/drivers/ieee1394/csr.c --- v2.4.6/linux/drivers/ieee1394/csr.c Thu Mar 1 16:57:11 2001 +++ linux/drivers/ieee1394/csr.c Thu Jul 19 17:48:15 2001 @@ -118,9 +118,8 @@ int oldcycle; quadlet_t ret; - if ((csraddr | length) & 0x3) { + if ((csraddr | length) & 0x3) return RCODE_TYPE_ERROR; - } length /= 4; @@ -222,14 +221,13 @@ return RCODE_COMPLETE; } -static int write_regs(struct hpsb_host *host, int nodeid, quadlet_t *data, - u64 addr, unsigned int length) +static int write_regs(struct hpsb_host *host, int nodeid, int destid, + quadlet_t *data, u64 addr, unsigned int length) { int csraddr = addr - CSR_REGISTER_BASE; - if ((csraddr | length) & 0x3) { + if ((csraddr | length) & 0x3) return RCODE_TYPE_ERROR; - } length /= 4; @@ -310,7 +308,8 @@ unsigned long flags; quadlet_t *regptr = NULL; - if (csraddr & 0x3) return RCODE_TYPE_ERROR; + if (csraddr & 0x3) + return RCODE_TYPE_ERROR; if (csraddr < CSR_BUS_MANAGER_ID || csraddr > CSR_CHANNELS_AVAILABLE_LO || extcode != EXTCODE_COMPARE_SWAP) @@ -379,14 +378,13 @@ } } -static int write_fcp(struct hpsb_host *host, int nodeid, quadlet_t *data, - u64 addr, unsigned int length) +static int write_fcp(struct hpsb_host *host, int nodeid, int dest, + quadlet_t *data, u64 addr, unsigned int length) { int csraddr = addr - CSR_REGISTER_BASE; - if (length > 512) { + if (length > 512) return RCODE_TYPE_ERROR; - } switch (csraddr) { case CSR_FCP_COMMAND: diff -u --recursive --new-file v2.4.6/linux/drivers/ieee1394/guid.c linux/drivers/ieee1394/guid.c --- v2.4.6/linux/drivers/ieee1394/guid.c Thu Mar 1 16:57:11 2001 +++ linux/drivers/ieee1394/guid.c Wed Dec 31 16:00:00 1969 @@ -1,237 +0,0 @@ -/* - * IEEE 1394 for Linux - * - * GUID collection and management - * - * Copyright (C) 2000 Andreas E. Bombe - * - * This code is licensed under the GPL. See the file COPYING in the root - * directory of the kernel sources for details. - */ - -#include <linux/kernel.h> -#include <linux/list.h> -#include <linux/slab.h> -#include <asm/byteorder.h> -#include <asm/atomic.h> - -#include "ieee1394_types.h" -#include "ieee1394.h" -#include "hosts.h" -#include "ieee1394_transactions.h" -#include "highlevel.h" -#include "csr.h" - - -static atomic_t outstanding_requests; - -static LIST_HEAD(guid_list); -rwlock_t guid_lock = RW_LOCK_UNLOCKED; - -struct guid_entry { - struct list_head list; - atomic_t refcount; - - u64 guid; - - struct hpsb_host *host; - nodeid_t node_id; - - atomic_t generation; -}; - -struct guid_req { - struct hpsb_packet *pkt; - struct tq_struct tq; -}; - - -static struct guid_entry *create_guid_entry(void) -{ - struct guid_entry *ge; - unsigned long flags; - - ge = kmalloc(sizeof(struct guid_entry), SLAB_ATOMIC); - if (!ge) return NULL; - - INIT_LIST_HEAD(&ge->list); - atomic_set(&ge->refcount, 0); - ge->guid = (u64) -1; - ge->host = NULL; - ge->node_id = 0; - atomic_set(&ge->generation, -1); - - write_lock_irqsave(&guid_lock, flags); - list_add_tail(&ge->list, &guid_list); - write_unlock_irqrestore(&guid_lock, flags); - - return ge; -} - -static struct guid_entry *find_entry(u64 guid) -{ - struct list_head *lh; - struct guid_entry *ge; - - lh = guid_list.next; - while (lh != &guid_list) { - ge = list_entry(lh, struct guid_entry, list); - if (ge->guid == guid) return ge; - lh = lh->next; - } - - return NULL; -} - -static void associate_guid(struct hpsb_host *host, nodeid_t nodeid, u64 guid) -{ - struct guid_entry *ge; - unsigned long flags; - - HPSB_DEBUG("node %d on host 0x%p has GUID 0x%08x%08x", - nodeid & NODE_MASK, host, (unsigned int)(guid >> 32), - (unsigned int)(guid & 0xffffffff)); - - read_lock_irqsave(&guid_lock, flags); - ge = find_entry(guid); - read_unlock_irqrestore(&guid_lock, flags); - - if (!ge) ge = create_guid_entry(); - if (!ge) return; - - ge->host = host; - ge->node_id = nodeid; - ge->guid = guid; - - atomic_set(&ge->generation, get_hpsb_generation()); -} - -static void pkt_complete(struct guid_req *req) -{ - struct hpsb_packet *pkt = req->pkt; - int rcode = (pkt->header[1] >> 12) & 0xf; - - if (pkt->ack_code == ACK_PENDING && rcode == RCODE_COMPLETE) { - if (*(char *)pkt->data > 1) { - associate_guid(pkt->host, pkt->node_id, - ((u64)be32_to_cpu(pkt->data[3]) << 32) - | be32_to_cpu(pkt->data[4])); - } else { - HPSB_DEBUG("minimal ROM on node %d", - pkt->node_id & NODE_MASK); - } - } else { - HPSB_DEBUG("guid transaction error: ack %d, rcode %d", - pkt->ack_code, rcode); - } - - free_tlabel(pkt->host, pkt->node_id, pkt->tlabel); - free_hpsb_packet(pkt); - kfree(req); - - if (atomic_dec_and_test(&outstanding_requests)) { - /* FIXME: free unreferenced and inactive GUID entries. */ - } -} - - -static void host_reset(struct hpsb_host *host) -{ - struct guid_req *greq; - struct hpsb_packet *pkt; - struct selfid *sid = (struct selfid *)host->topology_map; - int nodecount = host->node_count; - nodeid_t nodeid = LOCAL_BUS; - - for (; nodecount; nodecount--, nodeid++, sid++) { - while (sid->extended) sid++; - if (!sid->link_active) continue; - if (nodeid == host->node_id) continue; - - greq = kmalloc(sizeof(struct guid_req), SLAB_ATOMIC); - if (!greq) { - HPSB_ERR("out of memory in GUID processing"); - return; - } - - pkt = hpsb_make_readbpacket(host, nodeid, - CSR_REGISTER_BASE + CSR_CONFIG_ROM, - 20); - if (!pkt) { - kfree(greq); - HPSB_ERR("out of memory in GUID processing"); - return; - } - - INIT_TQ_LINK(greq->tq); - greq->tq.sync = 0; - greq->tq.routine = (void (*)(void*))pkt_complete; - greq->tq.data = greq; - greq->pkt = pkt; - - queue_task(&greq->tq, &pkt->complete_tq); - - if (!hpsb_send_packet(pkt)) { - free_tlabel(pkt->host, pkt->node_id, pkt->tlabel); - free_hpsb_packet(pkt); - kfree(greq); - HPSB_NOTICE("failed to send packet in GUID processing"); - } - - HPSB_INFO("GUID request sent to node %d", nodeid & NODE_MASK); - atomic_inc(&outstanding_requests); - } -} - - -struct guid_entry *hpsb_guid_get_handle(u64 guid) -{ - unsigned long flags; - struct guid_entry *ge; - - read_lock_irqsave(&guid_lock, flags); - ge = find_entry(guid); - if (ge) atomic_inc(&ge->refcount); - read_unlock_irqrestore(&guid_lock, flags); - - return ge; -} - -struct hpsb_host *hpsb_guid_localhost(struct guid_entry *ge) -{ - if (atomic_read(&ge->generation) != get_hpsb_generation()) return NULL; - if (ge->node_id == ge->host->node_id) return ge->host; - return NULL; -} - -int hpsb_guid_fill_packet(struct guid_entry *ge, struct hpsb_packet *pkt) -{ - if (atomic_read(&ge->generation) != get_hpsb_generation()) return 0; - - pkt->host = ge->host; - pkt->node_id = ge->node_id; - pkt->generation = atomic_read(&ge->generation); - return 1; -} - - -static struct hpsb_highlevel_ops guid_ops = { - host_reset: host_reset, -}; - -static struct hpsb_highlevel *hl; - -void init_ieee1394_guid(void) -{ - atomic_set(&outstanding_requests, 0); - - hl = hpsb_register_highlevel("GUID manager", &guid_ops); - if (!hl) { - HPSB_ERR("out of memory during ieee1394 initialization"); - } -} - -void cleanup_ieee1394_guid(void) -{ - hpsb_unregister_highlevel(hl); -} diff -u --recursive --new-file v2.4.6/linux/drivers/ieee1394/guid.h linux/drivers/ieee1394/guid.h --- v2.4.6/linux/drivers/ieee1394/guid.h Thu Mar 1 16:57:11 2001 +++ linux/drivers/ieee1394/guid.h Wed Dec 31 16:00:00 1969 @@ -1,54 +0,0 @@ - -#ifndef _IEEE1394_GUID_H -#define _IEEE1394_GUID_H - - -/* - * General information: Finding out which GUID belongs to which node is done by - * sending packets and therefore waiting for the answers. Wherever it is - * mentioned that a node is inaccessible this could just as well mean that we - * just don't know yet (usually, bus reset handlers can't rely on GUIDs being - * associated with current nodes). - */ - -struct guid_entry; -typedef struct guid_entry *hpsb_guid_t; - - -/* - * Returns a guid handle (which has its reference count incremented) or NULL if - * there is the GUID in question is not known of. Getting a valid handle does - * not mean that the node with this GUID is currently accessible (might not be - * plugged in or powered down). - */ -hpsb_guid_t hpsb_guid_get_handle(u64 guid); - -/* - * If the handle refers to a local host, this function will return the pointer - * to the hpsb_host structure. It will return NULL otherwise. Once you have - * established it is a local host, you can use that knowledge from then on (the - * GUID won't wander to an external node). - * - * Note that the local GUID currently isn't collected, so this will always - * return NULL. - */ -struct hpsb_host *hpsb_guid_localhost(hpsb_guid_t handle); - -/* - * This will fill in the given, pre-initialised hpsb_packet with the current - * information from the GUID handle (host, node ID, generation number). It will - * return false if the node owning the GUID is not accessible (and not modify the - * hpsb_packet) and return true otherwise. - * - * Note that packet sending may still fail in hpsb_send_packet if a bus reset - * happens while you are trying to set up the packet (due to obsolete generation - * number). It will at least reliably fail so that you don't accidentally and - * unknowingly send your packet to the wrong node. - */ -int hpsb_guid_fill_packet(hpsb_guid_t handle, struct hpsb_packet *pkt); - - -void init_ieee1394_guid(void); -void cleanup_ieee1394_guid(void); - -#endif /* _IEEE1394_GUID_H */ diff -u --recursive --new-file v2.4.6/linux/drivers/ieee1394/highlevel.c linux/drivers/ieee1394/highlevel.c --- v2.4.6/linux/drivers/ieee1394/highlevel.c Wed Jul 5 13:03:56 2000 +++ linux/drivers/ieee1394/highlevel.c Thu Jul 19 17:48:15 2001 @@ -175,6 +175,19 @@ DEFINE_MULTIPLEXER(host_reset) #undef DEFINE_MULTIPLEXER +/* Add one host to our list */ +void highlevel_add_one_host (struct hpsb_host *host) +{ + if (host->template->initialize_host) + if (!host->template->initialize_host(host)) + goto fail; + host->initialized = 1; + highlevel_add_host (host); + hpsb_reset_bus (host, LONG_RESET); +fail: + host->template->number_of_hosts++; +} + void highlevel_iso_receive(struct hpsb_host *host, quadlet_t *data, unsigned int length) { @@ -200,7 +213,7 @@ { struct list_head *entry; struct hpsb_highlevel *hl; - int cts = data[0]; + int cts = data[0] >> 4; read_lock(&hl_drivers_lock); entry = hl_drivers.next; @@ -262,8 +275,8 @@ return rcode; } -int highlevel_write(struct hpsb_host *host, int nodeid, quadlet_t *data, - u64 addr, unsigned int length) +int highlevel_write(struct hpsb_host *host, int nodeid, int destid, + quadlet_t *data, u64 addr, unsigned int length) { struct hpsb_address_serve *as; struct list_head *entry; @@ -281,8 +294,8 @@ length); if (as->op->write != NULL) { - rcode = as->op->write(host, nodeid, data, addr, - partlength); + rcode = as->op->write(host, nodeid, destid, data, + addr, partlength); } else { rcode = RCODE_TYPE_ERROR; } @@ -376,23 +389,6 @@ return rcode; } - - -#ifndef MODULE - -void register_builtin_highlevels(void) -{ -#ifdef CONFIG_IEEE1394_RAWIO - { - int init_raw1394(void); - init_raw1394(); - } -#endif -} - -#endif /* !MODULE */ - - void init_hpsb_highlevel(void) { INIT_LIST_HEAD(&dummy_zero_addr.as_list); @@ -407,8 +403,4 @@ list_add_tail(&dummy_zero_addr.as_list, &addr_space); list_add_tail(&dummy_max_addr.as_list, &addr_space); - -#ifndef MODULE - register_builtin_highlevels(); -#endif } diff -u --recursive --new-file v2.4.6/linux/drivers/ieee1394/highlevel.h linux/drivers/ieee1394/highlevel.h --- v2.4.6/linux/drivers/ieee1394/highlevel.h Wed Mar 22 00:02:48 2000 +++ linux/drivers/ieee1394/highlevel.h Thu Jul 19 17:48:15 2001 @@ -76,8 +76,8 @@ /* These functions have to implement block reads for themselves. */ int (*read) (struct hpsb_host *host, int nodeid, quadlet_t *buffer, u64 addr, unsigned int length); - int (*write) (struct hpsb_host *host, int nodeid, quadlet_t *data, - u64 addr, unsigned int length); + int (*write) (struct hpsb_host *host, int nodeid, int destid, + quadlet_t *data, u64 addr, unsigned int length); /* Lock transactions: write results of ext_tcode operation into * *store. */ @@ -91,13 +91,14 @@ void init_hpsb_highlevel(void); void highlevel_add_host(struct hpsb_host *host); +void highlevel_add_one_host(struct hpsb_host *host); void highlevel_remove_host(struct hpsb_host *host); void highlevel_host_reset(struct hpsb_host *host); int highlevel_read(struct hpsb_host *host, int nodeid, quadlet_t *buffer, u64 addr, unsigned int length); -int highlevel_write(struct hpsb_host *host, int nodeid, quadlet_t *data, - u64 addr, unsigned int length); +int highlevel_write(struct hpsb_host *host, int nodeid, int destid, + quadlet_t *data, u64 addr, unsigned int length); int highlevel_lock(struct hpsb_host *host, int nodeid, quadlet_t *store, u64 addr, quadlet_t data, quadlet_t arg, int ext_tcode); int highlevel_lock64(struct hpsb_host *host, int nodeid, octlet_t *store, diff -u --recursive --new-file v2.4.6/linux/drivers/ieee1394/hosts.c linux/drivers/ieee1394/hosts.c --- v2.4.6/linux/drivers/ieee1394/hosts.c Sun Feb 4 21:34:18 2001 +++ linux/drivers/ieee1394/hosts.c Thu Jul 19 17:48:15 2001 @@ -106,9 +106,7 @@ sema_init(&h->tlabel_count, 64); spin_lock_init(&h->tlabel_lock); - INIT_TQ_LINK(h->timeout_tq); - h->timeout_tq.routine = (void (*)(void*))abort_timedouts; - h->timeout_tq.data = h; + INIT_TQUEUE(&h->timeout_tq, (void (*)(void*))abort_timedouts, h); h->topology_map = h->csr.topology_map + 3; h->speed_map = (u8 *)(h->csr.speed_map + 2); @@ -149,6 +147,10 @@ int count; struct hpsb_host *host; + /* PCI cards should register one host at a time */ + if (tmpl->detect_hosts == NULL) + return; + count = tmpl->detect_hosts(tmpl); for (host = tmpl->hosts; host != NULL; host = host->next) { @@ -156,13 +158,13 @@ host->initialized = 1; highlevel_add_host(host); - hpsb_reset_bus(host); + hpsb_reset_bus(host, LONG_RESET); } } tmpl->number_of_hosts = count; - HPSB_INFO("detected %d %s adapter%c", count, tmpl->name, - (count != 1 ? 's' : ' ')); + HPSB_INFO("detected %d %s adapter%s", count, tmpl->name, + (count != 1 ? "s" : "")); } static void shutdown_hosts(struct hpsb_host_template *tmpl) @@ -252,7 +254,7 @@ int hpsb_register_lowlevel(struct hpsb_host_template *tmpl) { add_template(tmpl); - HPSB_INFO("registered %s driver, initializing now", tmpl->name); + HPSB_DEBUG("Registered %s driver, initializing now", tmpl->name); init_hosts(tmpl); return 0; @@ -266,56 +268,3 @@ HPSB_PANIC("remove_template failed on %s", tmpl->name); } } - - - -#ifndef MODULE - -/* - * This is the init function for builtin lowlevel drivers. To add new drivers - * put their setup code (get and register template) here. Module only - * drivers don't need to touch this. - */ - -#define SETUP_TEMPLATE(name, visname) \ -do { \ - extern struct hpsb_host_template *get_ ## name ## _template(void); \ - t = get_ ## name ## _template(); \ - \ - if (t != NULL) { \ - if(!hpsb_register_lowlevel(t)) { \ - count++; \ - } \ - } else { \ - HPSB_WARN(visname " driver returned no host template"); \ - } \ -} while (0) - -void __init register_builtin_lowlevels() -{ - struct hpsb_host_template *t; - int count = 0; - - /* Touch t to avoid warning if no drivers are configured to - * be built directly into the kernel. */ - t = NULL; - -#ifdef CONFIG_IEEE1394_PCILYNX - SETUP_TEMPLATE(lynx, "Lynx"); -#endif - -#ifdef CONFIG_IEEE1394_AIC5800 - SETUP_TEMPLATE(aic, "AIC-5800"); -#endif - -#ifdef CONFIG_IEEE1394_OHCI1394 - SETUP_TEMPLATE(ohci, "OHCI-1394"); -#endif - - HPSB_INFO("%d host adapter%s initialized", count, - (count != 1 ? "s" : "")); -} - -#undef SETUP_TEMPLATE - -#endif /* !MODULE */ diff -u --recursive --new-file v2.4.6/linux/drivers/ieee1394/hosts.h linux/drivers/ieee1394/hosts.h --- v2.4.6/linux/drivers/ieee1394/hosts.h Tue Jan 2 16:45:38 2001 +++ linux/drivers/ieee1394/hosts.h Thu Jul 19 17:48:15 2001 @@ -56,6 +56,7 @@ /* fields readable and writeable by the hosts */ void *hostdata; + struct pci_dev *pdev; int embedded_hostdata[0]; }; @@ -94,6 +95,16 @@ * listen on unrequested channels. */ ISO_LISTEN_CHANNEL, ISO_UNLISTEN_CHANNEL +}; + +enum reset_types { + /* 166 microsecond reset -- only type of reset available on + non-1394a capable IEEE 1394 controllers */ + LONG_RESET, + + /* Short (arbitrated) reset -- only available on 1394a capable + IEEE 1394 capable controllers */ + SHORT_RESET }; struct hpsb_host_template { diff -u --recursive --new-file v2.4.6/linux/drivers/ieee1394/ieee1394_core.c linux/drivers/ieee1394/ieee1394_core.c --- v2.4.6/linux/drivers/ieee1394/ieee1394_core.c Thu Mar 1 16:57:11 2001 +++ linux/drivers/ieee1394/ieee1394_core.c Fri Jul 20 12:47:31 2001 @@ -10,6 +10,7 @@ * directory of the kernel sources for details. */ +#include <linux/module.h> #include <linux/config.h> #include <linux/kernel.h> #include <linux/list.h> @@ -28,7 +29,7 @@ #include "highlevel.h" #include "ieee1394_transactions.h" #include "csr.h" -#include "guid.h" +#include "nodemgr.h" atomic_t hpsb_generation = ATOMIC_INIT(0); @@ -72,24 +73,18 @@ struct hpsb_packet *alloc_hpsb_packet(size_t data_size) { struct hpsb_packet *packet = NULL; - void *header = NULL, *data = NULL; + void *data = NULL; int kmflags = in_interrupt() ? GFP_ATOMIC : GFP_KERNEL; packet = kmalloc(sizeof(struct hpsb_packet), kmflags); - header = kmalloc(5 * 4, kmflags); - if (header == NULL || packet == NULL) { - kfree(header); - kfree(packet); - return NULL; - } + if (!packet) return NULL; memset(packet, 0, sizeof(struct hpsb_packet)); - packet->header = header; + packet->header = packet->embedded_header; if (data_size) { data = kmalloc(data_size + 8, kmflags); - if (data == NULL) { - kfree(header); + if (!data) { kfree(packet); return NULL; } @@ -98,7 +93,7 @@ packet->data_size = data_size; } - INIT_TQ_HEAD(packet->complete_tq); + INIT_LIST_HEAD(&packet->complete_tq); INIT_LIST_HEAD(&packet->list); sema_init(&packet->state_change, 0); packet->state = unused; @@ -118,24 +113,21 @@ */ void free_hpsb_packet(struct hpsb_packet *packet) { - if (packet == NULL) { - return; - } + if (!packet) return; kfree(packet->data); - kfree(packet->header); kfree(packet); } -int hpsb_reset_bus(struct hpsb_host *host) +int hpsb_reset_bus(struct hpsb_host *host, int type) { if (!host->initialized) { return 1; } if (!hpsb_bus_reset(host)) { - host->template->devctl(host, RESET_BUS, 0); + host->template->devctl(host, RESET_BUS, type); return 0; } else { return 1; @@ -297,14 +289,16 @@ } } + void hpsb_selfid_received(struct hpsb_host *host, quadlet_t sid) { if (host->in_bus_reset) { - HPSB_DEBUG("including selfid 0x%x", sid); + HPSB_DEBUG("Including SelfID 0x%x", sid); host->topology_map[host->selfid_count++] = sid; } else { /* FIXME - info on which host */ - HPSB_NOTICE("spurious selfid packet (0x%8.8x) received", sid); + HPSB_NOTICE("Spurious SelfID packet (0x%08x) received from %s", + sid, host->template->name); } } @@ -318,13 +312,12 @@ if (!host->node_count) { if (host->reset_retries++ < 20) { /* selfid stage did not complete without error */ - HPSB_NOTICE("error in SelfID stage - resetting"); - hpsb_reset_bus(host); + HPSB_NOTICE("Error in SelfID stage, resetting"); + hpsb_reset_bus(host, LONG_RESET); return; } else { - HPSB_NOTICE("stopping out-of-control reset loop"); - HPSB_NOTICE("warning - topology map and speed map will " - "therefore not be valid"); + HPSB_NOTICE("Stopping out-of-control reset loop"); + HPSB_NOTICE("Warning - topology map and speed map will not be valid"); } } else { build_speed_map(host, host->node_count); @@ -459,7 +452,7 @@ } if (lh == &host->pending_packets) { - HPSB_INFO("unsolicited response packet received - np"); + HPSB_DEBUG("unsolicited response packet received - np"); dump_packet("contents:", data, 16); spin_unlock_irqrestore(&host->pending_pkt_lock, flags); return; @@ -554,7 +547,8 @@ { struct hpsb_packet *packet; int length, rcode, extcode; - int source = data[1] >> 16; + nodeid_t source = data[1] >> 16; + nodeid_t dest = data[0] >> 16; u64 addr; /* big FIXME - no error checking is done for an out of bounds length */ @@ -562,7 +556,8 @@ switch (tcode) { case TCODE_WRITEQ: addr = (((u64)(data[1] & 0xffff)) << 32) | data[2]; - rcode = highlevel_write(host, source, data+3, addr, 4); + rcode = highlevel_write(host, source, dest, data+3, + addr, 4); if (!write_acked && ((data[0] >> 16) & NODE_MASK) != NODE_MASK) { @@ -575,8 +570,8 @@ case TCODE_WRITEB: addr = (((u64)(data[1] & 0xffff)) << 32) | data[2]; - rcode = highlevel_write(host, source, data+4, addr, - data[3]>>16); + rcode = highlevel_write(host, source, dest, data+4, + addr, data[3]>>16); if (!write_acked && ((data[0] >> 16) & NODE_MASK) != NODE_MASK) { @@ -783,31 +778,19 @@ } -#ifndef MODULE - -void __init ieee1394_init(void) +static int __init ieee1394_init(void) { - register_builtin_lowlevels(); init_hpsb_highlevel(); init_csr(); - init_ieee1394_guid(); + init_ieee1394_nodemgr(); + return 0; } -#else - -int init_module(void) +static void __exit ieee1394_cleanup(void) { - init_hpsb_highlevel(); - init_csr(); - init_ieee1394_guid(); - - return 0; -} - -void cleanup_module(void) -{ - cleanup_ieee1394_guid(); + cleanup_ieee1394_nodemgr(); cleanup_csr(); } -#endif +module_init(ieee1394_init); +module_exit(ieee1394_cleanup); diff -u --recursive --new-file v2.4.6/linux/drivers/ieee1394/ieee1394_core.h linux/drivers/ieee1394/ieee1394_core.h --- v2.4.6/linux/drivers/ieee1394/ieee1394_core.h Mon Dec 11 13:20:17 2000 +++ linux/drivers/ieee1394/ieee1394_core.h Thu Jul 19 17:48:15 2001 @@ -70,6 +70,8 @@ /* Store jiffies for implementing bus timeouts. */ unsigned long sendtime; + + quadlet_t embedded_header[5]; }; @@ -107,7 +109,7 @@ /* Initiate bus reset on the given host. Returns 1 if bus reset already in * progress, 0 otherwise. */ -int hpsb_reset_bus(struct hpsb_host *host); +int hpsb_reset_bus(struct hpsb_host *host, int type); /* * The following functions are exported for host driver module usage. All of diff -u --recursive --new-file v2.4.6/linux/drivers/ieee1394/ieee1394_syms.c linux/drivers/ieee1394/ieee1394_syms.c --- v2.4.6/linux/drivers/ieee1394/ieee1394_syms.c Sun Oct 1 19:53:07 2000 +++ linux/drivers/ieee1394/ieee1394_syms.c Fri Jul 20 12:47:31 2001 @@ -18,7 +18,7 @@ #include "ieee1394_core.h" #include "ieee1394_transactions.h" #include "highlevel.h" -#include "guid.h" +#include "nodemgr.h" EXPORT_SYMBOL(hpsb_register_lowlevel); EXPORT_SYMBOL(hpsb_unregister_lowlevel); @@ -49,11 +49,15 @@ EXPORT_SYMBOL(fill_async_lock); EXPORT_SYMBOL(fill_async_lock_resp); EXPORT_SYMBOL(fill_iso_packet); +EXPORT_SYMBOL(fill_phy_packet); EXPORT_SYMBOL(hpsb_make_readqpacket); EXPORT_SYMBOL(hpsb_make_readbpacket); EXPORT_SYMBOL(hpsb_make_writeqpacket); EXPORT_SYMBOL(hpsb_make_writebpacket); EXPORT_SYMBOL(hpsb_make_lockpacket); +EXPORT_SYMBOL(hpsb_make_phypacket); +EXPORT_SYMBOL(hpsb_packet_success); +EXPORT_SYMBOL(hpsb_make_packet); EXPORT_SYMBOL(hpsb_read); EXPORT_SYMBOL(hpsb_write); EXPORT_SYMBOL(hpsb_lock); @@ -67,7 +71,10 @@ EXPORT_SYMBOL(highlevel_write); EXPORT_SYMBOL(highlevel_lock); EXPORT_SYMBOL(highlevel_lock64); - +EXPORT_SYMBOL(highlevel_add_host); +EXPORT_SYMBOL(highlevel_remove_host); +EXPORT_SYMBOL(highlevel_host_reset); +EXPORT_SYMBOL(highlevel_add_one_host); EXPORT_SYMBOL(hpsb_guid_get_handle); -EXPORT_SYMBOL(hpsb_guid_localhost); +EXPORT_SYMBOL(hpsb_get_host_by_ge); EXPORT_SYMBOL(hpsb_guid_fill_packet); diff -u --recursive --new-file v2.4.6/linux/drivers/ieee1394/ieee1394_transactions.c linux/drivers/ieee1394/ieee1394_transactions.c --- v2.4.6/linux/drivers/ieee1394/ieee1394_transactions.c Sun Oct 1 19:53:07 2000 +++ linux/drivers/ieee1394/ieee1394_transactions.c Thu Jul 19 17:48:15 2001 @@ -131,9 +131,21 @@ packet->header_size = 4; packet->data_size = length; + packet->type = iso; packet->tcode = TCODE_ISO_DATA; } +void fill_phy_packet(struct hpsb_packet *packet, quadlet_t data) +{ + packet->header[0] = data; + packet->header[1] = ~data; + packet->header_size = 8; + packet->data_size = 0; + packet->expect_response = 0; + packet->type = raw; /* No CRC added */ + packet->speed_code = SPEED_100; /* Force speed to be 100Mbps */ +} + /** * get_tlabel - allocate a transaction label @@ -384,6 +396,20 @@ return p; } +struct hpsb_packet *hpsb_make_phypacket(struct hpsb_host *host, + quadlet_t data) +{ + struct hpsb_packet *p; + + p = alloc_hpsb_packet(0); + if (!p) return NULL; + + p->host = host; + fill_phy_packet(p, data); + + return p; +} + /* * FIXME - these functions should probably read from / write to user space to * avoid in kernel buffers for user space callers @@ -440,42 +466,53 @@ return retval; } - -int hpsb_write(struct hpsb_host *host, nodeid_t node, u64 addr, - quadlet_t *buffer, size_t length) +struct hpsb_packet *hpsb_make_packet (struct hpsb_host *host, nodeid_t node, + u64 addr, quadlet_t *buffer, size_t length) { struct hpsb_packet *packet; - int retval = 0; - if (length == 0) { - return -EINVAL; - } - - if (host->node_id == node) { - switch(highlevel_write(host, node, buffer, addr, length)) { - case RCODE_COMPLETE: - return 0; - case RCODE_TYPE_ERROR: - return -EACCES; - case RCODE_ADDRESS_ERROR: - default: - return -EINVAL; - } - } + if (length == 0) + return NULL; - if (length == 4) { + if (length == 4) packet = hpsb_make_writeqpacket(host, node, addr, *buffer); - } else { + else packet = hpsb_make_writebpacket(host, node, addr, length); - } - if (!packet) { - return -ENOMEM; - } + if (!packet) + return NULL; - if (length != 4) { + if (length != 4) memcpy(packet->data, buffer, length); - } + + return packet; +} + +int hpsb_write(struct hpsb_host *host, nodeid_t node, u64 addr, + quadlet_t *buffer, size_t length) +{ + struct hpsb_packet *packet; + int retval; + + if (length == 0) + return -EINVAL; + + if (host->node_id == node) { + switch(highlevel_write(host, node, node, buffer, addr, length)) { + case RCODE_COMPLETE: + return 0; + case RCODE_TYPE_ERROR: + return -EACCES; + case RCODE_ADDRESS_ERROR: + default: + return -EINVAL; + } + } + + packet = hpsb_make_packet (host, node, addr, buffer, length); + + if (!packet) + return -ENOMEM; hpsb_send_packet(packet); down(&packet->state_change); diff -u --recursive --new-file v2.4.6/linux/drivers/ieee1394/ieee1394_transactions.h linux/drivers/ieee1394/ieee1394_transactions.h --- v2.4.6/linux/drivers/ieee1394/ieee1394_transactions.h Mon Dec 11 13:20:17 2000 +++ linux/drivers/ieee1394/ieee1394_transactions.h Thu Jul 19 17:48:15 2001 @@ -22,6 +22,7 @@ int length); void fill_iso_packet(struct hpsb_packet *packet, int length, int channel, int tag, int sync); +void fill_phy_packet(struct hpsb_packet *packet, quadlet_t data); /* * Get and free transaction labels. @@ -41,6 +42,8 @@ size_t length); struct hpsb_packet *hpsb_make_lockpacket(struct hpsb_host *host, nodeid_t node, u64 addr, int extcode); +struct hpsb_packet *hpsb_make_phypacket(struct hpsb_host *host, + quadlet_t data) ; /* @@ -68,5 +71,10 @@ quadlet_t *buffer, size_t length); int hpsb_lock(struct hpsb_host *host, nodeid_t node, u64 addr, int extcode, quadlet_t *data, quadlet_t arg); + +/* Generic packet creation. Used by hpsb_write. Also useful for protocol + * drivers that want to implement their own hpsb_write replacement. */ +struct hpsb_packet *hpsb_make_packet (struct hpsb_host *host, nodeid_t node, + u64 addr, quadlet_t *buffer, size_t length); #endif /* _IEEE1394_TRANSACTIONS_H */ diff -u --recursive --new-file v2.4.6/linux/drivers/ieee1394/ieee1394_types.h linux/drivers/ieee1394/ieee1394_types.h --- v2.4.6/linux/drivers/ieee1394/ieee1394_types.h Sun Feb 4 21:34:18 2001 +++ linux/drivers/ieee1394/ieee1394_types.h Thu Jul 19 17:48:15 2001 @@ -9,22 +9,7 @@ #include <asm/byteorder.h> -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0) -#include "linux22compat.h" -#else -#define V22_COMPAT_MOD_INC_USE_COUNT do {} while (0) -#define V22_COMPAT_MOD_DEC_USE_COUNT do {} while (0) -#define OWNER_THIS_MODULE owner: THIS_MODULE, - -#define INIT_TQ_LINK(tq) INIT_LIST_HEAD(&(tq).list) -#define INIT_TQ_HEAD(tq) INIT_LIST_HEAD(&(tq)) -#endif - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,18) -#include <asm/spinlock.h> -#else #include <linux/spinlock.h> -#endif #ifndef MIN #define MIN(a,b) ((a) < (b) ? (a) : (b)) @@ -58,9 +43,10 @@ #ifdef __BIG_ENDIAN -static __inline__ void *memcpy_le32(u32 *dest, const u32 *src, size_t count) +static __inline__ void *memcpy_le32(u32 *dest, const u32 *__src, size_t count) { void *tmp = dest; + u32 *src = (u32 *)__src; count /= 4; diff -u --recursive --new-file v2.4.6/linux/drivers/ieee1394/nodemgr.c linux/drivers/ieee1394/nodemgr.c --- v2.4.6/linux/drivers/ieee1394/nodemgr.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/ieee1394/nodemgr.c Fri Jul 20 12:47:31 2001 @@ -0,0 +1,391 @@ +/* + * Node information (ConfigROM) collection and management. + * + * Copyright (C) 2000 Andreas E. Bombe + * 2001 Ben Collins <bcollins@debian.net> + * + * This code is licensed under the GPL. See the file COPYING in the root + * directory of the kernel sources for details. + */ + +#include <linux/kernel.h> +#include <linux/list.h> +#include <linux/slab.h> +#include <asm/byteorder.h> +#include <asm/atomic.h> +#include <linux/smp_lock.h> +#include <linux/interrupt.h> + +#include "ieee1394_types.h" +#include "ieee1394.h" +#include "hosts.h" +#include "ieee1394_transactions.h" +#include "highlevel.h" +#include "csr.h" + + +/* Basically what we do here is start off retrieving the bus_info block. + * From there will fill in some info about the node, verify it is of IEEE + * 1394 type, and the the crc checks out ok. After that we start off with + * the root directory, and subdirectories. To do this, we retrieve the + * quadlet header for a directory, find out the length, and retrieve the + * complete directory entry (be it a leaf or a directory). We then process + * it and add the info to our structure for that particular node. + * + * We verify CRC's along the way for each directory/block/leaf. The + * entire node structure is generic, and simply stores the information in + * a way that's easy to parse by the protocol interface. + * + * XXX: Most of this isn't done yet :) */ + + +static atomic_t outstanding_requests; + +static LIST_HEAD(node_list); +rwlock_t node_lock = RW_LOCK_UNLOCKED; + +static LIST_HEAD(host_info_list); +spinlock_t host_info_lock = SPIN_LOCK_UNLOCKED; + +struct host_info { + struct hpsb_host *host; + int pid; + wait_queue_head_t reset_wait; + struct list_head list; +}; + +struct node_entry { + struct list_head list; + atomic_t refcount; + + u64 guid; + + struct hpsb_host *host; + nodeid_t node_id; + + atomic_t generation; +}; + +static struct node_entry *create_node_entry(void) +{ + struct node_entry *ge; + unsigned long flags; + + ge = kmalloc(sizeof(struct node_entry), SLAB_ATOMIC); + if (!ge) return NULL; + + INIT_LIST_HEAD(&ge->list); + atomic_set(&ge->refcount, 0); + ge->guid = (u64) -1; + ge->host = NULL; + ge->node_id = 0; + atomic_set(&ge->generation, -1); + + write_lock_irqsave(&node_lock, flags); + list_add_tail(&ge->list, &node_list); + write_unlock_irqrestore(&node_lock, flags); + + return ge; +} + +static struct node_entry *find_entry(u64 guid) +{ + struct list_head *lh; + struct node_entry *ge; + + lh = node_list.next; + while (lh != &node_list) { + ge = list_entry(lh, struct node_entry, list); + if (ge->guid == guid) return ge; + lh = lh->next; + } + + return NULL; +} + +static void associate_guid(struct hpsb_host *host, nodeid_t nodeid, u64 guid) +{ + struct node_entry *ge; + unsigned long flags; + + HPSB_DEBUG("Node %d on %s host: GUID %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", + nodeid & NODE_MASK, host->template->name, ((u8 *)&guid)[0], + ((u8 *)&guid)[1], ((u8 *)&guid)[2], ((u8 *)&guid)[3], + ((u8 *)&guid)[4], ((u8 *)&guid)[5], ((u8 *)&guid)[6], + ((u8 *)&guid)[7]); + + read_lock_irqsave(&node_lock, flags); + ge = find_entry(guid); + read_unlock_irqrestore(&node_lock, flags); + + if (!ge) ge = create_node_entry(); + if (!ge) return; + + ge->host = host; + ge->node_id = nodeid; + ge->guid = guid; + + atomic_set(&ge->generation, get_hpsb_generation()); +} + +/* This is where we probe the nodes for their information and provided + * features. */ +static void nodemgr_node_probe(struct hpsb_host *host) +{ + struct selfid *sid = (struct selfid *)host->topology_map; + int nodecount = host->node_count; + nodeid_t nodeid = LOCAL_BUS; + quadlet_t buffer[5], quad; + octlet_t base = CSR_REGISTER_BASE + CSR_CONFIG_ROM; + int retval; + + /* We need to detect when the ConfigROM's generation has changed, + * so we only update the node's info when it needs to be. */ + for (; nodecount; nodecount--, nodeid++, sid++) { + int header_count = 0; + unsigned header_size = 0; + while (sid->extended) + sid++; + if (!sid->link_active) + continue; + if (nodeid == host->node_id) + continue; + + HPSB_DEBUG("Initiating ConfigROM request for node %d", nodeid & NODE_MASK); + + retval = hpsb_read(host, nodeid, base, &quad, 4); + buffer[header_count++] = be32_to_cpu(quad); + + if (retval) { + HPSB_ERR("ConfigROM quadlet transaction error for %d", + nodeid & NODE_MASK); + continue; + } + + header_size = buffer[0] >> 24; + + if (header_size < 4) { + HPSB_INFO("Node %d on %s host has non-standard ROM format (%d quads), " + "cannot parse", nodeid & NODE_MASK, host->template->name, + header_size); + continue; + } + + while (header_count <= header_size && (header_count<<2) < sizeof(buffer)) { + retval = hpsb_read(host, nodeid, base + (header_count<<2), &quad, 4); + buffer[header_count++] = be32_to_cpu(quad); + + if (retval) { + HPSB_ERR("ConfigROM quadlet transaction error for %d", + nodeid & NODE_MASK); + goto failed_read; + } + + } + + associate_guid(host, nodeid, be64_to_cpu(((u64)buffer[3] << 32) | buffer[4])); +failed_read: + continue; + } + + /* Need to detect when nodes are no longer associated with + * anything. I believe we can do this using the generation of the + * entries after a reset, compared the the hosts generation. */ +} + + +struct node_entry *hpsb_guid_get_handle(u64 guid) +{ + unsigned long flags; + struct node_entry *ge; + + read_lock_irqsave(&node_lock, flags); + ge = find_entry(guid); + if (ge) atomic_inc(&ge->refcount); + read_unlock_irqrestore(&node_lock, flags); + + return ge; +} + +struct hpsb_host *hpsb_get_host_by_ge(struct node_entry *ge) +{ + if (atomic_read(&ge->generation) != get_hpsb_generation()) return NULL; + if (ge->node_id == ge->host->node_id) return ge->host; + return NULL; +} + +int hpsb_guid_fill_packet(struct node_entry *ge, struct hpsb_packet *pkt) +{ + if (atomic_read(&ge->generation) != get_hpsb_generation()) return 0; + + pkt->host = ge->host; + pkt->node_id = ge->node_id; + pkt->generation = atomic_read(&ge->generation); + return 1; +} + +static int nodemgr_reset_handler(void *__hi) +{ + struct host_info *hi = (struct host_info *)__hi; + struct hpsb_host *host = hi->host; + + /* Standard thread setup */ + lock_kernel(); + daemonize(); + strcpy(current->comm, "NodeMngr"); + unlock_kernel(); + + for (;;) { + if (signal_pending(current)) + break; + + /* Let's take a short pause to make sure all the devices + * have time to settle. */ + + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(HZ/50); + + if (hi && host) + nodemgr_node_probe(host); + + /* Wait for the next bus reset */ + if (hi && host) + interruptible_sleep_on(&hi->reset_wait); + } + + return(0); +} + +static void nodemgr_add_host(struct hpsb_host *host) +{ + struct host_info *hi = kmalloc (sizeof (struct host_info), GFP_KERNEL); + int flags; + + if (!hi) { + HPSB_ERR ("Out of memory in Node Manager"); + return; + } + + hi->host = host; + INIT_LIST_HEAD(&hi->list); + hi->pid = -1; + init_waitqueue_head(&hi->reset_wait); + + spin_lock_irqsave (&host_info_lock, flags); + list_add_tail (&hi->list, &host_info_list); + spin_unlock_irqrestore (&host_info_lock, flags); + + return; +} + +static void nodemgr_schedule_thread (void *__hi) +{ + struct host_info *hi = (struct host_info *)__hi; + + hi->pid = kernel_thread(nodemgr_reset_handler, hi, + CLONE_FS|CLONE_FILES|CLONE_SIGHAND); +} + +static void nodemgr_host_reset(struct hpsb_host *host) +{ + struct list_head *lh; + struct host_info *hi = NULL; + int flags; + + spin_lock_irqsave (&host_info_lock, flags); + lh = host_info_list.next; + while (lh != &host_info_list) { + struct host_info *myhi = list_entry(lh, struct host_info, list); + if (myhi->host == host) { + hi = myhi; + break; + } + lh = lh->next; + } + + if (hi == NULL) { + HPSB_ERR ("Could not process reset of non-existent host in Node Manager"); + goto done_reset_host; + } + + if (hi->pid >= 0) { + wake_up(&hi->reset_wait); + } else { + if (in_interrupt()) { + static struct tq_struct task; + memset(&task, 0, sizeof(struct tq_struct)); + + task.routine = nodemgr_schedule_thread; + task.data = (void*)hi; + + if (schedule_task(&task) < 0) + HPSB_ERR ("Failed to schedule Node Manager thread!\n"); + } else { + nodemgr_schedule_thread(hi); + } + } + +done_reset_host: + spin_unlock_irqrestore (&host_info_lock, flags); + + return; +} + +static void nodemgr_remove_host(struct hpsb_host *host) +{ + struct list_head *lh; + struct host_info *hi = NULL; + int flags; + + spin_lock_irqsave (&host_info_lock, flags); + lh = host_info_list.next; + while (lh != &host_info_list) { + struct host_info *myhi = list_entry(lh, struct host_info, list); + if (myhi->host == host) { + hi = myhi; + break; + } + lh = lh->next; + } + + if (hi == NULL) { + HPSB_ERR ("Could not remove non-exitent host in Node Manager"); + goto done_remove_host; + } + + if (hi->pid >= 0) + kill_proc(hi->pid, SIGINT, 1); + + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(HZ*2); /* 2 second delay */ + + kfree (hi); + +done_remove_host: + spin_unlock_irqrestore (&host_info_lock, flags); + + return; +} + +static struct hpsb_highlevel_ops guid_ops = { + add_host: nodemgr_add_host, + host_reset: nodemgr_host_reset, + remove_host: nodemgr_remove_host, +}; + +static struct hpsb_highlevel *hl; + +void init_ieee1394_nodemgr(void) +{ + atomic_set(&outstanding_requests, 0); + + hl = hpsb_register_highlevel("Node manager", &guid_ops); + if (!hl) { + HPSB_ERR("Out of memory during ieee1394 initialization"); + } +} + +void cleanup_ieee1394_nodemgr(void) +{ + hpsb_unregister_highlevel(hl); +} diff -u --recursive --new-file v2.4.6/linux/drivers/ieee1394/nodemgr.h linux/drivers/ieee1394/nodemgr.h --- v2.4.6/linux/drivers/ieee1394/nodemgr.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/ieee1394/nodemgr.h Fri Jul 20 12:47:31 2001 @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2000 Andreas E. Bombe + * 2001 Ben Collins <bcollins@debian.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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 _IEEE1394_NODEMGR_H +#define _IEEE1394_NODEMGR_H + + +/* + * General information: Finding out which GUID belongs to which node is done by + * sending packets and therefore waiting for the answers. Wherever it is + * mentioned that a node is inaccessible this could just as well mean that we + * just don't know yet (usually, bus reset handlers can't rely on GUIDs being + * associated with current nodes). + */ + +struct node_entry; +typedef struct node_entry *hpsb_guid_t; + + +/* + * Returns a guid handle (which has its reference count incremented) or NULL if + * there is the GUID in question is not known of. Getting a valid handle does + * not mean that the node with this GUID is currently accessible (might not be + * plugged in or powered down). + */ +hpsb_guid_t hpsb_guid_get_handle(u64 guid); + +/* + * If the handle refers to a local host, this function will return the pointer + * to the hpsb_host structure. It will return NULL otherwise. Once you have + * established it is a local host, you can use that knowledge from then on (the + * GUID won't wander to an external node). + * + * Note that the local GUID currently isn't collected, so this will always + * return NULL. + */ +struct hpsb_host *hpsb_get_host_by_ge(hpsb_guid_t handle); + +/* + * This will fill in the given, pre-initialised hpsb_packet with the current + * information from the GUID handle (host, node ID, generation number). It will + * return false if the node owning the GUID is not accessible (and not modify the + * hpsb_packet) and return true otherwise. + * + * Note that packet sending may still fail in hpsb_send_packet if a bus reset + * happens while you are trying to set up the packet (due to obsolete generation + * number). It will at least reliably fail so that you don't accidentally and + * unknowingly send your packet to the wrong node. + */ +int hpsb_guid_fill_packet(hpsb_guid_t handle, struct hpsb_packet *pkt); + + +void init_ieee1394_nodemgr(void); +void cleanup_ieee1394_nodemgr(void); + +#endif /* _IEEE1394_NODEMGR_H */ diff -u --recursive --new-file v2.4.6/linux/drivers/ieee1394/ohci1394.c linux/drivers/ieee1394/ohci1394.c --- v2.4.6/linux/drivers/ieee1394/ohci1394.c Fri Mar 2 18:38:38 2001 +++ linux/drivers/ieee1394/ohci1394.c Fri Jul 20 12:47:31 2001 @@ -2,6 +2,7 @@ * ohci1394.c - driver for OHCI 1394 boards * Copyright (C)1999,2000 Sebastien Rougeaux <sebastien.rougeaux@anu.edu.au> * Gord Peters <GordPeters@smarttech.com> + * 2001 Ben Collins <bcollins@debian.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -26,16 +27,20 @@ * . Async Response Transmit * . Iso Receive * . DMA mmap for iso receive + * . Config ROM generation + * + * Things implemented, but still in test phase: + * . Iso Transmit * * Things not implemented: - * . Iso Transmit + * . Async Stream Packets * . DMA error recovery * * Things to be fixed: - * . Config ROM + * . Latency problems on UltraSPARC * * Known bugs: - * . Self-id are sometimes not received properly + * . SelfID are sometimes not received properly * if card is initialized with no other nodes * on the bus * . Apple PowerBook detected but not working yet @@ -46,26 +51,41 @@ * * Adam J Richter <adam@yggdrasil.com> * . Use of pci_class to find device + * * Andreas Tobler <toa@pop.agri.ch> * . Updated proc_fs calls + * * Emilie Chung <emilie.chung@axis.com> * . Tip on Async Request Filter + * * Pascal Drolet <pascal.drolet@informission.ca> * . Various tips for optimization and functionnalities + * * Robert Ficklin <rficklin@westengineering.com> * . Loop in irq_handler + * * James Goodwin <jamesg@Filanet.com> * . Various tips on initialization, self-id reception, etc. + * * Albrecht Dress <ad@mpifr-bonn.mpg.de> * . Apple PowerBook detection + * * Daniel Kobras <daniel.kobras@student.uni-tuebingen.de> * . Reset the board properly before leaving + misc cleanups + * * Leon van Stuivenberg <leonvs@iae.nl> * . Bug fixes + * + * Ben Collins <bcollins@debian.org> + * . Working big-endian support + * . Updated to 2.4.x module scheme (PCI aswell) + * . Removed procfs support since it trashes random mem + * . Config ROM generation */ #include <linux/config.h> #include <linux/kernel.h> +#include <linux/list.h> #include <linux/slab.h> #include <linux/interrupt.h> #include <linux/wait.h> @@ -78,9 +98,9 @@ #include <asm/atomic.h> #include <asm/io.h> #include <asm/uaccess.h> -#include <linux/proc_fs.h> #include <linux/tqueue.h> #include <linux/delay.h> +#include <linux/spinlock.h> #include <asm/pgtable.h> #include <asm/page.h> @@ -95,83 +115,10 @@ #include "ieee1394_types.h" #include "hosts.h" #include "ieee1394_core.h" +#include "highlevel.h" #include "ohci1394.h" -/* This structure is not properly initialized ... it is taken from - the lynx_csr_rom written by Andreas ... Some fields in the root - directory and the module dependent info needs to be modified - I do not have the proper doc */ -quadlet_t ohci_csr_rom[] = { - /* bus info block */ - 0x04040000, /* info/CRC length, CRC */ - 0x31333934, /* 1394 magic number */ - 0xf07da002, /* cyc_clk_acc = 125us, max_rec = 1024 */ - 0x00000000, /* vendor ID, chip ID high (written from card info) */ - 0x00000000, /* chip ID low (written from card info) */ - /* root directory - FIXME */ - 0x00090000, /* CRC length, CRC */ - 0x03080028, /* vendor ID (Texas Instr.) */ - 0x81000009, /* offset to textual ID */ - 0x0c000200, /* node capabilities */ - 0x8d00000e, /* offset to unique ID */ - 0xc7000010, /* offset to module independent info */ - 0x04000000, /* module hardware version */ - 0x81000026, /* offset to textual ID */ - 0x09000000, /* node hardware version */ - 0x81000026, /* offset to textual ID */ - /* module vendor ID textual */ - 0x00080000, /* CRC length, CRC */ - 0x00000000, - 0x00000000, - 0x54455841, /* "Texas Instruments" */ - 0x5320494e, - 0x53545255, - 0x4d454e54, - 0x53000000, - /* node unique ID leaf */ - 0x00020000, /* CRC length, CRC */ - 0x08002856, /* vendor ID, chip ID high */ - 0x0000083E, /* chip ID low */ - /* module dependent info - FIXME */ - 0x00060000, /* CRC length, CRC */ - 0xb8000006, /* ??? offset to module textual ID */ - 0x81000004, /* ??? textual descriptor */ - 0x00000000, /* SRAM size */ - 0x00000000, /* AUXRAM size */ - 0x00000000, /* AUX device */ - /* module textual ID */ - 0x00050000, /* CRC length, CRC */ - 0x00000000, - 0x00000000, - 0x54534231, /* "TSB12LV22" */ - 0x324c5632, - 0x32000000, - /* part number */ - 0x00060000, /* CRC length, CRC */ - 0x00000000, - 0x00000000, - 0x39383036, /* "9806000-0001" */ - 0x3030342d, - 0x30303431, - 0x20000001, - /* module hardware version textual */ - 0x00050000, /* CRC length, CRC */ - 0x00000000, - 0x00000000, - 0x5453424b, /* "TSBKOHCI403" */ - 0x4f484349, - 0x34303300, - /* node hardware version textual */ - 0x00050000, /* CRC length, CRC */ - 0x00000000, - 0x00000000, - 0x54534234, /* "TSB41LV03" */ - 0x314c5630, - 0x33000000 -}; - - #ifdef CONFIG_IEEE1394_VERBOSEDEBUG #define OHCI1394_DEBUG #endif @@ -187,6 +134,19 @@ #define DBGMSG(card, fmt, args...) #endif +#ifdef CONFIG_IEEE1394_OHCI_DMA_DEBUG +#define OHCI_DMA_ALLOC(fmt, args...) \ + HPSB_ERR("ohci1394("__FUNCTION__")alloc(%d): "fmt, \ + ++global_outstanding_dmas, ## args) +#define OHCI_DMA_FREE(fmt, args...) \ + HPSB_ERR("ohci1394("__FUNCTION__")free(%d): "fmt, \ + --global_outstanding_dmas, ## args) +u32 global_outstanding_dmas = 0; +#else +#define OHCI_DMA_ALLOC(fmt, args...) +#define OHCI_DMA_FREE(fmt, args...) +#endif + /* print general (card independent) information */ #define PRINT_G(level, fmt, args...) \ printk(level "ohci1394: " fmt "\n" , ## args) @@ -195,36 +155,16 @@ #define PRINT(level, card, fmt, args...) \ printk(level "ohci1394_%d: " fmt "\n" , card , ## args) -#define FAIL(fmt, args...) \ - PRINT_G(KERN_ERR, fmt , ## args); \ - num_of_cards--; \ - remove_card(ohci); \ - return 1; - -#if USE_DEVICE - -int supported_chips[][2] = { - { PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_OHCI1394_LV22 }, - { PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_OHCI1394_LV23 }, - { PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_OHCI1394_LV26 }, - { PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_OHCI1394_PCI4450 }, - { PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_OHCI1394 }, - { PCI_VENDOR_ID_SONY, PCI_DEVICE_ID_SONY_CXD3222 }, - { PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_UPD72862 }, - { PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_UPD72870 }, - { PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_UPD72871 }, - { PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_UNI_N_FW }, - { PCI_VENDOR_ID_AL, PCI_DEVICE_ID_ALI_OHCI1394_M5251 }, - { PCI_VENDOR_ID_LUCENT, PCI_DEVICE_ID_LUCENT_FW323 }, - { -1, -1 } -}; - -#else +#define FAIL(fmt, args...) \ +do { \ + PRINT_G(KERN_ERR, fmt , ## args); \ + remove_card(ohci); \ + return 1; \ +} while(0) #define PCI_CLASS_FIREWIRE_OHCI ((PCI_CLASS_SERIAL_FIREWIRE << 8) | 0x10) -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) -static struct pci_device_id ohci1394_pci_tbl[] __initdata = { +static struct pci_device_id ohci1394_pci_tbl[] __devinitdata = { { class: PCI_CLASS_FIREWIRE_OHCI, class_mask: 0x00ffffff, @@ -236,191 +176,181 @@ { 0, }, }; MODULE_DEVICE_TABLE(pci, ohci1394_pci_tbl); -#endif -#endif /* USE_DEVICE */ +static char version[] __devinitdata = + "v0.50 15/Jul/01 Ben Collins <bcollins@debian.org>"; +/* Module Parameters */ MODULE_PARM(attempt_root,"i"); +MODULE_PARM_DESC(attempt_root, "Attempt to make the host root."); static int attempt_root = 0; -static struct ti_ohci cards[MAX_OHCI1394_CARDS]; -static int num_of_cards = 0; +#ifdef __LITTLE_ENDIAN +/* Don't waste cycles on same sex byte swaps */ +#define packet_swab(w,x,y,z) +#define block_swab32(x,y) +#else +static void packet_swab(quadlet_t *data, char tcode, int len, int payload_swap); +static __inline__ void block_swab32(quadlet_t *data, size_t size); +#endif + +static unsigned int card_id_counter = 0; -static int add_card(struct pci_dev *dev); +static void dma_trm_tasklet(unsigned long data); static void remove_card(struct ti_ohci *ohci); -static int init_driver(void); -static void dma_trm_bh(void *data); -static void dma_rcv_bh(void *data); static void dma_trm_reset(struct dma_trm_ctx *d); /*********************************** * IEEE-1394 functionality section * ***********************************/ -#if 0 /* not needed at this time */ -static int get_phy_reg(struct ti_ohci *ohci, int addr) +static u8 get_phy_reg(struct ti_ohci *ohci, u8 addr) { - int timeout=10000; - static quadlet_t r; - - if ((addr < 1) || (addr > 15)) { - PRINT(KERN_ERR, ohci->id, __FUNCTION__ - ": PHY register address %d out of range", addr); - return -EFAULT; - } - - spin_lock(&ohci->phy_reg_lock); + int i, flags; + quadlet_t r; - /* initiate read request */ - reg_write(ohci, OHCI1394_PhyControl, - ((addr<<8)&0x00000f00) | 0x00008000); + spin_lock_irqsave (&ohci->phy_reg_lock, flags); - /* wait */ - while (!(reg_read(ohci, OHCI1394_PhyControl)&0x80000000) && timeout) - timeout--; + reg_write(ohci, OHCI1394_PhyControl, (((u16)addr << 8) & 0x00000f00) | 0x00008000); + for (i = 0; i < OHCI_LOOP_COUNT; i++) { + if (reg_read(ohci, OHCI1394_PhyControl) & 0x80000000) + break; - if (!timeout) { - PRINT(KERN_ERR, ohci->id, "get_phy_reg timeout !!!\n"); - spin_unlock(&ohci->phy_reg_lock); - return -EFAULT; + mdelay(1); } + r = reg_read(ohci, OHCI1394_PhyControl); + + if (i >= OHCI_LOOP_COUNT) + PRINT (KERN_ERR, ohci->id, "Get PHY Reg timeout [0x%08x/0x%08x/%d]\n", + r, r & 0x80000000, i); - spin_unlock(&ohci->phy_reg_lock); + spin_unlock_irqrestore (&ohci->phy_reg_lock, flags); - return (r&0x00ff0000)>>16; + return (r & 0x00ff0000) >> 16; } -static int set_phy_reg(struct ti_ohci *ohci, int addr, unsigned char data) { - int timeout=10000; +static void set_phy_reg(struct ti_ohci *ohci, u8 addr, u8 data) +{ + int i, flags; u32 r; - if ((addr < 1) || (addr > 15)) { - PRINT(KERN_ERR, ohci->id, __FUNCTION__ - ": PHY register address %d out of range", addr); - return -EFAULT; - } + spin_lock_irqsave (&ohci->phy_reg_lock, flags); + + reg_write(ohci, OHCI1394_PhyControl, 0x00004000 | (((u16)addr << 8) & 0x00000f00) | data); + + for (i = 0; i < OHCI_LOOP_COUNT; i++) { + r = reg_read(ohci, OHCI1394_PhyControl); + if (!(r & 0x00004000)) + break; - r = ((addr<<8)&0x00000f00) | 0x00004000 | ((u32)data & 0x000000ff); + mdelay(1); + } - spin_lock(&ohci->phy_reg_lock); + if (i == OHCI_LOOP_COUNT) + PRINT (KERN_ERR, ohci->id, "Set PHY Reg timeout [0x%08x/0x%08x/%d]\n", + r, r & 0x00004000, i); - reg_write(ohci, OHCI1394_PhyControl, r); + spin_unlock_irqrestore (&ohci->phy_reg_lock, flags); - /* wait */ - while (!(reg_read(ohci, OHCI1394_PhyControl)&0x80000000) && timeout) - timeout--; + return; +} - spin_unlock(&ohci->phy_reg_lock); +/* Or's our value into the current value */ +static void set_phy_reg_mask(struct ti_ohci *ohci, u8 addr, u8 data) +{ + u8 old; - if (!timeout) { - PRINT(KERN_ERR, ohci->id, "set_phy_reg timeout !!!\n"); - return -EFAULT; - } + old = get_phy_reg (ohci, addr); + old |= data; + set_phy_reg (ohci, addr, old); - return 0; + return; } -#endif /* unneeded functions */ -inline static int handle_selfid(struct ti_ohci *ohci, struct hpsb_host *host, +static int handle_selfid(struct ti_ohci *ohci, struct hpsb_host *host, int phyid, int isroot) { quadlet_t *q = ohci->selfid_buf_cpu; quadlet_t self_id_count=reg_read(ohci, OHCI1394_SelfIDCount); size_t size; - quadlet_t lsid; + quadlet_t q0, q1; - /* Self-id handling seems much easier than for the aic5800 chip. - All the self-id packets, including this device own self-id, + /* SelfID handling seems much easier than for the aic5800 chip. + All the self-id packets, including this devices own self-id, should be correctly arranged in the selfid buffer at this stage */ /* Check status of self-id reception */ - if ((self_id_count&0x80000000) || - ((self_id_count&0x00FF0000) != (q[0]&0x00FF0000))) { + + if (ohci->selfid_swap) + q0 = le32_to_cpu(q[0]); + else + q0 = q[0]; + + if ((self_id_count & 0x80000000) || + ((self_id_count & 0x00FF0000) != (q0 & 0x00FF0000))) { PRINT(KERN_ERR, ohci->id, - "Error in reception of self-id packets" - "Self-id count: %08x q[0]: %08x", - self_id_count, q[0]); - - /* - * Tip by James Goodwin <jamesg@Filanet.com>: - * We had an error, generate another bus reset in response. - * TODO. Actually read the current value in the phy before - * generating a bus reset (read modify write). This way - * we don't stomp any current gap count settings, etc. - */ + "Error in reception of SelfID packets [0x%08x/0x%08x]", + self_id_count, q0); + + /* Tip by James Goodwin <jamesg@Filanet.com>: + * We had an error, generate another bus reset in response. */ if (ohci->self_id_errors<OHCI1394_MAX_SELF_ID_ERRORS) { - reg_write(ohci, OHCI1394_PhyControl, 0x000041ff); + set_phy_reg_mask (ohci, 1, 0x40); ohci->self_id_errors++; - } - else { + } else { PRINT(KERN_ERR, ohci->id, - "Timeout on self-id error reception"); + "Too many errors on SelfID error reception, giving up!"); } return -1; } - size = ((self_id_count&0x00001FFC)>>2) - 1; + size = ((self_id_count & 0x00001FFC) >> 2) - 1; q++; while (size > 0) { - if (q[0] == ~q[1]) { - PRINT(KERN_INFO, ohci->id, "selfid packet 0x%x rcvd", - q[0]); - hpsb_selfid_received(host, cpu_to_be32(q[0])); - if (((q[0]&0x3f000000)>>24)==phyid) { - lsid=q[0]; - PRINT(KERN_INFO, ohci->id, - "This node self-id is 0x%08x", lsid); - } + if (ohci->selfid_swap) { + q0 = le32_to_cpu(q[0]); + q1 = le32_to_cpu(q[1]); + } else { + q0 = q[0]; + q1 = q[1]; + } + + if (q0 == ~q1) { + PRINT(KERN_DEBUG, ohci->id, "SelfID packet 0x%x received", q0); + hpsb_selfid_received(host, cpu_to_be32(q0)); + if (((q0 & 0x3f000000) >> 24) == phyid) + DBGMSG (ohci->id, "SelfID for this node is 0x%08x", q0); } else { PRINT(KERN_ERR, ohci->id, - "inconsistent selfid 0x%x/0x%x", q[0], q[1]); + "SelfID is inconsistent [0x%08x/0x%08x]", q0, q1); } q += 2; size -= 2; } - PRINT(KERN_INFO, ohci->id, "calling self-id complete"); + PRINT(KERN_DEBUG, ohci->id, "SelfID complete"); hpsb_selfid_complete(host, phyid, isroot); return 0; } -static int ohci_detect(struct hpsb_host_template *tmpl) -{ - struct hpsb_host *host; - int i; - - init_driver(); - - for (i = 0; i < num_of_cards; i++) { - host = hpsb_get_host(tmpl, 0); - if (host == NULL) { - /* simply don't init more after out of mem */ - return i; - } - host->hostdata = &cards[i]; - cards[i].host = host; - } - - return num_of_cards; -} - static int ohci_soft_reset(struct ti_ohci *ohci) { - int timeout=10000; + int i; reg_write(ohci, OHCI1394_HCControlSet, 0x00010000); - while ((reg_read(ohci, OHCI1394_HCControlSet)&0x00010000) && timeout) - timeout--; - if (!timeout) { - PRINT(KERN_ERR, ohci->id, "soft reset timeout !!!"); - return -EFAULT; + for (i = 0; i < OHCI_LOOP_COUNT; i++) { + if (reg_read(ohci, OHCI1394_HCControlSet) & 0x00010000) + break; + mdelay(10); } - else PRINT(KERN_INFO, ohci->id, "soft reset finished"); + + PRINT(KERN_DEBUG, ohci->id, "Soft reset finished"); + return 0; } @@ -432,7 +362,7 @@ nodeId = reg_read(ohci, OHCI1394_NodeID); if (!(nodeId&0x80000000)) { PRINT(KERN_ERR, ohci->id, - "Running dma failed because Node ID not valid"); + "Running dma failed because Node ID is not valid"); return -1; } @@ -446,7 +376,7 @@ /* Run the dma context */ reg_write(ohci, reg, 0x8000); - if (msg) PRINT(KERN_INFO, ohci->id, "%s", msg); + if (msg) PRINT(KERN_DEBUG, ohci->id, "%s", msg); return 0; } @@ -461,19 +391,20 @@ for (i=0; i<d->num_desc; i++) { - /* end of descriptor list? */ + d->prg_cpu[i]->control = + cpu_to_le32((0x280C << 16) | d->buf_size); + + /* End of descriptor list? */ if ((i+1) < d->num_desc) { - d->prg_cpu[i]->control = (0x283C << 16) | d->buf_size; d->prg_cpu[i]->branchAddress = - (d->prg_bus[i+1] & 0xfffffff0) | 0x1; + cpu_to_le32((d->prg_bus[i+1] & 0xfffffff0) | 0x1); } else { - d->prg_cpu[i]->control = (0x283C << 16) | d->buf_size; d->prg_cpu[i]->branchAddress = - d->prg_bus[0] & 0xfffffff0; + cpu_to_le32((d->prg_bus[0] & 0xfffffff0)); } - d->prg_cpu[i]->address = d->buf_bus[i]; - d->prg_cpu[i]->status = d->buf_size; + d->prg_cpu[i]->address = cpu_to_le32(d->buf_bus[i]); + d->prg_cpu[i]->status = cpu_to_le32(d->buf_size); } d->buf_ind = 0; @@ -485,7 +416,7 @@ /* Run AR context */ reg_write(ohci, d->ctrlSet, 0x00008000); - PRINT(KERN_INFO, ohci->id, "Receive DMA ctx=%d initialized", d->ctx); + DBGMSG(ohci->id, "Receive DMA ctx=%d initialized", d->ctx); } /* Initialize the dma transmit context */ @@ -505,7 +436,7 @@ d->pending_first = NULL; d->pending_last = NULL; - PRINT(KERN_INFO, ohci->id, "AT dma ctx=%d initialized", d->ctx); + DBGMSG(ohci->id, "Transmit dma ctx=%d initialized", d->ctx); } /* Count the number of available iso contexts */ @@ -534,6 +465,7 @@ int retval, i; spin_lock_init(&ohci->phy_reg_lock); + spin_lock_init(&ohci->event_lock); /* * Tip by James Goodwin <jamesg@Filanet.com>: @@ -543,13 +475,14 @@ */ /* Soft reset */ - if ((retval=ohci_soft_reset(ohci))<0) return retval; + if ((retval = ohci_soft_reset(ohci)) < 0) + return retval; /* * Delay after soft reset to make sure everything has settled * down (sanity) */ - mdelay(100); + mdelay(10); /* Set Link Power Status (LPS) */ reg_write(ohci, OHCI1394_HCControlSet, 0x00080000); @@ -558,7 +491,7 @@ * Delay after setting LPS in order to make sure link/phy * communication is established */ - mdelay(100); + mdelay(10); /* Set the bus number */ reg_write(ohci, OHCI1394_NodeID, 0x0000ffc0); @@ -585,26 +518,10 @@ /* Set the configuration ROM mapping register */ reg_write(ohci, OHCI1394_ConfigROMmap, ohci->csr_config_rom_bus); - /* Set bus options */ - reg_write(ohci, OHCI1394_BusOptions, - cpu_to_be32(ohci->csr_config_rom_cpu[2])); - -#if 0 - /* Write the GUID into the csr config rom */ - ohci->csr_config_rom_cpu[3] = - be32_to_cpu(reg_read(ohci, OHCI1394_GUIDHi)); - ohci->csr_config_rom_cpu[4] = - be32_to_cpu(reg_read(ohci, OHCI1394_GUIDLo)); -#endif - - /* Write the config ROM header */ - reg_write(ohci, OHCI1394_ConfigROMhdr, - cpu_to_be32(ohci->csr_config_rom_cpu[0])); - ohci->max_packet_size = 1<<(((reg_read(ohci, OHCI1394_BusOptions)>>12)&0xf)+1); - PRINT(KERN_INFO, ohci->id, "max packet size = %d bytes", - ohci->max_packet_size); + PRINT(KERN_DEBUG, ohci->id, "Max packet size = %d bytes", + ohci->max_packet_size); /* Don't accept phy packets into AR request context */ reg_write(ohci, OHCI1394_LinkControlClear, 0x00000400); @@ -612,8 +529,8 @@ /* Initialize IR dma */ ohci->nb_iso_rcv_ctx = get_nb_iso_ctx(ohci, OHCI1394_IsoRecvIntMaskSet); - PRINT(KERN_INFO, ohci->id, "%d iso receive contexts available", - ohci->nb_iso_rcv_ctx); + DBGMSG(ohci->id, "%d iso receive contexts available", + ohci->nb_iso_rcv_ctx); for (i=0;i<ohci->nb_iso_rcv_ctx;i++) { reg_write(ohci, OHCI1394_IsoRcvContextControlClear+32*i, 0xffffffff); @@ -634,8 +551,8 @@ /* Initialize IT dma */ ohci->nb_iso_xmit_ctx = get_nb_iso_ctx(ohci, OHCI1394_IsoXmitIntMaskSet); - PRINT(KERN_INFO, ohci->id, "%d iso transmit contexts available", - ohci->nb_iso_xmit_ctx); + DBGMSG(ohci->id, "%d iso transmit contexts available", + ohci->nb_iso_xmit_ctx); for (i=0;i<ohci->nb_iso_xmit_ctx;i++) { reg_write(ohci, OHCI1394_IsoXmitContextControlClear+32*i, 0xffffffff); @@ -661,10 +578,16 @@ /* Initialize IR dma */ initialize_dma_rcv_ctx(ohci->ir_context); + /* Initialize IT dma */ + initialize_dma_trm_ctx(ohci->it_context); + /* Set up isoRecvIntMask to generate interrupts for context 0 (thanks to Michael Greger for seeing that I forgot this) */ reg_write(ohci, OHCI1394_IsoRecvIntMaskSet, 0x00000001); + /* Set up isoXmitIntMask to generate interrupts for context 0 */ + reg_write(ohci, OHCI1394_IsoXmitIntMaskSet, 0x00000001); + /* * Accept AT requests from all nodes. This probably * will have to be controlled from the subsystem @@ -678,11 +601,8 @@ (OHCI1394_MAX_AT_RESP_RETRIES<<4) | (OHCI1394_MAX_PHYS_RESP_RETRIES<<8)); -#ifndef __BIG_ENDIAN + /* We don't want hardware swapping */ reg_write(ohci, OHCI1394_HCControlClear, 0x40000000); -#else - reg_write(ohci, OHCI1394_HCControlSet, 0x40000000); -#endif /* Enable interrupts */ reg_write(ohci, OHCI1394_IntMaskSet, @@ -692,12 +612,11 @@ OHCI1394_selfIDComplete | OHCI1394_RSPkt | OHCI1394_RQPkt | - OHCI1394_ARRS | - OHCI1394_ARRQ | OHCI1394_respTxComplete | OHCI1394_reqTxComplete | OHCI1394_isochRx | - OHCI1394_isochTx + OHCI1394_isochTx | + OHCI1394_unrecoverableError ); /* Enable link */ @@ -709,7 +628,7 @@ static void ohci_remove(struct hpsb_host *host) { struct ti_ohci *ohci; - + if (host != NULL) { ohci = host->hostdata; remove_card(ohci); @@ -729,6 +648,9 @@ u32 cycleTimer; int idx = d->prg_ind; + DBGMSG(ohci->id, "Inserting packet for node %d, tlabel=%d, tcode=0x%x, speed=%d\n", + packet->node_id, packet->tlabel, packet->tcode, packet->speed_code); + d->prg_cpu[idx]->begin.address = 0; d->prg_cpu[idx]->begin.branchAddress = 0; if (d->ctx==1) { @@ -737,75 +659,132 @@ * the 16 lower bits of the status... let's try 1 sec timeout */ cycleTimer = reg_read(ohci, OHCI1394_IsochronousCycleTimer); - d->prg_cpu[idx]->begin.status = + d->prg_cpu[idx]->begin.status = cpu_to_le32( (((((cycleTimer>>25)&0x7)+1)&0x7)<<13) | - ((cycleTimer&0x01fff000)>>12); + ((cycleTimer&0x01fff000)>>12)); DBGMSG(ohci->id, "cycleTimer: %08x timeStamp: %08x", cycleTimer, d->prg_cpu[idx]->begin.status); - } - else + } else d->prg_cpu[idx]->begin.status = 0; - if (packet->type == raw) { - d->prg_cpu[idx]->data[0] = OHCI1394_TCODE_PHY<<4; - d->prg_cpu[idx]->data[1] = packet->header[0]; - d->prg_cpu[idx]->data[2] = packet->header[1]; - } - else { - d->prg_cpu[idx]->data[0] = packet->speed_code<<16 | - (packet->header[0] & 0xFFFF); - d->prg_cpu[idx]->data[1] = (packet->header[1] & 0xFFFF) | - (packet->header[0] & 0xFFFF0000); - d->prg_cpu[idx]->data[2] = packet->header[2]; - d->prg_cpu[idx]->data[3] = packet->header[3]; - } + if ( (packet->type == async) || (packet->type == raw) ) { - if (packet->data_size) { /* block transmit */ - d->prg_cpu[idx]->begin.control = OUTPUT_MORE_IMMEDIATE | 0x10; - d->prg_cpu[idx]->end.control = OUTPUT_LAST | packet->data_size; - /* - * FIXME: check that the packet data buffer - * do not cross a page boundary - */ - if (cross_bound((unsigned long)packet->data, - packet->data_size)>0) { - /* FIXME: do something about it */ - PRINT(KERN_ERR, ohci->id, __FUNCTION__ - ": packet data addr: %p size %d bytes " - "cross page boundary", - packet->data, packet->data_size); - } - - d->prg_cpu[idx]->end.address = - pci_map_single(ohci->dev, packet->data, - packet->data_size, PCI_DMA_TODEVICE); - d->prg_cpu[idx]->end.branchAddress = 0; - d->prg_cpu[idx]->end.status = 0; - if (d->branchAddrPtr) - *(d->branchAddrPtr) = d->prg_bus[idx] | 0x3; - d->branchAddrPtr = &(d->prg_cpu[idx]->end.branchAddress); - } - else { /* quadlet transmit */ - if (packet->type == raw) - d->prg_cpu[idx]->begin.control = - OUTPUT_LAST_IMMEDIATE|(packet->header_size+4); - else + if (packet->type == raw) { + d->prg_cpu[idx]->data[0] = cpu_to_le32(OHCI1394_TCODE_PHY<<4); + d->prg_cpu[idx]->data[1] = packet->header[0]; + d->prg_cpu[idx]->data[2] = packet->header[1]; + } else { + d->prg_cpu[idx]->data[0] = packet->speed_code<<16 | + (packet->header[0] & 0xFFFF); + d->prg_cpu[idx]->data[1] = + (packet->header[1] & 0xFFFF) | + (packet->header[0] & 0xFFFF0000); + d->prg_cpu[idx]->data[2] = packet->header[2]; + d->prg_cpu[idx]->data[3] = packet->header[3]; + packet_swab(d->prg_cpu[idx]->data, packet->tcode, + packet->header_size>>2, ohci->payload_swap); + } + + if (packet->data_size) { /* block transmit */ d->prg_cpu[idx]->begin.control = - OUTPUT_LAST_IMMEDIATE|packet->header_size; + cpu_to_le32(OUTPUT_MORE_IMMEDIATE | 0x10); + d->prg_cpu[idx]->end.control = + cpu_to_le32(OUTPUT_LAST | packet->data_size); + /* + * Check that the packet data buffer + * does not cross a page boundary. + */ + if (cross_bound((unsigned long)packet->data, + packet->data_size)>0) { + /* FIXME: do something about it */ + PRINT(KERN_ERR, ohci->id, __FUNCTION__ + ": packet data addr: %p size %Zd bytes " + "cross page boundary", + packet->data, packet->data_size); + } + + d->prg_cpu[idx]->end.address = cpu_to_le32( + pci_map_single(ohci->dev, packet->data, + packet->data_size, + PCI_DMA_TODEVICE)); + OHCI_DMA_ALLOC("single, block transmit packet"); + + if (ohci->payload_swap) + block_swab32(packet->data, packet->data_size >> 2); + + d->prg_cpu[idx]->end.branchAddress = 0; + d->prg_cpu[idx]->end.status = 0; + if (d->branchAddrPtr) + *(d->branchAddrPtr) = + cpu_to_le32(d->prg_bus[idx] | 0x3); + d->branchAddrPtr = + &(d->prg_cpu[idx]->end.branchAddress); + } else { /* quadlet transmit */ + if (packet->type == raw) + d->prg_cpu[idx]->begin.control = cpu_to_le32( + OUTPUT_LAST_IMMEDIATE | + (packet->header_size+4)); + else + d->prg_cpu[idx]->begin.control = cpu_to_le32( + OUTPUT_LAST_IMMEDIATE | + packet->header_size); + + if (d->branchAddrPtr) + *(d->branchAddrPtr) = + cpu_to_le32(d->prg_bus[idx] | 0x2); + d->branchAddrPtr = + &(d->prg_cpu[idx]->begin.branchAddress); + } - if (d->branchAddrPtr) - *(d->branchAddrPtr) = d->prg_bus[idx] | 0x2; - d->branchAddrPtr = &(d->prg_cpu[idx]->begin.branchAddress); - } + } else { /* iso packet */ + d->prg_cpu[idx]->data[0] = packet->speed_code<<16 | + (packet->header[0] & 0xFFFF); + d->prg_cpu[idx]->data[1] = packet->header[0] & 0xFFFF0000; + packet_swab(d->prg_cpu[idx]->data, packet->tcode, packet->header_size>>2, + ohci->payload_swap); + + d->prg_cpu[idx]->begin.control = cpu_to_le32(OUTPUT_MORE_IMMEDIATE | 0x8); + d->prg_cpu[idx]->end.control = cpu_to_le32( + OUTPUT_LAST | 0x08000000 | packet->data_size); + d->prg_cpu[idx]->end.address = cpu_to_le32( + pci_map_single(ohci->dev, packet->data, + packet->data_size, PCI_DMA_TODEVICE)); + OHCI_DMA_ALLOC("single, iso transmit packet"); + + if (ohci->payload_swap) + block_swab32(packet->data, packet->data_size>>2); + + d->prg_cpu[idx]->end.branchAddress = 0; + d->prg_cpu[idx]->end.status = 0; + DBGMSG(ohci->id, "iso xmit context info: header[%08x %08x]\n" + " begin=%08x %08x %08x %08x\n" + " %08x %08x %08x %08x\n" + " end =%08x %08x %08x %08x", + d->prg_cpu[idx]->data[0], d->prg_cpu[idx]->data[1], + d->prg_cpu[idx]->begin.control, + d->prg_cpu[idx]->begin.address, + d->prg_cpu[idx]->begin.branchAddress, + d->prg_cpu[idx]->begin.status, + d->prg_cpu[idx]->data[0], + d->prg_cpu[idx]->data[1], + d->prg_cpu[idx]->data[2], + d->prg_cpu[idx]->data[3], + d->prg_cpu[idx]->end.control, + d->prg_cpu[idx]->end.address, + d->prg_cpu[idx]->end.branchAddress, + d->prg_cpu[idx]->end.status); + if (d->branchAddrPtr) + *(d->branchAddrPtr) = cpu_to_le32(d->prg_bus[idx] | 0x3); + d->branchAddrPtr = &(d->prg_cpu[idx]->end.branchAddress); + } d->free_prgs--; /* queue the packet in the appropriate context queue */ if (d->fifo_last) { d->fifo_last->xnext = packet; d->fifo_last = packet; - } - else { + } else { d->fifo_first = packet; d->fifo_last = packet; } @@ -814,7 +793,8 @@ /* * This function fills the AT FIFO with the (eventual) pending packets - * and runs or wake up the AT DMA prg if necessary. + * and runs or wakes up the AT DMA prg if necessary. + * * The function MUST be called with the d->lock held. */ static int dma_trm_flush(struct ti_ohci *ohci, struct dma_trm_ctx *d) @@ -836,27 +816,26 @@ d->pending_last = NULL; else PRINT(KERN_INFO, ohci->id, - "AT DMA FIFO ctx=%d full... waiting",d->ctx); + "Transmit DMA FIFO ctx=%d is full... waiting",d->ctx); /* Is the context running ? (should be unless it is the first packet to be sent in this context) */ if (!(reg_read(ohci, d->ctrlSet) & 0x8000)) { - DBGMSG(ohci->id,"Starting AT DMA ctx=%d",d->ctx); + DBGMSG(ohci->id,"Starting transmit DMA ctx=%d",d->ctx); reg_write(ohci, d->cmdPtr, d->prg_bus[idx]|z); run_context(ohci, d->ctrlSet, NULL); } else { - DBGMSG(ohci->id,"Waking AT DMA ctx=%d",d->ctx); - /* wake up the dma context if necessary */ - if (!(reg_read(ohci, d->ctrlSet) & 0x400)) + /* Wake up the dma context if necessary */ + if (!(reg_read(ohci, d->ctrlSet) & 0x400)) { + DBGMSG(ohci->id,"Waking transmit DMA ctx=%d",d->ctx); reg_write(ohci, d->ctrlSet, 0x1000); + } } return 1; } -/* - * Transmission of an async packet - */ +/* Transmission of an async packet */ static int ohci_transmit(struct hpsb_host *host, struct hpsb_packet *packet) { struct ti_ohci *ohci = host->hostdata; @@ -866,20 +845,21 @@ if (packet->data_size > ohci->max_packet_size) { PRINT(KERN_ERR, ohci->id, - "transmit packet size = %d too big", + "Transmit packet size %Zd is too big", packet->data_size); return 0; } packet->xnext = NULL; - /* Decide wether we have a request or a response packet */ + /* Decide wether we have an iso, a request, or a response packet */ tcode = (packet->header[0]>>4)&0xf; - if (tcode & 0x02) d = ohci->at_resp_context; + if (tcode == TCODE_ISO_DATA) d = ohci->it_context; + else if (tcode & 0x02) d = ohci->at_resp_context; else d = ohci->at_req_context; spin_lock_irqsave(&d->lock,flags); - /* queue the packet for later insertion into to dma fifo */ + /* queue the packet for later insertion into the dma fifo */ if (d->pending_last) { d->pending_last->xnext = packet; d->pending_last = packet; @@ -904,15 +884,11 @@ switch (cmd) { case RESET_BUS: - /* - * FIXME: this flag might be necessary in some case - */ - PRINT(KERN_INFO, ohci->id, "resetting bus on request%s", - ((host->attempt_root || attempt_root) ? + PRINT (KERN_DEBUG, ohci->id, "Resetting bus on request%s", + ((host->attempt_root || attempt_root) ? " and attempting to become root" : "")); - reg_write(ohci, OHCI1394_PhyControl, - (host->attempt_root || attempt_root) ? - 0x000041ff : 0x0000417f); + set_phy_reg_mask (ohci, 1, 0x40 | ((host->attempt_root || attempt_root) ? + 0x80 : 0)); break; case GET_CYCLE_COUNTER: @@ -965,7 +941,7 @@ if (arg<0 || arg>63) { PRINT(KERN_ERR, ohci->id, __FUNCTION__ - "IS0_LISTEN_CHANNEL channel %d out of range", + "IS0 listne channel %d is out of range", arg); return -EFAULT; } @@ -976,7 +952,7 @@ if (ohci->ISO_channel_usage & mask) { PRINT(KERN_ERR, ohci->id, __FUNCTION__ - "IS0_LISTEN_CHANNEL channel %d already used", + "IS0 listen channel %d is already used", arg); spin_unlock_irqrestore(&ohci->IR_channel_lock, flags); return -EFAULT; @@ -992,7 +968,7 @@ 1<<arg); spin_unlock_irqrestore(&ohci->IR_channel_lock, flags); - DBGMSG(ohci->id, "listening enabled on channel %d", arg); + DBGMSG(ohci->id, "Listening enabled on channel %d", arg); break; } case ISO_UNLISTEN_CHANNEL: @@ -1001,7 +977,7 @@ if (arg<0 || arg>63) { PRINT(KERN_ERR, ohci->id, __FUNCTION__ - "IS0_UNLISTEN_CHANNEL channel %d out of range", + "IS0 unlisten channel %d is out of range", arg); return -EFAULT; } @@ -1012,7 +988,7 @@ if (!(ohci->ISO_channel_usage & mask)) { PRINT(KERN_ERR, ohci->id, __FUNCTION__ - "IS0_UNLISTEN_CHANNEL channel %d not used", + "IS0 unlisten channel %d is not used", arg); spin_unlock_irqrestore(&ohci->IR_channel_lock, flags); return -EFAULT; @@ -1028,7 +1004,7 @@ 1<<arg); spin_unlock_irqrestore(&ohci->IR_channel_lock, flags); - DBGMSG(ohci->id, "listening disabled on channel %d", arg); + DBGMSG(ohci->id, "Listening disabled on channel %d", arg); break; } default: @@ -1063,7 +1039,7 @@ spin_lock_irqsave(&d->lock,flags); - /* is there still any packet pending in the fifo ? */ + /* Is there still any packet pending in the fifo ? */ while(d->fifo_first) { PRINT(KERN_INFO, ohci->id, "AT dma reset ctx=%d, aborting transmission", @@ -1095,203 +1071,198 @@ static void ohci_irq_handler(int irq, void *dev_id, struct pt_regs *regs_are_unused) { - quadlet_t event,node_id; + quadlet_t event, node_id; struct ti_ohci *ohci = (struct ti_ohci *)dev_id; struct hpsb_host *host = ohci->host; - int phyid = -1, isroot = 0; - int timeout = 255; + int phyid = -1, isroot = 0, flags; - do { - /* read the interrupt event register */ - event=reg_read(ohci, OHCI1394_IntEventClear); - - if (!event) return; - - DBGMSG(ohci->id, "IntEvent: %08x",event); - - /* clear the interrupt event register */ - reg_write(ohci, OHCI1394_IntEventClear, event); - - if (event & OHCI1394_busReset) { - if (!host->in_bus_reset) { - PRINT(KERN_INFO, ohci->id, "Bus reset"); - - /* Wait for the AT fifo to be flushed */ - dma_trm_reset(ohci->at_req_context); - dma_trm_reset(ohci->at_resp_context); - - /* Subsystem call */ - hpsb_bus_reset(ohci->host); - - ohci->NumBusResets++; - } + /* Read the interrupt event register */ + spin_lock_irqsave(&ohci->event_lock, flags); + event = reg_read(ohci, OHCI1394_IntEventClear); + reg_write(ohci, OHCI1394_IntEventClear, event); + spin_unlock_irqrestore(&ohci->event_lock, flags); + + if (!event) return; + + DBGMSG(ohci->id, "IntEvent: %08x", event); + + /* Die right here an now */ + if (event & OHCI1394_unrecoverableError) { + PRINT(KERN_ERR, ohci->id, "Unrecoverable error, shutting down card!"); + remove_card(ohci); + return; + } + + /* Someone wants a bus reset. Better watch what you wish for... + * + * XXX: Read 6.1.1 of the OHCI1394 spec. We need to take special + * care with the BusReset Interrupt, before and until the SelfID + * phase is over. This is why the SelfID phase sometimes fails for + * this driver. */ + if (event & OHCI1394_busReset) { + if (!host->in_bus_reset) { + PRINT(KERN_DEBUG, ohci->id, "Bus reset requested"); + + /* Wait for the AT fifo to be flushed */ + dma_trm_reset(ohci->at_req_context); + dma_trm_reset(ohci->at_resp_context); + + /* Subsystem call */ + hpsb_bus_reset(ohci->host); + + ohci->NumBusResets++; } - /* - * Problem: How can I ensure that the AT bottom half will be - * executed before the AR bottom half (both events may have - * occurred within a single irq event) - * Quick hack: just launch it within the IRQ handler - */ - if (event & OHCI1394_reqTxComplete) { - struct dma_trm_ctx *d = ohci->at_req_context; - DBGMSG(ohci->id, "Got reqTxComplete interrupt " - "status=0x%08X", reg_read(ohci, d->ctrlSet)); + event &= ~OHCI1394_busReset; + } + + /* XXX: We need a way to also queue the OHCI1394_reqTxComplete, + * but for right now we simply run it upon reception, to make sure + * we get sent acks before response packets. This sucks mainly + * because it halts the interrupt handler. */ + if (event & OHCI1394_reqTxComplete) { + struct dma_trm_ctx *d = ohci->at_req_context; + DBGMSG(ohci->id, "Got reqTxComplete interrupt " + "status=0x%08X", reg_read(ohci, d->ctrlSet)); + if (reg_read(ohci, d->ctrlSet) & 0x800) + ohci1394_stop_context(ohci, d->ctrlClear, + "reqTxComplete"); + else + dma_trm_tasklet ((unsigned long)d); + event &= ~OHCI1394_reqTxComplete; + } + if (event & OHCI1394_respTxComplete) { + struct dma_trm_ctx *d = ohci->at_resp_context; + DBGMSG(ohci->id, "Got respTxComplete interrupt " + "status=0x%08X", reg_read(ohci, d->ctrlSet)); + if (reg_read(ohci, d->ctrlSet) & 0x800) + ohci1394_stop_context(ohci, d->ctrlClear, + "respTxComplete"); + else + tasklet_schedule(&d->task); + event &= ~OHCI1394_respTxComplete; + } + if (event & OHCI1394_RQPkt) { + struct dma_rcv_ctx *d = ohci->ar_req_context; + DBGMSG(ohci->id, "Got RQPkt interrupt status=0x%08X", + reg_read(ohci, d->ctrlSet)); + if (reg_read(ohci, d->ctrlSet) & 0x800) + ohci1394_stop_context(ohci, d->ctrlClear, "RQPkt"); + else + tasklet_schedule(&d->task); + event &= ~OHCI1394_RQPkt; + } + if (event & OHCI1394_RSPkt) { + struct dma_rcv_ctx *d = ohci->ar_resp_context; + DBGMSG(ohci->id, "Got RSPkt interrupt status=0x%08X", + reg_read(ohci, d->ctrlSet)); + if (reg_read(ohci, d->ctrlSet) & 0x800) + ohci1394_stop_context(ohci, d->ctrlClear, "RSPkt"); + else + tasklet_schedule(&d->task); + event &= ~OHCI1394_RSPkt; + } + if (event & OHCI1394_isochRx) { + quadlet_t isoRecvIntEvent; + struct dma_rcv_ctx *d = ohci->ir_context; + isoRecvIntEvent = + reg_read(ohci, OHCI1394_IsoRecvIntEventSet); + reg_write(ohci, OHCI1394_IsoRecvIntEventClear, + isoRecvIntEvent); + DBGMSG(ohci->id, "Got isochRx interrupt " + "status=0x%08X isoRecvIntEvent=%08x", + reg_read(ohci, d->ctrlSet), isoRecvIntEvent); + if (isoRecvIntEvent & 0x1) { if (reg_read(ohci, d->ctrlSet) & 0x800) ohci1394_stop_context(ohci, d->ctrlClear, - "reqTxComplete"); + "isochRx"); else - dma_trm_bh((void *)d); + tasklet_schedule(&d->task); } - if (event & OHCI1394_respTxComplete) { - struct dma_trm_ctx *d = ohci->at_resp_context; - DBGMSG(ohci->id, "Got respTxComplete interrupt " - "status=0x%08X", reg_read(ohci, d->ctrlSet)); + if (ohci->video_tmpl) + ohci->video_tmpl->irq_handler(ohci->id, isoRecvIntEvent, + 0); + event &= ~OHCI1394_isochRx; + } + if (event & OHCI1394_isochTx) { + quadlet_t isoXmitIntEvent; + struct dma_trm_ctx *d = ohci->it_context; + isoXmitIntEvent = + reg_read(ohci, OHCI1394_IsoXmitIntEventSet); + reg_write(ohci, OHCI1394_IsoXmitIntEventClear, + isoXmitIntEvent); + DBGMSG(ohci->id, "Got isochTx interrupt " + "status=0x%08x isoXmitIntEvent=%08x", + reg_read(ohci, d->ctrlSet), isoXmitIntEvent); + if (ohci->video_tmpl) + ohci->video_tmpl->irq_handler(ohci->id, 0, + isoXmitIntEvent); + if (isoXmitIntEvent & 0x1) { if (reg_read(ohci, d->ctrlSet) & 0x800) - ohci1394_stop_context(ohci, d->ctrlClear, - "respTxComplete"); + ohci1394_stop_context(ohci, d->ctrlClear, "isochTx"); else - dma_trm_bh((void *)d); - } - if (event & OHCI1394_RQPkt) { - struct dma_rcv_ctx *d = ohci->ar_req_context; - DBGMSG(ohci->id, "Got RQPkt interrupt status=0x%08X", - reg_read(ohci, d->ctrlSet)); - if (reg_read(ohci, d->ctrlSet) & 0x800) - ohci1394_stop_context(ohci, d->ctrlClear, "RQPkt"); - else { -#if IEEE1394_USE_BOTTOM_HALVES - queue_task(&d->task, &tq_immediate); - mark_bh(IMMEDIATE_BH); -#else - dma_rcv_bh((void *)d); -#endif - } - } - if (event & OHCI1394_RSPkt) { - struct dma_rcv_ctx *d = ohci->ar_resp_context; - DBGMSG(ohci->id, "Got RSPkt interrupt status=0x%08X", - reg_read(ohci, d->ctrlSet)); - if (reg_read(ohci, d->ctrlSet) & 0x800) - ohci1394_stop_context(ohci, d->ctrlClear, "RSPkt"); - else { -#if IEEE1394_USE_BOTTOM_HALVES - queue_task(&d->task, &tq_immediate); - mark_bh(IMMEDIATE_BH); -#else - dma_rcv_bh((void *)d); -#endif - } + tasklet_schedule(&d->task); } - if (event & OHCI1394_isochRx) { - quadlet_t isoRecvIntEvent; - struct dma_rcv_ctx *d = ohci->ir_context; - isoRecvIntEvent = - reg_read(ohci, OHCI1394_IsoRecvIntEventSet); - reg_write(ohci, OHCI1394_IsoRecvIntEventClear, - isoRecvIntEvent); - DBGMSG(ohci->id, "Got isochRx interrupt " - "status=0x%08X isoRecvIntEvent=%08x", - reg_read(ohci, d->ctrlSet), isoRecvIntEvent); - if (isoRecvIntEvent & 0x1) { - if (reg_read(ohci, d->ctrlSet) & 0x800) - ohci1394_stop_context(ohci, d->ctrlClear, - "isochRx"); - else { -#if IEEE1394_USE_BOTTOM_HALVES - queue_task(&d->task, &tq_immediate); - mark_bh(IMMEDIATE_BH); -#else - dma_rcv_bh((void *)d); -#endif - } - } - if (ohci->video_tmpl) - ohci->video_tmpl->irq_handler(ohci->id, - isoRecvIntEvent, - 0); - } - if (event & OHCI1394_isochTx) { - quadlet_t isoXmitIntEvent; - isoXmitIntEvent = - reg_read(ohci, OHCI1394_IsoXmitIntEventSet); - reg_write(ohci, OHCI1394_IsoXmitIntEventClear, - isoXmitIntEvent); - DBGMSG(ohci->id, "Got isochTx interrupt"); - if (ohci->video_tmpl) - ohci->video_tmpl->irq_handler(ohci->id, 0, - isoXmitIntEvent); - } - if (event & OHCI1394_selfIDComplete) { - if (host->in_bus_reset) { - /* - * Begin Fix (JSG): Check to make sure our - * node id is valid - */ - node_id = reg_read(ohci, OHCI1394_NodeID); - if (!(node_id & 0x80000000)) { - mdelay(1); /* phy is upset - - * this happens once in - * a while on hot-plugs... - * give it a ms to recover - */ - } - /* End Fix (JSG) */ - + event &= ~OHCI1394_isochTx; + } + if (event & OHCI1394_selfIDComplete) { + if (host->in_bus_reset) { + node_id = reg_read(ohci, OHCI1394_NodeID); + + /* If our nodeid is not valid, give a msec delay + * to let it settle in and try again. */ + if (!(node_id & 0x80000000)) { + mdelay(1); node_id = reg_read(ohci, OHCI1394_NodeID); - if (node_id & 0x80000000) { /* NodeID valid */ - phyid = node_id & 0x0000003f; - isroot = (node_id & 0x40000000) != 0; - - PRINT(KERN_INFO, ohci->id, - "SelfID process finished " - "(phyid %d, %s)", phyid, - (isroot ? "root" : "not root")); - - handle_selfid(ohci, host, - phyid, isroot); - } - else - PRINT(KERN_ERR, ohci->id, - "SelfID process finished but " - "NodeID not valid: %08X", - node_id); - - /* Accept Physical requests from all nodes. */ - reg_write(ohci,OHCI1394_AsReqFilterHiSet, - 0xffffffff); - reg_write(ohci,OHCI1394_AsReqFilterLoSet, - 0xffffffff); - /* - * Tip by James Goodwin <jamesg@Filanet.com> - * Turn on phys dma reception. We should - * probably manage the filtering somehow, - * instead of blindly turning it on. - */ - reg_write(ohci,OHCI1394_PhyReqFilterHiSet, - 0xffffffff); - reg_write(ohci,OHCI1394_PhyReqFilterLoSet, - 0xffffffff); - reg_write(ohci,OHCI1394_PhyUpperBound, - 0xffff0000); - } - else PRINT(KERN_ERR, ohci->id, - "self-id received outside of bus reset" - "sequence"); - } - if (event & OHCI1394_phyRegRcvd) { -#if 1 - if (host->in_bus_reset) { - PRINT(KERN_INFO, ohci->id, "PhyControl: %08X", - reg_read(ohci, OHCI1394_PhyControl)); } - else PRINT(KERN_ERR, ohci->id, - "phy reg received outside of bus reset" - "sequence"); -#endif - } - } while (--timeout); - PRINT(KERN_ERR, ohci->id, "irq_handler timeout event=0x%08x", event); + if (node_id & 0x80000000) { /* NodeID valid */ + phyid = node_id & 0x0000003f; + isroot = (node_id & 0x40000000) != 0; + + PRINT(KERN_DEBUG, ohci->id, + "SelfID interrupt received " + "(phyid %d, %s)", phyid, + (isroot ? "root" : "not root")); + + handle_selfid(ohci, host, + phyid, isroot); + } else + PRINT(KERN_ERR, ohci->id, + "SelfID interrupt received, but " + "NodeID is not valid: %08X", + node_id); + + /* Accept Physical requests from all nodes. */ + reg_write(ohci,OHCI1394_AsReqFilterHiSet, + 0xffffffff); + reg_write(ohci,OHCI1394_AsReqFilterLoSet, + 0xffffffff); + /* Turn on phys dma reception. We should + * probably manage the filtering somehow, + * instead of blindly turning it on. */ + reg_write(ohci,OHCI1394_PhyReqFilterHiSet, + 0xffffffff); + reg_write(ohci,OHCI1394_PhyReqFilterLoSet, + 0xffffffff); + reg_write(ohci,OHCI1394_PhyUpperBound, + 0xffff0000); + } else + PRINT(KERN_ERR, ohci->id, + "SelfID received outside of bus reset sequence"); + event &= ~OHCI1394_selfIDComplete; + } + if (event & OHCI1394_phyRegRcvd) { + if (host->in_bus_reset) { + DBGMSG (ohci->id, "PhyControl: %08X", + reg_read(ohci, OHCI1394_PhyControl)); + } else + PRINT(KERN_ERR, ohci->id, + "Physical register received outside of bus reset sequence"); + event &= ~OHCI1394_phyRegRcvd; + } + if (event) + PRINT(KERN_ERR, ohci->id, "Unhandled interrupt(s) 0x%08x\n", + event); } /* Put the buffer back into the dma context */ @@ -1300,119 +1271,123 @@ struct ti_ohci *ohci = (struct ti_ohci*)(d->ohci); DBGMSG(ohci->id, "Inserting dma buf ctx=%d idx=%d", d->ctx, idx); - d->prg_cpu[idx]->status = d->buf_size; - d->prg_cpu[idx]->branchAddress &= 0xfffffff0; + d->prg_cpu[idx]->status = cpu_to_le32(d->buf_size); + d->prg_cpu[idx]->branchAddress &= le32_to_cpu(0xfffffff0); idx = (idx + d->num_desc - 1 ) % d->num_desc; - d->prg_cpu[idx]->branchAddress |= 0x1; + d->prg_cpu[idx]->branchAddress |= le32_to_cpu(0x00000001); /* wake up the dma context if necessary */ if (!(reg_read(ohci, d->ctrlSet) & 0x400)) { PRINT(KERN_INFO, ohci->id, - "Waking dma cxt=%d ... processing is probably too slow", + "Waking dma ctx=%d ... processing is probably too slow", d->ctx); reg_write(ohci, d->ctrlSet, 0x1000); } -} - -static int block_length(struct dma_rcv_ctx *d, int idx, - quadlet_t *buf_ptr, int offset) -{ - int length=0; - - /* Where is the data length ? */ - if (offset+12>=d->buf_size) - length = (d->buf_cpu[(idx+1)%d->num_desc] - [3-(d->buf_size-offset)/4]>>16); - else - length = (buf_ptr[3]>>16); - if (length % 4) length += 4 - (length % 4); - return length; } -const int TCODE_SIZE[16] = {20, 0, 16, -1, 16, 20, 20, 0, +#define cond_le32_to_cpu(data, noswap) \ + (noswap ? data : le32_to_cpu(data)) + +static const int TCODE_SIZE[16] = {20, 0, 16, -1, 16, 20, 20, 0, -1, 0, -1, 0, -1, -1, 16, -1}; /* * Determine the length of a packet in the buffer * Optimization suggested by Pascal Drolet <pascal.drolet@informission.ca> */ -static int packet_length(struct dma_rcv_ctx *d, int idx, quadlet_t *buf_ptr, -int offset) +static __inline__ int packet_length(struct dma_rcv_ctx *d, int idx, quadlet_t *buf_ptr, + int offset, unsigned char tcode, int noswap) { - unsigned char tcode; - int length = -1; - - /* Let's see what kind of packet is in there */ - tcode = (buf_ptr[0] >> 4) & 0xf; + int length = -1; if (d->ctx < 2) { /* Async Receive Response/Request */ length = TCODE_SIZE[tcode]; - if (length == 0) - length = block_length(d, idx, buf_ptr, offset) + 20; - } - else if (d->ctx==2) { /* Iso receive */ + if (length == 0) { + if (offset + 12 >= d->buf_size) { + length = (cond_le32_to_cpu(d->buf_cpu[(idx + 1) % d->num_desc] + [3 - ((d->buf_size - offset) >> 2)], noswap) >> 16); + } else { + length = (cond_le32_to_cpu(buf_ptr[3], noswap) >> 16); + } + length += 20; + } + } else if (d->ctx == 2) { /* Iso receive */ /* Assumption: buffer fill mode with header/trailer */ - length = (buf_ptr[0]>>16); - if (length % 4) length += 4 - (length % 4); - length+=8; + length = (cond_le32_to_cpu(buf_ptr[0], noswap) >> 16) + 8; } + + if (length > 0 && length % 4) + length += 4 - (length % 4); + return length; } -/* Bottom half that processes dma receive buffers */ -static void dma_rcv_bh(void *data) +/* Tasklet that processes dma receive buffers */ +static void dma_rcv_tasklet (unsigned long data) { struct dma_rcv_ctx *d = (struct dma_rcv_ctx*)data; struct ti_ohci *ohci = (struct ti_ohci*)(d->ohci); unsigned int split_left, idx, offset, rescount; unsigned char tcode; - int length, bytes_left, ack; + int length, bytes_left, ack, flags; quadlet_t *buf_ptr; char *split_ptr; char msg[256]; - spin_lock(&d->lock); + spin_lock_irqsave(&d->lock, flags); idx = d->buf_ind; offset = d->buf_offset; buf_ptr = d->buf_cpu[idx] + offset/4; - rescount = d->prg_cpu[idx]->status&0xffff; + dma_cache_wback_inv(&(d->prg_cpu[idx]->status), sizeof(d->prg_cpu[idx]->status)); + rescount = le32_to_cpu(d->prg_cpu[idx]->status) & 0xffff; + bytes_left = d->buf_size - rescount - offset; + dma_cache_wback_inv(buf_ptr, bytes_left); + + while (bytes_left > 0) { + tcode = (cond_le32_to_cpu(buf_ptr[0], ohci->payload_swap) >> 4) & 0xf; + + /* packet_length() will return < 4 for an error */ + length = packet_length(d, idx, buf_ptr, offset, tcode, ohci->payload_swap); - while (bytes_left>0) { - tcode = (buf_ptr[0]>>4)&0xf; - length = packet_length(d, idx, buf_ptr, offset); - - if (length<4) { /* something is wrong */ - sprintf(msg,"unexpected tcode 0x%X in AR ctx=%d", - tcode, d->ctx); + if (length < 4) { /* something is wrong */ + sprintf(msg,"Unexpected tcode 0x%x(0x%08x) in AR ctx=%d, length=%d", + tcode, cond_le32_to_cpu(buf_ptr[0], ohci->payload_swap), + d->ctx, length); ohci1394_stop_context(ohci, d->ctrlClear, msg); - spin_unlock(&d->lock); + spin_unlock_irqrestore(&d->lock, flags); return; } - if ((offset+length)>d->buf_size) { /* Split packet */ - if (length>d->split_buf_size) { + /* The first case is where we have a packet that crosses + * over more than one descriptor. The next case is where + * it's all in the first descriptor. */ + if ((offset + length) > d->buf_size) { + DBGMSG(ohci->id,"Split packet rcv'd\n"); + if (length > d->split_buf_size) { ohci1394_stop_context(ohci, d->ctrlClear, - "split packet size exceeded"); + "Split packet size exceeded"); d->buf_ind = idx; d->buf_offset = offset; - spin_unlock(&d->lock); + spin_unlock_irqrestore(&d->lock, flags); return; } - if (d->prg_cpu[(idx+1)%d->num_desc]->status - ==d->buf_size) { - /* other part of packet not written yet */ - /* this should never happen I think */ - /* anyway we'll get it on the next call */ +#if 0 + if (le32_to_cpu(d->prg_cpu[(idx+1)%d->num_desc]->status) + == d->buf_size) { + /* Other part of packet not written yet. + * this should never happen I think + * anyway we'll get it on the next call. */ PRINT(KERN_INFO, ohci->id, - "Got only half a packet !!!"); + "Got only half a packet!"); d->buf_ind = idx; d->buf_offset = offset; - spin_unlock(&d->lock); + spin_unlock_irqrestore(&d->lock, flags); return; } +#endif split_left = length; split_ptr = (char *)d->spb; memcpy(split_ptr,buf_ptr,d->buf_size-offset); @@ -1421,7 +1396,9 @@ insert_dma_buffer(d, idx); idx = (idx+1) % d->num_desc; buf_ptr = d->buf_cpu[idx]; + dma_cache_wback_inv(buf_ptr, d->buf_size); offset=0; + while (split_left >= d->buf_size) { memcpy(split_ptr,buf_ptr,d->buf_size); split_ptr += d->buf_size; @@ -1429,63 +1406,17 @@ insert_dma_buffer(d, idx); idx = (idx+1) % d->num_desc; buf_ptr = d->buf_cpu[idx]; + dma_cache_wback_inv(buf_ptr, d->buf_size); } - if (split_left>0) { + + if (split_left > 0) { memcpy(split_ptr, buf_ptr, split_left); offset = split_left; buf_ptr += offset/4; } - - /* - * We get one phy packet for each bus reset. - * we know that from now on the bus topology may - * have changed. Just ignore it for the moment - */ - if (tcode != 0xE) { - DBGMSG(ohci->id, "Split packet received from" - " node %d ack=0x%02X spd=%d tcode=0x%X" - " length=%d data=0x%08x ctx=%d", - (d->spb[1]>>16)&0x3f, - (d->spb[length/4-1]>>16)&0x1f, - (d->spb[length/4-1]>>21)&0x3, - tcode, length, d->spb[3], d->ctx); - - ack = (((d->spb[length/4-1]>>16)&0x1f) - == 0x11) ? 1 : 0; - - hpsb_packet_received(ohci->host, d->spb, - length, ack); - } - else - PRINT(KERN_INFO, ohci->id, - "Got phy packet ctx=%d ... discarded", - d->ctx); - } - else { - /* - * We get one phy packet for each bus reset. - * we know that from now on the bus topology may - * have changed. Just ignore it for the moment - */ - if (tcode != 0xE) { - DBGMSG(ohci->id, "Packet received from node" - " %d ack=0x%02X spd=%d tcode=0x%X" - " length=%d data=0x%08x ctx=%d", - (buf_ptr[1]>>16)&0x3f, - (buf_ptr[length/4-1]>>16)&0x1f, - (buf_ptr[length/4-1]>>21)&0x3, - tcode, length, buf_ptr[3], d->ctx); - - ack = (((buf_ptr[length/4-1]>>16)&0x1f) - == 0x11) ? 1 : 0; - - hpsb_packet_received(ohci->host, buf_ptr, - length, ack); - } - else - PRINT(KERN_INFO, ohci->id, - "Got phy packet ctx=%d ... discarded", - d->ctx); + } else { + DBGMSG(ohci->id,"Single packet rcv'd\n"); + memcpy(d->spb, buf_ptr, length); offset += length; buf_ptr += length/4; if (offset==d->buf_size) { @@ -1495,7 +1426,38 @@ offset=0; } } - rescount = d->prg_cpu[idx]->status & 0xffff; + + /* We get one phy packet to the async descriptor for each + * bus reset. We always ignore it. */ + if (tcode != OHCI1394_TCODE_PHY) { + if (!ohci->payload_swap) + packet_swab(d->spb, tcode, (length - 4) >> 2, 0); + + DBGMSG(ohci->id, "Packet received from node" + " %d ack=0x%02X spd=%d tcode=0x%X" + " length=%d ctx=%d tlabel=%d", + (d->spb[1]>>16)&0x3f, + (cond_le32_to_cpu(d->spb[length/4-1], ohci->payload_swap)>>16)&0x1f, + (cond_le32_to_cpu(d->spb[length/4-1], ohci->payload_swap)>>21)&0x3, + tcode, length, d->ctx, + (cond_le32_to_cpu(d->spb[length/4-1], ohci->payload_swap)>>10)&0x3f); + + ack = (((cond_le32_to_cpu(d->spb[length/4-1], ohci->payload_swap)>>16)&0x1f) + == 0x11) ? 1 : 0; + + hpsb_packet_received(ohci->host, d->spb, + length-4, ack); + } +#if OHCI1394_DEBUG + else + PRINT (KERN_DEBUG, ohci->id, "Got phy packet ctx=%d ... discarded", + d->ctx); +#endif + + dma_cache_wback_inv(&(d->prg_cpu[idx]->status), + sizeof(d->prg_cpu[idx]->status)); + rescount = le32_to_cpu(d->prg_cpu[idx]->status) & 0xffff; + bytes_left = d->buf_size - rescount - offset; } @@ -1503,11 +1465,11 @@ d->buf_ind = idx; d->buf_offset = offset; - spin_unlock(&d->lock); + spin_unlock_irqrestore(&d->lock, flags); } /* Bottom half that processes sent packets */ -static void dma_trm_bh(void *data) +static void dma_trm_tasklet (unsigned long data) { struct dma_trm_ctx *d = (struct dma_trm_ctx*)data; struct ti_ohci *ohci = (struct ti_ohci*)(d->ohci); @@ -1518,7 +1480,7 @@ spin_lock_irqsave(&d->lock, flags); - if (d->fifo_first==NULL) { + if (d->fifo_first == NULL) { #if 0 ohci1394_stop_context(ohci, d->ctrlClear, "Packet sent ack received but queue is empty"); @@ -1530,12 +1492,14 @@ while (d->fifo_first) { packet = d->fifo_first; datasize = d->fifo_first->data_size; - if (datasize) - ack = d->prg_cpu[d->sent_ind]->end.status>>16; + if (datasize && packet->type != raw) + ack = le32_to_cpu( + d->prg_cpu[d->sent_ind]->end.status) >> 16; else - ack = d->prg_cpu[d->sent_ind]->begin.status>>16; + ack = le32_to_cpu( + d->prg_cpu[d->sent_ind]->begin.status) >> 16; - if (ack==0) + if (ack == 0) /* this packet hasn't been sent yet*/ break; @@ -1544,37 +1508,47 @@ DBGMSG(ohci->id, "Packet sent to node %d tcode=0x%X tLabel=" "0x%02X ack=0x%X spd=%d dataLength=%d ctx=%d", - (d->prg_cpu[d->sent_ind]->data[1]>>16)&0x3f, - (d->prg_cpu[d->sent_ind]->data[0]>>4)&0xf, - (d->prg_cpu[d->sent_ind]->data[0]>>10)&0x3f, - ack&0x1f, (ack>>5)&0x3, - d->prg_cpu[d->sent_ind]->data[3]>>16, - d->ctx); + (le32_to_cpu(d->prg_cpu[d->sent_ind]->data[1]) + >>16)&0x3f, + (le32_to_cpu(d->prg_cpu[d->sent_ind]->data[0]) + >>4)&0xf, + (le32_to_cpu(d->prg_cpu[d->sent_ind]->data[0]) + >>10)&0x3f, + ack&0x1f, (ack>>5)&0x3, + le32_to_cpu(d->prg_cpu[d->sent_ind]->data[3]) + >>16, + d->ctx); else DBGMSG(ohci->id, "Packet sent to node %d tcode=0x%X tLabel=" "0x%02X ack=0x%X spd=%d data=0x%08X ctx=%d", - (d->prg_cpu[d->sent_ind]->data[1]>>16)&0x3f, - (d->prg_cpu[d->sent_ind]->data[0]>>4)&0xf, - (d->prg_cpu[d->sent_ind]->data[0]>>10)&0x3f, - ack&0x1f, (ack>>5)&0x3, - d->prg_cpu[d->sent_ind]->data[3], - d->ctx); + (le32_to_cpu(d->prg_cpu[d->sent_ind]->data[1]) + >>16)&0x3f, + (le32_to_cpu(d->prg_cpu[d->sent_ind]->data[0]) + >>4)&0xf, + (le32_to_cpu(d->prg_cpu[d->sent_ind]->data[0]) + >>10)&0x3f, + ack&0x1f, (ack>>5)&0x3, + le32_to_cpu(d->prg_cpu[d->sent_ind]->data[3]), + d->ctx); #endif nextpacket = packet->xnext; - hpsb_packet_sent(ohci->host, packet, ack&0xf); + hpsb_packet_sent(ohci->host, packet, ack & 0xf); - if (datasize) + if (datasize) { pci_unmap_single(ohci->dev, - d->prg_cpu[d->sent_ind]->end.address, + cpu_to_le32(d->prg_cpu[d->sent_ind]->end.address), datasize, PCI_DMA_TODEVICE); + OHCI_DMA_FREE("single Xmit data packet"); + } d->sent_ind = (d->sent_ind+1)%d->num_desc; d->free_prgs++; d->fifo_first = nextpacket; } - if (d->fifo_first==NULL) d->fifo_last=NULL; + if (d->fifo_first == NULL) + d->fifo_last = NULL; dma_trm_flush(ohci, d); @@ -1594,26 +1568,32 @@ ohci1394_stop_context(ohci, (*d)->ctrlClear, NULL); + tasklet_kill(&(*d)->task); + if ((*d)->buf_cpu) { for (i=0; i<(*d)->num_desc; i++) - if ((*d)->buf_cpu[i] && (*d)->buf_bus[i]) + if ((*d)->buf_cpu[i] && (*d)->buf_bus[i]) { pci_free_consistent( ohci->dev, (*d)->buf_size, (*d)->buf_cpu[i], (*d)->buf_bus[i]); + OHCI_DMA_FREE("consistent dma_rcv buf[%d]", i); + } kfree((*d)->buf_cpu); kfree((*d)->buf_bus); } if ((*d)->prg_cpu) { for (i=0; i<(*d)->num_desc; i++) - if ((*d)->prg_cpu[i] && (*d)->prg_bus[i]) + if ((*d)->prg_cpu[i] && (*d)->prg_bus[i]) { pci_free_consistent( ohci->dev, sizeof(struct dma_cmd), (*d)->prg_cpu[i], (*d)->prg_bus[i]); + OHCI_DMA_FREE("consistent dma_rcv prg[%d]", i); + } kfree((*d)->prg_cpu); kfree((*d)->prg_bus); } if ((*d)->spb) kfree((*d)->spb); - + kfree(*d); *d = NULL; @@ -1631,11 +1611,13 @@ d = (struct dma_rcv_ctx *)kmalloc(sizeof(struct dma_rcv_ctx), GFP_KERNEL); - if (d==NULL) { - PRINT(KERN_ERR, ohci->id, "failed to allocate dma_rcv_ctx"); + if (d == NULL) { + PRINT(KERN_ERR, ohci->id, "Failed to allocate dma_rcv_ctx"); return NULL; } + memset (d, 0, sizeof (struct dma_rcv_ctx)); + d->ohci = (void *)ohci; d->ctx = ctx; @@ -1656,7 +1638,7 @@ d->buf_bus = kmalloc(d->num_desc * sizeof(dma_addr_t), GFP_KERNEL); if (d->buf_cpu == NULL || d->buf_bus == NULL) { - PRINT(KERN_ERR, ohci->id, "failed to allocate dma buffer"); + PRINT(KERN_ERR, ohci->id, "Failed to allocate dma buffer"); free_dma_rcv_ctx(&d); return NULL; } @@ -1668,7 +1650,7 @@ d->prg_bus = kmalloc(d->num_desc * sizeof(dma_addr_t), GFP_KERNEL); if (d->prg_cpu == NULL || d->prg_bus == NULL) { - PRINT(KERN_ERR, ohci->id, "failed to allocate dma prg"); + PRINT(KERN_ERR, ohci->id, "Failed to allocate dma prg"); free_dma_rcv_ctx(&d); return NULL; } @@ -1678,21 +1660,22 @@ d->spb = kmalloc(d->split_buf_size, GFP_KERNEL); if (d->spb == NULL) { - PRINT(KERN_ERR, ohci->id, "failed to allocate split buffer"); + PRINT(KERN_ERR, ohci->id, "Failed to allocate split buffer"); free_dma_rcv_ctx(&d); return NULL; } for (i=0; i<d->num_desc; i++) { - d->buf_cpu[i] = pci_alloc_consistent(ohci->dev, + d->buf_cpu[i] = pci_alloc_consistent(ohci->dev, d->buf_size, d->buf_bus+i); + OHCI_DMA_ALLOC("consistent dma_rcv buf[%d]", i); - if (d->buf_cpu[i] != NULL) { + if (d->buf_cpu[i] != NULL) { memset(d->buf_cpu[i], 0, d->buf_size); } else { PRINT(KERN_ERR, ohci->id, - "failed to allocate dma buffer"); + "Failed to allocate dma buffer"); free_dma_rcv_ctx(&d); return NULL; } @@ -1701,12 +1684,13 @@ d->prg_cpu[i] = pci_alloc_consistent(ohci->dev, sizeof(struct dma_cmd), d->prg_bus+i); + OHCI_DMA_ALLOC("consistent dma_rcv prg[%d]", i); if (d->prg_cpu[i] != NULL) { memset(d->prg_cpu[i], 0, sizeof(struct dma_cmd)); } else { PRINT(KERN_ERR, ohci->id, - "failed to allocate dma prg"); + "Failed to allocate dma prg"); free_dma_rcv_ctx(&d); return NULL; } @@ -1714,11 +1698,8 @@ spin_lock_init(&d->lock); - /* initialize bottom handler */ - d->task.sync = 0; - INIT_TQ_LINK(d->task); - d->task.routine = dma_rcv_bh; - d->task.data = (void*)d; + /* initialize tasklet */ + tasklet_init (&d->task, dma_rcv_tasklet, (unsigned long)d); return d; } @@ -1736,12 +1717,16 @@ ohci1394_stop_context(ohci, (*d)->ctrlClear, NULL); + tasklet_kill(&(*d)->task); + if ((*d)->prg_cpu) { for (i=0; i<(*d)->num_desc; i++) - if ((*d)->prg_cpu[i] && (*d)->prg_bus[i]) + if ((*d)->prg_cpu[i] && (*d)->prg_bus[i]) { pci_free_consistent( ohci->dev, sizeof(struct at_dma_prg), (*d)->prg_cpu[i], (*d)->prg_bus[i]); + OHCI_DMA_FREE("consistent dma_trm prg[%d]", i); + } kfree((*d)->prg_cpu); kfree((*d)->prg_bus); } @@ -1762,10 +1747,12 @@ GFP_KERNEL); if (d==NULL) { - PRINT(KERN_ERR, ohci->id, "failed to allocate dma_trm_ctx"); + PRINT(KERN_ERR, ohci->id, "Failed to allocate dma_trm_ctx"); return NULL; } + memset (d, 0, sizeof (struct dma_trm_ctx)); + d->ohci = (void *)ohci; d->ctx = ctx; d->num_desc = num_desc; @@ -1780,7 +1767,7 @@ d->prg_bus = kmalloc(d->num_desc * sizeof(dma_addr_t), GFP_KERNEL); if (d->prg_cpu == NULL || d->prg_bus == NULL) { - PRINT(KERN_ERR, ohci->id, "failed to allocate at dma prg"); + PRINT(KERN_ERR, ohci->id, "Failed to allocate at dma prg"); free_dma_trm_ctx(&d); return NULL; } @@ -1791,12 +1778,13 @@ d->prg_cpu[i] = pci_alloc_consistent(ohci->dev, sizeof(struct at_dma_prg), d->prg_bus+i); + OHCI_DMA_ALLOC("consistent dma_trm prg[%d]", i); if (d->prg_cpu[i] != NULL) { memset(d->prg_cpu[i], 0, sizeof(struct at_dma_prg)); } else { PRINT(KERN_ERR, ohci->id, - "failed to allocate at dma prg"); + "Failed to allocate at dma prg"); free_dma_trm_ctx(&d); return NULL; } @@ -1805,105 +1793,333 @@ spin_lock_init(&d->lock); /* initialize bottom handler */ - INIT_TQ_LINK(d->task); - d->task.routine = dma_trm_bh; - d->task.data = (void*)d; + tasklet_init (&d->task, dma_trm_tasklet, (unsigned long)d); return d; } -static u32 ohci_crc16(unsigned *data, int length) +static u16 ohci_crc16 (u32 *ptr, int length) { - int check=0, i; - int shift, sum, next=0; - - for (i = length; i; i--) { - for (next = check, shift = 28; shift >= 0; shift -= 4 ) { - sum = ((next >> 12) ^ (*data >> shift)) & 0xf; - next = (next << 4) ^ (sum << 12) ^ (sum << 5) ^ (sum); - } - check = next & 0xffff; - data++; - } + int shift; + u32 crc, sum, data; - return check; + crc = 0; + for (; length > 0; length--) { + data = *ptr++; + for (shift = 28; shift >= 0; shift -= 4) { + sum = ((crc >> 12) ^ (data >> shift)) & 0x000f; + crc = (crc << 4) ^ (sum << 12) ^ (sum << 5) ^ sum; + } + crc &= 0xffff; + } + return crc; } +/* Config ROM macro implementation influenced by NetBSD OHCI driver */ + +struct config_rom_unit { + u32 *start; + u32 *refer; + int length; + int refunit; +}; + +struct config_rom_ptr { + u32 *data; + int unitnum; + struct config_rom_unit unitdir[10]; +}; + +#define cf_put_1quad(cr, q) (((cr)->data++)[0] = cpu_to_be32(q)) + +#define cf_put_4bytes(cr, b1, b2, b3, b4) \ + (((cr)->data++)[0] = cpu_to_be32(((b1) << 24) | ((b2) << 16) | ((b3) << 8) | (b4))) + +#define cf_put_keyval(cr, key, val) (((cr)->data++)[0] = cpu_to_be32((key) << 24) | (val)) + +#define cf_put_crc16(cr, unit) \ + (*(cr)->unitdir[unit].start = cpu_to_be32(((cr)->unitdir[unit].length << 16) | \ + ohci_crc16((cr)->unitdir[unit].start + 1, (cr)->unitdir[unit].length))) + +#define cf_unit_begin(cr, unit) \ +do { \ + if ((cr)->unitdir[unit].refer != NULL) { \ + *(cr)->unitdir[unit].refer |= \ + (cr)->data - (cr)->unitdir[unit].refer; \ + cf_put_crc16(cr, (cr)->unitdir[unit].refunit); \ + } \ + (cr)->unitnum = (unit); \ + (cr)->unitdir[unit].start = (cr)->data++; \ +} while (0) + +#define cf_put_refer(cr, key, unit) \ +do { \ + (cr)->unitdir[unit].refer = (cr)->data; \ + (cr)->unitdir[unit].refunit = (cr)->unitnum; \ + ((cr)->data++)[0] = cpu_to_be32((key) << 24); \ +} while(0) + +#define cf_unit_end(cr) \ +do { \ + (cr)->unitdir[(cr)->unitnum].length = (cr)->data - \ + ((cr)->unitdir[(cr)->unitnum].start + 1); \ + cf_put_crc16((cr), (cr)->unitnum); \ +} while(0) + static void ohci_init_config_rom(struct ti_ohci *ohci) { + struct config_rom_ptr cr; + + memset(&cr, 0, sizeof(cr)); + memset (ohci->csr_config_rom_cpu, 0, sizeof (ohci->csr_config_rom_cpu)); + + cr.data = ohci->csr_config_rom_cpu; + + /* Bus info block */ + cf_unit_begin(&cr, 0); + cf_put_1quad(&cr, reg_read(ohci, OHCI1394_BusID)); + cf_put_1quad(&cr, reg_read(ohci, OHCI1394_BusOptions)); + cf_put_1quad(&cr, reg_read(ohci, OHCI1394_GUIDHi)); + cf_put_1quad(&cr, reg_read(ohci, OHCI1394_GUIDLo)); + cf_unit_end(&cr); + + DBGMSG(ohci->id, "GUID: %08x:%08x\n", reg_read(ohci, OHCI1394_GUIDHi), + reg_read(ohci, OHCI1394_GUIDLo)); + + /* IEEE P1212 suggests the initial ROM header CRC should only + * cover the header itself (and not the entire ROM). Since we use + * this, then we can make our bus_info_len the same as the CRC + * length. */ + ohci->csr_config_rom_cpu[0] |= cpu_to_be32( + (be32_to_cpu(ohci->csr_config_rom_cpu[0]) & 0x00ff0000) << 8); + reg_write(ohci, OHCI1394_ConfigROMhdr, + be32_to_cpu(ohci->csr_config_rom_cpu[0])); + + /* Root directory */ + cf_unit_begin(&cr, 1); + cf_put_keyval(&cr, 0x03, 0x00005e); /* Vendor ID */ + cf_put_refer(&cr, 0x81, 2); /* Textual description unit */ + cf_put_keyval(&cr, 0x0c, 0x0083c0); /* Node capabilities */ + cf_put_refer(&cr, 0xd1, 3); /* IPv4 unit directory */ + cf_put_refer(&cr, 0xd1, 4); /* IPv6 unit directory */ + /* NOTE: Add other unit referers here, and append at bottom */ + cf_unit_end(&cr); + + /* Textual description - "Linux 1394" */ + cf_unit_begin(&cr, 2); + cf_put_keyval(&cr, 0, 0); + cf_put_1quad(&cr, 0); + cf_put_4bytes(&cr, 'L', 'i', 'n', 'u'); + cf_put_4bytes(&cr, 'x', ' ', '1', '3'); + cf_put_4bytes(&cr, '9', '4', 0x0, 0x0); + cf_unit_end(&cr); + + /* IPv4 unit directory, RFC 2734 */ + cf_unit_begin(&cr, 3); + cf_put_keyval(&cr, 0x12, 0x00005e); /* Unit spec ID */ + cf_put_refer(&cr, 0x81, 6); /* Textual description unit */ + cf_put_keyval(&cr, 0x13, 0x000001); /* Unit software version */ + cf_put_refer(&cr, 0x81, 7); /* Textual description unit */ + cf_unit_end(&cr); + + cf_unit_begin(&cr, 6); + cf_put_keyval(&cr, 0, 0); + cf_put_1quad(&cr, 0); + cf_put_4bytes(&cr, 'I', 'A', 'N', 'A'); + cf_unit_end(&cr); + + cf_unit_begin(&cr, 7); + cf_put_keyval(&cr, 0, 0); + cf_put_1quad(&cr, 0); + cf_put_4bytes(&cr, 'I', 'P', 'v', '4'); + cf_unit_end(&cr); + + /* IPv6 unit directory, draft-ietf-ipngwg-1394-01.txt */ + cf_unit_begin(&cr, 4); + cf_put_keyval(&cr, 0x12, 0x00005e); /* Unit spec ID */ + cf_put_refer(&cr, 0x81, 8); /* Textual description unit */ + cf_put_keyval(&cr, 0x13, 0x000002); /* (Proposed) Unit software version */ + cf_put_refer(&cr, 0x81, 9); /* Textual description unit */ + cf_unit_end(&cr); + + cf_unit_begin(&cr, 8); + cf_put_keyval(&cr, 0, 0); + cf_put_1quad(&cr, 0); + cf_put_4bytes(&cr, 'I', 'A', 'N', 'A'); + cf_unit_end(&cr); + + cf_unit_begin(&cr, 9); + cf_put_keyval(&cr, 0, 0); + cf_put_1quad(&cr, 0); + cf_put_4bytes(&cr, 'I', 'P', 'v', '6'); + cf_unit_end(&cr); + + return; +} + +static size_t get_ohci_rom(struct hpsb_host *host, const quadlet_t **ptr) +{ + struct ti_ohci *ohci=host->hostdata; + + DBGMSG(ohci->id, "request csr_rom address: %p", + ohci->csr_config_rom_cpu); + + *ptr = ohci->csr_config_rom_cpu; + + return sizeof(ohci->csr_config_rom_cpu); +} + +int ohci_compare_swap(struct ti_ohci *ohci, quadlet_t *data, + quadlet_t compare, int sel) +{ int i; + reg_write(ohci, OHCI1394_CSRData, *data); + reg_write(ohci, OHCI1394_CSRCompareData, compare); + reg_write(ohci, OHCI1394_CSRControl, sel & 0x3); - ohci_csr_rom[3] = reg_read(ohci, OHCI1394_GUIDHi); - ohci_csr_rom[4] = reg_read(ohci, OHCI1394_GUIDLo); - - ohci_csr_rom[0] = 0x04040000 | ohci_crc16(ohci_csr_rom+1, 4); + for (i = 0; i < OHCI_LOOP_COUNT; i++) { + if (reg_read(ohci, OHCI1394_CSRControl) & 0x80000000) + break; + + mdelay(10); + } - for (i=0;i<sizeof(ohci_csr_rom)/4;i++) - ohci->csr_config_rom_cpu[i] = cpu_to_be32(ohci_csr_rom[i]); + *data = reg_read(ohci, OHCI1394_CSRData); + return 0; } -static int add_card(struct pci_dev *dev) +static quadlet_t ohci_hw_csr_reg(struct hpsb_host *host, int reg, + quadlet_t data, quadlet_t compare) { - struct ti_ohci *ohci; /* shortcut to currently handled device */ + struct ti_ohci *ohci=host->hostdata; + + ohci_compare_swap (ohci, &data, compare, reg); + + return data; +} + +struct hpsb_host_template *get_ohci_template(void) +{ + static struct hpsb_host_template tmpl; + static int initialized = 0; + + if (!initialized) { + memset (&tmpl, 0, sizeof (struct hpsb_host_template)); - if (num_of_cards == MAX_OHCI1394_CARDS) { - PRINT_G(KERN_WARNING, "cannot handle more than %d cards. " - "Adjust MAX_OHCI1394_CARDS in ti_ohci1394.h.", - MAX_OHCI1394_CARDS); - return 1; + /* Initialize by field names so that a template structure + * reorganization does not influence this code. */ + tmpl.name = "ohci1394"; + + tmpl.initialize_host = ohci_initialize; + tmpl.release_host = ohci_remove; + tmpl.get_rom = get_ohci_rom; + tmpl.transmit_packet = ohci_transmit; + tmpl.devctl = ohci_devctl; + tmpl.hw_csr_reg = ohci_hw_csr_reg; + initialized = 1; } + return &tmpl; +} + +static int __devinit ohci1394_add_one(struct pci_dev *dev, const struct pci_device_id *ent) +{ + struct ti_ohci *ohci; /* shortcut to currently handled device */ + struct hpsb_host *host; + unsigned long ohci_base, ohci_len; + static int version_printed = 0; + + if (version_printed++ == 0) + PRINT_G(KERN_INFO, "%s", version); + if (pci_enable_device(dev)) { - PRINT_G(KERN_NOTICE, "failed to enable OHCI hardware %d", - num_of_cards); - return 1; + /* Skip ID's that fail */ + PRINT_G(KERN_NOTICE, "Failed to enable OHCI hardware %d", + card_id_counter++); + return -ENXIO; } pci_set_master(dev); - ohci = &cards[num_of_cards++]; - - ohci->id = num_of_cards-1; + host = hpsb_get_host(get_ohci_template(), sizeof (struct ti_ohci)); + if (!host) { + PRINT_G(KERN_ERR, "Out of memory trying to allocate host structure"); + return -ENOMEM; + } + ohci = host->hostdata; + ohci->host = host; + INIT_LIST_HEAD(&ohci->list); + ohci->id = card_id_counter++; ohci->dev = dev; - - ohci->state = 0; + host->pdev = dev; + ohci->host = host; + pci_set_drvdata(dev, ohci); + + PRINT(KERN_INFO, ohci->id, "OHCI (PCI) IEEE-1394 Controller"); + + /* We don't want hardware swapping */ + pci_write_config_dword(dev, OHCI1394_PCI_HCI_Control, 0); + + /* Some oddball Apple controllers do not order the selfid + * properly, so we make up for it here. */ +#ifndef __LITTLE_ENDIAN + /* XXX: Need a better way to check this. I'm wondering if we can + * read the values of the OHCI1394_PCI_HCI_Control and the + * noByteSwapData registers to see if they were not cleared to + * zero. Should this work? Obviously it's not defined what these + * registers will read when they aren't supported. Bleh! */ + if (dev->vendor == PCI_VENDOR_ID_APPLE) { + ohci->payload_swap = 1; + if (dev->device != PCI_DEVICE_ID_APPLE_UNI_N_FW) + ohci->selfid_swap = 1; + } else + ohci->selfid_swap = 1; +#endif /* csr_config rom allocation */ ohci->csr_config_rom_cpu = - pci_alloc_consistent(ohci->dev, sizeof(ohci_csr_rom), + pci_alloc_consistent(ohci->dev, OHCI_CONFIG_ROM_LEN, &ohci->csr_config_rom_bus); - if (ohci->csr_config_rom_cpu == NULL) { - FAIL("failed to allocate buffer config rom"); - } + OHCI_DMA_ALLOC("consistent csr_config_rom"); + if (ohci->csr_config_rom_cpu == NULL) + FAIL("Failed to allocate buffer config rom"); /* * self-id dma buffer allocation - * FIXME: some early chips may need 8KB alignment for the - * selfid buffer... if you have problems a temporary fic - * is to allocate 8192 bytes instead of 2048 */ ohci->selfid_buf_cpu = - pci_alloc_consistent(ohci->dev, 8192, &ohci->selfid_buf_bus); - if (ohci->selfid_buf_cpu == NULL) { - FAIL("failed to allocate DMA buffer for self-id packets"); - } + pci_alloc_consistent(ohci->dev, OHCI1394_SI_DMA_BUF_SIZE, + &ohci->selfid_buf_bus); + OHCI_DMA_ALLOC("consistent selfid_buf"); + if (ohci->selfid_buf_cpu == NULL) + FAIL("Failed to allocate DMA buffer for self-id packets"); + if ((unsigned long)ohci->selfid_buf_cpu & 0x1fff) - PRINT(KERN_INFO, ohci->id, "Selfid buffer %p not aligned on " - "8Kb boundary... may cause pb on some CXD3222 chip", + PRINT(KERN_INFO, ohci->id, "SelfID buffer %p is not aligned on " + "8Kb boundary... may cause problems on some CXD3222 chip", ohci->selfid_buf_cpu); -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,13) - ohci->registers = ioremap_nocache(dev->base_address[0], - OHCI1394_REGISTER_SIZE); -#else - ohci->registers = ioremap_nocache(dev->resource[0].start, - OHCI1394_REGISTER_SIZE); -#endif + ohci->it_context = + alloc_dma_trm_ctx(ohci, 2, IT_NUM_DESC, + OHCI1394_IsoXmitContextControlSet, + OHCI1394_IsoXmitContextControlClear, + OHCI1394_IsoXmitCommandPtr); - if (ohci->registers == NULL) { - FAIL("failed to remap registers - card not accessible"); - } + if (ohci->it_context == NULL) + FAIL("Failed to allocate IT context"); + + ohci_base = pci_resource_start(dev, 0); + ohci_len = pci_resource_len(dev, 0); - PRINT(KERN_INFO, ohci->id, "remapped memory spaces reg 0x%p", + if (!request_mem_region (ohci_base, ohci_len, host->template->name)) + FAIL("MMIO resource (0x%lx@0x%lx) unavailable, aborting.", + ohci_base, ohci_len); + + ohci->registers = ioremap(ohci_base, ohci_len); + + if (ohci->registers == NULL) + FAIL("Failed to remap registers - card not accessible"); + + DBGMSG(ohci->id, "Remapped memory spaces reg 0x%p", ohci->registers); ohci->ar_req_context = @@ -1913,9 +2129,8 @@ OHCI1394_AsReqRcvContextControlClear, OHCI1394_AsReqRcvCommandPtr); - if (ohci->ar_req_context == NULL) { - FAIL("failed to allocate AR Req context"); - } + if (ohci->ar_req_context == NULL) + FAIL("Failed to allocate AR Req context"); ohci->ar_resp_context = alloc_dma_rcv_ctx(ohci, 1, AR_RESP_NUM_DESC, @@ -1924,9 +2139,8 @@ OHCI1394_AsRspRcvContextControlClear, OHCI1394_AsRspRcvCommandPtr); - if (ohci->ar_resp_context == NULL) { - FAIL("failed to allocate AR Resp context"); - } + if (ohci->ar_resp_context == NULL) + FAIL("Failed to allocate AR Resp context"); ohci->at_req_context = alloc_dma_trm_ctx(ohci, 0, AT_REQ_NUM_DESC, @@ -1934,9 +2148,8 @@ OHCI1394_AsReqTrContextControlClear, OHCI1394_AsReqTrCommandPtr); - if (ohci->at_req_context == NULL) { - FAIL("failed to allocate AT Req context"); - } + if (ohci->at_req_context == NULL) + FAIL("Failed to allocate AT Req context"); ohci->at_resp_context = alloc_dma_trm_ctx(ohci, 1, AT_RESP_NUM_DESC, @@ -1944,10 +2157,9 @@ OHCI1394_AsRspTrContextControlClear, OHCI1394_AsRspTrCommandPtr); - if (ohci->at_resp_context == NULL) { - FAIL("failed to allocate AT Resp context"); - } - + if (ohci->at_resp_context == NULL) + FAIL("Failed to allocate AT Resp context"); + ohci->ir_context = alloc_dma_rcv_ctx(ohci, 2, IR_NUM_DESC, IR_BUF_SIZE, IR_SPLIT_BUF_SIZE, @@ -1955,275 +2167,30 @@ OHCI1394_IsoRcvContextControlClear, OHCI1394_IsoRcvCommandPtr); - if (ohci->ir_context == NULL) { - FAIL("failed to allocate IR context"); - } + if (ohci->ir_context == NULL) + FAIL("Failed to allocate IR context"); - ohci->ISO_channel_usage= 0; + ohci->ISO_channel_usage = 0; spin_lock_init(&ohci->IR_channel_lock); if (!request_irq(dev->irq, ohci_irq_handler, SA_SHIRQ, - OHCI1394_DRIVER_NAME, ohci)) { - PRINT(KERN_INFO, ohci->id, "allocated interrupt %d", dev->irq); - } else { - FAIL("failed to allocate shared interrupt %d", dev->irq); - } + OHCI1394_DRIVER_NAME, ohci)) + PRINT(KERN_DEBUG, ohci->id, "Allocated interrupt %d", dev->irq); + else + FAIL("Failed to allocate shared interrupt %d", dev->irq); ohci_init_config_rom(ohci); - DBGMSG(ohci->id, "The 1st byte at offset 0x404 is: 0x%02x", - *((char *)ohci->csr_config_rom_cpu+4)); + /* Tell the highlevel this host is ready */ + highlevel_add_one_host (host); return 0; #undef FAIL } -#ifdef CONFIG_PROC_FS - -#define SR(fmt, reg0, reg1, reg2)\ -p += sprintf(p,fmt,reg_read(ohci, reg0),\ - reg_read(ohci, reg1),reg_read(ohci, reg2)); - -static int ohci_get_status(char *buf) -{ - struct ti_ohci *ohci=&cards[0]; - struct hpsb_host *host=ohci->host; - char *p=buf; - //unsigned char phyreg; - //int i, nports; - int i; - - struct dma_rcv_ctx *d=NULL; - struct dma_trm_ctx *dt=NULL; - - p += sprintf(p,"IEEE-1394 OHCI Driver status report:\n"); - p += sprintf(p," bus number: 0x%x Node ID: 0x%x\n", - (reg_read(ohci, OHCI1394_NodeID) & 0xFFC0) >> 6, - reg_read(ohci, OHCI1394_NodeID)&0x3f); -#if 0 - p += sprintf(p," hardware version %d.%d GUID_ROM is %s\n\n", - (reg_read(ohci, OHCI1394_Version) & 0xFF0000) >>16, - reg_read(ohci, OHCI1394_Version) & 0xFF, - (reg_read(ohci, OHCI1394_Version) & 0x01000000) - ? "set" : "clear"); -#endif - p += sprintf(p,"\n### Host data ###\n"); - p += sprintf(p,"node_count: %8d ",host->node_count); - p += sprintf(p,"node_id : %08X\n",host->node_id); - p += sprintf(p,"irm_id : %08X ",host->irm_id); - p += sprintf(p,"busmgr_id : %08X\n",host->busmgr_id); - p += sprintf(p,"%s %s %s\n", - host->initialized ? "initialized" : "", - host->in_bus_reset ? "in_bus_reset" : "", - host->attempt_root ? "attempt_root" : ""); - p += sprintf(p,"%s %s %s %s\n", - host->is_root ? "root" : "", - host->is_cycmst ? "cycle_master" : "", - host->is_irm ? "iso_res_mgr" : "", - host->is_busmgr ? "bus_mgr" : ""); - - p += sprintf(p,"\n---Iso Receive DMA---\n"); - - d = ohci->ir_context; -#if 0 - for (i=0; i<d->num_desc; i++) { - p += sprintf(p, "IR buf[%d] : %p prg[%d]: %p\n", - i, d->buf[i], i, d->prg[i]); - } -#endif - p += sprintf(p, "Current buf: %d offset: %d\n", - d->buf_ind,d->buf_offset); - - p += sprintf(p,"\n---Async Receive DMA---\n"); - d = ohci->ar_req_context; -#if 0 - for (i=0; i<d->num_desc; i++) { - p += sprintf(p, "AR req buf[%d] : %p prg[%d]: %p\n", - i, d->buf[i], i, d->prg[i]); - } -#endif - p += sprintf(p, "Ar req current buf: %d offset: %d\n", - d->buf_ind,d->buf_offset); - - d = ohci->ar_resp_context; -#if 0 - for (i=0; i<d->num_desc; i++) { - p += sprintf(p, "AR resp buf[%d] : %p prg[%d]: %p\n", - i, d->buf[i], i, d->prg[i]); - } -#endif - p += sprintf(p, "AR resp current buf: %d offset: %d\n", - d->buf_ind,d->buf_offset); - - p += sprintf(p,"\n---Async Transmit DMA---\n"); - dt = ohci->at_req_context; - p += sprintf(p, "AT req prg: %d sent: %d free: %d branchAddrPtr: %p\n", - dt->prg_ind, dt->sent_ind, dt->free_prgs, - dt->branchAddrPtr); - p += sprintf(p, "AT req queue: first: %p last: %p\n", - dt->fifo_first, dt->fifo_last); - dt = ohci->at_resp_context; -#if 0 - for (i=0; i<dt->num_desc; i++) { - p += sprintf(p, "------- AT resp prg[%02d] ------\n",i); - p += sprintf(p, "%p: control : %08x\n", - &(dt->prg[i].begin.control), - dt->prg[i].begin.control); - p += sprintf(p, "%p: address : %08x\n", - &(dt->prg[i].begin.address), - dt->prg[i].begin.address); - p += sprintf(p, "%p: brancAddr: %08x\n", - &(dt->prg[i].begin.branchAddress), - dt->prg[i].begin.branchAddress); - p += sprintf(p, "%p: status : %08x\n", - &(dt->prg[i].begin.status), - dt->prg[i].begin.status); - p += sprintf(p, "%p: header[0]: %08x\n", - &(dt->prg[i].data[0]), - dt->prg[i].data[0]); - p += sprintf(p, "%p: header[1]: %08x\n", - &(dt->prg[i].data[1]), - dt->prg[i].data[1]); - p += sprintf(p, "%p: header[2]: %08x\n", - &(dt->prg[i].data[2]), - dt->prg[i].data[2]); - p += sprintf(p, "%p: header[3]: %08x\n", - &(dt->prg[i].data[3]), - dt->prg[i].data[3]); - p += sprintf(p, "%p: control : %08x\n", - &(dt->prg[i].end.control), - dt->prg[i].end.control); - p += sprintf(p, "%p: address : %08x\n", - &(dt->prg[i].end.address), - dt->prg[i].end.address); - p += sprintf(p, "%p: brancAddr: %08x\n", - &(dt->prg[i].end.branchAddress), - dt->prg[i].end.branchAddress); - p += sprintf(p, "%p: status : %08x\n", - &(dt->prg[i].end.status), - dt->prg[i].end.status); - } -#endif - p += sprintf(p, "AR resp prg: %d sent: %d free: %d" - " branchAddrPtr: %p\n", - dt->prg_ind, dt->sent_ind, dt->free_prgs, - dt->branchAddrPtr); - p += sprintf(p, "AT resp queue: first: %p last: %p\n", - dt->fifo_first, dt->fifo_last); - - /* ----- Register Dump ----- */ - p += sprintf(p,"\n### HC Register dump ###\n"); - SR("Version : %08x GUID_ROM : %08x ATRetries : %08x\n", - OHCI1394_Version, OHCI1394_GUID_ROM, OHCI1394_ATRetries); - SR("CSRData : %08x CSRCompData : %08x CSRControl : %08x\n", - OHCI1394_CSRData, OHCI1394_CSRCompareData, OHCI1394_CSRControl); - SR("ConfigROMhdr: %08x BusID : %08x BusOptions : %08x\n", - OHCI1394_ConfigROMhdr, OHCI1394_BusID, OHCI1394_BusOptions); - SR("GUIDHi : %08x GUIDLo : %08x ConfigROMmap: %08x\n", - OHCI1394_GUIDHi, OHCI1394_GUIDLo, OHCI1394_ConfigROMmap); - SR("PtdWrAddrLo : %08x PtdWrAddrHi : %08x VendorID : %08x\n", - OHCI1394_PostedWriteAddressLo, OHCI1394_PostedWriteAddressHi, - OHCI1394_VendorID); - SR("HCControl : %08x SelfIDBuffer: %08x SelfIDCount : %08x\n", - OHCI1394_HCControlSet, OHCI1394_SelfIDBuffer, OHCI1394_SelfIDCount); - SR("IRMuChMaskHi: %08x IRMuChMaskLo: %08x IntEvent : %08x\n", - OHCI1394_IRMultiChanMaskHiSet, OHCI1394_IRMultiChanMaskLoSet, - OHCI1394_IntEventSet); - SR("IntMask : %08x IsoXmIntEvnt: %08x IsoXmIntMask: %08x\n", - OHCI1394_IntMaskSet, OHCI1394_IsoXmitIntEventSet, - OHCI1394_IsoXmitIntMaskSet); - SR("IsoRcvIntEvt: %08x IsoRcvIntMsk: %08x FairnessCtrl: %08x\n", - OHCI1394_IsoRecvIntEventSet, OHCI1394_IsoRecvIntMaskSet, - OHCI1394_FairnessControl); - SR("LinkControl : %08x NodeID : %08x PhyControl : %08x\n", - OHCI1394_LinkControlSet, OHCI1394_NodeID, OHCI1394_PhyControl); - SR("IsoCyclTimer: %08x AsRqFilterHi: %08x AsRqFilterLo: %08x\n", - OHCI1394_IsochronousCycleTimer, - OHCI1394_AsReqFilterHiSet, OHCI1394_AsReqFilterLoSet); - SR("PhyReqFiltHi: %08x PhyReqFiltLo: %08x PhyUpperBnd : %08x\n", - OHCI1394_PhyReqFilterHiSet, OHCI1394_PhyReqFilterLoSet, - OHCI1394_PhyUpperBound); - SR("AsRqTrCxtCtl: %08x AsRqTrCmdPtr: %08x AsRsTrCtxCtl: %08x\n", - OHCI1394_AsReqTrContextControlSet, OHCI1394_AsReqTrCommandPtr, - OHCI1394_AsRspTrContextControlSet); - SR("AsRsTrCmdPtr: %08x AsRqRvCtxCtl: %08x AsRqRvCmdPtr: %08x\n", - OHCI1394_AsRspTrCommandPtr, OHCI1394_AsReqRcvContextControlSet, - OHCI1394_AsReqRcvCommandPtr); - SR("AsRsRvCtxCtl: %08x AsRsRvCmdPtr: %08x IntEvent : %08x\n", - OHCI1394_AsRspRcvContextControlSet, OHCI1394_AsRspRcvCommandPtr, - OHCI1394_IntEventSet); - for (i=0;i<ohci->nb_iso_rcv_ctx;i++) { - p += sprintf(p,"IsoRCtxCtl%02d: %08x IsoRCmdPtr%02d: %08x" - " IsoRCxtMch%02d: %08x\n", i, - reg_read(ohci, - OHCI1394_IsoRcvContextControlSet+32*i), - i,reg_read(ohci, OHCI1394_IsoRcvCommandPtr+32*i), - i,reg_read(ohci, - OHCI1394_IsoRcvContextMatch+32*i)); - } - for (i=0;i<ohci->nb_iso_xmit_ctx;i++) { - p += sprintf(p,"IsoTCtxCtl%02d: %08x IsoTCmdPtr%02d: %08x\n", - i, - reg_read(ohci, - OHCI1394_IsoXmitContextControlSet+32*i), - i,reg_read(ohci,OHCI1394_IsoXmitCommandPtr+32*i)); - } - -#if 0 - p += sprintf(p,"\n### Phy Register dump ###\n"); - phyreg=get_phy_reg(ohci,1); - p += sprintf(p,"offset: %d val: 0x%02x -> RHB: %d" - "IBR: %d Gap_count: %d\n", - 1,phyreg,(phyreg&0x80) != 0, - (phyreg&0x40) !=0, phyreg&0x3f); - phyreg=get_phy_reg(ohci,2); - nports=phyreg&0x1f; - p += sprintf(p,"offset: %d val: 0x%02x -> SPD: %d" - " E : %d Ports : %2d\n", - 2,phyreg, (phyreg&0xC0)>>6, (phyreg&0x20) !=0, nports); - for (i=0;i<nports;i++) { - phyreg=get_phy_reg(ohci,3+i); - p += sprintf(p,"offset: %d val: 0x%02x -> [port %d]" - " TPA: %d TPB: %d | %s %s\n", - 3+i,phyreg, - i, (phyreg&0xC0)>>6, (phyreg&0x30)>>4, - (phyreg&0x08) ? "child" : "parent", - (phyreg&0x04) ? "connected" : "disconnected"); - } - phyreg=get_phy_reg(ohci,3+i); - p += sprintf(p,"offset: %d val: 0x%02x -> ENV: %s Reg_count: %d\n", - 3+i,phyreg, - (((phyreg&0xC0)>>6)==0) ? "backplane" : - (((phyreg&0xC0)>>6)==1) ? "cable" : "reserved", - phyreg&0x3f); -#endif - - return p - buf; -} - -static int ohci1394_read_proc(char *page, char **start, off_t off, - int count, int *eof, void *data) -{ - int len = ohci_get_status(page); - if (len <= off+count) *eof = 1; - *start = page + off; - len -= off; - if (len>count) len = count; - if (len<0) len = 0; - return len; -} - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0) -struct proc_dir_entry *ohci_proc_entry; -#endif /* LINUX_VERSION_CODE */ -#endif /* CONFIG_PROC_FS */ - static void remove_card(struct ti_ohci *ohci) { - /* - * Reset the board properly before leaving - * Daniel Kobras <daniel.kobras@student.uni-tuebingen.de> - */ + /* Reset the board properly before leaving */ ohci_soft_reset(ohci); /* Free AR dma */ @@ -2237,122 +2204,35 @@ /* Free IR dma */ free_dma_rcv_ctx(&ohci->ir_context); + /* Free IT dma */ + free_dma_trm_ctx(&ohci->it_context); + /* Free self-id buffer */ - if (ohci->selfid_buf_cpu) - pci_free_consistent(ohci->dev, 2048, + if (ohci->selfid_buf_cpu) { + pci_free_consistent(ohci->dev, OHCI1394_SI_DMA_BUF_SIZE, ohci->selfid_buf_cpu, ohci->selfid_buf_bus); + OHCI_DMA_FREE("consistent selfid_buf"); + } /* Free config rom */ - if (ohci->csr_config_rom_cpu) - pci_free_consistent(ohci->dev, sizeof(ohci_csr_rom), + if (ohci->csr_config_rom_cpu) { + pci_free_consistent(ohci->dev, OHCI_CONFIG_ROM_LEN, ohci->csr_config_rom_cpu, ohci->csr_config_rom_bus); + OHCI_DMA_FREE("consistent csr_config_rom"); + } /* Free the IRQ */ free_irq(ohci->dev->irq, ohci); - if (ohci->registers) + if (ohci->registers) iounmap(ohci->registers); - ohci->state = 0; -} - -static int init_driver() -{ - struct pci_dev *dev = NULL; - int success = 0; -#if USE_DEVICE - int i; -#endif - if (num_of_cards) { - PRINT_G(KERN_DEBUG, __PRETTY_FUNCTION__ " called again"); - return 0; - } - - PRINT_G(KERN_INFO, "looking for Ohci1394 cards"); - -#if USE_DEVICE - for (i = 0; supported_chips[i][0] != -1; i++) { - while ((dev = pci_find_device(supported_chips[i][0], - supported_chips[i][1], dev)) - != NULL) { - if (add_card(dev) == 0) { - success = 1; - } - } - } -#else - while ((dev = pci_find_class(PCI_CLASS_FIREWIRE_OHCI, dev)) != NULL ) { - if (add_card(dev) == 0) success = 1; - } -#endif /* USE_DEVICE */ - if (success == 0) { - PRINT_G(KERN_WARNING, "no operable Ohci1394 cards found"); - return -ENXIO; - } + release_mem_region (pci_resource_start(ohci->dev, 0), + pci_resource_len(ohci->dev, 0)); -#ifdef CONFIG_PROC_FS -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) - create_proc_read_entry ("ohci1394", 0, NULL, ohci1394_read_proc, NULL); -#else - if ((ohci_proc_entry = create_proc_entry("ohci1394", 0, NULL))) - ohci_proc_entry->read_proc = ohci1394_read_proc; -#endif -#endif - return 0; -} - -static size_t get_ohci_rom(struct hpsb_host *host, const quadlet_t **ptr) -{ - struct ti_ohci *ohci=host->hostdata; - - DBGMSG(ohci->id, "request csr_rom address: %08X", - (u32)ohci->csr_config_rom_cpu); - - *ptr = ohci->csr_config_rom_cpu; - return sizeof(ohci_csr_rom); -} - -static quadlet_t ohci_hw_csr_reg(struct hpsb_host *host, int reg, - quadlet_t data, quadlet_t compare) -{ - struct ti_ohci *ohci=host->hostdata; - int timeout = 255; - - reg_write(ohci, OHCI1394_CSRData, data); - reg_write(ohci, OHCI1394_CSRCompareData, compare); - reg_write(ohci, OHCI1394_CSRControl, reg&0x3); - - while (timeout-- && !(reg_read(ohci, OHCI1394_CSRControl)&0x80000000)); - - if (!timeout) - PRINT(KERN_ERR, ohci->id, __FUNCTION__ "timeout!"); - - return reg_read(ohci, OHCI1394_CSRData); -} - -struct hpsb_host_template *get_ohci_template(void) -{ - static struct hpsb_host_template tmpl; - static int initialized = 0; - - if (!initialized) { - /* Initialize by field names so that a template structure - * reorganization does not influence this code. */ - tmpl.name = "ohci1394"; - - tmpl.detect_hosts = ohci_detect; - tmpl.initialize_host = ohci_initialize; - tmpl.release_host = ohci_remove; - tmpl.get_rom = get_ohci_rom; - tmpl.transmit_packet = ohci_transmit; - tmpl.devctl = ohci_devctl; - tmpl.hw_csr_reg = ohci_hw_csr_reg; - initialized = 1; - } - - return &tmpl; + pci_set_drvdata(ohci->dev, NULL); } void ohci1394_stop_context(struct ti_ohci *ohci, int reg, char *msg) @@ -2367,18 +2247,11 @@ i++; if (i>5000) { PRINT(KERN_ERR, ohci->id, - "runaway loop while stopping context..."); + "Runaway loop while stopping context..."); break; } } - if (msg) PRINT(KERN_ERR, ohci->id, "%s\n dma prg stopped\n", msg); -} - -struct ti_ohci *ohci1394_get_struct(int card_num) -{ - if (card_num>=0 && card_num<num_of_cards) - return &cards[card_num]; - return NULL; + if (msg) PRINT(KERN_ERR, ohci->id, "%s: dma prg stopped", msg); } int ohci1394_register_video(struct ti_ohci *ohci, @@ -2397,31 +2270,75 @@ if (ohci->video_tmpl != tmpl) { PRINT(KERN_ERR, ohci->id, "Trying to unregister wrong video device"); - } - else { + } else { ohci->video_tmpl = NULL; MOD_DEC_USE_COUNT; } } -#if 0 -int ohci_compare_swap(struct ti_ohci *ohci, quadlet_t *data, - quadlet_t compare, int sel) +#ifndef __LITTLE_ENDIAN + +/* Swap a series of quads inplace. */ +static __inline__ void block_swab32(quadlet_t *data, size_t size) { + while (size--) + data[size] = swab32(data[size]); +} + +/* Swap headers and sometimes data too */ +static void packet_swab(quadlet_t *data, char tcode, int len, int payload_swap) { - int timeout = 255; - reg_write(ohci, OHCI1394_CSRData, *data); - reg_write(ohci, OHCI1394_CSRCompareData, compare); - reg_write(ohci, OHCI1394_CSRControl, sel); - while(!(reg_read(ohci, OHCI1394_CSRControl)&0x80000000)) { - if (timeout--) { - PRINT(KERN_INFO, ohci->id, "request_channel timeout"); - return -1; - } + if (payload_swap) { + block_swab32(data, len); + return; } - *data = reg_read(ohci, OHCI1394_CSRData); - return 0; + + switch(tcode) + { + /* 4 quad header */ + case TCODE_READB_RESPONSE: + case TCODE_LOCK_RESPONSE: + case TCODE_LOCK_REQUEST: + case TCODE_WRITEB: + case TCODE_READB: + block_swab32(data, 4); + break; + + /* 3 quad header, 1 quad payload */ + case TCODE_WRITEQ: + case TCODE_READQ_RESPONSE: + block_swab32(data, 3); + break; + + /* 3 quad header */ + case TCODE_WRITE_RESPONSE: + case TCODE_READQ: + block_swab32(data, 3); + break; + + /* 2 quad header */ + case TCODE_ISO_DATA: + block_swab32(data, 2); + break; + + case OHCI1394_TCODE_PHY: + break; /* should never happen anyway */ + + case TCODE_CYCLE_START: + PRINT_G(KERN_ERR, "Unhandled tcode in packet_swab (0x%x)", tcode); + /* Atleast swap one quad */ + block_swab32(data, 1); + break; + default: + PRINT_G(KERN_ERR, "Invalid tcode in packet_swab (0x%x)\n", tcode); + break; + } + return; } +#endif /* !LITTLE_ENDIAN */ + + +#if 0 int ohci1394_request_channel(struct ti_ohci *ohci, int channel) { int csrSel; @@ -2464,37 +2381,49 @@ #endif EXPORT_SYMBOL(ohci1394_stop_context); -EXPORT_SYMBOL(ohci1394_get_struct); EXPORT_SYMBOL(ohci1394_register_video); EXPORT_SYMBOL(ohci1394_unregister_video); -#ifdef MODULE +MODULE_AUTHOR("Sebastien Rougeaux <sebastien.rougeaux@anu.edu.au>"); +MODULE_DESCRIPTION("Driver for PCI OHCI IEEE-1394 controllers"); -/* EXPORT_NO_SYMBOLS; */ +static void __devexit ohci1394_remove_one(struct pci_dev *pdev) +{ + struct ti_ohci *ohci = pci_get_drvdata(pdev); -MODULE_AUTHOR("Sebastien Rougeaux <sebastien.rougeaux@anu.edu.au>"); -MODULE_DESCRIPTION("driver for PCI Ohci IEEE-1394 controller"); -MODULE_SUPPORTED_DEVICE("ohci1394"); + if (ohci) { + remove_card (ohci); + pci_set_drvdata(pdev, NULL); + } +} + +static struct pci_driver ohci1394_driver = { + name: "ohci1394", + id_table: ohci1394_pci_tbl, + probe: ohci1394_add_one, + remove: ohci1394_remove_one, +}; -void cleanup_module(void) +static void __exit ohci1394_cleanup (void) { hpsb_unregister_lowlevel(get_ohci_template()); -#ifdef CONFIG_PROC_FS - remove_proc_entry ("ohci1394", NULL); -#endif - - PRINT_G(KERN_INFO, "removed " OHCI1394_DRIVER_NAME " module"); + pci_unregister_driver(&ohci1394_driver); } -int init_module(void) +static int __init ohci1394_init(void) { - memset(cards, 0, MAX_OHCI1394_CARDS * sizeof (struct ti_ohci)); - + int ret; if (hpsb_register_lowlevel(get_ohci_template())) { - PRINT_G(KERN_ERR, "registering failed"); + PRINT_G(KERN_ERR, "Registering failed"); return -ENXIO; - } - return 0; + } + if ((ret = pci_module_init(&ohci1394_driver))) { + PRINT_G(KERN_ERR, "PCI module init failed\n"); + hpsb_unregister_lowlevel(get_ohci_template()); + return ret; + } + return ret; } -#endif /* MODULE */ +module_init(ohci1394_init); +module_exit(ohci1394_cleanup); diff -u --recursive --new-file v2.4.6/linux/drivers/ieee1394/ohci1394.h linux/drivers/ieee1394/ohci1394.h --- v2.4.6/linux/drivers/ieee1394/ohci1394.h Tue Mar 6 19:28:32 2001 +++ linux/drivers/ieee1394/ohci1394.h Thu Jul 19 17:48:16 2001 @@ -23,94 +23,38 @@ #include "ieee1394_types.h" -#define IEEE1394_USE_BOTTOM_HALVES 1 - #define OHCI1394_DRIVER_NAME "ohci1394" -#define USE_DEVICE 0 - -#if USE_DEVICE - -#ifndef PCI_DEVICE_ID_TI_OHCI1394_LV22 -#define PCI_DEVICE_ID_TI_OHCI1394_LV22 0x8009 -#endif - -#ifndef PCI_DEVICE_ID_TI_OHCI1394_LV23 -#define PCI_DEVICE_ID_TI_OHCI1394_LV23 0x8019 -#endif - -#ifndef PCI_DEVICE_ID_TI_OHCI1394_LV26 -#define PCI_DEVICE_ID_TI_OHCI1394_LV26 0x8020 -#endif - -#ifndef PCI_DEVICE_ID_TI_OHCI1394_PCI4450 -#define PCI_DEVICE_ID_TI_OHCI1394_PCI4450 0x8011 -#endif - -#ifndef PCI_DEVICE_ID_VIA_OHCI1394 -#define PCI_DEVICE_ID_VIA_OHCI1394 0x3044 -#endif - -#ifndef PCI_VENDOR_ID_SONY -#define PCI_VENDOR_ID_SONY 0x104d -#endif - -#ifndef PCI_DEVICE_ID_SONY_CXD3222 -#define PCI_DEVICE_ID_SONY_CXD3222 0x8039 -#endif +#define OHCI1394_MAX_AT_REQ_RETRIES 0x2 +#define OHCI1394_MAX_AT_RESP_RETRIES 0x2 +#define OHCI1394_MAX_PHYS_RESP_RETRIES 0x8 +#define OHCI1394_MAX_SELF_ID_ERRORS 16 -#ifndef PCI_DEVICE_ID_NEC_1394 -#define PCI_DEVICE_ID_NEC_1394 0x00cd -#endif +#define AR_REQ_NUM_DESC 4 /* number of AR req descriptors */ +#define AR_REQ_BUF_SIZE PAGE_SIZE /* size of AR req buffers */ +#define AR_REQ_SPLIT_BUF_SIZE PAGE_SIZE /* split packet buffer */ -#ifndef PCI_DEVICE_ID_NEC_UPD72862 -#define PCI_DEVICE_ID_NEC_UPD72862 0x0063 -#endif +#define AR_RESP_NUM_DESC 4 /* number of AR resp descriptors */ +#define AR_RESP_BUF_SIZE PAGE_SIZE /* size of AR resp buffers */ +#define AR_RESP_SPLIT_BUF_SIZE PAGE_SIZE /* split packet buffer */ -#ifndef PCI_DEVICE_ID_NEC_UPD72870 -#define PCI_DEVICE_ID_NEC_UPD72870 0x00cd -#endif +#define IR_NUM_DESC 16 /* number of IR descriptors */ +#define IR_BUF_SIZE PAGE_SIZE /* 4096 bytes/buffer */ +#define IR_SPLIT_BUF_SIZE PAGE_SIZE /* split packet buffer */ -#ifndef PCI_DEVICE_ID_NEC_UPD72871 -#define PCI_DEVICE_ID_NEC_UPD72871 0x00ce -#endif +#define IT_NUM_DESC 16 /* number of IT descriptors */ -#ifndef PCI_DEVICE_ID_ALI_OHCI1394_M5251 -#define PCI_DEVICE_ID_ALI_OHCI1394_M5251 0x5251 -#endif +#define AT_REQ_NUM_DESC 32 /* number of AT req descriptors */ +#define AT_RESP_NUM_DESC 32 /* number of AT resp descriptors */ -#ifndef PCI_VENDOR_ID_LUCENT -#define PCI_VENDOR_ID_LUCENT 0x11c1 -#endif +#define OHCI_LOOP_COUNT 100 /* Number of loops for reg read waits */ -#ifndef PCI_DEVICE_ID_LUCENT_FW323 -#define PCI_DEVICE_ID_LUCENT_FW323 0x5811 -#endif +#define OHCI_CONFIG_ROM_LEN 1024 /* Length of the mapped configrom space */ -#endif /* USE_DEVICE */ +#define OHCI1394_SI_DMA_BUF_SIZE 8192 /* length of the selfid buffer */ - -#define MAX_OHCI1394_CARDS 4 - -#define OHCI1394_MAX_AT_REQ_RETRIES 0x2 -#define OHCI1394_MAX_AT_RESP_RETRIES 0x2 -#define OHCI1394_MAX_PHYS_RESP_RETRIES 0x8 -#define OHCI1394_MAX_SELF_ID_ERRORS 16 - -#define AR_REQ_NUM_DESC 4 /* number of AR req descriptors */ -#define AR_REQ_BUF_SIZE PAGE_SIZE /* size of AR req buffers */ -#define AR_REQ_SPLIT_BUF_SIZE PAGE_SIZE /* split packet buffer */ - -#define AR_RESP_NUM_DESC 4 /* number of AR resp descriptors */ -#define AR_RESP_BUF_SIZE PAGE_SIZE /* size of AR resp buffers */ -#define AR_RESP_SPLIT_BUF_SIZE PAGE_SIZE /* split packet buffer */ - -#define IR_NUM_DESC 16 /* number of IR descriptors */ -#define IR_BUF_SIZE PAGE_SIZE /* 4096 bytes/buffer */ -#define IR_SPLIT_BUF_SIZE PAGE_SIZE /* split packet buffer */ - -#define AT_REQ_NUM_DESC 32 /* number of AT req descriptors */ -#define AT_RESP_NUM_DESC 32 /* number of AT resp descriptors */ +/* PCI configuration space addresses */ +#define OHCI1394_PCI_HCI_Control 0x40 struct dma_cmd { u32 control; @@ -137,6 +81,7 @@ void *ohci; int ctx; unsigned int num_desc; + unsigned int buf_size; unsigned int split_buf_size; @@ -152,7 +97,7 @@ unsigned int buf_offset; quadlet_t *spb; spinlock_t lock; - struct tq_struct task; + struct tasklet_struct task; int ctrlClear; int ctrlSet; int cmdPtr; @@ -182,7 +127,7 @@ struct hpsb_packet *pending_last; spinlock_t lock; - struct tq_struct task; + struct tasklet_struct task; int ctrlClear; int ctrlSet; int cmdPtr; @@ -198,6 +143,8 @@ struct ti_ohci { int id; /* sequential card number */ + struct list_head list; + struct pci_dev *dev; u32 state; @@ -229,6 +176,7 @@ int nb_iso_rcv_ctx; /* iso transmit */ + struct dma_trm_ctx *it_context; int nb_iso_xmit_ctx; u64 ISO_channel_usage; @@ -239,12 +187,18 @@ int phyid, isroot; spinlock_t phy_reg_lock; + spinlock_t event_lock; int self_id_errors; int NumBusResets; /* video device */ struct video_template *video_tmpl; + + /* Swap the selfid buffer? */ + unsigned int selfid_swap:1; + /* Swap the payload? */ + unsigned int payload_swap:1; }; static inline int cross_bound(unsigned long addr, unsigned int size) diff -u --recursive --new-file v2.4.6/linux/drivers/ieee1394/pcilynx.c linux/drivers/ieee1394/pcilynx.c --- v2.4.6/linux/drivers/ieee1394/pcilynx.c Tue Mar 20 15:42:18 2001 +++ linux/drivers/ieee1394/pcilynx.c Fri Jul 20 12:47:31 2001 @@ -25,6 +25,7 @@ #include <linux/wait.h> #include <linux/errno.h> #include <linux/module.h> +#include <linux/init.h> #include <linux/pci.h> #include <linux/fs.h> #include <linux/poll.h> @@ -359,7 +360,7 @@ } if (q[0] == ~q[1]) { - PRINT(KERN_DEBUG, lynx->id, "selfid packet 0x%x rcvd", + PRINT(KERN_DEBUG, lynx->id, "SelfID packet 0x%x rcvd", q[0]); hpsb_selfid_received(host, q[0]); } else { @@ -598,7 +599,7 @@ unsigned long flags; if (packet->data_size >= 4096) { - PRINT(KERN_ERR, lynx->id, "transmit packet data too big (%d)", + PRINT(KERN_ERR, lynx->id, "transmit packet data too big (%Zd)", packet->data_size); return 0; } @@ -770,7 +771,7 @@ static struct file_operations aux_ops = { - OWNER_THIS_MODULE + owner: THIS_MODULE, read: mem_read, write: mem_write, poll: aux_poll, @@ -795,23 +796,18 @@ enum { t_rom, t_aux, t_ram } type; struct memdata *md; - V22_COMPAT_MOD_INC_USE_COUNT; - if (cid < PCILYNX_MINOR_AUX_START) { /* just for completeness */ - V22_COMPAT_MOD_DEC_USE_COUNT; return -ENXIO; } else if (cid < PCILYNX_MINOR_ROM_START) { cid -= PCILYNX_MINOR_AUX_START; if (cid >= num_of_cards || !cards[cid].aux_port) { - V22_COMPAT_MOD_DEC_USE_COUNT; return -ENXIO; } type = t_aux; } else if (cid < PCILYNX_MINOR_RAM_START) { cid -= PCILYNX_MINOR_ROM_START; if (cid >= num_of_cards || !cards[cid].local_rom) { - V22_COMPAT_MOD_DEC_USE_COUNT; return -ENXIO; } type = t_rom; @@ -820,17 +816,16 @@ * It is currently used inside the driver! */ cid -= PCILYNX_MINOR_RAM_START; if (cid >= num_of_cards || !cards[cid].local_ram) { - V22_COMPAT_MOD_DEC_USE_COUNT; return -ENXIO; } type = t_ram; } md = (struct memdata *)kmalloc(sizeof(struct memdata), SLAB_KERNEL); - if (md == NULL) { - V22_COMPAT_MOD_DEC_USE_COUNT; + if (md == NULL) return -ENOMEM; - } + + MOD_INC_USE_COUNT; md->lynx = &cards[cid]; md->cid = cid; @@ -860,7 +855,7 @@ kfree(md); - V22_COMPAT_MOD_DEC_USE_COUNT; + MOD_DEC_USE_COUNT; return 0; } @@ -1108,6 +1103,8 @@ PRINTD(KERN_DEBUG, lynx->id, "interrupt: 0x%08x / 0x%08x", intmask, linkint); + if (!(intmask & PCI_INT_INT_PEND)) return; + reg_write(lynx, LINK_INT_STATUS, linkint); reg_write(lynx, PCI_INT_STATUS, intmask); @@ -1354,6 +1351,7 @@ lynx->id = num_of_cards-1; lynx->dev = dev; + lynx->host->pdev = dev; lynx->lock = SPIN_LOCK_UNLOCKED; lynx->phy_reg_lock = SPIN_LOCK_UNLOCKED; @@ -1466,9 +1464,8 @@ init_waitqueue_head(&lynx->aux_intr_wait); #endif - INIT_TQ_LINK(lynx->iso_rcv.tq); - lynx->iso_rcv.tq.routine = (void (*)(void*))iso_rcv_bh; - lynx->iso_rcv.tq.data = lynx; + INIT_TQUEUE(&lynx->iso_rcv.tq, (void (*)(void*))iso_rcv_bh, lynx); + lynx->iso_rcv.lock = SPIN_LOCK_UNLOCKED; lynx->async.queue_lock = SPIN_LOCK_UNLOCKED; @@ -1596,21 +1593,17 @@ } -#ifdef MODULE - -/* EXPORT_NO_SYMBOLS; */ - MODULE_AUTHOR("Andreas E. Bombe <andreas.bombe@munich.netsurf.de>"); MODULE_DESCRIPTION("driver for Texas Instruments PCI Lynx IEEE-1394 controller"); MODULE_SUPPORTED_DEVICE("pcilynx"); -void cleanup_module(void) +static void __exit pcilynx_cleanup(void) { hpsb_unregister_lowlevel(get_lynx_template()); PRINT_G(KERN_INFO, "removed " PCILYNX_DRIVER_NAME " module"); } -int init_module(void) +static int __init pcilynx_init(void) { if (hpsb_register_lowlevel(get_lynx_template())) { PRINT_G(KERN_ERR, "registering failed"); @@ -1620,4 +1613,5 @@ } } -#endif /* MODULE */ +module_init(pcilynx_init); +module_exit(pcilynx_cleanup); diff -u --recursive --new-file v2.4.6/linux/drivers/ieee1394/raw1394.c linux/drivers/ieee1394/raw1394.c --- v2.4.6/linux/drivers/ieee1394/raw1394.c Sun Feb 4 21:34:18 2001 +++ linux/drivers/ieee1394/raw1394.c Thu Jul 19 17:48:16 2001 @@ -16,13 +16,12 @@ #include <linux/fs.h> #include <linux/poll.h> #include <linux/module.h> +#include <linux/init.h> #include <linux/version.h> #include <linux/smp_lock.h> #include <asm/uaccess.h> -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,0) #include <linux/devfs_fs_kernel.h> -#endif #include "ieee1394.h" #include "ieee1394_types.h" @@ -64,8 +63,7 @@ if (req != NULL) { memset(req, 0, sizeof(struct pending_request)); INIT_LIST_HEAD(&req->list); - INIT_TQ_LINK(req->tq); - req->tq.routine = (void(*)(void*))queue_complete_cb; + INIT_TQUEUE(&req->tq, (void(*)(void*))queue_complete_cb, NULL); } return req; @@ -605,7 +603,7 @@ break; } - req->req.error = highlevel_write(fi->host, node, req->data, + req->req.error = highlevel_write(fi->host, node, node, req->data, addr, req->req.length); req->req.length = 0; break; @@ -650,8 +648,11 @@ req->req.error = RAW1394_ERROR_STATE_ORDER; } - if (req->req.error) req->req.length = 0; - req->req.error |= 0x00100000; + if (req->req.error) + req->req.length = 0; + if (req->req.error >= 0) + req->req.error |= ACK_PENDING << 16; + queue_complete_req(req); return sizeof(struct raw1394_request); } @@ -827,7 +828,7 @@ return sizeof(struct raw1394_request); case RAW1394_REQ_RESET_BUS: - hpsb_reset_bus(fi->host); + hpsb_reset_bus(fi->host, LONG_RESET); return sizeof(struct raw1394_request); } @@ -912,14 +913,14 @@ return -ENXIO; } - V22_COMPAT_MOD_INC_USE_COUNT; + MOD_INC_USE_COUNT; fi = kmalloc(sizeof(struct file_info), SLAB_KERNEL); if (fi == NULL) { - V22_COMPAT_MOD_DEC_USE_COUNT; + MOD_DEC_USE_COUNT; return -ENOMEM; } - + memset(fi, 0, sizeof(struct file_info)); INIT_LIST_HEAD(&fi->list); @@ -986,7 +987,7 @@ kfree(fi); - V22_COMPAT_MOD_DEC_USE_COUNT; + MOD_DEC_USE_COUNT; unlock_kernel(); return 0; } @@ -1000,7 +1001,7 @@ }; static struct file_operations file_ops = { - OWNER_THIS_MODULE + owner: THIS_MODULE, read: dev_read, write: dev_write, poll: dev_poll, @@ -1008,7 +1009,7 @@ release: dev_release, }; -int init_raw1394(void) +static int __init init_raw1394(void) { hl_handle = hpsb_register_highlevel(RAW1394_DEVICE_NAME, &hl_ops); if (hl_handle == NULL) { @@ -1030,23 +1031,12 @@ return 0; } -void cleanup_raw1394(void) +static void __exit cleanup_raw1394(void) { devfs_unregister_chrdev(RAW1394_DEVICE_MAJOR, RAW1394_DEVICE_NAME); devfs_unregister(devfs_handle); hpsb_unregister_highlevel(hl_handle); } -#ifdef MODULE - -int init_module(void) -{ - return init_raw1394(); -} - -void cleanup_module(void) -{ - return cleanup_raw1394(); -} - -#endif +module_init(init_raw1394); +module_exit(cleanup_raw1394); diff -u --recursive --new-file v2.4.6/linux/drivers/ieee1394/sbp2.c linux/drivers/ieee1394/sbp2.c --- v2.4.6/linux/drivers/ieee1394/sbp2.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/ieee1394/sbp2.c Thu Jul 19 17:48:16 2001 @@ -0,0 +1,3588 @@ +/* + * sbp2.c - SBP-2 protocol driver for IEEE-1394 + * + * Copyright (C) 2000 James Goodwin, Filanet Corporation (www.filanet.com) + * jamesg@filanet.com + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* + * Brief Description: + * + * This driver implements the Serial Bus Protocol 2 (SBP-2) over IEEE-1394 + * under Linux. The SBP-2 driver is implemented as an IEEE-1394 high-level + * driver. It also registers as a SCSI lower-level driver in order to accept + * SCSI commands for transport using SBP-2. + * + * Driver Loading: + * + * Currently, the SBP-2 driver is supported only as a module. Because the + * Linux SCSI stack is not Plug-N-Play aware, module load order is + * important. Assuming the SCSI core drivers are either built into the + * kernel or already loaded as modules, you should load the IEEE-1394 modules + * in the following order: + * + * ieee1394 (e.g. insmod ieee1394) + * ohci1394 (e.g. insmod ohci1394) + * sbp2 (e.g. insmod sbp2) + * + * The SBP-2 driver will attempt to discover any attached SBP-2 devices when first + * loaded, or after any IEEE-1394 bus reset (e.g. a hot-plug). It will then print + * out a debug message indicating if it was able to discover a SBP-2 device. + * + * Currently, the SBP-2 driver will catch any attached SBP-2 devices during the + * initial scsi bus scan (when the driver is first loaded). To add or remove + * SBP-2 devices after this initial scan (i.e. if you plug-in or un-plug a + * device after the SBP-2 driver is loaded), you must either use the scsi procfs + * add-single-device, remove-single-device, or a shell script such as + * rescan-scsi-bus.sh. + * + * The easiest way to add/detect new SBP-2 devices is to run the shell script + * rescan-scsi-bus.sh (or re-load the SBP-2 driver). This script may be + * found at: + * http://www.garloff.de/kurt/linux/rescan-scsi-bus.sh + * + * As an alternative, you may manually add/remove SBP-2 devices via the procfs with + * add-single-device <h> <b> <t> <l> or remove-single-device <h> <b> <t> <l>, where: + * <h> = host (starting at zero for first SCSI adapter) + * <b> = bus (normally zero) + * <t> = target (starting at zero for first SBP-2 device) + * <l> = lun (normally zero) + * + * e.g. To manually add/detect a new SBP-2 device + * echo "scsi add-single-device 0 0 0 0" > /proc/scsi/scsi + * + * e.g. To manually remove a SBP-2 device after it's been unplugged + * echo "scsi remove-single-device 0 0 0 0" > /proc/scsi/scsi + * + * e.g. To check to see which SBP-2/SCSI devices are currently registered + * cat /proc/scsi/scsi + * + * After scanning for new SCSI devices (above), you may access any attached + * SBP-2 storage devices as if they were SCSI devices (e.g. mount /dev/sda1, + * fdisk, mkfs, etc.). + * + * + * Module Load Options: + * + * The SBP-2 driver now has a number of module load parameters available for use + * in debugging/testing. Following are the valid parameters + * + * no_bus_scan - Skip the initial scsi bus scan during module load + * (1 = skip bus scan, 0 = perform bus scan, default = 0) + * + * mode_sense_hack - Emulate mode sense for devices like 1394 memory stick readers + * (1 = emulate/fake mode sense, 0 = do not emulate/fake mode sense, default = 0) + * + * max_speed - Force max speed allowed + * (0 = 100mb, 1 = 200mb, 2 = 400mb, default = auto configure) + * + * serialize_io - Force scsi stack to send down one command at a time, for debugging + * (1 = serialize all I/O, 0 = do not serialize I/O, default = 1) + * + * no_large_packets - Force scsi stack to limit max packet size sent down, for debugging + * (1 = limit max transfer size, 0 = do not limit max packet size, default = 0) + * + * (e.g. insmod sbp2 no_bus_scan=1) + * + * + * Current Support: + * + * The SBP-2 driver is still in an early state, but supports a variety of devices. + * I have read/written many gigabytes of data from/to SBP-2 drives, and have seen + * performance of more than 16 MBytes/s on individual drives (limit of the media + * transfer rate). + * + * Following are the devices that have been tested successfully: + * + * - Western Digital IEEE-1394 hard drives + * - Maxtor IEEE-1394 hard drives + * - VST (SmartDisk) IEEE-1394 hard drives and Zip drives (several flavors) + * - LaCie IEEE-1394 hard drives (several flavors) + * - QPS IEEE-1394 CD-RW/DVD drives and hard drives + * - BusLink IEEE-1394 hard drives + * - Iomega IEEE-1394 Zip/Jazz drives + * - ClubMac IEEE-1394 hard drives + * - FirePower IEEE-1394 hard drives + * - EzQuest IEEE-1394 hard drives and CD-RW drives + * - Castlewood/ADS IEEE-1394 ORB drives + * - Evergreen IEEE-1394 hard drives and CD-RW drives + * - Addonics IEEE-1394 CD-RW drives + * - Bellstor IEEE-1394 hard drives and CD-RW drives + * - APDrives IEEE-1394 hard drives + * - Fujitsu IEEE-1394 MO drives + * - Sony IEEE-1394 CD-RW drives + * - Epson IEEE-1394 scanner + * - ADS IEEE-1394 memory stick and compact flash readers + * (e.g. "insmod sbp2 mode_sense_hack=1" for mem stick and flash readers)) + * - SBP-2 bridge-based devices (LSI, Oxford Semiconductor, Indigita bridges) + * - Various other standard IEEE-1394 hard drives and enclosures + * + * + * Performance Issues: + * + * - Make sure you are "not" running fat/fat32 on your attached SBP-2 drives. You'll + * get much better performance formatting the drive ext2 (but you will lose the + * ability to easily move the drive between Windows/Linux). + * + * + * Current Issues: + * + * - Currently, all I/O from the scsi stack is serialized by default, as there + * are some stress issues under investigation with deserialized I/O. To enable + * deserialized I/O for testing, do "insmod sbp2 serialize_io=0" + * + * - Hot-Plugging: Need to add procfs support and integration with linux + * hot-plug support (http://linux-hotplug.sourceforge.net) for auto-mounting + * of drives. + * + * - Error Handling: SCSI aborts and bus reset requests are handled somewhat + * but the code needs additional debugging. + * + * - IEEE-1394 Bus Management: There is currently little bus management + * in the core IEEE-1394 stack. Because of this, the SBP-2 driver handles + * detection of SBP-2 devices itself. This should be moved to the core + * stack. + * + * - The SBP-2 driver is currently only supported as a module. It would not take + * much work to allow it to be compiled into the kernel, but you'd have to + * add some init code to the kernel to support this... and modules are much + * more flexible anyway. ;-) + * + * - Workaround for PPC pismo firewire chipset (enable SBP2_PPC_PISMO_WORKAROUND + * define below). + * + * + * Core IEEE-1394 Stack Changes: + * + * - The IEEE-1394 core stack guid code attempts to read the node unique id from + * each attached device after a bus reset. It currently uses a block read + * request to do this, which "upsets" certain not-well-behaved devices, such as + * some drives from QPS. If you have trouble with your IEEE-1394 storage + * device being detected after loading sbp2, try commenting out the + * init_ieee1394_guid() and cleanup_ieee1394_guid() lines at the bottom of + * ieee1394_core.c (and rebuild ieee1394.o). + * + * - In ohci1394.h, remove the IEEE1394_USE_BOTTOM_HALVES #define, and rebuild. + * This will give you around 30% to 40% performance increase. + * + * + * History: + * + * 07/25/00 - Initial revision (JSG) + * 08/11/00 - Following changes/bug fixes were made (JSG): + * * Bug fix to SCSI procfs code (still needs to be synched with 2.4 kernel). + * * Bug fix where request sense commands were actually sent on the bus. + * * Changed bus reset/abort code to deal with devices that spin up quite + * slowly (which result in SCSI time-outs). + * * "More" properly pull information from device's config rom, for enumeration + * of SBP-2 devices, and determining SBP-2 register offsets. + * * Change Simplified Direct Access Device type to Direct Access Device type in + * returned inquiry data, in order to make the SCSI stack happy. + * * Modified driver to register with the SCSI stack "before" enumerating any attached + * SBP-2 devices. This means that you'll have to use procfs scsi-add-device or + * some sort of script to discover new SBP-2 devices. + * * Minor re-write of some code and other minor changes. + * 08/28/00 - Following changes/bug fixes were made (JSG): + * * Bug fixes to scatter/gather support (case of one s/g element) + * * Updated direction table for scsi commands (mostly DVD commands) + * * Retries when trying to detect SBP-2 devices (for slow devices) + * * Slightly better error handling (previously none) when commands time-out. + * * Misc. other bug fixes and code reorganization. + * 09/13/00 - Following changes/bug fixes were made (JSG) + * * Moved detection/enumeration code to a kernel thread which is woken up when IEEE-1394 + * bus resets occur. + * * Added code to handle bus resets and hot-plugging while devices are mounted, but full + * hot-plug support is not quite there yet. + * * Now use speed map to determine speed and max payload sizes for ORBs + * * Clean-up of code and reorganization + * 09/19/00 - Added better hot-plug support and other minor changes (JSG) + * 10/15/00 - Fixes for latest 2.4.0 test kernel, minor fix for hot-plug race. (JSG) + * 12/03/00 - Created pool of request packet structures for use in sending out sbp2 command + * and agent reset requests. This removes the kmallocs/kfrees in the critical I/O paths, + * and also deals with some subtle race conditions related to allocating and freeing + * packets. (JSG) + * 12/09/00 - Improved the sbp2 device detection by actually reading the root and unit + * directory (khk@khk.net) + * 12/23/00 - Following changes/enhancements were made (JSG) + * * Only do SCSI to RBC command conversion for Direct Access and Simplified + * Direct Access Devices (this is pulled from the config rom root directory). + * This is needed because doing the conversion for all device types broke the + * Epson scanner. Still looking for a better way of determining when to convert + * commands (for RBC devices). Thanks to khk for helping on this! + * * Added ability to "emulate" physical dma support, for host adapters such as TILynx. + * * Determine max payload and speed by also looking at the host adapter's max_rec field. + * 01/19/01 - Added checks to sbp2 login and made the login time-out longer. Also fixed a compile + * problem for 2.4.0. (JSG) + * 01/24/01 - Fixed problem when individual s/g elements are 64KB or larger. Needed to break + * up these larger elements, since the sbp2 page table element size is only 16 bits. (JSG) + * 01/29/01 - Minor byteswap fix for login response (used for reconnect and log out). + * 03/07/01 - Following changes/enhancements were made (JSG) + * * Changes to allow us to catch the initial scsi bus scan (for detecting sbp2 + * devices when first loading sbp2.o). To disable this, un-define + * SBP2_SUPPORT_INITIAL_BUS_SCAN. + * * Temporary fix to deal with many sbp2 devices that do not support individual + * transfers of greater than 128KB in size. + * * Mode sense conversion from 6 byte to 10 byte versions for CDRW/DVD devices. (Mark Burton) + * * Define allowing support for goofy sbp2 devices that do not support mode + * sense command at all, allowing them to be mounted rw (such as 1394 memory + * stick and compact flash readers). Define SBP2_MODE_SENSE_WRITE_PROTECT_HACK + * if you need this fix. + * 03/29/01 - Major performance enhancements and misc. other changes. Thanks to Daniel Berlin for many of + * changes and suggestions for change: + * * Now use sbp2 doorbell and link commands on the fly (instead of serializing requests) + * * Removed all bit fields in an attempt to run on PPC machines (still needs a little more work) + * * Added large request break-up/linking support for sbp2 chipsets that do not support transfers + * greater than 128KB in size. + * * Bumped up max commands per lun to two, and max total outstanding commands to eight. + * 04/03/01 - Minor clean-up. Write orb pointer directly if no outstanding commands (saves one 1394 bus + * transaction). Added module load options (bus scan, mode sense hack, max speed, serialize_io, + * no_large_transfers). Better bus reset handling while I/O pending. Set serialize_io to 1 by + * default (debugging of deserialized I/O in progress). + * 04/04/01 - Added workaround for PPC Pismo firewire chipset. See #define below. (Daniel Berlin) + * 04/20/01 - Minor clean-up. Allocate more orb structures when running with sbp2 target chipsets with + * 128KB max transfer limit. + * 06/16/01 - Converted DMA interfaces to pci_dma - Ben Collins + * <bcollins@debian.org + */ + +/* + * Includes + */ + +#include <linux/config.h> +#include <linux/kernel.h> +#include <linux/list.h> +#include <linux/string.h> +#include <linux/slab.h> +#include <linux/fs.h> +#include <linux/poll.h> +#include <linux/module.h> +#include <linux/types.h> +#include <linux/delay.h> +#include <linux/sched.h> +#include <linux/proc_fs.h> +#include <linux/blk.h> +#include <linux/smp_lock.h> +#include <asm/current.h> +#include <asm/uaccess.h> +#include <asm/io.h> +#include <asm/byteorder.h> +#include <asm/system.h> +#include <asm/io.h> +#include <asm/scatterlist.h> + +#include "ieee1394.h" +#include "ieee1394_types.h" +#include "ieee1394_core.h" +#include "hosts.h" +#include "highlevel.h" +#include "ieee1394_transactions.h" +#include "../scsi/scsi.h" +#include "../scsi/hosts.h" +#include "../scsi/sd.h" +#include "sbp2.h" + +/* + * PPC firewire Pismo chipset workaround!!! + * + * This is a workaround for a bug in the firewire pismo chipset. For some odd reason the status + * fifo address hi/lo must be byteswapped and the response address byteswapped, but no other + * parts of the structure. Apple's drivers seem to specifically check for the pismo and do + * the same workaround for sbp2. (Daniel Berlin) + * + * Please enable the following define if you're running on the PPC Pismo chipset. + */ + +#ifdef CONFIG_IEEE1394_SBP2_PISMO +#define SBP2_NEED_LOGIN_DESCRIPTOR_WORKAROUND +#endif + +/* + * Module load parameter definitions + */ + +/* + * Normally the sbp2 driver tries to catch the initial scsi bus scan to pick up any + * attached sbp2 devices. Setting no_bus_scan to 1 tells the sbp2 driver not to catch + * this initial scsi bus scan on module load. You can always either add or remove devices + * later through the rescan-scsi-bus.sh script or scsi procfs. + */ +MODULE_PARM(no_bus_scan,"i"); +MODULE_PARM_DESC(no_bus_scan, "Skip the initial scsi bus scan during module load"); +static int no_bus_scan = 0; + +/* + * Set mode_sense_hack to 1 if you have some sort of unusual sbp2 device, like a 1394 memory + * stick reader, compact flash reader, or MO drive that does not support mode sense. Allows + * you to mount the media rw instead of ro. + */ +MODULE_PARM(mode_sense_hack,"i"); +MODULE_PARM_DESC(mode_sense_hack, "Emulate mode sense for devices like 1394 memory stick readers"); +static int mode_sense_hack = 0; + +/* + * Change max_speed on module load if you have a bad IEEE-1394 controller that has trouble running + * 2KB packets at 400mb. + * + * NOTE: On certain OHCI parts I have seen short packets on async transmit (probably + * due to PCI latency/throughput issues with the part). You can bump down the speed if + * you are running into problems. + * + * Valid values: + * max_speed = 2 (default: max speed 400mb) + * max_speed = 1 (max speed 200mb) + * max_speed = 0 (max speed 100mb) + */ +MODULE_PARM(max_speed,"i"); +MODULE_PARM_DESC(max_speed, "Force down max speed (2 = 400mb default, 1 = 200mb, 0 = 100mb)"); +static int max_speed = SPEED_S400; + +/* + * Set serialize_io to 1 if you'd like only one scsi command sent down to us at a time (debugging). + */ +MODULE_PARM(serialize_io,"i"); +MODULE_PARM_DESC(serialize_io, "Serialize all I/O coming down from the scsi drivers (debugging)"); +static int serialize_io = 1; /* serialize I/O until stress issues are resolved */ + +/* + * Set no_large_packets to 1 if you'd like to limit the size of requests sent down to us (normally + * the sbp2 driver will break up any requests to any individual devices with 128KB transfer size limits). + * Sets max s/g list elements to 0x1f in size and disables s/g clustering. + */ +MODULE_PARM(no_large_packets,"i"); +MODULE_PARM_DESC(no_large_packets, "Do not allow large transfers from scsi drivers (debugging)"); +static int no_large_packets = 0; + +/* + * Debug levels, configured via kernel config. + */ + +#ifdef CONFIG_IEEE1394_SBP2_DEBUG_ORBS +#define SBP2_ORB_DEBUG(fmt, args...) HPSB_ERR("sbp2("__FUNCTION__"): "fmt, ## args) +u32 global_outstanding_command_orbs = 0; +#define outstanding_orb_incr global_outstanding_command_orbs++ +#define outstanding_orb_decr global_outstanding_command_orbs-- +#else +#define SBP2_ORB_DEBUG(fmt, args...) +#define outstanding_orb_incr +#define outstanding_orb_decr +#endif + +#ifdef CONFIG_IEEE1394_SBP2_DEBUG_DMA +#define SBP2_DMA_ALLOC(fmt, args...) \ + HPSB_ERR("sbp2("__FUNCTION__")alloc(%d): "fmt, \ + ++global_outstanding_dmas, ## args) +#define SBP2_DMA_FREE(fmt, args...) \ + HPSB_ERR("sbp2("__FUNCTION__")free(%d): "fmt, \ + --global_outstanding_dmas, ## args) +u32 global_outstanding_dmas = 0; +#else +#define SBP2_DMA_ALLOC(fmt, args...) +#define SBP2_DMA_FREE(fmt, args...) +#endif + +#if CONFIG_IEEE1394_SBP2_DEBUG >= 2 +#define SBP2_DEBUG(fmt, args...) HPSB_ERR(fmt, ## args) +#define SBP2_INFO(fmt, args...) HPSB_ERR(fmt, ## args) +#define SBP2_NOTICE(fmt, args...) HPSB_ERR(fmt, ## args) +#define SBP2_WARN(fmt, args...) HPSB_ERR(fmt, ## args) +#elif CONFIG_IEEE1394_SBP2_DEBUG == 1 +#define SBP2_DEBUG(fmt, args...) HPSB_DEBUG(fmt, ## args) +#define SBP2_INFO(fmt, args...) HPSB_INFO(fmt, ## args) +#define SBP2_NOTICE(fmt, args...) HPSB_NOTICE(fmt, ## args) +#define SBP2_WARN(fmt, args...) HPSB_WARN(fmt, ## args) +#else +#define SBP2_DEBUG(fmt, args...) +#define SBP2_INFO(fmt, args...) +#define SBP2_NOTICE(fmt, args...) +#define SBP2_WARN(fmt, args...) +#endif + +#define SBP2_ERR(fmt, args...) HPSB_ERR(fmt, ## args) + +/* + * Spinlock debugging stuff. I'm playing it safe until the driver has been debugged on SMP. (JSG) + */ +/* #define SBP2_USE_REAL_SPINLOCKS */ +#ifdef SBP2_USE_REAL_SPINLOCKS +#define sbp2_spin_lock(lock, flags) spin_lock_irqsave(lock, flags) +#define sbp2_spin_unlock(lock, flags) spin_unlock_irqrestore(lock, flags); +#else +#define sbp2_spin_lock(lock, flags) do {save_flags(flags); cli();} while (0) +#define sbp2_spin_unlock(lock, flags) do {restore_flags(flags);} while (0) +#endif + +/* + * Globals + */ + +Scsi_Host_Template *global_scsi_tpnt = NULL; + +LIST_HEAD(sbp2_host_info_list); +static int sbp2_host_count = 0; +spinlock_t sbp2_host_info_lock = SPIN_LOCK_UNLOCKED; + +static struct hpsb_highlevel *sbp2_hl_handle = NULL; + +static struct hpsb_highlevel_ops sbp2_hl_ops = { + sbp2_add_host, + sbp2_remove_host, + sbp2_host_reset, + NULL, + NULL +}; + +static struct hpsb_address_ops sbp2_ops = { + write: sbp2_handle_status_write, +}; + +#if 0 +static struct hpsb_address_ops sbp2_physdma_ops = { + read: sbp2_handle_physdma_read, + write: sbp2_handle_physdma_write, +}; +#endif + +/************************************** + * General utility functions + **************************************/ + + +#ifndef __BIG_ENDIAN +/* + * Converts a buffer from be32 to cpu byte ordering. Length is in bytes. + */ +static __inline__ void sbp2util_be32_to_cpu_buffer(void *buffer, int length) +{ + u32 *temp = buffer; + + for (length = (length >> 2); length--; ) + temp[length] = be32_to_cpu(temp[length]); + + return; +} + +/* + * Converts a buffer from cpu to be32 byte ordering. Length is in bytes. + */ +static __inline__ void sbp2util_cpu_to_be32_buffer(void *buffer, int length) +{ + u32 *temp = buffer; + + for (length = (length >> 2); length--; ) + temp[length] = cpu_to_be32(temp[length]); + + return; +} +#else /* BIG_ENDIAN */ +/* Why waste the cpu cycles? */ +#define sbp2util_be32_to_cpu_buffer(x,y) +#define sbp2util_cpu_to_be32_buffer(x,y) +#endif + +/* + * This function does quadlet sized reads (used by detection code) + */ +static int sbp2util_read_quadlet(struct sbp2scsi_host_info *hi, nodeid_t node, u64 addr, + quadlet_t *buffer) +{ + int retval = 0; + int retry_count = 3; + + /* + * Retry a couple times if needed (for slow devices) + */ + do { + + retval = hpsb_read(hi->host, node, addr, buffer, 4); + + if (retval) { + SBP2_DEBUG("sbp2: sbp2util_read_quadlet data packet error"); + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(HZ/50); /* 20ms delay */ + } + + retry_count--; + + } while (retval && retry_count); + + return(retval); +} + +/* + * This function returns the address of the unit directory. + */ +static int sbp2util_unit_directory(struct sbp2scsi_host_info *hi, nodeid_t node_id, u64 *unit_directory_addr) +{ + quadlet_t root_directory_length, current_quadlet; + u64 current_addr; + int length, i; + + /* + * First, read the first quadlet of the root directory to determine its size + */ + if (sbp2util_read_quadlet(hi, LOCAL_BUS | node_id, CONFIG_ROM_ROOT_DIR_BASE, + &root_directory_length)) { + SBP2_DEBUG("sbp2: Error reading root directory length - bad status"); + return(-EIO); + } + + current_addr = CONFIG_ROM_ROOT_DIR_BASE; + length = be32_to_cpu(root_directory_length) >> 16; + + /* + * Step through the root directory and look for the "Unit_Directory entry", which + * contains the offset to the unit directory. + */ + for (i=0; i < length; i++) { + + current_addr += 4; + + if (sbp2util_read_quadlet(hi, LOCAL_BUS | node_id, current_addr, ¤t_quadlet)) { + SBP2_DEBUG("sbp2: Error reading at address 0x%08x%08x - bad status", + (unsigned int) ((current_addr) >> 32), (unsigned int) ((current_addr) & 0xffffffff)); + return(-EIO); + } + + /* + * Check for unit directory offset tag + */ + if ((be32_to_cpu(current_quadlet) >> 24) == SBP2_UNIT_DIRECTORY_OFFSET_KEY) { + *unit_directory_addr = current_addr + 4 * ((be32_to_cpu(current_quadlet) & 0xffffff)); + SBP2_DEBUG("sbp2: unit_directory_addr = %lu", *unit_directory_addr); + } + } + + return(0); +} + +/* + * This function is called to initially create a packet pool for use in sbp2 I/O requests. + * This packet pool is used when sending out sbp2 command and agent reset requests, and + * allows us to remove all kmallocs/kfrees from the critical I/O paths. + */ +static int sbp2util_create_request_packet_pool(struct sbp2scsi_host_info *hi) +{ + struct hpsb_packet *packet; + int i; + unsigned long flags; + + /* + * Create SBP2_MAX_REQUEST_PACKETS number of request packets. + */ + sbp2_spin_lock(&hi->sbp2_request_packet_lock, flags); + for (i=0; i<SBP2_MAX_REQUEST_PACKETS; i++) { + + /* + * Max payload of 8 bytes since the sbp2 command request uses a payload of + * 8 bytes, and agent reset is a quadlet write request. Bump this up if we + * plan on using this pool for other stuff. + */ + packet = alloc_hpsb_packet(8); + + if (!packet) { + SBP2_ERR("sbp2: sbp2util_create_request_packet_pool - packet allocation failed!"); + sbp2_spin_unlock(&hi->sbp2_request_packet_lock, flags); + return(-ENOMEM); + } + + /* + * Put these request packets into a free list + */ + INIT_LIST_HEAD(&hi->request_packet[i].list); + hi->request_packet[i].packet = packet; + list_add_tail(&hi->request_packet[i].list, &hi->sbp2_req_free); + + } + sbp2_spin_unlock(&hi->sbp2_request_packet_lock, flags); + + return(0); +} + +/* + * This function is called to remove the packet pool. It is called when the sbp2 driver is unloaded. + */ +static void sbp2util_remove_request_packet_pool(struct sbp2scsi_host_info *hi) +{ + struct list_head *lh; + struct sbp2_request_packet *request_packet; + unsigned long flags; + + /* + * Go through free list releasing packets + */ + sbp2_spin_lock(&hi->sbp2_request_packet_lock, flags); + while (!list_empty(&hi->sbp2_req_free)) { + + lh = hi->sbp2_req_free.next; + list_del(lh); + + request_packet = list_entry(lh, struct sbp2_request_packet, list); + + /* + * Free the hpsb packets that we allocated for the pool + */ + if (request_packet) { + free_hpsb_packet(request_packet->packet); + } + + } + sbp2_spin_unlock(&hi->sbp2_request_packet_lock, flags); + + return; +} + +/* + * This function is called to retrieve a block write packet from our packet pool. This function is + * used in place of calling alloc_hpsb_packet (which costs us three kmallocs). Instead we + * just pull out a free request packet and re-initialize values in it. I'm sure this can still + * stand some more optimization. + */ +static struct sbp2_request_packet *sbp2util_allocate_write_request_packet(struct sbp2scsi_host_info *hi, + nodeid_t node, u64 addr, + size_t data_size, + quadlet_t data) { + struct list_head *lh; + struct sbp2_request_packet *request_packet = NULL; + struct hpsb_packet *packet; + unsigned long flags; + + sbp2_spin_lock(&hi->sbp2_request_packet_lock, flags); + if (!list_empty(&hi->sbp2_req_free)) { + + /* + * Pull out a free request packet + */ + lh = hi->sbp2_req_free.next; + list_del(lh); + + request_packet = list_entry(lh, struct sbp2_request_packet, list); + packet = request_packet->packet; + + /* + * Initialize the packet (this is really initialization the core 1394 stack should do, + * but I'm doing it myself to avoid the overhead). + */ + packet->data_size = data_size; + INIT_LIST_HEAD(&packet->list); + sema_init(&packet->state_change, 0); + packet->state = unused; + packet->generation = get_hpsb_generation(); + packet->data_be = 1; + + packet->host = hi->host; + packet->tlabel = get_tlabel(hi->host, node, 1); + packet->node_id = node; + + if (!data_size) { + fill_async_writequad(packet, addr, data); + } else { + fill_async_writeblock(packet, addr, data_size); + } + + /* + * Set up a task queue completion routine, which returns the packet to the free list + * and releases the tlabel + */ + request_packet->tq.routine = (void (*)(void*))sbp2util_free_request_packet; + request_packet->tq.data = request_packet; + request_packet->hi_context = hi; + queue_task(&request_packet->tq, &packet->complete_tq); + + /* + * Now, put the packet on the in-use list + */ + list_add_tail(&request_packet->list, &hi->sbp2_req_inuse); + + } else { + SBP2_ERR("sbp2: sbp2util_allocate_request_packet - no packets available!"); + } + sbp2_spin_unlock(&hi->sbp2_request_packet_lock, flags); + + return(request_packet); +} + +/* + * This function is called to return a packet to our packet pool. It is also called as a + * completion routine when a request packet is completed. + */ +static void sbp2util_free_request_packet(struct sbp2_request_packet *request_packet) +{ + unsigned long flags; + struct sbp2scsi_host_info *hi = request_packet->hi_context; + + /* + * Free the tlabel, and return the packet to the free pool + */ + sbp2_spin_lock(&hi->sbp2_request_packet_lock, flags); + free_tlabel(hi->host, LOCAL_BUS | request_packet->packet->node_id, + request_packet->packet->tlabel); + list_del(&request_packet->list); + list_add_tail(&request_packet->list, &hi->sbp2_req_free); + sbp2_spin_unlock(&hi->sbp2_request_packet_lock, flags); + + return; +} + +/* + * This function is called to create a pool of command orbs used for command processing. It is called + * when a new sbp2 device is detected. + */ +static int sbp2util_create_command_orb_pool(struct scsi_id_instance_data *scsi_id, + struct sbp2scsi_host_info *hi) +{ + int i; + unsigned long flags; + struct sbp2_command_info *command; + + sbp2_spin_lock(&scsi_id->sbp2_command_orb_lock, flags); + for (i = 0; i < scsi_id->sbp2_total_command_orbs; i++) { + command = (struct sbp2_command_info *) + kmalloc(sizeof(struct sbp2_command_info), GFP_KERNEL); + if (!command) { + sbp2_spin_unlock(&scsi_id->sbp2_command_orb_lock, flags); + return(-ENOMEM); + } + memset(command, '\0', sizeof(struct sbp2_command_info)); + command->command_orb_dma = + pci_map_single (hi->host->pdev, &command->command_orb, + sizeof(struct sbp2_command_orb), + PCI_DMA_BIDIRECTIONAL); + SBP2_DMA_ALLOC("single command orb DMA"); + command->sge_dma = + pci_map_single (hi->host->pdev, &command->scatter_gather_element, + sizeof(command->scatter_gather_element), + PCI_DMA_BIDIRECTIONAL); + SBP2_DMA_ALLOC("scatter_gather_element"); + INIT_LIST_HEAD(&command->list); + list_add_tail(&command->list, &scsi_id->sbp2_command_orb_completed); + } + sbp2_spin_unlock(&scsi_id->sbp2_command_orb_lock, flags); + return 0; +} + +/* + * This function is called to delete a pool of command orbs. + */ +static void sbp2util_remove_command_orb_pool(struct scsi_id_instance_data *scsi_id, + struct sbp2scsi_host_info *hi) +{ + struct list_head *lh; + struct sbp2_command_info *command; + unsigned long flags; + + sbp2_spin_lock(&scsi_id->sbp2_command_orb_lock, flags); + if (!list_empty(&scsi_id->sbp2_command_orb_completed)) { + list_for_each(lh, &scsi_id->sbp2_command_orb_completed) { + command = list_entry(lh, struct sbp2_command_info, list); + + /* Release our generic DMA's */ + pci_unmap_single(hi->host->pdev, command->command_orb_dma, + sizeof(struct sbp2_command_orb), + PCI_DMA_BIDIRECTIONAL); + SBP2_DMA_FREE("single command orb DMA"); + pci_unmap_single(hi->host->pdev, command->sge_dma, + sizeof(command->scatter_gather_element), + PCI_DMA_BIDIRECTIONAL); + SBP2_DMA_FREE("scatter_gather_element"); + + kfree(command); + } + } + sbp2_spin_unlock(&scsi_id->sbp2_command_orb_lock, flags); + return; +} + +/* + * This functions finds the sbp2_command for a given outstanding + * command orb. Only looks at the inuse list. + */ +static struct sbp2_command_info *sbp2util_find_command_for_orb(struct scsi_id_instance_data *scsi_id, dma_addr_t orb) +{ + struct list_head *lh; + struct sbp2_command_info *command; + unsigned long flags; + + sbp2_spin_lock(&scsi_id->sbp2_command_orb_lock, flags); + if (!list_empty(&scsi_id->sbp2_command_orb_inuse)) { + list_for_each(lh, &scsi_id->sbp2_command_orb_inuse) { + command = list_entry(lh, struct sbp2_command_info, list); + if (command->command_orb_dma == orb) { + sbp2_spin_unlock(&scsi_id->sbp2_command_orb_lock, flags); + return (command); + } + } + } + sbp2_spin_unlock(&scsi_id->sbp2_command_orb_lock, flags); + + SBP2_ORB_DEBUG("could not match command orb %x", (unsigned int)orb); + + return(NULL); +} + +/* + * This functions finds the sbp2_command for a given outstanding SCpnt. Only looks at the inuse list + */ +static struct sbp2_command_info *sbp2util_find_command_for_SCpnt(struct scsi_id_instance_data *scsi_id, void *SCpnt) +{ + struct list_head *lh; + struct sbp2_command_info *command; + unsigned long flags; + + sbp2_spin_lock(&scsi_id->sbp2_command_orb_lock, flags); + if (!list_empty(&scsi_id->sbp2_command_orb_inuse)) { + list_for_each(lh, &scsi_id->sbp2_command_orb_inuse) { + command = list_entry(lh, struct sbp2_command_info, list); + if (command->Current_SCpnt == SCpnt) { + sbp2_spin_unlock(&scsi_id->sbp2_command_orb_lock, flags); + return (command); + } + } + } + sbp2_spin_unlock(&scsi_id->sbp2_command_orb_lock, flags); + return(NULL); +} + +/* + * This function allocates a command orb used to send a scsi command. + */ +static struct sbp2_command_info *sbp2util_allocate_command_orb(struct scsi_id_instance_data *scsi_id, + Scsi_Cmnd *Current_SCpnt, + void (*Current_done)(Scsi_Cmnd *), + struct sbp2scsi_host_info *hi) +{ + struct list_head *lh; + struct sbp2_command_info *command = NULL; + unsigned long flags; + + sbp2_spin_lock(&scsi_id->sbp2_command_orb_lock, flags); + if (!list_empty(&scsi_id->sbp2_command_orb_completed)) { + lh = scsi_id->sbp2_command_orb_completed.next; + list_del(lh); + command = list_entry(lh, struct sbp2_command_info, list); + command->Current_done = Current_done; + command->Current_SCpnt = Current_SCpnt; + command->linked = 0; + list_add_tail(&command->list, &scsi_id->sbp2_command_orb_inuse); + } else { + SBP2_ERR("sbp2: sbp2util_allocate_command_orb - No orbs available!"); + } + sbp2_spin_unlock(&scsi_id->sbp2_command_orb_lock, flags); + return (command); +} + +/* Free our DMA's */ +static void sbp2util_free_command_dma(struct sbp2_command_info *command) +{ + struct sbp2scsi_host_info *hi; + + hi = (struct sbp2scsi_host_info *) command->Current_SCpnt->host->hostdata[0]; + + if (hi == NULL) { + printk(KERN_ERR __FUNCTION__": hi == NULL\n"); + return; + } + + if (command->cmd_dma) { + pci_unmap_single(hi->host->pdev, command->cmd_dma, + command->dma_size, command->dma_dir); + SBP2_DMA_FREE("single bulk"); + command->cmd_dma = 0; + } + + if (command->sge_buffer) { + pci_unmap_sg(hi->host->pdev, command->sge_buffer, + command->dma_size, command->dma_dir); + SBP2_DMA_FREE("scatter list"); + command->sge_buffer = NULL; + } +} + +/* + * This function moves a command to the completed orb list. + */ +static void sbp2util_mark_command_completed(struct scsi_id_instance_data *scsi_id, struct sbp2_command_info *command) +{ + unsigned long flags; + + sbp2_spin_lock(&scsi_id->sbp2_command_orb_lock, flags); + list_del(&command->list); + sbp2util_free_command_dma(command); + list_add_tail(&command->list, &scsi_id->sbp2_command_orb_completed); + sbp2_spin_unlock(&scsi_id->sbp2_command_orb_lock, flags); +} + +/********************************************* + * IEEE-1394 core driver stack related section + *********************************************/ + +/* + * This function is called at SCSI init in order to register our driver with the + * IEEE-1394 stack + */ +int sbp2_init(void) +{ + SBP2_DEBUG("sbp2: sbp2_init"); + + /* + * Register our high level driver with 1394 stack + */ + sbp2_hl_handle = hpsb_register_highlevel(SBP2_DEVICE_NAME, &sbp2_hl_ops); + + if (sbp2_hl_handle == NULL) { + SBP2_ERR("sbp2: sbp2 failed to register with ieee1394 highlevel"); + return(-ENOMEM); + } + + /* + * Register our sbp2 status address space... + */ + hpsb_register_addrspace(sbp2_hl_handle, &sbp2_ops, SBP2_STATUS_FIFO_ADDRESS, + SBP2_STATUS_FIFO_ADDRESS + sizeof(struct sbp2_status_block)); + + /* + * Register physical dma address space... used for + * adapters not supporting hardware phys dma. + * + * XXX: Disabled for now. + */ + /* hpsb_register_addrspace(sbp2_hl_handle, &sbp2_physdma_ops, + 0x0ULL, 0xfffffffcULL); */ + + return(0); +} + +/* + * This function is called from cleanup module, or during shut-down, in order to + * unregister our driver + */ +void sbp2_cleanup(void) +{ + SBP2_DEBUG("sbp2: sbp2_cleanup"); + + if (sbp2_hl_handle) { + hpsb_unregister_highlevel(sbp2_hl_handle); + sbp2_hl_handle = NULL; + } + return; +} + +/* + * This function is called after registering our operations in sbp2_init. We go ahead and + * allocate some memory for our host info structure, and init some structures. + */ +static void sbp2_add_host(struct hpsb_host *host) +{ + struct sbp2scsi_host_info *hi; + unsigned int flags; + + SBP2_DEBUG("sbp2: sbp2_add_host"); + + /* + * Allocate some memory for our host info structure + */ + hi = (struct sbp2scsi_host_info *)kmalloc(sizeof(struct sbp2scsi_host_info), GFP_KERNEL); + + if (hi != NULL) { + + /* + * Initialize some host stuff + */ + memset(hi, 0, sizeof(struct sbp2scsi_host_info)); + INIT_LIST_HEAD(&hi->list); + INIT_LIST_HEAD(&hi->sbp2_req_inuse); + INIT_LIST_HEAD(&hi->sbp2_req_free); + hi->host = host; + hi->sbp2_command_lock = SPIN_LOCK_UNLOCKED; + hi->sbp2_request_packet_lock = SPIN_LOCK_UNLOCKED; + + /* + * Create our request packet pool (pool of packets for use in I/O) + */ + if (sbp2util_create_request_packet_pool(hi)) { + SBP2_ERR("sbp2: sbp2util_create_request_packet_pool failed!"); + return; + } + + sbp2_spin_lock(&sbp2_host_info_lock, flags); + list_add_tail(&hi->list, &sbp2_host_info_list); + sbp2_host_count++; + sbp2_spin_lock(&sbp2_host_info_lock, flags); + + /* + * Initialize us to bus reset in progress + */ + hi->bus_reset_in_progress = 1; + + /* + * Register our host with the SCSI stack. + */ + sbp2scsi_register_scsi_host(hi); + + /* + * Start our kernel thread to deal with sbp2 device detection + */ + init_waitqueue_head(&hi->sbp2_detection_wait); + hi->sbp2_detection_pid = 0; + hi->sbp2_detection_pid = kernel_thread(sbp2_detection_thread, hi, CLONE_FS | CLONE_FILES | CLONE_SIGHAND); + + } + + return; +} + +/* + * This fuction returns a host info structure from the host structure, in case we have multiple hosts + */ +static struct sbp2scsi_host_info *sbp2_find_host_info(struct hpsb_host *host) { + struct list_head *lh; + struct sbp2scsi_host_info *hi; + + lh = sbp2_host_info_list.next; + while (lh != &sbp2_host_info_list) { + hi = list_entry(lh, struct sbp2scsi_host_info, list); + if (hi->host == host) { + return hi; + } + lh = lh->next; + } + + return(NULL); +} + +/* + * This function is called when the host is removed + */ +static void sbp2_remove_host(struct hpsb_host *host) +{ + struct sbp2scsi_host_info *hi; + int i; + unsigned int flags; + + SBP2_DEBUG("sbp2: sbp2_remove_host"); + + sbp2_spin_lock(&sbp2_host_info_lock, flags); + hi = sbp2_find_host_info(host); + + if (hi != NULL) { + + /* + * Need to remove any attached SBP-2 devices. Also make sure to logout of all devices. + */ + for (i=0; i<SBP2SCSI_MAX_SCSI_IDS; i++) { + if (hi->scsi_id[i]) { + sbp2_logout_device(hi, hi->scsi_id[i]); + hi->scsi_id[i]->validated = 0; + } + } + + sbp2_remove_unvalidated_devices(hi); + + list_del(&hi->list); + sbp2_host_count--; + } + sbp2_spin_unlock(&sbp2_host_info_lock, flags); + + if (hi == NULL) { + SBP2_ERR("sbp2: attempt to remove unknown host %p", host); + return; + } + + /* + * Remove the packet pool (release the packets) + */ + sbp2util_remove_request_packet_pool(hi); + + /* + * Kill our detection thread + */ + if (hi->sbp2_detection_pid >= 0) { + kill_proc(hi->sbp2_detection_pid, SIGINT, 1); + } + + /* + * Give the detection thread a little time to exit + */ + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(HZ); /* 1 second delay */ + + kfree(hi); + hi = NULL; + + return; +} + +/* + * This is our sbp2 detection thread. It is signalled when bus resets occur + * so that we can find and initialize any sbp2 devices. + */ +static int sbp2_detection_thread(void *__hi) +{ + struct sbp2scsi_host_info *hi = (struct sbp2scsi_host_info *)__hi; + + SBP2_DEBUG("sbp2: sbp2_detection_thread"); + + lock_kernel(); + + /* + * This thread doesn't need any user-level access, + * so get rid of all our resources + */ + daemonize(); + + /* + * Set-up a nice name + */ + strcpy(current->comm, "sbp2"); + + unlock_kernel(); + + while ((!signal_pending(current)) && hi) { + + /* + * Process our bus reset now + */ + if (hi) { + MOD_INC_USE_COUNT; + sbp2_bus_reset_handler(hi); + MOD_DEC_USE_COUNT; + } + + /* + * Sleep until next bus reset + */ + if (hi) { + interruptible_sleep_on(&hi->sbp2_detection_wait); + } + } + + return(0); +} + +/* + * This function is where we first pull the node unique ids, and then allocate memory and register + * a SBP-2 device + */ +static int sbp2_start_device(struct sbp2scsi_host_info *hi, int node_id) +{ + quadlet_t node_unique_id_lo, node_unique_id_hi; + u64 node_unique_id; + struct scsi_id_instance_data *scsi_id = NULL; + int i; + + SBP2_DEBUG("sbp2: sbp2_start_device"); + + /* + * Let's read the node unique id off of the device (using two quadlet reads for hi and lo) + */ + if (sbp2util_read_quadlet(hi, LOCAL_BUS | node_id, CONFIG_ROM_NODE_UNIQUE_ID_HI_ADDRESS, + &node_unique_id_hi)) { + SBP2_DEBUG("sbp2: Error reading node unique id - bad status"); + return(-EIO); + } + + if (sbp2util_read_quadlet(hi, LOCAL_BUS | node_id, CONFIG_ROM_NODE_UNIQUE_ID_LO_ADDRESS, + &node_unique_id_lo)) { + SBP2_DEBUG("sbp2: Error reading node unique id - bad status"); + return(-EIO); + } + + /* + * Spit out the node unique ids we got + */ + SBP2_DEBUG("sbp2: Node %x, node unique id hi = %x", (LOCAL_BUS | node_id), (unsigned int) node_unique_id_hi); + SBP2_DEBUG("sbp2: Node %x, node unique id lo = %x", (LOCAL_BUS | node_id), (unsigned int) node_unique_id_lo); + + node_unique_id = (((u64)node_unique_id_hi) << 32) | ((u64)node_unique_id_lo); + + /* + * First, we need to find out whether this is a "new" SBP-2 device plugged in, or one that already + * exists and is initialized. We do this by looping through our scsi id instance data structures + * looking for matching node unique ids. + */ + for (i=0; i<SBP2SCSI_MAX_SCSI_IDS; i++) { + + if (hi->scsi_id[i]) { + + if (hi->scsi_id[i]->node_unique_id == node_unique_id) { + + /* + * Update our node id + */ + hi->scsi_id[i]->node_id = node_id; + + /* + * Mark the device as validated, since it still exists on the bus + */ + hi->scsi_id[i]->validated = 1; + SBP2_DEBUG("sbp2: SBP-2 device re-validated, SCSI ID = %x", (unsigned int) i); + + /* + * Reconnect to the sbp-2 device + */ + if (sbp2_reconnect_device(hi, hi->scsi_id[i])) { + + /* + * Ok, reconnect has failed. Perhaps we didn't reconnect fast enough. Try + * doing a regular login. + */ + if (sbp2_login_device(hi, hi->scsi_id[i])) { + + /* + * Login failed too... so, just mark him as unvalidated, so that he gets cleaned up + * later + */ + SBP2_ERR("sbp2: sbp2_reconnect_device failed!"); + hi->scsi_id[i]->validated = 0; + } + } + + if (hi->scsi_id[i]->validated) { + + /* + * Set max retries to something large on the device + */ + sbp2_set_busy_timeout(hi, hi->scsi_id[i]); + + /* + * Do a SBP-2 fetch agent reset + */ + sbp2_agent_reset(hi, hi->scsi_id[i], 0); + + /* + * Get the max speed and packet size that we can use + */ + sbp2_max_speed_and_size(hi, hi->scsi_id[i]); + + } + + /* + * Nothing more to do, since we found the device + */ + return(0); + + } + } + } + + /* + * This really is a "new" device plugged in. Let's allocate memory for our scsi id instance data + */ + scsi_id = (struct scsi_id_instance_data *)kmalloc(sizeof(struct scsi_id_instance_data), + GFP_KERNEL); + if (!scsi_id) + goto alloc_fail_first; + memset(scsi_id, 0, sizeof(struct scsi_id_instance_data)); + + /* Login FIFO DMA */ + scsi_id->login_response = + pci_alloc_consistent(hi->host->pdev, sizeof(struct sbp2_login_response), + &scsi_id->login_response_dma); + if (!scsi_id->login_response) + goto alloc_fail; + SBP2_DMA_ALLOC("consistent DMA region for login FIFO"); + + /* Reconnect ORB DMA */ + scsi_id->reconnect_orb = + pci_alloc_consistent(hi->host->pdev, sizeof(struct sbp2_reconnect_orb), + &scsi_id->reconnect_orb_dma); + if (!scsi_id->reconnect_orb) + goto alloc_fail; + SBP2_DMA_ALLOC("consistent DMA region for reconnect ORB"); + + /* Logout ORB DMA */ + scsi_id->logout_orb = + pci_alloc_consistent(hi->host->pdev, sizeof(struct sbp2_logout_orb), + &scsi_id->logout_orb_dma); + if (!scsi_id->logout_orb) + goto alloc_fail; + SBP2_DMA_ALLOC("consistent DMA region for logout ORB"); + + /* Login ORB DMA */ + scsi_id->login_orb = + pci_alloc_consistent(hi->host->pdev, sizeof(struct sbp2_login_orb), + &scsi_id->login_orb_dma); + if (scsi_id->login_orb == NULL) { +alloc_fail: + if (scsi_id->logout_orb) { + pci_free_consistent(hi->host->pdev, + sizeof(struct sbp2_logout_orb), + scsi_id->logout_orb, + scsi_id->logout_orb_dma); + SBP2_DMA_FREE("logout ORB DMA"); + } + + if (scsi_id->reconnect_orb) { + pci_free_consistent(hi->host->pdev, + sizeof(struct sbp2_reconnect_orb), + scsi_id->reconnect_orb, + scsi_id->reconnect_orb_dma); + SBP2_DMA_FREE("reconnect ORB DMA"); + } + + if (scsi_id->login_response) { + pci_free_consistent(hi->host->pdev, + sizeof(struct sbp2_login_response), + scsi_id->login_response, + scsi_id->login_response_dma); + SBP2_DMA_FREE("login FIFO DMA"); + } + + kfree(scsi_id); +alloc_fail_first: + SBP2_ERR ("sbp2: Could not allocate memory for scsi_id"); + return(-ENOMEM); + } + SBP2_DMA_ALLOC("consistent DMA region for login ORB"); + + /* + * Initialize some of the fields in this structure + */ + scsi_id->node_id = node_id; + scsi_id->node_unique_id = node_unique_id; + scsi_id->validated = 1; + scsi_id->speed_code = SPEED_S100; + scsi_id->max_payload_size = MAX_PAYLOAD_S100; + + init_waitqueue_head(&scsi_id->sbp2_login_wait); + + /* + * Initialize structures needed for the command orb pool. + */ + INIT_LIST_HEAD(&scsi_id->sbp2_command_orb_inuse); + INIT_LIST_HEAD(&scsi_id->sbp2_command_orb_completed); + scsi_id->sbp2_command_orb_lock = SPIN_LOCK_UNLOCKED; + scsi_id->sbp2_total_command_orbs = 0; + + /* + * Make sure that we've gotten ahold of the sbp2 management agent address. Also figure out the + * command set being used (SCSI or RBC). + */ + if (sbp2_parse_unit_directory(hi, scsi_id)) { + SBP2_ERR("sbp2: Error while parsing sbp2 unit directory"); + hi->scsi_id[i]->validated = 0; + return(-EIO); + } + + scsi_id->sbp2_total_command_orbs = SBP2_MAX_COMMAND_ORBS; + + /* + * Knock the total command orbs down if we are serializing I/O + */ + if (serialize_io) { + scsi_id->sbp2_total_command_orbs = 2; /* one extra for good measure */ + } + + /* + * Allocate some extra command orb structures for devices with 128KB limit + */ + if (scsi_id->sbp2_firmware_revision == SBP2_128KB_BROKEN_FIRMWARE) { + scsi_id->sbp2_total_command_orbs *= 4; + } + + /* + * Create our command orb pool + */ + if (sbp2util_create_command_orb_pool(scsi_id, hi)) { + SBP2_ERR("sbp2: sbp2util_create_command_orb_pool failed!"); + hi->scsi_id[i]->validated = 0; + return (-ENOMEM); + } + + /* + * Find an empty spot to stick our scsi id instance data. + */ + for (i=0; i<SBP2SCSI_MAX_SCSI_IDS; i++) { + if (!hi->scsi_id[i]) { + hi->scsi_id[i] = scsi_id; + SBP2_DEBUG("sbp2: New SBP-2 device inserted, SCSI ID = %x", (unsigned int) i); + break; + } + } + + /* + * Make sure we are not out of space + */ + if (i >= SBP2SCSI_MAX_SCSI_IDS) { + SBP2_ERR("sbp2: No slots left for SBP-2 device"); + hi->scsi_id[i]->validated = 0; + return(-EBUSY); + } + + /* + * Login to the sbp-2 device + */ + if (sbp2_login_device(hi, hi->scsi_id[i])) { + + /* + * Login failed... so, just mark him as unvalidated, so that he gets cleaned up later + */ + SBP2_ERR("sbp2: sbp2_login_device failed"); + hi->scsi_id[i]->validated = 0; + } + + if (hi->scsi_id[i]->validated) { + + /* + * Set max retries to something large on the device + */ + sbp2_set_busy_timeout(hi, hi->scsi_id[i]); + + /* + * Do a SBP-2 fetch agent reset + */ + sbp2_agent_reset(hi, hi->scsi_id[i], 0); + + /* + * Get the max speed and packet size that we can use + */ + sbp2_max_speed_and_size(hi, hi->scsi_id[i]); + + } + + return(0); +} + +/* + * This function trys to determine if a device is a valid SBP-2 device + */ +static int sbp2_check_device(struct sbp2scsi_host_info *hi, int node_id) +{ + quadlet_t unit_spec_id_data = 0, unit_sw_ver_data = 0; + quadlet_t unit_directory_length, current_quadlet; + u64 unit_directory_addr, current_addr; + unsigned int i, length; + + SBP2_DEBUG("sbp2: sbp2_check_device"); + + /* + * Let's try and read the unit spec id and unit sw ver to determine if this is an SBP2 device... + */ + + if (sbp2util_unit_directory(hi, LOCAL_BUS | node_id, &unit_directory_addr)) { + SBP2_DEBUG("sbp2: Error reading unit directory address - bad status"); + return(-EIO); + } + + /* + * Read the size of the unit directory + */ + if (sbp2util_read_quadlet(hi, LOCAL_BUS | node_id, unit_directory_addr, + &unit_directory_length)) { + SBP2_DEBUG("sbp2: Error reading root directory length - bad status"); + return(-EIO); + } + + current_addr = unit_directory_addr; + length = be32_to_cpu(unit_directory_length) >> 16; + + /* + * Now, step through the unit directory and look for the unit_spec_ID and the unit_sw_version + */ + for (i=0; i < length; i++) { + + current_addr += 4; + + if (sbp2util_read_quadlet(hi, LOCAL_BUS | node_id, current_addr, ¤t_quadlet)) { + SBP2_DEBUG("sbp2: Error reading at address 0x%08x%08x - bad status", + (unsigned int) ((current_addr) >> 32), (unsigned int) ((current_addr) & 0xffffffff)); + return(-EIO); + } + + /* + * Check for unit_spec_ID tag + */ + if ((be32_to_cpu(current_quadlet) >> 24) == SBP2_UNIT_SPEC_ID_KEY) { + unit_spec_id_data = current_quadlet; + SBP2_DEBUG("sbp2: Node %x, unit spec id = %x", (LOCAL_BUS | node_id), + (unsigned int) be32_to_cpu(unit_spec_id_data)); + } + + /* + * Check for unit_sw_version tag + */ + if ((be32_to_cpu(current_quadlet) >> 24) == SBP2_UNIT_SW_VERSION_KEY) { + unit_sw_ver_data = current_quadlet; + SBP2_DEBUG("sbp2: Node %x, unit sw version = %x", (LOCAL_BUS | node_id), + (unsigned int) be32_to_cpu(unit_sw_ver_data)); + } + } + + /* + * Validate unit spec id and unit sw ver to see if this is an SBP-2 device + */ + if ((be32_to_cpu(unit_spec_id_data) != SBP2_UNIT_SPEC_ID_ENTRY) || + (be32_to_cpu(unit_sw_ver_data) != SBP2_SW_VERSION_ENTRY)) { + + /* + * Not an sbp2 device + */ + return(-ENXIO); + } + + /* + * This device is a valid SBP-2 device + */ + SBP2_INFO("sbp2: Node 0x%04x, Found SBP-2 device", (LOCAL_BUS | node_id)); + return(0); +} + +/* + * This function removes (cleans-up after) any unvalidated sbp2 devices + */ +static void sbp2_remove_unvalidated_devices(struct sbp2scsi_host_info *hi) +{ + int i; + + /* + * Loop through and free any unvalidated scsi id instance data structures + */ + for (i=0; i<SBP2SCSI_MAX_SCSI_IDS; i++) { + if (hi->scsi_id[i]) { + if (!hi->scsi_id[i]->validated) { + + /* + * Complete any pending commands with selection timeout + */ + sbp2scsi_complete_all_commands(hi, hi->scsi_id[i], DID_NO_CONNECT); + + /* + * Clean up any other structures + */ + if (hi->scsi_id[i]->sbp2_total_command_orbs) { + sbp2util_remove_command_orb_pool(hi->scsi_id[i], hi); + } + if (hi->scsi_id[i]->login_response) { + pci_free_consistent(hi->host->pdev, + sizeof(struct sbp2_login_response), + hi->scsi_id[i]->login_response, + hi->scsi_id[i]->login_response_dma); + SBP2_DMA_FREE("single login FIFO"); + } + + if (hi->scsi_id[i]->login_orb) { + pci_free_consistent(hi->host->pdev, + sizeof(struct sbp2_login_orb), + hi->scsi_id[i]->login_orb, + hi->scsi_id[i]->login_orb_dma); + SBP2_DMA_FREE("single login ORB"); + } + + if (hi->scsi_id[i]->reconnect_orb) { + pci_free_consistent(hi->host->pdev, + sizeof(struct sbp2_reconnect_orb), + hi->scsi_id[i]->reconnect_orb, + hi->scsi_id[i]->reconnect_orb_dma); + SBP2_DMA_FREE("single reconnect orb"); + } + + if (hi->scsi_id[i]->logout_orb) { + pci_free_consistent(hi->host->pdev, + sizeof(struct sbp2_logout_orb), + hi->scsi_id[i]->logout_orb, + hi->scsi_id[i]->reconnect_orb_dma); + SBP2_DMA_FREE("single logout orb"); + } + + kfree(hi->scsi_id[i]); + hi->scsi_id[i] = NULL; + SBP2_DEBUG("sbp2: Unvalidated SBP-2 device removed, SCSI ID = %x", (unsigned int) i); + } + } + } + + return; +} + +/* + * This function is our reset handler. It is run out of a thread, since we get + * notified of a bus reset from a bh (or interrupt). + */ +static void sbp2_bus_reset_handler(void *context) +{ + struct sbp2scsi_host_info *hi = context; + quadlet_t signature_data; + int i; + unsigned long flags; + struct scsi_id_instance_data *scsi_id; + + SBP2_DEBUG("sbp2: sbp2_bus_reset_handler"); + + /* + * TODO. Check and keep track of generation number of all requests, in case a + * bus reset occurs while trying to find and login to SBP-2 devices. + */ + + /* + * First thing to do. Invalidate all SBP-2 devices. This is needed so that + * we stop sending down I/O requests to the device, and also so that we can + * figure out which devices have disappeared after a bus reset. + */ + for (i=0; i<SBP2SCSI_MAX_SCSI_IDS; i++) { + if (hi->scsi_id[i]) { + hi->scsi_id[i]->validated = 0; + } + } + + /* + * Give the sbp2 devices a little time to recover after the bus reset + */ + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(HZ/2); /* 1/2 second delay */ + + /* + * Spit out what we know from the host + */ + SBP2_DEBUG("host: node_count = %x", (unsigned int) hi->host->node_count); + SBP2_DEBUG("host: selfid_count = %x", (unsigned int) hi->host->selfid_count); + SBP2_DEBUG("host: node_id = %x", (unsigned int) hi->host->node_id); + SBP2_DEBUG("host: irm_id = %x", (unsigned int) hi->host->irm_id); + SBP2_DEBUG("host: busmgr_id = %x", (unsigned int) hi->host->busmgr_id); + SBP2_DEBUG("host: is_root = %x", (unsigned int) hi->host->is_root); + SBP2_DEBUG("host: is_cycmst = %x", (unsigned int) hi->host->is_cycmst); + SBP2_DEBUG("host: is_irm = %x", (unsigned int) hi->host->is_irm); + SBP2_DEBUG("host: is_busmgr = %x", (unsigned int) hi->host->is_busmgr); + + /* + * Let's try and figure out which devices out there are SBP-2 devices! Loop through all + * nodes out there. + */ + for (i=0; i<hi->host->node_count; i++) { + + /* + * Don't read from ourselves! + */ + if (i != ((hi->host->node_id) & NODE_MASK)) { + + /* + * Try and send a request for a config rom signature. This is expected to fail for + * some nodes, as they might be repeater phys or not be initialized. + */ + if (!sbp2util_read_quadlet(hi, LOCAL_BUS | i, CONFIG_ROM_SIGNATURE_ADDRESS, &signature_data)) { + + if (be32_to_cpu(signature_data) == IEEE1394_CONFIG_ROM_SIGNATURE) { + + /* + * Hey, we've got a valid responding IEEE1394 node. Need to now see if it's an SBP-2 device + */ + if (!sbp2_check_device(hi, i)) { + + /* + * Found an SBP-2 device. Now, actually start the device. + */ + sbp2_start_device(hi, i); + } + } + } + } + } + + /* + * This code needs protection + */ + sbp2_spin_lock(&hi->sbp2_command_lock, flags); + + /* + * Ok, we've discovered and re-validated all SBP-2 devices out there. Let's remove structures of all + * devices not re-validated (meaning they've been removed). + */ + sbp2_remove_unvalidated_devices(hi); + + /* + * Complete any pending commands with busy (so they get retried) and remove them from our queue + */ + for (i=0; i<SBP2SCSI_MAX_SCSI_IDS; i++) { + if (hi->scsi_id[i]) { + sbp2scsi_complete_all_commands(hi, hi->scsi_id[i], DID_BUS_BUSY); + } + } + + /* + * Now, note that the bus reset is complete (finally!) + */ + hi->bus_reset_in_progress = 0; + + /* + * Deal with the initial scsi bus scan if needed (since we only now know if there are + * any sbp2 devices attached) + */ + if (!no_bus_scan && !hi->initial_scsi_bus_scan_complete && hi->bus_scan_SCpnt) { + + hi->initial_scsi_bus_scan_complete = 1; + scsi_id = hi->scsi_id[hi->bus_scan_SCpnt->target]; + + /* + * If the sbp2 device exists, then let's now execute the command. + * If not, then just complete it as a selection time-out. + */ + if (scsi_id) { + if (sbp2_send_command(hi, scsi_id, hi->bus_scan_SCpnt, hi->bus_scan_done)) { + SBP2_ERR("sbp2: Error sending SCSI command"); + sbp2scsi_complete_command(hi, scsi_id, SBP2_SCSI_STATUS_SELECTION_TIMEOUT, + hi->bus_scan_SCpnt, hi->bus_scan_done); + } + } else { + void (*done)(Scsi_Cmnd *) = hi->bus_scan_done; + hi->bus_scan_SCpnt->result = DID_NO_CONNECT << 16; + done (hi->bus_scan_SCpnt); + } + } + + sbp2_spin_unlock(&hi->sbp2_command_lock, flags); + + return; +} + + +/* + * This is called from the host's bh when a bus reset is complete. We wake up our detection thread + * to deal with the reset + */ +static void sbp2_host_reset(struct hpsb_host *host) +{ + unsigned long flags; + struct sbp2scsi_host_info *hi; + int i; + + SBP2_INFO("sbp2: IEEE-1394 bus reset"); + sbp2_spin_lock(&sbp2_host_info_lock, flags); + hi = sbp2_find_host_info(host); + + if (hi != NULL) { + + /* + * Wake up our detection thread, only if it's not already handling a reset + */ + if (!hi->bus_reset_in_progress) { + + /* + * First thing to do. Invalidate all SBP-2 devices. This is needed so that + * we stop sending down I/O requests to the device, and also so that we can + * figure out which devices have disappeared after a bus reset. + */ + for (i=0; i<SBP2SCSI_MAX_SCSI_IDS; i++) { + if (hi->scsi_id[i]) { + hi->scsi_id[i]->validated = 0; + } + } + + hi->bus_reset_in_progress = 1; + + wake_up(&hi->sbp2_detection_wait); + } + } + sbp2_spin_unlock(&sbp2_host_info_lock, flags); + return; +} + +/* XXX: How best to handle these with DMA interface? */ + +#if 0 +/* + * This function deals with physical dma write requests (for adapters that do not support + * physical dma in hardware). + */ +static int sbp2_handle_physdma_write(struct hpsb_host *host, int nodeid, quadlet_t *data, + u64 addr, unsigned int length) +{ + + /* + * Manually put the data in the right place. + */ + memcpy(bus_to_virt((u32)addr), data, length); + return(RCODE_COMPLETE); +} + +/* + * This function deals with physical dma read requests (for adapters that do not support + * physical dma in hardware). + */ +static int sbp2_handle_physdma_read(struct hpsb_host *host, int nodeid, quadlet_t *data, + u64 addr, unsigned int length) +{ + + /* + * Grab data from memory and send a read response. + */ + memcpy(data, bus_to_virt((u32)addr), length); + return(RCODE_COMPLETE); +} +#endif + +/************************************** + * SBP-2 protocol related section + **************************************/ + +/* + * This function is called in order to login to a particular SBP-2 device, after a bus reset + */ +static int sbp2_login_device(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id) +{ + quadlet_t data[2]; + unsigned long flags; + + SBP2_DEBUG("sbp2: sbp2_login_device"); + + if (!scsi_id->login_orb) { + SBP2_DEBUG("sbp2: sbp2_login_device: login_orb not alloc'd!"); + return(-EIO); + } + + /* + * Set-up login ORB + */ + scsi_id->login_orb->password_hi = 0; /* Assume no password */ + scsi_id->login_orb->password_lo = 0; + SBP2_DEBUG("sbp2: sbp2_login_device: password_hi/lo initialized"); +#ifdef SBP2_NEED_LOGIN_DESCRIPTOR_WORKAROUND + scsi_id->login_orb->login_response_lo = cpu_to_le32(scsi_id->login_response_dma); + scsi_id->login_orb->login_response_hi = cpu_to_le32(ORB_SET_NODE_ID(hi->host->node_id)); +#else + scsi_id->login_orb->login_response_lo = scsi_id->login_response_dma; + scsi_id->login_orb->login_response_hi = ORB_SET_NODE_ID(hi->host->node_id); +#endif + SBP2_DEBUG("sbp2: sbp2_login_device: login_response_hi/lo initialized"); + scsi_id->login_orb->lun_misc = ORB_SET_FUNCTION(LOGIN_REQUEST); + scsi_id->login_orb->lun_misc |= ORB_SET_RECONNECT(0); /* One second reconnect time */ + scsi_id->login_orb->lun_misc |= ORB_SET_EXCLUSIVE(1); /* Exclusive access to device */ + scsi_id->login_orb->lun_misc |= ORB_SET_NOTIFY(1); /* Notify us of login complete */ + SBP2_DEBUG("sbp2: sbp2_login_device: lun_misc initialized"); + scsi_id->login_orb->passwd_resp_lengths = ORB_SET_LOGIN_RESP_LENGTH(sizeof(struct sbp2_login_response)); + SBP2_DEBUG("sbp2: sbp2_login_device: passwd_resp_lengths initialized"); +#ifdef SBP2_NEED_LOGIN_DESCRIPTOR_WORKAROUND + scsi_id->login_orb->status_FIFO_lo = cpu_to_le32((u32)SBP2_STATUS_FIFO_ADDRESS_LO); + scsi_id->login_orb->status_FIFO_hi = (ORB_SET_NODE_ID(hi->host->node_id) | cpu_to_le16(SBP2_STATUS_FIFO_ADDRESS_HI)); +#else + scsi_id->login_orb->status_FIFO_lo = SBP2_STATUS_FIFO_ADDRESS_LO; + scsi_id->login_orb->status_FIFO_hi = (ORB_SET_NODE_ID(hi->host->node_id) | SBP2_STATUS_FIFO_ADDRESS_HI); +#endif + SBP2_DEBUG("sbp2: sbp2_login_device: status FIFO initialized"); + + /* + * Byte swap ORB if necessary + */ + sbp2util_cpu_to_be32_buffer(scsi_id->login_orb, sizeof(struct sbp2_login_orb)); + + SBP2_DEBUG("sbp2: sbp2_login_device: orb byte-swapped"); + + /* + * Initialize login response and status fifo + */ + memset(scsi_id->login_response, 0, sizeof(struct sbp2_login_response)); + memset(&scsi_id->status_block, 0, sizeof(struct sbp2_status_block)); + + SBP2_DEBUG("sbp2: sbp2_login_device: login_response/status FIFO memset"); + + /* + * Ok, let's write to the target's management agent register + */ + data[0] = ORB_SET_NODE_ID(hi->host->node_id); + data[1] = scsi_id->login_orb_dma; + sbp2util_cpu_to_be32_buffer(data, 8); + + SBP2_DEBUG("sbp2: sbp2_login_device: prepared to write"); + + hpsb_write(hi->host, LOCAL_BUS | scsi_id->node_id, scsi_id->sbp2_management_agent_addr, data, 8); + + /* + * Wait for login status... but, only if the device has not already logged-in (some devices are fast) + */ + + SBP2_DEBUG("sbp2: sbp2_login_device: written"); + save_flags(flags); + cli(); + if (scsi_id->status_block.ORB_offset_lo != scsi_id->login_orb_dma) { + interruptible_sleep_on_timeout(&scsi_id->sbp2_login_wait, 10*HZ); /* 10 second timeout */ + } + restore_flags(flags); + + SBP2_DEBUG("sbp2: sbp2_login_device: initial check"); + + /* + * Match status to the login orb. If they do not match, it's probably because the login timed-out + */ + if (scsi_id->status_block.ORB_offset_lo != scsi_id->login_orb_dma) { + SBP2_ERR("sbp2: Error logging into SBP-2 device - login timed-out"); + return(-EIO); + } + + SBP2_DEBUG("sbp2: sbp2_login_device: second check"); + + /* + * Check status + */ + if (STATUS_GET_RESP(scsi_id->status_block.ORB_offset_hi_misc) || + STATUS_GET_DEAD_BIT(scsi_id->status_block.ORB_offset_hi_misc) || + STATUS_GET_SBP_STATUS(scsi_id->status_block.ORB_offset_hi_misc)) { + + SBP2_ERR("sbp2: Error logging into SBP-2 device - login failed"); + return(-EIO); + } + + /* + * Byte swap the login response, for use when reconnecting or logging out. + */ + sbp2util_cpu_to_be32_buffer(scsi_id->login_response, sizeof(struct sbp2_login_response)); + + /* + * Grab our command block agent address from the login response + */ + SBP2_DEBUG("sbp2: command_block_agent_hi = %x", (unsigned int)scsi_id->login_response->command_block_agent_hi); + SBP2_DEBUG("sbp2: command_block_agent_lo = %x", (unsigned int)scsi_id->login_response->command_block_agent_lo); + + scsi_id->sbp2_command_block_agent_addr = ((u64)scsi_id->login_response->command_block_agent_hi) << 32; + scsi_id->sbp2_command_block_agent_addr |= ((u64)scsi_id->login_response->command_block_agent_lo); + scsi_id->sbp2_command_block_agent_addr &= 0x0000ffffffffffffULL; + + SBP2_INFO("sbp2: Logged into SBP-2 device"); + + return(0); + +} + +/* + * This function is called in order to logout from a particular SBP-2 device, usually called during driver + * unload + */ +static int sbp2_logout_device(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id) +{ + quadlet_t data[2]; + + SBP2_DEBUG("sbp2: sbp2_logout_device"); + + /* + * Set-up logout ORB + */ + scsi_id->logout_orb->reserved1 = 0x0; + scsi_id->logout_orb->reserved2 = 0x0; + scsi_id->logout_orb->reserved3 = 0x0; + scsi_id->logout_orb->reserved4 = 0x0; + scsi_id->logout_orb->login_ID_misc = ORB_SET_FUNCTION(LOGOUT_REQUEST); + scsi_id->logout_orb->login_ID_misc |= ORB_SET_LOGIN_ID(scsi_id->login_response->length_login_ID); + scsi_id->logout_orb->login_ID_misc |= ORB_SET_NOTIFY(1); /* Notify us when complete */ + scsi_id->logout_orb->reserved5 = 0x0; +#ifdef SBP2_NEED_LOGIN_DESCRIPTOR_WORKAROUND + scsi_id->logout_orb->status_FIFO_lo = cpu_to_le32((u32)SBP2_STATUS_FIFO_ADDRESS_LO); + scsi_id->logout_orb->status_FIFO_hi = (ORB_SET_NODE_ID(hi->host->node_id) | cpu_to_le16(SBP2_STATUS_FIFO_ADDRESS_HI)); +#else + scsi_id->logout_orb->status_FIFO_lo = SBP2_STATUS_FIFO_ADDRESS_LO; + scsi_id->logout_orb->status_FIFO_hi = (ORB_SET_NODE_ID(hi->host->node_id) | SBP2_STATUS_FIFO_ADDRESS_HI); +#endif + + /* + * Byte swap ORB if necessary + */ + sbp2util_cpu_to_be32_buffer(scsi_id->logout_orb, sizeof(struct sbp2_logout_orb)); + + /* + * Ok, let's write to the target's management agent register + */ + data[0] = ORB_SET_NODE_ID(hi->host->node_id); + data[1] = scsi_id->logout_orb_dma; + sbp2util_cpu_to_be32_buffer(data, 8); + + hpsb_write(hi->host, LOCAL_BUS | scsi_id->node_id, scsi_id->sbp2_management_agent_addr, data, 8); + + /* + * Wait for device to logout... + */ + interruptible_sleep_on_timeout(&scsi_id->sbp2_login_wait, HZ); /* 1 second timeout */ + + SBP2_INFO("sbp2: Logged out of SBP-2 device"); + + return(0); + +} + +/* + * This function is called in order to reconnect to a particular SBP-2 device, after a bus reset + */ +static int sbp2_reconnect_device(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id) +{ + quadlet_t data[2]; + unsigned long flags; + + SBP2_DEBUG("sbp2: sbp2_reconnect_device"); + + /* + * Set-up reconnect ORB + */ + scsi_id->reconnect_orb->reserved1 = 0x0; + scsi_id->reconnect_orb->reserved2 = 0x0; + scsi_id->reconnect_orb->reserved3 = 0x0; + scsi_id->reconnect_orb->reserved4 = 0x0; + scsi_id->reconnect_orb->login_ID_misc = ORB_SET_FUNCTION(RECONNECT_REQUEST); + scsi_id->reconnect_orb->login_ID_misc |= ORB_SET_LOGIN_ID(scsi_id->login_response->length_login_ID); + scsi_id->reconnect_orb->login_ID_misc |= ORB_SET_NOTIFY(1); /* Notify us when complete */ + scsi_id->reconnect_orb->reserved5 = 0x0; +#ifdef SBP2_NEED_LOGIN_DESCRIPTOR_WORKAROUND + scsi_id->reconnect_orb->status_FIFO_lo = cpu_to_le32((u32)SBP2_STATUS_FIFO_ADDRESS_LO); + scsi_id->reconnect_orb->status_FIFO_hi = (ORB_SET_NODE_ID(hi->host->node_id) | cpu_to_le16(SBP2_STATUS_FIFO_ADDRESS_HI)); +#else + scsi_id->reconnect_orb->status_FIFO_lo = SBP2_STATUS_FIFO_ADDRESS_LO; + scsi_id->reconnect_orb->status_FIFO_hi = (ORB_SET_NODE_ID(hi->host->node_id) | SBP2_STATUS_FIFO_ADDRESS_HI); +#endif + + /* + * Byte swap ORB if necessary + */ + sbp2util_cpu_to_be32_buffer(scsi_id->reconnect_orb, sizeof(struct sbp2_reconnect_orb)); + + /* + * Initialize status fifo + */ + memset(&scsi_id->status_block, 0, sizeof(struct sbp2_status_block)); + + /* + * Ok, let's write to the target's management agent register + */ + data[0] = ORB_SET_NODE_ID(hi->host->node_id); + data[1] = scsi_id->reconnect_orb_dma; + sbp2util_cpu_to_be32_buffer(data, 8); + + hpsb_write(hi->host, LOCAL_BUS | scsi_id->node_id, scsi_id->sbp2_management_agent_addr, data, 8); + + /* + * Wait for reconnect status... but, only if the device has not already reconnected (some devices are fast) + */ + save_flags(flags); + cli(); + if (scsi_id->status_block.ORB_offset_lo != scsi_id->reconnect_orb_dma) { + interruptible_sleep_on_timeout(&scsi_id->sbp2_login_wait, HZ); /* one second timeout */ + } + restore_flags(flags); + + /* + * Match status to the reconnect orb. If they do not match, it's probably because the reconnect timed-out + */ + if (scsi_id->status_block.ORB_offset_lo != scsi_id->reconnect_orb_dma) { + SBP2_ERR("sbp2: Error reconnecting to SBP-2 device - reconnect timed-out"); + return(-EIO); + } + + /* + * Check status + */ + if (STATUS_GET_RESP(scsi_id->status_block.ORB_offset_hi_misc) || + STATUS_GET_DEAD_BIT(scsi_id->status_block.ORB_offset_hi_misc) || + STATUS_GET_SBP_STATUS(scsi_id->status_block.ORB_offset_hi_misc)) { + + SBP2_ERR("sbp2: Error reconnecting to SBP-2 device - reconnect failed"); + return(-EIO); + } + + SBP2_INFO("sbp2: Reconnected to SBP-2 device"); + + return(0); + +} + +/* + * This function is called in order to set the busy timeout (number of retries to attempt) on the sbp2 device. + */ +static int sbp2_set_busy_timeout(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id) +{ + quadlet_t data; + + SBP2_DEBUG("sbp2: sbp2_set_busy_timeout"); + + /* + * Ok, let's write to the target's busy timeout register + */ + data = cpu_to_be32(SBP2_BUSY_TIMEOUT_VALUE); + + if (hpsb_write(hi->host, LOCAL_BUS | scsi_id->node_id, SBP2_BUSY_TIMEOUT_ADDRESS, &data, 4)) { + SBP2_ERR("sbp2: sbp2_set_busy_timeout error"); + } + + return(0); +} + +/* + * This function is called to parse sbp2 device's config rom unit directory. Used to determine + * things like sbp2 management agent offset, and command set used (SCSI or RBC). + */ +static int sbp2_parse_unit_directory(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id) +{ + quadlet_t unit_directory_length, unit_directory_data; + u64 unit_directory_addr; + u32 i; + + SBP2_DEBUG("sbp2: sbp2_parse_unit_directory"); + + if (sbp2util_unit_directory(hi, LOCAL_BUS | scsi_id->node_id, &unit_directory_addr)) { + SBP2_DEBUG("sbp2: Error reading unit directory address - bad status"); + return(-EIO); + } + + /* + * Read the size of the unit directory + */ + if (sbp2util_read_quadlet(hi, LOCAL_BUS | scsi_id->node_id, unit_directory_addr, + &unit_directory_length)) { + SBP2_DEBUG("sbp2: Error reading unit directory length - bad status"); + return(-EIO); + } + + unit_directory_length = ((be32_to_cpu(unit_directory_length)) >> 16); + + /* + * Now, sweep through the unit directory looking for the management agent offset + * Give up if we hit any error or somehow miss it... + */ + for (i=0; i<unit_directory_length; i++) { + + if (sbp2util_read_quadlet(hi, LOCAL_BUS | scsi_id->node_id, unit_directory_addr + (i<<2) + 4, + &unit_directory_data)) { + SBP2_DEBUG("sbp2: Error reading unit directory - bad status"); + return(-EIO); + } + + /* + * Handle different fields in the unit directory, based on keys + */ + unit_directory_data = be32_to_cpu(unit_directory_data); + switch (unit_directory_data >> 24) { + + case SBP2_CSR_OFFSET_KEY: + + /* + * Save off the management agent address + */ + scsi_id->sbp2_management_agent_addr = CONFIG_ROM_INITIAL_MEMORY_SPACE + + ((unit_directory_data & 0x00ffffff) << 2); + + SBP2_DEBUG("sbp2: sbp2_management_agent_addr = %x", (unsigned int) scsi_id->sbp2_management_agent_addr); + break; + + case SBP2_COMMAND_SET_SPEC_ID_KEY: + + /* + * Command spec organization + */ + scsi_id->sbp2_command_set_spec_id = unit_directory_data & 0xffffff; + SBP2_DEBUG("sbp2: sbp2_command_set_spec_id = %x", (unsigned int) scsi_id->sbp2_command_set_spec_id); + break; + + case SBP2_COMMAND_SET_KEY: + + /* + * Command set used by sbp2 device + */ + scsi_id->sbp2_command_set = unit_directory_data & 0xffffff; + SBP2_DEBUG("sbp2: sbp2_command_set = %x", (unsigned int) scsi_id->sbp2_command_set); + break; + + case SBP2_UNIT_CHARACTERISTICS_KEY: + + /* + * Unit characterisitcs (orb related stuff that I'm not yet paying attention to) + */ + scsi_id->sbp2_unit_characteristics = unit_directory_data & 0xffffff; + SBP2_DEBUG("sbp2: sbp2_unit_characteristics = %x", (unsigned int) scsi_id->sbp2_unit_characteristics); + break; + + case SBP2_DEVICE_TYPE_AND_LUN_KEY: + + /* + * Device type and lun (used for detemining type of sbp2 device) + */ + scsi_id->sbp2_device_type_and_lun = unit_directory_data & 0xffffff; + SBP2_DEBUG("sbp2: sbp2_device_type_and_lun = %x", (unsigned int) scsi_id->sbp2_device_type_and_lun); + break; + + case SBP2_UNIT_SPEC_ID_KEY: + + /* + * Unit spec id (used for protocol detection) + */ + scsi_id->sbp2_unit_spec_id = unit_directory_data & 0xffffff; + SBP2_DEBUG("sbp2: sbp2_unit_spec_id = %x", (unsigned int) scsi_id->sbp2_unit_spec_id); + break; + + case SBP2_UNIT_SW_VERSION_KEY: + + /* + * Unit sw version (used for protocol detection) + */ + scsi_id->sbp2_unit_sw_version = unit_directory_data & 0xffffff; + SBP2_DEBUG("sbp2: sbp2_unit_sw_version = %x", (unsigned int) scsi_id->sbp2_unit_sw_version); + break; + + case SBP2_FIRMWARE_REVISION_KEY: + + /* + * Firmware revision (used to find broken devices). If the vendor id is 0xa0b8 + * (Symbios vendor id), then we have a bridge with 128KB max transfer size limitation. + */ + scsi_id->sbp2_firmware_revision = unit_directory_data & 0xffff00; + if (scsi_id->sbp2_firmware_revision == SBP2_128KB_BROKEN_FIRMWARE) { + SBP2_WARN("sbp2: warning: Bridge chipset supports 128KB max transfer size"); + } + break; + + default: + break; + } + + } + + return(0); +} + +/* + * This function is called in order to determine the max speed and packet size we can use in our ORBs. + */ +static int sbp2_max_speed_and_size(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id) +{ + quadlet_t node_options, max_rec; + u8 speed_code; + + SBP2_DEBUG("sbp2: sbp2_max_speed_and_size"); + + /* + * Get speed code from internal host structure. There should be a better way to obtain this. + */ + speed_code = hi->host->speed_map[(hi->host->node_id & NODE_MASK) * 64 + (scsi_id->node_id & NODE_MASK)]; + + /* + * Bump down our speed if there is a module parameter forcing us slower + */ + if (speed_code > max_speed) { + speed_code = max_speed; + SBP2_ERR("sbp2: Reducing SBP-2 max speed allowed (%x)", max_speed); + } + + switch (speed_code) { + case SPEED_S100: + scsi_id->speed_code = SPEED_S100; + scsi_id->max_payload_size = MAX_PAYLOAD_S100; + SBP2_INFO("sbp2: SBP-2 device max speed S100 and payload 512 bytes"); + break; + case SPEED_S200: + scsi_id->speed_code = SPEED_S200; + scsi_id->max_payload_size = MAX_PAYLOAD_S200; + SBP2_INFO("sbp2: SBP-2 device max speed S200 and payload 1KB"); + break; + case SPEED_S400: + scsi_id->speed_code = SPEED_S400; + scsi_id->max_payload_size = MAX_PAYLOAD_S400; + SBP2_INFO("sbp2: SBP-2 device max speed S400 and payload 2KB"); + break; + default: + scsi_id->speed_code = SPEED_S100; + scsi_id->max_payload_size = MAX_PAYLOAD_S100; + SBP2_ERR("sbp2: Undefined speed: Using SBP-2 device max speed S100 and payload 512 bytes"); + break; + } + + /* + * Finally, check the adapter's capabilities to further bump down our max payload size + * if necessary. For instance, TILynx may not support the default max payload at a + * particular speed. + */ + if (!hpsb_read(hi->host, hi->host->node_id | LOCAL_BUS, CONFIG_ROM_NODE_OPTIONS, &node_options, 4)) { + + /* + * Grab max_rec (max payload = 2 ^ (max_rec+1)) from node options. Sbp2 max payload is + * defined as 2 ^ (max_pay+2)... so, have to subtract one from max rec for comparison... + * confusing, eh? ;-) + */ + max_rec = (be32_to_cpu(node_options) & 0x0000f000) >> 12; + if (scsi_id->max_payload_size > (max_rec - 1)) { + scsi_id->max_payload_size = (max_rec - 1); + SBP2_ERR("sbp2: Reducing SBP-2 max payload allowed (%x)", (max_rec - 1)); + } + + } + + return(0); +} + +/* + * This function is called in order to perform a SBP-2 agent reset. + */ +static int sbp2_agent_reset(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id, u32 flags) +{ + struct sbp2_request_packet *agent_reset_request_packet; + + SBP2_DEBUG("sbp2: sbp2_agent_reset"); + + /* + * Ok, let's write to the target's management agent register + */ + agent_reset_request_packet = sbp2util_allocate_write_request_packet(hi, LOCAL_BUS | scsi_id->node_id, + scsi_id->sbp2_command_block_agent_addr + SBP2_AGENT_RESET_OFFSET, + 0, ntohl(SBP2_AGENT_RESET_DATA)); + + if (!agent_reset_request_packet) { + SBP2_ERR("sbp2: sbp2util_allocate_write_request_packet failed"); + return(-EIO); + } + + if (!hpsb_send_packet(agent_reset_request_packet->packet)) { + SBP2_ERR("sbp2: hpsb_send_packet failed"); + sbp2util_free_request_packet(agent_reset_request_packet); + return(-EIO); + } + + if (!(flags & SBP2_SEND_NO_WAIT)) { + down(&agent_reset_request_packet->packet->state_change); + down(&agent_reset_request_packet->packet->state_change); + } + + /* + * Need to make sure orb pointer is written on next command + */ + scsi_id->last_orb = NULL; + + return(0); + +} + +/* + * This function is called to create the actual command orb and s/g list out of the + * scsi command itself. + */ +static int sbp2_create_command_orb(struct sbp2scsi_host_info *hi, + struct scsi_id_instance_data *scsi_id, + struct sbp2_command_info *command, + unchar *scsi_cmd, + unsigned int scsi_use_sg, + unsigned int scsi_request_bufflen, + void *scsi_request_buffer, int dma_dir) +{ + struct scatterlist *sgpnt = (struct scatterlist *) scsi_request_buffer; + struct sbp2_command_orb *command_orb = &command->command_orb; + struct sbp2_unrestricted_page_table *scatter_gather_element = + &command->scatter_gather_element[0]; + u32 sg_count, sg_len; + dma_addr_t sg_addr; + int i; + + /* + * Set-up our command ORB.. + * + * NOTE: We're doing unrestricted page tables (s/g), as this is best performance + * (at least with the devices I have). This means that data_size becomes the number + * of s/g elements, and page_size should be zero (for unrestricted). + */ + command_orb->next_ORB_hi = 0xffffffff; + command_orb->next_ORB_lo = 0xffffffff; + command_orb->misc = ORB_SET_MAX_PAYLOAD(scsi_id->max_payload_size); + command_orb->misc |= ORB_SET_SPEED(scsi_id->speed_code); + command_orb->misc |= ORB_SET_NOTIFY(1); /* Notify us when complete */ + + /* + * Set-up our pagetable stuff... unfortunately, this has become messier than I'd like. Need to + * clean this up a bit. ;-) + */ + if (sbp2scsi_direction_table[*scsi_cmd] == ORB_DIRECTION_NO_DATA_TRANSFER) { + + SBP2_DEBUG("sbp2: No data transfer"); + + /* + * Handle no data transfer + */ + command_orb->data_descriptor_hi = 0xffffffff; + command_orb->data_descriptor_lo = 0xffffffff; + command_orb->misc |= ORB_SET_DIRECTION(1); + + } else if (scsi_use_sg) { + + SBP2_DEBUG("sbp2: Use scatter/gather"); + + /* + * Special case if only one element (and less than 64KB in size) + */ + if ((scsi_use_sg == 1) && (sgpnt[0].length <= SBP2_MAX_SG_ELEMENT_LENGTH)) { + + SBP2_DEBUG("sbp2: Only one s/g element"); + command->dma_dir = dma_dir; + command->dma_size = sgpnt[0].length; + command->cmd_dma = pci_map_single (hi->host->pdev, sgpnt[0].address, + command->dma_size, + command->dma_dir); + SBP2_DMA_ALLOC("single scatter element"); + + command_orb->data_descriptor_hi = ORB_SET_NODE_ID(hi->host->node_id); + command_orb->data_descriptor_lo = command->cmd_dma; + command_orb->misc |= ORB_SET_DATA_SIZE(command->dma_size); + command_orb->misc |= ORB_SET_DIRECTION(sbp2scsi_direction_table[*scsi_cmd]); + + } else { + int count = pci_map_sg(hi->host->pdev, sgpnt, scsi_use_sg, dma_dir); + SBP2_DMA_ALLOC("scatter list"); + + command->dma_size = scsi_use_sg; + command->dma_dir = dma_dir; + command->sge_buffer = sgpnt; + + /* use page tables (s/g) */ + command_orb->misc |= ORB_SET_PAGE_TABLE_PRESENT(0x1); + command_orb->misc |= ORB_SET_DIRECTION(sbp2scsi_direction_table[*scsi_cmd]); + command_orb->data_descriptor_hi = ORB_SET_NODE_ID(hi->host->node_id); + command_orb->data_descriptor_lo = command->sge_dma; + + /* + * Loop through and fill out our sbp-2 page tables + * (and split up anything too large) + */ + for (i = 0, sg_count = 0 ; i < count; i++, sgpnt++) { + sg_len = sg_dma_len(sgpnt); + sg_addr = sg_dma_address(sgpnt); + while (sg_len) { + scatter_gather_element[sg_count].segment_base_lo = sg_addr; + if (sg_len > SBP2_MAX_SG_ELEMENT_LENGTH) { + scatter_gather_element[sg_count].length_segment_base_hi = + PAGE_TABLE_SET_SEGMENT_LENGTH(SBP2_MAX_SG_ELEMENT_LENGTH); + sg_addr += SBP2_MAX_SG_ELEMENT_LENGTH; + sg_len -= SBP2_MAX_SG_ELEMENT_LENGTH; + } else { + scatter_gather_element[sg_count].length_segment_base_hi = + PAGE_TABLE_SET_SEGMENT_LENGTH(sg_len); + sg_len = 0; + } + sg_count++; + } + } + + command_orb->misc |= ORB_SET_DATA_SIZE(sg_count); /* number of page table (s/g) elements */ + + /* + * Byte swap page tables if necessary + */ + sbp2util_cpu_to_be32_buffer(scatter_gather_element, + (sizeof(struct sbp2_unrestricted_page_table)) * sg_count); + + } + + } else { + + SBP2_DEBUG("sbp2: No scatter/gather"); + + command->dma_dir = dma_dir; + command->dma_size = scsi_request_bufflen; + command->cmd_dma = pci_map_single (hi->host->pdev, scsi_request_buffer, + command->dma_size, + command->dma_dir); + SBP2_DMA_ALLOC("single bulk"); + + /* + * Handle case where we get a command w/o s/g enabled (but check + * for transfers larger than 64K) + */ + if (scsi_request_bufflen <= SBP2_MAX_SG_ELEMENT_LENGTH) { + + command_orb->data_descriptor_hi = ORB_SET_NODE_ID(hi->host->node_id); + command_orb->data_descriptor_lo = command->cmd_dma; + command_orb->misc |= ORB_SET_DATA_SIZE(scsi_request_bufflen); + command_orb->misc |= ORB_SET_DIRECTION(sbp2scsi_direction_table[*scsi_cmd]); + + /* + * Sanity, in case our direction table is not up-to-date + */ + if (!scsi_request_bufflen) { + command_orb->data_descriptor_hi = 0xffffffff; + command_orb->data_descriptor_lo = 0xffffffff; + command_orb->misc |= ORB_SET_DIRECTION(1); + } + + } else { + /* + * Need to turn this into page tables, since the buffer is too large. + */ + command_orb->data_descriptor_hi = ORB_SET_NODE_ID(hi->host->node_id); + command_orb->data_descriptor_lo = command->sge_dma; + command_orb->misc |= ORB_SET_PAGE_TABLE_PRESENT(0x1); /* use page tables (s/g) */ + command_orb->misc |= ORB_SET_DIRECTION(sbp2scsi_direction_table[*scsi_cmd]); + + /* + * fill out our sbp-2 page tables (and split up the large buffer) + */ + sg_count = 0; + sg_len = scsi_request_bufflen; + sg_addr = command->cmd_dma; + while (sg_len) { + scatter_gather_element[sg_count].segment_base_lo = sg_addr; + if (sg_len > SBP2_MAX_SG_ELEMENT_LENGTH) { + scatter_gather_element[sg_count].length_segment_base_hi = + PAGE_TABLE_SET_SEGMENT_LENGTH(SBP2_MAX_SG_ELEMENT_LENGTH); + sg_addr += SBP2_MAX_SG_ELEMENT_LENGTH; + sg_len -= SBP2_MAX_SG_ELEMENT_LENGTH; + } else { + scatter_gather_element[sg_count].length_segment_base_hi = + PAGE_TABLE_SET_SEGMENT_LENGTH(sg_len); + sg_len = 0; + } + sg_count++; + } + + command_orb->misc |= ORB_SET_DATA_SIZE(sg_count); /* number of page table (s/g) elements */ + + /* + * Byte swap page tables if necessary + */ + sbp2util_cpu_to_be32_buffer(scatter_gather_element, + (sizeof(struct sbp2_unrestricted_page_table)) * + sg_count); + + } + + } + + /* + * Byte swap command ORB if necessary + */ + sbp2util_cpu_to_be32_buffer(command_orb, sizeof(struct sbp2_command_orb)); + + /* + * Put our scsi command in the command ORB + */ + memset(command_orb->cdb, 0, 12); + memcpy(command_orb->cdb, scsi_cmd, COMMAND_SIZE(*scsi_cmd)); + + return(0); +} + +/* + * This function is called in order to begin a regular SBP-2 command. + */ +static int sbp2_link_orb_command(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id, + struct sbp2_command_info *command) +{ + struct sbp2_request_packet *command_request_packet; + struct sbp2_command_orb *command_orb = &command->command_orb; + + outstanding_orb_incr; + SBP2_ORB_DEBUG("sending command orb %p, linked = %x, total orbs = %x", + command_orb, command->linked, global_outstanding_command_orbs); + + /* + * Check to see if there are any previous orbs to use + */ + if (scsi_id->last_orb == NULL) { + + /* + * Ok, let's write to the target's management agent register + */ + if (!hi->bus_reset_in_progress) { + + command_request_packet = sbp2util_allocate_write_request_packet(hi, LOCAL_BUS | scsi_id->node_id, + scsi_id->sbp2_command_block_agent_addr + SBP2_ORB_POINTER_OFFSET, + 8, 0); + + if (!command_request_packet) { + SBP2_ERR("sbp2: sbp2util_allocate_write_request_packet failed"); + return(-EIO); + } + + command_request_packet->packet->data[0] = ORB_SET_NODE_ID(hi->host->node_id); + command_request_packet->packet->data[1] = command->command_orb_dma; + sbp2util_cpu_to_be32_buffer(command_request_packet->packet->data, 8); + + SBP2_ORB_DEBUG("write command agent, command orb %p", command_orb); + + if (!hpsb_send_packet(command_request_packet->packet)) { + SBP2_ERR("sbp2: hpsb_send_packet failed"); + sbp2util_free_request_packet(command_request_packet); + return(-EIO); + } + + SBP2_ORB_DEBUG("write command agent complete"); + } + + scsi_id->last_orb = command_orb; + + } else { + + /* + * We have an orb already sent (maybe or maybe not + * processed) that we can append this orb to. So do so, + * and ring the doorbell. Have to be very careful + * modifying these next orb pointers, as they are accessed + * both by the sbp2 device and us. + */ + scsi_id->last_orb->next_ORB_lo = cpu_to_be32(command->command_orb_dma); + scsi_id->last_orb->next_ORB_hi = 0x0; /* Tells hardware that this pointer is valid */ + + /* + * Only ring the doorbell if we need to (first parts of linked orbs don't need this) + */ + if (!command->linked && !hi->bus_reset_in_progress) { + + command_request_packet = sbp2util_allocate_write_request_packet(hi, + LOCAL_BUS | scsi_id->node_id, + scsi_id->sbp2_command_block_agent_addr + SBP2_DOORBELL_OFFSET, + 0, cpu_to_be32(command->command_orb_dma)); + + if (!command_request_packet) { + SBP2_ERR("sbp2: sbp2util_allocate_write_request_packet failed"); + return(-EIO); + } + + SBP2_ORB_DEBUG("ring doorbell, command orb %p", command_orb); + + if (!hpsb_send_packet(command_request_packet->packet)) { + SBP2_ERR("sbp2: hpsb_send_packet failed"); + sbp2util_free_request_packet(command_request_packet); + return(-EIO); + } + } + + scsi_id->last_orb = command_orb; + + } + return(0); +} + +/* + * This function is called in order to begin a regular SBP-2 command. + */ +static int sbp2_send_command(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id, + Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) +{ + unchar *cmd = (unchar *) SCpnt->cmnd; + u32 device_type = (scsi_id->sbp2_device_type_and_lun & 0x00ff0000) >> 16; + struct sbp2_command_info *command; + + SBP2_DEBUG("sbp2: sbp2_send_command"); + SBP2_DEBUG("sbp2: SCSI command = %02x", *cmd); + SBP2_DEBUG("sbp2: SCSI transfer size = %x", SCpnt->request_bufflen); + SBP2_DEBUG("sbp2: SCSI s/g elements = %x", (unsigned int)SCpnt->use_sg); + + /* + * Check for broken devices that can't handle greater than 128K transfers, and deal with them in a + * hacked ugly way. + */ + if ((scsi_id->sbp2_firmware_revision == SBP2_128KB_BROKEN_FIRMWARE) && + (SCpnt->request_bufflen > SBP2_BROKEN_FIRMWARE_MAX_TRANSFER) && + (device_type == TYPE_DISK) && + (SCpnt->use_sg) && + (*cmd == 0x28 || *cmd == 0x2a || *cmd == 0x0a || *cmd == 0x08)) { + + /* + * Darn, a broken device. We'll need to split up the transfer ourselves + */ + sbp2_send_split_command(hi, scsi_id, SCpnt, done); + return(0); + } + + /* + * Allocate a command orb and s/g structure + */ + command = sbp2util_allocate_command_orb(scsi_id, SCpnt, done, hi); + if (!command) { + return(-EIO); + } + + /* + * Now actually fill in the comamnd orb and sbp2 s/g list + */ + sbp2_create_command_orb(hi, scsi_id, command, cmd, SCpnt->use_sg, + SCpnt->request_bufflen, SCpnt->request_buffer, + scsi_to_pci_dma_dir(SCpnt->sc_data_direction)); + + /* + * Update our cdb if necessary (to handle sbp2 RBC command set differences). + * This is where the command set hacks go! =) + */ + if ((device_type == TYPE_DISK) || + (device_type == TYPE_SDAD) || + (device_type == TYPE_ROM)) { + sbp2_check_sbp2_command(command->command_orb.cdb); + } + + /* + * Initialize status fifo + */ + memset(&scsi_id->status_block, 0, sizeof(struct sbp2_status_block)); + + /* + * Link up the orb, and ring the doorbell if needed + */ + sbp2_link_orb_command(hi, scsi_id, command); + + return(0); +} + +/* + * This function is called for broken sbp2 device, where we have to break up large transfers. + */ +static int sbp2_send_split_command(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id, + Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) +{ + unchar *cmd = (unchar *) SCpnt->cmnd; + struct scatterlist *sgpnt = (struct scatterlist *) SCpnt->request_buffer; + struct sbp2_command_info *command; + unsigned int i, block_count, block_address, block_size; + unsigned int current_sg = 0; + unsigned int total_transfer = 0; + unsigned int total_sg = 0; + unchar new_cmd[12]; + + memset(new_cmd, 0, 12); + memcpy(new_cmd, cmd, COMMAND_SIZE(*cmd)); + + /* + * Turns command into 10 byte version + */ + sbp2_check_sbp2_command(new_cmd); + + /* + * Pull block size, block address, block count from command sent down + */ + block_count = (cmd[7] << 8) | cmd[8]; + block_address = (cmd[2] << 24) | (cmd[3] << 16) | (cmd[4] << 8) | cmd[5]; + block_size = SCpnt->request_bufflen/block_count; + + /* + * Walk the scsi s/g list to determine how much we can transfer in one pop + */ + for (i=0; i<SCpnt->use_sg; i++) { + + total_transfer+=sgpnt[i].length; + total_sg++; + + if (total_transfer > SBP2_BROKEN_FIRMWARE_MAX_TRANSFER) { + + /* + * Back everything up one, so that we're less than 128KB + */ + total_transfer-=sgpnt[i].length; + total_sg--; + i--; + + command = sbp2util_allocate_command_orb(scsi_id, SCpnt, done, hi); + if (!command) { + return(-EIO); + } + + /* + * This is not the final piece, so mark it as linked + */ + command->linked = 1; + + block_count = total_transfer/block_size; + new_cmd[2] = (unchar) (block_address >> 24) & 0xff; + new_cmd[3] = (unchar) (block_address >> 16) & 0xff; + new_cmd[4] = (unchar) (block_address >> 8) & 0xff; + new_cmd[5] = (unchar) block_address & 0xff; + new_cmd[7] = (unchar) (block_count >> 8) & 0xff; + new_cmd[8] = (unchar) block_count & 0xff; + block_address+=block_count; + + sbp2_create_command_orb(hi, scsi_id, command, new_cmd, total_sg, + total_transfer, &sgpnt[current_sg], + scsi_to_pci_dma_dir(SCpnt->sc_data_direction)); + + /* + * Link up the orb, and ring the doorbell if needed + */ + memset(&scsi_id->status_block, 0, sizeof(struct sbp2_status_block)); + sbp2_link_orb_command(hi, scsi_id, command); + + current_sg += total_sg; + total_sg = 0; + total_transfer = 0; + + } + + } + + /* + * Get the last piece... + */ + command = sbp2util_allocate_command_orb(scsi_id, SCpnt, done, hi); + if (!command) { + return(-EIO); + } + + block_count = total_transfer/block_size; + new_cmd[2] = (unchar) (block_address >> 24) & 0xff; + new_cmd[3] = (unchar) (block_address >> 16) & 0xff; + new_cmd[4] = (unchar) (block_address >> 8) & 0xff; + new_cmd[5] = (unchar) block_address & 0xff; + new_cmd[7] = (unchar) (block_count >> 8) & 0xff; + new_cmd[8] = (unchar) block_count & 0xff; + + sbp2_create_command_orb(hi, scsi_id, command, new_cmd, total_sg, + total_transfer, &sgpnt[current_sg], + scsi_to_pci_dma_dir(SCpnt->sc_data_direction)); + + /* + * Link up the orb, and ring the doorbell if needed + */ + memset(&scsi_id->status_block, 0, sizeof(struct sbp2_status_block)); + sbp2_link_orb_command(hi, scsi_id, command); + + + return(0); +} + +/* + * This function deals with command set differences between Linux scsi command set and sbp2 RBC + * command set. + */ +static void sbp2_check_sbp2_command(unchar *cmd) +{ + unchar new_cmd[16]; + + SBP2_DEBUG("sbp2: sbp2_check_sbp2_command"); + + switch (*cmd) { + + case READ_6: + + SBP2_DEBUG("sbp2: Convert READ_6 to READ_10"); + + /* + * Need to turn read_6 into read_10 + */ + new_cmd[0] = 0x28; + new_cmd[1] = (cmd[1] & 0xe0); + new_cmd[2] = 0x0; + new_cmd[3] = (cmd[1] & 0x1f); + new_cmd[4] = cmd[2]; + new_cmd[5] = cmd[3]; + new_cmd[6] = 0x0; + new_cmd[7] = 0x0; + new_cmd[8] = cmd[4]; + new_cmd[9] = cmd[5]; + + memcpy(cmd, new_cmd, 10); + + break; + + case WRITE_6: + + SBP2_DEBUG("sbp2: Convert WRITE_6 to WRITE_10"); + + /* + * Need to turn write_6 into write_10 + */ + new_cmd[0] = 0x2a; + new_cmd[1] = (cmd[1] & 0xe0); + new_cmd[2] = 0x0; + new_cmd[3] = (cmd[1] & 0x1f); + new_cmd[4] = cmd[2]; + new_cmd[5] = cmd[3]; + new_cmd[6] = 0x0; + new_cmd[7] = 0x0; + new_cmd[8] = cmd[4]; + new_cmd[9] = cmd[5]; + + memcpy(cmd, new_cmd, 10); + + break; + + case MODE_SENSE: + + SBP2_DEBUG("sbp2: Convert MODE_SENSE_6 to MOSE_SENSE_10"); + + /* + * Need to turn mode_sense_6 into mode_sense_10 + */ + new_cmd[0] = 0x5a; + new_cmd[1] = cmd[1]; + new_cmd[2] = cmd[2]; + new_cmd[3] = 0x0; + new_cmd[4] = 0x0; + new_cmd[5] = 0x0; + new_cmd[6] = 0x0; + new_cmd[7] = 0x0; + new_cmd[8] = cmd[4]; + new_cmd[9] = cmd[5]; + + memcpy(cmd, new_cmd, 10); + + break; + + case MODE_SELECT: + + /* + * TODO. Probably need to change mode select to 10 byte version + */ + + default: + break; + } + + return; +} + +/* + * Translates SBP-2 status into SCSI sense data for check conditions + */ +static unsigned int sbp2_status_to_sense_data(unchar *sbp2_status, unchar *sense_data) +{ + SBP2_DEBUG("sbp2: sbp2_status_to_sense_data"); + + /* + * Ok, it's pretty ugly... ;-) + */ + sense_data[0] = 0x70; + sense_data[1] = 0x0; + sense_data[2] = sbp2_status[9]; + sense_data[3] = sbp2_status[12]; + sense_data[4] = sbp2_status[13]; + sense_data[5] = sbp2_status[14]; + sense_data[6] = sbp2_status[15]; + sense_data[7] = 10; + sense_data[8] = sbp2_status[16]; + sense_data[9] = sbp2_status[17]; + sense_data[10] = sbp2_status[18]; + sense_data[11] = sbp2_status[19]; + sense_data[12] = sbp2_status[10]; + sense_data[13] = sbp2_status[11]; + sense_data[14] = sbp2_status[20]; + sense_data[15] = sbp2_status[21]; + + return(sbp2_status[8] & 0x3f); /* return scsi status */ +} + +/* + * This function is called after a command is completed, in order to do any necessary SBP-2 + * response data translations for the SCSI stack + */ +static void sbp2_check_sbp2_response(struct sbp2scsi_host_info *hi, + struct scsi_id_instance_data *scsi_id, + Scsi_Cmnd *SCpnt) +{ + u8 *scsi_buf = SCpnt->request_buffer; + u32 device_type = (scsi_id->sbp2_device_type_and_lun & 0x00ff0000) >> 16; + + SBP2_DEBUG("sbp2: sbp2_check_sbp2_response"); + + switch (SCpnt->cmnd[0]) { + + case INQUIRY: + + SBP2_DEBUG("sbp2: Check Inquiry data"); + + /* + * Check for Simple Direct Access Device and change it to TYPE_DISK + */ + if ((scsi_buf[0] & 0x1f) == TYPE_SDAD) { + SBP2_DEBUG("sbp2: Changing TYPE_SDAD to TYPE_DISK"); + scsi_buf[0] &= 0xe0; + } + + /* + * Fix ansi revision and response data format + */ + scsi_buf[2] |= 2; + scsi_buf[3] = (scsi_buf[3] & 0xf0) | 2; + + break; + + case MODE_SENSE: + + if ((device_type == TYPE_DISK) || + (device_type == TYPE_SDAD) || + (device_type == TYPE_ROM)) { + + SBP2_DEBUG("sbp2: Modify mode sense response (10 byte version)"); + + scsi_buf[0] = scsi_buf[1]; /* Mode data length */ + scsi_buf[1] = scsi_buf[2]; /* Medium type */ + scsi_buf[2] = scsi_buf[3]; /* Device specific parameter */ + scsi_buf[3] = scsi_buf[7]; /* Block descriptor length */ + memcpy(scsi_buf + 4, scsi_buf + 8, scsi_buf[0]); + + } + + break; + + case MODE_SELECT: + + /* + * TODO. Probably need to change mode select to 10 byte version + */ + + default: + break; + } + return; +} + +/* + * This function deals with status writes from the SBP-2 device + */ +static int sbp2_handle_status_write(struct hpsb_host *host, int nodeid, int destid, + quadlet_t *data, u64 addr, unsigned int length) +{ + struct sbp2scsi_host_info *hi = NULL; + struct scsi_id_instance_data *scsi_id = NULL; + int i; + unsigned long flags; + Scsi_Cmnd *SCpnt = NULL; + u32 scsi_status = SBP2_SCSI_STATUS_GOOD; + struct sbp2_command_info *command; + + SBP2_DEBUG("sbp2: sbp2_handle_status_write"); + + if (!host) { + SBP2_ERR("sbp2: host is NULL - this is bad!"); + return(RCODE_ADDRESS_ERROR); + } + + sbp2_spin_lock(&sbp2_host_info_lock, flags); + hi = sbp2_find_host_info(host); + sbp2_spin_unlock(&sbp2_host_info_lock, flags); + + if (!hi) { + SBP2_ERR("sbp2: host info is NULL - this is bad!"); + return(RCODE_ADDRESS_ERROR); + } + + sbp2_spin_lock(&hi->sbp2_command_lock, flags); + + /* + * Find our scsi_id structure + */ + for (i=0; i<SBP2SCSI_MAX_SCSI_IDS; i++) { + if (hi->scsi_id[i]) { + if (hi->scsi_id[i]->node_id == (nodeid & NODE_MASK)) { + scsi_id = hi->scsi_id[i]; + SBP2_DEBUG("sbp2: SBP-2 status write from node %x", scsi_id->node_id); + break; + } + } + } + + if (!scsi_id) { + SBP2_ERR("sbp2: scsi_id is NULL - device is gone?"); + sbp2_spin_unlock(&hi->sbp2_command_lock, flags); + return(RCODE_ADDRESS_ERROR); + } + + /* + * Put response into scsi_id status fifo... + */ + memcpy(&scsi_id->status_block, data, length); + + /* + * Byte swap first two quadlets (8 bytes) of status for processing + */ + sbp2util_be32_to_cpu_buffer(&scsi_id->status_block, 8); + + /* + * Handle command ORB status here if necessary. First, need to match status with command. + */ + command = sbp2util_find_command_for_orb(scsi_id, scsi_id->status_block.ORB_offset_lo); + if (command) { + + SBP2_DEBUG("sbp2: Found status for command ORB"); + + SBP2_ORB_DEBUG("matched command orb %p", &command->command_orb); + outstanding_orb_decr; + + /* + * Matched status with command, now grab scsi command pointers and check status + */ + SCpnt = command->Current_SCpnt; + sbp2util_mark_command_completed(scsi_id, command); + + if (SCpnt && !command->linked) { + + /* + * Handle check conditions + */ + if (STATUS_GET_SBP_STATUS(scsi_id->status_block.ORB_offset_hi_misc)) { + + SBP2_DEBUG("sbp2: CHECK CONDITION"); + + /* + * Translate SBP-2 status to SCSI sense data + */ + scsi_status = sbp2_status_to_sense_data((unchar *)&scsi_id->status_block, SCpnt->sense_buffer); + + /* + * Initiate a fetch agent reset. + */ + sbp2_agent_reset(hi, scsi_id, SBP2_SEND_NO_WAIT); + + } + + SBP2_ORB_DEBUG("completing command orb %p", &command->command_orb); + + /* + * Complete the SCSI command + */ + SBP2_DEBUG("sbp2: Completing SCSI command"); + sbp2scsi_complete_command(hi, scsi_id, scsi_status, SCpnt, command->Current_done); + SBP2_ORB_DEBUG("command orb completed"); + } + + /* + * Check here to see if there are no commands in-use. If there are none, we can + * null out last orb so that next time around we write directly to the orb pointer... + * Quick start saves one 1394 bus transaction. + */ + if (list_empty(&scsi_id->sbp2_command_orb_inuse)) { + scsi_id->last_orb = NULL; + } + + } + + sbp2_spin_unlock(&hi->sbp2_command_lock, flags); + wake_up(&scsi_id->sbp2_login_wait); + return(RCODE_COMPLETE); +} + + +/************************************** + * SCSI interface related section + **************************************/ + +/* + * This routine is the main request entry routine for doing I/O. It is + * called from the scsi stack directly. + */ +static int sbp2scsi_queuecommand (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) +{ + struct sbp2scsi_host_info *hi = NULL; + struct scsi_id_instance_data *scsi_id = NULL; + unsigned long flags; + + SBP2_DEBUG("sbp2: sbp2scsi_queuecommand"); + + /* + * Pull our host info and scsi id instance data from the scsi command + */ + hi = (struct sbp2scsi_host_info *) SCpnt->host->hostdata[0]; + + if (!hi) { + SBP2_ERR("sbp2: sbp2scsi_host_info is NULL - this is bad!"); + SCpnt->result = DID_NO_CONNECT << 16; + done (SCpnt); + return(0); + } + + scsi_id = hi->scsi_id[SCpnt->target]; + + /* + * Save off the command if this is the initial bus scan... so that we can + * complete it after we find all our sbp2 devices on the 1394 bus + */ + if (!no_bus_scan && !hi->initial_scsi_bus_scan_complete) { + hi->bus_scan_SCpnt = SCpnt; + hi->bus_scan_done = done; + return(0); + } + + /* + * If scsi_id is null, it means there is no device in this slot, so we should return + * selection timeout. + */ + if (!scsi_id) { + SCpnt->result = DID_NO_CONNECT << 16; + done (SCpnt); + return(0); + } + + /* + * Until we handle multiple luns, just return selection time-out to any IO directed at non-zero LUNs + */ + if (SCpnt->lun) { + SCpnt->result = DID_NO_CONNECT << 16; + done (SCpnt); + return(0); + } + + /* + * Check for request sense command, and handle it here (autorequest sense) + */ + if (SCpnt->cmnd[0] == REQUEST_SENSE) { + SBP2_DEBUG("sbp2: REQUEST_SENSE"); + memcpy(SCpnt->request_buffer, SCpnt->sense_buffer, SCpnt->request_bufflen); + memset(SCpnt->sense_buffer, 0, sizeof(SCpnt->sense_buffer)); + sbp2scsi_complete_command(hi, scsi_id, SBP2_SCSI_STATUS_GOOD, SCpnt, done); + return(0); + } + + /* + * Check to see if there is a command in progress and just return busy (to be queued later) + */ + if (hi->bus_reset_in_progress) { + SBP2_ERR("sbp2: Bus reset in progress - rejecting command"); + SCpnt->result = DID_BUS_BUSY << 16; + done (SCpnt); + return(0); + } + + /* + * Try and send our SCSI command + */ + sbp2_spin_lock(&hi->sbp2_command_lock, flags); + if (sbp2_send_command(hi, scsi_id, SCpnt, done)) { + SBP2_ERR("sbp2: Error sending SCSI command"); + sbp2scsi_complete_command(hi, scsi_id, SBP2_SCSI_STATUS_SELECTION_TIMEOUT, SCpnt, done); + } + sbp2_spin_unlock(&hi->sbp2_command_lock, flags); + + return(0); +} + +/* + * This function is called in order to complete all outstanding SBP-2 commands (in case of resets, etc.). + */ +static void sbp2scsi_complete_all_commands(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id, + u32 status) +{ + struct list_head *lh; + struct sbp2_command_info *command; + + SBP2_DEBUG("sbp2: sbp2_complete_all_commands"); + + while (!list_empty(&scsi_id->sbp2_command_orb_inuse)) { + SBP2_DEBUG("sbp2: Found pending command to complete"); + lh = scsi_id->sbp2_command_orb_inuse.next; + command = list_entry(lh, struct sbp2_command_info, list); + sbp2util_mark_command_completed(scsi_id, command); + if (command->Current_SCpnt && !command->linked) { + void (*done)(Scsi_Cmnd *) = command->Current_done; + command->Current_SCpnt->result = status << 16; + done (command->Current_SCpnt); + } + } + + return; +} + +/* + * This function is called in order to complete a regular SBP-2 command. + */ +static void sbp2scsi_complete_command(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id, u32 scsi_status, + Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) +{ + SBP2_DEBUG("sbp2: sbp2scsi_complete_command"); + + /* + * Sanity + */ + if (!SCpnt) { + SBP2_ERR("sbp2: SCpnt is NULL"); + return; + } + + /* + * If a bus reset is in progress and there was an error, don't complete the command, + * just let it get retried at the end of the bus reset. + */ + if ((hi->bus_reset_in_progress) && (scsi_status != SBP2_SCSI_STATUS_GOOD)) { + SBP2_ERR("sbp2: Bus reset in progress - retry command later"); + return; + } + + /* + * Switch on scsi status + */ + switch (scsi_status) { + case SBP2_SCSI_STATUS_GOOD: + SCpnt->result = DID_OK; + break; + + case SBP2_SCSI_STATUS_BUSY: + SBP2_ERR("sbp2: SBP2_SCSI_STATUS_BUSY"); + SCpnt->result = DID_BUS_BUSY << 16; + break; + + case SBP2_SCSI_STATUS_CHECK_CONDITION: + SBP2_DEBUG("sbp2: SBP2_SCSI_STATUS_CHECK_CONDITION"); + SCpnt->result = CHECK_CONDITION << 1; + + /* + * Debug stuff + */ + print_sense("bh", SCpnt); + + break; + + case SBP2_SCSI_STATUS_SELECTION_TIMEOUT: + SBP2_ERR("sbp2: SBP2_SCSI_STATUS_SELECTION_TIMEOUT"); + SCpnt->result = DID_NO_CONNECT << 16; + break; + + case SBP2_SCSI_STATUS_CONDITION_MET: + case SBP2_SCSI_STATUS_RESERVATION_CONFLICT: + case SBP2_SCSI_STATUS_COMMAND_TERMINATED: + SBP2_ERR("sbp2: Bad SCSI status = %x", scsi_status); + SCpnt->result = DID_ERROR << 16; + break; + + default: + SBP2_ERR("sbp2: Unsupported SCSI status = %x", scsi_status); + SCpnt->result = DID_ERROR << 16; + } + + /* + * Take care of any sbp2 response data mucking here (RBC stuff, etc.) + */ + if (SCpnt->result == DID_OK) { + sbp2_check_sbp2_response(hi, scsi_id, SCpnt); + } + + /* + * One more quick hack (not enabled by default). Some sbp2 devices do not support + * mode sense. Turn-on this hack to allow the device to pass the sd driver's + * write-protect test (so that you can mount the device rw). + */ + if (mode_sense_hack && SCpnt->result != DID_OK && SCpnt->cmnd[0] == MODE_SENSE) { + SBP2_INFO("sbp2: Returning success to mode sense command"); + SCpnt->result = DID_OK; + SCpnt->sense_buffer[0] = 0; + memset (SCpnt->request_buffer, 0, 8); + } + + /* + * If a bus reset is in progress and there was an error, complete the command + * as busy so that it will get retried. + */ + if ((hi->bus_reset_in_progress) && (scsi_status != SBP2_SCSI_STATUS_GOOD)) { + SBP2_ERR("sbp2: Completing command with busy (bus reset)"); + SCpnt->result = DID_BUS_BUSY << 16; + } + + /* + * If a unit attention occurs, return busy status so it gets retried... it could have happened because + * of a 1394 bus reset or hot-plug... + */ + if ((scsi_status == SBP2_SCSI_STATUS_CHECK_CONDITION) && (SCpnt->sense_buffer[2] == UNIT_ATTENTION)) { + SBP2_INFO("sbp2: UNIT ATTENTION - return busy"); + SCpnt->result = DID_BUS_BUSY << 16; + } + + /* + * Tell scsi stack that we're done with this command + */ + done (SCpnt); + + return; +} + +/* + * Called by scsi stack when something has really gone wrong. + * Usually called when a command has timed-out for some reason. + */ +static int sbp2scsi_abort (Scsi_Cmnd *SCpnt) +{ + struct sbp2scsi_host_info *hi = (struct sbp2scsi_host_info *) SCpnt->host->hostdata[0]; + struct scsi_id_instance_data *scsi_id = hi->scsi_id[SCpnt->target]; + struct sbp2_command_info *command; + unsigned long flags; + + SBP2_ERR("sbp2: aborting sbp2 command"); + + if (scsi_id) { + + /* + * Right now, just return any matching command structures to the free pool (there may + * be more than one because of broken up/linked commands). + */ + sbp2_spin_lock(&hi->sbp2_command_lock, flags); + do { + command = sbp2util_find_command_for_SCpnt(scsi_id, SCpnt); + if (command) { + SBP2_DEBUG("sbp2: Found command to abort"); + sbp2util_mark_command_completed(scsi_id, command); + if (command->Current_SCpnt && !command->linked) { + void (*done)(Scsi_Cmnd *) = command->Current_done; + command->Current_SCpnt->result = DID_ABORT << 16; + done (command->Current_SCpnt); + } + } + } while (command); + + /* + * Initiate a fetch agent reset. + */ + sbp2_agent_reset(hi, scsi_id, SBP2_SEND_NO_WAIT); + sbp2scsi_complete_all_commands(hi, scsi_id, DID_BUS_BUSY); + sbp2_spin_unlock(&hi->sbp2_command_lock, flags); + } + + return(SCSI_ABORT_SUCCESS); +} + +/* + * Called by scsi stack when something has really gone wrong. + */ +static int sbp2scsi_reset (Scsi_Cmnd *SCpnt, unsigned int reset_flags) +{ + struct sbp2scsi_host_info *hi = (struct sbp2scsi_host_info *) SCpnt->host->hostdata[0]; + + SBP2_ERR("sbp2: reset requested"); + + if (hi) { + SBP2_ERR("sbp2: generating IEEE-1394 bus reset"); + hpsb_reset_bus(hi->host, LONG_RESET); + } + + return(SCSI_RESET_SUCCESS); +} + +/* + * Called by scsi stack to get bios parameters (used by fdisk, and at boot). + */ +static int sbp2scsi_biosparam (Scsi_Disk *disk, kdev_t dev, int geom[]) +{ + int heads, sectors, cylinders; + + SBP2_DEBUG("sbp2: request for bios parameters"); + + heads = 64; + sectors = 32; + cylinders = disk->capacity / (heads * sectors); + + if (cylinders > 1024) { + heads = 255; + sectors = 63; + cylinders = disk->capacity / (heads * sectors); + } + + geom[0] = heads; + geom[1] = sectors; + geom[2] = cylinders; + + return(0); +} + +/* + * This routine is called at setup (init) and does nothing. Not used here. =) + */ +void sbp2scsi_setup( char *str, int *ints) +{ + SBP2_DEBUG("sbp2: sbp2scsi_setup"); + return; +} + +/* + * This is our detection routine, and is where we init everything. + */ +static int sbp2scsi_detect (Scsi_Host_Template *tpnt) +{ + SBP2_DEBUG("sbp2: sbp2scsi_detect"); + + global_scsi_tpnt = tpnt; + + global_scsi_tpnt->proc_name = "sbp2"; + + /* + * Module load option for force one command at a time + */ + if (serialize_io) { + SBP2_ERR("sbp2: Driver forced to serialize I/O (serialize_io = 1)"); + global_scsi_tpnt->can_queue = 1; + global_scsi_tpnt->cmd_per_lun = 1; + } + + /* + * Module load option to limit max size of requests from the scsi drivers + */ + if (no_large_packets) { + SBP2_ERR("sbp2: Driver forced to limit max transfer size (no_large_packets = 1)"); + global_scsi_tpnt->sg_tablesize = 0x1f; + global_scsi_tpnt->use_clustering = DISABLE_CLUSTERING; + } + + if (no_bus_scan) { + SBP2_ERR("sbp2: Initial scsi bus scan deferred (no_bus_scan = 1)"); + } + + if (mode_sense_hack) { + SBP2_ERR("sbp2: Mode sense emulation enabled (mode_sense_hack = 1)"); + } + + sbp2_init(); + + if (!sbp2_host_count) { + SBP2_ERR("sbp2: Please load the lower level IEEE-1394 driver (e.g. ohci1394) before sbp2..."); + if (sbp2_hl_handle) { + hpsb_unregister_highlevel(sbp2_hl_handle); + sbp2_hl_handle = NULL; + } + } + + /* + * Since we are returning this count, it means that sbp2 must be loaded "after" the + * host adapter module... + */ + return(sbp2_host_count); +} + +/* + * This function is called from sbp2_add_host, and is where we register our scsi host + */ +static void sbp2scsi_register_scsi_host(struct sbp2scsi_host_info *hi) +{ + struct Scsi_Host *shpnt = NULL; + + SBP2_DEBUG("sbp2: sbp2scsi_register_scsi_host"); + SBP2_DEBUG("sbp2: sbp2scsi_host_info = %p", hi); + + /* + * Let's register with the scsi stack + */ + if (global_scsi_tpnt) { + + shpnt = scsi_register (global_scsi_tpnt, sizeof(void *)); + + /* + * If successful, save off a context (to be used when SCSI commands are received) + */ + if (shpnt) { + shpnt->hostdata[0] = (unsigned long)hi; + } + } + + return; +} + +/* + * Called when our module is released + */ +static int sbp2scsi_release(struct Scsi_Host *host) +{ + SBP2_DEBUG("sbp2: sbp2scsi_release"); + sbp2_cleanup(); + return(0); +} + +/* + * Called for contents of procfs + */ +static const char *sbp2scsi_info (struct Scsi_Host *host) +{ + return "IEEE-1394 SBP-2 protocol driver"; +} + +/* + * Module related section + */ + +MODULE_AUTHOR("James Goodwin <jamesg@filanet.com>"); +MODULE_DESCRIPTION("IEEE-1394 SBP-2 protocol driver"); +MODULE_SUPPORTED_DEVICE("sbp2"); + +/* + * SCSI host template + */ +static Scsi_Host_Template driver_template = SBP2SCSI; + +#include "../scsi/scsi_module.c" diff -u --recursive --new-file v2.4.6/linux/drivers/ieee1394/sbp2.h linux/drivers/ieee1394/sbp2.h --- v2.4.6/linux/drivers/ieee1394/sbp2.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/ieee1394/sbp2.h Thu Jul 19 17:48:16 2001 @@ -0,0 +1,584 @@ +/* + * sbp2.h - Defines and prototypes for sbp2.c + * + * Copyright (C) 2000 James Goodwin, Filanet Corporation (www.filanet.com) + * jamesg@filanet.com + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef SBP2_H +#define SBP2_H + +#define SBP2_DEVICE_NAME "sbp2" +#define SBP2_DEVICE_NAME_SIZE 4 + +/* + * SBP2 specific structures and defines + */ + +#define ORB_FMT_CMD 0x0 +#define ORB_FMT_DUMMY 0x3 + +#define ORB_DIRECTION_WRITE_TO_MEDIA 0x0 +#define ORB_DIRECTION_READ_FROM_MEDIA 0x1 +#define ORB_DIRECTION_NO_DATA_TRANSFER 0x2 + +#define SPEED_S100 0x0 +#define SPEED_S200 0x1 +#define SPEED_S400 0x2 +#define SPEED_S800 0x3 +#define SPEED_S1600 0x4 +#define SPEED_S3200 0x5 + +/* 2^(MAX_PAYLOAD+2) = Maximum data transfer length */ +#define MAX_PAYLOAD_S100 0x7 +#define MAX_PAYLOAD_S200 0x8 +#define MAX_PAYLOAD_S400 0x9 + +#define ORB_SET_NOTIFY(value) ((value & 0x1) << 31) +#define ORB_SET_RQ_FMT(value) ((value & 0x3) << 29) +#define ORB_SET_NODE_ID(value) ((value & 0xffff) << 16) + +struct sbp2_dummy_orb { + volatile u32 next_ORB_hi; + volatile u32 next_ORB_lo; + u32 reserved1; + u32 reserved2; + u32 notify_rq_fmt; + u8 command_block[12]; +}; + +#define ORB_SET_DATA_SIZE(value) (value & 0xffff) +#define ORB_SET_PAGE_SIZE(value) ((value & 0x7) << 16) +#define ORB_SET_PAGE_TABLE_PRESENT(value) ((value & 0x1) << 19) +#define ORB_SET_MAX_PAYLOAD(value) ((value & 0xf) << 20) +#define ORB_SET_SPEED(value) ((value & 0x7) << 24) +#define ORB_SET_DIRECTION(value) ((value & 0x1) << 27) + +struct sbp2_command_orb { + volatile u32 next_ORB_hi; + volatile u32 next_ORB_lo; + u32 data_descriptor_hi; + u32 data_descriptor_lo; + u32 misc; + u8 cdb[12]; +}; + +#define LOGIN_REQUEST 0x0 +#define QUERY_LOGINS_REQUEST 0x1 +#define RECONNECT_REQUEST 0x3 +#define SET_PASSWORD_REQUEST 0x4 +#define LOGOUT_REQUEST 0x7 +#define ABORT_TASK_REQUEST 0xb +#define ABORT_TASK_SET 0xc +#define LOGICAL_UNIT_RESET 0xe +#define TARGET_RESET_REQUEST 0xf + +#define ORB_SET_LUN(value) (value & 0xffff) +#define ORB_SET_FUNCTION(value) ((value & 0xf) << 16) +#define ORB_SET_RECONNECT(value) ((value & 0xf) << 20) +#define ORB_SET_EXCLUSIVE(value) ((value & 0x1) << 28) +#define ORB_SET_LOGIN_RESP_LENGTH(value) (value & 0xffff) +#define ORB_SET_PASSWD_LENGTH(value) ((value & 0xffff) << 16) + +struct sbp2_login_orb { + u32 password_hi; + u32 password_lo; + u32 login_response_hi; + u32 login_response_lo; + u32 lun_misc; + u32 passwd_resp_lengths; + u32 status_FIFO_hi; + u32 status_FIFO_lo; +}; + +#define RESPONSE_GET_LOGIN_ID(value) (value & 0xffff) +#define RESPONSE_GET_LENGTH(value) ((value >> 16) & 0xffff) +#define RESPONSE_GET_RECONNECT_HOLD(value) (value & 0xffff) + +struct sbp2_login_response { + u32 length_login_ID; + u32 command_block_agent_hi; + u32 command_block_agent_lo; + u32 reconnect_hold; +}; + +#define ORB_SET_LOGIN_ID(value) (value & 0xffff) + +struct sbp2_reconnect_orb { + u32 reserved1; + u32 reserved2; + u32 reserved3; + u32 reserved4; + u32 login_ID_misc; + u32 reserved5; + u32 status_FIFO_hi; + u32 status_FIFO_lo; +}; + +struct sbp2_logout_orb { + u32 reserved1; + u32 reserved2; + u32 reserved3; + u32 reserved4; + u32 login_ID_misc; + u32 reserved5; + u32 status_FIFO_hi; + u32 status_FIFO_lo; +}; + +#define PAGE_TABLE_SET_SEGMENT_BASE_HI(value) (value & 0xffff) +#define PAGE_TABLE_SET_SEGMENT_LENGTH(value) ((value & 0xffff) << 16) + +struct sbp2_unrestricted_page_table { + u32 length_segment_base_hi; + u32 segment_base_lo; +}; + +#define RESP_STATUS_REQUEST_COMPLETE 0x0 +#define RESP_STATUS_TRANSPORT_FAILURE 0x1 +#define RESP_STATUS_ILLEGAL_REQUEST 0x2 +#define RESP_STATUS_VENDOR_DEPENDENT 0x3 + +#define SBP2_STATUS_NO_ADDITIONAL_INFO 0x0 +#define SBP2_STATUS_REQ_TYPE_NOT_SUPPORTED 0x1 +#define SBP2_STATUS_SPEED_NOT_SUPPORTED 0x2 +#define SBP2_STATUS_PAGE_SIZE_NOT_SUPPORTED 0x3 +#define SBP2_STATUS_ACCESS_DENIED 0x4 +#define SBP2_STATUS_LU_NOT_SUPPORTED 0x5 +#define SBP2_STATUS_MAX_PAYLOAD_TOO_SMALL 0x6 +#define SBP2_STATUS_RESOURCES_UNAVAILABLE 0x8 +#define SBP2_STATUS_FUNCTION_REJECTED 0x9 +#define SBP2_STATUS_LOGIN_ID_NOT_RECOGNIZED 0xa +#define SBP2_STATUS_DUMMY_ORB_COMPLETED 0xb +#define SBP2_STATUS_REQUEST_ABORTED 0xc +#define SBP2_STATUS_UNSPECIFIED_ERROR 0xff + +#define SFMT_CURRENT_ERROR 0x0 +#define SFMT_DEFERRED_ERROR 0x1 +#define SFMT_VENDOR_DEPENDENT_STATUS 0x3 + +#define SBP2_SCSI_STATUS_GOOD 0x0 +#define SBP2_SCSI_STATUS_CHECK_CONDITION 0x2 +#define SBP2_SCSI_STATUS_CONDITION_MET 0x4 +#define SBP2_SCSI_STATUS_BUSY 0x8 +#define SBP2_SCSI_STATUS_RESERVATION_CONFLICT 0x18 +#define SBP2_SCSI_STATUS_COMMAND_TERMINATED 0x22 + +#define SBP2_SCSI_STATUS_SELECTION_TIMEOUT 0xff + +#define STATUS_GET_ORB_OFFSET_HI(value) (value & 0xffff) +#define STATUS_GET_SBP_STATUS(value) ((value >> 16) & 0xff) +#define STATUS_GET_LENGTH(value) ((value >> 24) & 0x7) +#define STATUS_GET_DEAD_BIT(value) ((value >> 27) & 0x1) +#define STATUS_GET_RESP(value) ((value >> 28) & 0x3) +#define STATUS_GET_SRC(value) ((value >> 30) & 0x3) + +struct sbp2_status_block { + u32 ORB_offset_hi_misc; + u32 ORB_offset_lo; + u8 command_set_dependent[24]; +}; + +/* + * Miscellaneous SBP2 related config rom defines + */ + +#define SBP2_STATUS_FIFO_ADDRESS 0xfffe00000000ULL /* for write posting! */ +#define SBP2_STATUS_FIFO_ADDRESS_HI 0xfffe +#define SBP2_STATUS_FIFO_ADDRESS_LO 0x0 + +#define SBP2_UNIT_DIRECTORY_OFFSET_KEY 0xd1 +#define SBP2_CSR_OFFSET_KEY 0x54 +#define SBP2_UNIT_SPEC_ID_KEY 0x12 +#define SBP2_UNIT_SW_VERSION_KEY 0x13 +#define SBP2_COMMAND_SET_SPEC_ID_KEY 0x38 +#define SBP2_COMMAND_SET_KEY 0x39 +#define SBP2_UNIT_CHARACTERISTICS_KEY 0x3a +#define SBP2_DEVICE_TYPE_AND_LUN_KEY 0x14 +#define SBP2_FIRMWARE_REVISION_KEY 0x3c + +#define SBP2_AGENT_STATE_OFFSET 0x00ULL +#define SBP2_AGENT_RESET_OFFSET 0x04ULL +#define SBP2_ORB_POINTER_OFFSET 0x08ULL +#define SBP2_DOORBELL_OFFSET 0x10ULL +#define SBP2_UNSOLICITED_STATUS_ENABLE_OFFSET 0x14ULL +#define SBP2_UNSOLICITED_STATUS_VALUE 0xf + +#define SBP2_BUSY_TIMEOUT_ADDRESS 0xfffff0000210ULL +#define SBP2_BUSY_TIMEOUT_VALUE 0xf + +#define SBP2_AGENT_RESET_DATA 0xf + +/* + * Unit spec id and sw version entry for SBP-2 devices + */ + +#define SBP2_UNIT_SPEC_ID_ENTRY 0x1200609e +#define SBP2_SW_VERSION_ENTRY 0x13010483 + +/* + * Miscellaneous general config rom related defines + */ + +#define CONFIG_ROM_INITIAL_MEMORY_SPACE 0xfffff0000000ULL + +#define CONFIG_ROM_BASE_ADDRESS 0xfffff0000400ULL +#define CONFIG_ROM_ROOT_DIR_BASE 0xfffff0000414ULL +#define CONFIG_ROM_NODE_UNIQUE_ID_HI_ADDRESS 0xfffff000040cULL +#define CONFIG_ROM_NODE_UNIQUE_ID_LO_ADDRESS 0xfffff0000410ULL +#define CONFIG_ROM_SIGNATURE_ADDRESS 0xfffff0000404ULL +#define CONFIG_ROM_NODE_OPTIONS 0xfffff0000408ULL +#define CONFIG_ROM_UNIT_DIRECTORY_OFFSET 0xfffff0000424ULL + +#define IEEE1394_CONFIG_ROM_SIGNATURE 0x31333934 + +#define SBP2_128KB_BROKEN_FIRMWARE 0xa0b800 +#define SBP2_BROKEN_FIRMWARE_MAX_TRANSFER 0x20000 + +/* + * Flags for SBP-2 functions + */ +#define SBP2_SEND_NO_WAIT 0x00000001 + +/* + * SCSI specific stuff + */ + +#define SBP2_MAX_SG_ELEMENTS SG_ALL +#define SBP2_CLUSTERING ENABLE_CLUSTERING +#define SBP2_MAX_SG_ELEMENT_LENGTH 0xf000 +#define SBP2SCSI_MAX_SCSI_IDS 8 +#define SBP2SCSI_MAX_OUTSTANDING_CMDS 8 /* Max total outstanding sbp2 commands allowed at a time! */ +#define SBP2SCSI_MAX_CMDS_PER_LUN 4 /* Max outstanding sbp2 commands per device - tune as needed */ + +#ifndef TYPE_SDAD +#define TYPE_SDAD 0x0e /* simplified direct access device */ +#endif + +/* + * SCSI direction table... since the scsi stack doesn't specify direction... =( + * + * DIN = IN data direction + * DOU = OUT data direction + * DNO = No data transfer + * DUN = Unknown data direction + */ +#define DIN ORB_DIRECTION_READ_FROM_MEDIA +#define DOU ORB_DIRECTION_WRITE_TO_MEDIA +#define DNO ORB_DIRECTION_NO_DATA_TRANSFER +#define DUN DIN + +static unchar sbp2scsi_direction_table[0x100] = { + DNO,DNO,DIN,DIN,DOU,DIN,DIN,DOU,DIN,DUN,DOU,DOU,DUN,DUN,DUN,DIN, + DNO,DIN,DIN,DOU,DIN,DOU,DNO,DNO,DOU,DNO,DIN,DNO,DIN,DOU,DNO,DUN, + DIN,DUN,DIN,DIN,DOU,DIN,DUN,DUN,DIN,DIN,DOU,DNO,DUN,DIN,DOU,DOU, + DOU,DOU,DOU,DNO,DIN,DNO,DNO,DIN,DOU,DOU,DOU,DOU,DIN,DOU,DIN,DOU, + DOU,DOU,DIN,DIN,DIN,DNO,DIN,DNO,DNO,DNO,DUN,DNO,DOU,DIN,DNO,DUN, + DUN,DIN,DIN,DNO,DOU,DOU,DUN,DUN,DNO,DIN,DIN,DNO,DIN,DOU,DUN,DUN, + DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN, + DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN, + DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN, + DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN, + DUN,DNO,DOU,DOU,DIN,DNO,DNO,DNO,DIN,DNO,DOU,DUN,DNO,DIN,DOU,DOU, + DOU,DOU,DOU,DNO,DUN,DIN,DOU,DIN,DIN,DIN,DNO,DNO,DNO,DIN,DIN,DUN, + DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN, + DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN, + DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DOU,DUN,DUN,DUN,DUN,DUN, + DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN +}; + + +/* + * Scsi_Host structure + */ +#define SBP2SCSI { \ + name: "IEEE1394 SBP-2", \ + detect: sbp2scsi_detect, \ + release: sbp2scsi_release, \ + info: sbp2scsi_info, \ + queuecommand: sbp2scsi_queuecommand, \ + abort: sbp2scsi_abort, \ + reset: sbp2scsi_reset, \ + bios_param: sbp2scsi_biosparam, \ + can_queue: SBP2SCSI_MAX_OUTSTANDING_CMDS, \ + this_id: -1, \ + sg_tablesize: SBP2_MAX_SG_ELEMENTS, \ + cmd_per_lun: SBP2SCSI_MAX_CMDS_PER_LUN, \ + use_clustering: SBP2_CLUSTERING, \ + emulated: 1 \ +} + +/* + * Number of request packets available for actual sbp2 I/O requests (these are used + * for sending command and agent reset packets). + */ +#define SBP2_MAX_REQUEST_PACKETS SBP2SCSI_MAX_OUTSTANDING_CMDS /* Per host adapter instance */ +#define SBP2_MAX_COMMAND_ORBS SBP2SCSI_MAX_CMDS_PER_LUN * 2 /* Per sbp2 device instance */ + +/* + * Request packets structure (used for sending command and agent reset packets) + */ +struct sbp2_request_packet { + + struct list_head list; + struct hpsb_packet *packet; + struct tq_struct tq; + void *hi_context; + +}; + +/* + * Encapsulates all the info necessary for an outstanding command. + */ +struct sbp2_command_info { + + struct list_head list; + struct sbp2_command_orb command_orb; + dma_addr_t command_orb_dma; + Scsi_Cmnd *Current_SCpnt; + void (*Current_done)(Scsi_Cmnd *); + unsigned int linked; + + /* Also need s/g structure for each sbp2 command */ + struct sbp2_unrestricted_page_table scatter_gather_element[SBP2_MAX_SG_ELEMENTS]; + dma_addr_t sge_dma; + void *sge_buffer; + dma_addr_t cmd_dma; + int dma_type; + unsigned long dma_size; + int dma_dir; + +}; + +/* + * Information needed on a per scsi id basis (one for each sbp2 device) + */ +struct scsi_id_instance_data { + + /* + * Various sbp2 specific structures + */ + struct sbp2_command_orb *last_orb; + struct sbp2_login_orb *login_orb; + dma_addr_t login_orb_dma; + struct sbp2_login_response *login_response; + dma_addr_t login_response_dma; + struct sbp2_reconnect_orb *reconnect_orb; + dma_addr_t reconnect_orb_dma; + struct sbp2_logout_orb *logout_orb; + dma_addr_t logout_orb_dma; + struct sbp2_status_block status_block; + + /* + * Stuff we need to know about the sbp2 device itself + */ + u64 node_unique_id; + u64 sbp2_management_agent_addr; + u64 sbp2_command_block_agent_addr; + u32 node_id; + u32 speed_code; + u32 max_payload_size; + + /* + * Values pulled from the device's unit directory + */ + u32 sbp2_unit_spec_id; + u32 sbp2_unit_sw_version; + u32 sbp2_command_set_spec_id; + u32 sbp2_command_set; + u32 sbp2_unit_characteristics; + u32 sbp2_device_type_and_lun; + u32 sbp2_firmware_revision; + + /* + * Wait queue used for logins, reconnects, logouts + */ + wait_queue_head_t sbp2_login_wait; + + /* + * Flag noting whether the sbp2 device is currently validated (for use during + * bus resets). + */ + u32 validated; + + /* + * Pool of command orbs, so we can have more than overlapped command per id + */ + spinlock_t sbp2_command_orb_lock; + struct list_head sbp2_command_orb_inuse; + struct list_head sbp2_command_orb_completed; + u32 sbp2_total_command_orbs; + +}; + +/* + * Sbp2 host data structure (one per sbp2 host) + */ +struct sbp2scsi_host_info { + + /* + * For use in keeping track of hosts + */ + struct list_head list; + struct hpsb_host *host; + + /* + * Spin locks for command processing and packet pool management + */ + spinlock_t sbp2_command_lock; + spinlock_t sbp2_request_packet_lock; + + /* + * Flag indicating if a bus reset (or device detection) is in progress + */ + u32 bus_reset_in_progress; + + /* + * We currently use a kernel thread for dealing with bus resets and sbp2 + * device detection. We use this to wake up the thread when needed. + */ + wait_queue_head_t sbp2_detection_wait; + + /* + * PID of sbp2 detection kernel thread + */ + int sbp2_detection_pid; + + /* + * Lists keeping track of inuse/free sbp2_request_packets. These structures are + * used for sending out sbp2 command and agent reset packets. We initially create + * a pool of request packets so that we don't have to do any kmallocs while in critical + * I/O paths. + */ + struct list_head sbp2_req_inuse; + struct list_head sbp2_req_free; + + /* + * Stuff to keep track of the initial scsi bus scan (so that we don't miss it) + */ + u32 initial_scsi_bus_scan_complete; + Scsi_Cmnd *bus_scan_SCpnt; + void (*bus_scan_done)(Scsi_Cmnd *); + + /* + * Here is the pool of request packets. All the hpsb packets (for 1394 bus transactions) + * are allocated at init and simply re-initialized when needed. + */ + struct sbp2_request_packet request_packet[SBP2_MAX_REQUEST_PACKETS]; + + /* + * SCSI ID instance data (one for each sbp2 device instance possible) + */ + struct scsi_id_instance_data *scsi_id[SBP2SCSI_MAX_SCSI_IDS]; + +}; + +/* + * Function prototypes + */ + +/* + * Various utility prototypes + */ +static int sbp2util_read_quadlet(struct sbp2scsi_host_info *hi, nodeid_t node, u64 addr, + quadlet_t *buffer); +static int sbp2util_unit_directory(struct sbp2scsi_host_info *hi, nodeid_t node, u64 *addr); +static int sbp2util_create_request_packet_pool(struct sbp2scsi_host_info *hi); +static void sbp2util_remove_request_packet_pool(struct sbp2scsi_host_info *hi); +static struct sbp2_request_packet *sbp2util_allocate_write_request_packet(struct sbp2scsi_host_info *hi, + nodeid_t node, u64 addr, + size_t data_size, + quadlet_t data); +static void sbp2util_free_request_packet(struct sbp2_request_packet *request_packet); +static int sbp2util_create_command_orb_pool(struct scsi_id_instance_data *scsi_id, struct sbp2scsi_host_info *hi); +static void sbp2util_remove_command_orb_pool(struct scsi_id_instance_data *scsi_id, struct sbp2scsi_host_info *hi); +static struct sbp2_command_info *sbp2util_find_command_for_orb(struct scsi_id_instance_data *scsi_id, dma_addr_t orb); +static struct sbp2_command_info *sbp2util_find_command_for_SCpnt(struct scsi_id_instance_data *scsi_id, void *SCpnt); +static struct sbp2_command_info *sbp2util_allocate_command_orb(struct scsi_id_instance_data *scsi_id, + Scsi_Cmnd *Current_SCpnt, + void (*Current_done)(Scsi_Cmnd *), + struct sbp2scsi_host_info *hi); +static void sbp2util_mark_command_completed(struct scsi_id_instance_data *scsi_id, + struct sbp2_command_info *command); + +/* + * IEEE-1394 core driver related prototypes + */ +static void sbp2_remove_unvalidated_devices(struct sbp2scsi_host_info *hi); +static int sbp2_start_device(struct sbp2scsi_host_info *hi, int node_id); +static int sbp2_check_device(struct sbp2scsi_host_info *hi, int node_id); +static void sbp2_bus_reset_handler(void *context); +static void sbp2_add_host(struct hpsb_host *host); +static struct sbp2scsi_host_info *sbp2_find_host_info(struct hpsb_host *host); +static void sbp2_remove_host(struct hpsb_host *host); +static void sbp2_host_reset(struct hpsb_host *host); +static int sbp2_detection_thread(void *__sbp2); +int sbp2_init(void); +void sbp2_cleanup(void); +#if 0 +static int sbp2_handle_physdma_write(struct hpsb_host *host, int nodeid, quadlet_t *data, + u64 addr, unsigned int length); +static int sbp2_handle_physdma_read(struct hpsb_host *host, int nodeid, quadlet_t *data, + u64 addr, unsigned int length); +#endif +/* + * SBP-2 protocol related prototypes + */ +static int sbp2_login_device(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id); +static int sbp2_reconnect_device(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id); +static int sbp2_logout_device(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id); +static int sbp2_handle_status_write(struct hpsb_host *host, int nodeid, int destid, + quadlet_t *data, u64 addr, unsigned int length); +static int sbp2_agent_reset(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id, u32 flags); +static int sbp2_create_command_orb(struct sbp2scsi_host_info *hi, + struct scsi_id_instance_data *scsi_id, + struct sbp2_command_info *command, + unchar *scsi_cmd, + unsigned int scsi_use_sg, + unsigned int scsi_request_bufflen, + void *scsi_request_buffer, int dma_dir); +static int sbp2_link_orb_command(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id, + struct sbp2_command_info *command); +static int sbp2_send_command(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id, + Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)); +static int sbp2_send_split_command(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id, + Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)); +static unsigned int sbp2_status_to_sense_data(unchar *sbp2_status, unchar *sense_data); +static void sbp2_check_sbp2_command(unchar *cmd); +static void sbp2_check_sbp2_response(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id, + Scsi_Cmnd *SCpnt); +static int sbp2_parse_unit_directory(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id); +static int sbp2_set_busy_timeout(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id); +static int sbp2_max_speed_and_size(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id); + +/* + * Scsi interface related prototypes + */ +static const char *sbp2scsi_info (struct Scsi_Host *host); +static int sbp2scsi_detect (Scsi_Host_Template *tpnt); +void sbp2scsi_setup(char *str, int *ints); +static int sbp2scsi_biosparam (Scsi_Disk *disk, kdev_t dev, int geom[]); +static int sbp2scsi_abort (Scsi_Cmnd *SCpnt); +static int sbp2scsi_reset (Scsi_Cmnd *SCpnt, unsigned int reset_flags); +static int sbp2scsi_queuecommand (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)); +static void sbp2scsi_complete_all_commands(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id, + u32 status); +static void sbp2scsi_complete_command(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id, + u32 scsi_status, Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)); +static void sbp2scsi_register_scsi_host(struct sbp2scsi_host_info *hi); + +#endif /* SBP2_H */ diff -u --recursive --new-file v2.4.6/linux/drivers/ieee1394/video1394.c linux/drivers/ieee1394/video1394.c --- v2.4.6/linux/drivers/ieee1394/video1394.c Thu May 24 14:55:17 2001 +++ linux/drivers/ieee1394/video1394.c Thu Jul 19 17:48:16 2001 @@ -1,6 +1,7 @@ /* * video1394.c - video driver for OHCI 1394 boards * Copyright (C)1999,2000 Sebastien Rougeaux <sebastien.rougeaux@anu.edu.au> + * Peter Schlaile <udbz@rz.uni-karlsruhe.de> * * 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 @@ -19,11 +20,13 @@ #include <linux/config.h> #include <linux/kernel.h> +#include <linux/list.h> #include <linux/slab.h> #include <linux/interrupt.h> #include <linux/wait.h> #include <linux/errno.h> #include <linux/module.h> +#include <linux/init.h> #include <linux/pci.h> #include <linux/fs.h> #include <linux/poll.h> @@ -35,6 +38,7 @@ #include <linux/proc_fs.h> #include <linux/tqueue.h> #include <linux/delay.h> +#include <linux/devfs_fs_kernel.h> #include <asm/pgtable.h> #include <asm/page.h> @@ -48,6 +52,7 @@ #include "ieee1394_types.h" #include "hosts.h" #include "ieee1394_core.h" +#include "highlevel.h" #include "video1394.h" #include "ohci1394.h" @@ -77,6 +82,9 @@ int ctx; int channel; int last_buffer; + int * next_buffer; /* For ISO Transmit of video packets + to write the correct SYT field + into the next block */ unsigned int num_desc; unsigned int buf_size; unsigned int frame_size; @@ -87,16 +95,22 @@ struct dma_cmd **ir_prg; struct it_dma_prg **it_prg; unsigned int *buffer_status; + unsigned int *last_used_cmd; /* For ISO Transmit with + variable sized packets only ! */ int ctrlClear; int ctrlSet; int cmdPtr; int ctxMatch; wait_queue_head_t waitq; spinlock_t lock; + int flags; }; struct video_card { struct ti_ohci *ohci; + struct list_head list; + int id; + devfs_handle_t devfs; struct dma_iso_ctx **ir_context; struct dma_iso_ctx **it_context; @@ -129,11 +143,16 @@ void irq_handler(int card, quadlet_t isoRecvIntEvent, quadlet_t isoXmitIntEvent); -static struct video_card video_cards[MAX_OHCI1394_CARDS]; -static int num_of_video_cards = 0; +LIST_HEAD(video1394_cards); +static spinlock_t video1394_cards_lock = SPIN_LOCK_UNLOCKED; + +static devfs_handle_t devfs_handle; +static struct hpsb_highlevel *hl_handle = NULL; + static struct video_template video_tmpl = { irq_handler }; -/* Taken from bttv.c */ +/* Code taken from bttv.c */ + /*******************************/ /* Memory management functions */ /*******************************/ @@ -148,14 +167,10 @@ * * The code used to assume that the kernel vmalloc mappings * existed in the page tables of every process, this is simply - * not guarenteed. We now use pgd_offset_k which is the + * not guaranteed. We now use pgd_offset_k which is the * defined way to get at the kernel page tables. */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0) -#define page_address(x) (x) -#endif - /* Given PGD from the address space's page table, return the kernel * virtual mapping of the physical memory mapped at ADR. */ @@ -171,7 +186,8 @@ ptep = pte_offset(pmd, adr); pte = *ptep; if(pte_present(pte)) { - ret = (unsigned long) page_address(pte_page(pte)); + ret = (unsigned long) + page_address(pte_page(pte)); ret |= (adr & (PAGE_SIZE - 1)); } } @@ -255,6 +271,7 @@ vfree(mem); } } +/* End of code taken from bttv.c */ static int free_dma_iso_ctx(struct dma_iso_ctx **d) { @@ -286,7 +303,11 @@ if ((*d)->buffer_status) kfree((*d)->buffer_status); - + if ((*d)->last_used_cmd) + kfree((*d)->last_used_cmd); + if ((*d)->next_buffer) + kfree((*d)->next_buffer); + kfree(*d); *d = NULL; @@ -303,7 +324,7 @@ d = (struct dma_iso_ctx *)kmalloc(sizeof(struct dma_iso_ctx), GFP_KERNEL); if (d==NULL) { - PRINT(KERN_ERR, ohci->id, "failed to allocate dma_iso_ctx"); + PRINT(KERN_ERR, ohci->id, "Failed to allocate dma_iso_ctx"); return NULL; } @@ -326,7 +347,7 @@ d->buf = rvmalloc(d->num_desc * d->buf_size); if (d->buf == NULL) { - PRINT(KERN_ERR, ohci->id, "failed to allocate dma buffer"); + PRINT(KERN_ERR, ohci->id, "Failed to allocate dma buffer"); free_dma_iso_ctx(&d); return NULL; } @@ -343,7 +364,7 @@ if (d->ir_prg == NULL) { PRINT(KERN_ERR, ohci->id, - "failed to allocate dma ir prg"); + "Failed to allocate dma ir prg"); free_dma_iso_ctx(&d); return NULL; } @@ -359,7 +380,7 @@ GFP_KERNEL); if (d->ir_prg[i] == NULL) { PRINT(KERN_ERR, ohci->id, - "failed to allocate dma ir prg"); + "Failed to allocate dma ir prg"); free_dma_iso_ctx(&d); return NULL; } @@ -375,7 +396,7 @@ if (d->it_prg == NULL) { PRINT(KERN_ERR, ohci->id, - "failed to allocate dma it prg"); + "Failed to allocate dma it prg"); free_dma_iso_ctx(&d); return NULL; } @@ -385,8 +406,9 @@ if (PAGE_SIZE % packet_size || packet_size>4096) { PRINT(KERN_ERR, ohci->id, - "Packet size %d not yet supported\n", - packet_size); + "Packet size %d (page_size: %ld) " + "not yet supported\n", + packet_size, PAGE_SIZE); free_dma_iso_ctx(&d); return NULL; } @@ -405,7 +427,7 @@ GFP_KERNEL); if (d->it_prg[i] == NULL) { PRINT(KERN_ERR, ohci->id, - "failed to allocate dma it prg"); + "Failed to allocate dma it prg"); free_dma_iso_ctx(&d); return NULL; } @@ -414,13 +436,29 @@ d->buffer_status = kmalloc(d->num_desc * sizeof(unsigned int), GFP_KERNEL); + d->last_used_cmd = kmalloc(d->num_desc * sizeof(unsigned int), + GFP_KERNEL); + d->next_buffer = kmalloc(d->num_desc * sizeof(int), + GFP_KERNEL); if (d->buffer_status == NULL) { - PRINT(KERN_ERR, ohci->id, "failed to allocate dma ir prg"); + PRINT(KERN_ERR, ohci->id, "Failed to allocate buffer_status"); + free_dma_iso_ctx(&d); + return NULL; + } + if (d->last_used_cmd == NULL) { + PRINT(KERN_ERR, ohci->id, "Failed to allocate last_used_cmd"); + free_dma_iso_ctx(&d); + return NULL; + } + if (d->next_buffer == NULL) { + PRINT(KERN_ERR, ohci->id, "Failed to allocate next_buffer"); free_dma_iso_ctx(&d); return NULL; } memset(d->buffer_status, 0, d->num_desc * sizeof(unsigned int)); + memset(d->last_used_cmd, 0, d->num_desc * sizeof(unsigned int)); + memset(d->next_buffer, -1, d->num_desc * sizeof(int)); spin_lock_init(&d->lock); @@ -484,6 +522,8 @@ struct ti_ohci *ohci = (struct ti_ohci *)d->ohci; int i; + d->flags = flags; + ohci1394_stop_context(ohci, d->ctrlClear, NULL); for (i=0;i<d->num_desc;i++) { @@ -521,9 +561,9 @@ return i; } - PRINT(KERN_ERR, ohci->id, - "no iso context is listening to channel %d", + PRINT(KERN_ERR, ohci->id, "No iso context is listening to channel %d", channel); + return -1; } @@ -538,9 +578,9 @@ return i; } - PRINT(KERN_ERR, ohci->id, - "no iso context is talking to channel %d", + PRINT(KERN_ERR, ohci->id, "No iso context is talking to channel %d", channel); + return -1; } @@ -566,6 +606,32 @@ return 0; } +static inline void put_timestamp(struct ti_ohci *ohci, struct dma_iso_ctx * d, + int curr, int n) +{ + unsigned char* buf = d->buf + n * d->buf_size; + u32 cycleTimer; + u32 timeStamp; + + if (n == -1) { + return; + } + + cycleTimer = reg_read(ohci, OHCI1394_IsochronousCycleTimer); + + timeStamp = ((cycleTimer & 0x0fff) + 11059); + timeStamp = (timeStamp % 3072 + ((timeStamp / 3072) << 12) + + (cycleTimer & 0xf000)) & 0xffff; + + buf[6] = timeStamp >> 8; + buf[7] = timeStamp & 0xff; + +#if 0 + printk("curr: %d, next: %d, cycleTimer: %08x timeStamp: %08x\n", + curr, n, cycleTimer, timeStamp); +#endif +} + int wakeup_dma_it_ctx(struct ti_ohci *ohci, struct dma_iso_ctx *d) { int i; @@ -578,8 +644,10 @@ spin_lock(&d->lock); for (i=0;i<d->num_desc;i++) { - if (d->it_prg[i][d->nb_cmd-1].end.status & 0xFFFF0000) { - d->it_prg[i][d->nb_cmd-1].end.status = 0; + if (d->it_prg[i][d->last_used_cmd[i]].end.status& 0xFFFF0000) { + int next = d->next_buffer[i]; + put_timestamp(ohci, d, i, next); + d->it_prg[i][d->last_used_cmd[i]].end.status = 0; d->buffer_status[i] = VIDEO1394_BUFFER_READY; } } @@ -593,7 +661,7 @@ struct it_dma_prg *it_prg = d->it_prg[n]; unsigned long buf = (unsigned long)d->buf+n*d->buf_size; int i; - + d->last_used_cmd[n] = d->nb_cmd - 1; for (i=0;i<d->nb_cmd;i++) { it_prg[i].begin.control = OUTPUT_MORE_IMMEDIATE | 8 ; @@ -601,9 +669,11 @@ it_prg[i].begin.status = 0; - /* FIXME: what is the tag value + speed selection */ it_prg[i].data[0] = - (DMA_SPEED_400<<16) | (d->channel<<8) | 0xa0; + (DMA_SPEED_100 << 16) + | (/* tag */ 1 << 14) + | (d->channel << 8) + | (TCODE_ISO_DATA << 4); if (i==0) it_prg[i].data[0] |= sync_tag; it_prg[i].data[1] = d->packet_size << 16; it_prg[i].data[2] = 0; @@ -642,11 +712,58 @@ } } -static void initialize_dma_it_ctx(struct dma_iso_ctx *d, int sync_tag) +static void initialize_dma_it_prg_var_packet_queue( + struct dma_iso_ctx *d, int n, unsigned int * packet_sizes, + struct ti_ohci *ohci) +{ + struct it_dma_prg *it_prg = d->it_prg[n]; + int i; + +#if 0 + if (n != -1) { + put_timestamp(ohci, d, n); + } +#endif + d->last_used_cmd[n] = d->nb_cmd - 1; + + for (i = 0; i < d->nb_cmd; i++) { + unsigned int size; + if (packet_sizes[i] > d->packet_size) { + size = d->packet_size; + } else { + size = packet_sizes[i]; + } + it_prg[i].data[1] = size << 16; + it_prg[i].end.control = 0x100c0000; + + if (i < d->nb_cmd-1 && packet_sizes[i+1] != 0) { + it_prg[i].end.control |= size; + it_prg[i].begin.branchAddress = + (virt_to_bus(&(it_prg[i+1].begin.control)) + & 0xfffffff0) | 0x3; + it_prg[i].end.branchAddress = + (virt_to_bus(&(it_prg[i+1].begin.control)) + & 0xfffffff0) | 0x3; + } else { + /* the last prg generates an interrupt */ + it_prg[i].end.control |= 0x08300000 | size; + /* the last prg doesn't branch */ + it_prg[i].begin.branchAddress = 0; + it_prg[i].end.branchAddress = 0; + d->last_used_cmd[n] = i; + break; + } + } +} + +static void initialize_dma_it_ctx(struct dma_iso_ctx *d, int sync_tag, + int flags) { struct ti_ohci *ohci = (struct ti_ohci *)d->ohci; int i; + d->flags = flags; + ohci1394_stop_context(ohci, d->ctrlClear, NULL); for (i=0;i<d->num_desc;i++) @@ -689,9 +806,28 @@ static int video1394_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { - struct video_card *video = &video_cards[MINOR(inode->i_rdev)]; + struct video_card *video = NULL; struct ti_ohci *ohci= video->ohci; unsigned long flags; + struct list_head *lh; + + spin_lock_irqsave(&video1394_cards_lock, flags); + if (!list_empty(&video1394_cards)) { + struct video_card *p; + list_for_each(lh, &video1394_cards) { + p = list_entry(lh, struct video_card, list); + if (p->id == MINOR(inode->i_rdev)) { + video = p; + break; + } + } + } + spin_unlock_irqrestore(&video1394_cards_lock, flags); + + if (video == NULL) { + PRINT_G(KERN_ERR, __FUNCTION__": Unknown video card for minor %d", MINOR(inode->i_rdev)); + return -EFAULT; + } switch(cmd) { @@ -706,7 +842,7 @@ return -EFAULT; if (v.channel<0 || v.channel>(ISO_CHANNELS-1)) { PRINT(KERN_ERR, ohci->id, - "iso channel %d out of bound", v.channel); + "Iso channel %d out of bound", v.channel); return -EFAULT; } mask = (u64)0x1<<v.channel; @@ -716,7 +852,7 @@ (u32)(ohci->ISO_channel_usage&0xffffffff)); if (ohci->ISO_channel_usage & mask) { PRINT(KERN_ERR, ohci->id, - "channel %d is already taken", v.channel); + "Channel %d is already taken", v.channel); return -EFAULT; } ohci->ISO_channel_usage |= mask; @@ -747,7 +883,7 @@ if (i==(ohci->nb_iso_rcv_ctx-1)) { PRINT(KERN_ERR, ohci->id, - "no iso context available"); + "No iso context available"); return -EFAULT; } @@ -779,7 +915,7 @@ if (i==ohci->nb_iso_xmit_ctx) { PRINT(KERN_ERR, ohci->id, - "no iso context available"); + "No iso context available"); return -EFAULT; } @@ -794,14 +930,14 @@ return -EFAULT; } initialize_dma_it_ctx(video->it_context[i], - v.sync_tag); + v.sync_tag, v.flags); video->current_ctx = video->it_context[i]; v.buf_size = video->it_context[i]->buf_size; PRINT(KERN_INFO, ohci->id, - "iso context %d talk on channel %d", i, + "Iso context %d talk on channel %d", i, v.channel); } @@ -822,13 +958,13 @@ if (channel<0 || channel>(ISO_CHANNELS-1)) { PRINT(KERN_ERR, ohci->id, - "iso channel %d out of bound", channel); + "Iso channel %d out of bound", channel); return -EFAULT; } mask = (u64)0x1<<channel; if (!(ohci->ISO_channel_usage & mask)) { PRINT(KERN_ERR, ohci->id, - "channel %d is not being used", channel); + "Channel %d is not being used", channel); return -EFAULT; } ohci->ISO_channel_usage &= ~mask; @@ -840,7 +976,7 @@ free_dma_iso_ctx(&video->ir_context[i]); PRINT(KERN_INFO, ohci->id, - "iso context %d stop listening on channel %d", + "Iso context %d stop listening on channel %d", i+1, channel); } else { @@ -850,7 +986,7 @@ free_dma_iso_ctx(&video->it_context[i]); PRINT(KERN_INFO, ohci->id, - "iso context %d stop talking on channel %d", + "Iso context %d stop talking on channel %d", i, channel); } @@ -871,7 +1007,7 @@ if ((v.buffer<0) || (v.buffer>d->num_desc)) { PRINT(KERN_ERR, ohci->id, - "buffer %d out of range",v.buffer); + "Buffer %d out of range",v.buffer); return -EFAULT; } @@ -879,7 +1015,7 @@ if (d->buffer_status[v.buffer]==VIDEO1394_BUFFER_QUEUED) { PRINT(KERN_ERR, ohci->id, - "buffer %d is already used",v.buffer); + "Buffer %d is already used",v.buffer); spin_unlock_irqrestore(&d->lock,flags); return -EFAULT; } @@ -934,7 +1070,7 @@ if ((v.buffer<0) || (v.buffer>d->num_desc)) { PRINT(KERN_ERR, ohci->id, - "buffer %d out of range",v.buffer); + "Buffer %d out of range",v.buffer); return -EFAULT; } @@ -970,7 +1106,7 @@ break; default: PRINT(KERN_ERR, ohci->id, - "buffer %d is not queued",v.buffer); + "Buffer %d is not queued",v.buffer); spin_unlock_irqrestore(&d->lock, flags); return -EFAULT; } @@ -995,6 +1131,7 @@ case VIDEO1394_TALK_QUEUE_BUFFER: { struct video1394_wait v; + struct video1394_queue_variable qv; struct dma_iso_ctx *d; int i; @@ -1007,35 +1144,54 @@ if ((v.buffer<0) || (v.buffer>d->num_desc)) { PRINT(KERN_ERR, ohci->id, - "buffer %d out of range",v.buffer); + "Buffer %d out of range",v.buffer); return -EFAULT; } + if (d->flags & VIDEO1394_VARIABLE_PACKET_SIZE) { + if (copy_from_user(&qv, (void *)arg, sizeof(qv))) + return -EFAULT; + if (!access_ok(VERIFY_READ, qv.packet_sizes, + d->nb_cmd * sizeof(unsigned int))) { + return -EFAULT; + } + } + spin_lock_irqsave(&d->lock,flags); if (d->buffer_status[v.buffer]!=VIDEO1394_BUFFER_FREE) { PRINT(KERN_ERR, ohci->id, - "buffer %d is already used",v.buffer); + "Buffer %d is already used",v.buffer); spin_unlock_irqrestore(&d->lock,flags); return -EFAULT; } + if (d->flags & VIDEO1394_VARIABLE_PACKET_SIZE) { + initialize_dma_it_prg_var_packet_queue( + d, v.buffer, qv.packet_sizes, + ohci); + } + d->buffer_status[v.buffer]=VIDEO1394_BUFFER_QUEUED; if (d->last_buffer>=0) { d->it_prg[d->last_buffer] - [d->nb_cmd-1].end.branchAddress = + [ d->last_used_cmd[d->last_buffer] + ].end.branchAddress = (virt_to_bus(&(d->it_prg[v.buffer][0].begin.control)) & 0xfffffff0) | 0x3; d->it_prg[d->last_buffer] - [d->nb_cmd-1].begin.branchAddress = + [d->last_used_cmd[d->last_buffer] + ].begin.branchAddress = (virt_to_bus(&(d->it_prg[v.buffer][0].begin.control)) & 0xfffffff0) | 0x3; + d->next_buffer[d->last_buffer] = v.buffer; } d->last_buffer = v.buffer; + d->next_buffer[d->last_buffer] = -1; - d->it_prg[d->last_buffer][d->nb_cmd-1].end.branchAddress = 0; + d->it_prg[d->last_buffer][d->last_used_cmd[d->last_buffer]].end.branchAddress = 0; spin_unlock_irqrestore(&d->lock,flags); @@ -1078,7 +1234,7 @@ if ((v.buffer<0) || (v.buffer>d->num_desc)) { PRINT(KERN_ERR, ohci->id, - "buffer %d out of range",v.buffer); + "Buffer %d out of range",v.buffer); return -EFAULT; } @@ -1104,7 +1260,7 @@ return 0; default: PRINT(KERN_ERR, ohci->id, - "buffer %d is not queued",v.buffer); + "Buffer %d is not queued",v.buffer); return -EFAULT; } } @@ -1124,16 +1280,35 @@ int video1394_mmap(struct file *file, struct vm_area_struct *vma) { - struct video_card *video = - &video_cards[MINOR(file->f_dentry->d_inode->i_rdev)]; + struct video_card *video = NULL; struct ti_ohci *ohci; - int res = -EINVAL; + int res = -EINVAL, flags; + struct list_head *lh; + + spin_lock_irqsave(&video1394_cards_lock, flags); + if (!list_empty(&video1394_cards)) { + struct video_card *p; + list_for_each(lh, &video1394_cards) { + p = list_entry(lh, struct video_card, list); + if (p->id == MINOR(file->f_dentry->d_inode->i_rdev)) { + video = p; + break; + } + } + } + spin_unlock_irqrestore(&video1394_cards_lock, flags); + + if (video == NULL) { + PRINT_G(KERN_ERR, __FUNCTION__": Unknown video card for minor %d", + MINOR(file->f_dentry->d_inode->i_rdev)); + return -EFAULT; + } lock_kernel(); ohci = video->ohci; - PRINT(KERN_INFO, ohci->id, "mmap"); + if (video->current_ctx == NULL) { - PRINT(KERN_ERR, ohci->id, "current iso context not set"); + PRINT(KERN_ERR, ohci->id, "Current iso context not set"); } else res = do_iso_mmap(ohci, video->current_ctx, (char *)vma->vm_start, @@ -1144,26 +1319,59 @@ static int video1394_open(struct inode *inode, struct file *file) { - int i = MINOR(inode->i_rdev); - - if (i<0 || i>=num_of_video_cards) { - PRINT(KERN_ERR, i, "ohci card %d not found", i); - return -EIO; + int i = MINOR(inode->i_rdev), flags; + struct video_card *video = NULL; + struct list_head *lh; + + spin_lock_irqsave(&video1394_cards_lock, flags); + if (!list_empty(&video1394_cards)) { + struct video_card *p; + list_for_each(lh, &video1394_cards) { + p = list_entry(lh, struct video_card, list); + if (p->id == i) { + video = p; + break; + } + } } + spin_unlock_irqrestore(&video1394_cards_lock, flags); - V22_COMPAT_MOD_INC_USE_COUNT; + if (video == NULL) + return -EIO; - PRINT(KERN_INFO, i, "open"); + MOD_INC_USE_COUNT; return 0; } static int video1394_release(struct inode *inode, struct file *file) { - struct video_card *video = &video_cards[MINOR(inode->i_rdev)]; - struct ti_ohci *ohci= video->ohci; + struct video_card *video = NULL; + struct ti_ohci *ohci; u64 mask; - int i; + int i, flags; + struct list_head *lh; + + spin_lock_irqsave(&video1394_cards_lock, flags); + if (!list_empty(&video1394_cards)) { + struct video_card *p; + list_for_each(lh, &video1394_cards) { + p = list_entry(lh, struct video_card, list); + if (p->id == MINOR(inode->i_rdev)) { + video = p; + break; + } + } + } + spin_unlock_irqrestore(&video1394_cards_lock, flags); + + if (video == NULL) { + PRINT_G(KERN_ERR, __FUNCTION__": Unknown device for minor %d", + MINOR(inode->i_rdev)); + return 1; + } + + ohci = video->ohci; lock_kernel(); for (i=0;i<ohci->nb_iso_rcv_ctx-1;i++) @@ -1171,12 +1379,12 @@ mask = (u64)0x1<<video->ir_context[i]->channel; if (!(ohci->ISO_channel_usage & mask)) PRINT(KERN_ERR, ohci->id, - "channel %d is not being used", + "Channel %d is not being used", video->ir_context[i]->channel); else ohci->ISO_channel_usage &= ~mask; PRINT(KERN_INFO, ohci->id, - "iso receive context %d stop listening " + "Iso receive context %d stop listening " "on channel %d", i+1, video->ir_context[i]->channel); free_dma_iso_ctx(&video->ir_context[i]); @@ -1187,21 +1395,19 @@ mask = (u64)0x1<<video->it_context[i]->channel; if (!(ohci->ISO_channel_usage & mask)) PRINT(KERN_ERR, ohci->id, - "channel %d is not being used", + "Channel %d is not being used", video->it_context[i]->channel); else ohci->ISO_channel_usage &= ~mask; PRINT(KERN_INFO, ohci->id, - "iso transmit context %d stop talking " + "Iso transmit context %d stop talking " "on channel %d", i+1, video->it_context[i]->channel); free_dma_iso_ctx(&video->it_context[i]); } + MOD_DEC_USE_COUNT; - V22_COMPAT_MOD_DEC_USE_COUNT; - - PRINT(KERN_INFO, ohci->id, "release"); unlock_kernel(); return 0; } @@ -1209,8 +1415,28 @@ void irq_handler(int card, quadlet_t isoRecvIntEvent, quadlet_t isoXmitIntEvent) { - int i; - struct video_card *video = &video_cards[card]; + int i, flags; + struct video_card *video = NULL; + struct list_head *lh; + + spin_lock_irqsave(&video1394_cards_lock, flags); + if (!list_empty(&video1394_cards)) { + struct video_card *p; + list_for_each(lh, &video1394_cards) { + p = list_entry(lh, struct video_card, list); + if (p->id == card) { + video = p; + break; + } + } + } + spin_unlock_irqrestore(&video1394_cards_lock, flags); + + if (video == NULL) { + PRINT_G(KERN_ERR, __FUNCTION__": Unknown card number %d!!", + card); + return; + } DBGMSG(card, "Iso event Recv: %08x Xmit: %08x", isoRecvIntEvent, isoXmitIntEvent); @@ -1228,22 +1454,37 @@ static struct file_operations video1394_fops= { - OWNER_THIS_MODULE + owner: THIS_MODULE, ioctl: video1394_ioctl, mmap: video1394_mmap, open: video1394_open, release: video1394_release }; -static int video1394_init(int i, struct ti_ohci *ohci) +static int video1394_init(struct ti_ohci *ohci) { - struct video_card *video = &video_cards[i]; + struct video_card *video = kmalloc(sizeof(struct video_card), GFP_KERNEL); + int flags; + char name[16]; + + if (video == NULL) { + PRINT(KERN_ERR, ohci->id, "Cannot allocate video_card"); + return -1; + } + + memset(video, 0, sizeof(struct video_card)); + + spin_lock_irqsave(&video1394_cards_lock, flags); + INIT_LIST_HEAD(&video->list); + list_add_tail(&video->list, &video1394_cards); + spin_unlock_irqrestore(&video1394_cards_lock, flags); if (ohci1394_register_video(ohci, &video_tmpl)<0) { - PRINT(KERN_ERR, i, "register_video failed"); + PRINT(KERN_ERR, ohci->id, "Register_video failed"); return -1; } + video->id = ohci->id; video->ohci = ohci; /* Iso receive dma contexts */ @@ -1270,15 +1511,25 @@ return -1; } + sprintf(name, "%d", video->id); + video->devfs = devfs_register(devfs_handle, name, + DEVFS_FL_AUTO_OWNER, + VIDEO1394_MAJOR, 0, + S_IFCHR | S_IRUSR | S_IWUSR, + &video1394_fops, NULL); + return 0; } +/* Must be called under spinlock */ static void remove_card(struct video_card *video) { - int i; + int i, flags; ohci1394_unregister_video(video->ohci, &video_tmpl); + devfs_unregister(video->devfs); + /* Free the iso receive contexts */ if (video->ir_context) { for (i=0;i<video->ohci->nb_iso_rcv_ctx-1;i++) { @@ -1294,61 +1545,95 @@ } kfree(video->it_context); } + spin_lock_irqsave(&video1394_cards_lock, flags); + list_del(&video->list); + spin_unlock_irqrestore(&video1394_cards_lock, flags); + + kfree(video); } -#ifdef MODULE +static void video1394_remove_host (struct hpsb_host *host) +{ + struct ti_ohci *ohci; + int flags; + struct list_head *lh; + + /* We only work with the OHCI-1394 driver */ + if (strcmp(host->template->name, OHCI1394_DRIVER_NAME)) + return; + + ohci = (struct ti_ohci *)host->hostdata; + + spin_lock_irqsave(&video1394_cards_lock, flags); + if (!list_empty(&video1394_cards)) { + struct video_card *p; + list_for_each(lh, &video1394_cards) { + p = list_entry(lh, struct video_card, list); + if (p ->ohci == ohci) { + remove_card(p); + return; + } + } + } + spin_unlock_irqrestore(&video1394_cards_lock, flags); + + return; +} + +static void video1394_add_host (struct hpsb_host *host) +{ + struct ti_ohci *ohci; + + /* We only work with the OHCI-1394 driver */ + if (strcmp(host->template->name, OHCI1394_DRIVER_NAME)) + return; -/* EXPORT_NO_SYMBOLS; */ + ohci = (struct ti_ohci *)host->hostdata; + + video1394_init(ohci); + + return; +} + +static struct hpsb_highlevel_ops hl_ops = { + add_host: video1394_add_host, + remove_host: video1394_remove_host, +}; MODULE_AUTHOR("Sebastien Rougeaux <sebastien.rougeaux@anu.edu.au>"); MODULE_DESCRIPTION("driver for digital video on OHCI board"); MODULE_SUPPORTED_DEVICE("video1394"); -void cleanup_module(void) +static void __exit video1394_exit_module (void) { - int i; - unregister_chrdev(VIDEO1394_MAJOR, VIDEO1394_DRIVER_NAME); + hpsb_unregister_highlevel (hl_handle); - for (i=0; i<num_of_video_cards; i++) - remove_card(&video_cards[i]); + devfs_unregister(devfs_handle); + devfs_unregister_chrdev(VIDEO1394_MAJOR, VIDEO1394_DRIVER_NAME); - printk(KERN_INFO "removed " VIDEO1394_DRIVER_NAME " module\n"); + PRINT_G(KERN_INFO, "Removed " VIDEO1394_DRIVER_NAME " module\n"); } -int init_module(void) +static int __init video1394_init_module (void) { - struct ti_ohci *ohci; - int i; - - memset(video_cards, 0, MAX_OHCI1394_CARDS * sizeof(struct video_card)); - num_of_video_cards = 0; - - for (i=0; i<MAX_OHCI1394_CARDS; i++) { - ohci=ohci1394_get_struct(i); - if (ohci) { - num_of_video_cards++; - video1394_init(i, ohci); - } - } - - if (!num_of_video_cards) { - PRINT_G(KERN_INFO, "no ohci card found... init failed"); + if (devfs_register_chrdev(VIDEO1394_MAJOR, VIDEO1394_DRIVER_NAME, + &video1394_fops)) { + PRINT_G(KERN_ERR, "video1394: unable to get major %d\n", + VIDEO1394_MAJOR); return -EIO; } + devfs_handle = devfs_mk_dir(NULL, VIDEO1394_DRIVER_NAME, NULL); - if (register_chrdev(VIDEO1394_MAJOR, VIDEO1394_DRIVER_NAME, - &video1394_fops)) { - printk("video1394: unable to get major %d\n", - VIDEO1394_MAJOR); - return -EIO; + hl_handle = hpsb_register_highlevel (VIDEO1394_DRIVER_NAME, &hl_ops); + if (hl_handle == NULL) { + PRINT_G(KERN_ERR, "No more memory for driver\n"); + devfs_unregister(devfs_handle); + devfs_unregister_chrdev(VIDEO1394_MAJOR, VIDEO1394_DRIVER_NAME); + return -ENOMEM; } - PRINT_G(KERN_INFO, "initialized with %d ohci cards", - num_of_video_cards); - return 0; } -#endif /* MODULE */ - - +module_init(video1394_init_module); +module_exit(video1394_exit_module); diff -u --recursive --new-file v2.4.6/linux/drivers/ieee1394/video1394.h linux/drivers/ieee1394/video1394.h --- v2.4.6/linux/drivers/ieee1394/video1394.h Tue Jan 2 16:45:38 2001 +++ linux/drivers/ieee1394/video1394.h Thu Jul 19 17:48:16 2001 @@ -1,6 +1,7 @@ /* * video1394.h - driver for OHCI 1394 boards * Copyright (C)1999,2000 Sebastien Rougeaux <sebastien.rougeaux@anu.edu.au> + * Peter Schlaile <udbz@rz.uni-karlsruhe.de> * * 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 @@ -41,22 +42,32 @@ VIDEO1394_TALK_WAIT_BUFFER }; -#define VIDEO1394_SYNC_FRAMES 0x00000001 -#define VIDEO1394_INCLUDE_ISO_HEADERS 0x00000002 +#define VIDEO1394_SYNC_FRAMES 0x00000001 +#define VIDEO1394_INCLUDE_ISO_HEADERS 0x00000002 +#define VIDEO1394_VARIABLE_PACKET_SIZE 0x00000004 struct video1394_mmap { - int channel; - int sync_tag; - int nb_buffers; - int buf_size; - int packet_size; - int fps; - int flags; + unsigned int channel; + unsigned int sync_tag; + unsigned int nb_buffers; + unsigned int buf_size; + unsigned int packet_size; /* For VARIABLE_PACKET_SIZE: + Maximum packet size */ + unsigned int fps; + unsigned int flags; +}; + +/* For TALK_QUEUE_BUFFER with VIDEO1394_VARIABLE_PACKET_SIZE use */ +struct video1394_queue_variable { + unsigned int channel; + unsigned int buffer; + unsigned int* packet_sizes; /* Buffer of size: + buf_size / packet_size */ }; struct video1394_wait { - int channel; - int buffer; + unsigned int channel; + unsigned int buffer; }; diff -u --recursive --new-file v2.4.6/linux/drivers/isdn/avmb1/b1dma.c linux/drivers/isdn/avmb1/b1dma.c --- v2.4.6/linux/drivers/isdn/avmb1/b1dma.c Tue Jul 3 17:08:19 2001 +++ linux/drivers/isdn/avmb1/b1dma.c Wed Jul 18 09:45:40 2001 @@ -1,5 +1,5 @@ /* - * $Id: b1dma.c,v 1.11.6.6 2001/05/17 21:15:33 kai Exp $ + * $Id: b1dma.c,v 1.11.6.7 2001/07/18 16:02:15 kai Exp $ * * Common module for AVM B1 cards that support dma with AMCC * @@ -26,7 +26,11 @@ #include "capicmd.h" #include "capiutil.h" -static char *revision = "$Revision: 1.11.6.6 $"; +#if BITS_PER_LONG != 32 +#error FIXME: driver requires 32-bit platform +#endif + +static char *revision = "$Revision: 1.11.6.7 $"; /* ------------------------------------------------------------- */ diff -u --recursive --new-file v2.4.6/linux/drivers/isdn/eicon/eicon.h linux/drivers/isdn/eicon/eicon.h --- v2.4.6/linux/drivers/isdn/eicon/eicon.h Sat May 19 17:54:14 2001 +++ linux/drivers/isdn/eicon/eicon.h Fri Jul 6 17:01:06 2001 @@ -1,4 +1,4 @@ -/* $Id: eicon.h,v 1.23.6.3 2001/05/17 21:15:33 kai Exp $ +/* $Id: eicon.h,v 1.23.6.4 2001/06/09 15:14:16 kai Exp $ * * ISDN low-level module for Eicon active ISDN-Cards. * diff -u --recursive --new-file v2.4.6/linux/drivers/isdn/hisax/asuscom.c linux/drivers/isdn/hisax/asuscom.c --- v2.4.6/linux/drivers/isdn/hisax/asuscom.c Fri Mar 2 11:12:08 2001 +++ linux/drivers/isdn/hisax/asuscom.c Wed Jul 18 09:45:40 2001 @@ -1,4 +1,4 @@ -/* $Id: asuscom.c,v 1.11.6.1 2001/02/16 16:43:25 kai Exp $ +/* $Id: asuscom.c,v 1.11.6.2 2001/07/13 09:20:12 kai Exp $ * * asuscom.c low level stuff for ASUSCOM NETWORK INC. ISDNLink cards * @@ -20,7 +20,7 @@ extern const char *CardType[]; -const char *Asuscom_revision = "$Revision: 1.11.6.1 $"; +const char *Asuscom_revision = "$Revision: 1.11.6.2 $"; #define byteout(addr,val) outb(val,addr) #define bytein(addr) inb(addr) @@ -341,7 +341,7 @@ cs->cardmsg = &Asus_card_msg; val = readreg(cs->hw.asus.cfg_reg + ASUS_IPAC_ALE, cs->hw.asus.cfg_reg + ASUS_IPAC_DATA, IPAC_ID); - if (val == 1) { + if ((val == 1) || (val == 2)) { cs->subtyp = ASUS_IPAC; cs->hw.asus.adr = cs->hw.asus.cfg_reg + ASUS_IPAC_ALE; cs->hw.asus.isac = cs->hw.asus.cfg_reg + ASUS_IPAC_DATA; diff -u --recursive --new-file v2.4.6/linux/drivers/isdn/hisax/bkm_a4t.c linux/drivers/isdn/hisax/bkm_a4t.c --- v2.4.6/linux/drivers/isdn/hisax/bkm_a4t.c Fri Mar 2 11:12:08 2001 +++ linux/drivers/isdn/hisax/bkm_a4t.c Wed Jul 18 09:45:40 2001 @@ -1,4 +1,4 @@ -/* $Id: bkm_a4t.c,v 1.13.6.4 2001/02/16 16:43:25 kai Exp $ +/* $Id: bkm_a4t.c,v 1.13.6.5 2001/07/18 16:02:15 kai Exp $ * bkm_a4t.c low level stuff for T-Berkom A4T * derived from the original file sedlbauer.c * derived from the original file niccy.c @@ -24,11 +24,11 @@ extern const char *CardType[]; -const char *bkm_a4t_revision = "$Revision: 1.13.6.4 $"; +const char *bkm_a4t_revision = "$Revision: 1.13.6.5 $"; static inline u_char -readreg(unsigned int ale, unsigned int adr, u_char off) +readreg(unsigned int ale, unsigned long adr, u_char off) { register u_int ret; long flags; @@ -46,7 +46,7 @@ static inline void -readfifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size) +readfifo(unsigned int ale, unsigned long adr, u_char off, u_char * data, int size) { /* fifo read without cli because it's allready done */ int i; @@ -56,7 +56,7 @@ static inline void -writereg(unsigned int ale, unsigned int adr, u_char off, u_char data) +writereg(unsigned int ale, unsigned long adr, u_char off, u_char data) { long flags; unsigned int *po = (unsigned int *) adr; /* Postoffice */ @@ -71,7 +71,7 @@ static inline void -writefifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size) +writefifo(unsigned int ale, unsigned long adr, u_char off, u_char * data, int size) { /* fifo write without cli because it's allready done */ int i; @@ -316,11 +316,11 @@ printk(KERN_WARNING "HiSax: %s: No Memory base address\n", CardType[card->typ]); return (0); } - cs->hw.ax.base = (u_int) ioremap(pci_memaddr, 4096); + cs->hw.ax.base = (long) ioremap(pci_memaddr, 4096); /* Check suspecious address */ pI20_Regs = (I20_REGISTER_FILE *) (cs->hw.ax.base); if ((pI20_Regs->i20IntStatus & 0x8EFFFFFF) != 0) { - printk(KERN_WARNING "HiSax: %s address %x-%x suspecious\n", + printk(KERN_WARNING "HiSax: %s address %lx-%lx suspecious\n", CardType[card->typ], cs->hw.ax.base, cs->hw.ax.base + 4096); iounmap((void *) cs->hw.ax.base); cs->hw.ax.base = 0; @@ -335,7 +335,7 @@ printk(KERN_WARNING "HiSax: %s: unable to configure\n", CardType[card->typ]); return (0); #endif /* CONFIG_PCI */ - printk(KERN_INFO "HiSax: %s: Card configured at 0x%X IRQ %d\n", + printk(KERN_INFO "HiSax: %s: Card configured at 0x%lX IRQ %d\n", CardType[card->typ], cs->hw.ax.base, cs->irq); reset_bkm(cs); diff -u --recursive --new-file v2.4.6/linux/drivers/isdn/hisax/bkm_a8.c linux/drivers/isdn/hisax/bkm_a8.c --- v2.4.6/linux/drivers/isdn/hisax/bkm_a8.c Wed Apr 18 11:49:13 2001 +++ linux/drivers/isdn/hisax/bkm_a8.c Wed Jul 18 09:45:40 2001 @@ -1,4 +1,4 @@ -/* $Id: bkm_a8.c,v 1.14.6.5 2001/04/15 14:51:09 keil Exp $ +/* $Id: bkm_a8.c,v 1.14.6.6 2001/07/18 16:02:15 kai Exp $ * bkm_a8.c low level stuff for Scitel Quadro (4*S0, passive) * derived from the original file sedlbauer.c * derived from the original file niccy.c @@ -27,7 +27,7 @@ extern const char *CardType[]; -const char sct_quadro_revision[] = "$Revision: 1.14.6.5 $"; +const char sct_quadro_revision[] = "$Revision: 1.14.6.6 $"; static const char *sct_quadro_subtypes[] = { @@ -436,7 +436,7 @@ /* For isac and hscx data path */ cs->hw.ax.data_adr = cs->hw.ax.base + 4; - printk(KERN_INFO "HiSax: %s (%s) configured at 0x%.4X, 0x%.4X, 0x%.4X and IRQ %d\n", + printk(KERN_INFO "HiSax: %s (%s) configured at 0x%.4lX, 0x%.4lX, 0x%.4lX and IRQ %d\n", CardType[card->typ], sct_quadro_subtypes[cs->subtyp], cs->hw.ax.plx_adr, diff -u --recursive --new-file v2.4.6/linux/drivers/isdn/hisax/config.c linux/drivers/isdn/hisax/config.c --- v2.4.6/linux/drivers/isdn/hisax/config.c Tue Jul 3 17:08:19 2001 +++ linux/drivers/isdn/hisax/config.c Thu Jul 19 09:40:25 2001 @@ -1,4 +1,4 @@ -/* $Id: config.c,v 2.57.6.15 2001/06/09 15:14:17 kai Exp $ +/* $Id: config.c,v 2.57.6.16 2001/07/13 09:01:00 kai Exp $ * * Author Karsten Keil (keil@isdn4linux.de) * based on the teles driver from Jan den Ouden @@ -56,8 +56,8 @@ * 26 AVM A1 PCMCIA (Fritz) p0=irq p1=iobase * 27 AVM PnP/PCI p0=irq p1=iobase (PCI no parameter) * 28 Sedlbauer Speed Fax+ p0=irq p1=iobase (from isapnp setup) - * 29 Siemens I-Surf p0=irq p1=iobase p2=memory (from isapnp setup) - * 30 ACER P10 p0=irq p1=iobase (from isapnp setup) + * 29 Siemens I-Surf p0=irq p1=iobase p2=memory (from isapnp setup) + * 30 ACER P10 p0=irq p1=iobase (from isapnp setup) * 31 HST Saphir p0=irq p1=iobase * 32 Telekom A4T none * 33 Scitel Quadro p0=subcontroller (4*S0, subctrl 1...4) @@ -73,16 +73,18 @@ * */ -const char *CardType[] = -{"No Card", "Teles 16.0", "Teles 8.0", "Teles 16.3", "Creatix/Teles PnP", - "AVM A1", "Elsa ML", "Elsa Quickstep", "Teles PCMCIA", "ITK ix1-micro Rev.2", - "Elsa PCMCIA", "Eicon.Diehl Diva", "ISDNLink", "TeleInt", "Teles 16.3c", - "Sedlbauer Speed Card", "USR Sportster", "ith mic Linux", "Elsa PCI", - "Compaq ISA", "NETjet-S", "Teles PCI", "Sedlbauer Speed Star (PCMCIA)", - "AMD 7930", "NICCY", "S0Box", "AVM A1 (PCMCIA)", "AVM Fritz PnP/PCI", - "Sedlbauer Speed Fax +", "Siemens I-Surf", "Acer P10", "HST Saphir", - "Telekom A4T", "Scitel Quadro", "Gazel", "HFC 2BDS0 PCI", "Winbond 6692", - "HFC 2BDS0 SX", "NETspider-U", "HFC-2BDS0-SP PCMCIA", +const char *CardType[] = { + "No Card", "Teles 16.0", "Teles 8.0", "Teles 16.3", + "Creatix/Teles PnP", "AVM A1", "Elsa ML", "Elsa Quickstep", + "Teles PCMCIA", "ITK ix1-micro Rev.2", "Elsa PCMCIA", + "Eicon.Diehl Diva", "ISDNLink", "TeleInt", "Teles 16.3c", + "Sedlbauer Speed Card", "USR Sportster", "ith mic Linux", + "Elsa PCI", "Compaq ISA", "NETjet-S", "Teles PCI", + "Sedlbauer Speed Star (PCMCIA)", "AMD 7930", "NICCY", "S0Box", + "AVM A1 (PCMCIA)", "AVM Fritz PnP/PCI", "Sedlbauer Speed Fax +", + "Siemens I-Surf", "Acer P10", "HST Saphir", "Telekom A4T", + "Scitel Quadro", "Gazel", "HFC 2BDS0 PCI", "Winbond 6692", + "HFC 2BDS0 SX", "NETspider-U", "HFC-2BDS0-SP PCMCIA", }; void HiSax_closecard(int cardnr); @@ -90,9 +92,9 @@ #ifdef CONFIG_HISAX_ELSA #define DEFAULT_CARD ISDN_CTYPE_ELSA #define DEFAULT_CFG {0,0,0,0} -int elsa_init_pcmcia(void*, int, int*, int); +int elsa_init_pcmcia(void *, int, int *, int); EXPORT_SYMBOL(elsa_init_pcmcia); -#endif /* CONFIG_HISAX_ELSA */ +#endif #ifdef CONFIG_HISAX_AVM_A1 #undef DEFAULT_CARD @@ -106,9 +108,9 @@ #undef DEFAULT_CFG #define DEFAULT_CARD ISDN_CTYPE_A1_PCMCIA #define DEFAULT_CFG {11,0x170,0,0} -int avm_a1_init_pcmcia(void*, int, int*, int); +int avm_a1_init_pcmcia(void *, int, int *, int); EXPORT_SYMBOL(avm_a1_init_pcmcia); -#endif /* CONFIG_HISAX_AVM_A1_PCMCIA */ +#endif #ifdef CONFIG_HISAX_FRITZPCI #undef DEFAULT_CARD @@ -178,9 +180,9 @@ #undef DEFAULT_CFG #define DEFAULT_CARD ISDN_CTYPE_SEDLBAUER #define DEFAULT_CFG {11,0x270,0,0} -int sedl_init_pcmcia(void*, int, int*, int); +int sedl_init_pcmcia(void *, int, int *, int); EXPORT_SYMBOL(sedl_init_pcmcia); -#endif /* CONFIG_HISAX_SEDLBAUER */ +#endif #ifdef CONFIG_HISAX_SPORTSTER #undef DEFAULT_CARD @@ -222,7 +224,7 @@ #undef DEFAULT_CFG #define DEFAULT_CARD ISDN_CTYPE_HFC_SX #define DEFAULT_CFG {5,0x2E0,0,0} -int hfc_init_pcmcia(void*, int, int*, int); +int hfc_init_pcmcia(void *, int, int *, int); EXPORT_SYMBOL(hfc_init_pcmcia); #endif @@ -255,7 +257,7 @@ #define DEFAULT_CFG {5,0x250,0,0} #endif -#ifdef CONFIG_HISAX_BKM_A4T +#ifdef CONFIG_HISAX_BKM_A4T #undef DEFAULT_CARD #undef DEFAULT_CFG #define DEFAULT_CARD ISDN_CTYPE_BKM_A4T @@ -327,8 +329,7 @@ #define EMPTY_CARD {0, DEFAULT_PROTO, {0, 0, 0, 0}, NULL} -struct IsdnCard cards[] = -{ +struct IsdnCard cards[] = { FIRST_CARD, EMPTY_CARD, EMPTY_CARD, @@ -373,7 +374,7 @@ #ifdef IO0_IO1 MODULE_PARM(io0, "1-8i"); MODULE_PARM(io1, "1-8i"); -#endif /* IO0_IO1 */ +#endif #endif /* MODULE */ int nrcards; @@ -384,8 +385,7 @@ extern char *lli_revision; extern char *tei_revision; -char * -HiSax_getrev(const char *revision) +char *HiSax_getrev(const char *revision) { char *rev; char *p; @@ -399,8 +399,7 @@ return rev; } -void __init -HiSaxVersion(void) +void __init HiSaxVersion(void) { char tmp[64]; @@ -419,26 +418,24 @@ strcpy(tmp, l3_revision); printk(KERN_INFO "HiSax: Layer3 Revision %s\n", HiSax_getrev(tmp)); strcpy(tmp, lli_revision); - printk(KERN_INFO "HiSax: LinkLayer Revision %s\n", HiSax_getrev(tmp)); + printk(KERN_INFO "HiSax: LinkLayer Revision %s\n", + HiSax_getrev(tmp)); certification_check(1); } -void -HiSax_mod_dec_use_count(void) +void HiSax_mod_dec_use_count(void) { MOD_DEC_USE_COUNT; } -void -HiSax_mod_inc_use_count(void) +void HiSax_mod_inc_use_count(void) { MOD_INC_USE_COUNT; } #ifndef MODULE #define MAX_ARG (HISAX_MAX_CARDS*5) -static int __init -HiSax_setup(char *line) +static int __init HiSax_setup(char *line) { int i, j, argc; int ints[MAX_ARG + 1]; @@ -446,7 +443,7 @@ str = get_options(line, MAX_ARG, ints); argc = ints[0]; - printk(KERN_DEBUG"HiSax_setup: argc(%d) str(%s)\n", argc, str); + printk(KERN_DEBUG "HiSax_setup: argc(%d) str(%s)\n", argc, str); i = 0; j = 1; while (argc && (i < HISAX_MAX_CARDS)) { @@ -484,7 +481,7 @@ strcpy(HiSaxID, "HiSax"); HiSax_id = HiSaxID; } - return(1); + return 1; } __setup("hisax=", HiSax_setup); @@ -527,7 +524,7 @@ #endif #if CARD_DIEHLDIVA -extern int setup_diva(struct IsdnCard *card); +extern int setup_diva(struct IsdnCard *card); #endif #if CARD_ASUSCOM @@ -609,43 +606,41 @@ /* * Find card with given driverId */ -static inline struct IsdnCardState -*hisax_findcard(int driverid) +static inline struct IsdnCardState *hisax_findcard(int driverid) { int i; for (i = 0; i < nrcards; i++) if (cards[i].cs) if (cards[i].cs->myid == driverid) - return (cards[i].cs); - return (NULL); + return cards[i].cs; + return NULL; } /* * Find card with given card number */ -struct IsdnCardState -*hisax_get_card(int cardnr) +struct IsdnCardState *hisax_get_card(int cardnr) { - if ((cardnr <= nrcards) && (cardnr>0)) - if (cards[cardnr-1].cs) - return (cards[cardnr-1].cs); - return (NULL); + if ((cardnr <= nrcards) && (cardnr > 0)) + if (cards[cardnr - 1].cs) + return cards[cardnr - 1].cs; + return NULL; } -int -HiSax_readstatus(u_char * buf, int len, int user, int id, int channel) +int HiSax_readstatus(u_char * buf, int len, int user, int id, int channel) { - int count,cnt; + int count, cnt; u_char *p = buf; struct IsdnCardState *cs = hisax_findcard(id); if (cs) { if (len > HISAX_STATUS_BUFSIZE) { - printk(KERN_WARNING "HiSax: status overflow readstat %d/%d\n", - len, HISAX_STATUS_BUFSIZE); + printk(KERN_WARNING + "HiSax: status overflow readstat %d/%d\n", + len, HISAX_STATUS_BUFSIZE); } - count = cs->status_end - cs->status_read +1; + count = cs->status_end - cs->status_read + 1; if (count >= len) count = len; if (user) @@ -673,13 +668,12 @@ return len; } else { printk(KERN_ERR - "HiSax: if_readstatus called with invalid driverId!\n"); + "HiSax: if_readstatus called with invalid driverId!\n"); return -ENODEV; } } -inline int -jiftime(char *s, long mark) +int jiftime(char *s, long mark) { s += 8; @@ -697,15 +691,15 @@ *s-- = mark % 10 + '0'; mark /= 10; *s-- = mark % 10 + '0'; - return(8); + return 8; } static u_char tmpbuf[HISAX_STATUS_BUFSIZE]; -void -VHiSax_putstatus(struct IsdnCardState *cs, char *head, char *fmt, va_list args) +void VHiSax_putstatus(struct IsdnCardState *cs, char *head, char *fmt, + va_list args) { -/* if head == NULL the fmt contains the full info */ + /* if head == NULL the fmt contains the full info */ long flags; int count, i; @@ -729,18 +723,19 @@ len = strlen(fmt); } if (!cs) { - printk(KERN_WARNING "HiSax: No CardStatus for message %s", p); + printk(KERN_WARNING "HiSax: No CardStatus for message %s", + p); restore_flags(flags); return; } if (len > HISAX_STATUS_BUFSIZE) { printk(KERN_WARNING "HiSax: status overflow %d/%d\n", - len, HISAX_STATUS_BUFSIZE); + len, HISAX_STATUS_BUFSIZE); restore_flags(flags); return; } count = len; - i = cs->status_end - cs->status_write +1; + i = cs->status_end - cs->status_write + 1; if (i >= len) i = len; len -= i; @@ -754,7 +749,7 @@ cs->status_write += len; } #ifdef KERNELSTACK_DEBUG - i = (ulong)&len - current->kernel_stack_page; + i = (ulong) & len - current->kernel_stack_page; sprintf(tmpbuf, "kstack %s %lx use %ld\n", current->comm, current->kernel_stack_page, i); len = strlen(tmpbuf); @@ -774,8 +769,7 @@ } } -void -HiSax_putstatus(struct IsdnCardState *cs, char *head, char *fmt, ...) +void HiSax_putstatus(struct IsdnCardState *cs, char *head, char *fmt, ...) { va_list args; @@ -784,8 +778,7 @@ va_end(args); } -int -ll_run(struct IsdnCardState *cs, int addfeatures) +int ll_run(struct IsdnCardState *cs, int addfeatures) { long flags; isdn_ctrl ic; @@ -800,19 +793,17 @@ return 0; } -void -ll_stop(struct IsdnCardState *cs) +void ll_stop(struct IsdnCardState *cs) { isdn_ctrl ic; ic.command = ISDN_STAT_STOP; ic.driver = cs->myid; cs->iif.statcallb(&ic); -// CallcFreeChan(cs); + // CallcFreeChan(cs); } -static void -ll_unload(struct IsdnCardState *cs) +static void ll_unload(struct IsdnCardState *cs) { isdn_ctrl ic; @@ -827,8 +818,7 @@ kfree(cs->dlog); } -static void -closecard(int cardnr) +static void closecard(int cardnr) { struct IsdnCardState *csta = cards[cardnr].cs; @@ -856,56 +846,54 @@ ll_unload(csta); } -static int __devinit -init_card(struct IsdnCardState *cs) +static int __devinit init_card(struct IsdnCardState *cs) { int irq_cnt, cnt = 3; long flags; if (!cs->irq) - return(cs->cardmsg(cs, CARD_INIT, NULL)); + return cs->cardmsg(cs, CARD_INIT, NULL); save_flags(flags); cli(); irq_cnt = kstat_irqs(cs->irq); - printk(KERN_INFO "%s: IRQ %d count %d\n", CardType[cs->typ], cs->irq, - irq_cnt); + printk(KERN_INFO "%s: IRQ %d count %d\n", CardType[cs->typ], + cs->irq, irq_cnt); if (request_irq(cs->irq, cs->irq_func, cs->irq_flags, "HiSax", cs)) { printk(KERN_WARNING "HiSax: couldn't get interrupt %d\n", - cs->irq); + cs->irq); restore_flags(flags); - return(1); + return 1; } while (cnt) { cs->cardmsg(cs, CARD_INIT, NULL); sti(); set_current_state(TASK_UNINTERRUPTIBLE); /* Timeout 10ms */ - schedule_timeout((10*HZ)/1000); + schedule_timeout((10 * HZ) / 1000); restore_flags(flags); - printk(KERN_INFO "%s: IRQ %d count %d\n", CardType[cs->typ], - cs->irq, kstat_irqs(cs->irq)); + printk(KERN_INFO "%s: IRQ %d count %d\n", + CardType[cs->typ], cs->irq, kstat_irqs(cs->irq)); if (kstat_irqs(cs->irq) == irq_cnt) { printk(KERN_WARNING "%s: IRQ(%d) getting no interrupts during init %d\n", CardType[cs->typ], cs->irq, 4 - cnt); if (cnt == 1) { free_irq(cs->irq, cs); - return (2); + return 2; } else { cs->cardmsg(cs, CARD_RESET, NULL); cnt--; } } else { cs->cardmsg(cs, CARD_TEST, NULL); - return(0); + return 0; } } restore_flags(flags); - return(3); + return 3; } -static int __devinit -checkcard(int cardnr, char *id, int *busy_flag) +static int __devinit checkcard(int cardnr, char *id, int *busy_flag) { long flags; int ret = 0; @@ -923,8 +911,8 @@ } memset(cs, 0, sizeof(struct IsdnCardState)); card->cs = cs; - cs->chanlimit = 2; /* maximum B-channel number */ - cs->logecho = 0; /* No echo logging */ + cs->chanlimit = 2; /* maximum B-channel number */ + cs->logecho = 0; /* No echo logging */ cs->cardnr = cardnr; cs->debug = L1_DEB_WARN; cs->HW_Flags = 0; @@ -940,14 +928,12 @@ if (card->typ <= 0 || card->typ > ISDN_CTYPE_COUNT) { printk(KERN_WARNING - "HiSax: Card Type %d out of range\n", - card->typ); + "HiSax: Card Type %d out of range\n", card->typ); goto outf_cs; } if (!(cs->dlog = kmalloc(MAX_DLOG_SPACE, GFP_ATOMIC))) { printk(KERN_WARNING - "HiSax: No memory for dlog(card %d)\n", - cardnr + 1); + "HiSax: No memory for dlog(card %d)\n", cardnr + 1); goto outf_cs; } if (!(cs->status_buf = kmalloc(HISAX_STATUS_BUFSIZE, GFP_ATOMIC))) { @@ -981,7 +967,7 @@ ISDN_FEATURE_P_NI1 | #endif 0; - + cs->iif.command = HiSax_command; cs->iif.writecmd = NULL; cs->iif.writebuf_skb = HiSax_writebuf_skb; @@ -1092,12 +1078,12 @@ break; #endif #if CARD_HFC_PCI - case ISDN_CTYPE_HFC_PCI: + case ISDN_CTYPE_HFC_PCI: ret = setup_hfcpci(card); break; #endif #if CARD_HFC_SX - case ISDN_CTYPE_HFC_SX: + case ISDN_CTYPE_HFC_SX: ret = setup_hfcsx(card); break; #endif @@ -1126,7 +1112,7 @@ ret = setup_testemu(card); break; #endif -#if CARD_BKM_A4T +#if CARD_BKM_A4T case ISDN_CTYPE_BKM_A4T: ret = setup_bkm_a4t(card); break; @@ -1163,8 +1149,7 @@ goto outf_cs; } if (!(cs->rcvbuf = kmalloc(MAX_DFRAME_LEN_L1, GFP_ATOMIC))) { - printk(KERN_WARNING - "HiSax: No memory for isac rcvbuf\n"); + printk(KERN_WARNING "HiSax: No memory for isac rcvbuf\n"); ll_unload(cs); goto outf_cs; } @@ -1210,8 +1195,7 @@ return ret; } -void __devinit -HiSax_shiftcards(int idx) +void __devinit HiSax_shiftcards(int idx) { int i; @@ -1219,8 +1203,7 @@ memcpy(&cards[i], &cards[i + 1], sizeof(cards[i])); } -int __devinit -HiSax_inithardware(int *busy_flag) +int __devinit HiSax_inithardware(int *busy_flag) { int foundcards = 0; int i = 0; @@ -1254,7 +1237,8 @@ foundcards++; i++; } else { - printk(KERN_WARNING "HiSax: Card %s not installed !\n", + printk(KERN_WARNING + "HiSax: Card %s not installed !\n", CardType[cards[i].typ]); HiSax_shiftcards(i); nrcards--; @@ -1263,19 +1247,17 @@ return foundcards; } -void -HiSax_closecard(int cardnr) +void HiSax_closecard(int cardnr) { - int i,last=nrcards - 1; + int i, last = nrcards - 1; - if (cardnr>last) + if (cardnr > last) return; if (cards[cardnr].cs) { ll_stop(cards[cardnr].cs); release_tei(cards[cardnr].cs); - CallcFreeChan(cards[cardnr].cs); - + closecard(cardnr); if (cards[cardnr].cs->irq) free_irq(cards[cardnr].cs->irq, cards[cardnr].cs); @@ -1283,15 +1265,14 @@ cards[cardnr].cs = NULL; } i = cardnr; - while (i!=last) { - cards[i] = cards[i+1]; + while (i <= last) { + cards[i] = cards[i + 1]; i++; } nrcards--; } -void -HiSax_reportcard(int cardnr, int sel) +void HiSax_reportcard(int cardnr, int sel) { struct IsdnCardState *cs = cards[cardnr].cs; @@ -1299,21 +1280,25 @@ printk(KERN_DEBUG "HiSax: Type %s\n", CardType[cs->typ]); printk(KERN_DEBUG "HiSax: debuglevel %x\n", cs->debug); printk(KERN_DEBUG "HiSax: HiSax_reportcard address 0x%lX\n", - (ulong) & HiSax_reportcard); + (ulong) & HiSax_reportcard); printk(KERN_DEBUG "HiSax: cs 0x%lX\n", (ulong) cs); printk(KERN_DEBUG "HiSax: HW_Flags %lx bc0 flg %lx bc1 flg %lx\n", - cs->HW_Flags, cs->bcs[0].Flag, cs->bcs[1].Flag); + cs->HW_Flags, cs->bcs[0].Flag, cs->bcs[1].Flag); printk(KERN_DEBUG "HiSax: bcs 0 mode %d ch%d\n", - cs->bcs[0].mode, cs->bcs[0].channel); + cs->bcs[0].mode, cs->bcs[0].channel); printk(KERN_DEBUG "HiSax: bcs 1 mode %d ch%d\n", - cs->bcs[1].mode, cs->bcs[1].channel); + cs->bcs[1].mode, cs->bcs[1].channel); #ifdef ERROR_STATISTIC printk(KERN_DEBUG "HiSax: dc errors(rx,crc,tx) %d,%d,%d\n", - cs->err_rx, cs->err_crc, cs->err_tx); - printk(KERN_DEBUG "HiSax: bc0 errors(inv,rdo,crc,tx) %d,%d,%d,%d\n", - cs->bcs[0].err_inv, cs->bcs[0].err_rdo, cs->bcs[0].err_crc, cs->bcs[0].err_tx); - printk(KERN_DEBUG "HiSax: bc1 errors(inv,rdo,crc,tx) %d,%d,%d,%d\n", - cs->bcs[1].err_inv, cs->bcs[1].err_rdo, cs->bcs[1].err_crc, cs->bcs[1].err_tx); + cs->err_rx, cs->err_crc, cs->err_tx); + printk(KERN_DEBUG + "HiSax: bc0 errors(inv,rdo,crc,tx) %d,%d,%d,%d\n", + cs->bcs[0].err_inv, cs->bcs[0].err_rdo, cs->bcs[0].err_crc, + cs->bcs[0].err_tx); + printk(KERN_DEBUG + "HiSax: bc1 errors(inv,rdo,crc,tx) %d,%d,%d,%d\n", + cs->bcs[1].err_inv, cs->bcs[1].err_rdo, cs->bcs[1].err_crc, + cs->bcs[1].err_tx); if (sel == 99) { cs->err_rx = 0; cs->err_crc = 0; @@ -1333,7 +1318,7 @@ static int __init HiSax_init(void) { int i, retval; -#ifdef MODULE +#ifdef MODULE int j; int nzproto = 0; #endif @@ -1357,7 +1342,7 @@ #ifdef MODULE if (!type[0]) { - /* We 'll register drivers later, but init basic functions*/ + /* We 'll register drivers later, but init basic functions */ return 0; } #ifdef CONFIG_HISAX_ELSA @@ -1396,98 +1381,100 @@ nzproto++; } switch (type[i]) { - case ISDN_CTYPE_16_0: - cards[j].para[0] = irq[i]; - cards[j].para[1] = mem[i]; - cards[j].para[2] = io[i]; - break; + case ISDN_CTYPE_16_0: + cards[j].para[0] = irq[i]; + cards[j].para[1] = mem[i]; + cards[j].para[2] = io[i]; + break; - case ISDN_CTYPE_8_0: - cards[j].para[0] = irq[i]; - cards[j].para[1] = mem[i]; - break; + case ISDN_CTYPE_8_0: + cards[j].para[0] = irq[i]; + cards[j].para[1] = mem[i]; + break; #ifdef IO0_IO1 - case ISDN_CTYPE_PNP: - case ISDN_CTYPE_NICCY: - cards[j].para[0] = irq[i]; - cards[j].para[1] = io0[i]; - cards[j].para[2] = io1[i]; - break; - case ISDN_CTYPE_COMPAQ_ISA: - cards[j].para[0] = irq[i]; - cards[j].para[1] = io0[i]; - cards[j].para[2] = io1[i]; - cards[j].para[3] = io[i]; - break; -#endif - case ISDN_CTYPE_ELSA: - case ISDN_CTYPE_HFC_PCI: - cards[j].para[0] = io[i]; - break; - case ISDN_CTYPE_16_3: - case ISDN_CTYPE_TELESPCMCIA: - case ISDN_CTYPE_A1: - case ISDN_CTYPE_A1_PCMCIA: - case ISDN_CTYPE_ELSA_PNP: - case ISDN_CTYPE_ELSA_PCMCIA: - case ISDN_CTYPE_IX1MICROR2: - case ISDN_CTYPE_DIEHLDIVA: - case ISDN_CTYPE_ASUSCOM: - case ISDN_CTYPE_TELEINT: - case ISDN_CTYPE_SEDLBAUER: - case ISDN_CTYPE_SEDLBAUER_PCMCIA: - case ISDN_CTYPE_SEDLBAUER_FAX: - case ISDN_CTYPE_SPORTSTER: - case ISDN_CTYPE_MIC: - case ISDN_CTYPE_TELES3C: - case ISDN_CTYPE_ACERP10: - case ISDN_CTYPE_S0BOX: - case ISDN_CTYPE_FRITZPCI: - case ISDN_CTYPE_HSTSAPHIR: - case ISDN_CTYPE_GAZEL: - case ISDN_CTYPE_HFC_SX: - case ISDN_CTYPE_HFC_SP_PCMCIA: - cards[j].para[0] = irq[i]; - cards[j].para[1] = io[i]; - break; - case ISDN_CTYPE_ISURF: + case ISDN_CTYPE_PNP: + case ISDN_CTYPE_NICCY: + cards[j].para[0] = irq[i]; + cards[j].para[1] = io0[i]; + cards[j].para[2] = io1[i]; + break; + case ISDN_CTYPE_COMPAQ_ISA: + cards[j].para[0] = irq[i]; + cards[j].para[1] = io0[i]; + cards[j].para[2] = io1[i]; + cards[j].para[3] = io[i]; + break; +#endif + case ISDN_CTYPE_ELSA: + case ISDN_CTYPE_HFC_PCI: + cards[j].para[0] = io[i]; + break; + case ISDN_CTYPE_16_3: + case ISDN_CTYPE_TELESPCMCIA: + case ISDN_CTYPE_A1: + case ISDN_CTYPE_A1_PCMCIA: + case ISDN_CTYPE_ELSA_PNP: + case ISDN_CTYPE_ELSA_PCMCIA: + case ISDN_CTYPE_IX1MICROR2: + case ISDN_CTYPE_DIEHLDIVA: + case ISDN_CTYPE_ASUSCOM: + case ISDN_CTYPE_TELEINT: + case ISDN_CTYPE_SEDLBAUER: + case ISDN_CTYPE_SEDLBAUER_PCMCIA: + case ISDN_CTYPE_SEDLBAUER_FAX: + case ISDN_CTYPE_SPORTSTER: + case ISDN_CTYPE_MIC: + case ISDN_CTYPE_TELES3C: + case ISDN_CTYPE_ACERP10: + case ISDN_CTYPE_S0BOX: + case ISDN_CTYPE_FRITZPCI: + case ISDN_CTYPE_HSTSAPHIR: + case ISDN_CTYPE_GAZEL: + case ISDN_CTYPE_HFC_SX: + case ISDN_CTYPE_HFC_SP_PCMCIA: + cards[j].para[0] = irq[i]; + cards[j].para[1] = io[i]; + break; + case ISDN_CTYPE_ISURF: + cards[j].para[0] = irq[i]; + cards[j].para[1] = io[i]; + cards[j].para[2] = mem[i]; + break; + case ISDN_CTYPE_ELSA_PCI: + case ISDN_CTYPE_NETJET_S: + case ISDN_CTYPE_AMD7930: + case ISDN_CTYPE_TELESPCI: + case ISDN_CTYPE_W6692: + case ISDN_CTYPE_NETJET_U: + break; + case ISDN_CTYPE_BKM_A4T: + break; + case ISDN_CTYPE_SCT_QUADRO: + if (irq[i]) { cards[j].para[0] = irq[i]; - cards[j].para[1] = io[i]; - cards[j].para[2] = mem[i]; - break; - case ISDN_CTYPE_ELSA_PCI: - case ISDN_CTYPE_NETJET_S: - case ISDN_CTYPE_AMD7930: - case ISDN_CTYPE_TELESPCI: - case ISDN_CTYPE_W6692: - case ISDN_CTYPE_NETJET_U: - break; - case ISDN_CTYPE_BKM_A4T: - break; - case ISDN_CTYPE_SCT_QUADRO: - if (irq[i]) { - cards[j].para[0] = irq[i]; - } else { - /* QUADRO is a 4 BRI card */ - cards[j++].para[0] = 1; - cards[j].typ = ISDN_CTYPE_SCT_QUADRO; - cards[j].protocol = protocol[i]; - cards[j++].para[0] = 2; - cards[j].typ = ISDN_CTYPE_SCT_QUADRO; - cards[j].protocol = protocol[i]; - cards[j++].para[0] = 3; - cards[j].typ = ISDN_CTYPE_SCT_QUADRO; - cards[j].protocol = protocol[i]; - cards[j].para[0] = 4; - } - break; + } else { + /* QUADRO is a 4 BRI card */ + cards[j++].para[0] = 1; + cards[j].typ = ISDN_CTYPE_SCT_QUADRO; + cards[j].protocol = protocol[i]; + cards[j++].para[0] = 2; + cards[j].typ = ISDN_CTYPE_SCT_QUADRO; + cards[j].protocol = protocol[i]; + cards[j++].para[0] = 3; + cards[j].typ = ISDN_CTYPE_SCT_QUADRO; + cards[j].protocol = protocol[i]; + cards[j].para[0] = 4; + } + break; } j++; } if (!nzproto) { - printk(KERN_WARNING "HiSax: Warning - no protocol specified\n"); - printk(KERN_WARNING "HiSax: using protocol %s\n", DEFAULT_PROTO_NAME); + printk(KERN_WARNING + "HiSax: Warning - no protocol specified\n"); + printk(KERN_WARNING "HiSax: using protocol %s\n", + DEFAULT_PROTO_NAME); } #endif if (!HiSax_id) @@ -1505,7 +1492,7 @@ retval = -EIO; goto out_isdnl1; } - + return 0; out_isdnl1: @@ -1524,12 +1511,12 @@ static void __exit HiSax_exit(void) { - int cardnr = nrcards -1; + int cardnr = nrcards - 1; long flags; save_flags(flags); cli(); - while(cardnr>=0) + while (cardnr >= 0) HiSax_closecard(cardnr--); Isdnl1Free(); TeiFree(); @@ -1549,7 +1536,7 @@ nrcards = 0; /* Initialize all structs, even though we only accept two pcmcia cards - */ + */ for (i = 0; i < HISAX_MAX_CARDS; i++) { cards[i].para[0] = irq[i]; cards[i].para[1] = io[i]; @@ -1559,7 +1546,7 @@ } } cards[0].para[0] = pcm_irq; - cards[0].para[1] = (int)pcm_iob; + cards[0].para[1] = (int) pcm_iob; cards[0].protocol = prot; cards[0].typ = ISDN_CTYPE_ELSA_PCMCIA; @@ -1576,7 +1563,7 @@ HiSax_inithardware(busy_flag); printk(KERN_NOTICE "HiSax: module installed\n"); #endif - return (0); + return 0; } #endif @@ -1590,7 +1577,7 @@ nrcards = 0; /* Initialize all structs, even though we only accept two pcmcia cards - */ + */ for (i = 0; i < HISAX_MAX_CARDS; i++) { cards[i].para[0] = irq[i]; cards[i].para[1] = io[i]; @@ -1601,7 +1588,7 @@ } } cards[0].para[0] = pcm_irq; - cards[0].para[1] = (int)pcm_iob; + cards[0].para[1] = (int) pcm_iob; cards[0].protocol = prot; cards[0].typ = ISDN_CTYPE_HFC_SP_PCMCIA; nzproto = 1; @@ -1619,7 +1606,7 @@ HiSax_inithardware(busy_flag); printk(KERN_NOTICE "HiSax: module installed\n"); #endif - return (0); + return 0; } #endif @@ -1633,7 +1620,7 @@ nrcards = 0; /* Initialize all structs, even though we only accept two pcmcia cards - */ + */ for (i = 0; i < HISAX_MAX_CARDS; i++) { cards[i].para[0] = irq[i]; cards[i].para[1] = io[i]; @@ -1644,7 +1631,7 @@ } } cards[0].para[0] = pcm_irq; - cards[0].para[1] = (int)pcm_iob; + cards[0].para[1] = (int) pcm_iob; cards[0].protocol = prot; cards[0].typ = ISDN_CTYPE_SEDLBAUER_PCMCIA; nzproto = 1; @@ -1662,7 +1649,7 @@ HiSax_inithardware(busy_flag); printk(KERN_NOTICE "HiSax: module installed\n"); #endif - return (0); + return 0; } #endif @@ -1676,7 +1663,7 @@ nrcards = 0; /* Initialize all structs, even though we only accept two pcmcia cards - */ + */ for (i = 0; i < HISAX_MAX_CARDS; i++) { cards[i].para[0] = irq[i]; cards[i].para[1] = io[i]; @@ -1687,7 +1674,7 @@ } } cards[0].para[0] = pcm_irq; - cards[0].para[1] = (int)pcm_iob; + cards[0].para[1] = (int) pcm_iob; cards[0].protocol = prot; cards[0].typ = ISDN_CTYPE_A1_PCMCIA; nzproto = 1; @@ -1705,11 +1692,12 @@ HiSax_inithardware(busy_flag); printk(KERN_NOTICE "HiSax: module installed\n"); #endif - return (0); + return 0; } #endif -int __devinit hisax_init_pcmcia(void *pcm_iob, int *busy_flag, struct IsdnCard *card) +int __devinit hisax_init_pcmcia(void *pcm_iob, int *busy_flag, + struct IsdnCard *card) { u_char ids[16]; int ret = -1; @@ -1720,11 +1708,11 @@ else sprintf(ids, "HiSax"); if (!checkcard(nrcards, ids, busy_flag)) { - return(-1); + return -1; } ret = nrcards; nrcards++; - return (ret); + return ret; } #include <linux/pci.h> diff -u --recursive --new-file v2.4.6/linux/drivers/isdn/hisax/elsa.c linux/drivers/isdn/hisax/elsa.c --- v2.4.6/linux/drivers/isdn/hisax/elsa.c Fri Mar 2 11:12:08 2001 +++ linux/drivers/isdn/hisax/elsa.c Wed Jul 18 09:45:40 2001 @@ -1,4 +1,4 @@ -/* $Id: elsa.c,v 2.26.6.3 2001/02/16 16:43:25 kai Exp $ +/* $Id: elsa.c,v 2.26.6.5 2001/07/18 16:25:12 kai Exp $ * * elsa.c low level stuff for Elsa isdn cards * @@ -30,7 +30,7 @@ extern const char *CardType[]; -const char *Elsa_revision = "$Revision: 2.26.6.3 $"; +const char *Elsa_revision = "$Revision: 2.26.6.5 $"; const char *Elsa_Types[] = {"None", "PC", "PCC-8", "PCC-16", "PCF", "PCF-Pro", "PCMCIA", "QS 1000", "QS 3000", "Microlink PCI", "QS 3000 PCI", @@ -590,13 +590,13 @@ if (cs->subtyp==ELSA_QS1000) { cs->subtyp = ELSA_QS3000; printk(KERN_INFO - "Elsa: %s detected modem at 0x%x\n", + "Elsa: %s detected modem at 0x%lx\n", Elsa_Types[cs->subtyp], cs->hw.elsa.base+8); release_region(cs->hw.elsa.base, 8); if (check_region(cs->hw.elsa.base, 16)) { printk(KERN_WARNING - "HiSax: %s config port %x-%x already in use\n", + "HiSax: %s config port %lx-%lx already in use\n", Elsa_Types[cs->subtyp], cs->hw.elsa.base + 8, cs->hw.elsa.base + 16); @@ -606,13 +606,13 @@ } else if (cs->subtyp==ELSA_PCC16) { cs->subtyp = ELSA_PCF; printk(KERN_INFO - "Elsa: %s detected modem at 0x%x\n", + "Elsa: %s detected modem at 0x%lx\n", Elsa_Types[cs->subtyp], cs->hw.elsa.base+8); release_region(cs->hw.elsa.base, 8); if (check_region(cs->hw.elsa.base, 16)) { printk(KERN_WARNING - "HiSax: %s config port %x-%x already in use\n", + "HiSax: %s config port %lx-%lx already in use\n", Elsa_Types[cs->subtyp], cs->hw.elsa.base + 8, cs->hw.elsa.base + 16); @@ -621,7 +621,7 @@ "elsa isdn modem"); } else printk(KERN_INFO - "Elsa: %s detected modem at 0x%x\n", + "Elsa: %s detected modem at 0x%lx\n", Elsa_Types[cs->subtyp], cs->hw.elsa.base+8); arcofi_fsm(cs, ARCOFI_START, &ARCOFI_XOP_0); @@ -881,7 +881,7 @@ if (!(cs->subtyp = probe_elsa_adr(cs->hw.elsa.base, cs->typ))) { printk(KERN_WARNING - "Elsa: no Elsa Microlink at 0x%x\n", + "Elsa: no Elsa Microlink at %#lx\n", cs->hw.elsa.base); return (0); } @@ -919,7 +919,7 @@ if ((cs->subtyp == ELSA_PCFPRO) && (val = 'G')) val = 'C'; printk(KERN_INFO - "Elsa: %s found at 0x%x Rev.:%c IRQ %d\n", + "Elsa: %s found at %#lx Rev.:%c IRQ %d\n", Elsa_Types[cs->subtyp], cs->hw.elsa.base, val, cs->irq); @@ -946,7 +946,7 @@ cs->hw.elsa.timer = cs->hw.elsa.base + ELSA_START_TIMER; cs->hw.elsa.ctrl = cs->hw.elsa.base + ELSA_CONTROL; printk(KERN_INFO - "Elsa: %s defined at 0x%x IRQ %d\n", + "Elsa: %s defined at %#lx IRQ %d\n", Elsa_Types[cs->subtyp], cs->hw.elsa.base, cs->irq); @@ -970,7 +970,7 @@ cs->hw.elsa.trig = 0; cs->hw.elsa.ctrl = 0; printk(KERN_INFO - "Elsa: %s defined at 0x%x IRQ %d\n", + "Elsa: %s defined at %#lx IRQ %d\n", Elsa_Types[cs->subtyp], cs->hw.elsa.base, cs->irq); @@ -1028,7 +1028,7 @@ cs->hw.elsa.trig = 0; cs->irq_flags |= SA_SHIRQ; printk(KERN_INFO - "Elsa: %s defined at 0x%x/0x%x IRQ %d\n", + "Elsa: %s defined at %#lx/0x%x IRQ %d\n", Elsa_Types[cs->subtyp], cs->hw.elsa.base, cs->hw.elsa.cfg, @@ -1068,7 +1068,7 @@ here, it would fail. */ if (cs->typ != ISDN_CTYPE_ELSA_PCMCIA && check_region(cs->hw.elsa.base, bytecnt)) { printk(KERN_WARNING - "HiSax: %s config port %x-%x already in use\n", + "HiSax: %s config port %#lx-%#lx already in use\n", CardType[card->typ], cs->hw.elsa.base, cs->hw.elsa.base + bytecnt); diff -u --recursive --new-file v2.4.6/linux/drivers/isdn/hisax/hfc_sx.c linux/drivers/isdn/hisax/hfc_sx.c --- v2.4.6/linux/drivers/isdn/hisax/hfc_sx.c Tue Jul 3 17:08:19 2001 +++ linux/drivers/isdn/hisax/hfc_sx.c Wed Jul 18 09:45:40 2001 @@ -1,4 +1,4 @@ -/* $Id: hfc_sx.c,v 1.9.6.1 2001/06/09 15:14:17 kai Exp $ +/* $Id: hfc_sx.c,v 1.9.6.2 2001/07/18 16:25:12 kai Exp $ * hfc_sx.c low level driver for CCD´s hfc-s+/sp based cards * @@ -32,7 +32,7 @@ extern const char *CardType[]; -static const char *hfcsx_revision = "$Revision: 1.9.6.1 $"; +static const char *hfcsx_revision = "$Revision: 1.9.6.2 $"; /***************************************/ /* IRQ-table for CCDs demo board */ @@ -1492,7 +1492,7 @@ if ((!cs->hw.hfcsx.base) || check_region((cs->hw.hfcsx.base), 2)) { printk(KERN_WARNING - "HiSax: HFC-SX io-base 0x%x already in use\n", + "HiSax: HFC-SX io-base %#lx already in use\n", cs->hw.hfcsx.base); return(0); } else { diff -u --recursive --new-file v2.4.6/linux/drivers/isdn/hisax/hisax.h linux/drivers/isdn/hisax/hisax.h --- v2.4.6/linux/drivers/isdn/hisax/hisax.h Tue Jul 3 17:08:19 2001 +++ linux/drivers/isdn/hisax/hisax.h Wed Jul 18 09:45:40 2001 @@ -1,4 +1,4 @@ -/* $Id: hisax.h,v 2.52.6.6 2001/06/09 15:14:17 kai Exp $ +/* $Id: hisax.h,v 2.52.6.7 2001/07/18 16:02:15 kai Exp $ * * Basic declarations, defines and prototypes * @@ -535,7 +535,7 @@ }; struct elsa_hw { - unsigned int base; + unsigned long base; unsigned int cfg; unsigned int ctrl; unsigned int ale; @@ -597,9 +597,9 @@ unsigned long cfg_reg; unsigned long pci_cfg; unsigned int ctrl; - unsigned int isac_adr; + unsigned long isac_adr; unsigned int isac; - unsigned int hscx_adr; + unsigned long hscx_adr; unsigned int hscx; unsigned int status; struct timer_list tl; @@ -653,7 +653,7 @@ }; struct njet_hw { - unsigned int base; + unsigned long base; unsigned int isac; unsigned int auxa; unsigned char auxd; @@ -692,7 +692,7 @@ }; struct hfcSX_hw { - unsigned int base; + unsigned long base; unsigned char cirm; unsigned char ctmt; unsigned char conn; @@ -754,15 +754,15 @@ }; struct bkm_hw { - unsigned int base; + unsigned long base; /* A4T stuff */ - unsigned int isac_adr; + unsigned long isac_adr; unsigned int isac_ale; - unsigned int jade_adr; + unsigned long jade_adr; unsigned int jade_ale; /* Scitel Quadro stuff */ - unsigned int plx_adr; - unsigned int data_adr; + unsigned long plx_adr; + unsigned long data_adr; }; struct gazel_hw { @@ -1275,7 +1275,7 @@ struct IsdnCard { int typ; int protocol; /* EDSS1, 1TR6 or NI1 */ - unsigned int para[4]; + unsigned long para[4]; struct IsdnCardState *cs; }; diff -u --recursive --new-file v2.4.6/linux/drivers/isdn/hisax/md linux/drivers/isdn/hisax/md --- v2.4.6/linux/drivers/isdn/hisax/md Tue Jul 3 17:08:19 2001 +++ linux/drivers/isdn/hisax/md Wed Dec 31 16:00:00 1969 @@ -1,12 +0,0 @@ -6f9433a8b696076562562d090e3c420f isac.c -13c3eed869f5139f44c563e3a8fea1f5 isdnl1.c -addcff863b0ff1e366c0f2ae9fa6e81e isdnl2.c -7076deb94a363945c21ea27aca4a720a isdnl3.c -51c603829b6cc4f8421f744ad657ceff tei.c -669050ab5079f02887ed0239d86e5474 callc.c -e592db58630c1f1029cc064110108156 cert.c -fadeb3b85bb23bc1ac48470c0848d6fa l3dss1.c -cf7dec9fac6283716904d26b99188476 l3_1tr6.c -65d9e5471bc129624f858ebcf0743525 elsa.c -b4cf8a4dceed9ea6dcba65a85b4eecc7 diva.c -99e67bea8f6945fa0d4e0aded5bf0fa0 sedlbauer.c diff -u --recursive --new-file v2.4.6/linux/drivers/isdn/hisax/nj_s.c linux/drivers/isdn/hisax/nj_s.c --- v2.4.6/linux/drivers/isdn/hisax/nj_s.c Fri Mar 2 11:12:09 2001 +++ linux/drivers/isdn/hisax/nj_s.c Wed Jul 18 09:45:40 2001 @@ -1,4 +1,4 @@ -// $Id: nj_s.c,v 2.7.6.4 2001/02/16 16:43:28 kai Exp $ +// $Id: nj_s.c,v 2.7.6.5 2001/07/18 16:25:12 kai Exp $ // // This file is (c) under GNU General Public License // @@ -14,7 +14,7 @@ #include <linux/ppp_defs.h> #include "netjet.h" -const char *NETjet_S_revision = "$Revision: 2.7.6.4 $"; +const char *NETjet_S_revision = "$Revision: 2.7.6.5 $"; static u_char dummyrr(struct IsdnCardState *cs, int chan, u_char off) { @@ -240,11 +240,11 @@ bytecnt = 256; printk(KERN_INFO - "NETjet-S: PCI card configured at 0x%x IRQ %d\n", + "NETjet-S: PCI card configured at %#lx IRQ %d\n", cs->hw.njet.base, cs->irq); if (check_region(cs->hw.njet.base, bytecnt)) { printk(KERN_WARNING - "HiSax: %s config port %x-%x already in use\n", + "HiSax: %s config port %#lx-%#lx already in use\n", CardType[card->typ], cs->hw.njet.base, cs->hw.njet.base + bytecnt); diff -u --recursive --new-file v2.4.6/linux/drivers/isdn/hisax/nj_u.c linux/drivers/isdn/hisax/nj_u.c --- v2.4.6/linux/drivers/isdn/hisax/nj_u.c Fri Mar 2 11:12:09 2001 +++ linux/drivers/isdn/hisax/nj_u.c Wed Jul 18 09:45:40 2001 @@ -1,4 +1,4 @@ -/* $Id: nj_u.c,v 2.8.6.4 2001/02/16 16:43:28 kai Exp $ +/* $Id: nj_u.c,v 2.8.6.5 2001/07/18 16:25:12 kai Exp $ * * This file is (c) under GNU General Public License * @@ -15,7 +15,7 @@ #include <linux/ppp_defs.h> #include "netjet.h" -const char *NETjet_U_revision = "$Revision: 2.8.6.4 $"; +const char *NETjet_U_revision = "$Revision: 2.8.6.5 $"; static u_char dummyrr(struct IsdnCardState *cs, int chan, u_char off) { @@ -244,11 +244,11 @@ bytecnt = 256; printk(KERN_INFO - "NETspider-U: PCI card configured at 0x%x IRQ %d\n", + "NETspider-U: PCI card configured at %#lx IRQ %d\n", cs->hw.njet.base, cs->irq); if (check_region(cs->hw.njet.base, bytecnt)) { printk(KERN_WARNING - "HiSax: %s config port %x-%x already in use\n", + "HiSax: %s config port %#lx-%#lx already in use\n", CardType[card->typ], cs->hw.njet.base, cs->hw.njet.base + bytecnt); diff -u --recursive --new-file v2.4.6/linux/drivers/isdn/hisax/sedlbauer.c linux/drivers/isdn/hisax/sedlbauer.c --- v2.4.6/linux/drivers/isdn/hisax/sedlbauer.c Fri Mar 2 11:12:09 2001 +++ linux/drivers/isdn/hisax/sedlbauer.c Wed Jul 18 09:45:40 2001 @@ -1,4 +1,4 @@ -/* $Id: sedlbauer.c,v 1.25.6.4 2001/02/16 16:43:29 kai Exp $ +/* $Id: sedlbauer.c,v 1.25.6.5 2001/07/13 09:20:12 kai Exp $ * * sedlbauer.c low level stuff for Sedlbauer cards * includes support for the Sedlbauer speed star (speed star II), @@ -30,11 +30,11 @@ * Speed Win2 IPAC ISAPNP * ISDN PC/104 IPAC DIP-SWITCH * Speed Star2 IPAC CARDMGR - * Speed PCI IPAC PCI PNP + * Speed PCI IPAC PCI PNP * Speed Fax+ ISAC_ISAR PCI PNP Full analog support * * Important: - * For the sedlbauer speed fax+ to work properly you have to download + * For the sedlbauer speed fax+ to work properly you have to download * the firmware onto the card. * For example: hisaxctrl <DriverID> 9 ISAR.BIN */ @@ -52,10 +52,10 @@ extern const char *CardType[]; -const char *Sedlbauer_revision = "$Revision: 1.25.6.4 $"; +const char *Sedlbauer_revision = "$Revision: 1.25.6.5 $"; const char *Sedlbauer_Types[] = - {"None", "speed card/win", "speed star", "speed fax+", + {"None", "speed card/win", "speed star", "speed fax+", "speed win II / ISDN PC/104", "speed star II", "speed pci", "speed fax+ pyramid", "speed fax+ pci"}; @@ -63,7 +63,7 @@ #define PCI_SUBVENDOR_SEDLBAUER_PCI 0x53 #define PCI_SUBVENDOR_SPEEDFAX_PCI 0x54 #define PCI_SUB_ID_SEDLBAUER 0x01 - + #define SEDL_SPEED_CARD_WIN 1 #define SEDL_SPEED_STAR 2 #define SEDL_SPEED_FAX 3 @@ -231,7 +231,7 @@ * mode = 1 access with IRQ off * mode = 2 access with IRQ off and using last offset */ - + static u_char ReadISAR(struct IsdnCardState *cs, int mode, u_char offset) { @@ -287,7 +287,7 @@ causing us to just crash the kernel. bad. */ printk(KERN_WARNING "Sedlbauer: card not available!\n"); return; - } + } val = readreg(cs->hw.sedl.adr, cs->hw.sedl.hscx, HSCX_ISTA + 0x40); Start_HSCX: @@ -632,9 +632,10 @@ #endif /* CONFIG_PCI */ } - /* In case of the sedlbauer pcmcia card, this region is in use, - reserved for us by the card manager. So we do not check it - here, it would fail. */ + /* In case of the sedlbauer pcmcia card, this region is in use, + * reserved for us by the card manager. So we do not check it + * here, it would fail. + */ if (cs->hw.sedl.bus != SEDL_BUS_PCMCIA && check_region((cs->hw.sedl.cfg_reg), bytecnt)) { printk(KERN_WARNING @@ -659,22 +660,23 @@ cs->cardmsg = &Sedl_card_msg; /* - * testing ISA and PCMCIA Cards for IPAC, default is ISAC + * testing ISA and PCMCIA Cards for IPAC, default is ISAC * do not test for PCI card, because ports are different * and PCI card uses only IPAC (for the moment) */ if (cs->hw.sedl.bus != SEDL_BUS_PCI) { val = readreg(cs->hw.sedl.cfg_reg + SEDL_IPAC_ANY_ADR, - cs->hw.sedl.cfg_reg + SEDL_IPAC_ANY_IPAC, IPAC_ID); - if (val == 1) { - /* IPAC */ - cs->subtyp = SEDL_SPEED_WIN2_PC104; + cs->hw.sedl.cfg_reg + SEDL_IPAC_ANY_IPAC, IPAC_ID); + printk(KERN_DEBUG "Sedlbauer: testing IPAC version %x\n", val); + if ((val == 1) || (val == 2)) { + /* IPAC */ + cs->subtyp = SEDL_SPEED_WIN2_PC104; if (cs->hw.sedl.bus == SEDL_BUS_PCMCIA) { cs->subtyp = SEDL_SPEED_STAR2; } cs->hw.sedl.chip = SEDL_CHIP_IPAC; } else { - /* ISAC_HSCX oder ISAC_ISAR */ + /* ISAC_HSCX oder ISAC_ISAR */ if (cs->hw.sedl.chip == SEDL_CHIP_TEST) { cs->hw.sedl.chip = SEDL_CHIP_ISAC_HSCX; } @@ -691,25 +693,25 @@ if (cs->hw.sedl.chip == SEDL_CHIP_IPAC) { if (cs->hw.sedl.bus == SEDL_BUS_PCI) { cs->hw.sedl.adr = cs->hw.sedl.cfg_reg + SEDL_IPAC_PCI_ADR; - cs->hw.sedl.isac = cs->hw.sedl.cfg_reg + SEDL_IPAC_PCI_IPAC; - cs->hw.sedl.hscx = cs->hw.sedl.cfg_reg + SEDL_IPAC_PCI_IPAC; + cs->hw.sedl.isac = cs->hw.sedl.cfg_reg + SEDL_IPAC_PCI_IPAC; + cs->hw.sedl.hscx = cs->hw.sedl.cfg_reg + SEDL_IPAC_PCI_IPAC; } else { cs->hw.sedl.adr = cs->hw.sedl.cfg_reg + SEDL_IPAC_ANY_ADR; - cs->hw.sedl.isac = cs->hw.sedl.cfg_reg + SEDL_IPAC_ANY_IPAC; - cs->hw.sedl.hscx = cs->hw.sedl.cfg_reg + SEDL_IPAC_ANY_IPAC; + cs->hw.sedl.isac = cs->hw.sedl.cfg_reg + SEDL_IPAC_ANY_IPAC; + cs->hw.sedl.hscx = cs->hw.sedl.cfg_reg + SEDL_IPAC_ANY_IPAC; } - test_and_set_bit(HW_IPAC, &cs->HW_Flags); - cs->readisac = &ReadISAC_IPAC; - cs->writeisac = &WriteISAC_IPAC; - cs->readisacfifo = &ReadISACfifo_IPAC; - cs->writeisacfifo = &WriteISACfifo_IPAC; - cs->irq_func = &sedlbauer_interrupt_ipac; + test_and_set_bit(HW_IPAC, &cs->HW_Flags); + cs->readisac = &ReadISAC_IPAC; + cs->writeisac = &WriteISAC_IPAC; + cs->readisacfifo = &ReadISACfifo_IPAC; + cs->writeisacfifo = &WriteISACfifo_IPAC; + cs->irq_func = &sedlbauer_interrupt_ipac; val = readreg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_ID); - printk(KERN_INFO "Sedlbauer: IPAC version %x\n", val); + printk(KERN_INFO "Sedlbauer: IPAC version %x\n", val); reset_sedlbauer(cs); } else { - /* ISAC_HSCX oder ISAC_ISAR */ + /* ISAC_HSCX oder ISAC_ISAR */ cs->readisac = &ReadISAC; cs->writeisac = &WriteISAC; cs->readisacfifo = &ReadISACfifo; diff -u --recursive --new-file v2.4.6/linux/drivers/isdn/hysdn/boardergo.c linux/drivers/isdn/hysdn/boardergo.c --- v2.4.6/linux/drivers/isdn/hysdn/boardergo.c Sat May 19 17:54:14 2001 +++ linux/drivers/isdn/hysdn/boardergo.c Wed Jul 18 09:45:40 2001 @@ -1,4 +1,4 @@ -/* $Id: boardergo.c,v 1.5.6.4 2001/04/20 02:42:00 keil Exp $ +/* $Id: boardergo.c,v 1.5.6.5 2001/07/18 16:02:16 kai Exp $ * Linux driver for HYSDN cards, specific routines for ergo type boards. * @@ -35,6 +35,7 @@ #include <linux/kernel.h> #include <linux/ioport.h> #include <linux/interrupt.h> +#include <linux/vmalloc.h> #include "hysdn_defs.h" #include "boardergo.h" diff -u --recursive --new-file v2.4.6/linux/drivers/isdn/isdn_bsdcomp.c linux/drivers/isdn/isdn_bsdcomp.c --- v2.4.6/linux/drivers/isdn/isdn_bsdcomp.c Fri Mar 2 11:12:09 2001 +++ linux/drivers/isdn/isdn_bsdcomp.c Tue Jul 17 18:53:55 2001 @@ -76,6 +76,7 @@ #include <linux/skbuff.h> #include <linux/inet.h> #include <linux/ioctl.h> +#include <linux/vmalloc.h> #include <linux/ppp_defs.h> diff -u --recursive --new-file v2.4.6/linux/drivers/isdn/isdn_tty.c linux/drivers/isdn/isdn_tty.c --- v2.4.6/linux/drivers/isdn/isdn_tty.c Tue Jul 3 17:08:19 2001 +++ linux/drivers/isdn/isdn_tty.c Fri Jul 6 17:01:06 2001 @@ -1,4 +1,4 @@ -/* $Id: isdn_tty.c,v 1.94.6.2 2001/06/09 15:14:15 kai Exp $ +/* $Id: isdn_tty.c,v 1.94.6.3 2001/07/03 14:48:25 kai Exp $ * Linux ISDN subsystem, tty functions and AT-command emulator (linklevel). * @@ -66,7 +66,7 @@ static int si2bit[8] = {4, 1, 4, 4, 4, 4, 4, 4}; -char *isdn_tty_revision = "$Revision: 1.94.6.2 $"; +char *isdn_tty_revision = "$Revision: 1.94.6.3 $"; /* isdn_tty_try_read() is called from within isdn_tty_rcv_skb() @@ -1420,8 +1420,7 @@ status = info->lsr; restore_flags(flags); result = ((status & UART_LSR_TEMT) ? TIOCSER_TEMT : 0); - put_user(result, (uint *) value); - return 0; + return put_user(result, (uint *) value); } @@ -1444,8 +1443,7 @@ | ((status & UART_MSR_RI) ? TIOCM_RNG : 0) | ((status & UART_MSR_DSR) ? TIOCM_DSR : 0) | ((status & UART_MSR_CTS) ? TIOCM_CTS : 0); - put_user(result, (uint *) value); - return 0; + return put_user(result, (uint *) value); } static int @@ -1454,7 +1452,8 @@ uint arg; int pre_dtr; - get_user(arg, (uint *) value); + if (get_user(arg, (uint *) value)) + return -EFAULT; switch (cmd) { case TIOCMBIS: #ifdef ISDN_DEBUG_MODEM_IOCTL @@ -1522,7 +1521,6 @@ uint cmd, ulong arg) { modem_info *info = (modem_info *) tty->driver_data; - int error; int retval; if (isdn_tty_paranoia_check(info, tty->device, "isdn_tty_ioctl")) @@ -1552,19 +1550,13 @@ #ifdef ISDN_DEBUG_MODEM_IOCTL printk(KERN_DEBUG "ttyI%d ioctl TIOCGSOFTCAR\n", info->line); #endif - error = verify_area(VERIFY_WRITE, (void *) arg, sizeof(long)); - if (error) - return error; - put_user(C_CLOCAL(tty) ? 1 : 0, (ulong *) arg); - return 0; + return put_user(C_CLOCAL(tty) ? 1 : 0, (ulong *) arg); case TIOCSSOFTCAR: #ifdef ISDN_DEBUG_MODEM_IOCTL printk(KERN_DEBUG "ttyI%d ioctl TIOCSSOFTCAR\n", info->line); #endif - error = verify_area(VERIFY_READ, (void *) arg, sizeof(long)); - if (error) - return error; - get_user(arg, (ulong *) arg); + if (get_user(arg, (ulong *) arg)) + return -EFAULT; tty->termios->c_cflag = ((tty->termios->c_cflag & ~CLOCAL) | (arg ? CLOCAL : 0)); @@ -1573,26 +1565,16 @@ #ifdef ISDN_DEBUG_MODEM_IOCTL printk(KERN_DEBUG "ttyI%d ioctl TIOCMGET\n", info->line); #endif - error = verify_area(VERIFY_WRITE, (void *) arg, sizeof(uint)); - if (error) - return error; return isdn_tty_get_modem_info(info, (uint *) arg); case TIOCMBIS: case TIOCMBIC: case TIOCMSET: - error = verify_area(VERIFY_READ, (void *) arg, sizeof(uint)); - if (error) - return error; return isdn_tty_set_modem_info(info, cmd, (uint *) arg); case TIOCSERGETLSR: /* Get line status register */ #ifdef ISDN_DEBUG_MODEM_IOCTL printk(KERN_DEBUG "ttyI%d ioctl TIOCSERGETLSR\n", info->line); #endif - error = verify_area(VERIFY_WRITE, (void *) arg, sizeof(uint)); - if (error) - return error; - else - return isdn_tty_get_lsr_info(info, (uint *) arg); + return isdn_tty_get_lsr_info(info, (uint *) arg); default: #ifdef ISDN_DEBUG_MODEM_IOCTL printk(KERN_DEBUG "UNKNOWN ioctl 0x%08x on ttyi%d\n", cmd, info->line); diff -u --recursive --new-file v2.4.6/linux/drivers/isdn/tpam/tpam_main.c linux/drivers/isdn/tpam/tpam_main.c --- v2.4.6/linux/drivers/isdn/tpam/tpam_main.c Tue Jul 3 17:08:19 2001 +++ linux/drivers/isdn/tpam/tpam_main.c Wed Jul 18 09:45:40 2001 @@ -1,4 +1,4 @@ -/* $Id: tpam_main.c,v 1.1.2.1 2001/06/05 19:45:37 kai Exp $ +/* $Id: tpam_main.c,v 1.1.2.2 2001/07/11 12:22:59 kai Exp $ * * Turbo PAM ISDN driver for Linux. (Kernel Driver - main routines) * @@ -148,7 +148,8 @@ card->interface.features = ISDN_FEATURE_P_EURO | ISDN_FEATURE_L2_HDLC | - ISDN_FEATURE_L2_MODEM; + ISDN_FEATURE_L2_MODEM | + ISDN_FEATURE_L3_TRANS; card->interface.hl_hdrlen = 0; card->interface.command = tpam_command; card->interface.writebuf_skb = tpam_writebuf_skb; diff -u --recursive --new-file v2.4.6/linux/drivers/md/lvm.c linux/drivers/md/lvm.c --- v2.4.6/linux/drivers/md/lvm.c Sat Apr 21 10:37:16 2001 +++ linux/drivers/md/lvm.c Wed Jul 11 16:35:37 2001 @@ -988,6 +988,10 @@ case LV_BMAP: /* turn logical block into (dev_t, block). non privileged. */ + /* don't bmap a snapshot, since the mapping can change */ + if (lv_ptr->lv_access & LV_SNAPSHOT) + return -EPERM; + return lvm_user_bmap(inode, (struct lv_bmap *) arg); break; @@ -1075,8 +1079,8 @@ return -EFAULT; memset(&bh,0,sizeof bh); - bh.b_rsector = block; - bh.b_dev = bh.b_rdev = inode->i_dev; + bh.b_blocknr = block; + bh.b_dev = bh.b_rdev = inode->i_rdev; bh.b_size = lvm_get_blksize(bh.b_dev); if ((err=lvm_map(&bh, READ)) < 0) { printk("lvm map failed: %d\n", err); @@ -1084,7 +1088,8 @@ } return put_user(kdev_t_to_nr(bh.b_rdev), &user_result->lv_dev) || - put_user(bh.b_rsector, &user_result->lv_block) ? -EFAULT : 0; + put_user(bh.b_rsector/(bh.b_size>>9), &user_result->lv_block) ? + -EFAULT : 0; } diff -u --recursive --new-file v2.4.6/linux/drivers/md/raid5.c linux/drivers/md/raid5.c --- v2.4.6/linux/drivers/md/raid5.c Tue Jul 3 17:08:20 2001 +++ linux/drivers/md/raid5.c Mon Jul 9 18:21:41 2001 @@ -66,10 +66,11 @@ BUG(); if (atomic_read(&conf->active_stripes)==0) BUG(); - if (test_bit(STRIPE_DELAYED, &sh->state)) - list_add_tail(&sh->lru, &conf->delayed_list); - else if (test_bit(STRIPE_HANDLE, &sh->state)) { - list_add_tail(&sh->lru, &conf->handle_list); + if (test_bit(STRIPE_HANDLE, &sh->state)) { + if (test_bit(STRIPE_DELAYED, &sh->state)) + list_add_tail(&sh->lru, &conf->delayed_list); + else + list_add_tail(&sh->lru, &conf->handle_list); md_wakeup_thread(conf->thread); } else { if (test_and_clear_bit(STRIPE_PREREAD_ACTIVE, &sh->state)) { @@ -1167,10 +1168,9 @@ raid5_activate_delayed(conf); - if (conf->plugged) { - conf->plugged = 0; - md_wakeup_thread(conf->thread); - } + conf->plugged = 0; + md_wakeup_thread(conf->thread); + spin_unlock_irqrestore(&conf->device_lock, flags); } diff -u --recursive --new-file v2.4.6/linux/drivers/media/video/Config.in linux/drivers/media/video/Config.in --- v2.4.6/linux/drivers/media/video/Config.in Fri Feb 16 16:02:36 2001 +++ linux/drivers/media/video/Config.in Wed Jul 4 14:41:33 2001 @@ -21,6 +21,13 @@ dep_tristate ' QuickCam Colour Video For Linux (EXPERIMENTAL)' CONFIG_VIDEO_CQCAM $CONFIG_VIDEO_DEV $CONFIG_PARPORT fi fi +if [ "$CONFIG_PARPORT" != "n" ]; then + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + if [ "$CONFIG_PARPORT_1284" != "n" ]; then + dep_tristate ' Winbond W9966CF Webcam Video For Linux (EXPERIMENTAL)' CONFIG_VIDEO_W9966 $CONFIG_VIDEO_DEV $CONFIG_PARPORT + fi + fi +fi dep_tristate ' CPiA Video For Linux' CONFIG_VIDEO_CPIA $CONFIG_VIDEO_DEV if [ "$CONFIG_VIDEO_CPIA" != "n" ]; then if [ "$CONFIG_PARPORT_1284" != "n" ]; then @@ -39,7 +46,9 @@ dep_tristate ' Stradis 4:2:2 MPEG-2 video driver (EXPERIMENTAL)' CONFIG_VIDEO_STRADIS $CONFIG_VIDEO_DEV $CONFIG_PCI fi dep_tristate ' Zoran ZR36057/36060 Video For Linux' CONFIG_VIDEO_ZORAN $CONFIG_VIDEO_DEV $CONFIG_PCI $CONFIG_I2C -dep_tristate ' Include support for Iomega Buz' CONFIG_VIDEO_BUZ $CONFIG_VIDEO_ZORAN dep_tristate ' Zoran ZR36120/36125 Video For Linux' CONFIG_VIDEO_ZR36120 $CONFIG_VIDEO_DEV $CONFIG_PCI $CONFIG_I2C +if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + dep_tristate ' Sony Vaio Picturebook Motion Eye Video For Linux' CONFIG_VIDEO_MEYE $CONFIG_VIDEO_DEV $CONFIG_PCI $CONFIG_SONYPI +fi endmenu diff -u --recursive --new-file v2.4.6/linux/drivers/media/video/Makefile linux/drivers/media/video/Makefile --- v2.4.6/linux/drivers/media/video/Makefile Fri Dec 29 14:07:22 2000 +++ linux/drivers/media/video/Makefile Wed Jul 4 14:41:33 2001 @@ -38,12 +38,13 @@ tda7432.o tda9875.o tuner.o obj-$(CONFIG_SOUND_TVMIXER) += tvmixer.o -obj-$(CONFIG_VIDEO_ZR36120) += zoran.o i2c-old.o tuner.o saa7110.o saa7111.o saa7185.o +obj-$(CONFIG_VIDEO_ZR36120) += zoran.o obj-$(CONFIG_I2C_PARPORT) += i2c-parport.o i2c-old.o obj-$(CONFIG_VIDEO_SAA5249) += saa5249.o i2c-old.o obj-$(CONFIG_VIDEO_CQCAM) += c-qcam.o obj-$(CONFIG_VIDEO_BWQCAM) += bw-qcam.o -obj-$(CONFIG_VIDEO_ZORAN) += buz.o i2c-old.o saa7110.o saa7111.o saa7185.o +obj-$(CONFIG_VIDEO_W9966) += w9966.o +obj-$(CONFIG_VIDEO_ZORAN) += zr36067.o i2c-old.o saa7110.o saa7111.o saa7185.o adv7175.o bt819.o bt856.o obj-$(CONFIG_VIDEO_LML33) += bt856.o bt819.o obj-$(CONFIG_VIDEO_PMS) += pms.o obj-$(CONFIG_VIDEO_PLANB) += planb.o @@ -52,6 +53,7 @@ obj-$(CONFIG_VIDEO_CPIA) += cpia.o obj-$(CONFIG_VIDEO_CPIA_PP) += cpia_pp.o obj-$(CONFIG_VIDEO_CPIA_USB) += cpia_usb.o +obj-$(CONFIG_VIDEO_MEYE) += meye.o obj-$(CONFIG_TUNER_3036) += tuner-3036.o # Extract lists of the multi-part drivers. diff -u --recursive --new-file v2.4.6/linux/drivers/media/video/bttv-driver.c linux/drivers/media/video/bttv-driver.c --- v2.4.6/linux/drivers/media/video/bttv-driver.c Tue Jul 3 17:08:20 2001 +++ linux/drivers/media/video/bttv-driver.c Mon Jul 16 15:13:32 2001 @@ -1688,6 +1688,9 @@ vfree(vcp); return -EFAULT; } + } else if (vw.clipcount > 2048) { + up(&btv->lock); + return -EINVAL; } else if (vw.clipcount) { if((vcp=vmalloc(sizeof(struct video_clip)* (vw.clipcount))) == NULL) { diff -u --recursive --new-file v2.4.6/linux/drivers/media/video/buz.c linux/drivers/media/video/buz.c --- v2.4.6/linux/drivers/media/video/buz.c Tue Mar 6 19:44:35 2001 +++ linux/drivers/media/video/buz.c Wed Dec 31 16:00:00 1969 @@ -1,3463 +0,0 @@ -/* - buz - Iomega Buz driver version 1.0 - - Copyright (C) 1999 Rainer Johanni <Rainer@Johanni.de> - - based on - - buz.0.0.3 Copyright (C) 1998 Dave Perks <dperks@ibm.net> - - and - - bttv - Bt848 frame grabber driver - - Copyright (C) 1996,97,98 Ralph Metzler (rjkm@thp.uni-koeln.de) - & Marcus Metzler (mocm@thp.uni-koeln.de) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include <linux/module.h> -#include <linux/delay.h> -#include <linux/errno.h> -#include <linux/fs.h> -#include <linux/kernel.h> -#include <linux/major.h> -#include <linux/slab.h> -#include <linux/mm.h> -#include <linux/pci.h> -#include <linux/signal.h> -#include <asm/io.h> -#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/spinlock.h> -#include <linux/vmalloc.h> - -#include <linux/videodev.h> - -#include <linux/version.h> -#include <asm/uaccess.h> - -#include <linux/i2c-old.h> -#include "buz.h" -#include <linux/video_decoder.h> -#include <linux/video_encoder.h> - -#define IRQ_MASK ( ZR36057_ISR_GIRQ0 | /* ZR36057_ISR_GIRQ1 | ZR36057_ISR_CodRepIRQ | */ ZR36057_ISR_JPEGRepIRQ ) -#define GPIO_MASK 0xdf - -/* - - BUZ - - GPIO0 = 1, take board out of reset - GPIO1 = 1, take JPEG codec out of sleep mode - GPIO3 = 1, deassert FRAME# to 36060 - - - GIRQ0 signals a vertical sync of the video signal - GIRQ1 signals that ZR36060's DATERR# line is asserted. - - SAA7111A - - In their infinite wisdom, the Iomega engineers decided to - use the same input line for composite and S-Video Color, - although there are two entries not connected at all! - Through this ingenious strike, it is not possible to - keep two running video sources connected at the same time - to Composite and S-VHS input! - - mode 0 - N/C - mode 1 - S-Video Y - mode 2 - noise or something I don't know - mode 3 - Composite and S-Video C - mode 4 - N/C - mode 5 - S-Video (gain C independently selectable of gain Y) - mode 6 - N/C - mode 7 - S-Video (gain C adapted to gain Y) - */ - -#define MAJOR_VERSION 1 /* driver major version */ -#define MINOR_VERSION 0 /* driver minor version */ - -#define BUZ_NAME "Iomega BUZ V-1.0" /* name of the driver */ - -#define DEBUG(x) /* Debug driver */ -#define IDEBUG(x) /* Debug interrupt handler */ -#define IOCTL_DEBUG(x) - - -/* The parameters for this driver */ - -/* - The video mem address of the video card. - The driver has a little database for some videocards - to determine it from there. If your video card is not in there - you have either to give it to the driver as a parameter - or set in in a VIDIOCSFBUF ioctl - */ - -static unsigned long vidmem; /* Video memory base address (default 0) */ - -/* Special purposes only: */ - -static int triton; /* 0=no (default), 1=yes */ -static int natoma; /* 0=no (default), 1=yes */ - -/* - Number and size of grab buffers for Video 4 Linux - The vast majority of applications should not need more than 2, - the very popular BTTV driver actually does ONLY have 2. - Time sensitive applications might need more, the maximum - is VIDEO_MAX_FRAME (defined in <linux/videodev.h>). - - The size is set so that the maximum possible request - can be satisfied. Decrease it, if bigphys_area alloc'd - memory is low. If you don't have the bigphys_area patch, - set it to 128 KB. Will you allow only to grab small - images with V4L, but that's better than nothing. - - v4l_bufsize has to be given in KB ! - - */ - -static int v4l_nbufs = 2; -static int v4l_bufsize = 128; /* Everybody should be able to work with this setting */ - -/* - Default input and video norm at startup of the driver. - */ - -static int default_input; /* 0=Composite (default), 1=S-VHS */ -static int default_norm; /* 0=PAL (default), 1=NTSC */ - -MODULE_PARM(vidmem, "i"); -MODULE_PARM(triton, "i"); -MODULE_PARM(natoma, "i"); -MODULE_PARM(v4l_nbufs, "i"); -MODULE_PARM(v4l_bufsize, "i"); -MODULE_PARM(default_input, "i"); -MODULE_PARM(default_norm, "i"); - -/* Anybody who uses more than four? */ -#define BUZ_MAX 4 - -static int zoran_num; /* number of Buzs in use */ -static struct zoran zoran[BUZ_MAX]; - -/* forward references */ - -static void v4l_fbuffer_free(struct zoran *zr); -static void jpg_fbuffer_free(struct zoran *zr); -static void zoran_feed_stat_com(struct zoran *zr); - - - -/* - * Allocate the V4L grab buffers - * - * These have to be pysically contiguous. - * If v4l_bufsize <= KMALLOC_MAXSIZE we use kmalloc - */ - -static int v4l_fbuffer_alloc(struct zoran *zr) -{ - int i, off; - unsigned char *mem; - - for (i = 0; i < v4l_nbufs; i++) { - if (zr->v4l_gbuf[i].fbuffer) - printk(KERN_WARNING "%s: v4l_fbuffer_alloc: buffer %d allready allocated ?\n", zr->name, i); - - if (v4l_bufsize <= KMALLOC_MAXSIZE) { - /* Use kmalloc */ - - mem = (unsigned char *) kmalloc(v4l_bufsize, GFP_KERNEL); - if (mem == 0) { - printk(KERN_ERR "%s: kmalloc for V4L bufs failed\n", zr->name); - v4l_fbuffer_free(zr); - return -ENOBUFS; - } - zr->v4l_gbuf[i].fbuffer = mem; - zr->v4l_gbuf[i].fbuffer_phys = virt_to_phys(mem); - zr->v4l_gbuf[i].fbuffer_bus = virt_to_bus(mem); - for (off = 0; off < v4l_bufsize; off += PAGE_SIZE) - mem_map_reserve(virt_to_page(mem + off)); - DEBUG(printk(BUZ_INFO ": V4L frame %d mem 0x%x (bus: 0x%x=%d)\n", i, mem, virt_to_bus(mem), virt_to_bus(mem))); - } else { - v4l_fbuffer_free(zr); - return -ENOBUFS; - } - } - - return 0; -} - -/* free the V4L grab buffers */ -static void v4l_fbuffer_free(struct zoran *zr) -{ - int i, off; - unsigned char *mem; - - for (i = 0; i < v4l_nbufs; i++) { - if (!zr->v4l_gbuf[i].fbuffer) - continue; - - mem = zr->v4l_gbuf[i].fbuffer; - for (off = 0; off < v4l_bufsize; off += PAGE_SIZE) - mem_map_unreserve(virt_to_page(mem + off)); - kfree((void *) zr->v4l_gbuf[i].fbuffer); - zr->v4l_gbuf[i].fbuffer = NULL; - } -} - -/* - * Allocate the MJPEG grab buffers. - * - * If the requested buffer size is smaller than KMALLOC_MAXSIZE, - * kmalloc is used to request a physically contiguous area, - * else we allocate the memory in framgents with get_free_page. - * - * If a Natoma chipset is present and this is a revision 1 zr36057, - * each MJPEG buffer needs to be physically contiguous. - * (RJ: This statement is from Dave Perks' original driver, - * I could never check it because I have a zr36067) - * The driver cares about this because it reduces the buffer - * size to KMALLOC_MAXSIZE in that case (which forces contiguous allocation). - * - * RJ: The contents grab buffers needs never be accessed in the driver. - * Therefore there is no need to allocate them with vmalloc in order - * to get a contiguous virtual memory space. - * I don't understand why many other drivers first allocate them with - * vmalloc (which uses internally also get_free_page, but delivers you - * virtual addresses) and then again have to make a lot of efforts - * to get the physical address. - * - */ - -static int jpg_fbuffer_alloc(struct zoran *zr) -{ - int i, j, off, alloc_contig; - unsigned long mem; - - /* Decide if we should alloc contiguous or fragmented memory */ - /* This has to be identical in jpg_fbuffer_alloc and jpg_fbuffer_free */ - - alloc_contig = (zr->jpg_bufsize < KMALLOC_MAXSIZE); - - for (i = 0; i < zr->jpg_nbufs; i++) { - if (zr->jpg_gbuf[i].frag_tab) - printk(KERN_WARNING "%s: jpg_fbuffer_alloc: buffer %d allready allocated ???\n", zr->name, i); - - /* Allocate fragment table for this buffer */ - - mem = get_free_page(GFP_KERNEL); - if (mem == 0) { - printk(KERN_ERR "%s: jpg_fbuffer_alloc: get_free_page (frag_tab) failed for buffer %d\n", zr->name, i); - jpg_fbuffer_free(zr); - return -ENOBUFS; - } - memset((void *) mem, 0, PAGE_SIZE); - zr->jpg_gbuf[i].frag_tab = (u32 *) mem; - zr->jpg_gbuf[i].frag_tab_bus = virt_to_bus((void *) mem); - - if (alloc_contig) { - mem = (unsigned long) kmalloc(zr->jpg_bufsize, GFP_KERNEL); - if (mem == 0) { - jpg_fbuffer_free(zr); - return -ENOBUFS; - } - zr->jpg_gbuf[i].frag_tab[0] = virt_to_bus((void *) mem); - zr->jpg_gbuf[i].frag_tab[1] = ((zr->jpg_bufsize / 4) << 1) | 1; - for (off = 0; off < zr->jpg_bufsize; off += PAGE_SIZE) - mem_map_reserve(virt_to_page(mem + off)); - } else { - /* jpg_bufsize is alreay page aligned */ - for (j = 0; j < zr->jpg_bufsize / PAGE_SIZE; j++) { - mem = get_free_page(GFP_KERNEL); - if (mem == 0) { - jpg_fbuffer_free(zr); - return -ENOBUFS; - } - zr->jpg_gbuf[i].frag_tab[2 * j] = virt_to_bus((void *) mem); - zr->jpg_gbuf[i].frag_tab[2 * j + 1] = (PAGE_SIZE / 4) << 1; - mem_map_reserve(virt_to_page(mem)); - } - - zr->jpg_gbuf[i].frag_tab[2 * j - 1] |= 1; - } - } - - DEBUG(printk("jpg_fbuffer_alloc: %d KB allocated\n", - (zr->jpg_nbufs * zr->jpg_bufsize) >> 10)); - zr->jpg_buffers_allocated = 1; - return 0; -} - -/* free the MJPEG grab buffers */ -static void jpg_fbuffer_free(struct zoran *zr) -{ - int i, j, off, alloc_contig; - unsigned char *mem; - - /* Decide if we should alloc contiguous or fragmented memory */ - /* This has to be identical in jpg_fbuffer_alloc and jpg_fbuffer_free */ - - alloc_contig = (zr->jpg_bufsize < KMALLOC_MAXSIZE); - - for (i = 0; i < zr->jpg_nbufs; i++) { - if (!zr->jpg_gbuf[i].frag_tab) - continue; - - if (alloc_contig) { - if (zr->jpg_gbuf[i].frag_tab[0]) { - mem = (unsigned char *) bus_to_virt(zr->jpg_gbuf[i].frag_tab[0]); - for (off = 0; off < zr->jpg_bufsize; off += PAGE_SIZE) - mem_map_unreserve(virt_to_page(mem + off)); - kfree((void *) mem); - zr->jpg_gbuf[i].frag_tab[0] = 0; - zr->jpg_gbuf[i].frag_tab[1] = 0; - } - } else { - for (j = 0; j < zr->jpg_bufsize / PAGE_SIZE; j++) { - if (!zr->jpg_gbuf[i].frag_tab[2 * j]) - break; - mem_map_unreserve(virt_to_page(bus_to_virt(zr->jpg_gbuf[i].frag_tab[2 * j]))); - free_page((unsigned long) bus_to_virt(zr->jpg_gbuf[i].frag_tab[2 * j])); - zr->jpg_gbuf[i].frag_tab[2 * j] = 0; - zr->jpg_gbuf[i].frag_tab[2 * j + 1] = 0; - } - } - - free_page((unsigned long) zr->jpg_gbuf[i].frag_tab); - zr->jpg_gbuf[i].frag_tab = NULL; - } - zr->jpg_buffers_allocated = 0; -} - - -/* ----------------------------------------------------------------------- */ - -/* I2C functions */ - -#define I2C_DELAY 10 - - -/* software I2C functions */ - -static void i2c_setlines(struct i2c_bus *bus, int ctrl, int data) -{ - struct zoran *zr = (struct zoran *) bus->data; - btwrite((data << 1) | ctrl, ZR36057_I2CBR); - btread(ZR36057_I2CBR); - udelay(I2C_DELAY); -} - -static int i2c_getdataline(struct i2c_bus *bus) -{ - struct zoran *zr = (struct zoran *) bus->data; - return (btread(ZR36057_I2CBR) >> 1) & 1; -} - -static void attach_inform(struct i2c_bus *bus, int id) -{ - DEBUG(struct zoran *zr = (struct zoran *) bus->data); - DEBUG(printk(BUZ_DEBUG "-%u: i2c attach %02x\n", zr->id, id)); -} - -static void detach_inform(struct i2c_bus *bus, int id) -{ - DEBUG(struct zoran *zr = (struct zoran *) bus->data); - DEBUG(printk(BUZ_DEBUG "-%u: i2c detach %02x\n", zr->id, id)); -} - -static struct i2c_bus zoran_i2c_bus_template = { - name: "zr36057", - id: I2C_BUSID_BT848, - bus_lock: SPIN_LOCK_UNLOCKED, - - attach_inform: attach_inform, - detach_inform: detach_inform, - - i2c_setlines: i2c_setlines, - i2c_getdataline: i2c_getdataline, -}; - - -/* ----------------------------------------------------------------------- */ - -static void GPIO(struct zoran *zr, unsigned bit, unsigned value) -{ - u32 reg; - u32 mask; - - mask = 1 << (24 + bit); - reg = btread(ZR36057_GPPGCR1) & ~mask; - if (value) { - reg |= mask; - } - btwrite(reg, ZR36057_GPPGCR1); - /* Stop any PCI posting on the GPIO bus */ - btread(ZR36057_I2CBR); -} - - -/* - * Set the registers for the size we have specified. Don't bother - * trying to understand this without the ZR36057 manual in front of - * you [AC]. - * - * PS: The manual is free for download in .pdf format from - * www.zoran.com - nicely done those folks. - */ - -struct tvnorm { - u16 Wt, Wa, Ht, Ha, HStart, VStart; -}; - -static struct tvnorm tvnorms[] = -{ - /* PAL-BDGHI */ - {864, 720, 625, 576, 31, 16}, - /* NTSC */ - {858, 720, 525, 480, 21, 8}, -}; -#define TVNORMS (sizeof(tvnorms) / sizeof(tvnorm)) - -static int format2bpp(int format) -{ - int bpp; - - /* Determine the number of bytes per pixel for the video format requested */ - - switch (format) { - - case VIDEO_PALETTE_YUV422: - bpp = 2; - break; - - case VIDEO_PALETTE_RGB555: - bpp = 2; - break; - - case VIDEO_PALETTE_RGB565: - bpp = 2; - break; - - case VIDEO_PALETTE_RGB24: - bpp = 3; - break; - - case VIDEO_PALETTE_RGB32: - bpp = 4; - break; - - default: - bpp = 0; - } - - return bpp; -} - -/* - * set geometry - */ -static void zr36057_set_vfe(struct zoran *zr, int video_width, int video_height, - unsigned int video_format) -{ - struct tvnorm *tvn; - unsigned HStart, HEnd, VStart, VEnd; - unsigned DispMode; - unsigned VidWinWid, VidWinHt; - unsigned hcrop1, hcrop2, vcrop1, vcrop2; - unsigned Wa, We, Ha, He; - unsigned X, Y, HorDcm, VerDcm; - u32 reg; - unsigned mask_line_size; - - if (zr->params.norm < 0 || zr->params.norm > 1) { - printk(KERN_ERR "%s: set_vfe: video_norm = %d not valid\n", zr->name, zr->params.norm); - return; - } - if (video_width < BUZ_MIN_WIDTH || video_height < BUZ_MIN_HEIGHT) { - printk(KERN_ERR "%s: set_vfe: w=%d h=%d not valid\n", zr->name, video_width, video_height); - return; - } - tvn = &tvnorms[zr->params.norm]; - - Wa = tvn->Wa; - Ha = tvn->Ha; - - /* if window has more than half of active height, - switch on interlacing - we want the full information */ - - zr->video_interlace = (video_height > Ha / 2); - -/**** zr36057 ****/ - - /* horizontal */ - VidWinWid = video_width; - X = (VidWinWid * 64 + tvn->Wa - 1) / tvn->Wa; - We = (VidWinWid * 64) / X; - HorDcm = 64 - X; - hcrop1 = 2 * ((tvn->Wa - We) / 4); - hcrop2 = tvn->Wa - We - hcrop1; - HStart = tvn->HStart | 1; - HEnd = HStart + tvn->Wa - 1; - HStart += hcrop1; - HEnd -= hcrop2; - reg = ((HStart & ZR36057_VFEHCR_Hmask) << ZR36057_VFEHCR_HStart) - | ((HEnd & ZR36057_VFEHCR_Hmask) << ZR36057_VFEHCR_HEnd); - reg |= ZR36057_VFEHCR_HSPol; - btwrite(reg, ZR36057_VFEHCR); - - /* Vertical */ - DispMode = !zr->video_interlace; - VidWinHt = DispMode ? video_height : video_height / 2; - Y = (VidWinHt * 64 * 2 + tvn->Ha - 1) / tvn->Ha; - He = (VidWinHt * 64) / Y; - VerDcm = 64 - Y; - vcrop1 = (tvn->Ha / 2 - He) / 2; - vcrop2 = tvn->Ha / 2 - He - vcrop1; - VStart = tvn->VStart; - VEnd = VStart + tvn->Ha / 2 - 1; - VStart += vcrop1; - VEnd -= vcrop2; - reg = ((VStart & ZR36057_VFEVCR_Vmask) << ZR36057_VFEVCR_VStart) - | ((VEnd & ZR36057_VFEVCR_Vmask) << ZR36057_VFEVCR_VEnd); - reg |= ZR36057_VFEVCR_VSPol; - btwrite(reg, ZR36057_VFEVCR); - - /* scaler and pixel format */ - reg = 0 // ZR36057_VFESPFR_ExtFl /* Trying to live without ExtFl */ - | (HorDcm << ZR36057_VFESPFR_HorDcm) - | (VerDcm << ZR36057_VFESPFR_VerDcm) - | (DispMode << ZR36057_VFESPFR_DispMode) - | ZR36057_VFESPFR_LittleEndian; - /* RJ: I don't know, why the following has to be the opposite - of the corresponding ZR36060 setting, but only this way - we get the correct colors when uncompressing to the screen */ - reg |= ZR36057_VFESPFR_VCLKPol; - /* RJ: Don't know if that is needed for NTSC also */ - reg |= ZR36057_VFESPFR_TopField; - switch (video_format) { - - case VIDEO_PALETTE_YUV422: - reg |= ZR36057_VFESPFR_YUV422; - break; - - case VIDEO_PALETTE_RGB555: - reg |= ZR36057_VFESPFR_RGB555 | ZR36057_VFESPFR_ErrDif; - break; - - case VIDEO_PALETTE_RGB565: - reg |= ZR36057_VFESPFR_RGB565 | ZR36057_VFESPFR_ErrDif; - break; - - case VIDEO_PALETTE_RGB24: - reg |= ZR36057_VFESPFR_RGB888 | ZR36057_VFESPFR_Pack24; - break; - - case VIDEO_PALETTE_RGB32: - reg |= ZR36057_VFESPFR_RGB888; - break; - - default: - printk(KERN_INFO "%s: Unknown color_fmt=%x\n", zr->name, video_format); - return; - - } - if (HorDcm >= 48) { - reg |= 3 << ZR36057_VFESPFR_HFilter; /* 5 tap filter */ - } else if (HorDcm >= 32) { - reg |= 2 << ZR36057_VFESPFR_HFilter; /* 4 tap filter */ - } else if (HorDcm >= 16) { - reg |= 1 << ZR36057_VFESPFR_HFilter; /* 3 tap filter */ - } - btwrite(reg, ZR36057_VFESPFR); - - /* display configuration */ - - reg = (16 << ZR36057_VDCR_MinPix) - | (VidWinHt << ZR36057_VDCR_VidWinHt) - | (VidWinWid << ZR36057_VDCR_VidWinWid); - if (triton) - reg &= ~ZR36057_VDCR_Triton; - else - reg |= ZR36057_VDCR_Triton; - btwrite(reg, ZR36057_VDCR); - - /* Write overlay clipping mask data, but don't enable overlay clipping */ - /* RJ: since this makes only sense on the screen, we use - zr->window.width instead of video_width */ - - mask_line_size = (BUZ_MAX_WIDTH + 31) / 32; - reg = virt_to_bus(zr->overlay_mask); - btwrite(reg, ZR36057_MMTR); - reg = virt_to_bus(zr->overlay_mask + mask_line_size); - btwrite(reg, ZR36057_MMBR); - reg = mask_line_size - (zr->window.width + 31) / 32; - if (DispMode == 0) - reg += mask_line_size; - reg <<= ZR36057_OCR_MaskStride; - btwrite(reg, ZR36057_OCR); - -} - -/* - * Switch overlay on or off - */ - -static void zr36057_overlay(struct zoran *zr, int on) -{ - int fmt, bpp; - u32 reg; - - if (on) { - /* do the necessary settings ... */ - - btand(~ZR36057_VDCR_VidEn, ZR36057_VDCR); /* switch it off first */ - - switch (zr->buffer.depth) { - case 15: - fmt = VIDEO_PALETTE_RGB555; - bpp = 2; - break; - case 16: - fmt = VIDEO_PALETTE_RGB565; - bpp = 2; - break; - case 24: - fmt = VIDEO_PALETTE_RGB24; - bpp = 3; - break; - case 32: - fmt = VIDEO_PALETTE_RGB32; - bpp = 4; - break; - default: - fmt = 0; - bpp = 0; - } - - zr36057_set_vfe(zr, zr->window.width, zr->window.height, fmt); - - /* Start and length of each line MUST be 4-byte aligned. - This should be allready checked before the call to this routine. - All error messages are internal driver checking only! */ - - /* video display top and bottom registers */ - - reg = (u32) zr->buffer.base - + zr->window.x * bpp - + zr->window.y * zr->buffer.bytesperline; - btwrite(reg, ZR36057_VDTR); - if (reg & 3) - printk(KERN_ERR "%s: zr36057_overlay: video_address not aligned\n", zr->name); - if (zr->video_interlace) - reg += zr->buffer.bytesperline; - btwrite(reg, ZR36057_VDBR); - - /* video stride, status, and frame grab register */ - - reg = zr->buffer.bytesperline - zr->window.width * bpp; - if (zr->video_interlace) - reg += zr->buffer.bytesperline; - if (reg & 3) - printk(KERN_ERR "%s: zr36057_overlay: video_stride not aligned\n", zr->name); - reg = (reg << ZR36057_VSSFGR_DispStride); - reg |= ZR36057_VSSFGR_VidOvf; /* clear overflow status */ - btwrite(reg, ZR36057_VSSFGR); - - /* Set overlay clipping */ - - if (zr->window.clipcount) - btor(ZR36057_OCR_OvlEnable, ZR36057_OCR); - - /* ... and switch it on */ - - btor(ZR36057_VDCR_VidEn, ZR36057_VDCR); - } else { - /* Switch it off */ - - btand(~ZR36057_VDCR_VidEn, ZR36057_VDCR); - } -} - -/* - * The overlay mask has one bit for each pixel on a scan line, - * and the maximum window size is BUZ_MAX_WIDTH * BUZ_MAX_HEIGHT pixels. - */ -static void write_overlay_mask(struct zoran *zr, struct video_clip *vp, int count) -{ - unsigned mask_line_size = (BUZ_MAX_WIDTH + 31) / 32; - u32 *mask; - int x, y, width, height; - unsigned i, j, k; - u32 reg; - - /* fill mask with one bits */ - memset(zr->overlay_mask, ~0, mask_line_size * 4 * BUZ_MAX_HEIGHT); - reg = 0; - - for (i = 0; i < count; ++i) { - /* pick up local copy of clip */ - x = vp[i].x; - y = vp[i].y; - width = vp[i].width; - height = vp[i].height; - - /* trim clips that extend beyond the window */ - if (x < 0) { - width += x; - x = 0; - } - if (y < 0) { - height += y; - y = 0; - } - if (x + width > zr->window.width) { - width = zr->window.width - x; - } - if (y + height > zr->window.height) { - height = zr->window.height - y; - } - /* ignore degenerate clips */ - if (height <= 0) { - continue; - } - if (width <= 0) { - continue; - } - /* apply clip for each scan line */ - for (j = 0; j < height; ++j) { - /* reset bit for each pixel */ - /* this can be optimized later if need be */ - mask = zr->overlay_mask + (y + j) * mask_line_size; - for (k = 0; k < width; ++k) { - mask[(x + k) / 32] &= ~((u32) 1 << (x + k) % 32); - } - } - } -} - -/* Enable/Disable uncompressed memory grabbing of the 36057 */ - -static void zr36057_set_memgrab(struct zoran *zr, int mode) -{ - if (mode) { - if (btread(ZR36057_VSSFGR) & (ZR36057_VSSFGR_SnapShot | ZR36057_VSSFGR_FrameGrab)) - printk(KERN_WARNING "%s: zr36057_set_memgrab_on with SnapShot or FrameGrab on ???\n", zr->name); - - /* switch on VSync interrupts */ - - btwrite(IRQ_MASK, ZR36057_ISR); // Clear Interrupts - - btor(ZR36057_ICR_GIRQ0, ZR36057_ICR); - - /* enable SnapShot */ - - btor(ZR36057_VSSFGR_SnapShot, ZR36057_VSSFGR); - - /* Set zr36057 video front end and enable video */ - -#ifdef XAWTV_HACK - zr36057_set_vfe(zr, zr->gwidth > 720 ? 720 : zr->gwidth, zr->gheight, zr->gformat); -#else - zr36057_set_vfe(zr, zr->gwidth, zr->gheight, zr->gformat); -#endif - - zr->v4l_memgrab_active = 1; - } else { - zr->v4l_memgrab_active = 0; - - /* switch off VSync interrupts */ - - btand(~ZR36057_ICR_GIRQ0, ZR36057_ICR); - - /* reenable grabbing to screen if it was running */ - - if (zr->v4l_overlay_active) { - zr36057_overlay(zr, 1); - } else { - btand(~ZR36057_VDCR_VidEn, ZR36057_VDCR); - btand(~ZR36057_VSSFGR_SnapShot, ZR36057_VSSFGR); - } - } -} - -static int wait_grab_pending(struct zoran *zr) -{ - unsigned long flags; - - /* wait until all pending grabs are finished */ - - if (!zr->v4l_memgrab_active) - return 0; - - while (zr->v4l_pend_tail != zr->v4l_pend_head) { - interruptible_sleep_on(&zr->v4l_capq); - if (signal_pending(current)) - return -ERESTARTSYS; - } - - spin_lock_irqsave(&zr->lock, flags); - zr36057_set_memgrab(zr, 0); - spin_unlock_irqrestore(&zr->lock, flags); - - return 0; -} - -/* - * V4L Buffer grabbing - */ - -static int v4l_grab(struct zoran *zr, struct video_mmap *mp) -{ - unsigned long flags; - int res, bpp; - - /* - * There is a long list of limitations to what is allowed to be grabbed - * We don't output error messages her, since some programs (e.g. xawtv) - * just try several settings to find out what is valid or not. - */ - - /* No grabbing outside the buffer range! */ - - if (mp->frame >= v4l_nbufs || mp->frame < 0) - return -EINVAL; - - /* Check size and format of the grab wanted */ - - if (mp->height < BUZ_MIN_HEIGHT || mp->width < BUZ_MIN_WIDTH) - return -EINVAL; - if (mp->height > BUZ_MAX_HEIGHT || mp->width > BUZ_MAX_WIDTH) - return -EINVAL; - - bpp = format2bpp(mp->format); - if (bpp == 0) - return -EINVAL; - - /* Check against available buffer size */ - - if (mp->height * mp->width * bpp > v4l_bufsize) - return -EINVAL; - - /* The video front end needs 4-byte alinged line sizes */ - - if ((bpp == 2 && (mp->width & 1)) || (bpp == 3 && (mp->width & 3))) - return -EINVAL; - - /* - * To minimize the time spent in the IRQ routine, we avoid setting up - * the video front end there. - * If this grab has different parameters from a running streaming capture - * we stop the streaming capture and start it over again. - */ - - if (zr->v4l_memgrab_active && - (zr->gwidth != mp->width || zr->gheight != mp->height || zr->gformat != mp->format)) { - res = wait_grab_pending(zr); - if (res) - return res; - } - zr->gwidth = mp->width; - zr->gheight = mp->height; - zr->gformat = mp->format; - zr->gbpl = bpp * zr->gwidth; - - - spin_lock_irqsave(&zr->lock, flags); - - /* make sure a grab isn't going on currently with this buffer */ - - switch (zr->v4l_gbuf[mp->frame].state) { - - default: - case BUZ_STATE_PEND: - res = -EBUSY; /* what are you doing? */ - break; - - case BUZ_STATE_USER: - case BUZ_STATE_DONE: - /* since there is at least one unused buffer there's room for at least one more pend[] entry */ - zr->v4l_pend[zr->v4l_pend_head++ & V4L_MASK_FRAME] = mp->frame; - zr->v4l_gbuf[mp->frame].state = BUZ_STATE_PEND; - res = 0; - break; - - } - - /* put the 36057 into frame grabbing mode */ - - if (!res && !zr->v4l_memgrab_active) - zr36057_set_memgrab(zr, 1); - - spin_unlock_irqrestore(&zr->lock, flags); - - return res; -} - -/* - * Sync on a V4L buffer - */ - -static int v4l_sync(struct zoran *zr, int frame) -{ - unsigned long flags; - - - /* check passed-in frame number */ - if (frame >= v4l_nbufs || frame < 0) { - printk(KERN_ERR "%s: v4l_sync: frame %d is invalid\n", zr->name, frame); - return -EINVAL; - } - /* Check if is buffer was queued at all */ - - if (zr->v4l_gbuf[frame].state == BUZ_STATE_USER) { -// printk(KERN_ERR "%s: v4l_sync: Trying to sync on a buffer which was not queued?\n", zr->name); - return -EINVAL; - } - /* wait on this buffer to get ready */ - - while (zr->v4l_gbuf[frame].state == BUZ_STATE_PEND) { - interruptible_sleep_on(&zr->v4l_capq); - if (signal_pending(current)) - return -ERESTARTSYS; - } - - /* buffer should now be in BUZ_STATE_DONE */ - - if (zr->v4l_gbuf[frame].state != BUZ_STATE_DONE) - printk(KERN_ERR "%s: v4l_sync - internal error\n", zr->name); - - /* Check if streaming capture has finished */ - - spin_lock_irqsave(&zr->lock, flags); - - if (zr->v4l_pend_tail == zr->v4l_pend_head) - zr36057_set_memgrab(zr, 0); - - spin_unlock_irqrestore(&zr->lock, flags); - - return 0; -} -/***************************************************************************** - * * - * Set up the Buz-specific MJPEG part * - * * - *****************************************************************************/ - -/* - * Wait til post office is no longer busy - */ - -static int post_office_wait(struct zoran *zr) -{ - u32 por; - u32 ct=0; - - while (((por = btread(ZR36057_POR)) & (ZR36057_POR_POPen | ZR36057_POR_POTime)) == ZR36057_POR_POPen) { - ct++; - if(ct>100000) - { - printk(KERN_ERR "%s: timeout on post office.\n", zr->name); - return -1; - } - /* wait for something to happen */ - } - if ((por & ZR36057_POR_POPen) != 0) { - printk(KERN_WARNING "%s: pop pending %08x\n", zr->name, por); - return -1; - } - if ((por & (ZR36057_POR_POTime | ZR36057_POR_POPen)) != 0) { - printk(KERN_WARNING "%s: pop timeout %08x\n", zr->name, por); - return -1; - } - return 0; -} - -static int post_office_write(struct zoran *zr, unsigned guest, unsigned reg, unsigned value) -{ - u32 por; - - post_office_wait(zr); - por = ZR36057_POR_PODir | ZR36057_POR_POTime | ((guest & 7) << 20) | ((reg & 7) << 16) | (value & 0xFF); - btwrite(por, ZR36057_POR); - return post_office_wait(zr); -} - -static int post_office_read(struct zoran *zr, unsigned guest, unsigned reg) -{ - u32 por; - - post_office_wait(zr); - por = ZR36057_POR_POTime | ((guest & 7) << 20) | ((reg & 7) << 16); - btwrite(por, ZR36057_POR); - if (post_office_wait(zr) < 0) { - return -1; - } - return btread(ZR36057_POR) & 0xFF; -} - -static int zr36060_write_8(struct zoran *zr, unsigned reg, unsigned val) -{ - if (post_office_wait(zr) - || post_office_write(zr, 0, 1, reg >> 8) - || post_office_write(zr, 0, 2, reg)) { - return -1; - } - return post_office_write(zr, 0, 3, val); -} - -static int zr36060_write_16(struct zoran *zr, unsigned reg, unsigned val) -{ - if (zr36060_write_8(zr, reg + 0, val >> 8)) { - return -1; - } - return zr36060_write_8(zr, reg + 1, val >> 0); -} - -static int zr36060_write_24(struct zoran *zr, unsigned reg, unsigned val) -{ - if (zr36060_write_8(zr, reg + 0, val >> 16)) { - return -1; - } - return zr36060_write_16(zr, reg + 1, val >> 0); -} - -static int zr36060_write_32(struct zoran *zr, unsigned reg, unsigned val) -{ - if (zr36060_write_16(zr, reg + 0, val >> 16)) { - return -1; - } - return zr36060_write_16(zr, reg + 2, val >> 0); -} - -static u32 zr36060_read_8(struct zoran *zr, unsigned reg) -{ - if (post_office_wait(zr) - || post_office_write(zr, 0, 1, reg >> 8) - || post_office_write(zr, 0, 2, reg)) { - return -1; - } - return post_office_read(zr, 0, 3) & 0xFF; -} - -static int zr36060_reset(struct zoran *zr) -{ - return post_office_write(zr, 3, 0, 0); -} - -static void zr36060_sleep(struct zoran *zr, int sleep) -{ - GPIO(zr, 1, !sleep); -} - - -static void zr36060_set_jpg(struct zoran *zr, enum zoran_codec_mode mode) -{ - struct tvnorm *tvn; - u32 reg; - int size; - - reg = (1 << 0) /* CodeMstr */ - |(0 << 2) /* CFIS=0 */ - |(0 << 6) /* Endian=0 */ - |(0 << 7); /* Code16=0 */ - zr36060_write_8(zr, 0x002, reg); - - switch (mode) { - - case BUZ_MODE_MOTION_DECOMPRESS: - case BUZ_MODE_STILL_DECOMPRESS: - reg = 0x00; /* Codec mode = decompression */ - break; - - case BUZ_MODE_MOTION_COMPRESS: - case BUZ_MODE_STILL_COMPRESS: - default: - reg = 0xa4; /* Codec mode = compression with variable scale factor */ - break; - - } - zr36060_write_8(zr, 0x003, reg); - - reg = 0x00; /* reserved, mbz */ - zr36060_write_8(zr, 0x004, reg); - - reg = 0xff; /* 510 bits/block */ - zr36060_write_8(zr, 0x005, reg); - - /* JPEG markers */ - reg = (zr->params.jpeg_markers) & 0x38; /* DRI, DQT, DHT */ - if (zr->params.COM_len) - reg |= JPEG_MARKER_COM; - if (zr->params.APP_len) - reg |= JPEG_MARKER_APP; - zr36060_write_8(zr, 0x006, reg); - - reg = (0 << 3) /* DATERR=0 */ - |(0 << 2) /* END=0 */ - |(0 << 1) /* EOI=0 */ - |(0 << 0); /* EOAV=0 */ - zr36060_write_8(zr, 0x007, reg); - - /* code volume */ - - /* Target field size in pixels: */ - tvn = &tvnorms[zr->params.norm]; - size = (tvn->Ha / 2) * (tvn->Wa) / (zr->params.HorDcm) / (zr->params.VerDcm); - - /* Target compressed field size in bits: */ - size = size * 16; /* uncompressed size in bits */ - size = size * zr->params.quality / 400; /* quality = 100 is a compression ratio 1:4 */ - - /* Lower limit (arbitrary, 1 KB) */ - if (size < 8192) - size = 8192; - - /* Upper limit: 7/8 of the code buffers */ - if (size * zr->params.field_per_buff > zr->jpg_bufsize * 7) - size = zr->jpg_bufsize * 7 / zr->params.field_per_buff; - - reg = size; - zr36060_write_32(zr, 0x009, reg); - - /* how do we set initial SF as a function of quality parameter? */ - reg = 0x0100; /* SF=1.0 */ - zr36060_write_16(zr, 0x011, reg); - - reg = 0x00ffffff; /* AF=max */ - zr36060_write_24(zr, 0x013, reg); - - reg = 0x0000; /* test */ - zr36060_write_16(zr, 0x024, reg); -} - -static void zr36060_set_video(struct zoran *zr, enum zoran_codec_mode mode) -{ - struct tvnorm *tvn; - u32 reg; - - reg = (0 << 7) /* Video8=0 */ - |(0 << 6) /* Range=0 */ - |(0 << 3) /* FlDet=0 */ - |(1 << 2) /* FlVedge=1 */ - |(0 << 1) /* FlExt=0 */ - |(0 << 0); /* SyncMstr=0 */ - - /* According to ZR36067 documentation, FlDet should correspond - to the odd_even flag of the ZR36067 */ - if (zr->params.odd_even) - reg |= (1 << 3); - - if (mode != BUZ_MODE_STILL_DECOMPRESS) { - /* limit pixels to range 16..235 as per CCIR-601 */ - reg |= (1 << 6); /* Range=1 */ - } - zr36060_write_8(zr, 0x030, reg); - - reg = (0 << 7) /* VCLKPol=0 */ - |(0 << 6) /* PValPol=0 */ - |(1 << 5) /* PoePol=1 */ - |(0 << 4) /* SImgPol=0 */ - |(0 << 3) /* BLPol=0 */ - |(0 << 2) /* FlPol=0 */ - |(0 << 1) /* HSPol=0, sync on falling edge */ - |(1 << 0); /* VSPol=1 */ - zr36060_write_8(zr, 0x031, reg); - - switch (zr->params.HorDcm) { - default: - case 1: - reg = (0 << 0); - break; /* HScale = 0 */ - - case 2: - reg = (1 << 0); - break; /* HScale = 1 */ - - case 4: - reg = (2 << 0); - break; /* HScale = 2 */ - } - if (zr->params.VerDcm == 2) - reg |= (1 << 2); - zr36060_write_8(zr, 0x032, reg); - - reg = 0x80; /* BackY */ - zr36060_write_8(zr, 0x033, reg); - - reg = 0xe0; /* BackU */ - zr36060_write_8(zr, 0x034, reg); - - reg = 0xe0; /* BackV */ - zr36060_write_8(zr, 0x035, reg); - - /* sync generator */ - - tvn = &tvnorms[zr->params.norm]; - - reg = tvn->Ht - 1; /* Vtotal */ - zr36060_write_16(zr, 0x036, reg); - - reg = tvn->Wt - 1; /* Htotal */ - zr36060_write_16(zr, 0x038, reg); - - reg = 6 - 1; /* VsyncSize */ - zr36060_write_8(zr, 0x03a, reg); - - reg = 100 - 1; /* HsyncSize */ - zr36060_write_8(zr, 0x03b, reg); - - reg = tvn->VStart - 1; /* BVstart */ - zr36060_write_8(zr, 0x03c, reg); - - reg += tvn->Ha / 2; /* BVend */ - zr36060_write_16(zr, 0x03e, reg); - - reg = tvn->HStart - 1; /* BHstart */ - zr36060_write_8(zr, 0x03d, reg); - - reg += tvn->Wa; /* BHend */ - zr36060_write_16(zr, 0x040, reg); - - /* active area */ - reg = zr->params.img_y + tvn->VStart; /* Vstart */ - zr36060_write_16(zr, 0x042, reg); - - reg += zr->params.img_height; /* Vend */ - zr36060_write_16(zr, 0x044, reg); - - reg = zr->params.img_x + tvn->HStart; /* Hstart */ - zr36060_write_16(zr, 0x046, reg); - - reg += zr->params.img_width; /* Hend */ - zr36060_write_16(zr, 0x048, reg); - - /* subimage area */ - reg = zr->params.img_y + tvn->VStart; /* SVstart */ - zr36060_write_16(zr, 0x04a, reg); - - reg += zr->params.img_height; /* SVend */ - zr36060_write_16(zr, 0x04c, reg); - - reg = zr->params.img_x + tvn->HStart; /* SHstart */ - zr36060_write_16(zr, 0x04e, reg); - - reg += zr->params.img_width; /* SHend */ - zr36060_write_16(zr, 0x050, reg); -} - -static void zr36060_set_jpg_SOF(struct zoran *zr) -{ - u32 reg; - - - reg = 0xffc0; /* SOF marker */ - zr36060_write_16(zr, 0x060, reg); - - reg = 17; /* SOF length */ - zr36060_write_16(zr, 0x062, reg); - - reg = 8; /* precision 8 bits */ - zr36060_write_8(zr, 0x064, reg); - - reg = zr->params.img_height / zr->params.VerDcm; /* image height */ - zr36060_write_16(zr, 0x065, reg); - - reg = zr->params.img_width / zr->params.HorDcm; /* image width */ - zr36060_write_16(zr, 0x067, reg); - - reg = 3; /* 3 color components */ - zr36060_write_8(zr, 0x069, reg); - - reg = 0x002100; /* Y component */ - zr36060_write_24(zr, 0x06a, reg); - - reg = 0x011101; /* U component */ - zr36060_write_24(zr, 0x06d, reg); - - reg = 0x021101; /* V component */ - zr36060_write_24(zr, 0x070, reg); -} - -static void zr36060_set_jpg_SOS(struct zoran *zr) -{ - u32 reg; - - - reg = 0xffda; /* SOS marker */ - zr36060_write_16(zr, 0x07a, reg); - - reg = 12; /* SOS length */ - zr36060_write_16(zr, 0x07c, reg); - - reg = 3; /* 3 color components */ - zr36060_write_8(zr, 0x07e, reg); - - reg = 0x0000; /* Y component */ - zr36060_write_16(zr, 0x07f, reg); - - reg = 0x0111; /* U component */ - zr36060_write_16(zr, 0x081, reg); - - reg = 0x0211; /* V component */ - zr36060_write_16(zr, 0x083, reg); - - reg = 0x003f00; /* Start, end spectral scans */ - zr36060_write_24(zr, 0x085, reg); -} - -static void zr36060_set_jpg_DRI(struct zoran *zr) -{ - u32 reg; - - - reg = 0xffdd; /* DRI marker */ - zr36060_write_16(zr, 0x0c0, reg); - - reg = 4; /* DRI length */ - zr36060_write_16(zr, 0x0c2, reg); - - reg = 8; /* length in MCUs */ - zr36060_write_16(zr, 0x0c4, reg); -} - -static void zr36060_set_jpg_DQT(struct zoran *zr) -{ - unsigned i; - unsigned adr; - static const u8 dqt[] = - { - 0xff, 0xdb, /* DHT marker */ - 0x00, 0x84, /* DHT length */ - 0x00, /* table ID 0 */ - 0x10, 0x0b, 0x0c, 0x0e, 0x0c, 0x0a, 0x10, 0x0e, - 0x0d, 0x0e, 0x12, 0x11, 0x10, 0x13, 0x18, 0x28, - 0x1a, 0x18, 0x16, 0x16, 0x18, 0x31, 0x23, 0x25, - 0x1d, 0x28, 0x3a, 0x33, 0x3d, 0x3c, 0x39, 0x33, - 0x38, 0x37, 0x40, 0x48, 0x5c, 0x4e, 0x40, 0x44, - 0x57, 0x45, 0x37, 0x38, 0x50, 0x6d, 0x51, 0x57, - 0x5f, 0x62, 0x67, 0x68, 0x67, 0x3e, 0x4d, 0x71, - 0x79, 0x70, 0x64, 0x78, 0x5c, 0x65, 0x67, 0x63, - 0x01, /* table ID 1 */ - 0x11, 0x12, 0x12, 0x18, 0x15, 0x18, 0x2f, 0x1a, - 0x1a, 0x2f, 0x63, 0x42, 0x38, 0x42, 0x63, 0x63, - 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, - 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, - 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, - 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, - 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, - 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63 - }; - - /* write fixed quantitization tables */ - adr = 0x0cc; - for (i = 0; i < sizeof(dqt); ++i) { - zr36060_write_8(zr, adr++, dqt[i]); - } -} - -static void zr36060_set_jpg_DHT(struct zoran *zr) -{ - unsigned i; - unsigned adr; - static const u8 dht[] = - { - 0xff, 0xc4, /* DHT marker */ - 0x01, 0xa2, /* DHT length */ - 0x00, /* table class 0, ID 0 */ - 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, /* # codes of length 1..8 */ - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* # codes of length 8..16 */ - 0x00, /* values for codes of length 2 */ - 0x01, 0x02, 0x03, 0x04, 0x05, /* values for codes of length 3 */ - 0x06, /* values for codes of length 4 */ - 0x07, /* values for codes of length 5 */ - 0x08, /* values for codes of length 6 */ - 0x09, /* values for codes of length 7 */ - 0x0a, /* values for codes of length 8 */ - 0x0b, /* values for codes of length 9 */ - 0x01, /* table class 0, ID 1 */ - 0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, /* # codes of length 1..8 */ - 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, /* # codes of length 9..16 */ - 0x00, 0x01, 0x02, /* values for codes of length 2 */ - 0x03, /* values for codes of length 3 */ - 0x04, /* values for codes of length 4 */ - 0x05, /* values for codes of length 5 */ - 0x06, /* values for codes of length 6 */ - 0x07, /* values for codes of length 7 */ - 0x08, /* values for codes of length 8 */ - 0x09, /* values for codes of length 9 */ - 0x0a, /* values for codes of length 10 */ - 0x0b, /* values for codes of length 11 */ - 0x10, - 0x00, 0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x03, - 0x05, 0x05, 0x04, 0x04, 0x00, 0x00, 0x01, 0x7d, - 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, - 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, - 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08, - 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0, - 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16, - 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28, - 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, - 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, - 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, - 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, - 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, - 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, - 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, - 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, - 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, - 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, - 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, - 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2, - 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, - 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, - 0xf9, 0xfa, 0x11, 0x00, 0x02, 0x01, 0x02, 0x04, - 0x04, 0x03, 0x04, 0x07, 0x05, 0x04, 0x04, 0x00, - 0x01, 0x02, 0x77, 0x00, 0x01, 0x02, 0x03, 0x11, - 0x04, 0x05, 0x21, 0x31, 0x06, 0x12, 0x41, 0x51, - 0x07, 0x61, 0x71, 0x13, 0x22, 0x32, 0x81, 0x08, - 0x14, 0x42, 0x91, 0xa1, 0xb1, 0xc1, 0x09, 0x23, - 0x33, 0x52, 0xf0, 0x15, 0x62, 0x72, 0xd1, 0x0a, - 0x16, 0x24, 0x34, 0xe1, 0x25, 0xf1, 0x17, 0x18, - 0x19, 0x1a, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x35, - 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, - 0x46, 0x47, 0x48, 0x49, 0x4a, 0x53, 0x54, 0x55, - 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65, - 0x66, 0x67, 0x68, 0x69, 0x6a, 0x73, 0x74, 0x75, - 0x76, 0x77, 0x78, 0x79, 0x7a, 0x82, 0x83, 0x84, - 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93, - 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, - 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, - 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, - 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, - 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, - 0xd8, 0xd9, 0xda, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, - 0xe7, 0xe8, 0xe9, 0xea, 0xf2, 0xf3, 0xf4, 0xf5, - 0xf6, 0xf7, 0xf8, 0xf9, 0xfa - }; - - /* write fixed Huffman tables */ - adr = 0x1d4; - for (i = 0; i < sizeof(dht); ++i) { - zr36060_write_8(zr, adr++, dht[i]); - } -} - -static void zr36060_set_jpg_APP(struct zoran *zr) -{ - unsigned adr; - int len, i; - u32 reg; - - - len = zr->params.APP_len; - if (len < 0) - len = 0; - if (len > 60) - len = 60; - - i = zr->params.APPn; - if (i < 0) - i = 0; - if (i > 15) - i = 15; - - reg = 0xffe0 + i; /* APPn marker */ - zr36060_write_16(zr, 0x380, reg); - - reg = len + 2; /* APPn len */ - zr36060_write_16(zr, 0x382, reg); - - /* write APPn data */ - adr = 0x384; - for (i = 0; i < 60; i++) { - zr36060_write_8(zr, adr++, (i < len ? zr->params.APP_data[i] : 0)); - } -} - -static void zr36060_set_jpg_COM(struct zoran *zr) -{ - unsigned adr; - int len, i; - u32 reg; - - - len = zr->params.COM_len; - if (len < 0) - len = 0; - if (len > 60) - len = 60; - - reg = 0xfffe; /* COM marker */ - zr36060_write_16(zr, 0x3c0, reg); - - reg = len + 2; /* COM len */ - zr36060_write_16(zr, 0x3c2, reg); - - /* write COM data */ - adr = 0x3c4; - for (i = 0; i < 60; i++) { - zr36060_write_8(zr, adr++, (i < len ? zr->params.COM_data[i] : 0)); - } -} - -static void zr36060_set_cap(struct zoran *zr, enum zoran_codec_mode mode) -{ - unsigned i; - u32 reg; - - zr36060_reset(zr); - mdelay(10); - - reg = (0 << 7) /* Load=0 */ - |(1 << 0); /* SynRst=1 */ - zr36060_write_8(zr, 0x000, reg); - - zr36060_set_jpg(zr, mode); - zr36060_set_video(zr, mode); - zr36060_set_jpg_SOF(zr); - zr36060_set_jpg_SOS(zr); - zr36060_set_jpg_DRI(zr); - zr36060_set_jpg_DQT(zr); - zr36060_set_jpg_DHT(zr); - zr36060_set_jpg_APP(zr); - zr36060_set_jpg_COM(zr); - - reg = (1 << 7) /* Load=1 */ - |(0 << 0); /* SynRst=0 */ - zr36060_write_8(zr, 0x000, reg); - - /* wait for codec to unbusy */ - for (i = 0; i < 1000; ++i) { - reg = zr36060_read_8(zr, 0x001); - if ((reg & (1 << 7)) == 0) { - DEBUG(printk(KERN_DEBUG "060: loaded, loops=%u\n", i)); - return; - } - udelay(1000); - } - printk(KERN_INFO "060: stuck busy, statux=%02x\n", reg); -} - -static void zr36057_set_jpg(struct zoran *zr, enum zoran_codec_mode mode) -{ - struct tvnorm *tvn; - u32 reg; - int i; - - tvn = &tvnorms[zr->params.norm]; - - /* assert P_Reset */ - btwrite(0, ZR36057_JPC); - - /* re-initialize DMA ring stuff */ - zr->jpg_que_head = 0; - zr->jpg_dma_head = 0; - zr->jpg_dma_tail = 0; - zr->jpg_que_tail = 0; - zr->jpg_seq_num = 0; - for (i = 0; i < BUZ_NUM_STAT_COM; ++i) { - zr->stat_com[i] = 1; /* mark as unavailable to zr36057 */ - } - for (i = 0; i < zr->jpg_nbufs; i++) { - zr->jpg_gbuf[i].state = BUZ_STATE_USER; /* nothing going on */ - } - - /* MJPEG compression mode */ - switch (mode) { - - case BUZ_MODE_MOTION_COMPRESS: - default: - reg = ZR36057_JMC_MJPGCmpMode; - break; - - case BUZ_MODE_MOTION_DECOMPRESS: - reg = ZR36057_JMC_MJPGExpMode; - reg |= ZR36057_JMC_SyncMstr; - /* RJ: The following is experimental - improves the output to screen */ - if (zr->params.VFIFO_FB) - reg |= ZR36057_JMC_VFIFO_FB; - break; - - case BUZ_MODE_STILL_COMPRESS: - reg = ZR36057_JMC_JPGCmpMode; - break; - - case BUZ_MODE_STILL_DECOMPRESS: - reg = ZR36057_JMC_JPGExpMode; - break; - - } - reg |= ZR36057_JMC_JPG; - if (zr->params.field_per_buff == 1) - reg |= ZR36057_JMC_Fld_per_buff; - btwrite(reg, ZR36057_JMC); - - /* vertical */ - btor(ZR36057_VFEVCR_VSPol, ZR36057_VFEVCR); - reg = (6 << ZR36057_VSP_VsyncSize) | (tvn->Ht << ZR36057_VSP_FrmTot); - btwrite(reg, ZR36057_VSP); - reg = ((zr->params.img_y + tvn->VStart) << ZR36057_FVAP_NAY) - | (zr->params.img_height << ZR36057_FVAP_PAY); - btwrite(reg, ZR36057_FVAP); - - /* horizontal */ - btor(ZR36057_VFEHCR_HSPol, ZR36057_VFEHCR); - reg = ((tvn->Wt - 100) << ZR36057_HSP_HsyncStart) | (tvn->Wt << ZR36057_HSP_LineTot); - btwrite(reg, ZR36057_HSP); - reg = ((zr->params.img_x + tvn->HStart) << ZR36057_FHAP_NAX) - | (zr->params.img_width << ZR36057_FHAP_PAX); - btwrite(reg, ZR36057_FHAP); - - /* field process parameters */ - if (zr->params.odd_even) - reg = ZR36057_FPP_Odd_Even; - else - reg = 0; - btwrite(reg, ZR36057_FPP); - - /* Set proper VCLK Polarity, else colors will be wrong during playback */ - btor(ZR36057_VFESPFR_VCLKPol, ZR36057_VFESPFR); - - /* code base address and FIFO threshold */ - reg = virt_to_bus(zr->stat_com); - btwrite(reg, ZR36057_JCBA); - reg = 0x50; - btwrite(reg, ZR36057_JCFT); - - /* JPEG codec guest ID */ - reg = (1 << ZR36057_JCGI_JPEGuestID) | (0 << ZR36057_JCGI_JPEGuestReg); - btwrite(reg, ZR36057_JCGI); - - /* Code transfer guest ID */ - reg = (0 << ZR36057_MCTCR_CodGuestID) | (3 << ZR36057_MCTCR_CodGuestReg); - reg |= ZR36057_MCTCR_CFlush; - btwrite(reg, ZR36057_MCTCR); - - /* deassert P_Reset */ - btwrite(ZR36057_JPC_P_Reset, ZR36057_JPC); -} - -static void zr36057_enable_jpg(struct zoran *zr, enum zoran_codec_mode mode) -{ - static int zero = 0; - static int one = 1; - - switch (mode) { - - case BUZ_MODE_MOTION_COMPRESS: - zr36060_set_cap(zr, mode); - zr36057_set_jpg(zr, mode); - i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_ENABLE_OUTPUT, &one); - i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEOENCODER, ENCODER_SET_INPUT, &zero); - - /* deassert P_Reset, assert Code transfer enable */ - btwrite(IRQ_MASK, ZR36057_ISR); - btand(~ZR36057_MCTCR_CFlush, ZR36057_MCTCR); - break; - - case BUZ_MODE_MOTION_DECOMPRESS: - i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_ENABLE_OUTPUT, &zero); - i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEOENCODER, ENCODER_SET_INPUT, &one); - zr36060_set_cap(zr, mode); - zr36057_set_jpg(zr, mode); - - /* deassert P_Reset, assert Code transfer enable */ - btwrite(IRQ_MASK, ZR36057_ISR); - btand(~ZR36057_MCTCR_CFlush, ZR36057_MCTCR); - break; - - case BUZ_MODE_IDLE: - default: - /* shut down processing */ - btor(ZR36057_MCTCR_CFlush, ZR36057_MCTCR); - btwrite(ZR36057_JPC_P_Reset, ZR36057_JPC); - btand(~ZR36057_JMC_VFIFO_FB, ZR36057_JMC); - btand(~ZR36057_JMC_SyncMstr, ZR36057_JMC); - btand(~ZR36057_JMC_Go_en, ZR36057_JMC); - btwrite(0, ZR36057_ISR); - zr36060_reset(zr); - i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_ENABLE_OUTPUT, &one); - i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEOENCODER, ENCODER_SET_INPUT, &zero); - break; - - } - zr->codec_mode = mode; -} - -/* - * Queue a MJPEG buffer for capture/playback - */ - -static int jpg_qbuf(struct zoran *zr, int frame, enum zoran_codec_mode mode) -{ - unsigned long flags; - int res; - - /* Check if buffers are allocated */ - - if (!zr->jpg_buffers_allocated) { - printk(KERN_ERR "%s: jpg_qbuf: buffers not yet allocated\n", zr->name); - return -ENOMEM; - } - /* Does the user want to stop streaming? */ - - if (frame < 0) { - if (zr->codec_mode == mode) { - zr36057_enable_jpg(zr, BUZ_MODE_IDLE); - return 0; - } else { - printk(KERN_ERR "%s: jpg_qbuf - stop streaming but not in streaming mode\n", zr->name); - return -EINVAL; - } - } - /* No grabbing outside the buffer range! */ - - if (frame >= zr->jpg_nbufs) { - printk(KERN_ERR "%s: jpg_qbuf: buffer %d out of range\n", zr->name, frame); - return -EINVAL; - } - /* what is the codec mode right now? */ - - if (zr->codec_mode == BUZ_MODE_IDLE) { - /* Ok load up the zr36060 and go */ - zr36057_enable_jpg(zr, mode); - } else if (zr->codec_mode != mode) { - /* wrong codec mode active - invalid */ - printk(KERN_ERR "%s: jpg_qbuf - codec in wrong mode\n", zr->name); - return -EINVAL; - } - spin_lock_irqsave(&zr->lock, flags); - - /* make sure a grab isn't going on currently with this buffer */ - - switch (zr->jpg_gbuf[frame].state) { - - default: - case BUZ_STATE_DMA: - case BUZ_STATE_PEND: - case BUZ_STATE_DONE: - res = -EBUSY; /* what are you doing? */ - break; - - case BUZ_STATE_USER: - /* since there is at least one unused buffer there's room for at least one more pend[] entry */ - zr->jpg_pend[zr->jpg_que_head++ & BUZ_MASK_FRAME] = frame; - zr->jpg_gbuf[frame].state = BUZ_STATE_PEND; - zoran_feed_stat_com(zr); - res = 0; - break; - - } - - spin_unlock_irqrestore(&zr->lock, flags); - - /* Start the zr36060 when the first frame is queued */ - if (zr->jpg_que_head == 1) { - btor(ZR36057_JMC_Go_en, ZR36057_JMC); - btwrite(ZR36057_JPC_P_Reset | ZR36057_JPC_CodTrnsEn | ZR36057_JPC_Active, ZR36057_JPC); - } - return res; -} - -/* - * Sync on a MJPEG buffer - */ - -static int jpg_sync(struct zoran *zr, struct zoran_sync *bs) -{ - unsigned long flags; - int frame; - - if (zr->codec_mode != BUZ_MODE_MOTION_DECOMPRESS && - zr->codec_mode != BUZ_MODE_MOTION_COMPRESS) { - return -EINVAL; - } - while (zr->jpg_que_tail == zr->jpg_dma_tail) { - interruptible_sleep_on(&zr->jpg_capq); - if (signal_pending(current)) - return -ERESTARTSYS; - } - - spin_lock_irqsave(&zr->lock, flags); - - frame = zr->jpg_pend[zr->jpg_que_tail++ & BUZ_MASK_FRAME]; - - /* buffer should now be in BUZ_STATE_DONE */ - - if (zr->jpg_gbuf[frame].state != BUZ_STATE_DONE) - printk(KERN_ERR "%s: jpg_sync - internal error\n", zr->name); - - *bs = zr->jpg_gbuf[frame].bs; - zr->jpg_gbuf[frame].state = BUZ_STATE_USER; - - spin_unlock_irqrestore(&zr->lock, flags); - - return 0; -} - -/* when this is called the spinlock must be held */ -static void zoran_feed_stat_com(struct zoran *zr) -{ - /* move frames from pending queue to DMA */ - - int frame, i, max_stat_com; - - max_stat_com = (zr->params.TmpDcm == 1) ? BUZ_NUM_STAT_COM : (BUZ_NUM_STAT_COM >> 1); - - while ((zr->jpg_dma_head - zr->jpg_dma_tail) < max_stat_com - && zr->jpg_dma_head != zr->jpg_que_head) { - - frame = zr->jpg_pend[zr->jpg_dma_head & BUZ_MASK_FRAME]; - if (zr->params.TmpDcm == 1) { - /* fill 1 stat_com entry */ - i = zr->jpg_dma_head & BUZ_MASK_STAT_COM; - zr->stat_com[i] = zr->jpg_gbuf[frame].frag_tab_bus; - } else { - /* fill 2 stat_com entries */ - i = (zr->jpg_dma_head & 1) * 2; - zr->stat_com[i] = zr->jpg_gbuf[frame].frag_tab_bus; - zr->stat_com[i + 1] = zr->jpg_gbuf[frame].frag_tab_bus; - } - zr->jpg_gbuf[frame].state = BUZ_STATE_DMA; - zr->jpg_dma_head++; - - } -} - -/* when this is called the spinlock must be held */ -static void zoran_reap_stat_com(struct zoran *zr) -{ - /* move frames from DMA queue to done queue */ - - int i; - u32 stat_com; - unsigned int seq; - unsigned int dif; - int frame; - struct zoran_gbuffer *gbuf; - - /* In motion decompress we don't have a hardware frame counter, - we just count the interrupts here */ - - if (zr->codec_mode == BUZ_MODE_MOTION_DECOMPRESS) - zr->jpg_seq_num++; - - while (zr->jpg_dma_tail != zr->jpg_dma_head) { - if (zr->params.TmpDcm == 1) - i = zr->jpg_dma_tail & BUZ_MASK_STAT_COM; - else - i = (zr->jpg_dma_tail & 1) * 2 + 1; - - stat_com = zr->stat_com[i]; - - if ((stat_com & 1) == 0) { - return; - } - frame = zr->jpg_pend[zr->jpg_dma_tail & BUZ_MASK_FRAME]; - gbuf = &zr->jpg_gbuf[frame]; - get_fast_time(&gbuf->bs.timestamp); - - if (zr->codec_mode == BUZ_MODE_MOTION_COMPRESS) { - gbuf->bs.length = (stat_com & 0x7fffff) >> 1; - - /* update sequence number with the help of the counter in stat_com */ - - seq = stat_com >> 24; - dif = (seq - zr->jpg_seq_num) & 0xff; - zr->jpg_seq_num += dif; - } else { - gbuf->bs.length = 0; - } - gbuf->bs.seq = zr->params.TmpDcm == 2 ? (zr->jpg_seq_num >> 1) : zr->jpg_seq_num; - gbuf->state = BUZ_STATE_DONE; - - zr->jpg_dma_tail++; - } -} - -static void zoran_irq(int irq, void *dev_id, struct pt_regs *regs) -{ - u32 stat, astat; - int count; - struct zoran *zr; - unsigned long flags; - - zr = (struct zoran *) dev_id; - count = 0; - - spin_lock_irqsave(&zr->lock, flags); - while (1) { - /* get/clear interrupt status bits */ - stat = btread(ZR36057_ISR); - astat = stat & IRQ_MASK; - if (!astat) { - break; - } - btwrite(astat, ZR36057_ISR); - IDEBUG(printk(BUZ_DEBUG "-%u: astat %08x stat %08x\n", zr->id, astat, stat)); - -#if (IRQ_MASK & ZR36057_ISR_GIRQ0) - if (astat & ZR36057_ISR_GIRQ0) { - - /* Interrupts may still happen when zr->v4l_memgrab_active is switched off. - We simply ignore them */ - - if (zr->v4l_memgrab_active) { - -/* A lot more checks should be here ... */ - if ((btread(ZR36057_VSSFGR) & ZR36057_VSSFGR_SnapShot) == 0) - printk(KERN_WARNING "%s: BuzIRQ with SnapShot off ???\n", zr->name); - - if (zr->v4l_grab_frame != NO_GRAB_ACTIVE) { - /* There is a grab on a frame going on, check if it has finished */ - - if ((btread(ZR36057_VSSFGR) & ZR36057_VSSFGR_FrameGrab) == 0) { - /* it is finished, notify the user */ - - zr->v4l_gbuf[zr->v4l_grab_frame].state = BUZ_STATE_DONE; - zr->v4l_grab_frame = NO_GRAB_ACTIVE; - zr->v4l_grab_seq++; - zr->v4l_pend_tail++; - } - } - if (zr->v4l_grab_frame == NO_GRAB_ACTIVE) - wake_up_interruptible(&zr->v4l_capq); - - /* Check if there is another grab queued */ - - if (zr->v4l_grab_frame == NO_GRAB_ACTIVE && - zr->v4l_pend_tail != zr->v4l_pend_head) { - - int frame = zr->v4l_pend[zr->v4l_pend_tail & V4L_MASK_FRAME]; - u32 reg; - - zr->v4l_grab_frame = frame; - - /* Set zr36057 video front end and enable video */ - - /* Buffer address */ - - reg = zr->v4l_gbuf[frame].fbuffer_bus; - btwrite(reg, ZR36057_VDTR); - if (zr->video_interlace) - reg += zr->gbpl; - btwrite(reg, ZR36057_VDBR); - - /* video stride, status, and frame grab register */ - -#ifdef XAWTV_HACK - reg = (zr->gwidth > 720) ? ((zr->gwidth & ~3) - 720) * zr->gbpl / zr->gwidth : 0; -#else - reg = 0; -#endif - if (zr->video_interlace) - reg += zr->gbpl; - reg = (reg << ZR36057_VSSFGR_DispStride); - reg |= ZR36057_VSSFGR_VidOvf; - reg |= ZR36057_VSSFGR_SnapShot; - reg |= ZR36057_VSSFGR_FrameGrab; - btwrite(reg, ZR36057_VSSFGR); - - btor(ZR36057_VDCR_VidEn, ZR36057_VDCR); - } - } - } -#endif /* (IRQ_MASK & ZR36057_ISR_GIRQ0) */ - -#if (IRQ_MASK & ZR36057_ISR_GIRQ1) - if (astat & ZR36057_ISR_GIRQ1) { - unsigned csr = zr36060_read_8(zr, 0x001); - unsigned isr = zr36060_read_8(zr, 0x008); - - IDEBUG(printk(KERN_DEBUG "%s: ZR36057_ISR_GIRQ1 60_code=%02x 60_intr=%02x\n", - zr->name, csr, isr)); - - btand(~ZR36057_ICR_GIRQ1, ZR36057_ICR); - zoran_reap_stat_com(zr); - zoran_feed_stat_com(zr); - } -#endif /* (IRQ_MASK & ZR36057_ISR_GIRQ1) */ - -#if (IRQ_MASK & ZR36057_ISR_CodRepIRQ) - if (astat & ZR36057_ISR_CodRepIRQ) { - IDEBUG(printk(KERN_DEBUG "%s: ZR36057_ISR_CodRepIRQ\n", zr->name)); - btand(~ZR36057_ICR_CodRepIRQ, ZR36057_ICR); - } -#endif /* (IRQ_MASK & ZR36057_ISR_CodRepIRQ) */ - -#if (IRQ_MASK & ZR36057_ISR_JPEGRepIRQ) - if ((astat & ZR36057_ISR_JPEGRepIRQ) && - (zr->codec_mode == BUZ_MODE_MOTION_DECOMPRESS || - zr->codec_mode == BUZ_MODE_MOTION_COMPRESS)) { - zoran_reap_stat_com(zr); - zoran_feed_stat_com(zr); - wake_up_interruptible(&zr->jpg_capq); - } -#endif /* (IRQ_MASK & ZR36057_ISR_JPEGRepIRQ) */ - - count++; - if (count > 10) { - printk(KERN_WARNING "%s: irq loop %d\n", zr->name, count); - if (count > 20) { - btwrite(0, ZR36057_ICR); - printk(KERN_ERR "%s: IRQ lockup, cleared int mask\n", zr->name); - break; - } - } - } - spin_unlock_irqrestore(&zr->lock, flags); -} - -/* Check a zoran_params struct for correctness, insert default params */ - -static int zoran_check_params(struct zoran *zr, struct zoran_params *params) -{ - int err = 0, err0 = 0; - - /* insert constant params */ - - params->major_version = MAJOR_VERSION; - params->minor_version = MINOR_VERSION; - - /* Check input and norm */ - - if (params->input != 0 && params->input != 1) { - err++; - } - if (params->norm != VIDEO_MODE_PAL && params->norm != VIDEO_MODE_NTSC) { - err++; - } - /* Check decimation, set default values for decimation = 1, 2, 4 */ - - switch (params->decimation) { - case 1: - - params->HorDcm = 1; - params->VerDcm = 1; - params->TmpDcm = 1; - params->field_per_buff = 2; - - params->img_x = 0; - params->img_y = 0; - params->img_width = 720; - params->img_height = tvnorms[params->norm].Ha / 2; - break; - - case 2: - - params->HorDcm = 2; - params->VerDcm = 1; - params->TmpDcm = 2; - params->field_per_buff = 1; - - params->img_x = 8; - params->img_y = 0; - params->img_width = 704; - params->img_height = tvnorms[params->norm].Ha / 2; - break; - - case 4: - - params->HorDcm = 4; - params->VerDcm = 2; - params->TmpDcm = 2; - params->field_per_buff = 1; - - params->img_x = 8; - params->img_y = 0; - params->img_width = 704; - params->img_height = tvnorms[params->norm].Ha / 2; - break; - - case 0: - - /* We have to check the data the user has set */ - - if (params->HorDcm != 1 && params->HorDcm != 2 && params->HorDcm != 4) - err0++; - if (params->VerDcm != 1 && params->VerDcm != 2) - err0++; - if (params->TmpDcm != 1 && params->TmpDcm != 2) - err0++; - if (params->field_per_buff != 1 && params->field_per_buff != 2) - err0++; - - if (params->img_x < 0) - err0++; - if (params->img_y < 0) - err0++; - if (params->img_width < 0) - err0++; - if (params->img_height < 0) - err0++; - if (params->img_x + params->img_width > 720) - err0++; - if (params->img_y + params->img_height > tvnorms[params->norm].Ha / 2) - err0++; - if (params->img_width % (16 * params->HorDcm) != 0) - err0++; - if (params->img_height % (8 * params->VerDcm) != 0) - err0++; - - if (err0) { - err++; - } - break; - - default: - err++; - break; - } - - if (params->quality > 100) - params->quality = 100; - if (params->quality < 5) - params->quality = 5; - - if (params->APPn < 0) - params->APPn = 0; - if (params->APPn > 15) - params->APPn = 15; - if (params->APP_len < 0) - params->APP_len = 0; - if (params->APP_len > 60) - params->APP_len = 60; - if (params->COM_len < 0) - params->COM_len = 0; - if (params->COM_len > 60) - params->COM_len = 60; - - if (err) - return -EINVAL; - - return 0; - -} -static void zoran_open_init_params(struct zoran *zr) -{ - int i; - - /* Per default, map the V4L Buffers */ - - zr->map_mjpeg_buffers = 0; - - /* User must explicitly set a window */ - - zr->window_set = 0; - - zr->window.x = 0; - zr->window.y = 0; - zr->window.width = 0; - zr->window.height = 0; - zr->window.chromakey = 0; - zr->window.flags = 0; - zr->window.clips = NULL; - zr->window.clipcount = 0; - - zr->video_interlace = 0; - - zr->v4l_memgrab_active = 0; - zr->v4l_overlay_active = 0; - - zr->v4l_grab_frame = NO_GRAB_ACTIVE; - zr->v4l_grab_seq = 0; - - zr->gwidth = 0; - zr->gheight = 0; - zr->gformat = 0; - zr->gbpl = 0; - - /* DMA ring stuff for V4L */ - - zr->v4l_pend_tail = 0; - zr->v4l_pend_head = 0; - for (i = 0; i < v4l_nbufs; i++) { - zr->v4l_gbuf[i].state = BUZ_STATE_USER; /* nothing going on */ - } - - /* Set necessary params and call zoran_check_params to set the defaults */ - - zr->params.decimation = 1; - - zr->params.quality = 50; /* default compression factor 8 */ - zr->params.odd_even = 1; - - zr->params.APPn = 0; - zr->params.APP_len = 0; /* No APPn marker */ - for (i = 0; i < 60; i++) - zr->params.APP_data[i] = 0; - - zr->params.COM_len = 0; /* No COM marker */ - for (i = 0; i < 60; i++) - zr->params.COM_data[i] = 0; - - zr->params.VFIFO_FB = 0; - - memset(zr->params.reserved, 0, sizeof(zr->params.reserved)); - - zr->params.jpeg_markers = JPEG_MARKER_DHT | JPEG_MARKER_DQT; - - i = zoran_check_params(zr, &zr->params); - if (i) - printk(KERN_ERR "%s: zoran_open_init_params internal error\n", zr->name); -} - -/* - * Open a buz card. Right now the flags stuff is just playing - */ - -static int zoran_open(struct video_device *dev, int flags) -{ - struct zoran *zr = (struct zoran *) dev; - - DEBUG(printk(KERN_INFO ": zoran_open\n")); - - switch (flags) { - - case 0: - if (zr->user) - return -EBUSY; - zr->user++; - - if (v4l_fbuffer_alloc(zr) < 0) { - zr->user--; - return -ENOMEM; - } - /* default setup */ - - zoran_open_init_params(zr); - - zr36057_enable_jpg(zr, BUZ_MODE_IDLE); - - btwrite(IRQ_MASK, ZR36057_ISR); // Clears interrupts - - btor(ZR36057_ICR_IntPinEn, ZR36057_ICR); - - break; - - default: - return -EBUSY; - - } - return 0; -} - -static void zoran_close(struct video_device *dev) -{ - struct zoran *zr = (struct zoran *) dev; - - DEBUG(printk(KERN_INFO ": zoran_close\n")); - - /* disable interrupts */ - btand(~ZR36057_ICR_IntPinEn, ZR36057_ICR); - - /* wake up sleeping beauties */ - wake_up_interruptible(&zr->v4l_capq); - wake_up_interruptible(&zr->jpg_capq); - - zr36057_enable_jpg(zr, BUZ_MODE_IDLE); - zr36057_set_memgrab(zr, 0); - if (zr->v4l_overlay_active) - zr36057_overlay(zr, 0); - - zr->user--; - - v4l_fbuffer_free(zr); - jpg_fbuffer_free(zr); - zr->jpg_nbufs = 0; - - DEBUG(printk(KERN_INFO ": zoran_close done\n")); -} - - -static long zoran_read(struct video_device *dev, char *buf, unsigned long count, int nonblock) -{ - return -EINVAL; -} - -static long zoran_write(struct video_device *dev, const char *buf, unsigned long count, int nonblock) -{ - return -EINVAL; -} - -/* - * ioctl routine - */ - - -static int zoran_ioctl(struct video_device *dev, unsigned int cmd, void *arg) -{ - struct zoran *zr = (struct zoran *) dev; - - switch (cmd) { - - case VIDIOCGCAP: - { - struct video_capability b; - IOCTL_DEBUG(printk("buz ioctl VIDIOCGCAP\n")); - strncpy(b.name, zr->video_dev.name, sizeof(b.name)); - b.type = VID_TYPE_CAPTURE | - VID_TYPE_OVERLAY | - VID_TYPE_CLIPPING | - VID_TYPE_FRAMERAM | - VID_TYPE_SCALES; - /* theoretically we could also flag VID_TYPE_SUBCAPTURE - but this is not even implemented in the BTTV driver */ - - b.channels = 2; /* composite, svhs */ - b.audios = 0; - b.maxwidth = BUZ_MAX_WIDTH; - b.maxheight = BUZ_MAX_HEIGHT; - b.minwidth = BUZ_MIN_WIDTH; - b.minheight = BUZ_MIN_HEIGHT; - if (copy_to_user(arg, &b, sizeof(b))) { - return -EFAULT; - } - return 0; - } - - case VIDIOCGCHAN: - { - struct video_channel v; - - if (copy_from_user(&v, arg, sizeof(v))) { - return -EFAULT; - } - IOCTL_DEBUG(printk("buz ioctl VIDIOCGCHAN for channel %d\n", v.channel)); - switch (v.channel) { - case 0: - strcpy(v.name, "Composite"); - break; - case 1: - strcpy(v.name, "SVHS"); - break; - default: - return -EINVAL; - } - v.tuners = 0; - v.flags = 0; - v.type = VIDEO_TYPE_CAMERA; - v.norm = zr->params.norm; - if (copy_to_user(arg, &v, sizeof(v))) { - return -EFAULT; - } - return 0; - } - - /* RJ: the documentation at http://roadrunner.swansea.linux.org.uk/v4lapi.shtml says: - - * "The VIDIOCSCHAN ioctl takes an integer argument and switches the capture to this input." - * ^^^^^^^ - * The famos BTTV driver has it implemented with a struct video_channel argument - * and we follow it for compatibility reasons - * - * BTW: this is the only way the user can set the norm! - */ - - case VIDIOCSCHAN: - { - struct video_channel v; - int input; - int on, res; - - if (copy_from_user(&v, arg, sizeof(v))) { - return -EFAULT; - } - IOCTL_DEBUG(printk("buz ioctl VIDIOCSCHAN: channel=%d, norm=%d\n", v.channel, v.norm)); - switch (v.channel) { - case 0: - input = 3; - break; - case 1: - input = 7; - break; - default: - return -EINVAL; - } - - if (v.norm != VIDEO_MODE_PAL - && v.norm != VIDEO_MODE_NTSC) { - return -EINVAL; - } - zr->params.norm = v.norm; - zr->params.input = v.channel; - - /* We switch overlay off and on since a change in the norm - needs different VFE settings */ - - on = zr->v4l_overlay_active && !zr->v4l_memgrab_active; - if (on) - zr36057_overlay(zr, 0); - - i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_INPUT, &input); - i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_NORM, &zr->params.norm); - i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEOENCODER, ENCODER_SET_NORM, &zr->params.norm); - - if (on) - zr36057_overlay(zr, 1); - - /* Make sure the changes come into effect */ - res = wait_grab_pending(zr); - if (res) - return res; - - return 0; - } - - case VIDIOCGTUNER: - case VIDIOCSTUNER: - return -EINVAL; - - case VIDIOCGPICT: - { - struct video_picture p = zr->picture; - - IOCTL_DEBUG(printk("buz ioctl VIDIOCGPICT\n")); - p.depth = zr->buffer.depth; - switch (zr->buffer.depth) { - case 15: - p.palette = VIDEO_PALETTE_RGB555; - break; - - case 16: - p.palette = VIDEO_PALETTE_RGB565; - break; - - case 24: - p.palette = VIDEO_PALETTE_RGB24; - break; - - case 32: - p.palette = VIDEO_PALETTE_RGB32; - break; - } - - if (copy_to_user(arg, &p, sizeof(p))) { - return -EFAULT; - } - return 0; - } - - case VIDIOCSPICT: - { - struct video_picture p; - - if (copy_from_user(&p, arg, sizeof(p))) { - return -EFAULT; - } - i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_PICTURE, &p); - IOCTL_DEBUG(printk("buz ioctl VIDIOCSPICT bri=%d hue=%d col=%d con=%d dep=%d pal=%d\n", - p.brightness, p.hue, p.colour, p.contrast, p.depth, p.palette)); - /* The depth and palette values have no meaning to us, - should we return -EINVAL if they don't fit ? */ - zr->picture = p; - return 0; - } - - case VIDIOCCAPTURE: - { - int v, res; - - if (copy_from_user(&v, arg, sizeof(v))) { - return -EFAULT; - } - IOCTL_DEBUG(printk("buz ioctl VIDIOCCAPTURE: %d\n", v)); - /* If there is nothing to do, return immediatly */ - - if ((v && zr->v4l_overlay_active) || (!v && !zr->v4l_overlay_active)) - return 0; - - if (v == 0) { - zr->v4l_overlay_active = 0; - if (!zr->v4l_memgrab_active) - zr36057_overlay(zr, 0); - /* When a grab is running, the video simply won't be switched on any more */ - } else { - if (!zr->buffer_set || !zr->window_set) { - return -EINVAL; - } - zr->v4l_overlay_active = 1; - if (!zr->v4l_memgrab_active) - zr36057_overlay(zr, 1); - /* When a grab is running, the video will be switched on when grab is finished */ - } - /* Make sure the changes come into effect */ - res = wait_grab_pending(zr); - if (res) - return res; - return 0; - } - - case VIDIOCGWIN: - { - IOCTL_DEBUG(printk("buz ioctl VIDIOCGWIN\n")); - if (copy_to_user(arg, &zr->window, sizeof(zr->window))) { - return -EFAULT; - } - return 0; - } - - case VIDIOCSWIN: - { - struct video_clip *vcp; - struct video_window vw; - int on, end, res; - - if (copy_from_user(&vw, arg, sizeof(vw))) { - return -EFAULT; - } - IOCTL_DEBUG(printk("buz ioctl VIDIOCSWIN: x=%d y=%d w=%d h=%d clipcount=%d\n", vw.x, vw.y, vw.width, vw.height, vw.clipcount)); - if (!zr->buffer_set) { - return -EINVAL; - } - /* - * The video front end needs 4-byte alinged line sizes, we correct that - * silently here if necessary - */ - - if (zr->buffer.depth == 15 || zr->buffer.depth == 16) { - end = (vw.x + vw.width) & ~1; /* round down */ - vw.x = (vw.x + 1) & ~1; /* round up */ - vw.width = end - vw.x; - } - if (zr->buffer.depth == 24) { - end = (vw.x + vw.width) & ~3; /* round down */ - vw.x = (vw.x + 3) & ~3; /* round up */ - vw.width = end - vw.x; - } -#if 0 - // At least xawtv seems to care about the following - just leave it away - /* - * Also corrected silently (as long as window fits at all): - * video not fitting the screen - */ -#if 0 - if (vw.x < 0 || vw.y < 0 || vw.x + vw.width > zr->buffer.width || - vw.y + vw.height > zr->buffer.height) { - printk(BUZ_ERR ": VIDIOCSWIN: window does not fit frame buffer: %dx%d+%d*%d\n", - vw.width, vw.height, vw.x, vw.y); - return -EINVAL; - } -#else - if (vw.x < 0) - vw.x = 0; - if (vw.y < 0) - vw.y = 0; - if (vw.x + vw.width > zr->buffer.width) - vw.width = zr->buffer.width - vw.x; - if (vw.y + vw.height > zr->buffer.height) - vw.height = zr->buffer.height - vw.y; -#endif -#endif - - /* Check for valid parameters */ - if (vw.width < BUZ_MIN_WIDTH || vw.height < BUZ_MIN_HEIGHT || - vw.width > BUZ_MAX_WIDTH || vw.height > BUZ_MAX_HEIGHT) { - return -EINVAL; - } -#ifdef XAWTV_HACK - if (vw.width > 720) - vw.width = 720; -#endif - - zr->window.x = vw.x; - zr->window.y = vw.y; - zr->window.width = vw.width; - zr->window.height = vw.height; - zr->window.chromakey = 0; - zr->window.flags = 0; // RJ: Is this intended for interlace on/off ? - - zr->window.clips = NULL; - zr->window.clipcount = vw.clipcount; - - /* - * If an overlay is running, we have to switch it off - * and switch it on again in order to get the new settings in effect. - * - * We also want to avoid that the overlay mask is written - * when an overlay is running. - */ - - on = zr->v4l_overlay_active && !zr->v4l_memgrab_active; - if (on) - zr36057_overlay(zr, 0); - - /* - * Write the overlay mask if clips are wanted. - */ - if (vw.clipcount) { - vcp = vmalloc(sizeof(struct video_clip) * (vw.clipcount + 4)); - if (vcp == NULL) { - return -ENOMEM; - } - if (copy_from_user(vcp, vw.clips, sizeof(struct video_clip) * vw.clipcount)) { - vfree(vcp); - return -EFAULT; - } - write_overlay_mask(zr, vcp, vw.clipcount); - vfree(vcp); - } - if (on) - zr36057_overlay(zr, 1); - zr->window_set = 1; - - /* Make sure the changes come into effect */ - res = wait_grab_pending(zr); - if (res) - return res; - - return 0; - } - - case VIDIOCGFBUF: - { - IOCTL_DEBUG(printk("buz ioctl VIDIOCGFBUF\n")); - if (copy_to_user(arg, &zr->buffer, sizeof(zr->buffer))) { - return -EFAULT; - } - return 0; - } - - case VIDIOCSFBUF: - { - struct video_buffer v; - - if (!capable(CAP_SYS_ADMIN) - || !capable(CAP_SYS_RAWIO)) - return -EPERM; - - if (copy_from_user(&v, arg, sizeof(v))) - return -EFAULT; - - IOCTL_DEBUG(printk("buz ioctl VIDIOCSFBUF: base=0x%x w=%d h=%d depth=%d bpl=%d\n", (u32) v.base, v.width, v.height, v.depth, v.bytesperline)); - if (zr->v4l_overlay_active) { - /* Has the user gotten crazy ... ? */ - return -EINVAL; - } - if (v.depth != 15 - && v.depth != 16 - && v.depth != 24 - && v.depth != 32) { - return -EINVAL; - } - if (v.height <= 0 || v.width <= 0 || v.bytesperline <= 0) { - return -EINVAL; - } - if (v.bytesperline & 3) { - return -EINVAL; - } - if (v.base) { - zr->buffer.base = (void *) ((unsigned long) v.base & ~3); - } - zr->buffer.height = v.height; - zr->buffer.width = v.width; - zr->buffer.depth = v.depth; - zr->buffer.bytesperline = v.bytesperline; - - if (zr->buffer.base) - zr->buffer_set = 1; - zr->window_set = 0; /* The user should set new window parameters */ - return 0; - } - - /* RJ: what is VIDIOCKEY intended to do ??? */ - - case VIDIOCGFREQ: - case VIDIOCSFREQ: - case VIDIOCGAUDIO: - case VIDIOCSAUDIO: - return -EINVAL; - - case VIDIOCSYNC: - { - int v; - - if (copy_from_user(&v, arg, sizeof(v))) { - return -EFAULT; - } - IOCTL_DEBUG(printk("buz ioctl VIDIOCSYNC %d\n", v)); - return v4l_sync(zr, v); - } - - case VIDIOCMCAPTURE: - { - struct video_mmap vm; - - if (copy_from_user((void *) &vm, (void *) arg, sizeof(vm))) { - return -EFAULT; - } - IOCTL_DEBUG(printk("buz ioctl VIDIOCMCAPTURE frame=%d geom=%dx%d fmt=%d\n", - vm.frame, vm.height, vm.width, vm.format)); - return v4l_grab(zr, &vm); - } - - case VIDIOCGMBUF: - { - struct video_mbuf vm; - int i; - - IOCTL_DEBUG(printk("buz ioctl VIDIOCGMBUF\n")); - - vm.size = v4l_nbufs * v4l_bufsize; - vm.frames = v4l_nbufs; - for (i = 0; i < v4l_nbufs; i++) { - vm.offsets[i] = i * v4l_bufsize; - } - - /* The next mmap will map the V4L buffers */ - zr->map_mjpeg_buffers = 0; - - if (copy_to_user(arg, &vm, sizeof(vm))) { - return -EFAULT; - } - return 0; - } - - case VIDIOCGUNIT: - { - struct video_unit vu; - - IOCTL_DEBUG(printk("buz ioctl VIDIOCGUNIT\n")); - vu.video = zr->video_dev.minor; - vu.vbi = VIDEO_NO_UNIT; - vu.radio = VIDEO_NO_UNIT; - vu.audio = VIDEO_NO_UNIT; - vu.teletext = VIDEO_NO_UNIT; - if (copy_to_user(arg, &vu, sizeof(vu))) - return -EFAULT; - return 0; - } - - /* - * RJ: In principal we could support subcaptures for V4L grabbing. - * Not even the famous BTTV driver has them, however. - * If there should be a strong demand, one could consider - * to implement them. - */ - case VIDIOCGCAPTURE: - case VIDIOCSCAPTURE: - return -EINVAL; - - case BUZIOC_G_PARAMS: - { - IOCTL_DEBUG(printk("buz ioctl BUZIOC_G_PARAMS\n")); - if (copy_to_user(arg, &(zr->params), sizeof(zr->params))) - return -EFAULT; - return 0; - } - - case BUZIOC_S_PARAMS: - { - struct zoran_params bp; - int input, on; - - if (zr->codec_mode != BUZ_MODE_IDLE) { - return -EINVAL; - } - if (copy_from_user(&bp, arg, sizeof(bp))) { - return -EFAULT; - } - IOCTL_DEBUG(printk("buz ioctl BUZIOC_S_PARAMS\n")); - - /* Check the params first before overwriting our internal values */ - - if (zoran_check_params(zr, &bp)) - return -EINVAL; - - zr->params = bp; - - /* Make changes of input and norm go into effect immediatly */ - - /* We switch overlay off and on since a change in the norm - needs different VFE settings */ - - on = zr->v4l_overlay_active && !zr->v4l_memgrab_active; - if (on) - zr36057_overlay(zr, 0); - - input = zr->params.input == 0 ? 3 : 7; - i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_INPUT, &input); - i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_NORM, &zr->params.norm); - i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEOENCODER, ENCODER_SET_NORM, &zr->params.norm); - - if (on) - zr36057_overlay(zr, 1); - - if (copy_to_user(arg, &bp, sizeof(bp))) { - return -EFAULT; - } - return 0; - } - - case BUZIOC_REQBUFS: - { - struct zoran_requestbuffers br; - - if (zr->jpg_buffers_allocated) { - return -EINVAL; - } - if (copy_from_user(&br, arg, sizeof(br))) { - return -EFAULT; - } - IOCTL_DEBUG(printk("buz ioctl BUZIOC_REQBUFS count = %lu size=%lu\n", - br.count, br.size)); - /* Enforce reasonable lower and upper limits */ - if (br.count < 4) - br.count = 4; /* Could be choosen smaller */ - if (br.count > BUZ_MAX_FRAME) - br.count = BUZ_MAX_FRAME; - br.size = PAGE_ALIGN(br.size); - if (br.size < 8192) - br.size = 8192; /* Arbitrary */ - /* br.size is limited by 1 page for the stat_com tables to a Maximum of 2 MB */ - if (br.size > (512 * 1024)) - br.size = (512 * 1024); /* 512 K should be enough */ - if (zr->need_contiguous && br.size > KMALLOC_MAXSIZE) - br.size = KMALLOC_MAXSIZE; - - zr->jpg_nbufs = br.count; - zr->jpg_bufsize = br.size; - - if (jpg_fbuffer_alloc(zr)) - return -ENOMEM; - - /* The next mmap will map the MJPEG buffers */ - zr->map_mjpeg_buffers = 1; - - if (copy_to_user(arg, &br, sizeof(br))) { - return -EFAULT; - } - return 0; - } - - case BUZIOC_QBUF_CAPT: - { - int nb; - - if (copy_from_user((void *) &nb, (void *) arg, sizeof(int))) { - return -EFAULT; - } - IOCTL_DEBUG(printk("buz ioctl BUZIOC_QBUF_CAPT %d\n", nb)); - return jpg_qbuf(zr, nb, BUZ_MODE_MOTION_COMPRESS); - } - - case BUZIOC_QBUF_PLAY: - { - int nb; - - if (copy_from_user((void *) &nb, (void *) arg, sizeof(int))) { - return -EFAULT; - } - IOCTL_DEBUG(printk("buz ioctl BUZIOC_QBUF_PLAY %d\n", nb)); - return jpg_qbuf(zr, nb, BUZ_MODE_MOTION_DECOMPRESS); - } - - case BUZIOC_SYNC: - { - struct zoran_sync bs; - int res; - - IOCTL_DEBUG(printk("buz ioctl BUZIOC_SYNC\n")); - res = jpg_sync(zr, &bs); - if (copy_to_user(arg, &bs, sizeof(bs))) { - return -EFAULT; - } - return res; - } - - case BUZIOC_G_STATUS: - { - struct zoran_status bs; - int norm, input, status; - - if (zr->codec_mode != BUZ_MODE_IDLE) { - return -EINVAL; - } - if (copy_from_user(&bs, arg, sizeof(bs))) { - return -EFAULT; - } - IOCTL_DEBUG(printk("buz ioctl BUZIOC_G_STATUS\n")); - switch (bs.input) { - case 0: - input = 3; - break; - case 1: - input = 7; - break; - default: - return -EINVAL; - } - - /* Set video norm to VIDEO_MODE_AUTO */ - - norm = VIDEO_MODE_AUTO; - i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_INPUT, &input); - i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_NORM, &norm); - - /* sleep 1 second */ - - schedule_timeout(HZ); - - /* Get status of video decoder */ - - i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_GET_STATUS, &status); - bs.signal = (status & DECODER_STATUS_GOOD) ? 1 : 0; - bs.norm = (status & DECODER_STATUS_NTSC) ? VIDEO_MODE_NTSC : VIDEO_MODE_PAL; - bs.color = (status & DECODER_STATUS_COLOR) ? 1 : 0; - - /* restore previous input and norm */ - input = zr->params.input == 0 ? 3 : 7; - i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_INPUT, &input); - i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_NORM, &zr->params.norm); - - if (copy_to_user(arg, &bs, sizeof(bs))) { - return -EFAULT; - } - return 0; - } - - default: - return -ENOIOCTLCMD; - - } - return 0; -} - - -/* - * This maps the buffers to user space. - * - * Depending on the state of zr->map_mjpeg_buffers - * the V4L or the MJPEG buffers are mapped - * - */ - -static int zoran_mmap(struct video_device *dev, const char *adr, unsigned long size) -{ - struct zoran *zr = (struct zoran *) dev; - unsigned long start = (unsigned long) adr; - unsigned long page, pos, todo, fraglen; - int i, j; - - if (zr->map_mjpeg_buffers) { - /* Map the MJPEG buffers */ - - if (!zr->jpg_buffers_allocated) { - return -ENOMEM; - } - if (size > zr->jpg_nbufs * zr->jpg_bufsize) { - return -EINVAL; - } - - for (i = 0; i < zr->jpg_nbufs; i++) { - for (j = 0; j < zr->jpg_bufsize / PAGE_SIZE; j++) { - fraglen = (zr->jpg_gbuf[i].frag_tab[2 * j + 1] & ~1) << 1; - todo = size; - if (todo > fraglen) - todo = fraglen; - pos = (unsigned long) zr->jpg_gbuf[i].frag_tab[2 * j]; - page = virt_to_phys(bus_to_virt(pos)); /* should just be pos on i386 */ - if (remap_page_range(start, page, todo, PAGE_SHARED)) { - printk(KERN_ERR "%s: zoran_mmap(V4L): remap_page_range failed\n", zr->name); - return -EAGAIN; - } - size -= todo; - start += todo; - if (size == 0) - break; - if (zr->jpg_gbuf[i].frag_tab[2 * j + 1] & 1) - break; /* was last fragment */ - } - if (size == 0) - break; - } - } else { - /* Map the V4L buffers */ - - if (size > v4l_nbufs * v4l_bufsize) { - return -EINVAL; - } - - for (i = 0; i < v4l_nbufs; i++) { - todo = size; - if (todo > v4l_bufsize) - todo = v4l_bufsize; - page = zr->v4l_gbuf[i].fbuffer_phys; - DEBUG(printk("V4L remap page range %d 0x%x %d to 0x%x\n", i, page, todo, start)); - if (remap_page_range(start, page, todo, PAGE_SHARED)) { - printk(KERN_ERR "%s: zoran_mmap(V4L): remap_page_range failed\n", zr->name); - return -EAGAIN; - } - size -= todo; - start += todo; - if (size == 0) - break; - } - } - return 0; -} - -static struct video_device zoran_template = -{ - owner: THIS_MODULE, - name: BUZ_NAME, - type: VID_TYPE_CAPTURE | VID_TYPE_OVERLAY | VID_TYPE_CLIPPING | VID_TYPE_FRAMERAM | - VID_TYPE_SCALES | VID_TYPE_SUBCAPTURE, - hardware: VID_HARDWARE_ZR36067, - open: zoran_open, - close: zoran_close, - read: zoran_read, - write: zoran_write, - ioctl: zoran_ioctl, - mmap: zoran_mmap, -}; - -static int zr36057_init(int i) -{ - struct zoran *zr = &zoran[i]; - unsigned long mem; - unsigned mem_needed; - int j; - int rev; - - /* reset zr36057 */ - btwrite(0, ZR36057_SPGPPCR); - mdelay(10); - - /* default setup of all parameters which will persist beetween opens */ - - zr->user = 0; - - init_waitqueue_head(&zr->v4l_capq); - init_waitqueue_head(&zr->jpg_capq); - - zr->map_mjpeg_buffers = 0; /* Map V4L buffers by default */ - - zr->jpg_nbufs = 0; - zr->jpg_bufsize = 0; - zr->jpg_buffers_allocated = 0; - - zr->buffer_set = 0; /* Flag if frame buffer has been set */ - zr->buffer.base = (void *) vidmem; - zr->buffer.width = 0; - zr->buffer.height = 0; - zr->buffer.depth = 0; - zr->buffer.bytesperline = 0; - - zr->params.norm = default_norm ? 1 : 0; /* Avoid nonsense settings from user */ - zr->params.input = default_input ? 1 : 0; /* Avoid nonsense settings from user */ - zr->video_interlace = 0; - - /* Should the following be reset at every open ? */ - - zr->picture.colour = 32768; - zr->picture.brightness = 32768; - zr->picture.hue = 32768; - zr->picture.contrast = 32768; - zr->picture.whiteness = 0; - zr->picture.depth = 0; - zr->picture.palette = 0; - - for (j = 0; j < VIDEO_MAX_FRAME; j++) { - zr->v4l_gbuf[i].fbuffer = 0; - zr->v4l_gbuf[i].fbuffer_phys = 0; - zr->v4l_gbuf[i].fbuffer_bus = 0; - } - - zr->stat_com = 0; - - /* default setup (will be repeated at every open) */ - - zoran_open_init_params(zr); - - /* allocate memory *before* doing anything to the hardware in case allocation fails */ - - /* STAT_COM table and overlay mask */ - - mem_needed = (BUZ_NUM_STAT_COM + ((BUZ_MAX_WIDTH + 31) / 32) * BUZ_MAX_HEIGHT) * 4; - mem = (unsigned long) kmalloc(mem_needed, GFP_KERNEL); - if (!mem) { - return -ENOMEM; - } - memset((void *) mem, 0, mem_needed); - - zr->stat_com = (u32 *) mem; - for (j = 0; j < BUZ_NUM_STAT_COM; j++) { - zr->stat_com[j] = 1; /* mark as unavailable to zr36057 */ - } - zr->overlay_mask = (u32 *) (mem + BUZ_NUM_STAT_COM * 4); - - /* Initialize zr->jpg_gbuf */ - - for (j = 0; j < BUZ_MAX_FRAME; j++) { - zr->jpg_gbuf[j].frag_tab = 0; - zr->jpg_gbuf[j].frag_tab_bus = 0; - zr->jpg_gbuf[j].state = BUZ_STATE_USER; - zr->jpg_gbuf[j].bs.frame = j; - } - - /* take zr36057 out of reset now */ - btwrite(ZR36057_SPGPPCR_SoftReset, ZR36057_SPGPPCR); - mdelay(10); - - /* stop all DMA processes */ - btwrite(ZR36057_MCTCR_CFlush, ZR36057_MCTCR); - btand(~ZR36057_VDCR_VidEn, ZR36057_VDCR); - /* assert P_Reset */ - btwrite(0, ZR36057_JPC); - - switch(zr->board) - { - case BOARD_BUZ: - - /* set up GPIO direction */ - btwrite(ZR36057_SPGPPCR_SoftReset | 0, ZR36057_SPGPPCR); - - /* Set up guest bus timing - Guests 0..3 Tdur=12, Trec=3 */ - btwrite((GPIO_MASK << 24) | 0x8888, ZR36057_GPPGCR1); - mdelay(10); - - /* reset video decoder */ - - GPIO(zr, 0, 0); - mdelay(10); - GPIO(zr, 0, 1); - mdelay(10); - - /* reset JPEG codec */ - zr36060_sleep(zr, 0); - mdelay(10); - zr36060_reset(zr); - mdelay(10); - - /* display codec revision */ - if ((rev=zr36060_read_8(zr, 0x022)) == 0x33) { - printk(KERN_INFO "%s: Zoran ZR36060 (rev %d)\n", - zr->name, zr36060_read_8(zr, 0x023)); - } else { - printk(KERN_ERR "%s: Zoran ZR36060 not found (Rev=%d)\n", zr->name, rev); - kfree((void *) zr->stat_com); - return -1; - } - break; - - case BOARD_LML33: -// btwrite(btread(ZR36057_SPGPPCR)&~ZR36057_SPGPPCR_SoftReset , ZR36057_SPGPPCR); -// udelay(100); -// btwrite(btread(ZR36057_SPGPPCR)|ZR36057_SPGPPCR_SoftReset , ZR36057_SPGPPCR); -// udelay(1000); - - /* - * Set up the GPIO direction - */ - btwrite(btread(ZR36057_SPGPPCR_SoftReset)|0 , ZR36057_SPGPPCR); - /* Set up guest bus timing - Guests 0..2 Tdur=12, Trec=3 */ - btwrite(0xFF00F888, ZR36057_GPPGCR1); - mdelay(10); - GPIO(zr, 5, 0); /* Analog video bypass */ - udelay(3000); - GPIO(zr, 0, 0); /* Reset 819 */ - udelay(3000); - GPIO(zr, 0, 1); /* 819 back */ - udelay(3000); - /* reset JPEG codec */ - zr36060_sleep(zr, 0); - udelay(3000); - zr36060_reset(zr); - udelay(3000); - - /* display codec revision */ - if ((rev=zr36060_read_8(zr, 0x022)) == 0x33) { - printk(KERN_INFO "%s: Zoran ZR36060 (rev %d)\n", - zr->name, zr36060_read_8(zr, 0x023)); - } else { - printk(KERN_ERR "%s: Zoran ZR36060 not found (rev=%d)\n", zr->name, rev); - kfree((void *) zr->stat_com); - return -1; - } - break; - } - /* i2c */ - memcpy(&zr->i2c, &zoran_i2c_bus_template, sizeof(struct i2c_bus)); - sprintf(zr->i2c.name, "zoran%u", zr->id); - zr->i2c.data = zr; - if (i2c_register_bus(&zr->i2c) < 0) { - kfree((void *) zr->stat_com); - return -1; - } - /* - * Now add the template and register the device unit. - */ - memcpy(&zr->video_dev, &zoran_template, sizeof(zoran_template)); - sprintf(zr->video_dev.name, "zoran%u", zr->id); - if (video_register_device(&zr->video_dev, VFL_TYPE_GRABBER) < 0) { - i2c_unregister_bus(&zr->i2c); - kfree((void *) zr->stat_com); - return -1; - } - /* toggle JPEG codec sleep to sync PLL */ - zr36060_sleep(zr, 1); - mdelay(10); - zr36060_sleep(zr, 0); - mdelay(10); - - /* Enable bus-mastering */ - pci_set_master(zr->pci_dev); - - j = zr->params.input == 0 ? 3 : 7; - i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_INPUT, &j); - i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_NORM, &zr->params.norm); - i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEOENCODER, ENCODER_SET_NORM, &zr->params.norm); - - /* set individual interrupt enables (without GIRQ0) - but don't global enable until zoran_open() */ - - btwrite(IRQ_MASK & ~ZR36057_ISR_GIRQ0, ZR36057_ICR); - - if(request_irq(zr->pci_dev->irq, zoran_irq, - SA_SHIRQ | SA_INTERRUPT, zr->name, (void *) zr)<0) - { - printk(KERN_ERR "%s: Can't assign irq.\n", zr->name); - video_unregister_device(&zr->video_dev); - i2c_unregister_bus(&zr->i2c); - kfree((void *) zr->stat_com); - return -1; - } - zr->initialized = 1; - return 0; -} - - - -static void release_zoran(void) -{ - u8 command; - int i; - struct zoran *zr; - - for (i = 0; i < zoran_num; i++) { - zr = &zoran[i]; - - if (!zr->initialized) - continue; - - /* unregister i2c_bus */ - i2c_unregister_bus((&zr->i2c)); - - /* disable PCI bus-mastering */ - pci_read_config_byte(zr->pci_dev, PCI_COMMAND, &command); - command &= ~PCI_COMMAND_MASTER; - pci_write_config_byte(zr->pci_dev, PCI_COMMAND, command); - - /* put chip into reset */ - btwrite(0, ZR36057_SPGPPCR); - - free_irq(zr->pci_dev->irq, zr); - - /* unmap and free memory */ - - kfree((void *) zr->stat_com); - - iounmap(zr->zr36057_mem); - - video_unregister_device(&zr->video_dev); - } -} - -/* - * Scan for a Buz card (actually for the PCI controller ZR36057), - * request the irq and map the io memory - */ - -static int find_zr36057(void) -{ - unsigned char latency; - struct zoran *zr; - struct pci_dev *dev = NULL; - - zoran_num = 0; - - while (zoran_num < BUZ_MAX - && (dev = pci_find_device(PCI_VENDOR_ID_ZORAN, PCI_DEVICE_ID_ZORAN_36057, dev)) != NULL) { - zr = &zoran[zoran_num]; - zr->pci_dev = dev; - zr->zr36057_mem = NULL; - zr->id = zoran_num; - sprintf(zr->name, "zoran%u", zr->id); - - spin_lock_init(&zr->lock); - - if (pci_enable_device(dev)) - continue; - - zr->zr36057_adr = pci_resource_start(zr->pci_dev, 0); - pci_read_config_byte(zr->pci_dev, PCI_CLASS_REVISION, &zr->revision); - if (zr->revision < 2) { - printk(KERN_INFO "%s: Zoran ZR36057 (rev %d) irq: %d, memory: 0x%08x.\n", - zr->name, zr->revision, zr->pci_dev->irq, zr->zr36057_adr); - } else { - unsigned short ss_vendor_id, ss_id; - - ss_vendor_id = zr->pci_dev->subsystem_vendor; - ss_id = zr->pci_dev->subsystem_device; - printk(KERN_INFO "%s: Zoran ZR36067 (rev %d) irq: %d, memory: 0x%08x\n", - zr->name, zr->revision, zr->pci_dev->irq, zr->zr36057_adr); - printk(KERN_INFO "%s: subsystem vendor=0x%04x id=0x%04x\n", - zr->name, ss_vendor_id, ss_id); - if(ss_vendor_id==0xFF10 && ss_id == 0xDE41) - { - zr->board = BOARD_LML33; - printk(KERN_INFO "%s: LML33 detected.\n", zr->name); - } - } - - zr->zr36057_mem = ioremap(zr->zr36057_adr, 0x1000); - if (!zr->zr36057_mem) { - printk(KERN_ERR "%s: ioremap failed\n", zr->name); - break; - } - - /* set PCI latency timer */ - pci_read_config_byte(zr->pci_dev, PCI_LATENCY_TIMER, &latency); - if (latency != 48) { - printk(KERN_INFO "%s: Changing PCI latency from %d to 48.\n", zr->name, latency); - latency = 48; - pci_write_config_byte(zr->pci_dev, PCI_LATENCY_TIMER, latency); - } - zoran_num++; - } - if (zoran_num == 0) - printk(KERN_INFO "zoran: no cards found.\n"); - - return zoran_num; -} - -static void handle_chipset(void) -{ - if(pci_pci_problems&PCIPCI_FAIL) - { - printk(KERN_WARNING "buz: This configuration is known to have PCI to PCI DMA problems\n"); - printk(KERN_WARNING "buz: You may not be able to use overlay mode.\n"); - } - - - if(pci_pci_problems&PCIPCI_TRITON) - { - printk("buz: Enabling Triton support.\n"); - triton = 1; - } - - if(pci_pci_problems&PCIPCI_NATOMA) - { - printk("buz: Enabling Natoma workaround.\n"); - natoma = 1; - } -} - -#ifdef MODULE -int init_module(void) -#else -int init_zoran_cards(struct video_init *unused) -#endif -{ - int i; - - - printk(KERN_INFO "Zoran driver 1.00 (c) 1999 Rainer Johanni, Dave Perks.\n"); - - /* Look for Buz cards */ - - if (find_zr36057() <= 0) { - return -EIO; - } - printk(KERN_INFO"zoran: %d zoran card(s) found\n", zoran_num); - - if (zoran_num == 0) - return -ENXIO; - - - /* check the parameters we have been given, adjust if necessary */ - - if (v4l_nbufs < 0) - v4l_nbufs = 0; - if (v4l_nbufs > VIDEO_MAX_FRAME) - v4l_nbufs = VIDEO_MAX_FRAME; - /* The user specfies the in KB, we want them in byte (and page aligned) */ - v4l_bufsize = PAGE_ALIGN(v4l_bufsize * 1024); - if (v4l_bufsize < 32768) - v4l_bufsize = 32768; - /* 2 MB is arbitrary but sufficient for the maximum possible images */ - if (v4l_bufsize > 2048 * 1024) - v4l_bufsize = 2048 * 1024; - - printk(KERN_INFO "zoran: using %d V4L buffers of size %d KB\n", v4l_nbufs, v4l_bufsize >> 10); - - /* Use parameter for vidmem or try to find a video card */ - - if (vidmem) { - printk(KERN_INFO "zoran: Using supplied video memory base address @ 0x%lx\n", vidmem); - } - - /* check if we have a Triton or Natome chipset */ - - handle_chipset(); - - /* take care of Natoma chipset and a revision 1 zr36057 */ - - for (i = 0; i < zoran_num; i++) { - if (natoma && zoran[i].revision <= 1) { - zoran[i].need_contiguous = 1; - printk(KERN_INFO "%s: ZR36057/Natome bug, max. buffer size is 128K\n", zoran[i].name); - } else { - zoran[i].need_contiguous = 0; - } - } - - /* initialize the Buzs */ - - /* We have to know which ones must be released if an error occurs */ - for (i = 0; i < zoran_num; i++) - zoran[i].initialized = 0; - - for (i = 0; i < zoran_num; i++) { - if (zr36057_init(i) < 0) { - release_zoran(); - return -EIO; - } - } - - return 0; -} - - - -#ifdef MODULE - -void cleanup_module(void) -{ - release_zoran(); -} - -#endif diff -u --recursive --new-file v2.4.6/linux/drivers/media/video/buz.h linux/drivers/media/video/buz.h --- v2.4.6/linux/drivers/media/video/buz.h Mon Dec 11 13:15:49 2000 +++ linux/drivers/media/video/buz.h Wed Dec 31 16:00:00 1969 @@ -1,319 +0,0 @@ -/* - buz - Iomega Buz driver - - Copyright (C) 1999 Rainer Johanni <Rainer@Johanni.de> - - based on - - buz.0.0.3 Copyright (C) 1998 Dave Perks <dperks@ibm.net> - - and - - bttv - Bt848 frame grabber driver - Copyright (C) 1996,97 Ralph Metzler (rjkm@thp.uni-koeln.de) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifndef _BUZ_H_ -#define _BUZ_H_ - -/* The Buz only supports a maximum width of 720, but some V4L - applications (e.g. xawtv are more happy with 768). - If XAWTV_HACK is defined, we try to fake a device with bigger width */ - -#define XAWTV_HACK - -#ifdef XAWTV_HACK -#define BUZ_MAX_WIDTH 768 /* never display more than 768 pixels */ -#else -#define BUZ_MAX_WIDTH 720 /* never display more than 720 pixels */ -#endif -#define BUZ_MAX_HEIGHT 576 /* never display more than 576 rows */ -#define BUZ_MIN_WIDTH 32 /* never display less than 32 pixels */ -#define BUZ_MIN_HEIGHT 24 /* never display less than 24 rows */ - -struct zoran_requestbuffers { - unsigned long count; /* Number of buffers for MJPEG grabbing */ - unsigned long size; /* Size PER BUFFER in bytes */ -}; - -struct zoran_sync { - unsigned long frame; /* number of buffer that has been free'd */ - unsigned long length; /* number of code bytes in buffer (capture only) */ - unsigned long seq; /* frame sequence number */ - struct timeval timestamp; /* timestamp */ -}; - -struct zoran_status { - int input; /* Input channel, has to be set prior to BUZIOC_G_STATUS */ - int signal; /* Returned: 1 if valid video signal detected */ - int norm; /* Returned: VIDEO_MODE_PAL or VIDEO_MODE_NTSC */ - int color; /* Returned: 1 if color signal detected */ -}; - -struct zoran_params { - - /* The following parameters can only be queried */ - - int major_version; /* Major version number of driver */ - int minor_version; /* Minor version number of driver */ - - /* Main control parameters */ - - int input; /* Input channel: 0 = Composite, 1 = S-VHS */ - int norm; /* Norm: VIDEO_MODE_PAL or VIDEO_MODE_NTSC */ - int decimation; /* decimation of captured video, - enlargement of video played back. - Valid values are 1, 2, 4 or 0. - 0 is a special value where the user - has full control over video scaling */ - - /* The following parameters only have to be set if decimation==0, - for other values of decimation they provide the data how the image is captured */ - - int HorDcm; /* Horizontal decimation: 1, 2 or 4 */ - int VerDcm; /* Vertical decimation: 1 or 2 */ - int TmpDcm; /* Temporal decimation: 1 or 2, - if TmpDcm==2 in capture every second frame is dropped, - in playback every frame is played twice */ - int field_per_buff; /* Number of fields per buffer: 1 or 2 */ - int img_x; /* start of image in x direction */ - int img_y; /* start of image in y direction */ - int img_width; /* image width BEFORE decimation, - must be a multiple of HorDcm*16 */ - int img_height; /* image height BEFORE decimation, - must be a multiple of VerDcm*8 */ - - /* --- End of parameters for decimation==0 only --- */ - - /* JPEG control parameters */ - - int quality; /* Measure for quality of compressed images. - Scales linearly with the size of the compressed images. - Must be beetween 0 and 100, 100 is a compression - ratio of 1:4 */ - - int odd_even; /* Which field should come first ??? */ - - int APPn; /* Number of APP segment to be written, must be 0..15 */ - int APP_len; /* Length of data in JPEG APPn segment */ - char APP_data[60]; /* Data in the JPEG APPn segment. */ - - int COM_len; /* Length of data in JPEG COM segment */ - char COM_data[60]; /* Data in JPEG COM segment */ - - unsigned long jpeg_markers; /* Which markers should go into the JPEG output. - Unless you exactly know what you do, leave them untouched. - Inluding less markers will make the resulting code - smaller, but there will be fewer aplications - which can read it. - The presence of the APP and COM marker is - influenced by APP0_len and COM_len ONLY! */ -#define JPEG_MARKER_DHT (1<<3) /* Define Huffman Tables */ -#define JPEG_MARKER_DQT (1<<4) /* Define Quantization Tables */ -#define JPEG_MARKER_DRI (1<<5) /* Define Restart Interval */ -#define JPEG_MARKER_COM (1<<6) /* Comment segment */ -#define JPEG_MARKER_APP (1<<7) /* App segment, driver will allways use APP0 */ - - int VFIFO_FB; /* Flag for enabling Video Fifo Feedback. - If this flag is turned on and JPEG decompressing - is going to the screen, the decompress process - is stopped every time the Video Fifo is full. - This enables a smooth decompress to the screen - but the video output signal will get scrambled */ - - /* Misc */ - - char reserved[312]; /* Makes 512 bytes for this structure */ -}; - -/* - Private IOCTL to set up for displaying MJPEG - */ -#define BUZIOC_G_PARAMS _IOR ('v', BASE_VIDIOCPRIVATE+0, struct zoran_params) -#define BUZIOC_S_PARAMS _IOWR('v', BASE_VIDIOCPRIVATE+1, struct zoran_params) -#define BUZIOC_REQBUFS _IOWR('v', BASE_VIDIOCPRIVATE+2, struct zoran_requestbuffers) -#define BUZIOC_QBUF_CAPT _IOW ('v', BASE_VIDIOCPRIVATE+3, int) -#define BUZIOC_QBUF_PLAY _IOW ('v', BASE_VIDIOCPRIVATE+4, int) -#define BUZIOC_SYNC _IOR ('v', BASE_VIDIOCPRIVATE+5, struct zoran_sync) -#define BUZIOC_G_STATUS _IOWR('v', BASE_VIDIOCPRIVATE+6, struct zoran_status) - - -#ifdef __KERNEL__ - -#define BUZ_NUM_STAT_COM 4 -#define BUZ_MASK_STAT_COM 3 - -#define BUZ_MAX_FRAME 256 /* Must be a power of 2 */ -#define BUZ_MASK_FRAME 255 /* Must be BUZ_MAX_FRAME-1 */ - -#if VIDEO_MAX_FRAME <= 32 -#define V4L_MAX_FRAME 32 -#elif VIDEO_MAX_FRAME <= 64 -#define V4L_MAX_FRAME 64 -#else -#error "Too many video frame buffers to handle" -#endif -#define V4L_MASK_FRAME (V4L_MAX_FRAME - 1) - - -#include "zr36057.h" - -enum zoran_codec_mode { - BUZ_MODE_IDLE, /* nothing going on */ - BUZ_MODE_MOTION_COMPRESS, /* grabbing frames */ - BUZ_MODE_MOTION_DECOMPRESS, /* playing frames */ - BUZ_MODE_STILL_COMPRESS, /* still frame conversion */ - BUZ_MODE_STILL_DECOMPRESS /* still frame conversion */ -}; - -enum zoran_buffer_state { - BUZ_STATE_USER, /* buffer is owned by application */ - BUZ_STATE_PEND, /* buffer is queued in pend[] ready to feed to I/O */ - BUZ_STATE_DMA, /* buffer is queued in dma[] for I/O */ - BUZ_STATE_DONE /* buffer is ready to return to application */ -}; - -struct zoran_gbuffer { - u32 *frag_tab; /* addresses of frag table */ - u32 frag_tab_bus; /* same value cached to save time in ISR */ - enum zoran_buffer_state state; /* non-zero if corresponding buffer is in use in grab queue */ - struct zoran_sync bs; /* DONE: info to return to application */ -}; - -struct v4l_gbuffer { - char *fbuffer; /* virtual address of frame buffer */ - unsigned long fbuffer_phys; /* physical address of frame buffer */ - unsigned long fbuffer_bus; /* bus address of frame buffer */ - enum zoran_buffer_state state; /* state: unused/pending/done */ -}; - -struct zoran { - struct video_device video_dev; - struct i2c_bus i2c; - - int initialized; /* flag if zoran has been correctly initalized */ - int user; /* number of current users (0 or 1) */ - - unsigned short id; /* number of this device */ - char name[32]; /* name of this device */ - struct pci_dev *pci_dev; /* PCI device */ - unsigned char revision; /* revision of zr36057 */ - int board; /* Board type */ -#define BOARD_BUZ 0 -#define BOARD_LML33 1 - unsigned int zr36057_adr; /* bus address of IO mem returned by PCI BIOS */ - unsigned char *zr36057_mem; /* pointer to mapped IO memory */ - - int map_mjpeg_buffers; /* Flag which bufferset will map by next mmap() */ - - spinlock_t lock; /* Spinlock */ - - /* Video for Linux parameters */ - - struct video_picture picture; /* Current picture params */ - struct video_buffer buffer; /* Current buffer params */ - struct video_window window; /* Current window params */ - int buffer_set, window_set; /* Flags if the above structures are set */ - int video_interlace; /* Image on screen is interlaced */ - - u32 *overlay_mask; - - wait_queue_head_t v4l_capq; /* wait here for grab to finish */ - - int v4l_overlay_active; /* Overlay grab is activated */ - int v4l_memgrab_active; /* Memory grab is activated */ - - int v4l_grab_frame; /* Frame number being currently grabbed */ -#define NO_GRAB_ACTIVE (-1) - int v4l_grab_seq; /* Number of frames grabbed */ - int gwidth; /* Width of current memory capture */ - int gheight; /* Height of current memory capture */ - int gformat; /* Format of ... */ - int gbpl; /* byte per line of ... */ - - /* V4L grab queue of frames pending */ - - unsigned v4l_pend_head; - unsigned v4l_pend_tail; - int v4l_pend[V4L_MAX_FRAME]; - - struct v4l_gbuffer v4l_gbuf[VIDEO_MAX_FRAME]; /* V4L buffers' info */ - - /* Buz MJPEG parameters */ - - unsigned long jpg_nbufs; /* Number of buffers */ - unsigned long jpg_bufsize; /* Size of mjpeg buffers in bytes */ - int jpg_buffers_allocated; /* Flag if buffers are allocated */ - int need_contiguous; /* Flag if contiguous buffers are needed */ - - enum zoran_codec_mode codec_mode; /* status of codec */ - struct zoran_params params; /* structure with a lot of things to play with */ - - wait_queue_head_t jpg_capq; /* wait here for grab to finish */ - - /* grab queue counts/indices, mask with BUZ_MASK_STAT_COM before using as index */ - /* (dma_head - dma_tail) is number active in DMA, must be <= BUZ_NUM_STAT_COM */ - /* (value & BUZ_MASK_STAT_COM) corresponds to index in stat_com table */ - unsigned long jpg_que_head; /* Index where to put next buffer which is queued */ - unsigned long jpg_dma_head; /* Index of next buffer which goes into stat_com */ - unsigned long jpg_dma_tail; /* Index of last buffer in stat_com */ - unsigned long jpg_que_tail; /* Index of last buffer in queue */ - unsigned long jpg_seq_num; /* count of frames since grab/play started */ - - /* zr36057's code buffer table */ - u32 *stat_com; /* stat_com[i] is indexed by dma_head/tail & BUZ_MASK_STAT_COM */ - - /* (value & BUZ_MASK_FRAME) corresponds to index in pend[] queue */ - int jpg_pend[BUZ_MAX_FRAME]; - - /* array indexed by frame number */ - struct zoran_gbuffer jpg_gbuf[BUZ_MAX_FRAME]; /* MJPEG buffers' info */ -}; - -#endif - -/*The following should be done in more portable way. It depends on define - of _ALPHA_BUZ in the Makefile. */ - -#ifdef _ALPHA_BUZ -#define btwrite(dat,adr) writel((dat),(char *) (zr->zr36057_adr+(adr))) -#define btread(adr) readl(zr->zr36057_adr+(adr)) -#else -#define btwrite(dat,adr) writel((dat), (char *) (zr->zr36057_mem+(adr))) -#define btread(adr) readl(zr->zr36057_mem+(adr)) -#endif - -#define btand(dat,adr) btwrite((dat) & btread(adr), adr) -#define btor(dat,adr) btwrite((dat) | btread(adr), adr) -#define btaor(dat,mask,adr) btwrite((dat) | ((mask) & btread(adr)), adr) - -#define I2C_TSA5522 0xc2 -#define I2C_TDA9850 0xb6 -#define I2C_HAUPEE 0xa0 -#define I2C_STBEE 0xae -#define I2C_SAA7111 0x48 -#define I2C_SAA7185 0x88 - -#define TDA9850_CON1 0x04 -#define TDA9850_CON2 0x05 -#define TDA9850_CON3 0x06 -#define TDA9850_CON4 0x07 -#define TDA9850_ALI1 0x08 -#define TDA9850_ALI2 0x09 -#define TDA9850_ALI3 0x0a - -#endif diff -u --recursive --new-file v2.4.6/linux/drivers/media/video/meye.c linux/drivers/media/video/meye.c --- v2.4.6/linux/drivers/media/video/meye.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/media/video/meye.c Wed Jul 4 14:41:33 2001 @@ -0,0 +1,1498 @@ +/* + * Motion Eye video4linux driver for Sony Vaio PictureBook + * + * Copyright (C) 2001 Stelian Pop <stelian.pop@fr.alcove.com>, Alcôve + * + * Copyright (C) 2000 Andrew Tridgell <tridge@valinux.com> + * + * Earlier work by Werner Almesberger, Paul `Rusty' Russell and Paul Mackerras. + * + * Some parts borrowed from various video4linux drivers, especially + * bttv-driver.c and zoran.c, see original files for credits. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include <linux/config.h> +#include <linux/module.h> +#include <linux/pci.h> +#include <linux/sched.h> +#include <linux/init.h> +#include <linux/videodev.h> +#include <asm/uaccess.h> +#include <asm/io.h> +#include <linux/delay.h> +#include <linux/wrapper.h> +#include <linux/interrupt.h> + +#include "meye.h" +#include "linux/meye.h" + +/* driver structure - only one possible */ +static struct meye meye; +/* number of grab buffers */ +static unsigned int gbuffers = 2; +/* size of a grab buffer */ +static unsigned int gbufsize = MEYE_MAX_BUFSIZE; +/* /dev/videoX registration number */ +static int video_nr = -1; + +/****************************************************************************/ +/* Queue routines */ +/****************************************************************************/ + +/* Inits the queue */ +static inline void meye_initq(struct meye_queue *queue) { + queue->head = queue->tail = 0; + queue->len = 0; + queue->s_lock = (spinlock_t)SPIN_LOCK_UNLOCKED; + init_waitqueue_head(&queue->proc_list); +} + +/* Pulls an element from the queue */ +static inline int meye_pullq(struct meye_queue *queue) { + int result; + unsigned long flags; + + spin_lock_irqsave(&queue->s_lock, flags); + if (!queue->len) { + spin_unlock_irqrestore(&queue->s_lock, flags); + return -1; + } + result = queue->buf[queue->head]; + queue->head++; + queue->head &= (MEYE_QUEUE_SIZE - 1); + queue->len--; + spin_unlock_irqrestore(&queue->s_lock, flags); + return result; +} + +/* Pushes an element into the queue */ +static inline void meye_pushq(struct meye_queue *queue, int element) { + unsigned long flags; + + spin_lock_irqsave(&queue->s_lock, flags); + if (queue->len == MEYE_QUEUE_SIZE) { + /* remove the first element */ + queue->head++; + queue->head &= (MEYE_QUEUE_SIZE - 1); + queue->len--; + } + queue->buf[queue->tail] = element; + queue->tail++; + queue->tail &= (MEYE_QUEUE_SIZE - 1); + queue->len++; + + spin_unlock_irqrestore(&queue->s_lock, flags); +} + +/* Tests if the queue is empty */ +static inline int meye_emptyq(struct meye_queue *queue, int *elem) { + int result; + unsigned long flags; + + spin_lock_irqsave(&queue->s_lock, flags); + result = (queue->len == 0); + if (!result && elem) + *elem = queue->buf[queue->head]; + spin_unlock_irqrestore(&queue->s_lock, flags); + return result; +} + +/****************************************************************************/ +/* Memory allocation routines (stolen from bttv-driver.c) */ +/****************************************************************************/ + +#define MDEBUG(x) do {} while (0) +/* #define MDEBUG(x) x */ + +/* Given PGD from the address space's page table, return the kernel + * virtual mapping of the physical memory mapped at ADR. + */ +static inline unsigned long uvirt_to_kva(pgd_t *pgd, unsigned long adr) { + unsigned long ret = 0UL; + pmd_t *pmd; + pte_t *ptep, pte; + + if (!pgd_none(*pgd)) { + pmd = pmd_offset(pgd, adr); + if (!pmd_none(*pmd)) { + ptep = pte_offset(pmd, adr); + pte = *ptep; + if(pte_present(pte)) { + ret = (unsigned long)page_address(pte_page(pte)); + ret |= (adr & (PAGE_SIZE - 1)); + + } + } + } + MDEBUG(printk("uv2kva(%lx-->%lx)\n", adr, ret)); + return ret; +} + +static inline unsigned long uvirt_to_bus(unsigned long adr) { + unsigned long kva, ret; + + kva = uvirt_to_kva(pgd_offset(current->mm, adr), adr); + ret = virt_to_bus((void *)kva); + MDEBUG(printk("uv2b(%lx-->%lx)\n", adr, ret)); + return ret; +} + +static inline unsigned long kvirt_to_bus(unsigned long adr) { + unsigned long va, kva, ret; + + va = VMALLOC_VMADDR(adr); + kva = uvirt_to_kva(pgd_offset_k(va), va); + ret = virt_to_bus((void *)kva); + MDEBUG(printk("kv2b(%lx-->%lx)\n", adr, ret)); + return ret; +} + +/* Here we want the physical address of the memory. + * This is used when initializing the contents of the + * area and marking the pages as reserved. + */ +static inline unsigned long kvirt_to_pa(unsigned long adr) { + unsigned long va, kva, ret; + + va = VMALLOC_VMADDR(adr); + kva = uvirt_to_kva(pgd_offset_k(va), va); + ret = __pa(kva); + MDEBUG(printk("kv2pa(%lx-->%lx)\n", adr, ret)); + return ret; +} + +static void *rvmalloc(signed long size) { + void *mem; + unsigned long adr, page; + + mem = vmalloc_32(size); + if (mem) { + memset(mem, 0, size); /* Clear the ram out, no junk to the user */ + adr = (unsigned long)mem; + while (size > 0) { + page = kvirt_to_pa(adr); + mem_map_reserve(virt_to_page(__va(page))); + adr += PAGE_SIZE; + size -= PAGE_SIZE; + } + } + return mem; +} + +static void rvfree(void * mem, signed long size) { + unsigned long adr, page; + + if (mem) { + adr = (unsigned long) mem; + while (size > 0) { + page = kvirt_to_pa(adr); + mem_map_unreserve(virt_to_page(__va(page))); + adr += PAGE_SIZE; + size -= PAGE_SIZE; + } + vfree(mem); + } +} + +/* return a page table pointing to N pages of locked memory */ +static void *ptable_alloc(int npages, u32 *pt_addr) { + int i = 0; + void *vmem; + u32 ptable[npages+1]; + signed long size; + unsigned long adr; + + size = (npages + 1) * PAGE_SIZE; + vmem = rvmalloc(size); + if (!vmem) + return NULL; + + memset(ptable, 0, sizeof(ptable)); + adr = (unsigned long)vmem; + while (size > 0) { + ptable[i++] = virt_to_bus(__va(kvirt_to_pa(adr))); + adr += PAGE_SIZE; + size -= PAGE_SIZE; + } + + memcpy(vmem + npages * PAGE_SIZE, ptable, PAGE_SIZE); + *pt_addr = ptable[npages]; + + return vmem; +} + +static void ptable_free(void *vmem, int npages) { + rvfree(vmem, (npages + 1) * PAGE_SIZE); +} + +/****************************************************************************/ +/* JPEG tables at different qualities to load into the VRJ chip */ +/****************************************************************************/ + +/* return a set of quantisation tables based on a quality from 1 to 10 */ +static u16 *jpeg_quantisation_tables(int *size, int quality) { + static u16 tables0[] = { + 0xdbff, 0x4300, 0xff00, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, + 0xdbff, 0x4300, 0xff01, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, + }; + static u16 tables1[] = { + 0xdbff, 0x4300, 0x5000, 0x3c37, 0x3c46, 0x5032, 0x4146, 0x5a46, + 0x5055, 0x785f, 0x82c8, 0x6e78, 0x786e, 0xaff5, 0x91b9, 0xffc8, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, + 0xdbff, 0x4300, 0x5501, 0x5a5a, 0x6978, 0xeb78, 0x8282, 0xffeb, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, + }; + static u16 tables2[] = { + 0xdbff, 0x4300, 0x2800, 0x1e1c, 0x1e23, 0x2819, 0x2123, 0x2d23, + 0x282b, 0x3c30, 0x4164, 0x373c, 0x3c37, 0x587b, 0x495d, 0x9164, + 0x9980, 0x8f96, 0x8c80, 0xa08a, 0xe6b4, 0xa0c3, 0xdaaa, 0x8aad, + 0xc88c, 0xcbff, 0xeeda, 0xfff5, 0xffff, 0xc19b, 0xffff, 0xfaff, + 0xe6ff, 0xfffd, 0xfff8, + 0xdbff, 0x4300, 0x2b01, 0x2d2d, 0x353c, 0x763c, 0x4141, 0xf876, + 0x8ca5, 0xf8a5, 0xf8f8, 0xf8f8, 0xf8f8, 0xf8f8, 0xf8f8, 0xf8f8, + 0xf8f8, 0xf8f8, 0xf8f8, 0xf8f8, 0xf8f8, 0xf8f8, 0xf8f8, 0xf8f8, + 0xf8f8, 0xf8f8, 0xf8f8, 0xf8f8, 0xf8f8, 0xf8f8, 0xf8f8, 0xf8f8, + 0xf8f8, 0xf8f8, 0xfff8, + }; + static u16 tables3[] = { + 0xdbff, 0x4300, 0x1b00, 0x1412, 0x1417, 0x1b11, 0x1617, 0x1e17, + 0x1b1c, 0x2820, 0x2b42, 0x2528, 0x2825, 0x3a51, 0x303d, 0x6042, + 0x6555, 0x5f64, 0x5d55, 0x6a5b, 0x9978, 0x6a81, 0x9071, 0x5b73, + 0x855d, 0x86b5, 0x9e90, 0xaba3, 0xabad, 0x8067, 0xc9bc, 0xa6ba, + 0x99c7, 0xaba8, 0xffa4, + 0xdbff, 0x4300, 0x1c01, 0x1e1e, 0x2328, 0x4e28, 0x2b2b, 0xa44e, + 0x5d6e, 0xa46e, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, + 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, + 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, + 0xa4a4, 0xa4a4, 0xffa4, + }; + static u16 tables4[] = { + 0xdbff, 0x4300, 0x1400, 0x0f0e, 0x0f12, 0x140d, 0x1012, 0x1712, + 0x1415, 0x1e18, 0x2132, 0x1c1e, 0x1e1c, 0x2c3d, 0x242e, 0x4932, + 0x4c40, 0x474b, 0x4640, 0x5045, 0x735a, 0x5062, 0x6d55, 0x4556, + 0x6446, 0x6588, 0x776d, 0x817b, 0x8182, 0x604e, 0x978d, 0x7d8c, + 0x7396, 0x817e, 0xff7c, + 0xdbff, 0x4300, 0x1501, 0x1717, 0x1a1e, 0x3b1e, 0x2121, 0x7c3b, + 0x4653, 0x7c53, 0x7c7c, 0x7c7c, 0x7c7c, 0x7c7c, 0x7c7c, 0x7c7c, + 0x7c7c, 0x7c7c, 0x7c7c, 0x7c7c, 0x7c7c, 0x7c7c, 0x7c7c, 0x7c7c, + 0x7c7c, 0x7c7c, 0x7c7c, 0x7c7c, 0x7c7c, 0x7c7c, 0x7c7c, 0x7c7c, + 0x7c7c, 0x7c7c, 0xff7c, + }; + static u16 tables5[] = { + 0xdbff, 0x4300, 0x1000, 0x0c0b, 0x0c0e, 0x100a, 0x0d0e, 0x120e, + 0x1011, 0x1813, 0x1a28, 0x1618, 0x1816, 0x2331, 0x1d25, 0x3a28, + 0x3d33, 0x393c, 0x3833, 0x4037, 0x5c48, 0x404e, 0x5744, 0x3745, + 0x5038, 0x516d, 0x5f57, 0x6762, 0x6768, 0x4d3e, 0x7971, 0x6470, + 0x5c78, 0x6765, 0xff63, + 0xdbff, 0x4300, 0x1101, 0x1212, 0x1518, 0x2f18, 0x1a1a, 0x632f, + 0x3842, 0x6342, 0x6363, 0x6363, 0x6363, 0x6363, 0x6363, 0x6363, + 0x6363, 0x6363, 0x6363, 0x6363, 0x6363, 0x6363, 0x6363, 0x6363, + 0x6363, 0x6363, 0x6363, 0x6363, 0x6363, 0x6363, 0x6363, 0x6363, + 0x6363, 0x6363, 0xff63, + }; + static u16 tables6[] = { + 0xdbff, 0x4300, 0x0d00, 0x0a09, 0x0a0b, 0x0d08, 0x0a0b, 0x0e0b, + 0x0d0e, 0x130f, 0x1520, 0x1213, 0x1312, 0x1c27, 0x171e, 0x2e20, + 0x3129, 0x2e30, 0x2d29, 0x332c, 0x4a3a, 0x333e, 0x4636, 0x2c37, + 0x402d, 0x4157, 0x4c46, 0x524e, 0x5253, 0x3e32, 0x615a, 0x505a, + 0x4a60, 0x5251, 0xff4f, + 0xdbff, 0x4300, 0x0e01, 0x0e0e, 0x1113, 0x2613, 0x1515, 0x4f26, + 0x2d35, 0x4f35, 0x4f4f, 0x4f4f, 0x4f4f, 0x4f4f, 0x4f4f, 0x4f4f, + 0x4f4f, 0x4f4f, 0x4f4f, 0x4f4f, 0x4f4f, 0x4f4f, 0x4f4f, 0x4f4f, + 0x4f4f, 0x4f4f, 0x4f4f, 0x4f4f, 0x4f4f, 0x4f4f, 0x4f4f, 0x4f4f, + 0x4f4f, 0x4f4f, 0xff4f, + }; + static u16 tables7[] = { + 0xdbff, 0x4300, 0x0a00, 0x0707, 0x0708, 0x0a06, 0x0808, 0x0b08, + 0x0a0a, 0x0e0b, 0x1018, 0x0d0e, 0x0e0d, 0x151d, 0x1116, 0x2318, + 0x251f, 0x2224, 0x221f, 0x2621, 0x372b, 0x262f, 0x3429, 0x2129, + 0x3022, 0x3141, 0x3934, 0x3e3b, 0x3e3e, 0x2e25, 0x4944, 0x3c43, + 0x3748, 0x3e3d, 0xff3b, + 0xdbff, 0x4300, 0x0a01, 0x0b0b, 0x0d0e, 0x1c0e, 0x1010, 0x3b1c, + 0x2228, 0x3b28, 0x3b3b, 0x3b3b, 0x3b3b, 0x3b3b, 0x3b3b, 0x3b3b, + 0x3b3b, 0x3b3b, 0x3b3b, 0x3b3b, 0x3b3b, 0x3b3b, 0x3b3b, 0x3b3b, + 0x3b3b, 0x3b3b, 0x3b3b, 0x3b3b, 0x3b3b, 0x3b3b, 0x3b3b, 0x3b3b, + 0x3b3b, 0x3b3b, 0xff3b, + }; + static u16 tables8[] = { + 0xdbff, 0x4300, 0x0600, 0x0504, 0x0506, 0x0604, 0x0506, 0x0706, + 0x0607, 0x0a08, 0x0a10, 0x090a, 0x0a09, 0x0e14, 0x0c0f, 0x1710, + 0x1814, 0x1718, 0x1614, 0x1a16, 0x251d, 0x1a1f, 0x231b, 0x161c, + 0x2016, 0x202c, 0x2623, 0x2927, 0x292a, 0x1f19, 0x302d, 0x282d, + 0x2530, 0x2928, 0xff28, + 0xdbff, 0x4300, 0x0701, 0x0707, 0x080a, 0x130a, 0x0a0a, 0x2813, + 0x161a, 0x281a, 0x2828, 0x2828, 0x2828, 0x2828, 0x2828, 0x2828, + 0x2828, 0x2828, 0x2828, 0x2828, 0x2828, 0x2828, 0x2828, 0x2828, + 0x2828, 0x2828, 0x2828, 0x2828, 0x2828, 0x2828, 0x2828, 0x2828, + 0x2828, 0x2828, 0xff28, + }; + static u16 tables9[] = { + 0xdbff, 0x4300, 0x0300, 0x0202, 0x0203, 0x0302, 0x0303, 0x0403, + 0x0303, 0x0504, 0x0508, 0x0405, 0x0504, 0x070a, 0x0607, 0x0c08, + 0x0c0a, 0x0b0c, 0x0b0a, 0x0d0b, 0x120e, 0x0d10, 0x110e, 0x0b0e, + 0x100b, 0x1016, 0x1311, 0x1514, 0x1515, 0x0f0c, 0x1817, 0x1416, + 0x1218, 0x1514, 0xff14, + 0xdbff, 0x4300, 0x0301, 0x0404, 0x0405, 0x0905, 0x0505, 0x1409, + 0x0b0d, 0x140d, 0x1414, 0x1414, 0x1414, 0x1414, 0x1414, 0x1414, + 0x1414, 0x1414, 0x1414, 0x1414, 0x1414, 0x1414, 0x1414, 0x1414, + 0x1414, 0x1414, 0x1414, 0x1414, 0x1414, 0x1414, 0x1414, 0x1414, + 0x1414, 0x1414, 0xff14, + }; + static u16 tables10[] = { + 0xdbff, 0x4300, 0x0100, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, + 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, + 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, + 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, + 0x0101, 0x0101, 0xff01, + 0xdbff, 0x4300, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, + 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, + 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, + 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, + 0x0101, 0x0101, 0xff01, + }; + + switch (quality) { + case 0: + *size = sizeof(tables0); + return tables0; + case 1: + *size = sizeof(tables1); + return tables1; + case 2: + *size = sizeof(tables2); + return tables2; + case 3: + *size = sizeof(tables3); + return tables3; + case 4: + *size = sizeof(tables4); + return tables4; + case 5: + *size = sizeof(tables5); + return tables5; + case 6: + *size = sizeof(tables6); + return tables6; + case 7: + *size = sizeof(tables7); + return tables7; + case 8: + *size = sizeof(tables8); + return tables8; + case 9: + *size = sizeof(tables9); + return tables9; + case 10: + *size = sizeof(tables10); + return tables10; + default: + printk(KERN_WARNING "meye: invalid quality level %d - using 8\n", quality); + *size = sizeof(tables8); + return tables8; + } + return NULL; +} + +/* return a generic set of huffman tables */ +static u16 *jpeg_huffman_tables(int *size) { + static u16 tables[] = { + 0xC4FF, 0xB500, 0x0010, 0x0102, 0x0303, 0x0402, 0x0503, 0x0405, + 0x0004, 0x0100, 0x017D, 0x0302, 0x0400, 0x0511, 0x2112, 0x4131, + 0x1306, 0x6151, 0x2207, 0x1471, 0x8132, 0xA191, 0x2308, 0xB142, + 0x15C1, 0xD152, 0x24F0, 0x6233, 0x8272, 0x0A09, 0x1716, 0x1918, + 0x251A, 0x2726, 0x2928, 0x342A, 0x3635, 0x3837, 0x3A39, 0x4443, + 0x4645, 0x4847, 0x4A49, 0x5453, 0x5655, 0x5857, 0x5A59, 0x6463, + 0x6665, 0x6867, 0x6A69, 0x7473, 0x7675, 0x7877, 0x7A79, 0x8483, + 0x8685, 0x8887, 0x8A89, 0x9392, 0x9594, 0x9796, 0x9998, 0xA29A, + 0xA4A3, 0xA6A5, 0xA8A7, 0xAAA9, 0xB3B2, 0xB5B4, 0xB7B6, 0xB9B8, + 0xC2BA, 0xC4C3, 0xC6C5, 0xC8C7, 0xCAC9, 0xD3D2, 0xD5D4, 0xD7D6, + 0xD9D8, 0xE1DA, 0xE3E2, 0xE5E4, 0xE7E6, 0xE9E8, 0xF1EA, 0xF3F2, + 0xF5F4, 0xF7F6, 0xF9F8, 0xFFFA, + 0xC4FF, 0xB500, 0x0011, 0x0102, 0x0402, 0x0304, 0x0704, 0x0405, + 0x0004, 0x0201, 0x0077, 0x0201, 0x1103, 0x0504, 0x3121, 0x1206, + 0x5141, 0x6107, 0x1371, 0x3222, 0x0881, 0x4214, 0xA191, 0xC1B1, + 0x2309, 0x5233, 0x15F0, 0x7262, 0x0AD1, 0x2416, 0xE134, 0xF125, + 0x1817, 0x1A19, 0x2726, 0x2928, 0x352A, 0x3736, 0x3938, 0x433A, + 0x4544, 0x4746, 0x4948, 0x534A, 0x5554, 0x5756, 0x5958, 0x635A, + 0x6564, 0x6766, 0x6968, 0x736A, 0x7574, 0x7776, 0x7978, 0x827A, + 0x8483, 0x8685, 0x8887, 0x8A89, 0x9392, 0x9594, 0x9796, 0x9998, + 0xA29A, 0xA4A3, 0xA6A5, 0xA8A7, 0xAAA9, 0xB3B2, 0xB5B4, 0xB7B6, + 0xB9B8, 0xC2BA, 0xC4C3, 0xC6C5, 0xC8C7, 0xCAC9, 0xD3D2, 0xD5D4, + 0xD7D6, 0xD9D8, 0xE2DA, 0xE4E3, 0xE6E5, 0xE8E7, 0xEAE9, 0xF3F2, + 0xF5F4, 0xF7F6, 0xF9F8, 0xFFFA, + 0xC4FF, 0x1F00, 0x0000, 0x0501, 0x0101, 0x0101, 0x0101, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0201, 0x0403, 0x0605, 0x0807, 0x0A09, + 0xFF0B, + 0xC4FF, 0x1F00, 0x0001, 0x0103, 0x0101, 0x0101, 0x0101, 0x0101, + 0x0000, 0x0000, 0x0000, 0x0201, 0x0403, 0x0605, 0x0807, 0x0A09, + 0xFF0B + }; + + *size = sizeof(tables); + return tables; +} + +/****************************************************************************/ +/* MCHIP low-level functions */ +/****************************************************************************/ + +/* waits for the specified miliseconds */ +static inline void wait_ms(unsigned int ms) { + if (!in_interrupt()) { + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(1 + ms * HZ / 1000); + } + else + mdelay(ms); +} + +/* returns the horizontal capture size */ +static inline int mchip_hsize(void) { + return meye.params.subsample ? 320 : 640; +} + +/* returns the vertical capture size */ +static inline int mchip_vsize(void) { + return meye.params.subsample ? 240 : 480; +} + +/* waits for a register to be available */ +static void mchip_sync(int reg) { + u32 status; + int i; + + if (reg == MCHIP_MM_FIFO_DATA) { + for (i = 0; i < MCHIP_REG_TIMEOUT; i++) { + status = readl(meye.mchip_mmregs + MCHIP_MM_FIFO_STATUS); + if (!(status & MCHIP_MM_FIFO_WAIT)) { + printk(KERN_WARNING "meye: fifo not ready\n"); + return; + } + if (status & MCHIP_MM_FIFO_READY) + return; + udelay(1); + } + } + else if (reg > 0x80) { + u32 mask = (reg < 0x100) ? MCHIP_HIC_STATUS_MCC_RDY + : MCHIP_HIC_STATUS_VRJ_RDY; + for (i = 0; i < MCHIP_REG_TIMEOUT; i++) { + status = readl(meye.mchip_mmregs + MCHIP_HIC_STATUS); + if (status & mask) + return; + udelay(1); + } + } + else + return; + printk(KERN_WARNING "meye: mchip_sync() timeout on reg 0x%x status=0x%x\n", reg, status); +} + +/* sets a value into the register */ +static inline void mchip_set(int reg, u32 v) { + mchip_sync(reg); + writel(v, meye.mchip_mmregs + reg); +} + +/* get the register value */ +static inline u32 mchip_read(int reg) { + mchip_sync(reg); + return readl(meye.mchip_mmregs + reg); +} + +/* wait for a register to become a particular value */ +static inline int mchip_delay(u32 reg, u32 v) { + int n = 10; + while (--n && mchip_read(reg) != v) + udelay(1); + return n; +} + +/* setup subsampling */ +static void mchip_subsample(void) { + mchip_set(MCHIP_MCC_R_SAMPLING, meye.params.subsample); + mchip_set(MCHIP_MCC_R_XRANGE, mchip_hsize()); + mchip_set(MCHIP_MCC_R_YRANGE, mchip_vsize()); + mchip_set(MCHIP_MCC_B_XRANGE, mchip_hsize()); + mchip_set(MCHIP_MCC_B_YRANGE, mchip_vsize()); + mchip_delay(MCHIP_HIC_STATUS, MCHIP_HIC_STATUS_IDLE); +} + +/* set the framerate into the mchip */ +static void mchip_set_framerate(void) { + mchip_set(MCHIP_HIC_S_RATE, meye.params.framerate); +} + +/* load some huffman and quantisation tables into the VRJ chip ready + for JPEG compression */ +static void mchip_load_tables(void) { + int i; + int size; + u16 *tables; + + tables = jpeg_huffman_tables(&size); + for (i = 0; i < size / 2; i++) + writel(tables[i], meye.mchip_mmregs + MCHIP_VRJ_TABLE_DATA); + + tables = jpeg_quantisation_tables(&size, meye.params.quality); + for (i = 0; i < size / 2; i++) + writel(tables[i], meye.mchip_mmregs + MCHIP_VRJ_TABLE_DATA); +} + +/* setup the VRJ parameters in the chip */ +static void mchip_vrj_setup(u8 mode) { + + mchip_set(MCHIP_VRJ_BUS_MODE, 5); + mchip_set(MCHIP_VRJ_SIGNAL_ACTIVE_LEVEL, 0x1f); + mchip_set(MCHIP_VRJ_PDAT_USE, 1); + mchip_set(MCHIP_VRJ_IRQ_FLAG, 0xa0); + mchip_set(MCHIP_VRJ_MODE_SPECIFY, mode); + mchip_set(MCHIP_VRJ_NUM_LINES, mchip_vsize()); + mchip_set(MCHIP_VRJ_NUM_PIXELS, mchip_hsize()); + mchip_set(MCHIP_VRJ_NUM_COMPONENTS, 0x1b); + mchip_set(MCHIP_VRJ_LIMIT_COMPRESSED_LO, 0xFFFF); + mchip_set(MCHIP_VRJ_LIMIT_COMPRESSED_HI, 0xFFFF); + mchip_set(MCHIP_VRJ_COMP_DATA_FORMAT, 0xC); + mchip_set(MCHIP_VRJ_RESTART_INTERVAL, 0); + mchip_set(MCHIP_VRJ_SOF1, 0x601); + mchip_set(MCHIP_VRJ_SOF2, 0x1502); + mchip_set(MCHIP_VRJ_SOF3, 0x1503); + mchip_set(MCHIP_VRJ_SOF4, 0x1596); + mchip_set(MCHIP_VRJ_SOS, 0x0ed0); + + mchip_load_tables(); +} + +/* setup for DMA transfers - also zeros the framebuffer */ +static int mchip_dma_alloc(void) { + if (!meye.mchip_fbuffer) { + meye.mchip_fbuffer = ptable_alloc(MCHIP_NB_PAGES, + &meye.mchip_ptaddr); + if (!meye.mchip_fbuffer) + return -1; + } + return 0; +} + +/* frees the DMA buffer */ +static void mchip_dma_free(void) { + if (meye.mchip_fbuffer) { + ptable_free(meye.mchip_fbuffer, MCHIP_NB_PAGES); + meye.mchip_fbuffer = 0; + meye.mchip_ptaddr = 0; + } +} + +/* sets the DMA parameters into the chip */ +static void mchip_dma_setup(void) { + int i; + + mchip_set(MCHIP_MM_PT_ADDR, meye.mchip_ptaddr); + for (i = 0; i < 4; i++) + mchip_set(MCHIP_MM_FIR(i), 0); + meye.mchip_fnum = 0; +} + +/* stop any existing HIC action and wait for any dma to complete then + reset the dma engine */ +static void mchip_hic_stop(void) { + int i = 0; + + meye.mchip_mode = MCHIP_HIC_MODE_NOOP; + if (!(mchip_read(MCHIP_HIC_STATUS) & MCHIP_HIC_STATUS_BUSY)) + return; + mchip_set(MCHIP_HIC_CMD, MCHIP_HIC_CMD_STOP); + mchip_delay(MCHIP_HIC_CMD, 0); + while (!mchip_delay(MCHIP_HIC_STATUS, MCHIP_HIC_STATUS_IDLE)) { + /* resetting HIC */ + mchip_set(MCHIP_HIC_CMD, MCHIP_HIC_CMD_STOP); + mchip_delay(MCHIP_HIC_CMD, 0); + mchip_set(MCHIP_HIC_CTL, MCHIP_HIC_CTL_SOFT_RESET); + wait_ms(250); + if (i++ > 20) { + printk(KERN_ERR "meye: resetting HIC hanged!\n"); + break; + } + } + wait_ms(100); +} + +/****************************************************************************/ +/* MCHIP frame processing functions */ +/****************************************************************************/ + +/* get the next ready frame from the dma engine */ +static u32 mchip_get_frame(void) { + u32 v; + + v = mchip_read(MCHIP_MM_FIR(meye.mchip_fnum)); + return v; +} + +/* frees the current frame from the dma engine */ +static void mchip_free_frame(void) { + mchip_set(MCHIP_MM_FIR(meye.mchip_fnum), 0); + meye.mchip_fnum++; + meye.mchip_fnum %= 4; +} + + +/* read one frame from the framebuffer assuming it was captured using + a uncompressed transfer */ +static void mchip_cont_read_frame(u32 v, u8 *buf, int size) { + int pt_id; + int avail; + + pt_id = (v >> 17) & 0x3FF; + avail = MCHIP_NB_PAGES - pt_id; + + if (size > avail*PAGE_SIZE) { + memcpy(buf, meye.mchip_fbuffer + pt_id * PAGE_SIZE, + avail * PAGE_SIZE); + memcpy(buf +avail * PAGE_SIZE, meye.mchip_fbuffer, + size - avail * PAGE_SIZE); + } + else + memcpy(buf, meye.mchip_fbuffer + pt_id * PAGE_SIZE, size); +} + +/* read a compressed frame from the framebuffer */ +static int mchip_comp_read_frame(u32 v, u8 *buf, int size) { + int pt_start, pt_end, trailer; + int fsize, fsize2; + int i; + + pt_start = (v >> 19) & 0xFF; + pt_end = (v >> 11) & 0xFF; + trailer = (v >> 1) & 0x3FF; + + if (pt_end < pt_start) { + fsize = (MCHIP_NB_PAGES_MJPEG - pt_start) * PAGE_SIZE; + fsize2 = pt_end * PAGE_SIZE + trailer * 4; + if (fsize + fsize2 > size) { + printk(KERN_WARNING "meye: oversized compressed frame %d %d\n", + fsize, fsize2); + return -1; + } else { + memcpy(buf, meye.mchip_fbuffer + pt_start * PAGE_SIZE, + fsize); + memcpy(buf + fsize, meye.mchip_fbuffer, fsize2); + fsize += fsize2; + } + } else { + fsize = (pt_end - pt_start) * PAGE_SIZE + trailer * 4; + if (fsize > size) { + printk(KERN_WARNING "meye: oversized compressed frame %d\n", + fsize); + return -1; + } else + memcpy(buf, meye.mchip_fbuffer + pt_start * PAGE_SIZE, + fsize); + } + + +#ifdef MEYE_JPEG_CORRECTION + + /* Some mchip generated jpeg frames are incorrect. In most + * (all ?) of those cases, the final EOI (0xff 0xd9) marker + * is not present at the end of the frame. + * + * Since adding the final marker is not enough to restore + * the jpeg integrity, we drop the frame. + */ + + for (i = fsize - 1; i > 0 && buf[i] == 0xff; i--) ; + + if (i < 2 || buf[i - 1] != 0xff || buf[i] != 0xd9) + return -1; + +#endif + + return fsize; +} + +/* take a picture into SDRAM */ +static void mchip_take_picture(void) { + int i; + + mchip_hic_stop(); + mchip_subsample(); + mchip_dma_setup(); + + mchip_set(MCHIP_HIC_MODE, MCHIP_HIC_MODE_STILL_CAP); + mchip_set(MCHIP_HIC_CMD, MCHIP_HIC_CMD_START); + + mchip_delay(MCHIP_HIC_CMD, 0); + + for (i = 0; i < 100; ++i) { + if (mchip_delay(MCHIP_HIC_STATUS, MCHIP_HIC_STATUS_IDLE)) + break; + wait_ms(1); + } +} + +/* dma a previously taken picture into a buffer */ +static void mchip_get_picture(u8 *buf, int bufsize) { + u32 v; + int i; + + mchip_set(MCHIP_HIC_MODE, MCHIP_HIC_MODE_STILL_OUT); + mchip_set(MCHIP_HIC_CMD, MCHIP_HIC_CMD_START); + + mchip_delay(MCHIP_HIC_CMD, 0); + for (i = 0; i < 100; ++i) { + if (mchip_delay(MCHIP_HIC_STATUS, MCHIP_HIC_STATUS_IDLE)) + break; + wait_ms(1); + } + for (i = 0; i < 4 ; ++i) { + v = mchip_get_frame(); + if (v & MCHIP_MM_FIR_RDY) { + mchip_cont_read_frame(v, buf, bufsize); + break; + } + mchip_free_frame(); + } +} + +/* start continuous dma capture */ +static void mchip_continuous_start(void) { + mchip_hic_stop(); + mchip_subsample(); + mchip_set_framerate(); + mchip_dma_setup(); + + meye.mchip_mode = MCHIP_HIC_MODE_CONT_OUT; + + mchip_set(MCHIP_HIC_MODE, MCHIP_HIC_MODE_CONT_OUT); + mchip_set(MCHIP_HIC_CMD, MCHIP_HIC_CMD_START); + + mchip_delay(MCHIP_HIC_CMD, 0); +} + +/* compress one frame into a buffer */ +static int mchip_compress_frame(u8 *buf, int bufsize) { + u32 v; + int len = -1, i; + + mchip_vrj_setup(0x3f); + udelay(50); + + mchip_set(MCHIP_HIC_MODE, MCHIP_HIC_MODE_STILL_COMP); + mchip_set(MCHIP_HIC_CMD, MCHIP_HIC_CMD_START); + + mchip_delay(MCHIP_HIC_CMD, 0); + for (i = 0; i < 100; ++i) { + if (mchip_delay(MCHIP_HIC_STATUS, MCHIP_HIC_STATUS_IDLE)) + break; + wait_ms(1); + } + + for (i = 0; i < 4 ; ++i) { + v = mchip_get_frame(); + if (v & MCHIP_MM_FIR_RDY) { + len = mchip_comp_read_frame(v, buf, bufsize); + break; + } + mchip_free_frame(); + } + return len; +} + +#if 0 +/* uncompress one image into a buffer */ +static int mchip_uncompress_frame(u8 *img, int imgsize, u8 *buf, int bufsize) { + mchip_vrj_setup(0x3f); + udelay(50); + + mchip_set(MCHIP_HIC_MODE, MCHIP_HIC_MODE_STILL_DECOMP); + mchip_set(MCHIP_HIC_CMD, MCHIP_HIC_CMD_START); + + mchip_delay(MCHIP_HIC_CMD, 0); + + return mchip_comp_read_frame(buf, bufsize); +} +#endif + +/* start continuous compressed capture */ +static void mchip_cont_compression_start(void) { + mchip_hic_stop(); + mchip_vrj_setup(0x3f); + mchip_subsample(); + mchip_set_framerate(); + mchip_dma_setup(); + + meye.mchip_mode = MCHIP_HIC_MODE_CONT_COMP; + + mchip_set(MCHIP_HIC_MODE, MCHIP_HIC_MODE_CONT_COMP); + mchip_set(MCHIP_HIC_CMD, MCHIP_HIC_CMD_START); + + mchip_delay(MCHIP_HIC_CMD, 0); +} + +/****************************************************************************/ +/* Interrupt handling */ +/****************************************************************************/ + +static void meye_irq(int irq, void *dev_id, struct pt_regs *regs) { + u32 v; + int reqnr; + v = mchip_read(MCHIP_MM_INTA); + + while (1) { + v = mchip_get_frame(); + if (!(v & MCHIP_MM_FIR_RDY)) + goto out; + switch (meye.mchip_mode) { + + case MCHIP_HIC_MODE_CONT_OUT: + if (!meye_emptyq(&meye.grabq, NULL)) { + int nr = meye_pullq(&meye.grabq); + mchip_cont_read_frame( + v, + meye.grab_fbuffer + gbufsize * nr, + mchip_hsize() * mchip_vsize() * 2); + meye.grab_buffer[nr].state = MEYE_BUF_DONE; + wake_up_interruptible(&meye.grabq.proc_list); + } + break; + + case MCHIP_HIC_MODE_CONT_COMP: + if (!meye_emptyq(&meye.grabq, &reqnr)) { + int size; + size = mchip_comp_read_frame( + v, + meye.grab_fbuffer + gbufsize * reqnr, + gbufsize); + if (size == -1) + break; + reqnr = meye_pullq(&meye.grabq); + meye.grab_buffer[reqnr].size = size; + meye.grab_buffer[reqnr].state = MEYE_BUF_DONE; + wake_up_interruptible(&meye.grabq.proc_list); + } + break; + + default: + /* do not free frame, since it can be a snap */ + goto out; + } /* switch */ + + mchip_free_frame(); + } +out: +} + +/****************************************************************************/ +/* video4linux integration */ +/****************************************************************************/ + +static int meye_open(struct video_device *dev, int flags) { + int i; + + down(&meye.lock); + if (meye.open_count) { + up(&meye.lock); + return -EBUSY; + } + meye.open_count++; + if (mchip_dma_alloc()) { + printk(KERN_ERR "meye: mchip framebuffer allocation failed\n"); + up(&meye.lock); + return -ENOBUFS; + } + mchip_hic_stop(); + meye_initq(&meye.grabq); + for (i = 0; i < MEYE_MAX_BUFNBRS; i++) + meye.grab_buffer[i].state = MEYE_BUF_UNUSED; + up(&meye.lock); + return 0; +} + +static void meye_close(struct video_device *dev) { + down(&meye.lock); + meye.open_count--; + mchip_hic_stop(); + up(&meye.lock); +} + +static int meye_ioctl(struct video_device *dev, unsigned int cmd, void *arg) { + + switch (cmd) { + + case VIDIOCGCAP: { + struct video_capability b; + strcpy(b.name,meye.video_dev.name); + b.type = VID_TYPE_CAPTURE; + b.channels = 1; + b.audios = 0; + b.maxwidth = 640; + b.maxheight = 480; + b.minwidth = 320; + b.minheight = 240; + if(copy_to_user(arg,&b,sizeof(b))) + return -EFAULT; + break; + } + + case VIDIOCGCHAN: { + struct video_channel v; + if(copy_from_user(&v, arg,sizeof(v))) + return -EFAULT; + v.flags = 0; + v.tuners = 0; + v.type = VIDEO_TYPE_CAMERA; + if (v.channel != 0) + return -EINVAL; + strcpy(v.name,"Camera"); + if(copy_to_user(arg,&v,sizeof(v))) + return -EFAULT; + break; + } + + case VIDIOCSCHAN: { + struct video_channel v; + if(copy_from_user(&v, arg,sizeof(v))) + return -EFAULT; + if (v.channel != 0) + return -EINVAL; + break; + } + + case VIDIOCGPICT: { + struct video_picture p = meye.picture; + if(copy_to_user(arg, &p, sizeof(p))) + return -EFAULT; + break; + } + + case VIDIOCSPICT: { + struct video_picture p; + if(copy_from_user(&p, arg,sizeof(p))) + return -EFAULT; + if (p.depth != 2) + return -EINVAL; + if (p.palette != VIDEO_PALETTE_YUV422) + return -EINVAL; + down(&meye.lock); + sonypi_camera_command(SONYPI_COMMAND_SETCAMERABRIGHTNESS, + p.brightness >> 10); + sonypi_camera_command(SONYPI_COMMAND_SETCAMERAHUE, + p.hue >> 10); + sonypi_camera_command(SONYPI_COMMAND_SETCAMERACOLOR, + p.colour >> 10); + sonypi_camera_command(SONYPI_COMMAND_SETCAMERACONTRAST, + p.contrast >> 10); + memcpy(&meye.picture, &p, sizeof(p)); + up(&meye.lock); + break; + } + + case VIDIOCSYNC: { + int i; + DECLARE_WAITQUEUE(wait, current); + + if(copy_from_user((void *)&i,arg,sizeof(int))) + return -EFAULT; + if (i < 0 || i >= gbuffers) + return -EINVAL; + + switch (meye.grab_buffer[i].state) { + + case MEYE_BUF_UNUSED: + return -EINVAL; + case MEYE_BUF_USING: + add_wait_queue(&meye.grabq.proc_list, &wait); + current->state = TASK_INTERRUPTIBLE; + while (meye.grab_buffer[i].state == MEYE_BUF_USING) { + schedule(); + if(signal_pending(current)) { + remove_wait_queue(&meye.grabq.proc_list, &wait); + current->state = TASK_RUNNING; + return -EINTR; + } + } + remove_wait_queue(&meye.grabq.proc_list, &wait); + current->state = TASK_RUNNING; + /* fall through */ + case MEYE_BUF_DONE: + meye.grab_buffer[i].state = MEYE_BUF_UNUSED; + } + break; + } + + case VIDIOCMCAPTURE: { + struct video_mmap vm; + int restart = 0; + + if(copy_from_user((void *) &vm, (void *) arg, sizeof(vm))) + return -EFAULT; + if (vm.frame >= gbuffers || vm.frame < 0) + return -EINVAL; + if (vm.format != VIDEO_PALETTE_YUV422) + return -EINVAL; + if (vm.height * vm.width * 2 > gbufsize) + return -EINVAL; + if (!meye.grab_fbuffer) + return -EINVAL; + if (meye.grab_buffer[vm.frame].state != MEYE_BUF_UNUSED) + return -EBUSY; + + down(&meye.lock); + if (vm.width == 640 && vm.height == 480) { + if (meye.params.subsample) { + meye.params.subsample = 0; + restart = 1; + } + } + else if (vm.width == 320 && vm.height == 240) { + if (!meye.params.subsample) { + meye.params.subsample = 1; + restart = 1; + } + } + else { + up(&meye.lock); + return -EINVAL; + } + + if (restart || meye.mchip_mode != MCHIP_HIC_MODE_CONT_OUT) + mchip_continuous_start(); + meye.grab_buffer[vm.frame].state = MEYE_BUF_USING; + meye_pushq(&meye.grabq, vm.frame); + up(&meye.lock); + break; + } + + case VIDIOCGMBUF: { + struct video_mbuf vm; + int i; + + memset(&vm, 0 , sizeof(vm)); + vm.size = gbufsize * gbuffers; + vm.frames = gbuffers; + for (i = 0; i < gbuffers; i++) + vm.offsets[i] = i * gbufsize; + if(copy_to_user((void *)arg, (void *)&vm, sizeof(vm))) + return -EFAULT; + break; + } + + case MEYEIOC_G_PARAMS: { + if (copy_to_user(arg, &meye.params, sizeof(meye.params))) + return -EFAULT; + break; + } + + case MEYEIOC_S_PARAMS: { + struct meye_params jp; + if (copy_from_user(&jp, arg, sizeof(jp))) + return -EFAULT; + if (jp.subsample > 1) + return -EINVAL; + if (jp.quality > 10) + return -EINVAL; + if (jp.sharpness > 63 || jp.agc > 63 || jp.picture > 63) + return -EINVAL; + if (jp.framerate > 31) + return -EINVAL; + down(&meye.lock); + if (meye.params.subsample != jp.subsample || + meye.params.quality != jp.quality) + mchip_hic_stop(); /* need restart */ + memcpy(&meye.params, &jp, sizeof(jp)); + sonypi_camera_command(SONYPI_COMMAND_SETCAMERASHARPNESS, + meye.params.sharpness); + sonypi_camera_command(SONYPI_COMMAND_SETCAMERAAGC, + meye.params.agc); + sonypi_camera_command(SONYPI_COMMAND_SETCAMERAPICTURE, + meye.params.picture); + up(&meye.lock); + break; + } + + case MEYEIOC_QBUF_CAPT: { + int nb; + + if (copy_from_user((void *) &nb, (void *) arg, sizeof(int))) + return -EFAULT; + + if (!meye.grab_fbuffer) + return -EINVAL; + if (nb >= gbuffers) + return -EINVAL; + if (nb < 0) { + /* stop capture */ + mchip_hic_stop(); + return 0; + } + if (meye.grab_buffer[nb].state != MEYE_BUF_UNUSED) + return -EBUSY; + down(&meye.lock); + if (meye.mchip_mode != MCHIP_HIC_MODE_CONT_COMP) + mchip_cont_compression_start(); + meye.grab_buffer[nb].state = MEYE_BUF_USING; + meye_pushq(&meye.grabq, nb); + up(&meye.lock); + break; + } + + case MEYEIOC_SYNC: { + int i; + DECLARE_WAITQUEUE(wait, current); + + if(copy_from_user((void *)&i,arg,sizeof(int))) + return -EFAULT; + if (i < 0 || i >= gbuffers) + return -EINVAL; + + switch (meye.grab_buffer[i].state) { + + case MEYE_BUF_UNUSED: + return -EINVAL; + case MEYE_BUF_USING: + add_wait_queue(&meye.grabq.proc_list, &wait); + current->state = TASK_INTERRUPTIBLE; + while (meye.grab_buffer[i].state == MEYE_BUF_USING) { + schedule(); + if(signal_pending(current)) { + remove_wait_queue(&meye.grabq.proc_list, &wait); + current->state = TASK_RUNNING; + return -EINTR; + } + } + remove_wait_queue(&meye.grabq.proc_list, &wait); + current->state = TASK_RUNNING; + /* fall through */ + case MEYE_BUF_DONE: + meye.grab_buffer[i].state = MEYE_BUF_UNUSED; + } + i = meye.grab_buffer[i].size; + if (copy_to_user(arg, (void *)&i, sizeof(int))) + return -EFAULT; + break; + } + + case MEYEIOC_STILLCAPT: { + + if (!meye.grab_fbuffer) + return -EINVAL; + if (meye.grab_buffer[0].state != MEYE_BUF_UNUSED) + return -EBUSY; + down(&meye.lock); + meye.grab_buffer[0].state = MEYE_BUF_USING; + mchip_take_picture(); + mchip_get_picture( + meye.grab_fbuffer, + mchip_hsize() * mchip_vsize() * 2); + meye.grab_buffer[0].state = MEYE_BUF_DONE; + up(&meye.lock); + break; + } + + case MEYEIOC_STILLJCAPT: { + int len = -1; + + if (!meye.grab_fbuffer) + return -EINVAL; + if (meye.grab_buffer[0].state != MEYE_BUF_UNUSED) + return -EBUSY; + down(&meye.lock); + meye.grab_buffer[0].state = MEYE_BUF_USING; + while (len == -1) { + mchip_take_picture(); + len = mchip_compress_frame(meye.grab_fbuffer, gbufsize); + } + meye.grab_buffer[0].state = MEYE_BUF_DONE; + up(&meye.lock); + if (copy_to_user(arg, (void *)&len, sizeof(int))) + return -EFAULT; + break; + } + + default: + return -ENOIOCTLCMD; + + } /* switch */ + + return 0; +} + +static int meye_mmap(struct video_device *dev, const char *adr, + unsigned long size) { + unsigned long start=(unsigned long) adr; + unsigned long page,pos; + + down(&meye.lock); + if (size > gbuffers * gbufsize) { + up(&meye.lock); + return -EINVAL; + } + if (!meye.grab_fbuffer) { + /* lazy allocation */ + meye.grab_fbuffer = rvmalloc(gbuffers*gbufsize); + if (!meye.grab_fbuffer) { + printk(KERN_ERR "meye: v4l framebuffer allocation failed\n"); + up(&meye.lock); + return -ENOMEM; + } + } + pos = (unsigned long)meye.grab_fbuffer; + + while (size > 0) { + page = kvirt_to_pa(pos); + if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED)) { + up(&meye.lock); + return -EAGAIN; + } + start += PAGE_SIZE; + pos += PAGE_SIZE; + size -= PAGE_SIZE; + } + up(&meye.lock); + return 0; +} + +static struct video_device meye_template = { + owner: THIS_MODULE, + name: "meye", + type: VID_TYPE_CAPTURE, + hardware: VID_HARDWARE_MEYE, + open: meye_open, + close: meye_close, + ioctl: meye_ioctl, + mmap: meye_mmap, +}; + +static int __devinit meye_probe(struct pci_dev *pcidev, + const struct pci_device_id *ent) { + int ret; + unsigned long mchip_adr; + u8 revision; + + if (meye.mchip_dev != NULL) { + printk(KERN_ERR "meye: only one device allowed!\n"); + ret = -EBUSY; + goto out1; + } + + sonypi_camera_command(SONYPI_COMMAND_SETCAMERA, 1); + + meye.mchip_dev = pcidev; + meye.mchip_irq = pcidev->irq; + memcpy(&meye.video_dev, &meye_template, sizeof(meye_template)); + + if (mchip_dma_alloc()) { + printk(KERN_ERR "meye: mchip framebuffer allocation failed\n"); + ret = -ENOMEM; + goto out2; + } + + if ((ret = pci_enable_device(meye.mchip_dev))) { + printk(KERN_ERR "meye: pci_enable_device failed\n"); + goto out3; + } + + mchip_adr = pci_resource_start(meye.mchip_dev,0); + if (!mchip_adr) { + printk(KERN_ERR "meye: mchip has no device base address\n"); + ret = -EIO; + goto out4; + } + if (!request_mem_region(pci_resource_start(meye.mchip_dev, 0), + pci_resource_len(meye.mchip_dev, 0), + "meye")) { + ret = -EIO; + printk(KERN_ERR "meye: request_mem_region failed\n"); + goto out4; + } + + pci_read_config_byte(meye.mchip_dev, PCI_REVISION_ID, &revision); + + pci_set_master(meye.mchip_dev); + + pci_write_config_byte(meye.mchip_dev, PCI_CACHE_LINE_SIZE, 8); + pci_write_config_byte(meye.mchip_dev, PCI_LATENCY_TIMER, 64); + + if ((ret = request_irq(meye.mchip_irq, meye_irq, + SA_INTERRUPT | SA_SHIRQ, "meye", meye_irq))) { + printk(KERN_ERR "meye: request_irq failed (ret=%d)\n", ret); + goto out5; + } + + meye.mchip_mmregs = ioremap(mchip_adr, MCHIP_MM_REGS); + if (!meye.mchip_mmregs) { + printk(KERN_ERR "meye: ioremap failed\n"); + ret = -EIO; + goto out6; + } + + /* Ask the camera to perform a soft reset. */ + pci_write_config_word(meye.mchip_dev, MCHIP_PCI_SOFTRESET_SET, 1); + + mchip_delay(MCHIP_HIC_CMD, 0); + mchip_delay(MCHIP_HIC_STATUS, MCHIP_HIC_STATUS_IDLE); + + wait_ms(1); + mchip_set(MCHIP_VRJ_SOFT_RESET, 1); + + wait_ms(1); + mchip_set(MCHIP_MM_PCI_MODE, 5); + + wait_ms(1); + mchip_set(MCHIP_MM_INTA, MCHIP_MM_INTA_HIC_1_MASK); + + if (video_register_device(&meye.video_dev, VFL_TYPE_GRABBER, video_nr) < 0) { + + printk(KERN_ERR "meye: video_register_device failed\n"); + ret = -EIO; + goto out7; + } + + printk(KERN_INFO "meye: Motion Eye Camera Driver v%d.%d.\n", + MEYE_DRIVER_MAJORVERSION, + MEYE_DRIVER_MINORVERSION); + printk(KERN_INFO "meye: mchip KL5A72002 rev. %d, base %lx, irq %d\n", + revision, mchip_adr, meye.mchip_irq); + + /* init all fields */ + init_MUTEX(&meye.lock); + + meye.picture.depth = 2; + meye.picture.palette = VIDEO_PALETTE_YUV422; + meye.picture.brightness = 32 << 10; + meye.picture.hue = 32 << 10; + meye.picture.colour = 32 << 10; + meye.picture.contrast = 32 << 10; + meye.picture.whiteness = 0; + meye.params.subsample = 0; + meye.params.quality = 7; + meye.params.sharpness = 32; + meye.params.agc = 48; + meye.params.picture = 0; + meye.params.framerate = 0; + sonypi_camera_command(SONYPI_COMMAND_SETCAMERABRIGHTNESS, 32); + sonypi_camera_command(SONYPI_COMMAND_SETCAMERAHUE, 32); + sonypi_camera_command(SONYPI_COMMAND_SETCAMERACOLOR, 32); + sonypi_camera_command(SONYPI_COMMAND_SETCAMERACONTRAST, 32); + sonypi_camera_command(SONYPI_COMMAND_SETCAMERASHARPNESS, 32); + sonypi_camera_command(SONYPI_COMMAND_SETCAMERAPICTURE, 0); + sonypi_camera_command(SONYPI_COMMAND_SETCAMERAAGC, 48); + + return 0; +out7: + iounmap(meye.mchip_mmregs); +out6: + free_irq(meye.mchip_irq, meye_irq); +out5: + release_mem_region(pci_resource_start(meye.mchip_dev, 0), + pci_resource_len(meye.mchip_dev, 0)); +out4: + pci_disable_device(meye.mchip_dev); +out3: + mchip_dma_free(); +out2: + sonypi_camera_command(SONYPI_COMMAND_SETCAMERA, 0); +out1: + return ret; +} + +static void __devexit meye_remove(struct pci_dev *pcidev) { + + video_unregister_device(&meye.video_dev); + + mchip_hic_stop(); + + /* disable interrupts */ + mchip_set(MCHIP_MM_INTA, 0x0); + + free_irq(meye.mchip_irq, meye_irq); + + + iounmap(meye.mchip_mmregs); + + release_mem_region(pci_resource_start(meye.mchip_dev, 0), + pci_resource_len(meye.mchip_dev, 0)); + + pci_disable_device(meye.mchip_dev); + + mchip_dma_free(); + + if (meye.grab_fbuffer) + rvfree(meye.grab_fbuffer, gbuffers*gbufsize); + + sonypi_camera_command(SONYPI_COMMAND_SETCAMERA, 0); + + printk(KERN_INFO "meye: removed\n"); +} + +static struct pci_device_id meye_pci_tbl[] __devinitdata = { + { PCI_VENDOR_ID_KAWASAKI, PCI_DEVICE_ID_MCHIP_KL5A72002, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { } +}; + +MODULE_DEVICE_TABLE(pci, meye_pci_tbl); + +static struct pci_driver meye_driver = { + name: "meye", + id_table: meye_pci_tbl, + probe: meye_probe, + remove: meye_remove, +}; + +static int __init meye_init_module(void) { + if (gbuffers < 2) + gbuffers = 2; + if (gbuffers > MEYE_MAX_BUFNBRS) + gbuffers = MEYE_MAX_BUFNBRS; + if (gbufsize < 0 || gbufsize > MEYE_MAX_BUFSIZE) + gbufsize = MEYE_MAX_BUFSIZE; + printk(KERN_INFO "meye: using %d buffers with %dk (%dk total) for capture\n", + gbuffers, gbufsize/1024, gbuffers*gbufsize/1024); + return pci_module_init(&meye_driver); +} + +static void __exit meye_cleanup_module(void) { + pci_unregister_driver(&meye_driver); +} + +MODULE_AUTHOR("Stelian Pop <stelian.pop@fr.alcove.com>"); +MODULE_DESCRIPTION("video4linux driver for the MotionEye camera"); + +MODULE_PARM(gbuffers,"i"); +MODULE_PARM_DESC(gbuffers,"number of capture buffers, default is 2 (32 max)"); +MODULE_PARM(gbufsize,"i"); +MODULE_PARM_DESC(gbufsize,"size of the capture buffers, default is 614400"); +MODULE_PARM(video_nr,"i"); +MODULE_PARM_DESC(video_nr,"video device to register (0=/dev/video0, etc)"); + +/* Module entry points */ +module_init(meye_init_module); +module_exit(meye_cleanup_module); diff -u --recursive --new-file v2.4.6/linux/drivers/media/video/meye.h linux/drivers/media/video/meye.h --- v2.4.6/linux/drivers/media/video/meye.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/media/video/meye.h Wed Jul 4 14:41:33 2001 @@ -0,0 +1,313 @@ +/* + * Motion Eye video4linux driver for Sony Vaio PictureBook + * + * Copyright (C) 2001 Stelian Pop <stelian.pop@fr.alcove.com>, Alcôve + * + * Copyright (C) 2000 Andrew Tridgell <tridge@valinux.com> + * + * Earlier work by Werner Almesberger, Paul `Rusty' Russell and Paul Mackerras. + * + * Some parts borrowed from various video4linux drivers, especially + * bttv-driver.c and zoran.c, see original files for credits. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef _MEYE_PRIV_H_ +#define _MEYE_PRIV_H_ + +#define MEYE_DRIVER_MAJORVERSION 1 +#define MEYE_DRIVER_MINORVERSION 0 + +/****************************************************************************/ +/* Motion JPEG chip registers */ +/****************************************************************************/ + +/* Motion JPEG chip PCI configuration registers */ +#define MCHIP_PCI_POWER_CSR 0x54 +#define MCHIP_PCI_MCORE_STATUS 0x60 /* see HIC_STATUS */ +#define MCHIP_PCI_HOSTUSEREQ_SET 0x64 +#define MCHIP_PCI_HOSTUSEREQ_CLR 0x68 +#define MCHIP_PCI_LOWPOWER_SET 0x6c +#define MCHIP_PCI_LOWPOWER_CLR 0x70 +#define MCHIP_PCI_SOFTRESET_SET 0x74 + +/* Motion JPEG chip memory mapped registers */ +#define MCHIP_MM_REGS 0x200 /* 512 bytes */ +#define MCHIP_REG_TIMEOUT 1000 /* reg access, ~us */ +#define MCHIP_MCC_VRJ_TIMEOUT 1000 /* MCC & VRJ access */ + +#define MCHIP_MM_PCI_MODE 0x00 /* PCI access mode */ +#define MCHIP_MM_PCI_MODE_RETRY 0x00000001 /* retry mode */ +#define MCHIP_MM_PCI_MODE_MASTER 0x00000002 /* master access */ +#define MCHIP_MM_PCI_MODE_READ_LINE 0x00000004 /* read line */ + +#define MCHIP_MM_INTA 0x04 /* Int status/mask */ +#define MCHIP_MM_INTA_MCC 0x00000001 /* MCC interrupt */ +#define MCHIP_MM_INTA_VRJ 0x00000002 /* VRJ interrupt */ +#define MCHIP_MM_INTA_HIC_1 0x00000004 /* one frame done */ +#define MCHIP_MM_INTA_HIC_1_MASK 0x00000400 /* 1: enable */ +#define MCHIP_MM_INTA_HIC_END 0x00000008 /* all frames done */ +#define MCHIP_MM_INTA_HIC_END_MASK 0x00000800 +#define MCHIP_MM_INTA_JPEG 0x00000010 /* decompress. error */ +#define MCHIP_MM_INTA_JPEG_MASK 0x00001000 +#define MCHIP_MM_INTA_CAPTURE 0x00000020 /* capture end */ +#define MCHIP_MM_INTA_PCI_ERR 0x00000040 /* PCI error */ +#define MCHIP_MM_INTA_PCI_ERR_MASK 0x00004000 + +#define MCHIP_MM_PT_ADDR 0x08 /* page table address */ + /* n*4kB */ +#define MCHIP_NB_PAGES 1024 /* pages for display */ +#define MCHIP_NB_PAGES_MJPEG 256 /* pages for mjpeg */ + +#define MCHIP_MM_FIR(n) (0x0c+(n)*4) /* Frame info 0-3 */ +#define MCHIP_MM_FIR_RDY 0x00000001 /* frame ready */ +#define MCHIP_MM_FIR_FAILFR_MASK 0xf8000000 /* # of failed frames */ +#define MCHIP_MM_FIR_FAILFR_SHIFT 27 + + /* continuous comp/decomp mode */ +#define MCHIP_MM_FIR_C_ENDL_MASK 0x000007fe /* end DW [10] */ +#define MCHIP_MM_FIR_C_ENDL_SHIFT 1 +#define MCHIP_MM_FIR_C_ENDP_MASK 0x0007f800 /* end page [8] */ +#define MCHIP_MM_FIR_C_ENDP_SHIFT 11 +#define MCHIP_MM_FIR_C_STARTP_MASK 0x07f80000 /* start page [8] */ +#define MCHIP_MM_FIR_C_STARTP_SHIFT 19 + + /* continuous picture output mode */ +#define MCHIP_MM_FIR_O_STARTP_MASK 0x7ffe0000 /* start page [10] */ +#define MCHIP_MM_FIR_O_STARTP_SHIFT 17 + +#define MCHIP_MM_FIFO_DATA 0x1c /* PCI TGT FIFO data */ +#define MCHIP_MM_FIFO_STATUS 0x20 /* PCI TGT FIFO stat */ +#define MCHIP_MM_FIFO_MASK 0x00000003 +#define MCHIP_MM_FIFO_WAIT_OR_READY 0x00000002 /* Bits common to WAIT & READY*/ +#define MCHIP_MM_FIFO_IDLE 0x0 /* HIC idle */ +#define MCHIP_MM_FIFO_IDLE1 0x1 /* idem ??? */ +#define MCHIP_MM_FIFO_WAIT 0x2 /* wait request */ +#define MCHIP_MM_FIFO_READY 0x3 /* data ready */ + +#define MCHIP_HIC_HOST_USEREQ 0x40 /* host uses MCORE */ + +#define MCHIP_HIC_TP_BUSY 0x44 /* taking picture */ + +#define MCHIP_HIC_PIC_SAVED 0x48 /* pic in SDRAM */ + +#define MCHIP_HIC_LOWPOWER 0x4c /* clock stopped */ + +#define MCHIP_HIC_CTL 0x50 /* HIC control */ +#define MCHIP_HIC_CTL_SOFT_RESET 0x00000001 /* MCORE reset */ +#define MCHIP_HIC_CTL_MCORE_RDY 0x00000002 /* MCORE ready */ + +#define MCHIP_HIC_CMD 0x54 /* HIC command */ +#define MCHIP_HIC_CMD_BITS 0x00000003 /* cmd width=[1:0]*/ +#define MCHIP_HIC_CMD_NOOP 0x0 +#define MCHIP_HIC_CMD_START 0x1 +#define MCHIP_HIC_CMD_STOP 0x2 + +#define MCHIP_HIC_MODE 0x58 +#define MCHIP_HIC_MODE_NOOP 0x0 +#define MCHIP_HIC_MODE_STILL_CAP 0x1 /* still pic capt */ +#define MCHIP_HIC_MODE_DISPLAY 0x2 /* display */ +#define MCHIP_HIC_MODE_STILL_COMP 0x3 /* still pic comp. */ +#define MCHIP_HIC_MODE_STILL_DECOMP 0x4 /* still pic decomp. */ +#define MCHIP_HIC_MODE_CONT_COMP 0x5 /* cont capt+comp */ +#define MCHIP_HIC_MODE_CONT_DECOMP 0x6 /* cont decomp+disp */ +#define MCHIP_HIC_MODE_STILL_OUT 0x7 /* still pic output */ +#define MCHIP_HIC_MODE_CONT_OUT 0x8 /* cont output */ + +#define MCHIP_HIC_STATUS 0x5c +#define MCHIP_HIC_STATUS_MCC_RDY 0x00000001 /* MCC reg acc ok */ +#define MCHIP_HIC_STATUS_VRJ_RDY 0x00000002 /* VRJ reg acc ok */ +#define MCHIP_HIC_STATUS_IDLE 0x00000003 +#define MCHIP_HIC_STATUS_CAPDIS 0x00000004 /* cap/disp in prog */ +#define MCHIP_HIC_STATUS_COMPDEC 0x00000008 /* (de)comp in prog */ +#define MCHIP_HIC_STATUS_BUSY 0x00000010 /* HIC busy */ + +#define MCHIP_HIC_S_RATE 0x60 /* MJPEG # frames */ + +#define MCHIP_HIC_PCI_VFMT 0x64 /* video format */ +#define MCHIP_HIC_PCI_VFMT_YVYU 0x00000001 /* 0: V Y' U Y */ + /* 1: Y' V Y U */ + +#define MCHIP_MCC_CMD 0x80 /* MCC commands */ +#define MCHIP_MCC_CMD_INITIAL 0x0 /* idle ? */ +#define MCHIP_MCC_CMD_IIC_START_SET 0x1 +#define MCHIP_MCC_CMD_IIC_END_SET 0x2 +#define MCHIP_MCC_CMD_FM_WRITE 0x3 /* frame memory */ +#define MCHIP_MCC_CMD_FM_READ 0x4 +#define MCHIP_MCC_CMD_FM_STOP 0x5 +#define MCHIP_MCC_CMD_CAPTURE 0x6 +#define MCHIP_MCC_CMD_DISPLAY 0x7 +#define MCHIP_MCC_CMD_END_DISP 0x8 +#define MCHIP_MCC_CMD_STILL_COMP 0x9 +#define MCHIP_MCC_CMD_STILL_DECOMP 0xa +#define MCHIP_MCC_CMD_STILL_OUTPUT 0xb +#define MCHIP_MCC_CMD_CONT_OUTPUT 0xc +#define MCHIP_MCC_CMD_CONT_COMP 0xd +#define MCHIP_MCC_CMD_CONT_DECOMP 0xe +#define MCHIP_MCC_CMD_RESET 0xf /* MCC reset */ + +#define MCHIP_MCC_IIC_WR 0x84 + +#define MCHIP_MCC_MCC_WR 0x88 + +#define MCHIP_MCC_MCC_RD 0x8c + +#define MCHIP_MCC_STATUS 0x90 +#define MCHIP_MCC_STATUS_CAPT 0x00000001 /* capturing */ +#define MCHIP_MCC_STATUS_DISP 0x00000002 /* displaying */ +#define MCHIP_MCC_STATUS_COMP 0x00000004 /* compressing */ +#define MCHIP_MCC_STATUS_DECOMP 0x00000008 /* decompressing */ +#define MCHIP_MCC_STATUS_MCC_WR 0x00000010 /* register ready */ +#define MCHIP_MCC_STATUS_MCC_RD 0x00000020 /* register ready */ +#define MCHIP_MCC_STATUS_IIC_WR 0x00000040 /* register ready */ +#define MCHIP_MCC_STATUS_OUTPUT 0x00000080 /* output in prog */ + +#define MCHIP_MCC_SIG_POLARITY 0x94 +#define MCHIP_MCC_SIG_POL_VS_H 0x00000001 /* VS active-high */ +#define MCHIP_MCC_SIG_POL_HS_H 0x00000002 /* HS active-high */ +#define MCHIP_MCC_SIG_POL_DOE_H 0x00000004 /* DOE active-high */ + +#define MCHIP_MCC_IRQ 0x98 +#define MCHIP_MCC_IRQ_CAPDIS_STRT 0x00000001 /* cap/disp started */ +#define MCHIP_MCC_IRQ_CAPDIS_STRT_MASK 0x00000010 +#define MCHIP_MCC_IRQ_CAPDIS_END 0x00000002 /* cap/disp ended */ +#define MCHIP_MCC_IRQ_CAPDIS_END_MASK 0x00000020 +#define MCHIP_MCC_IRQ_COMPDEC_STRT 0x00000004 /* (de)comp started */ +#define MCHIP_MCC_IRQ_COMPDEC_STRT_MASK 0x00000040 +#define MCHIP_MCC_IRQ_COMPDEC_END 0x00000008 /* (de)comp ended */ +#define MCHIP_MCC_IRQ_COMPDEC_END_MASK 0x00000080 + +#define MCHIP_MCC_HSTART 0x9c /* video in */ +#define MCHIP_MCC_VSTART 0xa0 +#define MCHIP_MCC_HCOUNT 0xa4 +#define MCHIP_MCC_VCOUNT 0xa8 +#define MCHIP_MCC_R_XBASE 0xac /* capt/disp */ +#define MCHIP_MCC_R_YBASE 0xb0 +#define MCHIP_MCC_R_XRANGE 0xb4 +#define MCHIP_MCC_R_YRANGE 0xb8 +#define MCHIP_MCC_B_XBASE 0xbc /* comp/decomp */ +#define MCHIP_MCC_B_YBASE 0xc0 +#define MCHIP_MCC_B_XRANGE 0xc4 +#define MCHIP_MCC_B_YRANGE 0xc8 + +#define MCHIP_MCC_R_SAMPLING 0xcc /* 1: 1:4 */ + +#define MCHIP_VRJ_CMD 0x100 /* VRJ commands */ + +/* VRJ registers (see table 12.2.4) */ +#define MCHIP_VRJ_COMPRESSED_DATA 0x1b0 +#define MCHIP_VRJ_PIXEL_DATA 0x1b8 + +#define MCHIP_VRJ_BUS_MODE 0x100 +#define MCHIP_VRJ_SIGNAL_ACTIVE_LEVEL 0x108 +#define MCHIP_VRJ_PDAT_USE 0x110 +#define MCHIP_VRJ_MODE_SPECIFY 0x118 +#define MCHIP_VRJ_LIMIT_COMPRESSED_LO 0x120 +#define MCHIP_VRJ_LIMIT_COMPRESSED_HI 0x124 +#define MCHIP_VRJ_COMP_DATA_FORMAT 0x128 +#define MCHIP_VRJ_TABLE_DATA 0x140 +#define MCHIP_VRJ_RESTART_INTERVAL 0x148 +#define MCHIP_VRJ_NUM_LINES 0x150 +#define MCHIP_VRJ_NUM_PIXELS 0x158 +#define MCHIP_VRJ_NUM_COMPONENTS 0x160 +#define MCHIP_VRJ_SOF1 0x168 +#define MCHIP_VRJ_SOF2 0x170 +#define MCHIP_VRJ_SOF3 0x178 +#define MCHIP_VRJ_SOF4 0x180 +#define MCHIP_VRJ_SOS 0x188 +#define MCHIP_VRJ_SOFT_RESET 0x190 + +#define MCHIP_VRJ_STATUS 0x1c0 +#define MCHIP_VRJ_STATUS_BUSY 0x00001 +#define MCHIP_VRJ_STATUS_COMP_ACCESS 0x00002 +#define MCHIP_VRJ_STATUS_PIXEL_ACCESS 0x00004 +#define MCHIP_VRJ_STATUS_ERROR 0x00008 + +#define MCHIP_VRJ_IRQ_FLAG 0x1c8 +#define MCHIP_VRJ_ERROR_REPORT 0x1d8 + +#define MCHIP_VRJ_START_COMMAND 0x1a0 + +/****************************************************************************/ +/* Driver definitions. */ +/****************************************************************************/ + +/* Sony Programmable I/O Controller for accessing the camera commands */ +#include <linux/sonypi.h> + +/* private API definitions */ +#include <linux/meye.h> + +/* Enable jpg software correction */ +#define MEYE_JPEG_CORRECTION 1 + +/* Maximum size of a buffer */ +#define MEYE_MAX_BUFSIZE 614400 /* 640 * 480 * 2 */ + +/* Maximum number of buffers */ +#define MEYE_MAX_BUFNBRS 32 + +/* State of a buffer */ +#define MEYE_BUF_UNUSED 0 /* not used */ +#define MEYE_BUF_USING 1 /* currently grabbing / playing */ +#define MEYE_BUF_DONE 2 /* done */ + +/* grab buffer */ +struct meye_grab_buffer { + int state; /* state of buffer */ + unsigned long size; /* size of jpg frame */ +}; + +/* queues containing the buffer indices */ +#define MEYE_QUEUE_SIZE MEYE_MAX_BUFNBRS +struct meye_queue { + unsigned int head; /* queue head */ + unsigned int tail; /* queue tail */ + unsigned int len; /* queue length */ + spinlock_t s_lock; /* spinlock protecting the queue */ + wait_queue_head_t proc_list; /* wait queue */ + int buf[MEYE_QUEUE_SIZE]; /* queue contents */ +}; + +/* Motion Eye device structure */ +struct meye { + + /* mchip related */ + struct pci_dev *mchip_dev; /* pci device */ + u8 mchip_irq; /* irq */ + u8 mchip_mode; /* actual mchip mode: HIC_MODE... */ + u8 mchip_fnum; /* current mchip frame number */ + + unsigned char *mchip_mmregs; /* mchip: memory mapped registers */ + unsigned char *mchip_fbuffer; /* mchip: framebuffer */ + u32 mchip_ptaddr; /* mchip: pointer to framebuffer */ + + unsigned char *grab_fbuffer; /* capture framebuffer */ + /* list of buffers */ + struct meye_grab_buffer grab_buffer[MEYE_MAX_BUFNBRS]; + + /* other */ + unsigned int open_count; /* open() count */ + struct semaphore lock; /* semaphore for open/mmap... */ + + struct meye_queue grabq; /* queue for buffers to be grabbed */ + + struct video_device video_dev; /* video device parameters */ + struct video_picture picture; /* video picture parameters */ + struct meye_params params; /* additional parameters */ +}; + +#endif diff -u --recursive --new-file v2.4.6/linux/drivers/media/video/saa5249.c linux/drivers/media/video/saa5249.c --- v2.4.6/linux/drivers/media/video/saa5249.c Sat May 19 17:43:06 2001 +++ linux/drivers/media/video/saa5249.c Wed Jul 4 14:41:33 2001 @@ -102,6 +102,7 @@ int disp_mode; int virtual_mode; struct i2c_client *client; + struct semaphore lock; }; @@ -175,6 +176,7 @@ } memset(t, 0, sizeof(*t)); strcpy(client->name, IF_NAME); + init_MUTEX(&t->lock); /* * Now create a video4linux device @@ -188,7 +190,7 @@ return -ENOMEM; } memcpy(vd, &saa_template, sizeof(*vd)); - + for (pgbuf = 0; pgbuf < NUM_DAUS; pgbuf++) { memset(t->vdau[pgbuf].pgbuf, ' ', sizeof(t->vdau[0].pgbuf)); @@ -199,7 +201,8 @@ t->vdau[pgbuf].stopped = TRUE; t->is_searching[pgbuf] = FALSE; } - vd->priv=t; + vd->priv=t; + /* * Register it @@ -342,9 +345,8 @@ * Standard character-device-driver functions */ -static int saa5249_ioctl(struct video_device *vd, unsigned int cmd, void *arg) +static int do_saa5249_ioctl(struct saa5249_device *t, unsigned int cmd, void *arg) { - struct saa5249_device *t=vd->priv; static int virtual_mode = FALSE; switch(cmd) @@ -602,6 +604,21 @@ return -EINVAL; } +/* + * Handle the locking + */ + +static int saa5249_ioctl(struct video_device *vd, unsigned int cmd, void *arg) +{ + struct saa5249_device *t=vd->priv; + int err; + + down(&t->lock); + err = do_saa5249_ioctl(t, cmd, arg); + up(&t->lock); + + return err; +} static int saa5249_open(struct video_device *vd, int nb) { @@ -632,7 +649,6 @@ t->is_searching[pgbuf] = FALSE; } t->virtual_mode=FALSE; - MOD_INC_USE_COUNT; return 0; } @@ -643,7 +659,6 @@ struct saa5249_device *t=vd->priv; i2c_senddata(t, 1, 0x20, -1); /* Turn off CCT */ i2c_senddata(t, 5, 3, 3, -1); /* Turn off TV-display */ - MOD_DEC_USE_COUNT; return; } @@ -669,6 +684,7 @@ static struct video_device saa_template = { + owner: THIS_MODULE, name: IF_NAME, type: VID_TYPE_TELETEXT, /*| VID_TYPE_TUNER ?? */ hardware: VID_HARDWARE_SAA5249, diff -u --recursive --new-file v2.4.6/linux/drivers/media/video/zoran.h linux/drivers/media/video/zoran.h --- v2.4.6/linux/drivers/media/video/zoran.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/media/video/zoran.h Wed Jul 4 14:41:33 2001 @@ -0,0 +1,372 @@ +/* + zoran - Iomega Buz driver + + Copyright (C) 1999 Rainer Johanni <Rainer@Johanni.de> + + based on + + zoran.0.0.3 Copyright (C) 1998 Dave Perks <dperks@ibm.net> + + and + + bttv - Bt848 frame grabber driver + Copyright (C) 1996,97 Ralph Metzler (rjkm@thp.uni-koeln.de) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef _BUZ_H_ +#define _BUZ_H_ + +#include <linux/config.h> + +#if LINUX_VERSION_CODE < 0x20212 +typedef struct wait_queue *wait_queue_head_t; +#endif + +/* The Buz only supports a maximum width of 720, but some V4L + applications (e.g. xawtv are more happy with 768). + If XAWTV_HACK is defined, we try to fake a device with bigger width */ + +//#define XAWTV_HACK + +//#ifdef XAWTV_HACK +//#define BUZ_MAX_WIDTH 768 /* never display more than 768 pixels */ +#define BUZ_MAX_WIDTH (zr->timing->Wa) +//#else +//#define BUZ_MAX_WIDTH 720 /* never display more than 720 pixels */ +//#endif +//#define BUZ_MAX_HEIGHT 576 /* never display more than 576 rows */ +#define BUZ_MAX_HEIGHT (zr->timing->Ha) +#define BUZ_MIN_WIDTH 32 /* never display less than 32 pixels */ +#define BUZ_MIN_HEIGHT 24 /* never display less than 24 rows */ + +struct zoran_requestbuffers { + unsigned long count; /* Number of buffers for MJPEG grabbing */ + unsigned long size; /* Size PER BUFFER in bytes */ +}; + +struct zoran_sync { + unsigned long frame; /* number of buffer that has been free'd */ + unsigned long length; /* number of code bytes in buffer (capture only) */ + unsigned long seq; /* frame sequence number */ + struct timeval timestamp; /* timestamp */ +}; + +struct zoran_status { + int input; /* Input channel, has to be set prior to BUZIOC_G_STATUS */ + int signal; /* Returned: 1 if valid video signal detected */ + int norm; /* Returned: VIDEO_MODE_PAL or VIDEO_MODE_NTSC */ + int color; /* Returned: 1 if color signal detected */ +}; + +struct zoran_params { + + /* The following parameters can only be queried */ + + int major_version; /* Major version number of driver */ + int minor_version; /* Minor version number of driver */ + + /* Main control parameters */ + + int input; /* Input channel: 0 = Composite, 1 = S-VHS */ + int norm; /* Norm: VIDEO_MODE_PAL or VIDEO_MODE_NTSC */ + int decimation; /* decimation of captured video, + enlargement of video played back. + Valid values are 1, 2, 4 or 0. + 0 is a special value where the user + has full control over video scaling */ + + /* The following parameters only have to be set if decimation==0, + for other values of decimation they provide the data how the image is captured */ + + int HorDcm; /* Horizontal decimation: 1, 2 or 4 */ + int VerDcm; /* Vertical decimation: 1 or 2 */ + int TmpDcm; /* Temporal decimation: 1 or 2, + if TmpDcm==2 in capture every second frame is dropped, + in playback every frame is played twice */ + int field_per_buff; /* Number of fields per buffer: 1 or 2 */ + int img_x; /* start of image in x direction */ + int img_y; /* start of image in y direction */ + int img_width; /* image width BEFORE decimation, + must be a multiple of HorDcm*16 */ + int img_height; /* image height BEFORE decimation, + must be a multiple of VerDcm*8 */ + + /* --- End of parameters for decimation==0 only --- */ + + /* JPEG control parameters */ + + int quality; /* Measure for quality of compressed images. + Scales linearly with the size of the compressed images. + Must be beetween 0 and 100, 100 is a compression + ratio of 1:4 */ + + int odd_even; /* Which field should come first ??? */ + + int APPn; /* Number of APP segment to be written, must be 0..15 */ + int APP_len; /* Length of data in JPEG APPn segment */ + char APP_data[60]; /* Data in the JPEG APPn segment. */ + + int COM_len; /* Length of data in JPEG COM segment */ + char COM_data[60]; /* Data in JPEG COM segment */ + + unsigned long jpeg_markers; /* Which markers should go into the JPEG output. + Unless you exactly know what you do, leave them untouched. + Inluding less markers will make the resulting code + smaller, but there will be fewer aplications + which can read it. + The presence of the APP and COM marker is + influenced by APP0_len and COM_len ONLY! */ +#define JPEG_MARKER_DHT (1<<3) /* Define Huffman Tables */ +#define JPEG_MARKER_DQT (1<<4) /* Define Quantization Tables */ +#define JPEG_MARKER_DRI (1<<5) /* Define Restart Interval */ +#define JPEG_MARKER_COM (1<<6) /* Comment segment */ +#define JPEG_MARKER_APP (1<<7) /* App segment, driver will allways use APP0 */ + + int VFIFO_FB; /* Flag for enabling Video Fifo Feedback. + If this flag is turned on and JPEG decompressing + is going to the screen, the decompress process + is stopped every time the Video Fifo is full. + This enables a smooth decompress to the screen + but the video output signal will get scrambled */ + + /* Misc */ + + char reserved[312]; /* Makes 512 bytes for this structure */ +}; + +/* +Private IOCTL to set up for displaying MJPEG +*/ +#define BUZIOC_G_PARAMS _IOR ('v', BASE_VIDIOCPRIVATE+0, struct zoran_params) +#define BUZIOC_S_PARAMS _IOWR('v', BASE_VIDIOCPRIVATE+1, struct zoran_params) +#define BUZIOC_REQBUFS _IOWR('v', BASE_VIDIOCPRIVATE+2, struct zoran_requestbuffers) +#define BUZIOC_QBUF_CAPT _IOW ('v', BASE_VIDIOCPRIVATE+3, int) +#define BUZIOC_QBUF_PLAY _IOW ('v', BASE_VIDIOCPRIVATE+4, int) +#define BUZIOC_SYNC _IOR ('v', BASE_VIDIOCPRIVATE+5, struct zoran_sync) +#define BUZIOC_G_STATUS _IOWR('v', BASE_VIDIOCPRIVATE+6, struct zoran_status) + + +#ifdef __KERNEL__ + +#define BUZ_NUM_STAT_COM 4 +#define BUZ_MASK_STAT_COM 3 + +#define BUZ_MAX_FRAME 256 /* Must be a power of 2 */ +#define BUZ_MASK_FRAME 255 /* Must be BUZ_MAX_FRAME-1 */ + +#if VIDEO_MAX_FRAME <= 32 +# define V4L_MAX_FRAME 32 +#elif VIDEO_MAX_FRAME <= 64 +# define V4L_MAX_FRAME 64 +#else +# error "Too many video frame buffers to handle" +#endif +#define V4L_MASK_FRAME (V4L_MAX_FRAME - 1) + + +#include "zr36057.h" + +enum card_type { + UNKNOWN = 0, + DC10, + DC10plus, + LML33, + BUZ +}; + +enum zoran_codec_mode { + BUZ_MODE_IDLE, /* nothing going on */ + BUZ_MODE_MOTION_COMPRESS, /* grabbing frames */ + BUZ_MODE_MOTION_DECOMPRESS, /* playing frames */ + BUZ_MODE_STILL_COMPRESS, /* still frame conversion */ + BUZ_MODE_STILL_DECOMPRESS /* still frame conversion */ +}; + +enum zoran_buffer_state { + BUZ_STATE_USER, /* buffer is owned by application */ + BUZ_STATE_PEND, /* buffer is queued in pend[] ready to feed to I/O */ + BUZ_STATE_DMA, /* buffer is queued in dma[] for I/O */ + BUZ_STATE_DONE /* buffer is ready to return to application */ +}; + +struct zoran_gbuffer { + u32 *frag_tab; /* addresses of frag table */ + u32 frag_tab_bus; /* same value cached to save time in ISR */ + enum zoran_buffer_state state; /* non-zero if corresponding buffer is in use in grab queue */ + struct zoran_sync bs; /* DONE: info to return to application */ +}; + +struct v4l_gbuffer { + char *fbuffer; /* virtual address of frame buffer */ + unsigned long fbuffer_phys; /* physical address of frame buffer */ + unsigned long fbuffer_bus; /* bus address of frame buffer */ + enum zoran_buffer_state state; /* state: unused/pending/done */ +}; + +struct tvnorm { + u16 Wt, Wa, HStart, HSyncStart, Ht, Ha, VStart; +}; + +struct zoran { + struct video_device video_dev; + struct i2c_bus i2c; + + int initialized; /* flag if zoran has been correctly initalized */ + int user; /* number of current users (0 or 1) */ + enum card_type card; + struct tvnorm *timing; + + unsigned short id; /* number of this device */ + char name[32]; /* name of this device */ + struct pci_dev *pci_dev; /* PCI device */ + unsigned char revision; /* revision of zr36057 */ + unsigned int zr36057_adr; /* bus address of IO mem returned by PCI BIOS */ + unsigned char *zr36057_mem; /* pointer to mapped IO memory */ + + int map_mjpeg_buffers; /* Flag which bufferset will map by next mmap() */ + + spinlock_t lock; /* Spinlock irq and hardware */ + struct semaphore sem; /* Guard parallel ioctls and mmap */ + + /* Video for Linux parameters */ + + struct video_picture picture; /* Current picture params */ + struct video_buffer buffer; /* Current buffer params */ + struct video_window window; /* Current window params */ + int buffer_set, window_set; /* Flags if the above structures are set */ + int video_interlace; /* Image on screen is interlaced */ + + u32 *overlay_mask; + wait_queue_head_t v4l_capq; + + int v4l_overlay_active; /* Overlay grab is activated */ + int v4l_memgrab_active; /* Memory grab is activated */ + + int v4l_grab_frame; /* Frame number being currently grabbed */ +#define NO_GRAB_ACTIVE (-1) + int v4l_grab_seq; /* Number of frames grabbed */ + int gwidth; /* Width of current memory capture */ + int gheight; /* Height of current memory capture */ + int gformat; /* Format of ... */ + int gbpl; /* byte per line of ... */ + + /* V4L grab queue of frames pending */ + + unsigned v4l_pend_head; + unsigned v4l_pend_tail; + int v4l_pend[V4L_MAX_FRAME]; + + struct v4l_gbuffer v4l_gbuf[VIDEO_MAX_FRAME]; /* V4L buffers' info */ + + /* Buz MJPEG parameters */ + + unsigned long jpg_nbufs; /* Number of buffers */ + unsigned long jpg_bufsize; /* Size of mjpeg buffers in bytes */ + int jpg_buffers_allocated; /* Flag if buffers are allocated */ + int need_contiguous; /* Flag if contiguous buffers are needed */ + + enum zoran_codec_mode codec_mode; /* status of codec */ + struct zoran_params params; /* structure with a lot of things to play with */ + + wait_queue_head_t jpg_capq; /* wait here for grab to finish */ + + /* grab queue counts/indices, mask with BUZ_MASK_STAT_COM before using as index */ + /* (dma_head - dma_tail) is number active in DMA, must be <= BUZ_NUM_STAT_COM */ + /* (value & BUZ_MASK_STAT_COM) corresponds to index in stat_com table */ + unsigned long jpg_que_head; /* Index where to put next buffer which is queued */ + unsigned long jpg_dma_head; /* Index of next buffer which goes into stat_com */ + unsigned long jpg_dma_tail; /* Index of last buffer in stat_com */ + unsigned long jpg_que_tail; /* Index of last buffer in queue */ + unsigned long jpg_seq_num; /* count of frames since grab/play started */ + unsigned long jpg_err_seq; /* last seq_num before error */ + unsigned long jpg_err_shift; + unsigned long jpg_queued_num; /* count of frames queued since grab/play started */ + + /* zr36057's code buffer table */ + u32 *stat_com; /* stat_com[i] is indexed by dma_head/tail & BUZ_MASK_STAT_COM */ + + /* (value & BUZ_MASK_FRAME) corresponds to index in pend[] queue */ + int jpg_pend[BUZ_MAX_FRAME]; + + /* array indexed by frame number */ + struct zoran_gbuffer jpg_gbuf[BUZ_MAX_FRAME]; /* MJPEG buffers' info */ + + /* Additional stuff for testing */ + struct proc_dir_entry *zoran_proc; + + int testing; + int jpeg_error; + int intr_counter_GIRQ1; + int intr_counter_GIRQ0; + int intr_counter_CodRepIRQ; + int intr_counter_JPEGRepIRQ; + int field_counter; + int IRQ1_in; + int IRQ1_out; + int JPEG_in; + int JPEG_out; + int JPEG_0; + int JPEG_1; + int END_event_missed; + int JPEG_missed; + int JPEG_error; + int num_errors; + int JPEG_max_missed; + int JPEG_min_missed; + + u32 last_isr; + unsigned long frame_num; + + wait_queue_head_t test_q; +}; + +#endif + +/*The following should be done in more portable way. It depends on define + of _ALPHA_BUZ in the Makefile.*/ + +#ifdef _ALPHA_BUZ +#define btwrite(dat,adr) writel((dat),(char *) (zr->zr36057_adr+(adr))) +#define btread(adr) readl(zr->zr36057_adr+(adr)) +#else +#define btwrite(dat,adr) writel((dat), (char *) (zr->zr36057_mem+(adr))) +#define btread(adr) readl(zr->zr36057_mem+(adr)) +#endif + +#define btand(dat,adr) btwrite((dat) & btread(adr), adr) +#define btor(dat,adr) btwrite((dat) | btread(adr), adr) +#define btaor(dat,mask,adr) btwrite((dat) | ((mask) & btread(adr)), adr) + +#define I2C_TSA5522 0xc2 +#define I2C_TDA9850 0xb6 +#define I2C_HAUPEE 0xa0 +#define I2C_STBEE 0xae +#define I2C_SAA7111 0x48 +#define I2C_SAA7110 0x9c +#define I2C_SAA7185 0x88 +//#define I2C_ADV7175 0xd4 +#define I2C_ADV7175 0x54 + +#define TDA9850_CON1 0x04 +#define TDA9850_CON2 0x05 +#define TDA9850_CON3 0x06 +#define TDA9850_CON4 0x07 +#define TDA9850_ALI1 0x08 +#define TDA9850_ALI2 0x09 +#define TDA9850_ALI3 0x0a + +#endif diff -u --recursive --new-file v2.4.6/linux/drivers/media/video/zoran_procfs.c linux/drivers/media/video/zoran_procfs.c --- v2.4.6/linux/drivers/media/video/zoran_procfs.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/media/video/zoran_procfs.c Wed Jul 4 14:41:33 2001 @@ -0,0 +1,170 @@ +#include <linux/config.h> +#include <linux/ctype.h> + +struct procfs_params_zr36067 { + char *name; + short reg; + u32 mask; + short bit; +}; + +static struct procfs_params_zr36067 zr67[] = { + {"HSPol", 0x000, 1, 30}, + {"HStart", 0x000, 0x3ff, 10}, + {"HEnd", 0x000, 0x3ff, 0}, + + {"VSPol", 0x004, 1, 30}, + {"VStart", 0x004, 0x3ff, 10}, + {"VEnd", 0x004, 0x3ff, 0}, + + {"ExtFl", 0x008, 1, 26}, + {"TopField", 0x008, 1, 25}, + {"VCLKPol", 0x008, 1, 24}, + {"DupFld", 0x008, 1, 20}, + {"LittleEndian", 0x008, 1, 0}, + + {"HsyncStart", 0x10c, 0xffff, 16}, + {"LineTot", 0x10c, 0xffff, 0}, + + {"NAX", 0x110, 0xffff, 16}, + {"PAX", 0x110, 0xffff, 0}, + + {"NAY", 0x114, 0xffff, 16}, + {"PAY", 0x114, 0xffff, 0}, +/* {"",,,}, */ + + {NULL, 0, 0, 0}, +}; + +static void setparam(struct zoran *zr, char *name, char *sval) +{ + int i, reg0, reg, val; + i = 0; + while (zr67[i].name != NULL) { + if (!strncmp(name, zr67[i].name, strlen(zr67[i].name))) { + reg = reg0 = btread(zr67[i].reg); + reg &= ~(zr67[i].mask << zr67[i].bit); + if (!isdigit(sval[0])) + break; + val = simple_strtoul(sval, NULL, 0); + if ((val & ~zr67[i].mask)) + break; + reg |= (val & zr67[i].mask) << zr67[i].bit; + printk(KERN_INFO "%s: setparam: setting ZR36067 register 0x%03x: 0x%08x=>0x%08x %s=%d\n", + zr->name, zr67[i].reg, reg0, reg, zr67[i].name, val); + btwrite(reg, zr67[i].reg); + break; + } + i++; + } +} + +/* This macro was stolen from /usr/src/drivers/char/nvram.c and modified */ +#define PRINT_PROC(args...) \ + do { \ + if (begin + len > offset + size) { \ + *eof = 0; \ + break; \ + } \ + len += sprintf( buffer+len, ##args ); \ + if (begin + len < offset) { \ + begin += len; \ + len = 0; \ + } \ + } while(0) + +static int zoran_read_proc(char *buffer, char **start, off_t offset, int size, int *eof, void *data) +{ +#ifdef CONFIG_PROC_FS + int len = 0; + off_t begin = 0; + + int i; + struct zoran *zr; + + zr = (struct zoran *) data; + DEBUG2(printk(KERN_INFO "%s: read_proc: buffer=%x, offset=%d, size=%d, data=%x\n", zr->name, (int) buffer, (int) offset, size, (int) data)); + *eof = 1; + PRINT_PROC("ZR36067 registers:"); + for (i = 0; i < 0x130; i += 4) { + if (!(i % 16)) { + PRINT_PROC("\n%03X", i); + } + PRINT_PROC(" %08X ", btread(i)); + } + PRINT_PROC("\n"); + if (offset >= len + begin) { + return 0; + } + *start = buffer + begin - offset; + return ((size < begin + len - offset) ? size : begin + len - offset); +#endif + return 0; +} + +static int zoran_write_proc(struct file *file, const char *buffer, unsigned long count, void *data) +{ +#ifdef CONFIG_PROC_FS + char *string, *sp; + char *line, *ldelim, *varname, *svar, *tdelim; + struct zoran *zr; + + zr = (struct zoran *) data; + + string = sp = vmalloc(count + 1); + if (!string) { + printk(KERN_ERR "%s: write_proc: can not allocate memory\n", zr->name); + return -ENOMEM; + } + memcpy(string, buffer, count); + string[count] = 0; + DEBUG2(printk(KERN_INFO "%s: write_proc: name=%s count=%lu data=%x\n", zr->name, file->f_dentry->d_name.name, count, (int) data)); + ldelim = " \t\n"; + tdelim = "="; + line = strpbrk(sp, ldelim); + while (line) { + *line = 0; + svar = strpbrk(sp, tdelim); + if (svar) { + *svar = 0; + varname = sp; + svar++; + setparam(zr, varname, svar); + } + sp = line + 1; + line = strpbrk(sp, ldelim); + } + vfree(string); +#endif + return count; +} + +static int zoran_proc_init(int i) +{ +#ifdef CONFIG_PROC_FS + char name[8]; + sprintf(name, "zoran%d", i); + if ((zoran[i].zoran_proc = create_proc_entry(name, 0, 0))) { + zoran[i].zoran_proc->read_proc = zoran_read_proc; + zoran[i].zoran_proc->write_proc = zoran_write_proc; + zoran[i].zoran_proc->data = &zoran[i]; + printk(KERN_INFO "%s: procfs entry /proc/%s allocated. data=%x\n", zoran[i].name, name, (int) zoran[i].zoran_proc->data); + } else { + printk(KERN_ERR "%s: Unable to initialise /proc/%s\n", zoran[i].name, name); + return 1; + } +#endif + return 0; +} + +static void zoran_proc_cleanup(int i) +{ +#ifdef CONFIG_PROC_FS + char name[8]; + sprintf(name, "zoran%d", i); + if (zoran[i].zoran_proc) { + remove_proc_entry(name, 0); + } + zoran[i].zoran_proc = NULL; +#endif +} diff -u --recursive --new-file v2.4.6/linux/drivers/media/video/zr36057.h linux/drivers/media/video/zr36057.h --- v2.4.6/linux/drivers/media/video/zr36057.h Mon Jul 5 20:09:40 1999 +++ linux/drivers/media/video/zr36057.h Wed Jul 4 14:41:33 2001 @@ -1,22 +1,22 @@ /* - zr36057.h - zr36057 register offsets + zr36057.h - zr36057 register offsets - Copyright (C) 1998 Dave Perks <dperks@ibm.net> + Copyright (C) 1998 Dave Perks <dperks@ibm.net> - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ #ifndef _ZR36057_H_ #define _ZR36057_H_ @@ -24,19 +24,19 @@ /* Zoran ZR36057 registers */ -#define ZR36057_VFEHCR 0x000 /* Video Front End, Horizontal Configuration Register */ +#define ZR36057_VFEHCR 0x000 /* Video Front End, Horizontal Configuration Register */ #define ZR36057_VFEHCR_HSPol (1<<30) #define ZR36057_VFEHCR_HStart 10 #define ZR36057_VFEHCR_HEnd 0 #define ZR36057_VFEHCR_Hmask 0x3ff -#define ZR36057_VFEVCR 0x004 /* Video Front End, Vertical Configuration Register */ +#define ZR36057_VFEVCR 0x004 /* Video Front End, Vertical Configuration Register */ #define ZR36057_VFEVCR_VSPol (1<<30) #define ZR36057_VFEVCR_VStart 10 #define ZR36057_VFEVCR_VEnd 0 #define ZR36057_VFEVCR_Vmask 0x3ff -#define ZR36057_VFESPFR 0x008 /* Video Front End, Scaler and Pixel Format Register */ +#define ZR36057_VFESPFR 0x008 /* Video Front End, Scaler and Pixel Format Register */ #define ZR36057_VFESPFR_ExtFl (1<<26) #define ZR36057_VFESPFR_TopField (1<<25) #define ZR36057_VFESPFR_VCLKPol (1<<24) @@ -52,65 +52,65 @@ #define ZR36057_VFESPFR_Pack24 (1<<1) #define ZR36057_VFESPFR_LittleEndian (1<<0) -#define ZR36057_VDTR 0x00c /* Video Display "Top" Register */ +#define ZR36057_VDTR 0x00c /* Video Display "Top" Register */ -#define ZR36057_VDBR 0x010 /* Video Display "Bottom" Register */ +#define ZR36057_VDBR 0x010 /* Video Display "Bottom" Register */ -#define ZR36057_VSSFGR 0x014 /* Video Stride, Status, and Frame Grab Register */ +#define ZR36057_VSSFGR 0x014 /* Video Stride, Status, and Frame Grab Register */ #define ZR36057_VSSFGR_DispStride 16 #define ZR36057_VSSFGR_VidOvf (1<<8) #define ZR36057_VSSFGR_SnapShot (1<<1) #define ZR36057_VSSFGR_FrameGrab (1<<0) -#define ZR36057_VDCR 0x018 /* Video Display Configuration Register */ +#define ZR36057_VDCR 0x018 /* Video Display Configuration Register */ #define ZR36057_VDCR_VidEn (1<<31) #define ZR36057_VDCR_MinPix 24 #define ZR36057_VDCR_Triton (1<<24) #define ZR36057_VDCR_VidWinHt 12 #define ZR36057_VDCR_VidWinWid 0 -#define ZR36057_MMTR 0x01c /* Masking Map "Top" Register */ +#define ZR36057_MMTR 0x01c /* Masking Map "Top" Register */ -#define ZR36057_MMBR 0x020 /* Masking Map "Bottom" Register */ +#define ZR36057_MMBR 0x020 /* Masking Map "Bottom" Register */ -#define ZR36057_OCR 0x024 /* Overlay Control Register */ +#define ZR36057_OCR 0x024 /* Overlay Control Register */ #define ZR36057_OCR_OvlEnable (1 << 15) #define ZR36057_OCR_MaskStride 0 -#define ZR36057_SPGPPCR 0x028 /* System, PCI, and General Purpose Pins Control Register */ +#define ZR36057_SPGPPCR 0x028 /* System, PCI, and General Purpose Pins Control Register */ #define ZR36057_SPGPPCR_SoftReset (1<<24) -#define ZR36057_GPPGCR1 0x02c /* General Purpose Pins and GuestBus Control Register (1) */ +#define ZR36057_GPPGCR1 0x02c /* General Purpose Pins and GuestBus Control Register (1) */ -#define ZR36057_MCSAR 0x030 /* MPEG Code Source Address Register */ +#define ZR36057_MCSAR 0x030 /* MPEG Code Source Address Register */ -#define ZR36057_MCTCR 0x034 /* MPEG Code Transfer Control Register */ +#define ZR36057_MCTCR 0x034 /* MPEG Code Transfer Control Register */ #define ZR36057_MCTCR_CodTime (1 << 30) #define ZR36057_MCTCR_CEmpty (1 << 29) #define ZR36057_MCTCR_CFlush (1 << 28) #define ZR36057_MCTCR_CodGuestID 20 #define ZR36057_MCTCR_CodGuestReg 16 -#define ZR36057_MCMPR 0x038 /* MPEG Code Memory Pointer Register */ +#define ZR36057_MCMPR 0x038 /* MPEG Code Memory Pointer Register */ -#define ZR36057_ISR 0x03c /* Interrupt Status Register */ +#define ZR36057_ISR 0x03c /* Interrupt Status Register */ #define ZR36057_ISR_GIRQ1 (1<<30) #define ZR36057_ISR_GIRQ0 (1<<29) #define ZR36057_ISR_CodRepIRQ (1<<28) #define ZR36057_ISR_JPEGRepIRQ (1<<27) -#define ZR36057_ICR 0x040 /* Interrupt Control Register */ +#define ZR36057_ICR 0x040 /* Interrupt Control Register */ #define ZR36057_ICR_GIRQ1 (1<<30) #define ZR36057_ICR_GIRQ0 (1<<29) #define ZR36057_ICR_CodRepIRQ (1<<28) #define ZR36057_ICR_JPEGRepIRQ (1<<27) #define ZR36057_ICR_IntPinEn (1<<24) -#define ZR36057_I2CBR 0x044 /* I2C Bus Register */ +#define ZR36057_I2CBR 0x044 /* I2C Bus Register */ #define ZR36057_I2CBR_SDA (1<<1) #define ZR36057_I2CBR_SCL (1<<0) -#define ZR36057_JMC 0x100 /* JPEG Mode and Control */ +#define ZR36057_JMC 0x100 /* JPEG Mode and Control */ #define ZR36057_JMC_JPG (1 << 31) #define ZR36057_JMC_JPGExpMode (0 << 29) #define ZR36057_JMC_JPGCmpMode (1 << 29) @@ -124,45 +124,45 @@ #define ZR36057_JMC_CFIFO_FB (1 << 1) #define ZR36057_JMC_Stll_LitEndian (1 << 0) -#define ZR36057_JPC 0x104 /* JPEG Process Control */ +#define ZR36057_JPC 0x104 /* JPEG Process Control */ #define ZR36057_JPC_P_Reset (1 << 7) #define ZR36057_JPC_CodTrnsEn (1 << 5) #define ZR36057_JPC_Active (1 << 0) -#define ZR36057_VSP 0x108 /* Vertical Sync Parameters */ +#define ZR36057_VSP 0x108 /* Vertical Sync Parameters */ #define ZR36057_VSP_VsyncSize 16 #define ZR36057_VSP_FrmTot 0 -#define ZR36057_HSP 0x10c /* Horizontal Sync Parameters */ +#define ZR36057_HSP 0x10c /* Horizontal Sync Parameters */ #define ZR36057_HSP_HsyncStart 16 #define ZR36057_HSP_LineTot 0 -#define ZR36057_FHAP 0x110 /* Field Horizontal Active Portion */ +#define ZR36057_FHAP 0x110 /* Field Horizontal Active Portion */ #define ZR36057_FHAP_NAX 16 #define ZR36057_FHAP_PAX 0 -#define ZR36057_FVAP 0x114 /* Field Vertical Active Portion */ +#define ZR36057_FVAP 0x114 /* Field Vertical Active Portion */ #define ZR36057_FVAP_NAY 16 #define ZR36057_FVAP_PAY 0 -#define ZR36057_FPP 0x118 /* Field Process Parameters */ +#define ZR36057_FPP 0x118 /* Field Process Parameters */ #define ZR36057_FPP_Odd_Even (1 << 0) -#define ZR36057_JCBA 0x11c /* JPEG Code Base Address */ +#define ZR36057_JCBA 0x11c /* JPEG Code Base Address */ -#define ZR36057_JCFT 0x120 /* JPEG Code FIFO Threshold */ +#define ZR36057_JCFT 0x120 /* JPEG Code FIFO Threshold */ -#define ZR36057_JCGI 0x124 /* JPEG Codec Guest ID */ +#define ZR36057_JCGI 0x124 /* JPEG Codec Guest ID */ #define ZR36057_JCGI_JPEGuestID 4 #define ZR36057_JCGI_JPEGuestReg 0 -#define ZR36057_GCR2 0x12c /* GuestBus Control Register (2) */ +#define ZR36057_GCR2 0x12c /* GuestBus Control Register (2) */ -#define ZR36057_POR 0x200 /* Post Office Register */ +#define ZR36057_POR 0x200 /* Post Office Register */ #define ZR36057_POR_POPen (1<<25) #define ZR36057_POR_POTime (1<<24) #define ZR36057_POR_PODir (1<<23) -#define ZR36057_STR 0x300 /* "Still" Transfer Register */ +#define ZR36057_STR 0x300 /* "Still" Transfer Register */ #endif diff -u --recursive --new-file v2.4.6/linux/drivers/media/video/zr36060.h linux/drivers/media/video/zr36060.h --- v2.4.6/linux/drivers/media/video/zr36060.h Mon Jul 5 20:09:40 1999 +++ linux/drivers/media/video/zr36060.h Wed Jul 4 14:41:33 2001 @@ -1,22 +1,22 @@ /* - zr36060.h - zr36060 register offsets + zr36060.h - zr36060 register offsets - Copyright (C) 1998 Dave Perks <dperks@ibm.net> + Copyright (C) 1998 Dave Perks <dperks@ibm.net> - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + 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. + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ + 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. +*/ #ifndef _ZR36060_H_ #define _ZR36060_H_ diff -u --recursive --new-file v2.4.6/linux/drivers/media/video/zr36067.c linux/drivers/media/video/zr36067.c --- v2.4.6/linux/drivers/media/video/zr36067.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/media/video/zr36067.c Wed Jul 4 14:41:33 2001 @@ -0,0 +1,4900 @@ +#define DEBUGLEVEL 0 +#define MAX_KMALLOC_MEM (128*1024) + +/* + Miro/Pinnacle Systems Inc. DC10/DC10plus and + Linux Media Labs LML33 video capture boards driver + now with IOMega BUZ support! + + Copyright (C) 2000 Serguei Miridonov <mirsev@cicese.mx> + + Changes for BUZ by Wolfgang Scherr <scherr@net4you.net> + + Based on + + Miro DC10 driver + Copyright (C) 1999 Wolfgang Scherr <scherr@net4you.net> + + Iomega Buz driver version 1.0 + Copyright (C) 1999 Rainer Johanni <Rainer@Johanni.de> + + buz.0.0.3 + Copyright (C) 1998 Dave Perks <dperks@ibm.net> + + bttv - Bt848 frame grabber driver + Copyright (C) 1996,97,98 Ralph Metzler (rjkm@thp.uni-koeln.de) + & Marcus Metzler (mocm@thp.uni-koeln.de) + + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include <linux/config.h> +#include <linux/version.h> +#include <linux/init.h> +#include <linux/module.h> +#include <linux/delay.h> +#include <linux/errno.h> +#include <linux/fs.h> +#include <linux/kernel.h> +#include <linux/major.h> +#include <linux/malloc.h> +#include <linux/mm.h> +#include <linux/pci.h> +#include <linux/signal.h> +#include <asm/io.h> +#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/spinlock.h> +#include <linux/vmalloc.h> +#include <linux/i2c-old.h> +#define MAP_NR(x) virt_to_page(x) +#define ZORAN_HARDWARE VID_HARDWARE_ZR36067 + +#include <linux/videodev.h> + +#include <asm/uaccess.h> +#include <linux/proc_fs.h> + +#include "zoran.h" +#include <linux/video_decoder.h> +#include <linux/video_encoder.h> + +// RJ: Test only - want to test BUZ_USE_HIMEM even when CONFIG_BIGPHYS_AREA is defined +#if !defined(CONFIG_BIGPHYS_AREA) +//#undef CONFIG_BIGPHYS_AREA +#define BUZ_USE_HIMEM +#endif + +#if defined(CONFIG_BIGPHYS_AREA) +# include <linux/bigphysarea.h> +#endif + +#define IRQ_MASK ( ZR36057_ISR_GIRQ0 | ZR36057_ISR_GIRQ1 | /* ZR36057_ISR_CodRepIRQ | */ ZR36057_ISR_JPEGRepIRQ ) // SW +//#define GPIO_MASK 0xcd +//#define GPIO_MASK 0x8d + +/* +DC10: +GPIO0 = /RESET ZR 36060 +GPIO1 = VIDEO BUS DIRECTION (0: CAPTURE, 1: DISPLAY) +GPIO2 = VIDEO BUS ENABLE (0: ON, 1: OFF) +GPIO3 = /SLEEP ZR 36060 +GPIO4 = ADC7175 (video out) FREQUENCY (0: LCC/SAA7110, 1: 27 MHz (quarz)) +GPIO5 = ZORAN FREQUENCY (0: LCC and LCC2 from SAA7110, + 1: 27 and 13.5 MHz (quarz)) +GPIO6 = /FRAME ZR 36060 +GPIO7 = /RESET ADV7175 (video out) +(I think they lost the SAA7110 reset.....) + +GIRQ0 signals that ZR36060's DATERR# line is asserted. +GIRQ1 signals a vertical sync of the video signal (VS SAA7110) + + SAA7110A: + mode 0 - Composite + mode 1 - + mode 2 - + mode 3 - + mode 4 - + mode 5 - internal Composite (from PCTV) + mode 6 - + mode 7 - S-Video + +BUZ: +GPIO0 = 1, take board out of reset +GPIO1 = 1, take JPEG codec out of sleep mode +GPIO3 = 1, deassert FRAME# to 36060 + +GIRQ0 signals a vertical sync of the video signal +GIRQ1 signals that ZR36060's DATERR# line is asserted. + +SAA7111A + + In their infinite wisdom, the Iomega engineers decided to + use the same input line for composite and S-Video Color, + although there are two entries not connected at all! + Through this ingenious strike, it is not possible to + keep two running video sources connected at the same time + to Composite and S-VHS input! + + mode 0 - N/C + mode 1 - S-Video Y + mode 2 - noise or something I don't know + mode 3 - Composite and S-Video C + mode 4 - N/C + mode 5 - S-Video (gain C independently selectable of gain Y) + mode 6 - N/C + mode 7 - S-Video (gain C adapted to gain Y) +*/ + +#define MAJOR_VERSION 0 /* driver major version */ +#define MINOR_VERSION 7 /* driver minor version */ + +#define ZORAN_NAME "zr36067" /* name of the device */ + +#define BUZ_ERR KERN_ERR ZORAN_NAME +#define BUZ_DEBUG KERN_INFO ZORAN_NAME +#define BUZ_INFO KERN_INFO ZORAN_NAME +#define BUZ_WARNING KERN_WARNING ZORAN_NAME + +#if(DEBUGLEVEL>0) +#define DEBUG1(x...) x +#else +#define DEBUG1(x...) +#endif + +#if(DEBUGLEVEL>1) +#define DEBUG2(x...) x +#else +#define DEBUG2(x...) +#endif + +#if(DEBUGLEVEL>2) +#define DEBUG3(x...) x +#else +#define DEBUG3(x...) +#endif + +#if(DEBUGLEVEL>3) +#define DEBUG4(x...) x +#else +#define DEBUG4(x...) +#endif + +/* The parameters for this driver */ + +/* + The video mem address of the video card. + The driver has a little database for some videocards + to determine it from there. If your video card is not in there + you have either to give it to the driver as a parameter + or set in in a VIDIOCSFBUF ioctl + */ + +static unsigned long vidmem = 0; /* Video memory base address */ + +/* Special purposes only: */ + +static int triton = 0; /* 0=no, 1=yes */ +static int natoma = 0; /* 0=no, 1=yes */ + +/* + Number and size of grab buffers for Video 4 Linux + The vast majority of applications should not need more than 2, + the very popular BTTV driver actually does ONLY have 2. + Time sensitive applications might need more, the maximum + is VIDEO_MAX_FRAME (defined in <linux/videodev.h>). + + The size is set so that the maximum possible request + can be satisfied. Decrease it, if bigphys_area alloc'd + memory is low. If you don't have the bigphys_area patch, + set it to 128 KB. Will you allow only to grab small + images with V4L, but that's better than nothing. + + v4l_bufsize has to be given in KB ! + +*/ + +static int v4l_nbufs = 2; +static int v4l_bufsize = 128; /* Everybody should be able to work with this setting */ + +/* + Default input and video norm at startup of the driver. +*/ + +static int default_input = 0; /* 0=Composite, 1=S-VHS */ +static int default_norm = 0; /* 0=PAL, 1=NTSC 2=SECAM */ +static int lock_norm = 0; /* 1=Don't change TV standard (norm) */ + +static int pass_through = 0; /* 1=Pass through TV signal when device is not used */ + /* 0=Show color bar when device is not used (LML33: only if lml33dpath=1) */ + +static int lml33dpath = 0; /* 1 will use digital path in capture mode instead of analog. + It can be used for picture adjustments using tool like xawtv + while watching image on TV monitor connected to the output. + However, due to absence of 75 Ohm load on Bt819 input, there + will be some image imperfections */ +static int video_nr = -1; + +MODULE_PARM(vidmem, "i"); +MODULE_PARM(triton, "i"); +MODULE_PARM(natoma, "i"); +MODULE_PARM(v4l_nbufs, "i"); +MODULE_PARM(v4l_bufsize, "i"); +MODULE_PARM(default_input, "i"); +MODULE_PARM(default_norm, "i"); +MODULE_PARM(lock_norm, "i"); +MODULE_PARM(pass_through, "i"); +MODULE_PARM(lml33dpath, "i"); +MODULE_PARM(video_nr, "i"); + +/* Anybody who uses more than four? */ +#define BUZ_MAX 4 + +static int zoran_num; /* number of Buzs in use */ +static struct zoran zoran[BUZ_MAX]; + +/* forward references */ + +static void v4l_fbuffer_free(struct zoran *zr); +static void jpg_fbuffer_free(struct zoran *zr); +static void zoran_feed_stat_com(struct zoran *zr); + +/* + * Allocate the V4L grab buffers + * + * These have to be pysically contiguous. + * If v4l_bufsize <= MAX_KMALLOC_MEM we use kmalloc + * else we try to allocate them with bigphysarea_alloc_pages + * if the bigphysarea patch is present in the kernel, + * else we try to use high memory (if the user has bootet + * Linux with the necessary memory left over). + */ + +static int v4l_fbuffer_alloc(struct zoran *zr) +{ + int i, off; + unsigned char *mem; + + for (i = 0; i < v4l_nbufs; i++) { + if (zr->v4l_gbuf[i].fbuffer) + printk(KERN_WARNING + "%s: v4l_fbuffer_alloc: buffer %d allready allocated ???\n", + zr->name, i); + + //udelay(20); + if (v4l_bufsize <= MAX_KMALLOC_MEM) { + /* Use kmalloc */ + + mem = + (unsigned char *) kmalloc(v4l_bufsize, + GFP_KERNEL); + if (mem == 0) { + printk(KERN_ERR + "%s: kmalloc for V4L bufs failed\n", + zr->name); + v4l_fbuffer_free(zr); + return -ENOBUFS; + } + zr->v4l_gbuf[i].fbuffer = mem; + zr->v4l_gbuf[i].fbuffer_phys = virt_to_phys(mem); + zr->v4l_gbuf[i].fbuffer_bus = virt_to_bus(mem); + for (off = 0; off < v4l_bufsize; off += PAGE_SIZE) + mem_map_reserve(MAP_NR(mem + off)); + DEBUG1(printk + (KERN_INFO + "%s: V4L frame %d mem 0x%lx (bus: 0x%lx)\n", + zr->name, i, (unsigned long) mem, + virt_to_bus(mem))); + } else { +#if defined(CONFIG_BIGPHYS_AREA) + /* Use bigphysarea_alloc_pages */ + + int n = (v4l_bufsize + PAGE_SIZE - 1) / PAGE_SIZE; + mem = + (unsigned char *) bigphysarea_alloc_pages(n, 0, + GFP_KERNEL); + if (mem == 0) { + printk(KERN_ERR + "%s: bigphysarea_alloc_pages for V4L bufs failed\n", + zr->name); + v4l_fbuffer_free(zr); + return -ENOBUFS; + } + zr->v4l_gbuf[i].fbuffer = mem; + zr->v4l_gbuf[i].fbuffer_phys = virt_to_phys(mem); + zr->v4l_gbuf[i].fbuffer_bus = virt_to_bus(mem); + DEBUG1(printk + (KERN_INFO + "%s: Bigphysarea frame %d mem 0x%x (bus: 0x%x)\n", + zr->name, i, (unsigned) mem, + (unsigned) virt_to_bus(mem))); + + /* Zero out the allocated memory */ + memset(zr->v4l_gbuf[i].fbuffer, 0, v4l_bufsize); +#else + /* No bigphysarea present, usage of high memory disabled, + but user wants buffers of more than MAX_KMALLOC_MEM */ + printk(KERN_ERR + "%s: No bigphysarea_patch present, usage of high memory disabled,\n", + zr->name); + printk(KERN_ERR + "%s: sorry, could not allocate V4L buffers of size %d KB.\n", + zr->name, v4l_bufsize >> 10); + return -ENOBUFS; +#endif + } + } + + return 0; +} + +/* free the V4L grab buffers */ + +static void v4l_fbuffer_free(struct zoran *zr) +{ + int i, off; + unsigned char *mem; + + for (i = 0; i < v4l_nbufs; i++) { + if (!zr->v4l_gbuf[i].fbuffer) + continue; + + if (v4l_bufsize <= MAX_KMALLOC_MEM) { + mem = zr->v4l_gbuf[i].fbuffer; + for (off = 0; off < v4l_bufsize; off += PAGE_SIZE) + mem_map_unreserve(MAP_NR(mem + off)); + kfree((void *) zr->v4l_gbuf[i].fbuffer); + } +#if defined(CONFIG_BIGPHYS_AREA) + else + bigphysarea_free_pages((void *) zr->v4l_gbuf[i]. + fbuffer); +#endif + zr->v4l_gbuf[i].fbuffer = NULL; + } +} + +/* + * Allocate the MJPEG grab buffers. + * + * If the requested buffer size is smaller than MAX_KMALLOC_MEM, + * kmalloc is used to request a physically contiguous area, + * else we allocate the memory in framgents with get_free_page. + * + * If a Natoma chipset is present and this is a revision 1 zr36057, + * each MJPEG buffer needs to be physically contiguous. + * (RJ: This statement is from Dave Perks' original driver, + * I could never check it because I have a zr36067) + * The driver cares about this because it reduces the buffer + * size to MAX_KMALLOC_MEM in that case (which forces contiguous allocation). + * + * RJ: The contents grab buffers needs never be accessed in the driver. + * Therefore there is no need to allocate them with vmalloc in order + * to get a contiguous virtual memory space. + * I don't understand why many other drivers first allocate them with + * vmalloc (which uses internally also get_free_page, but delivers you + * virtual addresses) and then again have to make a lot of efforts + * to get the physical address. + * + */ + +static int jpg_fbuffer_alloc(struct zoran *zr) +{ + int i, j, off; //alloc_contig; + unsigned long mem; + + /* Decide if we should alloc contiguous or fragmented memory */ + /* This has to be identical in jpg_fbuffer_alloc and jpg_fbuffer_free */ + + //alloc_contig = (zr->jpg_bufsize <= MAX_KMALLOC_MEM); + + for (i = 0; i < zr->jpg_nbufs; i++) { + if (zr->jpg_gbuf[i].frag_tab) + printk(KERN_WARNING + "%s: jpg_fbuffer_alloc: buffer %d allready allocated ???\n", + zr->name, i); + + /* Allocate fragment table for this buffer */ + + mem = get_free_page(GFP_KERNEL); + if (mem == 0) { + printk(KERN_ERR + "%s: jpg_fbuffer_alloc: get_free_page (frag_tab) failed for buffer %d\n", + zr->name, i); + jpg_fbuffer_free(zr); + return -ENOBUFS; + } + memset((void *) mem, 0, PAGE_SIZE); + zr->jpg_gbuf[i].frag_tab = (u32 *) mem; + zr->jpg_gbuf[i].frag_tab_bus = virt_to_bus((void *) mem); + + //if (alloc_contig) { + if (zr->need_contiguous) { + mem = (unsigned long) kmalloc(zr->jpg_bufsize, GFP_KERNEL); + if (mem == 0) { + printk(KERN_ERR "%s: jpg_fbuffer_alloc: kmalloc failed for buffer %d\n", + zr->name, i); + jpg_fbuffer_free(zr); + return -ENOBUFS; + } + zr->jpg_gbuf[i].frag_tab[0] = virt_to_bus((void *) mem); + zr->jpg_gbuf[i].frag_tab[1] = + ((zr->jpg_bufsize / 4) << 1) | 1; + for (off = 0; off < zr->jpg_bufsize; off += PAGE_SIZE) + mem_map_reserve(MAP_NR(mem + off)); + } else { + /* jpg_bufsize is allreay page aligned */ + for (j = 0; j < zr->jpg_bufsize / PAGE_SIZE; j++) + { + mem = get_free_page(GFP_KERNEL); + if (mem == 0) { + printk(KERN_ERR + "%s: jpg_fbuffer_alloc: get_free_page failed for buffer %d\n", + zr->name, i); + jpg_fbuffer_free(zr); + return -ENOBUFS; + } + + zr->jpg_gbuf[i].frag_tab[2 * j] = + virt_to_bus((void *) mem); + zr->jpg_gbuf[i].frag_tab[2 * j + 1] = + (PAGE_SIZE / 4) << 1; + mem_map_reserve(MAP_NR(mem)); + } + + zr->jpg_gbuf[i].frag_tab[2 * j - 1] |= 1; + } + } + + DEBUG1(printk + ("%s: jpg_fbuffer_alloc: %ld KB allocated\n", zr->name, + (zr->jpg_nbufs * zr->jpg_bufsize) >> 10)); + zr->jpg_buffers_allocated = 1; + return 0; +} + +/* free the MJPEG grab buffers */ +static void jpg_fbuffer_free(struct zoran *zr) +{ + int i, j, off; // alloc_contig; + unsigned char *mem; + + /* Decide if we should alloc contiguous or fragmented memory */ + /* This has to be identical in jpg_fbuffer_alloc and jpg_fbuffer_free */ + + //alloc_contig = (zr->jpg_bufsize <= MAX_KMALLOC_MEM); + + for (i = 0; i < zr->jpg_nbufs; i++) { + if (!zr->jpg_gbuf[i].frag_tab) + continue; + + //if (alloc_contig) { + if (zr->need_contiguous) { + if (zr->jpg_gbuf[i].frag_tab[0]) { + mem = + (unsigned char *) bus_to_virt(zr-> + jpg_gbuf + [i]. + frag_tab + [0]); + for (off = 0; off < zr->jpg_bufsize; + off += PAGE_SIZE) + mem_map_unreserve(MAP_NR + (mem + off)); + kfree((void *) mem); + zr->jpg_gbuf[i].frag_tab[0] = 0; + zr->jpg_gbuf[i].frag_tab[1] = 0; + } + } else { + for (j = 0; j < zr->jpg_bufsize / PAGE_SIZE; j++) { + if (!zr->jpg_gbuf[i].frag_tab[2 * j]) + break; + mem_map_unreserve(MAP_NR + (bus_to_virt + (zr->jpg_gbuf[i]. + frag_tab[2 * j]))); + free_page((unsigned long) + bus_to_virt(zr->jpg_gbuf[i]. + frag_tab[2 * j])); + zr->jpg_gbuf[i].frag_tab[2 * j] = 0; + zr->jpg_gbuf[i].frag_tab[2 * j + 1] = 0; + } + } + + free_page((unsigned long) zr->jpg_gbuf[i].frag_tab); + zr->jpg_gbuf[i].frag_tab = NULL; + } + zr->jpg_buffers_allocated = 0; +} + + +/* ----------------------------------------------------------------------- */ + +/* I2C functions */ + +#define I2C_DELAY 10 + + +/* software I2C functions */ + +static void i2c_setlines(struct i2c_bus *bus, int ctrl, int data) +{ + struct zoran *zr = (struct zoran *) bus->data; + btwrite((data << 1) | ctrl, ZR36057_I2CBR); + udelay(I2C_DELAY); +} + +static int i2c_getdataline(struct i2c_bus *bus) +{ + struct zoran *zr = (struct zoran *) bus->data; + return (btread(ZR36057_I2CBR) >> 1) & 1; +} + +static void attach_inform(struct i2c_bus *bus, int id) +{ + int i; + struct zoran *zr = (struct zoran *) bus->data; + + DEBUG1(printk(KERN_DEBUG "%s: i2c attach %02x\n", zr->name, id)); + for (i = 0; i < bus->devcount; i++) { + if (strcmp(bus->devices[i]->name, "saa7110") == 0) { + if (zr->revision < 2) { + zr->card = DC10; + sprintf(zr->name, "DC10[%u]", zr->id); + } else { + zr->card = DC10plus; + sprintf(zr->name, "DC10plus[%u]", zr->id); + } + break; + } + if (strcmp(bus->devices[i]->name, "bt819") == 0) { + zr->card = LML33; + sprintf(zr->name, "LML33[%u]", zr->id); + break; + } + if (strcmp(bus->devices[i]->name, "saa7111") == 0) { + zr->card = BUZ; + sprintf(zr->name, "Buz[%u]", zr->id); + break; + } + } +} + +static void detach_inform(struct i2c_bus *bus, int id) +{ + DEBUG1(struct zoran *zr = (struct zoran *) bus->data); + DEBUG1(printk(KERN_DEBUG "%s: i2c detach %02x\n", zr->name, id)); +} + +static struct i2c_bus zoran_i2c_bus_template = { + "zr36057", + I2C_BUSID_BT848, + NULL, + + SPIN_LOCK_UNLOCKED, + + attach_inform, + detach_inform, + + i2c_setlines, + i2c_getdataline, + NULL, + NULL, +}; + +/* + * Set the registers for the size we have specified. Don't bother + * trying to understand this without the ZR36057 manual in front of + * you [AC]. + * + * PS: The manual is free for download in .pdf format from + * www.zoran.com - nicely done those folks. + */ + +static struct tvnorm f50sqpixel = { 944, 768, 83, 880, 625, 576, 16 }; +static struct tvnorm f60sqpixel = { 780, 640, 51, 716, 525, 480, 12 }; + +static struct tvnorm f50ccir601 = { 864, 720, 75, 804, 625, 576, 18 }; +static struct tvnorm f60ccir601 = { 858, 720, 57, 788, 525, 480, 16 }; + +static struct tvnorm *dc10norms[] = { + &f50sqpixel, /* PAL-BDGHI */ + &f60sqpixel, /* NTSC */ + &f50sqpixel, /* SECAM */ +}; + +static struct tvnorm *lml33norms[] = { + &f50ccir601, /* PAL-BDGHI */ + &f60ccir601, /* NTSC */ + NULL, /* SECAM (not supported in LML33) */ +}; + +static struct tvnorm *buznorms[] = { + &f50ccir601, /* PAL-BDGHI */ + &f60ccir601, /* NTSC */ + NULL, /* SECAM */ +}; + +static struct tvnorm *unsupported[] = { + NULL, /* PAL-BDGHI */ + NULL, /* NTSC */ + NULL, /* SECAM */ +}; + +static struct tvnorm **cardnorms[] = { + unsupported, /* UNKNOWN */ + dc10norms, /* DC10 */ + dc10norms, /* DC10plus */ + lml33norms, /* LML33 */ + buznorms, /* Buz */ +}; + +static u32 cardvsync[] = { + 0, /* UNKNOWN */ + ZR36057_ISR_GIRQ1, /* DC10 */ + ZR36057_ISR_GIRQ1, /* DC10plus */ + ZR36057_ISR_GIRQ0, /* LML33 */ + ZR36057_ISR_GIRQ0, /* Buz */ +}; + +static u32 cardjpegint[] = { + 0, /* UNKNOWN */ + ZR36057_ISR_GIRQ0, /* DC10 */ + ZR36057_ISR_GIRQ0, /* DC10plus */ + ZR36057_ISR_GIRQ1, /* LML33 */ + ZR36057_ISR_GIRQ1, /* Buz */ +}; + +static int format2bpp(int format) +{ + int bpp; + + /* Determine the number of bytes per pixel for the video format requested */ + + switch (format) { + + case VIDEO_PALETTE_YUV422: + bpp = 2; + break; + + case VIDEO_PALETTE_RGB555: + bpp = 2; + break; + + case VIDEO_PALETTE_RGB565: + bpp = 2; + break; + + case VIDEO_PALETTE_RGB24: + bpp = 3; + break; + + case VIDEO_PALETTE_RGB32: + bpp = 4; + break; + + default: + bpp = 0; + } + + return bpp; +} + +static void zr36057_adjust_vfe(struct zoran *zr, + enum zoran_codec_mode mode) +{ + u32 reg; + switch (mode) { + case BUZ_MODE_MOTION_DECOMPRESS: + btand(~ZR36057_VFESPFR_ExtFl, ZR36057_VFESPFR); + reg = btread(ZR36057_VFEHCR); + if (reg & (1 << 10)) { + reg += ((1 << 10) | 1); + } + btwrite(reg, ZR36057_VFEHCR); + break; + case BUZ_MODE_MOTION_COMPRESS: + case BUZ_MODE_IDLE: + default: + if (zr->params.norm == VIDEO_MODE_NTSC) + btand(~ZR36057_VFESPFR_ExtFl, ZR36057_VFESPFR); + else + btor(ZR36057_VFESPFR_ExtFl, ZR36057_VFESPFR); + reg = btread(ZR36057_VFEHCR); + if (!(reg & (1 << 10))) { + reg -= ((1 << 10) | 1); + } + btwrite(reg, ZR36057_VFEHCR); + break; + } +} + +/* + * set geometry + */ +static void zr36057_set_vfe(struct zoran *zr, int video_width, + int video_height, unsigned int video_format) +{ + struct tvnorm *tvn; + unsigned HStart, HEnd, VStart, VEnd; + unsigned DispMode; + unsigned VidWinWid, VidWinHt; + unsigned hcrop1, hcrop2, vcrop1, vcrop2; + unsigned Wa, We, Ha, He; + unsigned X, Y, HorDcm, VerDcm; + u32 reg; + unsigned mask_line_size; + + tvn = zr->timing; + + Wa = tvn->Wa; + Ha = tvn->Ha; + + DEBUG1(printk (BUZ_INFO ": width = %d, height = %d\n", video_width, video_height)); + + if (zr->params.norm != VIDEO_MODE_PAL + && zr->params.norm != VIDEO_MODE_NTSC + && zr->params.norm != VIDEO_MODE_SECAM) { + printk(KERN_ERR "%s: set_vfe: video_norm = %d not valid\n", + zr->name, zr->params.norm); + return; + } + if (video_width < BUZ_MIN_WIDTH || video_height < BUZ_MIN_HEIGHT + || video_width > Wa || video_height > Ha) { + printk(KERN_ERR "%s: set_vfe: w=%d h=%d not valid\n", + zr->name, video_width, video_height); + return; + } + + /* if window has more than half of active height, + switch on interlacing - we want the full information */ + + zr->video_interlace = (video_height > Ha / 2); + + /**** zr36057 ****/ + + /* horizontal */ + VidWinWid = video_width; + X = (VidWinWid * 64 + tvn->Wa - 1) / tvn->Wa; + We = (VidWinWid * 64) / X; + HorDcm = 64 - X; + hcrop1 = 2 * ((tvn->Wa - We) / 4); + hcrop2 = tvn->Wa - We - hcrop1; + HStart = tvn->HStart | 1; + if (zr->card == LML33) + HStart += 62; + if (zr->card == BUZ) { //HStart += 67; + HStart += 44; + } + HEnd = HStart + tvn->Wa - 1; + HStart += hcrop1; + HEnd -= hcrop2; + reg = ((HStart & ZR36057_VFEHCR_Hmask) << ZR36057_VFEHCR_HStart) + | ((HEnd & ZR36057_VFEHCR_Hmask) << ZR36057_VFEHCR_HEnd); + if (zr->card != BUZ) + reg |= ZR36057_VFEHCR_HSPol; + btwrite(reg, ZR36057_VFEHCR); + + /* Vertical */ + DispMode = !zr->video_interlace; + VidWinHt = DispMode ? video_height : video_height / 2; + Y = (VidWinHt * 64 * 2 + tvn->Ha - 1) / tvn->Ha; + He = (VidWinHt * 64) / Y; + VerDcm = 64 - Y; + vcrop1 = (tvn->Ha / 2 - He) / 2; + vcrop2 = tvn->Ha / 2 - He - vcrop1; + VStart = tvn->VStart; + VEnd = VStart + tvn->Ha / 2 - 1; + VStart += vcrop1; + VEnd -= vcrop2; + reg = ((VStart & ZR36057_VFEVCR_Vmask) << ZR36057_VFEVCR_VStart) + | ((VEnd & ZR36057_VFEVCR_Vmask) << ZR36057_VFEVCR_VEnd); + reg |= ZR36057_VFEVCR_VSPol; + btwrite(reg, ZR36057_VFEVCR); + + /* scaler and pixel format */ + reg = 0; + reg |= (HorDcm << ZR36057_VFESPFR_HorDcm); + reg |= (VerDcm << ZR36057_VFESPFR_VerDcm); + reg |= (DispMode << ZR36057_VFESPFR_DispMode); + reg |= ZR36057_VFESPFR_LittleEndian; + /* RJ: I don't know, why the following has to be the opposite + of the corresponding ZR36060 setting, but only this way + we get the correct colors when uncompressing to the screen */ + //reg |= ZR36057_VFESPFR_VCLKPol; /**/ + /* RJ: Don't know if that is needed for NTSC also */ + if (zr->params.norm != VIDEO_MODE_NTSC) + reg |= ZR36057_VFESPFR_ExtFl; // NEEDED!!!!!!! Wolfgang + reg |= ZR36057_VFESPFR_TopField; + switch (video_format) { + + case VIDEO_PALETTE_YUV422: + reg |= ZR36057_VFESPFR_YUV422; + break; + + case VIDEO_PALETTE_RGB555: + reg |= ZR36057_VFESPFR_RGB555 | ZR36057_VFESPFR_ErrDif; + break; + + case VIDEO_PALETTE_RGB565: + reg |= ZR36057_VFESPFR_RGB565 | ZR36057_VFESPFR_ErrDif; + break; + + case VIDEO_PALETTE_RGB24: + reg |= ZR36057_VFESPFR_RGB888 | ZR36057_VFESPFR_Pack24; + break; + + case VIDEO_PALETTE_RGB32: + reg |= ZR36057_VFESPFR_RGB888; + break; + + default: + printk(KERN_INFO "%s: Unknown color_fmt=%x\n", zr->name, + video_format); + return; + + } + if (HorDcm >= 48) { + reg |= 3 << ZR36057_VFESPFR_HFilter; /* 5 tap filter */ + } else if (HorDcm >= 32) { + reg |= 2 << ZR36057_VFESPFR_HFilter; /* 4 tap filter */ + } else if (HorDcm >= 16) { + reg |= 1 << ZR36057_VFESPFR_HFilter; /* 3 tap filter */ + } + btwrite(reg, ZR36057_VFESPFR); + + /* display configuration */ + + reg = (16 << ZR36057_VDCR_MinPix) + | (VidWinHt << ZR36057_VDCR_VidWinHt) + | (VidWinWid << ZR36057_VDCR_VidWinWid); + if (triton || zr->revision <= 1) + reg &= ~ZR36057_VDCR_Triton; + else + reg |= ZR36057_VDCR_Triton; + btwrite(reg, ZR36057_VDCR); + + /* Write overlay clipping mask data, but don't enable overlay clipping */ + /* RJ: since this makes only sense on the screen, we use + zr->window.width instead of video_width */ + + mask_line_size = (BUZ_MAX_WIDTH + 31) / 32; + reg = virt_to_bus(zr->overlay_mask); + btwrite(reg, ZR36057_MMTR); + reg = virt_to_bus(zr->overlay_mask + mask_line_size); + btwrite(reg, ZR36057_MMBR); + reg = mask_line_size - (zr->window.width + 31) / 32; + if (DispMode == 0) + reg += mask_line_size; + reg <<= ZR36057_OCR_MaskStride; + btwrite(reg, ZR36057_OCR); + + zr36057_adjust_vfe(zr, zr->codec_mode); + +} + +/* + * Switch overlay on or off + */ + +static void zr36057_overlay(struct zoran *zr, int on) +{ + int fmt, bpp; + u32 reg; + + if (on) { + /* do the necessary settings ... */ + + btand(~ZR36057_VDCR_VidEn, ZR36057_VDCR); /* switch it off first */ + + switch (zr->buffer.depth) { + case 15: + fmt = VIDEO_PALETTE_RGB555; + bpp = 2; + break; + case 16: + fmt = VIDEO_PALETTE_RGB565; + bpp = 2; + break; + case 24: + fmt = VIDEO_PALETTE_RGB24; + bpp = 3; + break; + case 32: + fmt = VIDEO_PALETTE_RGB32; + bpp = 4; + break; + default: + fmt = 0; + bpp = 0; + } + + zr36057_set_vfe(zr, zr->window.width, zr->window.height, + fmt); + + /* Start and length of each line MUST be 4-byte aligned. + This should be allready checked before the call to this routine. + All error messages are internal driver checking only! */ + + /* video display top and bottom registers */ + + reg = + (u32) zr->buffer.base + zr->window.x * bpp + + zr->window.y * zr->buffer.bytesperline; + btwrite(reg, ZR36057_VDTR); + if (reg & 3) + printk(KERN_ERR + "%s: zr36057_overlay: video_address not aligned\n", + zr->name); + if (zr->video_interlace) + reg += zr->buffer.bytesperline; + btwrite(reg, ZR36057_VDBR); + + /* video stride, status, and frame grab register */ + + reg = zr->buffer.bytesperline - zr->window.width * bpp; + if (zr->video_interlace) + reg += zr->buffer.bytesperline; + if (reg & 3) + printk(KERN_ERR + "%s: zr36057_overlay: video_stride not aligned\n", + zr->name); + reg = (reg << ZR36057_VSSFGR_DispStride); + reg |= ZR36057_VSSFGR_VidOvf; /* clear overflow status */ + btwrite(reg, ZR36057_VSSFGR); + + /* Set overlay clipping */ + + if (zr->window.clipcount) + btor(ZR36057_OCR_OvlEnable, ZR36057_OCR); + + /* ... and switch it on */ + + btor(ZR36057_VDCR_VidEn, ZR36057_VDCR); + } else { + /* Switch it off */ + + btand(~ZR36057_VDCR_VidEn, ZR36057_VDCR); + } +} + +/* + * The overlay mask has one bit for each pixel on a scan line, + * and the maximum window size is BUZ_MAX_WIDTH * BUZ_MAX_HEIGHT pixels. + */ +static void write_overlay_mask(struct zoran *zr, struct video_clip *vp, + int count) +{ + unsigned mask_line_size = (BUZ_MAX_WIDTH + 31) / 32; + u32 *mask; + int x, y, width, height; + unsigned i, j, k; + u32 reg; + + /* fill mask with one bits */ + memset(zr->overlay_mask, ~0, mask_line_size * 4 * BUZ_MAX_HEIGHT); + reg = 0; + + for (i = 0; i < count; ++i) { + /* pick up local copy of clip */ + x = vp[i].x; + y = vp[i].y; + width = vp[i].width; + height = vp[i].height; + + /* trim clips that extend beyond the window */ + if (x < 0) { + width += x; + x = 0; + } + if (y < 0) { + height += y; + y = 0; + } + if (x + width > zr->window.width) { + width = zr->window.width - x; + } + if (y + height > zr->window.height) { + height = zr->window.height - y; + } + + /* ignore degenerate clips */ + if (height <= 0) { + continue; + } + if (width <= 0) { + continue; + } + + /* apply clip for each scan line */ + for (j = 0; j < height; ++j) { + /* reset bit for each pixel */ + /* this can be optimized later if need be */ + mask = zr->overlay_mask + (y + j) * mask_line_size; + for (k = 0; k < width; ++k) { + mask[(x + k) / 32] &= + ~((u32) 1 << (x + k) % 32); + } + } + } +} + +/* Enable/Disable uncompressed memory grabbing of the 36057 */ + +static void zr36057_set_memgrab(struct zoran *zr, int mode) +{ + if (mode) { + if (btread(ZR36057_VSSFGR) & + (ZR36057_VSSFGR_SnapShot | ZR36057_VSSFGR_FrameGrab)) + printk(KERN_WARNING + "%s: zr36057_set_memgrab_on with SnapShot or FrameGrab on ???\n", + zr->name); + + /* switch on VSync interrupts */ + + btwrite(IRQ_MASK, ZR36057_ISR); // Clear Interrupts + btor(cardvsync[zr->card], ZR36057_ICR); // SW + + /* enable SnapShot */ + + btor(ZR36057_VSSFGR_SnapShot, ZR36057_VSSFGR); + + /* Set zr36057 video front end and enable video */ + + zr36057_set_vfe(zr, zr->gwidth, zr->gheight, zr->gformat); + + zr->v4l_memgrab_active = 1; + } else { + zr->v4l_memgrab_active = 0; + + /* switch off VSync interrupts */ + + //btand(~ZR36057_ICR_GIRQ1, ZR36057_ICR); // SW + + /* reenable grabbing to screen if it was running */ + + if (zr->v4l_overlay_active) { + zr36057_overlay(zr, 1); + } else { + btand(~ZR36057_VDCR_VidEn, ZR36057_VDCR); + btand(~ZR36057_VSSFGR_SnapShot, ZR36057_VSSFGR); + } + } +} + +static int wait_grab_pending(struct zoran *zr) +{ + unsigned long flags; + + /* wait until all pending grabs are finished */ + + if (!zr->v4l_memgrab_active) + return 0; + + while (zr->v4l_pend_tail != zr->v4l_pend_head) { + interruptible_sleep_on(&zr->v4l_capq); + if (signal_pending(current)) + return -ERESTARTSYS; + } + + spin_lock_irqsave(&zr->lock, flags); + zr36057_set_memgrab(zr, 0); + spin_unlock_irqrestore(&zr->lock, flags); + + return 0; +} + +/* + * V4L Buffer grabbing + */ + +static int v4l_grab(struct zoran *zr, struct video_mmap *mp) +{ + unsigned long flags; + int res, bpp; + + /* + * There is a long list of limitations to what is allowed to be grabbed + * We don't output error messages here, since some programs (e.g. xawtv) + * just try several settings to find out what is valid or not. + */ + + /* No grabbing outside the buffer range! */ + + if (mp->frame >= v4l_nbufs || mp->frame < 0) { + DEBUG2(printk + (KERN_ERR "%s: Can not grab frame %d\n", zr->name, + mp->frame)); + return -EINVAL; + } + + /* Check size and format of the grab wanted */ + + if (mp->height < BUZ_MIN_HEIGHT || mp->width < BUZ_MIN_WIDTH + || mp->height > BUZ_MAX_HEIGHT || mp->width > BUZ_MAX_WIDTH) { + DEBUG2(printk + (KERN_ERR "%s: Wrong frame size.\n", zr->name)); + return -EINVAL; + } + + bpp = format2bpp(mp->format); + if (bpp == 0) { + DEBUG2(printk + (KERN_ERR "%s: Wrong bytes-per-pixel format\n", + zr->name)); + return -EINVAL; + } + + /* Check against available buffer size */ + + if (mp->height * mp->width * bpp > v4l_bufsize) { + DEBUG2(printk + (KERN_ERR "%s: Video buffer size is too small\n", + zr->name)); + return -EINVAL; + } + + /* The video front end needs 4-byte alinged line sizes */ + + if ((bpp == 2 && (mp->width & 1)) || (bpp == 3 && (mp->width & 3))) { + DEBUG2(printk + (KERN_ERR "%s: Wrong frame alingment\n", zr->name)); + return -EINVAL; + } + + /* + * To minimize the time spent in the IRQ routine, we avoid setting up + * the video front end there. + * If this grab has different parameters from a running streaming capture + * we stop the streaming capture and start it over again. + */ + + if (zr->v4l_memgrab_active + && (zr->gwidth != mp->width || zr->gheight != mp->height + || zr->gformat != mp->format)) { + res = wait_grab_pending(zr); + if (res) + return res; + } + zr->gwidth = mp->width; + zr->gheight = mp->height; + zr->gformat = mp->format; + zr->gbpl = bpp * zr->gwidth; + + + spin_lock_irqsave(&zr->lock, flags); + + /* make sure a grab isn't going on currently with this buffer */ + + switch (zr->v4l_gbuf[mp->frame].state) { + + default: + case BUZ_STATE_PEND: + res = -EBUSY; /* what are you doing? */ + break; + + case BUZ_STATE_USER: + case BUZ_STATE_DONE: + /* since there is at least one unused buffer there's room for at least one more pend[] entry */ + zr->v4l_pend[zr->v4l_pend_head++ & V4L_MASK_FRAME] = + mp->frame; + zr->v4l_gbuf[mp->frame].state = BUZ_STATE_PEND; + res = 0; + break; + + } + + /* put the 36057 into frame grabbing mode */ + + if (!res && !zr->v4l_memgrab_active) + zr36057_set_memgrab(zr, 1); + + spin_unlock_irqrestore(&zr->lock, flags); + //DEBUG2(printk(KERN_INFO "%s: Frame grab 3...\n", zr->name)); + + return res; +} + +/* + * Sync on a V4L buffer + */ + +static int v4l_sync(struct zoran *zr, int frame) +{ + unsigned long flags; + + /* check passed-in frame number */ + + if (frame >= v4l_nbufs || frame < 0) { + DEBUG1(printk(KERN_ERR "%s: v4l_sync: frame %d is invalid\n", + zr->name, frame)); + return -EINVAL; + } + + /* Check if is buffer was queued at all */ + + if (zr->v4l_gbuf[frame].state == BUZ_STATE_USER) { + DEBUG1(printk(KERN_ERR + "%s: v4l_sync: Attempt to sync on a buffer which was not queued?\n", + zr->name)); + return -EPROTO; + } + + /* wait on this buffer to get ready */ + + while (zr->v4l_gbuf[frame].state == BUZ_STATE_PEND) { + interruptible_sleep_on(&zr->v4l_capq); + if (signal_pending(current)) + return -ERESTARTSYS; + } + + /* buffer should now be in BUZ_STATE_DONE */ + + if (zr->v4l_gbuf[frame].state != BUZ_STATE_DONE) + printk(KERN_ERR "%s: v4l_sync - internal error\n", + zr->name); + + /* Check if streaming capture has finished */ + + spin_lock_irqsave(&zr->lock, flags); + + if (zr->v4l_pend_tail == zr->v4l_pend_head) + zr36057_set_memgrab(zr, 0); + + spin_unlock_irqrestore(&zr->lock, flags); + + return 0; +} + +/***************************************************************************** + * * + * Set up the Buz-specific MJPEG part * + * * + *****************************************************************************/ + +/* +Wait til post office is no longer busy */ +static int post_office_wait(struct zoran *zr) +{ + u32 por; + +// while (((por = btread(ZR36057_POR)) & (ZR36057_POR_POPen | ZR36057_POR_POTime)) == ZR36057_POR_POPen) { + while ((por = btread(ZR36057_POR)) & ZR36057_POR_POPen) { + /* wait for something to happen */ + } + if ((por & ZR36057_POR_POTime) && zr->card != LML33 + && zr->card != BUZ) { + /* In LML33/BUZ \GWS line is not connected, so it has always timeout set */ + printk(KERN_WARNING "%s: pop timeout %08x\n", zr->name, por); + return -1; + } + return 0; +} + +static int post_office_write(struct zoran *zr, unsigned guest, + unsigned reg, unsigned value) +{ + u32 por; + + por = + ZR36057_POR_PODir | ZR36057_POR_POTime | ((guest & 7) << 20) | + ((reg & 7) << 16) | (value & 0xFF); + btwrite(por, ZR36057_POR); + return post_office_wait(zr); +} + +static int post_office_read(struct zoran *zr, unsigned guest, unsigned reg) +{ + u32 por; + + por = ZR36057_POR_POTime | ((guest & 7) << 20) | ((reg & 7) << 16); + btwrite(por, ZR36057_POR); + if (post_office_wait(zr) < 0) { + return -1; + } + return btread(ZR36057_POR) & 0xFF; +} + +static int zr36060_write_8(struct zoran *zr, unsigned reg, unsigned val) +{ + if (post_office_wait(zr) + || post_office_write(zr, 0, 1, reg >> 8) + || post_office_write(zr, 0, 2, reg)) { + return -1; + } + return post_office_write(zr, 0, 3, val); +} + +static int zr36060_write_16(struct zoran *zr, unsigned reg, unsigned val) +{ + if (zr36060_write_8(zr, reg + 0, val >> 8)) { + return -1; + } + return zr36060_write_8(zr, reg + 1, val >> 0); +} + +static int zr36060_write_24(struct zoran *zr, unsigned reg, unsigned val) +{ + if (zr36060_write_8(zr, reg + 0, val >> 16)) { + return -1; + } + return zr36060_write_16(zr, reg + 1, val >> 0); +} + +static int zr36060_write_32(struct zoran *zr, unsigned reg, unsigned val) +{ + if (zr36060_write_16(zr, reg + 0, val >> 16)) { + return -1; + } + return zr36060_write_16(zr, reg + 2, val >> 0); +} + +static u32 zr36060_read_8(struct zoran *zr, unsigned reg) +{ + if (post_office_wait(zr) + || post_office_write(zr, 0, 1, reg >> 8) + || post_office_write(zr, 0, 2, reg)) { + return -1; + } + return post_office_read(zr, 0, 3) & 0xFF; +} + +/* ----------------------------------------------------------------------- */ + +static void GPIO(struct zoran *zr, unsigned bit, unsigned value) +{ + u32 reg; + u32 mask; + + mask = 1 << (24 + bit); + reg = btread(ZR36057_GPPGCR1) & ~mask; + if (value) { + reg |= mask; + } + btwrite(reg, ZR36057_GPPGCR1); + udelay(1); +} + + +static void zr36060_sleep(struct zoran *zr, int sleep) +{ + switch (zr->card) { + case DC10: + case DC10plus: + GPIO(zr, 3, !sleep); + break; + case BUZ: + case LML33: + GPIO(zr, 1, !sleep); + break; + default: + break; + } + if (!sleep) + udelay(500); + else + udelay(2); +} + +static int zr36060_reset(struct zoran *zr) +{ + switch (zr->card) { + case DC10: + case DC10plus: + zr36060_sleep(zr, 0); + GPIO(zr, 0, 0); + udelay(2); + GPIO(zr, 0, 1); + udelay(2); + break; + case LML33: + case BUZ: + zr36060_sleep(zr, 0); + post_office_write(zr, 3, 0, 0); + udelay(2); + default: + } + return 0; +} + +static void set_frame(struct zoran *zr, int val) +{ + switch (zr->card) { + case DC10: + case DC10plus: + GPIO(zr, 6, val); + break; + case LML33: + case BUZ: + GPIO(zr, 3, val); + break; + default: + break; + } +} + +static void set_videobus_dir(struct zoran *zr, int val) +{ + switch (zr->card) { + case DC10: + case DC10plus: + GPIO(zr, 1, val); + break; + case LML33: + if (lml33dpath == 0) + GPIO(zr, 5, val); + else + GPIO(zr, 5, 1); + break; + case BUZ: + default: + break; + } +} + +static void set_videobus_enable(struct zoran *zr, int val) +{ + switch (zr->card) { + case LML33: + GPIO(zr, 7, val); + break; + case DC10: + case DC10plus: + case BUZ: + default: + break; + } +} + +static void zr36060_set_jpg(struct zoran *zr, enum zoran_codec_mode mode) +{ + struct tvnorm *tvn; + u32 reg; + int size, blocks; + + reg = (1 << 0) /* CodeMstr */ + |(0 << 2) /* CFIS=0 */ + |(0 << 6) /* Endian=0 */ + |(0 << 7); /* Code16=0 */ + zr36060_write_8(zr, 0x002, reg); + + switch (mode) { + + case BUZ_MODE_MOTION_DECOMPRESS: + case BUZ_MODE_STILL_DECOMPRESS: + reg = 0x00; /* Codec mode = decompression */ + break; + + case BUZ_MODE_MOTION_COMPRESS: + case BUZ_MODE_STILL_COMPRESS: + default: + reg = 0xa4; /* Codec mode = compression with variable scale factor */ + break; + + } + zr36060_write_8(zr, 0x003, reg); + + reg = 0x00; /* reserved, mbz */ + zr36060_write_8(zr, 0x004, reg); + + /* code volume */ + + /* Target field size in pixels: */ + tvn = zr->timing; + size = + (tvn->Ha / 2) * (tvn->Wa) / (zr->params.HorDcm) / + (zr->params.VerDcm); + blocks = size / 64; + + /* Target compressed field size in bits: */ + size = size * 16; /* uncompressed size in bits */ + size = size * zr->params.quality / 400; /* quality = 100 is a compression ratio 1:4 */ + + /* Lower limit (arbitrary, 1 KB) */ + if (size < 8192) + size = 8192; + + /* Upper limit: 6/8 of the code buffers */ + if (size * zr->params.field_per_buff > zr->jpg_bufsize * 6) + size = zr->jpg_bufsize * 6 / zr->params.field_per_buff; + + reg = size * 4 / blocks; + if (reg > 0xf0) + reg = 0xf0; /* 480 bits/block, does 0xff represents unlimited? */ + zr36060_write_8(zr, 0x005, reg); + + /* JPEG markers */ + reg = (zr->params.jpeg_markers) & 0x38; /* DRI, DQT, DHT */ + if (zr->params.COM_len) + reg |= JPEG_MARKER_COM; + if (zr->params.APP_len) + reg |= JPEG_MARKER_APP; + zr36060_write_8(zr, 0x006, reg); + + if (zr->card != LML33 && zr->card != BUZ) { + reg = (0 << 3) /* EOAV=0 */ + |(0 << 2) /* EOI=0 */ + |(0 << 1) /* END=0 */ + |(1 << 0); /* DATERR=1 */ + } else { + reg = (0 << 3) /* EOAV=0 */ + |(0 << 2) /* EOI=0 */ + |(0 << 1) /* END=0 */ + |(0 << 0); /* DATERR=0 */ + } + zr36060_write_8(zr, 0x007, reg); + + reg = size; + zr36060_write_32(zr, 0x009, reg); + + reg = (size * 10) / 11; + zr36060_write_32(zr, 0x00d, reg); // Not needed for compr. with variable scale factor, just in case ... + + /* how do we set initial SF as a function of quality parameter? */ + reg = 0x0100; /* SF=1.0 */ + zr36060_write_16(zr, 0x011, reg); + + reg = 0x00ffffff; /* AF=max */ + zr36060_write_24(zr, 0x013, reg); + + reg = 0x0000; /* test */ + zr36060_write_16(zr, 0x024, reg); + + //post_office_read(zr,1,0); +} + +static void zr36060_set_video(struct zoran *zr, enum zoran_codec_mode mode) +{ + struct tvnorm *tvn; + u32 reg; + unsigned HStart; + + tvn = zr->timing; + + reg = (0 << 7) /* Video8 */ + |(0 << 6) /* Range */ + |(0 << 3) /* FlDet */ + |(1 << 2) /* FlVedge */ + |(0 << 1) /* FlExt */ + |(0 << 0); /* SyncMstr */ + + if (mode != BUZ_MODE_STILL_DECOMPRESS) { + /* limit pixels to range 16..235 as per CCIR-601 */ + reg |= (1 << 6); /* Range=1 */ + } + zr36060_write_8(zr, 0x030, reg); + + switch (zr->card) { + case DC10: + case DC10plus: + reg = (0 << 7) /* VCLKPol */ + |(0 << 6) /* PValPol */ + |(0 << 5) /* PoePol */ + |(0 << 4) /* SImgPol */ + |(1 << 3) /* BLPol */ + |(1 << 2) /* FlPol */ + |(1 << 1) /* HSPol */ + |(1 << 0); /* VSPol */ + break; + case LML33: + reg = (0 << 7) /* VCLKPol=0 */ + |(0 << 6) /* PValPol=0 */ + |(1 << 5) /* PoePol=1 */ + |(0 << 4) /* SImgPol=0 */ + |(0 << 3) /* BLPol=0 */ + |(0 << 2) /* FlPol=0 */ + |(0 << 1) /* HSPol=0, sync on falling edge */ + |(1 << 0); /* VSPol=1 */ + break; + case BUZ: + default: + reg = (0 << 7) /* VCLKPol=0 */ + |(0 << 6) /* PValPol=0 */ + |(1 << 5) /* PoePol=1 */ + |(0 << 4) /* SImgPol=0 */ + |(0 << 3) /* BLPol=0 */ + |(0 << 2) /* FlPol=0 */ + |(1 << 1) /* HSPol=0, sync on falling edge */ + |(1 << 0); /* VSPol=1 */ + break; + } + zr36060_write_8(zr, 0x031, reg); + + switch (zr->params.HorDcm) { + default: + case 1: + reg = (0 << 0); + break; /* HScale = 0 */ + + case 2: + reg = (1 << 0); + break; /* HScale = 1 */ + + case 4: + reg = (2 << 0); + break; /* HScale = 2 */ + } + if (zr->params.VerDcm == 2) + reg |= (1 << 2); + zr36060_write_8(zr, 0x032, reg); + + reg = 0x00; /* BackY */ + zr36060_write_8(zr, 0x033, reg); + + reg = 0x80; /* BackU */ + zr36060_write_8(zr, 0x034, reg); + + reg = 0x80; /* BackV */ + zr36060_write_8(zr, 0x035, reg); + + /* sync generator */ + + reg = tvn->Ht - 1; /* Vtotal */ + zr36060_write_16(zr, 0x036, reg); + + reg = tvn->Wt - 1; /* Htotal */ + zr36060_write_16(zr, 0x038, reg); + + reg = 6 - 1; /* VsyncSize */ + zr36060_write_8(zr, 0x03a, reg); + + //reg = 30 - 1; /* HsyncSize */ + reg = (zr->params.norm == 1 ? 57 : 68); + zr36060_write_8(zr, 0x03b, reg); + + reg = tvn->VStart - 1; /* BVstart */ + zr36060_write_8(zr, 0x03c, reg); + + reg += tvn->Ha / 2; /* BVend */ + zr36060_write_16(zr, 0x03e, reg); + + reg = tvn->HStart + 64 - 1; /* BHstart */ + zr36060_write_8(zr, 0x03d, reg); + + reg += tvn->Wa; /* BHend */ + zr36060_write_16(zr, 0x040, reg); + + /* active area */ + reg = zr->params.img_y + tvn->VStart; /* Vstart */ + zr36060_write_16(zr, 0x042, reg); + + reg += zr->params.img_height; /* Vend */ + zr36060_write_16(zr, 0x044, reg); + + HStart = tvn->HStart; + if (zr->card == BUZ) { + HStart += 44; + } else { + HStart += 64; + } + reg = zr->params.img_x + HStart; /* Hstart */ + zr36060_write_16(zr, 0x046, reg); + + reg += zr->params.img_width; /* Hend */ + zr36060_write_16(zr, 0x048, reg); + + /* subimage area */ + reg = tvn->VStart - 4; /* SVstart */ + zr36060_write_16(zr, 0x04a, reg); + + reg += tvn->Ha / 2 + 8; /* SVend */ + zr36060_write_16(zr, 0x04c, reg); + + reg = tvn->HStart + 64 - 4; /* SHstart */ + zr36060_write_16(zr, 0x04e, reg); + + reg += tvn->Wa + 8; /* SHend */ + zr36060_write_16(zr, 0x050, reg); +} + +static void zr36060_set_jpg_SOF(struct zoran *zr) +{ + u32 reg; + + + reg = 0xffc0; /* SOF marker */ + zr36060_write_16(zr, 0x060, reg); + + reg = 17; /* SOF length */ + zr36060_write_16(zr, 0x062, reg); + + reg = 8; /* precision 8 bits */ + zr36060_write_8(zr, 0x064, reg); + + reg = zr->params.img_height / zr->params.VerDcm; /* image height */ + zr36060_write_16(zr, 0x065, reg); + + reg = zr->params.img_width / zr->params.HorDcm; /* image width */ + zr36060_write_16(zr, 0x067, reg); + + reg = 3; /* 3 color components */ + zr36060_write_8(zr, 0x069, reg); + + reg = 0x002100; /* Y component */ + zr36060_write_24(zr, 0x06a, reg); + + reg = 0x011101; /* U component */ + zr36060_write_24(zr, 0x06d, reg); + + reg = 0x021101; /* V component */ + zr36060_write_24(zr, 0x070, reg); +} + +static void zr36060_set_jpg_SOS(struct zoran *zr) +{ + u32 reg; + + + reg = 0xffda; /* SOS marker */ + zr36060_write_16(zr, 0x07a, reg); + + reg = 12; /* SOS length */ + zr36060_write_16(zr, 0x07c, reg); + + reg = 3; /* 3 color components */ + zr36060_write_8(zr, 0x07e, reg); + + reg = 0x0000; /* Y component */ + zr36060_write_16(zr, 0x07f, reg); + + reg = 0x0111; /* U component */ + zr36060_write_16(zr, 0x081, reg); + + reg = 0x0211; /* V component */ + zr36060_write_16(zr, 0x083, reg); + + reg = 0x003f00; /* Start, end spectral scans */ + zr36060_write_24(zr, 0x085, reg); +} + +static void zr36060_set_jpg_DRI(struct zoran *zr) +{ + u32 reg; + + + reg = 0xffdd; /* DRI marker */ + zr36060_write_16(zr, 0x0c0, reg); + + reg = 4; /* DRI length */ + zr36060_write_16(zr, 0x0c2, reg); + + reg = 8; /* length in MCUs */ + zr36060_write_16(zr, 0x0c4, reg); +} + +static void zr36060_set_jpg_DQT(struct zoran *zr) +{ + unsigned i; + unsigned adr; + static const u8 dqt[] = { + 0xff, 0xdb, /* DHT marker */ + 0x00, 0x84, /* DHT length */ + 0x00, /* table ID 0 */ + 0x10, 0x0b, 0x0c, 0x0e, 0x0c, 0x0a, 0x10, 0x0e, + 0x0d, 0x0e, 0x12, 0x11, 0x10, 0x13, 0x18, 0x28, + 0x1a, 0x18, 0x16, 0x16, 0x18, 0x31, 0x23, 0x25, + 0x1d, 0x28, 0x3a, 0x33, 0x3d, 0x3c, 0x39, 0x33, + 0x38, 0x37, 0x40, 0x48, 0x5c, 0x4e, 0x40, 0x44, + 0x57, 0x45, 0x37, 0x38, 0x50, 0x6d, 0x51, 0x57, + 0x5f, 0x62, 0x67, 0x68, 0x67, 0x3e, 0x4d, 0x71, + 0x79, 0x70, 0x64, 0x78, 0x5c, 0x65, 0x67, 0x63, + 0x01, /* table ID 1 */ + 0x11, 0x12, 0x12, 0x18, 0x15, 0x18, 0x2f, 0x1a, + 0x1a, 0x2f, 0x63, 0x42, 0x38, 0x42, 0x63, 0x63, + 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, + 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, + 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, + 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, + 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, + 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63 + }; + + /* write fixed quantitization tables */ + adr = 0x0cc; + for (i = 0; i < sizeof(dqt); ++i) { + zr36060_write_8(zr, adr++, dqt[i]); + } +} + +static void zr36060_set_jpg_DHT(struct zoran *zr) +{ + unsigned i; + unsigned adr; + static const u8 dht[] = { + 0xff, 0xc4, /* DHT marker */ + 0x01, 0xa2, /* DHT length */ + 0x00, /* table class 0, ID 0 */ + 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, /* # codes of length 1..8 */ + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* # codes of length 8..16 */ + 0x00, /* values for codes of length 2 */ + 0x01, 0x02, 0x03, 0x04, 0x05, /* values for codes of length 3 */ + 0x06, /* values for codes of length 4 */ + 0x07, /* values for codes of length 5 */ + 0x08, /* values for codes of length 6 */ + 0x09, /* values for codes of length 7 */ + 0x0a, /* values for codes of length 8 */ + 0x0b, /* values for codes of length 9 */ + 0x01, /* table class 0, ID 1 */ + 0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, /* # codes of length 1..8 */ + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, /* # codes of length 9..16 */ + 0x00, 0x01, 0x02, /* values for codes of length 2 */ + 0x03, /* values for codes of length 3 */ + 0x04, /* values for codes of length 4 */ + 0x05, /* values for codes of length 5 */ + 0x06, /* values for codes of length 6 */ + 0x07, /* values for codes of length 7 */ + 0x08, /* values for codes of length 8 */ + 0x09, /* values for codes of length 9 */ + 0x0a, /* values for codes of length 10 */ + 0x0b, /* values for codes of length 11 */ + 0x10, + 0x00, 0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x03, + 0x05, 0x05, 0x04, 0x04, 0x00, 0x00, 0x01, 0x7d, + 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, + 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, + 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08, + 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0, + 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16, + 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28, + 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, + 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, + 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, + 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, + 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, + 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, + 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, + 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, + 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, + 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, + 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, + 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2, + 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, + 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, + 0xf9, 0xfa, 0x11, 0x00, 0x02, 0x01, 0x02, 0x04, + 0x04, 0x03, 0x04, 0x07, 0x05, 0x04, 0x04, 0x00, + 0x01, 0x02, 0x77, 0x00, 0x01, 0x02, 0x03, 0x11, + 0x04, 0x05, 0x21, 0x31, 0x06, 0x12, 0x41, 0x51, + 0x07, 0x61, 0x71, 0x13, 0x22, 0x32, 0x81, 0x08, + 0x14, 0x42, 0x91, 0xa1, 0xb1, 0xc1, 0x09, 0x23, + 0x33, 0x52, 0xf0, 0x15, 0x62, 0x72, 0xd1, 0x0a, + 0x16, 0x24, 0x34, 0xe1, 0x25, 0xf1, 0x17, 0x18, + 0x19, 0x1a, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x35, + 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, + 0x46, 0x47, 0x48, 0x49, 0x4a, 0x53, 0x54, 0x55, + 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65, + 0x66, 0x67, 0x68, 0x69, 0x6a, 0x73, 0x74, 0x75, + 0x76, 0x77, 0x78, 0x79, 0x7a, 0x82, 0x83, 0x84, + 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93, + 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, + 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, + 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, + 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, + 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, + 0xd8, 0xd9, 0xda, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, + 0xe7, 0xe8, 0xe9, 0xea, 0xf2, 0xf3, 0xf4, 0xf5, + 0xf6, 0xf7, 0xf8, 0xf9, 0xfa + }; + + /* write fixed Huffman tables */ + adr = 0x1d4; + for (i = 0; i < sizeof(dht); ++i) { + zr36060_write_8(zr, adr++, dht[i]); + } +} + +static void zr36060_set_jpg_APP(struct zoran *zr) +{ + unsigned adr; + int len, i; + u32 reg; + + + len = zr->params.APP_len; + if (len < 0) + len = 0; + if (len > 60) + len = 60; + + i = zr->params.APPn; + if (i < 0) + i = 0; + if (i > 15) + i = 15; + + reg = 0xffe0 + i; /* APPn marker */ + zr36060_write_16(zr, 0x380, reg); + + reg = len + 2; /* APPn len */ + zr36060_write_16(zr, 0x382, reg); + + /* write APPn data */ + adr = 0x384; + for (i = 0; i < 60; i++) { + zr36060_write_8(zr, adr++, + (i < len ? zr->params.APP_data[i] : 0)); + } +} + +static void zr36060_set_jpg_COM(struct zoran *zr) +{ + unsigned adr; + int len, i; + u32 reg; + + + len = zr->params.COM_len; + if (len < 0) + len = 0; + if (len > 60) + len = 60; + + reg = 0xfffe; /* COM marker */ + zr36060_write_16(zr, 0x3c0, reg); + + reg = len + 2; /* COM len */ + zr36060_write_16(zr, 0x3c2, reg); + + /* write COM data */ + adr = 0x3c4; + for (i = 0; i < 60; i++) { + zr36060_write_8(zr, adr++, + (i < len ? zr->params.COM_data[i] : 0)); + } +} + +static void zr36060_set_cap(struct zoran *zr, enum zoran_codec_mode mode) +{ + unsigned i; + u32 reg; + + zr36060_reset(zr); + mdelay(10); + + reg = (0 << 7) /* Load=0 */ + |(1 << 0); /* SynRst=1 */ + zr36060_write_8(zr, 0x000, reg); + + zr36060_set_jpg(zr, mode); + zr36060_set_video(zr, mode); + zr36060_set_jpg_SOF(zr); + zr36060_set_jpg_SOS(zr); + zr36060_set_jpg_DRI(zr); + zr36060_set_jpg_DQT(zr); + zr36060_set_jpg_DHT(zr); + zr36060_set_jpg_APP(zr); + zr36060_set_jpg_COM(zr); + + reg = (1 << 7) /* Load=1 */ + |(1 << 0); /* SynRst=0 */ + zr36060_write_8(zr, 0x000, reg); + + /* wait for codec to unbusy */ + for (i = 0; i < 100000; ++i) { + reg = zr36060_read_8(zr, 0x001); + if ((reg & (1 << 7)) == 0) { + return; + } + //udelay(100); + } + printk(KERN_ERR "%sZR36060: stuck busy, statux=%02x\n", zr->name, + reg); +} + +static void init_jpeg_queue(struct zoran *zr) +{ + int i; + /* re-initialize DMA ring stuff */ + zr->jpg_que_head = 0; + zr->jpg_dma_head = 0; + zr->jpg_dma_tail = 0; + zr->jpg_que_tail = 0; + zr->jpg_seq_num = 0; + zr->JPEG_error = 0; + zr->num_errors = 0; + zr->jpg_err_seq = 0; + zr->jpg_err_shift = 0; + zr->jpg_queued_num = 0; + for (i = 0; i < zr->jpg_nbufs; i++) { + zr->jpg_gbuf[i].state = BUZ_STATE_USER; /* nothing going on */ + } + for (i = 0; i < BUZ_NUM_STAT_COM; i++) { + zr->stat_com[i] = 1; /* mark as unavailable to zr36057 */ + } +} + +static void zr36057_set_jpg(struct zoran *zr, enum zoran_codec_mode mode) +{ + struct tvnorm *tvn; + u32 reg; + + tvn = zr->timing; + + /* assert P_Reset */ + btwrite(0, ZR36057_JPC); + + /* MJPEG compression mode */ + switch (mode) { + + case BUZ_MODE_MOTION_COMPRESS: + default: + reg = ZR36057_JMC_MJPGCmpMode; + break; + + case BUZ_MODE_MOTION_DECOMPRESS: + reg = ZR36057_JMC_MJPGExpMode; + reg |= ZR36057_JMC_SyncMstr; + /* RJ: The following is experimental - improves the output to screen */ + //if(zr->params.VFIFO_FB) reg |= ZR36057_JMC_VFIFO_FB; // No, it doesn't. SM + break; + + case BUZ_MODE_STILL_COMPRESS: + reg = ZR36057_JMC_JPGCmpMode; + break; + + case BUZ_MODE_STILL_DECOMPRESS: + reg = ZR36057_JMC_JPGExpMode; + break; + + } + reg |= ZR36057_JMC_JPG; + if (zr->params.field_per_buff == 1) + reg |= ZR36057_JMC_Fld_per_buff; + btwrite(reg, ZR36057_JMC); + + /* vertical */ + btor(ZR36057_VFEVCR_VSPol, ZR36057_VFEVCR); + reg = + (6 << ZR36057_VSP_VsyncSize) | (tvn->Ht << ZR36057_VSP_FrmTot); + btwrite(reg, ZR36057_VSP); + reg = ((zr->params.img_y + tvn->VStart) << ZR36057_FVAP_NAY) + | (zr->params.img_height << ZR36057_FVAP_PAY); + btwrite(reg, ZR36057_FVAP); + + /* horizontal */ + btor(ZR36057_VFEHCR_HSPol, ZR36057_VFEHCR); + reg = + ((tvn->HSyncStart) << ZR36057_HSP_HsyncStart) | (tvn-> + Wt << + ZR36057_HSP_LineTot); + btwrite(reg, ZR36057_HSP); + reg = ((zr->params.img_x + tvn->HStart + 4) << ZR36057_FHAP_NAX) + | (zr->params.img_width << ZR36057_FHAP_PAX); + btwrite(reg, ZR36057_FHAP); + + /* field process parameters */ + if (zr->params.odd_even) + reg = ZR36057_FPP_Odd_Even; + else + reg = 0; + if (mode == BUZ_MODE_MOTION_DECOMPRESS && zr->card != LML33 + && zr->card != BUZ) + reg ^= ZR36057_FPP_Odd_Even; + + btwrite(reg, ZR36057_FPP); + + /* Set proper VCLK Polarity, else colors will be wrong during playback */ + //btor(ZR36057_VFESPFR_VCLKPol, ZR36057_VFESPFR); + + /* code base address */ + reg = virt_to_bus(zr->stat_com); + btwrite(reg, ZR36057_JCBA); + + /* FIFO threshold (FIFO is 160. double words) */ + /* NOTE: decimal values here */ + switch (mode) { + + case BUZ_MODE_STILL_COMPRESS: + case BUZ_MODE_MOTION_COMPRESS: + reg = 140; + break; + + case BUZ_MODE_STILL_DECOMPRESS: + case BUZ_MODE_MOTION_DECOMPRESS: + reg = 20; + break; + + default: + reg = 80; + break; + + } + btwrite(reg, ZR36057_JCFT); + zr36057_adjust_vfe(zr, mode); + +} + +#if (DEBUGLEVEL > 2) +static void dump_guests(struct zoran *zr) +{ + int i, guest[8]; + + for (i = 1; i < 8; i++) { // Don't read zr36060 here + guest[i] = post_office_read(zr, i, 0); + } + + printk(KERN_INFO "%s: Guests:", zr->name); + + for (i = 1; i < 8; i++) { + printk(" 0x%02x", guest[i]); + } + printk("\n"); +} + +static unsigned long get_time(void) +{ + struct timeval tv; + do_gettimeofday(&tv); + return (1000000 * tv.tv_sec + tv.tv_usec); +} + +static void detect_guest_activity(struct zoran *zr) +{ + int timeout, i, j, res, guest[8], guest0[8], change[8][3]; + unsigned long t0, t1; + + dump_guests(zr); + printk(KERN_INFO "%s: Detecting guests activity, please wait...\n", + zr->name); + for (i = 1; i < 8; i++) { // Don't read zr36060 here + guest0[i] = guest[i] = post_office_read(zr, i, 0); + } + + timeout = 0; + j = 0; + t0 = get_time(); + while (timeout < 10000) { + udelay(10); + timeout++; + for (i = 1; (i < 8) && (j < 8); i++) { + res = post_office_read(zr, i, 0); + if (res != guest[i]) { + t1 = get_time(); + change[j][0] = (t1 - t0); + t0 = t1; + change[j][1] = i; + change[j][2] = res; + j++; + guest[i] = res; + } + } + if (j >= 8) + break; + } + printk(KERN_INFO "%s: Guests:", zr->name); + + for (i = 1; i < 8; i++) { + printk(" 0x%02x", guest0[i]); + } + printk("\n"); + if (j == 0) { + printk(KERN_INFO "%s: No activity detected.\n", zr->name); + return; + } + for (i = 0; i < j; i++) { + printk(KERN_INFO "%s: %6d: %d => 0x%02x\n", zr->name, + change[i][0], change[i][1], change[i][2]); + } +} +#endif + +static void print_interrupts(struct zoran *zr) +{ + int res, noerr; + noerr = 0; + printk(KERN_INFO "%s: interrupts received:", zr->name); + if ((res = zr->field_counter) < -1 || res > 1) { + printk(" FD:%d", res); + } + if ((res = zr->intr_counter_GIRQ1) != 0) { + printk(" GIRQ1:%d", res); + noerr++; + } + if ((res = zr->intr_counter_GIRQ0) != 0) { + printk(" GIRQ0:%d", res); + noerr++; + } + if ((res = zr->intr_counter_CodRepIRQ) != 0) { + printk(" CodRepIRQ:%d", res); + noerr++; + } + if ((res = zr->intr_counter_JPEGRepIRQ) != 0) { + printk(" JPEGRepIRQ:%d", res); + noerr++; + } + if (zr->JPEG_max_missed) { + printk(" JPEG delays: max=%d min=%d", zr->JPEG_max_missed, + zr->JPEG_min_missed); + } + if (zr->END_event_missed) { + printk(" ENDs missed: %d", zr->END_event_missed); + } + //if (zr->jpg_queued_num) { + printk(" queue_state=%ld/%ld/%ld/%ld", zr->jpg_que_tail, + zr->jpg_dma_tail, zr->jpg_dma_head, zr->jpg_que_head); + //} + if (!noerr) { + printk(": no interrupts detected."); + } + printk("\n"); +} + +static void clear_interrupt_counters(struct zoran *zr) +{ + zr->intr_counter_GIRQ1 = 0; + zr->intr_counter_GIRQ0 = 0; + zr->intr_counter_CodRepIRQ = 0; + zr->intr_counter_JPEGRepIRQ = 0; + zr->field_counter = 0; + zr->IRQ1_in = 0; + zr->IRQ1_out = 0; + zr->JPEG_in = 0; + zr->JPEG_out = 0; + zr->JPEG_0 = 0; + zr->JPEG_1 = 0; + zr->END_event_missed = 0; + zr->JPEG_missed = 0; + zr->JPEG_max_missed = 0; + zr->JPEG_min_missed = 0x7fffffff; +} + +static u32 count_reset_interrupt(struct zoran *zr) +{ + u32 isr; + if ((isr = btread(ZR36057_ISR) & 0x78000000)) { + if (isr & ZR36057_ISR_GIRQ1) { + btwrite(ZR36057_ISR_GIRQ1, ZR36057_ISR); + zr->intr_counter_GIRQ1++; + } + if (isr & ZR36057_ISR_GIRQ0) { + btwrite(ZR36057_ISR_GIRQ0, ZR36057_ISR); + zr->intr_counter_GIRQ0++; + } + if (isr & ZR36057_ISR_CodRepIRQ) { + btwrite(ZR36057_ISR_CodRepIRQ, ZR36057_ISR); + zr->intr_counter_CodRepIRQ++; + } + if (isr & ZR36057_ISR_JPEGRepIRQ) { + btwrite(ZR36057_ISR_JPEGRepIRQ, ZR36057_ISR); + zr->intr_counter_JPEGRepIRQ++; + } + } + return isr; +} + +static void jpeg_start(struct zoran *zr) +{ + int reg; + zr->frame_num = 0; + + btwrite(ZR36057_JPC_P_Reset, ZR36057_JPC); // /P_Reset + btand(~ZR36057_MCTCR_CFlush, ZR36057_MCTCR); // \CFlush + btor(ZR36057_JPC_CodTrnsEn, ZR36057_JPC); // /CodTrnsEn + btwrite(IRQ_MASK, ZR36057_ISR); // Clear IRQs + btwrite(IRQ_MASK | ZR36057_ICR_IntPinEn, ZR36057_ICR); // Enable IRQs + + set_frame(zr, 0); // \FRAME + + /* JPEG codec guest ID */ + reg = + (1 << ZR36057_JCGI_JPEGuestID) | (0 << + ZR36057_JCGI_JPEGuestReg); + btwrite(reg, ZR36057_JCGI); + + btor(ZR36057_JPC_Active, ZR36057_JPC); // /Active + btor(ZR36057_JMC_Go_en, ZR36057_JMC); // /Go_en + udelay(30); + set_frame(zr, 1); // /FRAME +} + +static void zr36057_enable_jpg(struct zoran *zr, + enum zoran_codec_mode mode) +{ + static int zero = 0; + static int one = 1; + + zr->codec_mode = mode; + switch (mode) { + + case BUZ_MODE_MOTION_COMPRESS: + set_videobus_enable(zr, 0); + set_videobus_dir(zr, 0); // GPIO(zr, 1, 0); + i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, + DECODER_ENABLE_OUTPUT, &one); + i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEOENCODER, + ENCODER_SET_INPUT, &zero); + set_videobus_enable(zr, 1); + zr36060_sleep(zr, 0); + zr36060_set_cap(zr, mode); // Load ZR36060 + init_jpeg_queue(zr); + zr36057_set_jpg(zr, mode); // \P_Reset, ... Video param, FIFO + + clear_interrupt_counters(zr); + DEBUG1(printk + (KERN_INFO "%s: enable_jpg MOTION_COMPRESS\n", + zr->name)); + break; + + case BUZ_MODE_MOTION_DECOMPRESS: + set_videobus_enable(zr, 0); + i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, + DECODER_ENABLE_OUTPUT, &zero); + set_videobus_dir(zr, 1); // GPIO(zr, 1, 1); + i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEOENCODER, + ENCODER_SET_INPUT, &one); + set_videobus_enable(zr, 1); + zr36060_sleep(zr, 0); + zr36060_set_cap(zr, mode); // Load ZR36060 + init_jpeg_queue(zr); + zr36057_set_jpg(zr, mode); // \P_Reset, ... Video param, FIFO + + clear_interrupt_counters(zr); + DEBUG1(printk + (KERN_INFO "%s: enable_jpg MOTION_DECOMPRESS\n", + zr->name)); + break; + + case BUZ_MODE_IDLE: + default: + /* shut down processing */ + btand(~(cardjpegint[zr->card] | ZR36057_ICR_JPEGRepIRQ), + ZR36057_ICR); + btwrite(cardjpegint[zr->card] | ZR36057_ICR_JPEGRepIRQ, + ZR36057_ISR); + btand(~ZR36057_JMC_Go_en, ZR36057_JMC); // \Go_en + + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(HZ/20); + + set_videobus_dir(zr, 0); // GPIO(zr, 1, 0); + set_frame(zr, 1); //GPIO(zr, 6, 1); // /FRAME + btor(ZR36057_MCTCR_CFlush, ZR36057_MCTCR); // /CFlush + btwrite(0, ZR36057_JPC); // \P_Reset,\CodTrnsEn,\Active + btand(~ZR36057_JMC_VFIFO_FB, ZR36057_JMC); + btand(~ZR36057_JMC_SyncMstr, ZR36057_JMC); + zr36060_reset(zr); + zr36060_sleep(zr, 1); + zr36057_adjust_vfe(zr, mode); + set_videobus_enable(zr, 0); + i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, + DECODER_ENABLE_OUTPUT, &one); + i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEOENCODER, + ENCODER_SET_INPUT, &zero); + set_videobus_enable(zr, 1); + DEBUG1(printk + (KERN_INFO "%s: enable_jpg IDLE\n", zr->name)); + break; + + } +} + +/* + * Queue a MJPEG buffer for capture/playback + */ + +static int jpg_qbuf(struct zoran *zr, int frame, + enum zoran_codec_mode mode) +{ + unsigned long flags; + int res; + + /* Check if buffers are allocated */ + + if (!zr->jpg_buffers_allocated) { + printk(KERN_ERR + "%s: jpg_qbuf: buffers not yet allocated\n", + zr->name); + return -ENOMEM; + } + + /* Does the user want to stop streaming? */ + + if (frame < 0) { + if (zr->codec_mode == mode) { + zr36057_enable_jpg(zr, BUZ_MODE_IDLE); + return 0; + } else { + printk(KERN_ERR + "%s: jpg_qbuf - stop streaming but not in streaming mode\n", + zr->name); + return -EINVAL; + } + } + + /* No grabbing outside the buffer range! */ + + if (frame >= zr->jpg_nbufs) { + printk(KERN_ERR "%s: jpg_qbuf: buffer %d out of range\n", + zr->name, frame); + return -EINVAL; + } + + /* what is the codec mode right now? */ + + if (zr->codec_mode == BUZ_MODE_IDLE) { + /* Ok load up the zr36060 */ + zr36057_enable_jpg(zr, mode); + } else if (zr->codec_mode != mode) { + /* wrong codec mode active - invalid */ + printk(KERN_ERR "%s: jpg_qbuf - codec in wrong mode\n", + zr->name); + return -EINVAL; + } + + spin_lock_irqsave(&zr->lock, flags); + + /* make sure a grab isn't going on currently with this buffer */ + + switch (zr->jpg_gbuf[frame].state) { + + case BUZ_STATE_DONE: + DEBUG1(printk + (KERN_WARNING + "%s: Warning: queing frame in BUZ_STATE_DONE state\n", + zr->name)); + case BUZ_STATE_USER: + /* since there is at least one unused buffer there's room for at least one more pend[] entry */ + zr->jpg_pend[zr->jpg_que_head++ & BUZ_MASK_FRAME] = frame; + zr->jpg_gbuf[frame].state = BUZ_STATE_PEND; + zoran_feed_stat_com(zr); + res = 0; + break; + + default: + case BUZ_STATE_DMA: + case BUZ_STATE_PEND: + res = -EBUSY; /* what are you doing? */ + break; + + } + + spin_unlock_irqrestore(&zr->lock, flags); + + /* Start the zr36060 when the first frame is queued */ + if (zr->jpg_que_head == 1) + jpeg_start(zr); + + return res; +} + +/* + * Sync on a MJPEG buffer + */ + +static int jpg_sync(struct zoran *zr, struct zoran_sync *bs) +{ + unsigned long flags; + int frame, timeout; + + if (zr->codec_mode != BUZ_MODE_MOTION_DECOMPRESS + && zr->codec_mode != BUZ_MODE_MOTION_COMPRESS) { + DEBUG1(printk(KERN_ERR + "%s: BUZIOCSYNC: - codec not in streaming mode\n", + zr->name)); + return -EINVAL; + } + while (zr->jpg_que_tail == zr->jpg_dma_tail) { + if (zr->jpg_dma_tail == zr->jpg_dma_head) + break; + timeout = + interruptible_sleep_on_timeout(&zr->jpg_capq, 10 * HZ); + if (!timeout) { + btand(~ZR36057_JMC_Go_en, ZR36057_JMC); + udelay(1); + printk(KERN_ERR + "%s: timeout: codec isr=0x%02x, csr=0x%02x\n", + zr->name, zr36060_read_8(zr, 0x008), + zr36060_read_8(zr, 0x001)); + return -ETIME; + } else if (signal_pending(current)) + return -ERESTARTSYS; + } + + spin_lock_irqsave(&zr->lock, flags); + + if (zr->jpg_dma_tail != zr->jpg_dma_head) + frame = zr->jpg_pend[zr->jpg_que_tail++ & BUZ_MASK_FRAME]; + else + frame = zr->jpg_pend[zr->jpg_que_tail & BUZ_MASK_FRAME]; + /* buffer should now be in BUZ_STATE_DONE */ + +#if(DEBUGLEVEL > 0) + if (zr->jpg_gbuf[frame].state != BUZ_STATE_DONE) + printk(KERN_ERR "%s: jpg_sync - internal error\n", + zr->name); +#endif + + *bs = zr->jpg_gbuf[frame].bs; + zr->jpg_gbuf[frame].state = BUZ_STATE_USER; + + spin_unlock_irqrestore(&zr->lock, flags); + + return 0; +} + +/* when this is called the spinlock must be held */ +static void zoran_feed_stat_com(struct zoran *zr) +{ + /* move frames from pending queue to DMA */ + + int frame, i, max_stat_com; + + max_stat_com = + (zr->params.TmpDcm == + 1) ? BUZ_NUM_STAT_COM : (BUZ_NUM_STAT_COM >> 1); + + while ((zr->jpg_dma_head - zr->jpg_dma_tail) < max_stat_com + && zr->jpg_dma_head < zr->jpg_que_head) { + + frame = zr->jpg_pend[zr->jpg_dma_head & BUZ_MASK_FRAME]; + if (zr->params.TmpDcm == 1) { + /* fill 1 stat_com entry */ + i = (zr->jpg_dma_head - + zr->jpg_err_shift) & BUZ_MASK_STAT_COM; + if (!(zr->stat_com[i] & 1)) + break; + zr->stat_com[i] = zr->jpg_gbuf[frame].frag_tab_bus; + } else { + /* fill 2 stat_com entries */ + i = ((zr->jpg_dma_head - + zr->jpg_err_shift) & 1) * 2; + if (!(zr->stat_com[i] & 1)) + break; + zr->stat_com[i] = zr->jpg_gbuf[frame].frag_tab_bus; + zr->stat_com[i + 1] = + zr->jpg_gbuf[frame].frag_tab_bus; + } + zr->jpg_gbuf[frame].state = BUZ_STATE_DMA; + zr->jpg_dma_head++; + + } + if (zr->codec_mode == BUZ_MODE_MOTION_DECOMPRESS) + zr->jpg_queued_num++; +} + +/* when this is called the spinlock must be held */ +static void zoran_reap_stat_com(struct zoran *zr) +{ + /* move frames from DMA queue to done queue */ + + int i; + u32 stat_com; + unsigned int seq; + unsigned int dif; + int frame; + struct zoran_gbuffer *gbuf; + + /* In motion decompress we don't have a hardware frame counter, + we just count the interrupts here */ + + if (zr->codec_mode == BUZ_MODE_MOTION_DECOMPRESS) { + zr->jpg_seq_num++; + } + while (zr->jpg_dma_tail < zr->jpg_dma_head) { + if (zr->params.TmpDcm == 1) + i = (zr->jpg_dma_tail - + zr->jpg_err_shift) & BUZ_MASK_STAT_COM; + else + i = ((zr->jpg_dma_tail - + zr->jpg_err_shift) & 1) * 2 + 1; + + stat_com = zr->stat_com[i]; + + if ((stat_com & 1) == 0) { + return; + } + frame = zr->jpg_pend[zr->jpg_dma_tail & BUZ_MASK_FRAME]; + gbuf = &zr->jpg_gbuf[frame]; + get_fast_time(&gbuf->bs.timestamp); + + if (zr->codec_mode == BUZ_MODE_MOTION_COMPRESS) { + gbuf->bs.length = (stat_com & 0x7fffff) >> 1; + + /* update sequence number with the help of the counter in stat_com */ + + seq = ((stat_com >> 24) + zr->jpg_err_seq) & 0xff; + dif = (seq - zr->jpg_seq_num) & 0xff; + zr->jpg_seq_num += dif; + } else { + gbuf->bs.length = 0; + } + gbuf->bs.seq = + zr->params.TmpDcm == + 2 ? (zr->jpg_seq_num >> 1) : zr->jpg_seq_num; + gbuf->state = BUZ_STATE_DONE; + + zr->jpg_dma_tail++; + } +} + +static void error_handler(struct zoran *zr, u32 astat, u32 stat) +{ + /* This is JPEG error handling part */ + if ((zr->codec_mode != BUZ_MODE_MOTION_COMPRESS) + && (zr->codec_mode != BUZ_MODE_MOTION_DECOMPRESS)) { + //printk(KERN_ERR "%s: Internal error: error handling request in mode %d\n", zr->name, zr->codec_mode); + return; + } + if ((stat & 1) == 0 + && zr->codec_mode == BUZ_MODE_MOTION_COMPRESS + && zr->jpg_dma_tail - zr->jpg_que_tail >= zr->jpg_nbufs) { + /* No free buffers... */ + zoran_reap_stat_com(zr); + zoran_feed_stat_com(zr); + wake_up_interruptible(&zr->jpg_capq); + zr->JPEG_missed = 0; + return; + } + if (zr->JPEG_error != 1) { + /* + * First entry: error just happened during normal operation + * + * In BUZ_MODE_MOTION_COMPRESS: + * + * Possible glitch in TV signal. In this case we should + * stop the codec and wait for good quality signal before + * restarting it to avoid further problems + * + * In BUZ_MODE_MOTION_DECOMPRESS: + * + * Bad JPEG frame: we have to mark it as processed (codec crashed + * and was not able to do it itself), and to remove it from queue. + */ + btand(~ZR36057_JMC_Go_en, ZR36057_JMC); + udelay(1); + stat = + stat | (post_office_read(zr, 7, 0) & 3) << 8 | + zr36060_read_8(zr, 0x008); + btwrite(0, ZR36057_JPC); + btor(ZR36057_MCTCR_CFlush, ZR36057_MCTCR); + zr36060_reset(zr); + zr36060_sleep(zr, 1); + zr->JPEG_error = 1; + zr->num_errors++; + /* Report error */ +#if(DEBUGLEVEL > 1) + if (zr->num_errors <= 8) { + long frame; + frame = + zr->jpg_pend[zr-> + jpg_dma_tail & BUZ_MASK_FRAME]; + printk(KERN_ERR + "%s: JPEG error stat=0x%08x(0x%08x) queue_state=%ld/%ld/%ld/%ld seq=%ld frame=%ld. Codec stopped. ", + zr->name, stat, zr->last_isr, + zr->jpg_que_tail, zr->jpg_dma_tail, + zr->jpg_dma_head, zr->jpg_que_head, + zr->jpg_seq_num, frame); + printk("stat_com frames:"); + { + int i, j; + for (j = 0; j < BUZ_NUM_STAT_COM; j++) { + for (i = 0; i < zr->jpg_nbufs; i++) { + if (zr->stat_com[j] == + zr->jpg_gbuf[i]. + frag_tab_bus) { + printk("% d->%d", + j, i); + } + } + } + printk("\n"); + } + } +#endif + /* Find an entry in stat_com and rotate contents */ + { + int i; + + if (zr->params.TmpDcm == 1) + i = (zr->jpg_dma_tail - + zr-> + jpg_err_shift) & BUZ_MASK_STAT_COM; + else + i = ((zr->jpg_dma_tail - + zr->jpg_err_shift) & 1) * 2; + if (zr->codec_mode == BUZ_MODE_MOTION_DECOMPRESS) { + /* Mimic zr36067 operation */ + zr->stat_com[i] |= 1; + if (zr->params.TmpDcm != 1) + zr->stat_com[i + 1] |= 1; + /* Refill */ + zoran_reap_stat_com(zr); + zoran_feed_stat_com(zr); + wake_up_interruptible(&zr->jpg_capq); + /* Find an entry in stat_com again after refill */ + if (zr->params.TmpDcm == 1) + i = (zr->jpg_dma_tail - + zr-> + jpg_err_shift) & + BUZ_MASK_STAT_COM; + else + i = ((zr->jpg_dma_tail - + zr->jpg_err_shift) & 1) * 2; + } + if (i) { + /* Rotate stat_comm entries to make current entry first */ + int j; + u32 bus_addr[BUZ_NUM_STAT_COM]; + + memcpy(bus_addr, zr->stat_com, + sizeof(bus_addr)); + for (j = 0; j < BUZ_NUM_STAT_COM; j++) { + zr->stat_com[j] = + bus_addr[(i + + j) & + BUZ_MASK_STAT_COM]; + } + zr->jpg_err_shift += i; + zr->jpg_err_shift &= BUZ_MASK_STAT_COM; + } + if (zr->codec_mode == BUZ_MODE_MOTION_COMPRESS) + zr->jpg_err_seq = zr->jpg_seq_num; /* + 1; */ + } + } + /* Now the stat_comm buffer is ready for restart */ + { + int status; + + status = 0; + if (zr->codec_mode == BUZ_MODE_MOTION_COMPRESS) + i2c_control_device(&zr->i2c, + I2C_DRIVERID_VIDEODECODER, + DECODER_GET_STATUS, &status); + if (zr->codec_mode == BUZ_MODE_MOTION_DECOMPRESS + || (status & DECODER_STATUS_GOOD)) { + /********** RESTART code *************/ + zr36060_reset(zr); + zr36060_set_cap(zr, zr->codec_mode); + zr36057_set_jpg(zr, zr->codec_mode); + jpeg_start(zr); +#if(DEBUGLEVEL > 1) + if (zr->num_errors <= 8) + printk(KERN_INFO "%s: Restart\n", + zr->name); +#endif + zr->JPEG_missed = 0; + zr->JPEG_error = 2; + /********** End RESTART code ***********/ + } + } +} + +static void zoran_irq(int irq, void *dev_id, struct pt_regs *regs) +{ + u32 stat, astat; + int count; + struct zoran *zr; + unsigned long flags; + + zr = (struct zoran *) dev_id; + count = 0; + + if (zr->testing) { + /* Testing interrupts */ + spin_lock_irqsave(&zr->lock, flags); + while ((stat = count_reset_interrupt(zr))) { + if (count++ > 100) { + btand(~ZR36057_ICR_IntPinEn, ZR36057_ICR); + printk(KERN_ERR + "%s: IRQ lockup while testing, isr=0x%08x, cleared int mask\n", + zr->name, stat); + wake_up_interruptible(&zr->test_q); + } + } + zr->last_isr = stat; + spin_unlock_irqrestore(&zr->lock, flags); + return; + } + + spin_lock_irqsave(&zr->lock, flags); + while (1) { + /* get/clear interrupt status bits */ + stat = count_reset_interrupt(zr); + astat = stat & IRQ_MASK; + if (!astat) { + break; + } + if (astat & cardvsync[zr->card]) { // SW + + if (zr->codec_mode == BUZ_MODE_MOTION_DECOMPRESS + || zr->codec_mode == + BUZ_MODE_MOTION_COMPRESS) { + /* count missed interrupts */ + zr->JPEG_missed++; + } + //post_office_read(zr,1,0); + /* Interrupts may still happen when zr->v4l_memgrab_active is switched off. + We simply ignore them */ + + if (zr->v4l_memgrab_active) { + + /* A lot more checks should be here ... */ + if ((btread(ZR36057_VSSFGR) & + ZR36057_VSSFGR_SnapShot) == 0) + printk(KERN_WARNING + "%s: BuzIRQ with SnapShot off ???\n", + zr->name); + + if (zr->v4l_grab_frame != NO_GRAB_ACTIVE) { + /* There is a grab on a frame going on, check if it has finished */ + + if ((btread(ZR36057_VSSFGR) & + ZR36057_VSSFGR_FrameGrab) == + 0) { + /* it is finished, notify the user */ + + zr->v4l_gbuf[zr-> + v4l_grab_frame]. + state = BUZ_STATE_DONE; + zr->v4l_grab_frame = + NO_GRAB_ACTIVE; + zr->v4l_grab_seq++; + zr->v4l_pend_tail++; + } + } + + if (zr->v4l_grab_frame == NO_GRAB_ACTIVE) + wake_up_interruptible(&zr-> + v4l_capq); + + /* Check if there is another grab queued */ + + if (zr->v4l_grab_frame == NO_GRAB_ACTIVE + && zr->v4l_pend_tail != + zr->v4l_pend_head) { + + int frame = + zr->v4l_pend[zr-> + v4l_pend_tail & + V4L_MASK_FRAME]; + u32 reg; + + zr->v4l_grab_frame = frame; + + /* Set zr36057 video front end and enable video */ + + /* Buffer address */ + + reg = + zr->v4l_gbuf[frame]. + fbuffer_bus; + btwrite(reg, ZR36057_VDTR); + if (zr->video_interlace) + reg += zr->gbpl; + btwrite(reg, ZR36057_VDBR); + + /* video stride, status, and frame grab register */ + + reg = 0; + if (zr->video_interlace) + reg += zr->gbpl; + reg = + (reg << + ZR36057_VSSFGR_DispStride); + reg |= ZR36057_VSSFGR_VidOvf; + reg |= ZR36057_VSSFGR_SnapShot; + reg |= ZR36057_VSSFGR_FrameGrab; + btwrite(reg, ZR36057_VSSFGR); + + btor(ZR36057_VDCR_VidEn, + ZR36057_VDCR); + } + } + } +#if (IRQ_MASK & ZR36057_ISR_CodRepIRQ) + if (astat & ZR36057_ISR_CodRepIRQ) { + zr->intr_counter_CodRepIRQ++; + IDEBUG(printk + (KERN_DEBUG "%s: ZR36057_ISR_CodRepIRQ\n", + zr->name)); + btand(~ZR36057_ICR_CodRepIRQ, ZR36057_ICR); + } +#endif /* (IRQ_MASK & ZR36057_ISR_CodRepIRQ) */ + +#if (IRQ_MASK & ZR36057_ISR_JPEGRepIRQ) + if (astat & ZR36057_ISR_JPEGRepIRQ) { + + if (zr->codec_mode == BUZ_MODE_MOTION_DECOMPRESS + || zr->codec_mode == + BUZ_MODE_MOTION_COMPRESS) { +#if(DEBUGLEVEL > 1) + if (!zr->frame_num || zr->JPEG_error) { + printk(KERN_INFO + "%s: first frame ready: state=0x%08x odd_even=%d field_per_buff=%d delay=%d\n", + zr->name, stat, + zr->params.odd_even, + zr->params.field_per_buff, + zr->JPEG_missed); + { + char sc[] = "0000"; + char sv[5]; + int i; + strcpy(sv, sc); + for (i = 0; i < 4; i++) { + if (zr-> + stat_com[i] & + 1) + sv[i] = + '1'; + } + sv[4] = 0; + printk(KERN_INFO + "%s: stat_com=%s queue_state=%ld/%ld/%ld/%ld\n", + zr->name, sv, + zr->jpg_que_tail, + zr->jpg_dma_tail, + zr->jpg_dma_head, + zr->jpg_que_head); + } + } else { + if (zr->JPEG_missed > zr->JPEG_max_missed) // Get statistics + zr->JPEG_max_missed = + zr->JPEG_missed; + if (zr->JPEG_missed < + zr->JPEG_min_missed) + zr->JPEG_min_missed = + zr->JPEG_missed; + } +#endif +#if(DEBUGLEVEL > 2) + if (zr->frame_num < 6) { + int i; + printk("%s: seq=%ld stat_com:", + zr->name, zr->jpg_seq_num); + for (i = 0; i < 4; i++) { + printk(" %08x", + zr->stat_com[i]); + } + printk("\n"); + } +#endif + zr->frame_num++; + zr->JPEG_missed = 0; + zr->JPEG_error = 0; + zoran_reap_stat_com(zr); + zoran_feed_stat_com(zr); + wake_up_interruptible(&zr->jpg_capq); + } //else { + // printk(KERN_ERR "%s: JPEG interrupt while not in motion (de)compress mode!\n", zr->name); + //} + } +#endif /* (IRQ_MASK & ZR36057_ISR_JPEGRepIRQ) */ + + if ((astat & cardjpegint[zr->card]) /* DATERR interrupt received */ + ||zr->JPEG_missed > 25 /* Too many fields missed without processing */ + || zr->JPEG_error == 1 /* We are already in error processing */ + || ((zr->codec_mode == BUZ_MODE_MOTION_DECOMPRESS) + && (zr-> + frame_num & (zr->JPEG_missed > + zr->params.field_per_buff))) + /* fields missed during decompression */ + ) { + error_handler(zr, astat, stat); + } + + count++; + if (count > 10) { + printk(KERN_WARNING "%s: irq loop %d\n", zr->name, + count); + if (count > 20) { + btand(~ZR36057_ICR_IntPinEn, ZR36057_ICR); + printk(KERN_ERR + "%s: IRQ lockup, cleared int mask\n", + zr->name); + break; + } + } + zr->last_isr = stat; + } + spin_unlock_irqrestore(&zr->lock, flags); +} + +/* Check a zoran_params struct for correctness, insert default params */ + +static int zoran_check_params(struct zoran *zr, + struct zoran_params *params) +{ + int err = 0, err0 = 0; + + /* insert constant params */ + + params->major_version = MAJOR_VERSION; + params->minor_version = MINOR_VERSION; + + /* Check input and norm: must be set by calling VIDIOCSCHAN only! */ + + params->norm = zr->params.norm; + params->input = zr->params.input; + + /* Check decimation, set default values for decimation = 1, 2, 4 */ + + switch (params->decimation) { + case 1: + + params->HorDcm = 1; + params->VerDcm = 1; + params->TmpDcm = 1; + params->field_per_buff = 2; + + params->img_x = 0; + params->img_y = 0; + params->img_width = zr->timing->Wa; + params->img_height = zr->timing->Ha / 2; + break; + + case 2: + + params->HorDcm = 2; + params->VerDcm = 1; + params->TmpDcm = 2; + params->field_per_buff = 1; + + params->img_x = 8; + params->img_y = 0; + params->img_width = zr->timing->Wa; + params->img_height = zr->timing->Ha / 2; + break; + + case 4: + + params->HorDcm = 4; + params->VerDcm = 2; + params->TmpDcm = 2; + params->field_per_buff = 1; + + params->img_x = 8; + params->img_y = 0; + params->img_width = zr->timing->Wa; + params->img_height = zr->timing->Ha / 2; + break; + + case 0: + + /* We have to check the data the user has set */ + + if (params->HorDcm != 1 && params->HorDcm != 2 + && params->HorDcm != 4) + err0++; + if (params->VerDcm != 1 && params->VerDcm != 2) + err0++; + if (params->TmpDcm != 1 && params->TmpDcm != 2) + err0++; + if (params->field_per_buff != 1 + && params->field_per_buff != 2) + err0++; + + if (params->img_x < 0) + err0++; + if (params->img_y < 0) + err0++; + if (params->img_width < 0) + err0++; + if (params->img_height < 0) + err0++; + if (params->img_x + params->img_width > zr->timing->Wa) + err0++; + if (params->img_y + params->img_height > + zr->timing->Ha / 2) + err0++; + if (params->HorDcm) { + if (params->img_width % (16 * params->HorDcm) != 0) + err0++; + if (params->img_height % (8 * params->VerDcm) != 0) + err0++; + } + + if (err0) { + DEBUG1(printk(KERN_ERR + "%s: SET PARAMS: error in params for decimation = 0\n", + zr->name)); + err++; + } + break; + + default: + DEBUG1(printk(KERN_ERR + "%s: SET PARAMS: decimation = %d, must be 0, 1, 2 or 4\n", + zr->name, params->decimation)); + err++; + break; + } + + if (params->quality > 100) + params->quality = 100; + if (params->quality < 5) + params->quality = 5; + + if (params->APPn < 0) + params->APPn = 0; + if (params->APPn > 15) + params->APPn = 15; + if (params->APP_len < 0) + params->APP_len = 0; + if (params->APP_len > 60) + params->APP_len = 60; + if (params->COM_len < 0) + params->COM_len = 0; + if (params->COM_len > 60) + params->COM_len = 60; + + if (err) + return -EINVAL; + + return 0; + +} +static void zoran_open_init_params(struct zoran *zr) +{ + int i; + + /* Per default, map the V4L Buffers */ + + zr->map_mjpeg_buffers = 0; + + /* User must explicitly set a window */ + + zr->window_set = 0; + + zr->window.x = 0; + zr->window.y = 0; + zr->window.width = 0; + zr->window.height = 0; + zr->window.chromakey = 0; + zr->window.flags = 0; + zr->window.clips = NULL; + zr->window.clipcount = 0; + + zr->video_interlace = 0; + + zr->v4l_memgrab_active = 0; + zr->v4l_overlay_active = 0; + + zr->v4l_grab_frame = NO_GRAB_ACTIVE; + zr->v4l_grab_seq = 0; + + zr->gwidth = 0; + zr->gheight = 0; + zr->gformat = 0; + zr->gbpl = 0; + + /* DMA ring stuff for V4L */ + + zr->v4l_pend_tail = 0; + zr->v4l_pend_head = 0; + for (i = 0; i < v4l_nbufs; i++) { + zr->v4l_gbuf[i].state = BUZ_STATE_USER; /* nothing going on */ + } + + /* Set necessary params and call zoran_check_params to set the defaults */ + + zr->params.decimation = 1; + + zr->params.quality = 50; /* default compression factor 8 */ + if (zr->card != BUZ) + zr->params.odd_even = 1; + else + zr->params.odd_even = 0; + + zr->params.APPn = 0; + zr->params.APP_len = 0; /* No APPn marker */ + for (i = 0; i < 60; i++) + zr->params.APP_data[i] = 0; + + zr->params.COM_len = 0; /* No COM marker */ + for (i = 0; i < 60; i++) + zr->params.COM_data[i] = 0; + + zr->params.VFIFO_FB = 0; + + memset(zr->params.reserved, 0, sizeof(zr->params.reserved)); + + zr->params.jpeg_markers = JPEG_MARKER_DHT | JPEG_MARKER_DQT; + + i = zoran_check_params(zr, &zr->params); + if (i) + printk(KERN_ERR + "%s: zoran_open_init_params internal error\n", + zr->name); + + clear_interrupt_counters(zr); + zr->testing = 0; +} + +/* + * Open a zoran card. Right now the flags stuff is just playing + */ + +static int zoran_open(struct video_device *dev, int flags) +{ + struct zoran *zr = (struct zoran *) dev; + //int one = 1; + + DEBUG1(printk + (KERN_INFO "%s: zoran_open, %s pid=[%d]\n", zr->name, + current->comm, current->pid)); + + switch (flags) { + + case 0: + if (zr->user > 1) { + DEBUG1(printk(KERN_WARNING + "%s: zoran_open: Buz is allready in use\n", + zr->name)); + return -EBUSY; + } + zr->user++; + + if (zr->user == 1 && v4l_fbuffer_alloc(zr) < 0) { + zr->user--; + printk(KERN_ERR + "%s: zoran_open: v4l_fbuffer_alloc failed\n", + zr->name); + return -ENOMEM; + } + + /* default setup */ + + if (zr->user == 1) { /* First device open */ + zoran_open_init_params(zr); + + zr36057_enable_jpg(zr, BUZ_MODE_IDLE); + + btwrite(IRQ_MASK, ZR36057_ISR); // Clears interrupts + btor(ZR36057_ICR_IntPinEn, ZR36057_ICR); + dev->busy = 0; /* Allow second open */ + } + + break; + + default: + DEBUG1(printk(KERN_WARNING + "%s: zoran_open: flags = 0x%x not yet supported\n", + zr->name, flags)); + return -EBUSY; + break; + + } + MOD_INC_USE_COUNT; + return 0; +} + +static void zoran_close(struct video_device *dev) +{ + struct zoran *zr = (struct zoran *) dev; + int zero = 0, two = 2; + + DEBUG1(printk + (KERN_INFO "%s: zoran_close, %s pid=[%d]\n", zr->name, + current->comm, current->pid)); + /* Clean up JPEG process */ + + wake_up_interruptible(&zr->jpg_capq); + zr36057_enable_jpg(zr, BUZ_MODE_IDLE); + jpg_fbuffer_free(zr); + zr->jpg_nbufs = 0; + + if (zr->user == 1) { /* Last process */ + /* disable interrupts */ + btand(~ZR36057_ICR_IntPinEn, ZR36057_ICR); + +#if(DEBUGLEVEL > 1) + print_interrupts(zr); +#endif + /* Overlay off */ + wake_up_interruptible(&zr->v4l_capq); + zr36057_set_memgrab(zr, 0); + if (zr->v4l_overlay_active) + zr36057_overlay(zr, 0); + v4l_fbuffer_free(zr); + + if (!pass_through) { /* Switch to color bar */ + set_videobus_enable(zr, 0); + i2c_control_device(&zr->i2c, + I2C_DRIVERID_VIDEODECODER, + DECODER_ENABLE_OUTPUT, &zero); + i2c_control_device(&zr->i2c, + I2C_DRIVERID_VIDEOENCODER, + ENCODER_SET_INPUT, &two); + set_videobus_enable(zr, 1); + } + } + + zr->user--; + + MOD_DEC_USE_COUNT; + DEBUG2(printk(KERN_INFO "%s: zoran_close done\n", zr->name)); +} + + +static long zoran_read(struct video_device *dev, char *buf, + unsigned long count, int nonblock) +{ + return -EINVAL; +} + +static long zoran_write(struct video_device *dev, const char *buf, + unsigned long count, int nonblock) +{ + return -EINVAL; +} + +/* + * ioctl routine + */ + +static int do_zoran_ioctl(struct zoran *zr, unsigned int cmd, + void *arg) +{ + switch (cmd) { + + case VIDIOCGCAP: + { + struct video_capability b; + DEBUG2(printk("%s: ioctl VIDIOCGCAP\n", zr->name)); + + strncpy(b.name, zr->video_dev.name, + sizeof(b.name)); + b.type = + VID_TYPE_CAPTURE | VID_TYPE_OVERLAY | + VID_TYPE_CLIPPING | VID_TYPE_FRAMERAM | + VID_TYPE_SCALES; + /* theoretically we could also flag VID_TYPE_SUBCAPTURE + but this is not even implemented in the BTTV driver */ + + if (zr->card == DC10 || zr->card == DC10plus) { + b.channels = 3; /* composite, svhs, internal */ + } else { + b.channels = 2; /* composite, svhs */ + } + b.audios = 0; + b.maxwidth = BUZ_MAX_WIDTH; + b.maxheight = BUZ_MAX_HEIGHT; + b.minwidth = BUZ_MIN_WIDTH; + b.minheight = BUZ_MIN_HEIGHT; + if (copy_to_user(arg, &b, sizeof(b))) { + return -EFAULT; + } + return 0; + } + break; + + case VIDIOCGCHAN: + { + struct video_channel v; + + if (copy_from_user(&v, arg, sizeof(v))) { + return -EFAULT; + } + DEBUG2(printk + ("%s: ioctl VIDIOCGCHAN for channel %d\n", + zr->name, v.channel)); + switch (v.channel) { + case 0: + strcpy(v.name, "Composite"); + break; + case 1: + strcpy(v.name, "SVHS"); + break; + case 2: + if (zr->card == DC10 + || zr->card == DC10plus) { + strcpy(v.name, "Internal/comp"); + break; + } + default: + DEBUG1(printk(KERN_ERR + "%s: VIDIOCGCHAN on not existing channel %d\n", + zr->name, v.channel)); + return -EINVAL; + } + v.tuners = 0; + v.flags = 0; + v.type = VIDEO_TYPE_CAMERA; + v.norm = zr->params.norm; + if (copy_to_user(arg, &v, sizeof(v))) { + return -EFAULT; + } + return 0; + } + break; + + /* RJ: the documentation at http://roadrunner.swansea.linux.org.uk/v4lapi.shtml says: + + * "The VIDIOCSCHAN ioctl takes an integer argument and switches the capture to this input." + * ^^^^^^^ + * The famos BTTV driver has it implemented with a struct video_channel argument + * and we follow it for compatibility reasons + * + * BTW: this is the only way the user can set the norm! + */ + + case VIDIOCSCHAN: + { + struct video_channel v; + int input; + int on, res; + int encoder_norm; + + if (copy_from_user(&v, arg, sizeof(v))) { + return -EFAULT; + } + + if (zr->codec_mode != BUZ_MODE_IDLE) { + if (v.norm != zr->params.norm + || v.channel != zr->params.input) { + DEBUG1(printk(KERN_ERR + "%s: VIDIOCSCHAN called while the card in capture/playback mode\n", + zr->name)); + return -EINVAL; + } else { + DEBUG1(printk(BUZ_WARNING + "%s: Warning: VIDIOCSCHAN called while the card in capture/playback mode\n", + zr->name)); + } + } + + DEBUG2(printk + ("%s: ioctl VIDIOCSCHAN: channel=%d, norm=%d\n", + zr->name, v.channel, v.norm)); + switch (v.channel) { + case 0: + if (zr->card == BUZ) + input = 3; + else + input = 0; + break; + case 1: + input = 7; + break; + case 2: + if (zr->card == DC10 + || zr->card == DC10plus) { + input = 5; + break; + } + default: + DEBUG1(printk(KERN_ERR + "%s: VIDIOCSCHAN on not existing channel %d\n", + zr->name, v.channel)); + return -EINVAL; + break; + } + + if (lock_norm && v.norm != zr->params.norm) { + if (lock_norm > 1) { + DEBUG1(printk(KERN_WARNING + "%s: VIDIOCSCHAN: TV standard is locked, can not switch norm.\n", + zr->name)); + return -EINVAL; + } else { + DEBUG1(printk(KERN_WARNING + "%s: VIDIOCSCHAN: TV standard is locked, norm was not changed.\n", + zr->name)); + v.norm = zr->params.norm; + } + } + + if(v.norm >= 2) + return -EINVAL; + + if (!cardnorms[zr->card][v.norm]) { + DEBUG1(printk(KERN_ERR + "%s: VIDIOCSCHAN with not supported norm %d\n", + zr->name, v.norm)); + return -EOPNOTSUPP; + break; + } + encoder_norm = v.norm; + + zr->params.norm = v.norm; + zr->params.input = v.channel; + zr->timing = cardnorms[zr->card][zr->params.norm]; + + /* We switch overlay off and on since a change in the norm + needs different VFE settings */ + + on = zr->v4l_overlay_active + && !zr->v4l_memgrab_active; + if (on) + zr36057_overlay(zr, 0); + + set_videobus_enable(zr, 0); + i2c_control_device(&zr->i2c, + I2C_DRIVERID_VIDEODECODER, + DECODER_SET_INPUT, &input); + i2c_control_device(&zr->i2c, + I2C_DRIVERID_VIDEODECODER, + DECODER_SET_NORM, + &zr->params.norm); + i2c_control_device(&zr->i2c, + I2C_DRIVERID_VIDEOENCODER, + ENCODER_SET_NORM, + &encoder_norm); + set_videobus_enable(zr, 1); + + if (on) + zr36057_overlay(zr, 1); + + /* Make sure the changes come into effect */ + res = wait_grab_pending(zr); + if (res) + return res; + + return 0; + } + break; + + case VIDIOCGTUNER: + { + DEBUG1(printk(KERN_ERR + "%s: ioctl VIDIOCGTUNER not supported\n", + zr->name)); + return -EINVAL; + } + break; + + case VIDIOCSTUNER: + { + DEBUG1(printk(KERN_ERR + "%s: ioctl VIDIOCSTUNER not supported\n", + zr->name)); + return -EINVAL; + } + break; + + case VIDIOCGPICT: + { + struct video_picture p = zr->picture; + + DEBUG2(printk + ("%s: ioctl VIDIOCGPICT\n", zr->name)); + p.depth = zr->buffer.depth; + switch (zr->buffer.depth) { + case 15: + p.palette = VIDEO_PALETTE_RGB555; + break; + + case 16: + p.palette = VIDEO_PALETTE_RGB565; + break; + + case 24: + p.palette = VIDEO_PALETTE_RGB24; + break; + + case 32: + p.palette = VIDEO_PALETTE_RGB32; + break; + } + + if (copy_to_user(arg, &p, sizeof(p))) { + return -EFAULT; + } + return 0; + } + break; + + case VIDIOCSPICT: + { + struct video_picture p; + + if (copy_from_user(&p, arg, sizeof(p))) { + return -EFAULT; + } + i2c_control_device(&zr->i2c, + I2C_DRIVERID_VIDEODECODER, + DECODER_SET_PICTURE, &p); + DEBUG2(printk + ("%s: ioctl VIDIOCSPICT bri=%d hue=%d col=%d con=%d dep=%d pal=%d\n", + zr->name, p.brightness, p.hue, p.colour, + p.contrast, p.depth, p.palette)); + /* The depth and palette values have no meaning to us, + should we return -EINVAL if they don't fit ? */ + zr->picture = p; + return 0; + } + break; + + case VIDIOCCAPTURE: + { + int v, res; + + if (copy_from_user(&v, arg, sizeof(v))) { + return -EFAULT; + } + DEBUG2(printk + ("%s: ioctl VIDIOCCAPTURE: %d\n", zr->name, + v)); + + /* If there is nothing to do, return immediatly */ + + if ((v && zr->v4l_overlay_active) + || (!v && !zr->v4l_overlay_active)) + return 0; + + if (v == 0) { + zr->v4l_overlay_active = 0; + if (!zr->v4l_memgrab_active) + zr36057_overlay(zr, 0); + /* When a grab is running, the video simply won't be switched on any more */ + } else { + if (!zr->buffer_set || !zr->window_set) { + DEBUG1(printk(KERN_ERR + "%s: VIDIOCCAPTURE: buffer or window not set\n", + zr->name)); + return -EINVAL; + } + zr->v4l_overlay_active = 1; + if (!zr->v4l_memgrab_active) + zr36057_overlay(zr, 1); + /* When a grab is running, the video will be switched on when grab is finished */ + } + /* Make sure the changes come into effect */ + res = wait_grab_pending(zr); + if (res) + return res; + return 0; + } + break; + + case VIDIOCGWIN: + { + DEBUG2(printk("%s: ioctl VIDIOCGWIN\n", zr->name)); + if (copy_to_user + (arg, &zr->window, sizeof(zr->window))) { + return -EFAULT; + } + return 0; + } + break; + + case VIDIOCSWIN: + { + struct video_clip *vcp; + struct video_window vw; + struct tvnorm *tvn; + int on, end, res, Wa, Ha; + + tvn = zr->timing; + + Wa = tvn->Wa; + Ha = tvn->Ha; + + if (copy_from_user(&vw, arg, sizeof(vw))) { + return -EFAULT; + } + + DEBUG2(printk + ("%s: ioctl VIDIOCSWIN: x=%d y=%d w=%d h=%d clipcount=%d\n", + zr->name, vw.x, vw.y, vw.width, vw.height, + vw.clipcount)); + + if (!zr->buffer_set) { + DEBUG1(printk(KERN_ERR + "%s: VIDIOCSWIN: frame buffer has to be set first\n", + zr->name)); + return -EINVAL; + } + + /* + * The video front end needs 4-byte alinged line sizes, we correct that + * silently here if necessary + */ + + if (zr->buffer.depth == 15 + || zr->buffer.depth == 16) { + end = (vw.x + vw.width) & ~1; /* round down */ + vw.x = (vw.x + 1) & ~1; /* round up */ + vw.width = end - vw.x; + } + + if (zr->buffer.depth == 24) { + end = (vw.x + vw.width) & ~3; /* round down */ + vw.x = (vw.x + 3) & ~3; /* round up */ + vw.width = end - vw.x; + } + + if (vw.width > Wa) + vw.width = Wa; + if (vw.height > Ha) + vw.height = Ha; + + /* Check for vaild parameters */ + if (vw.width < BUZ_MIN_WIDTH + || vw.height < BUZ_MIN_HEIGHT + || vw.width > BUZ_MAX_WIDTH + || vw.height > BUZ_MAX_HEIGHT) { + DEBUG1(printk(KERN_ERR + "%s: VIDIOCSWIN: width = %d or height = %d invalid\n", + zr->name, vw.width, vw.height)); + return -EINVAL; + } + + zr->window.x = vw.x; + zr->window.y = vw.y; + zr->window.width = vw.width; + zr->window.height = vw.height; + zr->window.chromakey = 0; + zr->window.flags = 0; // RJ: Is this intended for interlace on/off ? + zr->window.clips = NULL; + zr->window.clipcount = vw.clipcount; + + /* + * If an overlay is running, we have to switch it off + * and switch it on again in order to get the new settings in effect. + * + * We also want to avoid that the overlay mask is written + * when an overlay is running. + */ + + on = zr->v4l_overlay_active + && !zr->v4l_memgrab_active; + if (on) + zr36057_overlay(zr, 0); + + /* + * Write the overlay mask if clips are wanted. + */ + if (vw.clipcount) { + vcp = + vmalloc(sizeof(struct video_clip) * + (vw.clipcount + 4)); + if (vcp == NULL) { + printk(KERN_ERR + "%s: zoran_ioctl: Alloc of clip mask failed\n", + zr->name); + return -ENOMEM; + } + if (copy_from_user + (vcp, vw.clips, + sizeof(struct video_clip) * + vw.clipcount)) { + vfree(vcp); + return -EFAULT; + } + write_overlay_mask(zr, vcp, vw.clipcount); + vfree(vcp); + } + + if (on) + zr36057_overlay(zr, 1); + zr->window_set = 1; + + /* Make sure the changes come into effect */ + res = wait_grab_pending(zr); + if (res) + return res; + + return 0; + } + break; + + case VIDIOCGFBUF: + { + DEBUG2(printk + ("%s: ioctl VIDIOCGFBUF\n", zr->name)); + if (copy_to_user + (arg, &zr->buffer, sizeof(zr->buffer))) { + return -EFAULT; + } + return 0; + } + break; + + case VIDIOCSFBUF: + { + struct video_buffer v; + + /* RJ: Isn't this too restrictive? As long as the user doesn't set + the base address it shouldn't be too dangerous */ + + if (!capable(CAP_SYS_ADMIN)) { + DEBUG1(printk(KERN_ERR + "%s: Only the superuser may issue VIDIOCSFBUF ioctl\n", + zr->name)); + return -EPERM; + } + if (copy_from_user(&v, arg, sizeof(v))) { + return -EFAULT; + } + DEBUG2(printk + ("%s: ioctl VIDIOCSFBUF: base=0x%x w=%d h=%d depth=%d bpl=%d\n", + zr->name, (u32) v.base, v.width, v.height, + v.depth, v.bytesperline)); + if (zr->v4l_overlay_active) { + /* Has the user gotten crazy ... ? */ + DEBUG1(printk(KERN_ERR + "%s: VIDIOCSFBUF not allowed when overlay active\n", + zr->name)); + return -EINVAL; + } + if (v.depth != 15 && v.depth != 16 && v.depth != 24 + && v.depth != 32) { + DEBUG1(printk(KERN_ERR + "%s: VIDIOCSFBUF: depth=%d not supported\n", + zr->name, v.depth)); + return -EINVAL; + } + if (v.height <= 0 || v.width <= 0 + || v.bytesperline <= 0) { + DEBUG1(printk(KERN_ERR + "%s: VIDIOCSFBUF: invalid height/width/bpl value\n", + zr->name)); + return -EINVAL; + } + if (v.bytesperline & 3) { + DEBUG1(printk(KERN_ERR + "%s: VIDIOCSFBUF: bytesperline must be 4-byte aligned\n", + zr->name)); + return -EINVAL; + } + if (v.base) { + zr->buffer.base = + (void *) ((unsigned long) v.base & ~3); + } + zr->buffer.height = v.height; + zr->buffer.width = v.width; + zr->buffer.depth = v.depth; + zr->buffer.bytesperline = v.bytesperline; + + if (zr->buffer.base) + zr->buffer_set = 1; + zr->window_set = 0; /* The user should set new window parameters */ + return 0; + } + break; + + /* RJ: what is VIDIOCKEY intended to do ??? */ + + case VIDIOCKEY: + { + /* Will be handled higher up .. */ + DEBUG2(printk("%s: ioctl VIDIOCKEY\n", zr->name)); + return 0; + } + break; + + case VIDIOCGFREQ: + { + DEBUG1(printk(KERN_ERR + "%s: ioctl VIDIOCGFREQ not supported\n", + zr->name)); + return -EINVAL; + } + break; + + case VIDIOCSFREQ: + { + DEBUG1(printk(KERN_ERR + "%s: ioctl VIDIOCSFREQ not supported\n", + zr->name)); + return -EINVAL; + } + break; + + case VIDIOCGAUDIO: + { + DEBUG1(printk(KERN_ERR + "%s: ioctl VIDIOCGAUDIO not supported\n", + zr->name)); + return -EINVAL; + } + break; + + case VIDIOCSAUDIO: + { + DEBUG1(printk(KERN_ERR + "%s: ioctl VIDIOCSAUDIO not supported\n", + zr->name)); + return -EINVAL; + } + break; + + case VIDIOCSYNC: + { + int v; + + if (copy_from_user(&v, arg, sizeof(v))) { + return -EFAULT; + } + DEBUG3(printk + ("%s: ioctl VIDIOCSYNC %d\n", zr->name, v)); + return v4l_sync(zr, v); + } + break; + + case VIDIOCMCAPTURE: + { + struct video_mmap vm; + + if (copy_from_user + ((void *) &vm, (void *) arg, sizeof(vm))) { + return -EFAULT; + } + DEBUG2(printk + ("%s: ioctl VIDIOCMCAPTURE frame=%d geom=%dx%d fmt=%d\n", + zr->name, vm.frame, vm.width, vm.height, + vm.format)); + return v4l_grab(zr, &vm); + } + break; + + case VIDIOCGMBUF: + { + struct video_mbuf vm; + int i; + + DEBUG2(printk + ("%s: ioctl VIDIOCGMBUF\n", zr->name)); + vm.size = v4l_nbufs * v4l_bufsize; + vm.frames = v4l_nbufs; + for (i = 0; i < v4l_nbufs; i++) { + vm.offsets[i] = i * v4l_bufsize; + } + + /* The next mmap will map the V4L buffers */ + zr->map_mjpeg_buffers = 0; + + if (copy_to_user(arg, &vm, sizeof(vm))) { + return -EFAULT; + } + return 0; + } + break; + + case VIDIOCGUNIT: + { + struct video_unit vu; + + DEBUG2(printk + ("%s: ioctl VIDIOCGUNIT\n", zr->name)); + vu.video = zr->video_dev.minor; + vu.vbi = VIDEO_NO_UNIT; + vu.radio = VIDEO_NO_UNIT; + vu.audio = VIDEO_NO_UNIT; + vu.teletext = VIDEO_NO_UNIT; + if (copy_to_user(arg, &vu, sizeof(vu))) { + return -EFAULT; + } + return 0; + } + break; + + /* + * RJ: In principal we could support subcaptures for V4L grabbing. + * Not even the famous BTTV driver has them, however. + * If there should be a strong demand, one could consider + * to implement them. + */ + case VIDIOCGCAPTURE: + { + DEBUG1(printk(KERN_ERR + "%s: ioctl VIDIOCGCAPTURE not supported\n", + zr->name)); + return -EINVAL; + } + break; + + case VIDIOCSCAPTURE: + { + DEBUG1(printk(KERN_ERR + "%s: ioctl VIDIOCSCAPTURE not supported\n", + zr->name)); + return -EINVAL; + } + break; + + case BUZIOC_G_PARAMS: + { + DEBUG2(printk + ("%s: ioctl BUZIOC_G_PARAMS\n", zr->name)); + + if (copy_to_user + (arg, &(zr->params), sizeof(zr->params))) { + return -EFAULT; + } + return 0; + } + break; + + case BUZIOC_S_PARAMS: + { + struct zoran_params bp; + /* int input, on; */ + + if (zr->codec_mode != BUZ_MODE_IDLE) { + DEBUG1(printk(KERN_ERR + "%s: BUZIOC_S_PARAMS called but Buz in capture/playback mode\n", + zr->name)); + return -EINVAL; + } + + if (copy_from_user(&bp, arg, sizeof(bp))) { + return -EFAULT; + } + DEBUG2(printk + ("%s: ioctl BUZIOC_S_PARAMS\n", zr->name)); + + /* Check the params first before overwriting our internal values */ + + if (zoran_check_params(zr, &bp)) + return -EINVAL; + + zr->params = bp; + + /* Make changes of input and norm go into effect immediatly */ + + /* We switch overlay off and on since a change in the norm + needs different VFE settings */ + + if (copy_to_user(arg, &bp, sizeof(bp))) { + return -EFAULT; + } + return 0; + } + break; + + case BUZIOC_REQBUFS: + { + struct zoran_requestbuffers br; + + if (zr->jpg_buffers_allocated) { + DEBUG1(printk(KERN_ERR + "%s: BUZIOC_REQBUFS: buffers allready allocated\n", + zr->name)); + return -EINVAL; + } + if (copy_from_user(&br, arg, sizeof(br))) { + return -EFAULT; + } + DEBUG2(printk + ("%s: ioctl BUZIOC_REQBUFS count = %lu size=%lu\n", + zr->name, br.count, br.size)); + + /* Enforce reasonable lower and upper limits */ + if (br.count < 4) + br.count = 4; /* Could be choosen smaller */ + if (br.count > BUZ_MAX_FRAME) + br.count = BUZ_MAX_FRAME; + br.size = PAGE_ALIGN(br.size); + if (br.size < 8192) + br.size = 8192; /* Arbitrary */ + /* br.size is limited by 1 page for the stat_com tables to a Maximum of 2 MB */ + if (br.size > (512 * 1024)) + br.size = (512 * 1024); /* 512 K should be enough */ + if (zr->need_contiguous + && br.size > MAX_KMALLOC_MEM) + br.size = MAX_KMALLOC_MEM; + + zr->jpg_nbufs = br.count; + zr->jpg_bufsize = br.size; + + if (jpg_fbuffer_alloc(zr)) + return -ENOMEM; + + /* The next mmap will map the MJPEG buffers */ + zr->map_mjpeg_buffers = 1; + + if (copy_to_user(arg, &br, sizeof(br))) { + return -EFAULT; + } + return 0; + } + break; + + case BUZIOC_QBUF_CAPT: + { + int nb; + + if (copy_from_user + ((void *) &nb, (void *) arg, sizeof(int))) { + return -EFAULT; + } + DEBUG4(printk + ("%s: ioctl BUZIOC_QBUF_CAPT %d\n", + zr->name, nb)); + return jpg_qbuf(zr, nb, BUZ_MODE_MOTION_COMPRESS); + } + break; + + case BUZIOC_QBUF_PLAY: + { + int nb; + + if (copy_from_user + ((void *) &nb, (void *) arg, sizeof(int))) { + return -EFAULT; + } + DEBUG4(printk + ("%s: ioctl BUZIOC_QBUF_PLAY %d\n", + zr->name, nb)); + return jpg_qbuf(zr, nb, + BUZ_MODE_MOTION_DECOMPRESS); + } + break; + + case BUZIOC_SYNC: + { + struct zoran_sync bs; + int res; + + DEBUG4(printk + ("%s: ioctl BUZIOC_SYNC\n", zr->name)); + res = jpg_sync(zr, &bs); + if (copy_to_user(arg, &bs, sizeof(bs))) { + return -EFAULT; + } + return res; + } + break; + + case BUZIOC_G_STATUS: + { + struct zoran_status bs; + int norm, input, status; + unsigned long timeout; + + if (zr->codec_mode != BUZ_MODE_IDLE) { + DEBUG1(printk(KERN_ERR + "%s: BUZIOC_G_STATUS called but Buz in capture/playback mode\n", + zr->name)); + return -EINVAL; + } + + if (copy_from_user(&bs, arg, sizeof(bs))) { + return -EFAULT; + } + DEBUG2(printk + ("%s: ioctl BUZIOC_G_STATUS\n", zr->name)); + + switch (bs.input) { + case 0: + if (zr->card == BUZ) + input = 3; + else + input = 0; + break; + case 1: + input = 7; + break; + default: + DEBUG1(printk(KERN_ERR + "%s: BUZIOC_G_STATUS on not existing input %d\n", + zr->name, bs.input)); + return -EINVAL; + } + + /* Set video norm to VIDEO_MODE_AUTO */ + + norm = VIDEO_MODE_AUTO; + set_videobus_enable(zr, 0); + i2c_control_device(&zr->i2c, + I2C_DRIVERID_VIDEODECODER, + DECODER_SET_INPUT, &input); + i2c_control_device(&zr->i2c, + I2C_DRIVERID_VIDEODECODER, + DECODER_SET_NORM, &norm); + set_videobus_enable(zr, 1); + + /* sleep 1 second */ + + timeout = jiffies + 1 * HZ; + while (jiffies < timeout) + schedule(); + + /* Get status of video decoder */ + + i2c_control_device(&zr->i2c, + I2C_DRIVERID_VIDEODECODER, + DECODER_GET_STATUS, &status); + bs.signal = (status & DECODER_STATUS_GOOD) ? 1 : 0; + + if (status & DECODER_STATUS_NTSC) + bs.norm = VIDEO_MODE_NTSC; + else if (status & DECODER_STATUS_SECAM) + bs.norm = VIDEO_MODE_SECAM; + else + bs.norm = VIDEO_MODE_PAL; + + bs.color = (status & DECODER_STATUS_COLOR) ? 1 : 0; + + /* restore previous input and norm */ + if (zr->card == BUZ) + input = zr->params.input == 0 ? 3 : 7; + else + input = zr->params.input == 0 ? 0 : 7; + set_videobus_enable(zr, 0); + i2c_control_device(&zr->i2c, + I2C_DRIVERID_VIDEODECODER, + DECODER_SET_INPUT, &input); + i2c_control_device(&zr->i2c, + I2C_DRIVERID_VIDEODECODER, + DECODER_SET_NORM, + &zr->params.norm); + set_videobus_enable(zr, 1); + + if (copy_to_user(arg, &bs, sizeof(bs))) { + return -EFAULT; + } + return 0; + } + break; + + default: + DEBUG1(printk + ("%s: UNKNOWN ioctl cmd: 0x%x\n", zr->name, cmd)); + return -ENOIOCTLCMD; + } + return 0; +} + +static int zoran_ioctl(struct video_device *dev, unsigned int cmd, void *arg) +{ + struct zoran *zr = (struct zoran *) dev; + int err; + + down(&zr->sem); + err = do_zoran_ioctl(zr, cmd, arg); + up(&zr->sem); + + return err; +} + +/* + * This maps the buffers to user space. + * + * Depending on the state of zr->map_mjpeg_buffers + * the V4L or the MJPEG buffers are mapped + * + */ + +static int do_zoran_mmap(struct zoran *zr, const char *adr, + unsigned long size) +{ + unsigned long start = (unsigned long) adr; + unsigned long page, pos, todo, fraglen; + int i, j; + + DEBUG2(printk + (KERN_INFO "%s: mmap at 0x%08lx, size %lu\n", zr->name, + start, size)); + if (zr->map_mjpeg_buffers) { + /* Map the MJPEG buffers */ + + if (!zr->jpg_buffers_allocated) { + DEBUG1(printk(KERN_ERR + "%s: zoran_mmap(MJPEG): buffers not yet allocated\n", + zr->name)); + return -ENOMEM; + } + + if (size > zr->jpg_nbufs * zr->jpg_bufsize) { + DEBUG1(printk(KERN_ERR + "%s: zoran_mmap(MJPEG): Max size is %lu - you wanted %lu\n", + zr->name, zr->jpg_nbufs * zr->jpg_bufsize, + size)); + return -EINVAL; + } + + if (size != zr->jpg_nbufs * zr->jpg_bufsize) + DEBUG1(printk(KERN_WARNING + "%s: zoran_mmap(MJPEG): Expected %lu - you wanted %lu\n", + zr->name, zr->jpg_nbufs * zr->jpg_bufsize, + size)); + + for (i = 0; i < zr->jpg_nbufs; i++) { + for (j = 0; j < zr->jpg_bufsize / PAGE_SIZE; j++) { + fraglen = + (zr->jpg_gbuf[i]. + frag_tab[2 * j + 1] & ~1) << 1; + todo = size; + if (todo > fraglen) + todo = fraglen; + pos = + (unsigned long) zr->jpg_gbuf[i]. + frag_tab[2 * j]; + page = virt_to_phys(bus_to_virt(pos)); /* should just be pos on i386 */ + if (remap_page_range + (start, page, todo, PAGE_SHARED)) { + printk(KERN_ERR + "%s: zoran_mmap(V4L): remap_page_range failed\n", + zr->name); + return -EAGAIN; + } + size -= todo; + start += todo; + if (size == 0) + break; + if (zr->jpg_gbuf[i]. + frag_tab[2 * j + 1] & 1) + break; /* was last fragment */ + } + if (size == 0) + break; + } + } else { + /* Map the V4L buffers */ + + if (size > v4l_nbufs * v4l_bufsize) { + DEBUG1(printk(KERN_ERR + "%s: zoran_mmap(V4L): Max size is %d - you wanted %ld\n", + zr->name, v4l_nbufs * v4l_bufsize, size)); + return -EINVAL; + } + + if (size != v4l_nbufs * v4l_bufsize) + DEBUG1(printk(KERN_WARNING + "%s: zoran_mmap(V4L): Expected %d - you wanted %ld\n", + zr->name, v4l_nbufs * v4l_bufsize, size)); + + for (i = 0; i < v4l_nbufs; i++) { + todo = size; + if (todo > v4l_bufsize) + todo = v4l_bufsize; + page = zr->v4l_gbuf[i].fbuffer_phys; + DEBUG2(printk + ("V4L remap page range %d 0x%lx %ld to 0x%lx\n", + i, page, todo, start)); + if (remap_page_range + (start, page, todo, PAGE_SHARED)) { + printk(KERN_ERR + "%s: zoran_mmap(V4L): remap_page_range failed\n", + zr->name); + return -EAGAIN; + } + size -= todo; + start += todo; + if (size == 0) + break; + } + } + return 0; +} + +static int zoran_mmap(struct video_device *dev, const char *adr, + unsigned long size) +{ + int err; + struct zoran *zr = (struct zoran *) dev; + + down(&zr->sem); + err = do_zoran_mmap(zr, adr, size); + up(&zr->sem); + + return err; +} + +static int zoran_init_done(struct video_device *dev) +{ + return 0; +} + +static struct video_device zoran_template = { + THIS_MODULE, + ZORAN_NAME, + VID_TYPE_CAPTURE | VID_TYPE_OVERLAY | VID_TYPE_CLIPPING | + VID_TYPE_FRAMERAM | VID_TYPE_SCALES | VID_TYPE_SUBCAPTURE, + ZORAN_HARDWARE, + zoran_open, + zoran_close, + zoran_read, + zoran_write, + NULL, + zoran_ioctl, + zoran_mmap, + zoran_init_done, + NULL, + 0, + 0 +}; + +/* + * initialize video front end + */ +static void zr36057_init_vfe(struct zoran *zr) +{ + u32 reg; + reg = btread(ZR36057_VFESPFR); + reg |= ZR36057_VFESPFR_LittleEndian; + reg &= ~ZR36057_VFESPFR_VCLKPol; + reg |= ZR36057_VFESPFR_ExtFl; + reg |= ZR36057_VFESPFR_TopField; + btwrite(reg, ZR36057_VFESPFR); + reg = btread(ZR36057_VDCR); + if (triton || zr->revision <= 1) + reg &= ~ZR36057_VDCR_Triton; + else + reg |= ZR36057_VDCR_Triton; + btwrite(reg, ZR36057_VDCR); +} + +static void test_interrupts(struct zoran *zr) +{ + int timeout, icr; + + clear_interrupt_counters(zr); + zr->testing = 1; + icr = btread(ZR36057_ICR); + btwrite(0x78000000 | ZR36057_ICR_IntPinEn, ZR36057_ICR); + timeout = interruptible_sleep_on_timeout(&zr->test_q, 1 * HZ); + btwrite(0, ZR36057_ICR); + btwrite(0x78000000, ZR36057_ISR); + zr->testing = 0; + printk(KERN_INFO "%s: Testing interrupts...\n", zr->name); + if (timeout) { + printk(": time spent: %d\n", 1 * HZ - timeout); + } + print_interrupts(zr); + btwrite(icr, ZR36057_ICR); +} + +static int zr36057_init(int i) +{ + struct zoran *zr = &zoran[i]; + unsigned long mem; + unsigned mem_needed; + int j; + int two = 2; + int zero = 0; + + printk(KERN_INFO "%s: Initializing card[%d], zr=%x\n", zr->name, i, (int) zr); + + /* default setup of all parameters which will persist beetween opens */ + + zr->user = 0; + + init_waitqueue_head(&zr->v4l_capq); + init_waitqueue_head(&zr->jpg_capq); + init_waitqueue_head(&zr->test_q); + + zr->map_mjpeg_buffers = 0; /* Map V4L buffers by default */ + + zr->jpg_nbufs = 0; + zr->jpg_bufsize = 0; + zr->jpg_buffers_allocated = 0; + + zr->buffer_set = 0; /* Flag if frame buffer has been set */ + zr->buffer.base = (void *) vidmem; + zr->buffer.width = 0; + zr->buffer.height = 0; + zr->buffer.depth = 0; + zr->buffer.bytesperline = 0; + + zr->params.norm = default_norm = (default_norm < 3 ? default_norm : VIDEO_MODE_PAL); /* Avoid nonsense settings from user */ + if (!(zr->timing = cardnorms[zr->card][zr->params.norm])) { + printk(KERN_WARNING + "%s: default TV statdard not supported by hardware. PAL will be used.\n", + zr->name); + zr->params.norm = VIDEO_MODE_PAL; + zr->timing = cardnorms[zr->card][zr->params.norm]; + } + zr->params.input = default_input = (default_input ? 1 : 0); /* Avoid nonsense settings from user */ + zr->video_interlace = 0; + + /* Should the following be reset at every open ? */ + + zr->picture.colour = 32768; + zr->picture.brightness = 32768; + zr->picture.hue = 32768; + zr->picture.contrast = 32768; + zr->picture.whiteness = 0; + zr->picture.depth = 0; + zr->picture.palette = 0; + + for (j = 0; j < VIDEO_MAX_FRAME; j++) { + zr->v4l_gbuf[i].fbuffer = 0; + zr->v4l_gbuf[i].fbuffer_phys = 0; + zr->v4l_gbuf[i].fbuffer_bus = 0; + } + + zr->stat_com = 0; + + /* default setup (will be repeated at every open) */ + + zoran_open_init_params(zr); + + /* allocate memory *before* doing anything to the hardware in case allocation fails */ + + /* STAT_COM table and overlay mask */ + + mem_needed = (BUZ_NUM_STAT_COM + ((BUZ_MAX_WIDTH + 31) / 32) * BUZ_MAX_HEIGHT) * 4; + mem = (unsigned long) kmalloc(mem_needed, GFP_KERNEL); + if (!mem) { + printk(KERN_ERR "%s: zr36057_init: kmalloc (STAT_COM + ovl.mask) failed\n", zr->name); + return -ENOMEM; + } + memset((void *) mem, 0, mem_needed); + + zr->stat_com = (u32 *) mem; + for (j = 0; j < BUZ_NUM_STAT_COM; j++) { + zr->stat_com[j] = 1; /* mark as unavailable to zr36057 */ + } + zr->overlay_mask = (u32 *) (mem + BUZ_NUM_STAT_COM * 4); + + /* Initialize zr->jpg_gbuf */ + + for (j = 0; j < BUZ_MAX_FRAME; j++) { + zr->jpg_gbuf[j].frag_tab = 0; + zr->jpg_gbuf[j].frag_tab_bus = 0; + zr->jpg_gbuf[j].state = BUZ_STATE_USER; + zr->jpg_gbuf[j].bs.frame = j; + } + + /* + * Now add the template and register the device unit. + */ + memcpy(&zr->video_dev, &zoran_template, sizeof(zoran_template)); + strcpy(zr->video_dev.name, zr->name); + if (video_register_device(&zr->video_dev, VFL_TYPE_GRABBER, video_nr) < 0) { + i2c_unregister_bus(&zr->i2c); + kfree((void *) zr->stat_com); + return -1; + } + + /* Enable bus-mastering */ + pci_set_master(zr->pci_dev); + + if (zr->card == BUZ) + j = zr->params.input == 0 ? 3 : 7; + else + j = zr->params.input == 0 ? 0 : 7; + set_videobus_enable(zr, 0); + i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, + DECODER_SET_INPUT, &j); + i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, + DECODER_SET_NORM, &zr->params.norm); + i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEOENCODER, + ENCODER_SET_NORM, &zr->params.norm); + set_videobus_enable(zr, 1); + + /* toggle JPEG codec sleep to sync PLL */ + zr36060_sleep(zr, 1); + zr36060_sleep(zr, 0); + + /* set individual interrupt enables (without GIRQ1) + but don't global enable until zoran_open() */ + + //btwrite(IRQ_MASK & ~ZR36057_ISR_GIRQ1, ZR36057_ICR); // SW + // It looks like using only JPEGRepIRQEn is not always reliable, + // may be when JPEG codec crashes it won't generate IRQ? So, + btwrite(IRQ_MASK, ZR36057_ICR); // Enable Vsync interrupts too. SM + + zr36057_init_vfe(zr); + + zr->zoran_proc = NULL; + zr->initialized = 1; + + zr36057_enable_jpg(zr, BUZ_MODE_IDLE); +#if (DEBUGLEVEL > 2) + detect_guest_activity(zr); +#endif + test_interrupts(zr); + btwrite(IRQ_MASK, ZR36057_ICR); // Enable Vsync interrupts too. SM + if (!pass_through) { + set_videobus_enable(zr, 0); + i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, + DECODER_ENABLE_OUTPUT, &zero); + i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEOENCODER, + ENCODER_SET_INPUT, &two); + set_videobus_enable(zr, 1); + } + return 0; +} + +#include "zoran_procfs.c" + +static void release_dc10(void) +{ + u8 command; + int i; + struct zoran *zr; + + for (i = 0; i < zoran_num; i++) { + zr = &zoran[i]; + + if (!zr->initialized) + continue; + + /* unregister i2c_bus */ + i2c_unregister_bus((&zr->i2c)); + + /* disable PCI bus-mastering */ + pci_read_config_byte(zr->pci_dev, PCI_COMMAND, &command); + command &= ~PCI_COMMAND_MASTER; + pci_write_config_byte(zr->pci_dev, PCI_COMMAND, command); + + /* put chip into reset */ + btwrite(0, ZR36057_SPGPPCR); + + free_irq(zr->pci_dev->irq, zr); + + /* unmap and free memory */ + + kfree((void *) zr->stat_com); + + zoran_proc_cleanup(i); + iounmap(zr->zr36057_mem); + + video_unregister_device(&zr->video_dev); + } +} + +/* + * Scan for a Buz card (actually for the PCI contoler ZR36057), + * request the irq and map the io memory + */ + +static int find_zr36057(void) +{ + unsigned char latency, need_latency; + struct zoran *zr; + struct pci_dev *dev = NULL; + int result; + + zoran_num = 0; + + while (zoran_num < BUZ_MAX + && (dev = + pci_find_device(PCI_VENDOR_ID_ZORAN, + PCI_DEVICE_ID_ZORAN_36057, + dev)) != NULL) { + zr = &zoran[zoran_num]; + zr->pci_dev = dev; + zr->zr36057_mem = NULL; + zr->id = zoran_num; + sprintf(zr->name, "MJPEG[%u]", zr->id); + + spin_lock_init(&zr->lock); + init_MUTEX(&zr->sem); + + if (pci_enable_device(dev)) + continue; + + zr->zr36057_adr = pci_resource_start(zr->pci_dev, 0); + pci_read_config_byte(zr->pci_dev, PCI_CLASS_REVISION, + &zr->revision); + if (zr->revision < 2) { + printk(KERN_INFO + "%s: Zoran ZR36057 (rev %d) irq: %d, memory: 0x%08x.\n", + zr->name, zr->revision, zr->pci_dev->irq, + zr->zr36057_adr); + } else { + unsigned short ss_vendor_id, ss_id; + ss_vendor_id = zr->pci_dev->subsystem_vendor; + ss_id = zr->pci_dev->subsystem_device; + printk(KERN_INFO + "%s: Zoran ZR36067 (rev %d) irq: %d, memory: 0x%08x\n", + zr->name, zr->revision, zr->pci_dev->irq, + zr->zr36057_adr); + printk(KERN_INFO + "%s: subsystem vendor=0x%04x id=0x%04x\n", + zr->name, ss_vendor_id, ss_id); + } + + zr->zr36057_mem = ioremap_nocache(zr->zr36057_adr, 0x1000); + if (!zr->zr36057_mem) { + printk(KERN_ERR "%s: ioremap failed\n", zr->name); + /* XXX handle error */ + } + + result = request_irq(zr->pci_dev->irq, zoran_irq, SA_SHIRQ | SA_INTERRUPT, zr->name, (void *) zr); + if (result < 0) { + if (result == -EINVAL) { + printk(KERN_ERR + "%s: Bad irq number or handler\n", + zr->name); + } else if (result == -EBUSY) { + printk(KERN_ERR + "%s: IRQ %d busy, change your PnP config in BIOS\n", + zr->name, zr->pci_dev->irq); + } else { + printk(KERN_ERR + "%s: Can't assign irq, error code %d\n", + zr->name, result); + } + iounmap(zr->zr36057_mem); + continue; + } + + /* set PCI latency timer */ + pci_read_config_byte(zr->pci_dev, PCI_LATENCY_TIMER, &latency); + need_latency = zr->revision > 1 ? 32 : 48; + if (latency != need_latency) { + printk(KERN_INFO "%s: Changing PCI latency from %d to %d.\n", zr->name, latency, need_latency); + pci_write_config_byte(zr->pci_dev, PCI_LATENCY_TIMER, need_latency); + } + + btwrite(0, ZR36057_SPGPPCR); + mdelay(1); + btwrite(ZR36057_SPGPPCR_SoftReset, ZR36057_SPGPPCR); + mdelay(1); + + /* assert P_Reset */ + btwrite(0, ZR36057_JPC); + + /* set up GPIO direction - all output */ + btwrite(ZR36057_SPGPPCR_SoftReset | 0, ZR36057_SPGPPCR); + btwrite((0x81 << 24) | 0x8888, ZR36057_GPPGCR1); + + /* i2c */ + memcpy(&zr->i2c, &zoran_i2c_bus_template, + sizeof(struct i2c_bus)); + strcpy(zr->i2c.name, zr->name); + zr->i2c.data = zr; + printk(KERN_INFO "%s: Initializing i2c bus...\n", zr->name); + if (i2c_register_bus(&zr->i2c) < 0) { + /* put chip into reset */ + btwrite(0, ZR36057_SPGPPCR); + free_irq(zr->pci_dev->irq, zr); + iounmap(zr->zr36057_mem); + printk(KERN_ERR "%s: Can't initialize i2c bus\n", zr->name); + continue; + } + + if (zr->card != DC10 && zr->card != DC10plus + && zr->card != LML33 && zr->card != BUZ) { + /* unregister i2c_bus */ + i2c_unregister_bus((&zr->i2c)); + /* put chip into reset */ + btwrite(0, ZR36057_SPGPPCR); + free_irq(zr->pci_dev->irq, zr); + iounmap(zr->zr36057_mem); + printk(KERN_ERR "%s: Card not supported\n", + zr->name); + continue; + } + printk(KERN_INFO "%s card detected\n", zr->name); + if (zr->card == LML33) { + GPIO(zr, 2, 1); // Set Composite input/output + } + + /* reset JPEG codec */ + zr36060_sleep(zr, 1); + zr36060_reset(zr); + + /* video bus enabled */ + + /* display codec revision */ + if (zr36060_read_8(zr, 0x022) == 0x33) { + printk(KERN_INFO "%s: Zoran ZR36060 (rev %d)\n", + zr->name, zr36060_read_8(zr, 0x023)); + } else { + /* unregister i2c_bus */ + i2c_unregister_bus((&zr->i2c)); + /* put chip into reset */ + btwrite(0, ZR36057_SPGPPCR); + free_irq(zr->pci_dev->irq, zr); + iounmap(zr->zr36057_mem); + printk(KERN_ERR "%s: Zoran ZR36060 not found\n", + zr->name); + continue; + } + + zoran_num++; + } + if (zoran_num == 0) { + printk(KERN_INFO "No known MJPEG cards found.\n"); + } + return zoran_num; +} + +static void handle_chipset(void) +{ + if(pci_pci_problems & PCIPCI_FAIL) + printk(KERN_WARNING "Chipset may not support reliable PCI-PCI DMA.\n"); + + if(pci_pci_problems & PCIPCI_TRITON) + { + printk(KERN_WARNING "Enabling Triton support.\n"); + triton = 1; + } + + if(pci_pci_problems & PCIPCI_NATOMA) + { + printk(KERN_WARNING "Enabling Natoma workaround.\n"); + natoma = 1; + } +} + +static int init_dc10_cards(void) +{ + int i; + + memset(zoran, 0, sizeof(zoran)); + printk(KERN_INFO + "Zoran ZR36060 + ZR36057/67 MJPEG board driver version %d.%d\n", + MAJOR_VERSION, MINOR_VERSION); + + /* Look for cards */ + + if (find_zr36057() < 0) { + return -EIO; + } + if (zoran_num == 0) + return 0; //-ENXIO; + + printk(KERN_INFO "MJPEG: %d card(s) found\n", zoran_num); + + /* check the parameters we have been given, adjust if necessary */ + + if (v4l_nbufs < 0) + v4l_nbufs = 0; + if (v4l_nbufs > VIDEO_MAX_FRAME) + v4l_nbufs = VIDEO_MAX_FRAME; + /* The user specfies the in KB, we want them in byte (and page aligned) */ + v4l_bufsize = PAGE_ALIGN(v4l_bufsize * 1024); + if (v4l_bufsize < 32768) + v4l_bufsize = 32768; + /* 2 MB is arbitrary but sufficient for the maximum possible images */ + if (v4l_bufsize > 2048 * 1024) + v4l_bufsize = 2048 * 1024; + + printk(KERN_INFO "MJPEG: using %d V4L buffers of size %d KB\n", + v4l_nbufs, v4l_bufsize >> 10); + + /* Use parameter for vidmem or try to find a video card */ + + if (vidmem) { + printk(KERN_INFO + "MJPEG: Using supplied video memory base address @ 0x%lx\n", + vidmem); + } + /* check if we have a Triton or Natome chipset */ + + handle_chipset(); + + /* take care of Natoma chipset and a revision 1 zr36057 */ + + for (i = 0; i < zoran_num; i++) { + if (natoma && zoran[i].revision <= 1) { + zoran[i].need_contiguous = 1; + printk(KERN_INFO + "%s: ZR36057/Natoma bug, max. buffer size is 128K\n", + zoran[i].name); + } else { + zoran[i].need_contiguous = 0; + } + } + + /* initialize the Buzs */ + + /* We have to know which ones must be released if an error occurs */ + for (i = 0; i < zoran_num; i++) + zoran[i].initialized = 0; + + for (i = 0; i < zoran_num; i++) { + if (zr36057_init(i) < 0) { + release_dc10(); + return -EIO; + } + zoran_proc_init(i); + } + + return 0; +} + +static void unload_dc10_cards(void) +{ + release_dc10(); +} + + +module_init(init_dc10_cards); +module_exit(unload_dc10_cards); diff -u --recursive --new-file v2.4.6/linux/drivers/media/video/zr36120.c linux/drivers/media/video/zr36120.c --- v2.4.6/linux/drivers/media/video/zr36120.c Tue Jul 3 17:08:20 2001 +++ linux/drivers/media/video/zr36120.c Mon Jul 16 15:13:32 2001 @@ -1189,7 +1189,7 @@ if (vw.flags) return -EINVAL; - if (vw.clipcount>256) + if (vw.clipcount <0 || vw.clipcount>256) return -EDOM; /* Too many! */ /* diff -u --recursive --new-file v2.4.6/linux/drivers/message/fusion/Config.in linux/drivers/message/fusion/Config.in --- v2.4.6/linux/drivers/message/fusion/Config.in Wed Dec 31 16:00:00 1969 +++ linux/drivers/message/fusion/Config.in Fri Jul 6 17:03:11 2001 @@ -0,0 +1,39 @@ +mainmenu_option next_comment +comment 'Fusion MPT device support' + +dep_tristate "Fusion MPT (base + ScsiHost) drivers" CONFIG_FUSION $CONFIG_SCSI $CONFIG_BLK_DEV_SD + +if [ "$CONFIG_FUSION" = "y" -o "$CONFIG_FUSION" = "m" ]; then + + if [ "$CONFIG_BLK_DEV_SD" = "y" -a "$CONFIG_FUSION" = "y" ]; then + define_bool CONFIG_FUSION_BOOT y + comment "(ability to boot linux kernel from Fusion device is ENABLED!)" + else + define_bool CONFIG_FUSION_BOOT n + comment "(ability to boot linux kernel from Fusion device is DISABLED!)" + fi + + if [ "$CONFIG_MODULES" = "y" ]; then + # How can we force these options to module or nothing? + dep_tristate " Enhanced SCSI error reporting" CONFIG_FUSION_ISENSE $CONFIG_FUSION m + dep_tristate " Fusion MPT misc device (ioctl) driver" CONFIG_FUSION_CTL $CONFIG_FUSION m + fi + + dep_tristate " Fusion MPT LAN driver" CONFIG_FUSION_LAN $CONFIG_FUSION $CONFIG_NET + if [ "$CONFIG_FUSION_LAN" != "n" ]; then + define_bool CONFIG_NET_FC y + fi + +else + + define_bool CONFIG_FUSION_BOOT n + # These <should> be define_tristate, but we leave them define_bool + # for backward compatibility with pre-linux-2.2.15 kernels. + # (Bugzilla:fibrebugs, #384) + define_bool CONFIG_FUSION_ISENSE n + define_bool CONFIG_FUSION_CTL n + define_bool CONFIG_FUSION_LAN n + +fi + +endmenu diff -u --recursive --new-file v2.4.6/linux/drivers/message/fusion/Makefile linux/drivers/message/fusion/Makefile --- v2.4.6/linux/drivers/message/fusion/Makefile Wed Dec 31 16:00:00 1969 +++ linux/drivers/message/fusion/Makefile Fri Jul 6 17:03:11 2001 @@ -0,0 +1,72 @@ +# +# Makefile for the LSI Logic Fusion MPT (Message Passing Technology) drivers. +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# +# Note 2! The CFLAGS definition is now inherited from the +# parent makefile. +# +# Note 3! If you want to turn on various debug defines for an extended period of +# time but don't want them lingering around in the Makefile when you pass it on +# to someone else, use the MPT_CFLAGS env variable (thanks Steve). -nromer + +#=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-{ LSI_LOGIC + +# Architecture-specific... +# # intel +#EXTRA_CFLAGS += -g +# # sparc64 +#EXTRA_CFLAGS += -gstabs+ + +EXTRA_CFLAGS += -I. ${MPT_CFLAGS} + +# Fusion MPT drivers; recognized debug defines... +# MPT general: +#EXTRA_CFLAGS += -DDEBUG +#EXTRA_CFLAGS += -DMPT_DEBUG +#EXTRA_CFLAGS += -DMPT_DEBUG_MSG_FRAME +#EXTRA_CFLAGS += -DMPT_DEBUG_SPINLOCK +# driver/module specifics... +# For mptbase: +#CFLAGS_mptbase.o += -DMPT_DEBUG_HANDSHAKE +#CFLAGS_mptbase.o += -DMPT_DEBUG_IRQ +# For {mptscsih, mptctl}: +#CFLAGS_mptscsih.o += -DMPT_SCSI_USE_NEW_EH +#CFLAGS_mptscsih.o += -DMPT_SCSI_CACHE_AUTOSENSE +#CFLAGS_mptscsih.o += -DMPT_DEBUG_SG +#CFLAGS_mptctl.o += -DMPT_DEBUG_SG +# For mptlan: +#CFLAGS_mptlan.o += -DMPT_LAN_IO_DEBUG +# For isense: + +# EXP... +##mptscsih-objs := scsihost.o scsiherr.o + +#=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-} LSI_LOGIC + +O_TARGET := fusion.o + +export-objs := mptbase.o mptscsih.o mptlan.o mptctl.o isense.o + +# ? what's list-multi for? +#list-multi := fusion.o mptscsih.o + +obj-$(CONFIG_FUSION) += mptbase.o mptscsih.o +obj-$(CONFIG_FUSION_ISENSE) += isense.o +obj-$(CONFIG_FUSION_CTL) += mptctl.o +obj-$(CONFIG_FUSION_LAN) += mptlan.o + +O_OBJS := $(filter-out $(export-objs), $(obj-y)) +OX_OBJS := $(filter $(export-objs), $(obj-y)) +M_OBJS := $(sort $(filter-out $(export-objs), $(obj-m))) +MX_OBJS := $(sort $(filter $(export-objs), $(obj-m))) + +include $(TOPDIR)/Rules.make + + +# EXP... +## Fusion MPT extra's... +##mptscsih.o: $(mptscsih-objs) +## $(LD) -r -o $@ $(mptscsih-objs) diff -u --recursive --new-file v2.4.6/linux/drivers/message/fusion/ascq_tbl.c linux/drivers/message/fusion/ascq_tbl.c --- v2.4.6/linux/drivers/message/fusion/ascq_tbl.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/message/fusion/ascq_tbl.c Fri Jul 6 17:03:11 2001 @@ -0,0 +1,2416 @@ +#ifndef SCSI_ASCQ_TBL_C_INCLUDED +#define SCSI_ASCQ_TBL_C_INCLUDED + +/* AuToMaGiCaLlY generated from: "t10.org/asc-num.txt" + ******************************************************************************* + * File: ASC-NUM.TXT + * + * SCSI ASC/ASCQ Assignments + * Numeric Sorted Listing + * as of 5/18/00 + * + * D - DIRECT ACCESS DEVICE (SBC-2) device column key + * .T - SEQUENTIAL ACCESS DEVICE (SSC) ------------------- + * . L - PRINTER DEVICE (SSC) blank = reserved + * . P - PROCESSOR DEVICE (SPC) not blank = allowed + * . .W - WRITE ONCE READ MULTIPLE DEVICE (SBC-2) + * . . R - CD DEVICE (MMC) + * . . S - SCANNER DEVICE (SCSI-2) + * . . .O - OPTICAL MEMORY DEVICE (SBC-2) + * . . . M - MEDIA CHANGER DEVICE (SMC) + * . . . C - COMMUNICATION DEVICE (SCSI-2) + * . . . .A - STORAGE ARRAY DEVICE (SCC) + * . . . . E - ENCLOSURE SERVICES DEVICE (SES) + * . . . . B - SIMPLIFIED DIRECT-ACCESS DEVICE (RBC) + * . . . . .K - OPTICAL CARD READER/WRITER DEVICE (OCRW) + * ASC/ASCQ DTLPWRSOMCAEBK Description + * ------- -------------- ---------------------------------------------------- + */ + +static char SenseDevTypes001[] = "DTLPWRSOMCAEBK"; +static char SenseDevTypes002[] = ".T............"; +static char SenseDevTypes003[] = ".T....S......."; +static char SenseDevTypes004[] = ".TL...S......."; +static char SenseDevTypes005[] = ".....R........"; +static char SenseDevTypes006[] = "DTL.WRSOM.AEBK"; +static char SenseDevTypes007[] = "D...W..O....BK"; +static char SenseDevTypes008[] = "D...WR.OM...BK"; +static char SenseDevTypes009[] = "DTL.W.SO....BK"; +static char SenseDevTypes010[] = "DTL..R.O....B."; +static char SenseDevTypes011[] = "DT..W..OMCA.BK"; +static char SenseDevTypes012[] = ".............."; +static char SenseDevTypes013[] = "DTL.WRSOMCAEBK"; +static char SenseDevTypes014[] = "DTL.WRSOM...BK"; +static char SenseDevTypes015[] = "DT...R.OM...BK"; +static char SenseDevTypes016[] = "DTLPWRSO.C...K"; +static char SenseDevTypes017[] = "DT..WR.O....B."; +static char SenseDevTypes018[] = "....WR.O.....K"; +static char SenseDevTypes019[] = "....WR.O......"; +static char SenseDevTypes020[] = ".T...RS......."; +static char SenseDevTypes021[] = ".............K"; +static char SenseDevTypes022[] = "DT..W..O....B."; +static char SenseDevTypes023[] = "DT..WRSO....BK"; +static char SenseDevTypes024[] = "DT..W.SO....BK"; +static char SenseDevTypes025[] = "....WR.O....B."; +static char SenseDevTypes026[] = "....W..O....B."; +static char SenseDevTypes027[] = "DT.....O....BK"; +static char SenseDevTypes028[] = "DTL.WRSO....BK"; +static char SenseDevTypes029[] = "DT..WR.O....BK"; +static char SenseDevTypes030[] = "DT..W..O....BK"; +static char SenseDevTypes031[] = "D...WR.O....BK"; +static char SenseDevTypes032[] = "D......O.....K"; +static char SenseDevTypes033[] = "D......O....BK"; +static char SenseDevTypes034[] = "DT..WR.OM...BK"; +static char SenseDevTypes035[] = "D............."; +static char SenseDevTypes036[] = "DTLPWRSOMCAE.K"; +static char SenseDevTypes037[] = "DTLPWRSOMCA.BK"; +static char SenseDevTypes038[] = ".T...R........"; +static char SenseDevTypes039[] = "DT..WR.OM...B."; +static char SenseDevTypes040[] = "DTL.WRSOMCAE.K"; +static char SenseDevTypes041[] = "DTLPWRSOMCAE.."; +static char SenseDevTypes042[] = "......S......."; +static char SenseDevTypes043[] = "............B."; +static char SenseDevTypes044[] = "DTLPWRSO.CA..K"; +static char SenseDevTypes045[] = "DT...R.......K"; +static char SenseDevTypes046[] = "D.L..R.O....B."; +static char SenseDevTypes047[] = "..L..........."; +static char SenseDevTypes048[] = ".TL..........."; +static char SenseDevTypes049[] = "DTLPWRSOMC..BK"; +static char SenseDevTypes050[] = "DT..WR.OMCAEBK"; +static char SenseDevTypes051[] = "DT..WR.OMCAEB."; +static char SenseDevTypes052[] = ".T...R.O......"; +static char SenseDevTypes053[] = "...P.........."; +static char SenseDevTypes054[] = "DTLPWRSOM.AE.K"; +static char SenseDevTypes055[] = "DTLPWRSOM.AE.."; +static char SenseDevTypes056[] = ".......O......"; +static char SenseDevTypes057[] = "DTLPWRSOM...BK"; +static char SenseDevTypes058[] = "DT..WR.O..A.BK"; +static char SenseDevTypes059[] = "DTLPWRSOM....K"; +static char SenseDevTypes060[] = "D......O......"; +static char SenseDevTypes061[] = ".....R......B."; +static char SenseDevTypes062[] = "D...........B."; +static char SenseDevTypes063[] = "............BK"; +static char SenseDevTypes064[] = "..........A..."; + +static ASCQ_Table_t ASCQ_Table[] = { + { + 0x00, 0x00, + SenseDevTypes001, + "NO ADDITIONAL SENSE INFORMATION" + }, + { + 0x00, 0x01, + SenseDevTypes002, + "FILEMARK DETECTED" + }, + { + 0x00, 0x02, + SenseDevTypes003, + "END-OF-PARTITION/MEDIUM DETECTED" + }, + { + 0x00, 0x03, + SenseDevTypes002, + "SETMARK DETECTED" + }, + { + 0x00, 0x04, + SenseDevTypes003, + "BEGINNING-OF-PARTITION/MEDIUM DETECTED" + }, + { + 0x00, 0x05, + SenseDevTypes004, + "END-OF-DATA DETECTED" + }, + { + 0x00, 0x06, + SenseDevTypes001, + "I/O PROCESS TERMINATED" + }, + { + 0x00, 0x11, + SenseDevTypes005, + "AUDIO PLAY OPERATION IN PROGRESS" + }, + { + 0x00, 0x12, + SenseDevTypes005, + "AUDIO PLAY OPERATION PAUSED" + }, + { + 0x00, 0x13, + SenseDevTypes005, + "AUDIO PLAY OPERATION SUCCESSFULLY COMPLETED" + }, + { + 0x00, 0x14, + SenseDevTypes005, + "AUDIO PLAY OPERATION STOPPED DUE TO ERROR" + }, + { + 0x00, 0x15, + SenseDevTypes005, + "NO CURRENT AUDIO STATUS TO RETURN" + }, + { + 0x00, 0x16, + SenseDevTypes001, + "OPERATION IN PROGRESS" + }, + { + 0x00, 0x17, + SenseDevTypes006, + "CLEANING REQUESTED" + }, + { + 0x01, 0x00, + SenseDevTypes007, + "NO INDEX/SECTOR SIGNAL" + }, + { + 0x02, 0x00, + SenseDevTypes008, + "NO SEEK COMPLETE" + }, + { + 0x03, 0x00, + SenseDevTypes009, + "PERIPHERAL DEVICE WRITE FAULT" + }, + { + 0x03, 0x01, + SenseDevTypes002, + "NO WRITE CURRENT" + }, + { + 0x03, 0x02, + SenseDevTypes002, + "EXCESSIVE WRITE ERRORS" + }, + { + 0x04, 0x00, + SenseDevTypes001, + "LOGICAL UNIT NOT READY, CAUSE NOT REPORTABLE" + }, + { + 0x04, 0x01, + SenseDevTypes001, + "LOGICAL UNIT IS IN PROCESS OF BECOMING READY" + }, + { + 0x04, 0x02, + SenseDevTypes001, + "LOGICAL UNIT NOT READY, INITIALIZING CMD. REQUIRED" + }, + { + 0x04, 0x03, + SenseDevTypes001, + "LOGICAL UNIT NOT READY, MANUAL INTERVENTION REQUIRED" + }, + { + 0x04, 0x04, + SenseDevTypes010, + "LOGICAL UNIT NOT READY, FORMAT IN PROGRESS" + }, + { + 0x04, 0x05, + SenseDevTypes011, + "LOGICAL UNIT NOT READY, REBUILD IN PROGRESS" + }, + { + 0x04, 0x06, + SenseDevTypes011, + "LOGICAL UNIT NOT READY, RECALCULATION IN PROGRESS" + }, + { + 0x04, 0x07, + SenseDevTypes001, + "LOGICAL UNIT NOT READY, OPERATION IN PROGRESS" + }, + { + 0x04, 0x08, + SenseDevTypes005, + "LOGICAL UNIT NOT READY, LONG WRITE IN PROGRESS" + }, + { + 0x04, 0x09, + SenseDevTypes001, + "LOGICAL UNIT NOT READY, SELF-TEST IN PROGRESS" + }, + { + 0x04, 0x10, + SenseDevTypes012, + "auxiliary memory code 2 (99-148) [proposed]" + }, + { + 0x05, 0x00, + SenseDevTypes013, + "LOGICAL UNIT DOES NOT RESPOND TO SELECTION" + }, + { + 0x06, 0x00, + SenseDevTypes008, + "NO REFERENCE POSITION FOUND" + }, + { + 0x07, 0x00, + SenseDevTypes014, + "MULTIPLE PERIPHERAL DEVICES SELECTED" + }, + { + 0x08, 0x00, + SenseDevTypes013, + "LOGICAL UNIT COMMUNICATION FAILURE" + }, + { + 0x08, 0x01, + SenseDevTypes013, + "LOGICAL UNIT COMMUNICATION TIME-OUT" + }, + { + 0x08, 0x02, + SenseDevTypes013, + "LOGICAL UNIT COMMUNICATION PARITY ERROR" + }, + { + 0x08, 0x03, + SenseDevTypes015, + "LOGICAL UNIT COMMUNICATION CRC ERROR (ULTRA-DMA/32)" + }, + { + 0x08, 0x04, + SenseDevTypes016, + "UNREACHABLE COPY TARGET" + }, + { + 0x09, 0x00, + SenseDevTypes017, + "TRACK FOLLOWING ERROR" + }, + { + 0x09, 0x01, + SenseDevTypes018, + "TRACKING SERVO FAILURE" + }, + { + 0x09, 0x02, + SenseDevTypes018, + "FOCUS SERVO FAILURE" + }, + { + 0x09, 0x03, + SenseDevTypes019, + "SPINDLE SERVO FAILURE" + }, + { + 0x09, 0x04, + SenseDevTypes017, + "HEAD SELECT FAULT" + }, + { + 0x0A, 0x00, + SenseDevTypes001, + "ERROR LOG OVERFLOW" + }, + { + 0x0B, 0x00, + SenseDevTypes001, + "WARNING" + }, + { + 0x0B, 0x01, + SenseDevTypes001, + "WARNING - SPECIFIED TEMPERATURE EXCEEDED" + }, + { + 0x0B, 0x02, + SenseDevTypes001, + "WARNING - ENCLOSURE DEGRADED" + }, + { + 0x0C, 0x00, + SenseDevTypes020, + "WRITE ERROR" + }, + { + 0x0C, 0x01, + SenseDevTypes021, + "WRITE ERROR - RECOVERED WITH AUTO REALLOCATION" + }, + { + 0x0C, 0x02, + SenseDevTypes007, + "WRITE ERROR - AUTO REALLOCATION FAILED" + }, + { + 0x0C, 0x03, + SenseDevTypes007, + "WRITE ERROR - RECOMMEND REASSIGNMENT" + }, + { + 0x0C, 0x04, + SenseDevTypes022, + "COMPRESSION CHECK MISCOMPARE ERROR" + }, + { + 0x0C, 0x05, + SenseDevTypes022, + "DATA EXPANSION OCCURRED DURING COMPRESSION" + }, + { + 0x0C, 0x06, + SenseDevTypes022, + "BLOCK NOT COMPRESSIBLE" + }, + { + 0x0C, 0x07, + SenseDevTypes005, + "WRITE ERROR - RECOVERY NEEDED" + }, + { + 0x0C, 0x08, + SenseDevTypes005, + "WRITE ERROR - RECOVERY FAILED" + }, + { + 0x0C, 0x09, + SenseDevTypes005, + "WRITE ERROR - LOSS OF STREAMING" + }, + { + 0x0C, 0x0A, + SenseDevTypes005, + "WRITE ERROR - PADDING BLOCKS ADDED" + }, + { + 0x0C, 0x0B, + SenseDevTypes012, + "auxiliary memory code 4 (99-148) [proposed]" + }, + { + 0x10, 0x00, + SenseDevTypes007, + "ID CRC OR ECC ERROR" + }, + { + 0x11, 0x00, + SenseDevTypes023, + "UNRECOVERED READ ERROR" + }, + { + 0x11, 0x01, + SenseDevTypes023, + "READ RETRIES EXHAUSTED" + }, + { + 0x11, 0x02, + SenseDevTypes023, + "ERROR TOO LONG TO CORRECT" + }, + { + 0x11, 0x03, + SenseDevTypes024, + "MULTIPLE READ ERRORS" + }, + { + 0x11, 0x04, + SenseDevTypes007, + "UNRECOVERED READ ERROR - AUTO REALLOCATE FAILED" + }, + { + 0x11, 0x05, + SenseDevTypes025, + "L-EC UNCORRECTABLE ERROR" + }, + { + 0x11, 0x06, + SenseDevTypes025, + "CIRC UNRECOVERED ERROR" + }, + { + 0x11, 0x07, + SenseDevTypes026, + "DATA RE-SYNCHRONIZATION ERROR" + }, + { + 0x11, 0x08, + SenseDevTypes002, + "INCOMPLETE BLOCK READ" + }, + { + 0x11, 0x09, + SenseDevTypes002, + "NO GAP FOUND" + }, + { + 0x11, 0x0A, + SenseDevTypes027, + "MISCORRECTED ERROR" + }, + { + 0x11, 0x0B, + SenseDevTypes007, + "UNRECOVERED READ ERROR - RECOMMEND REASSIGNMENT" + }, + { + 0x11, 0x0C, + SenseDevTypes007, + "UNRECOVERED READ ERROR - RECOMMEND REWRITE THE DATA" + }, + { + 0x11, 0x0D, + SenseDevTypes017, + "DE-COMPRESSION CRC ERROR" + }, + { + 0x11, 0x0E, + SenseDevTypes017, + "CANNOT DECOMPRESS USING DECLARED ALGORITHM" + }, + { + 0x11, 0x0F, + SenseDevTypes005, + "ERROR READING UPC/EAN NUMBER" + }, + { + 0x11, 0x10, + SenseDevTypes005, + "ERROR READING ISRC NUMBER" + }, + { + 0x11, 0x11, + SenseDevTypes005, + "READ ERROR - LOSS OF STREAMING" + }, + { + 0x11, 0x12, + SenseDevTypes012, + "auxiliary memory code 3 (99-148) [proposed]" + }, + { + 0x12, 0x00, + SenseDevTypes007, + "ADDRESS MARK NOT FOUND FOR ID FIELD" + }, + { + 0x13, 0x00, + SenseDevTypes007, + "ADDRESS MARK NOT FOUND FOR DATA FIELD" + }, + { + 0x14, 0x00, + SenseDevTypes028, + "RECORDED ENTITY NOT FOUND" + }, + { + 0x14, 0x01, + SenseDevTypes029, + "RECORD NOT FOUND" + }, + { + 0x14, 0x02, + SenseDevTypes002, + "FILEMARK OR SETMARK NOT FOUND" + }, + { + 0x14, 0x03, + SenseDevTypes002, + "END-OF-DATA NOT FOUND" + }, + { + 0x14, 0x04, + SenseDevTypes002, + "BLOCK SEQUENCE ERROR" + }, + { + 0x14, 0x05, + SenseDevTypes030, + "RECORD NOT FOUND - RECOMMEND REASSIGNMENT" + }, + { + 0x14, 0x06, + SenseDevTypes030, + "RECORD NOT FOUND - DATA AUTO-REALLOCATED" + }, + { + 0x15, 0x00, + SenseDevTypes014, + "RANDOM POSITIONING ERROR" + }, + { + 0x15, 0x01, + SenseDevTypes014, + "MECHANICAL POSITIONING ERROR" + }, + { + 0x15, 0x02, + SenseDevTypes029, + "POSITIONING ERROR DETECTED BY READ OF MEDIUM" + }, + { + 0x16, 0x00, + SenseDevTypes007, + "DATA SYNCHRONIZATION MARK ERROR" + }, + { + 0x16, 0x01, + SenseDevTypes007, + "DATA SYNC ERROR - DATA REWRITTEN" + }, + { + 0x16, 0x02, + SenseDevTypes007, + "DATA SYNC ERROR - RECOMMEND REWRITE" + }, + { + 0x16, 0x03, + SenseDevTypes007, + "DATA SYNC ERROR - DATA AUTO-REALLOCATED" + }, + { + 0x16, 0x04, + SenseDevTypes007, + "DATA SYNC ERROR - RECOMMEND REASSIGNMENT" + }, + { + 0x17, 0x00, + SenseDevTypes023, + "RECOVERED DATA WITH NO ERROR CORRECTION APPLIED" + }, + { + 0x17, 0x01, + SenseDevTypes023, + "RECOVERED DATA WITH RETRIES" + }, + { + 0x17, 0x02, + SenseDevTypes029, + "RECOVERED DATA WITH POSITIVE HEAD OFFSET" + }, + { + 0x17, 0x03, + SenseDevTypes029, + "RECOVERED DATA WITH NEGATIVE HEAD OFFSET" + }, + { + 0x17, 0x04, + SenseDevTypes025, + "RECOVERED DATA WITH RETRIES AND/OR CIRC APPLIED" + }, + { + 0x17, 0x05, + SenseDevTypes031, + "RECOVERED DATA USING PREVIOUS SECTOR ID" + }, + { + 0x17, 0x06, + SenseDevTypes007, + "RECOVERED DATA WITHOUT ECC - DATA AUTO-REALLOCATED" + }, + { + 0x17, 0x07, + SenseDevTypes031, + "RECOVERED DATA WITHOUT ECC - RECOMMEND REASSIGNMENT" + }, + { + 0x17, 0x08, + SenseDevTypes031, + "RECOVERED DATA WITHOUT ECC - RECOMMEND REWRITE" + }, + { + 0x17, 0x09, + SenseDevTypes031, + "RECOVERED DATA WITHOUT ECC - DATA REWRITTEN" + }, + { + 0x18, 0x00, + SenseDevTypes029, + "RECOVERED DATA WITH ERROR CORRECTION APPLIED" + }, + { + 0x18, 0x01, + SenseDevTypes031, + "RECOVERED DATA WITH ERROR CORR. & RETRIES APPLIED" + }, + { + 0x18, 0x02, + SenseDevTypes031, + "RECOVERED DATA - DATA AUTO-REALLOCATED" + }, + { + 0x18, 0x03, + SenseDevTypes005, + "RECOVERED DATA WITH CIRC" + }, + { + 0x18, 0x04, + SenseDevTypes005, + "RECOVERED DATA WITH L-EC" + }, + { + 0x18, 0x05, + SenseDevTypes031, + "RECOVERED DATA - RECOMMEND REASSIGNMENT" + }, + { + 0x18, 0x06, + SenseDevTypes031, + "RECOVERED DATA - RECOMMEND REWRITE" + }, + { + 0x18, 0x07, + SenseDevTypes007, + "RECOVERED DATA WITH ECC - DATA REWRITTEN" + }, + { + 0x19, 0x00, + SenseDevTypes032, + "DEFECT LIST ERROR" + }, + { + 0x19, 0x01, + SenseDevTypes032, + "DEFECT LIST NOT AVAILABLE" + }, + { + 0x19, 0x02, + SenseDevTypes032, + "DEFECT LIST ERROR IN PRIMARY LIST" + }, + { + 0x19, 0x03, + SenseDevTypes032, + "DEFECT LIST ERROR IN GROWN LIST" + }, + { + 0x1A, 0x00, + SenseDevTypes001, + "PARAMETER LIST LENGTH ERROR" + }, + { + 0x1B, 0x00, + SenseDevTypes001, + "SYNCHRONOUS DATA TRANSFER ERROR" + }, + { + 0x1C, 0x00, + SenseDevTypes033, + "DEFECT LIST NOT FOUND" + }, + { + 0x1C, 0x01, + SenseDevTypes033, + "PRIMARY DEFECT LIST NOT FOUND" + }, + { + 0x1C, 0x02, + SenseDevTypes033, + "GROWN DEFECT LIST NOT FOUND" + }, + { + 0x1D, 0x00, + SenseDevTypes029, + "MISCOMPARE DURING VERIFY OPERATION" + }, + { + 0x1E, 0x00, + SenseDevTypes007, + "RECOVERED ID WITH ECC CORRECTION" + }, + { + 0x1F, 0x00, + SenseDevTypes032, + "PARTIAL DEFECT LIST TRANSFER" + }, + { + 0x20, 0x00, + SenseDevTypes001, + "INVALID COMMAND OPERATION CODE" + }, + { + 0x20, 0x01, + SenseDevTypes012, + "access controls code 1 (99-314) [proposed]" + }, + { + 0x20, 0x02, + SenseDevTypes012, + "access controls code 2 (99-314) [proposed]" + }, + { + 0x20, 0x03, + SenseDevTypes012, + "access controls code 3 (99-314) [proposed]" + }, + { + 0x21, 0x00, + SenseDevTypes034, + "LOGICAL BLOCK ADDRESS OUT OF RANGE" + }, + { + 0x21, 0x01, + SenseDevTypes034, + "INVALID ELEMENT ADDRESS" + }, + { + 0x22, 0x00, + SenseDevTypes035, + "ILLEGAL FUNCTION (USE 20 00, 24 00, OR 26 00)" + }, + { + 0x24, 0x00, + SenseDevTypes001, + "INVALID FIELD IN CDB" + }, + { + 0x24, 0x01, + SenseDevTypes001, + "CDB DECRYPTION ERROR" + }, + { + 0x25, 0x00, + SenseDevTypes001, + "LOGICAL UNIT NOT SUPPORTED" + }, + { + 0x26, 0x00, + SenseDevTypes001, + "INVALID FIELD IN PARAMETER LIST" + }, + { + 0x26, 0x01, + SenseDevTypes001, + "PARAMETER NOT SUPPORTED" + }, + { + 0x26, 0x02, + SenseDevTypes001, + "PARAMETER VALUE INVALID" + }, + { + 0x26, 0x03, + SenseDevTypes036, + "THRESHOLD PARAMETERS NOT SUPPORTED" + }, + { + 0x26, 0x04, + SenseDevTypes001, + "INVALID RELEASE OF PERSISTENT RESERVATION" + }, + { + 0x26, 0x05, + SenseDevTypes037, + "DATA DECRYPTION ERROR" + }, + { + 0x26, 0x06, + SenseDevTypes016, + "TOO MANY TARGET DESCRIPTORS" + }, + { + 0x26, 0x07, + SenseDevTypes016, + "UNSUPPORTED TARGET DESCRIPTOR TYPE CODE" + }, + { + 0x26, 0x08, + SenseDevTypes016, + "TOO MANY SEGMENT DESCRIPTORS" + }, + { + 0x26, 0x09, + SenseDevTypes016, + "UNSUPPORTED SEGMENT DESCRIPTOR TYPE CODE" + }, + { + 0x26, 0x0A, + SenseDevTypes016, + "UNEXPECTED INEXACT SEGMENT" + }, + { + 0x26, 0x0B, + SenseDevTypes016, + "INLINE DATA LENGTH EXCEEDED" + }, + { + 0x26, 0x0C, + SenseDevTypes016, + "INVALID OPERATION FOR COPY SOURCE OR DESTINATION" + }, + { + 0x26, 0x0D, + SenseDevTypes016, + "COPY SEGMENT GRANULARITY VIOLATION" + }, + { + 0x27, 0x00, + SenseDevTypes029, + "WRITE PROTECTED" + }, + { + 0x27, 0x01, + SenseDevTypes029, + "HARDWARE WRITE PROTECTED" + }, + { + 0x27, 0x02, + SenseDevTypes029, + "LOGICAL UNIT SOFTWARE WRITE PROTECTED" + }, + { + 0x27, 0x03, + SenseDevTypes038, + "ASSOCIATED WRITE PROTECT" + }, + { + 0x27, 0x04, + SenseDevTypes038, + "PERSISTENT WRITE PROTECT" + }, + { + 0x27, 0x05, + SenseDevTypes038, + "PERMANENT WRITE PROTECT" + }, + { + 0x28, 0x00, + SenseDevTypes001, + "NOT READY TO READY CHANGE, MEDIUM MAY HAVE CHANGED" + }, + { + 0x28, 0x01, + SenseDevTypes039, + "IMPORT OR EXPORT ELEMENT ACCESSED" + }, + { + 0x29, 0x00, + SenseDevTypes001, + "POWER ON, RESET, OR BUS DEVICE RESET OCCURRED" + }, + { + 0x29, 0x01, + SenseDevTypes001, + "POWER ON OCCURRED" + }, + { + 0x29, 0x02, + SenseDevTypes001, + "SCSI BUS RESET OCCURRED" + }, + { + 0x29, 0x03, + SenseDevTypes001, + "BUS DEVICE RESET FUNCTION OCCURRED" + }, + { + 0x29, 0x04, + SenseDevTypes001, + "DEVICE INTERNAL RESET" + }, + { + 0x29, 0x05, + SenseDevTypes001, + "TRANSCEIVER MODE CHANGED TO SINGLE-ENDED" + }, + { + 0x29, 0x06, + SenseDevTypes001, + "TRANSCEIVER MODE CHANGED TO LVD" + }, + { + 0x2A, 0x00, + SenseDevTypes013, + "PARAMETERS CHANGED" + }, + { + 0x2A, 0x01, + SenseDevTypes013, + "MODE PARAMETERS CHANGED" + }, + { + 0x2A, 0x02, + SenseDevTypes040, + "LOG PARAMETERS CHANGED" + }, + { + 0x2A, 0x03, + SenseDevTypes036, + "RESERVATIONS PREEMPTED" + }, + { + 0x2A, 0x04, + SenseDevTypes041, + "RESERVATIONS RELEASED" + }, + { + 0x2A, 0x05, + SenseDevTypes041, + "REGISTRATIONS PREEMPTED" + }, + { + 0x2B, 0x00, + SenseDevTypes016, + "COPY CANNOT EXECUTE SINCE HOST CANNOT DISCONNECT" + }, + { + 0x2C, 0x00, + SenseDevTypes001, + "COMMAND SEQUENCE ERROR" + }, + { + 0x2C, 0x01, + SenseDevTypes042, + "TOO MANY WINDOWS SPECIFIED" + }, + { + 0x2C, 0x02, + SenseDevTypes042, + "INVALID COMBINATION OF WINDOWS SPECIFIED" + }, + { + 0x2C, 0x03, + SenseDevTypes005, + "CURRENT PROGRAM AREA IS NOT EMPTY" + }, + { + 0x2C, 0x04, + SenseDevTypes005, + "CURRENT PROGRAM AREA IS EMPTY" + }, + { + 0x2C, 0x05, + SenseDevTypes043, + "ILLEGAL POWER CONDITION REQUEST" + }, + { + 0x2D, 0x00, + SenseDevTypes002, + "OVERWRITE ERROR ON UPDATE IN PLACE" + }, + { + 0x2E, 0x00, + SenseDevTypes044, + "ERROR DETECTED BY THIRD PARTY TEMPORARY INITIATOR" + }, + { + 0x2E, 0x01, + SenseDevTypes044, + "THIRD PARTY DEVICE FAILURE" + }, + { + 0x2E, 0x02, + SenseDevTypes044, + "COPY TARGET DEVICE NOT REACHABLE" + }, + { + 0x2E, 0x03, + SenseDevTypes044, + "INCORRECT COPY TARGET DEVICE TYPE" + }, + { + 0x2E, 0x04, + SenseDevTypes044, + "COPY TARGET DEVICE DATA UNDERRUN" + }, + { + 0x2E, 0x05, + SenseDevTypes044, + "COPY TARGET DEVICE DATA OVERRUN" + }, + { + 0x2F, 0x00, + SenseDevTypes001, + "COMMANDS CLEARED BY ANOTHER INITIATOR" + }, + { + 0x30, 0x00, + SenseDevTypes034, + "INCOMPATIBLE MEDIUM INSTALLED" + }, + { + 0x30, 0x01, + SenseDevTypes029, + "CANNOT READ MEDIUM - UNKNOWN FORMAT" + }, + { + 0x30, 0x02, + SenseDevTypes029, + "CANNOT READ MEDIUM - INCOMPATIBLE FORMAT" + }, + { + 0x30, 0x03, + SenseDevTypes045, + "CLEANING CARTRIDGE INSTALLED" + }, + { + 0x30, 0x04, + SenseDevTypes029, + "CANNOT WRITE MEDIUM - UNKNOWN FORMAT" + }, + { + 0x30, 0x05, + SenseDevTypes029, + "CANNOT WRITE MEDIUM - INCOMPATIBLE FORMAT" + }, + { + 0x30, 0x06, + SenseDevTypes017, + "CANNOT FORMAT MEDIUM - INCOMPATIBLE MEDIUM" + }, + { + 0x30, 0x07, + SenseDevTypes006, + "CLEANING FAILURE" + }, + { + 0x30, 0x08, + SenseDevTypes005, + "CANNOT WRITE - APPLICATION CODE MISMATCH" + }, + { + 0x30, 0x09, + SenseDevTypes005, + "CURRENT SESSION NOT FIXATED FOR APPEND" + }, + { + 0x31, 0x00, + SenseDevTypes029, + "MEDIUM FORMAT CORRUPTED" + }, + { + 0x31, 0x01, + SenseDevTypes046, + "FORMAT COMMAND FAILED" + }, + { + 0x32, 0x00, + SenseDevTypes007, + "NO DEFECT SPARE LOCATION AVAILABLE" + }, + { + 0x32, 0x01, + SenseDevTypes007, + "DEFECT LIST UPDATE FAILURE" + }, + { + 0x33, 0x00, + SenseDevTypes002, + "TAPE LENGTH ERROR" + }, + { + 0x34, 0x00, + SenseDevTypes001, + "ENCLOSURE FAILURE" + }, + { + 0x35, 0x00, + SenseDevTypes001, + "ENCLOSURE SERVICES FAILURE" + }, + { + 0x35, 0x01, + SenseDevTypes001, + "UNSUPPORTED ENCLOSURE FUNCTION" + }, + { + 0x35, 0x02, + SenseDevTypes001, + "ENCLOSURE SERVICES UNAVAILABLE" + }, + { + 0x35, 0x03, + SenseDevTypes001, + "ENCLOSURE SERVICES TRANSFER FAILURE" + }, + { + 0x35, 0x04, + SenseDevTypes001, + "ENCLOSURE SERVICES TRANSFER REFUSED" + }, + { + 0x36, 0x00, + SenseDevTypes047, + "RIBBON, INK, OR TONER FAILURE" + }, + { + 0x37, 0x00, + SenseDevTypes013, + "ROUNDED PARAMETER" + }, + { + 0x38, 0x00, + SenseDevTypes043, + "EVENT STATUS NOTIFICATION" + }, + { + 0x38, 0x02, + SenseDevTypes043, + "ESN - POWER MANAGEMENT CLASS EVENT" + }, + { + 0x38, 0x04, + SenseDevTypes043, + "ESN - MEDIA CLASS EVENT" + }, + { + 0x38, 0x06, + SenseDevTypes043, + "ESN - DEVICE BUSY CLASS EVENT" + }, + { + 0x39, 0x00, + SenseDevTypes040, + "SAVING PARAMETERS NOT SUPPORTED" + }, + { + 0x3A, 0x00, + SenseDevTypes014, + "MEDIUM NOT PRESENT" + }, + { + 0x3A, 0x01, + SenseDevTypes034, + "MEDIUM NOT PRESENT - TRAY CLOSED" + }, + { + 0x3A, 0x02, + SenseDevTypes034, + "MEDIUM NOT PRESENT - TRAY OPEN" + }, + { + 0x3A, 0x03, + SenseDevTypes039, + "MEDIUM NOT PRESENT - LOADABLE" + }, + { + 0x3A, 0x04, + SenseDevTypes039, + "MEDIUM NOT PRESENT - MEDIUM AUXILIARY MEMORY ACCESSIBLE" + }, + { + 0x3B, 0x00, + SenseDevTypes048, + "SEQUENTIAL POSITIONING ERROR" + }, + { + 0x3B, 0x01, + SenseDevTypes002, + "TAPE POSITION ERROR AT BEGINNING-OF-MEDIUM" + }, + { + 0x3B, 0x02, + SenseDevTypes002, + "TAPE POSITION ERROR AT END-OF-MEDIUM" + }, + { + 0x3B, 0x03, + SenseDevTypes047, + "TAPE OR ELECTRONIC VERTICAL FORMS UNIT NOT READY" + }, + { + 0x3B, 0x04, + SenseDevTypes047, + "SLEW FAILURE" + }, + { + 0x3B, 0x05, + SenseDevTypes047, + "PAPER JAM" + }, + { + 0x3B, 0x06, + SenseDevTypes047, + "FAILED TO SENSE TOP-OF-FORM" + }, + { + 0x3B, 0x07, + SenseDevTypes047, + "FAILED TO SENSE BOTTOM-OF-FORM" + }, + { + 0x3B, 0x08, + SenseDevTypes002, + "REPOSITION ERROR" + }, + { + 0x3B, 0x09, + SenseDevTypes042, + "READ PAST END OF MEDIUM" + }, + { + 0x3B, 0x0A, + SenseDevTypes042, + "READ PAST BEGINNING OF MEDIUM" + }, + { + 0x3B, 0x0B, + SenseDevTypes042, + "POSITION PAST END OF MEDIUM" + }, + { + 0x3B, 0x0C, + SenseDevTypes003, + "POSITION PAST BEGINNING OF MEDIUM" + }, + { + 0x3B, 0x0D, + SenseDevTypes034, + "MEDIUM DESTINATION ELEMENT FULL" + }, + { + 0x3B, 0x0E, + SenseDevTypes034, + "MEDIUM SOURCE ELEMENT EMPTY" + }, + { + 0x3B, 0x0F, + SenseDevTypes005, + "END OF MEDIUM REACHED" + }, + { + 0x3B, 0x11, + SenseDevTypes034, + "MEDIUM MAGAZINE NOT ACCESSIBLE" + }, + { + 0x3B, 0x12, + SenseDevTypes034, + "MEDIUM MAGAZINE REMOVED" + }, + { + 0x3B, 0x13, + SenseDevTypes034, + "MEDIUM MAGAZINE INSERTED" + }, + { + 0x3B, 0x14, + SenseDevTypes034, + "MEDIUM MAGAZINE LOCKED" + }, + { + 0x3B, 0x15, + SenseDevTypes034, + "MEDIUM MAGAZINE UNLOCKED" + }, + { + 0x3B, 0x16, + SenseDevTypes005, + "MECHANICAL POSITIONING OR CHANGER ERROR" + }, + { + 0x3D, 0x00, + SenseDevTypes036, + "INVALID BITS IN IDENTIFY MESSAGE" + }, + { + 0x3E, 0x00, + SenseDevTypes001, + "LOGICAL UNIT HAS NOT SELF-CONFIGURED YET" + }, + { + 0x3E, 0x01, + SenseDevTypes001, + "LOGICAL UNIT FAILURE" + }, + { + 0x3E, 0x02, + SenseDevTypes001, + "TIMEOUT ON LOGICAL UNIT" + }, + { + 0x3E, 0x03, + SenseDevTypes001, + "LOGICAL UNIT FAILED SELF-TEST" + }, + { + 0x3E, 0x04, + SenseDevTypes001, + "LOGICAL UNIT UNABLE TO UPDATE SELF-TEST LOG" + }, + { + 0x3F, 0x00, + SenseDevTypes001, + "TARGET OPERATING CONDITIONS HAVE CHANGED" + }, + { + 0x3F, 0x01, + SenseDevTypes001, + "MICROCODE HAS BEEN CHANGED" + }, + { + 0x3F, 0x02, + SenseDevTypes049, + "CHANGED OPERATING DEFINITION" + }, + { + 0x3F, 0x03, + SenseDevTypes001, + "INQUIRY DATA HAS CHANGED" + }, + { + 0x3F, 0x04, + SenseDevTypes050, + "COMPONENT DEVICE ATTACHED" + }, + { + 0x3F, 0x05, + SenseDevTypes050, + "DEVICE IDENTIFIER CHANGED" + }, + { + 0x3F, 0x06, + SenseDevTypes051, + "REDUNDANCY GROUP CREATED OR MODIFIED" + }, + { + 0x3F, 0x07, + SenseDevTypes051, + "REDUNDANCY GROUP DELETED" + }, + { + 0x3F, 0x08, + SenseDevTypes051, + "SPARE CREATED OR MODIFIED" + }, + { + 0x3F, 0x09, + SenseDevTypes051, + "SPARE DELETED" + }, + { + 0x3F, 0x0A, + SenseDevTypes050, + "VOLUME SET CREATED OR MODIFIED" + }, + { + 0x3F, 0x0B, + SenseDevTypes050, + "VOLUME SET DELETED" + }, + { + 0x3F, 0x0C, + SenseDevTypes050, + "VOLUME SET DEASSIGNED" + }, + { + 0x3F, 0x0D, + SenseDevTypes050, + "VOLUME SET REASSIGNED" + }, + { + 0x3F, 0x0E, + SenseDevTypes041, + "REPORTED LUNS DATA HAS CHANGED" + }, + { + 0x3F, 0x0F, + SenseDevTypes001, + "ECHO BUFFER OVERWRITTEN" + }, + { + 0x3F, 0x10, + SenseDevTypes039, + "MEDIUM LOADABLE" + }, + { + 0x3F, 0x11, + SenseDevTypes039, + "MEDIUM AUXILIARY MEMORY ACCESSIBLE" + }, + { + 0x40, 0x00, + SenseDevTypes035, + "RAM FAILURE (SHOULD USE 40 NN)" + }, + { + 0x40, 0xFF, + SenseDevTypes001, + "DIAGNOSTIC FAILURE ON COMPONENT NN (80H-FFH)" + }, + { + 0x41, 0x00, + SenseDevTypes035, + "DATA PATH FAILURE (SHOULD USE 40 NN)" + }, + { + 0x42, 0x00, + SenseDevTypes035, + "POWER-ON OR SELF-TEST FAILURE (SHOULD USE 40 NN)" + }, + { + 0x43, 0x00, + SenseDevTypes001, + "MESSAGE ERROR" + }, + { + 0x44, 0x00, + SenseDevTypes001, + "INTERNAL TARGET FAILURE" + }, + { + 0x45, 0x00, + SenseDevTypes001, + "SELECT OR RESELECT FAILURE" + }, + { + 0x46, 0x00, + SenseDevTypes049, + "UNSUCCESSFUL SOFT RESET" + }, + { + 0x47, 0x00, + SenseDevTypes001, + "SCSI PARITY ERROR" + }, + { + 0x47, 0x01, + SenseDevTypes001, + "DATA PHASE CRC ERROR DETECTED" + }, + { + 0x47, 0x02, + SenseDevTypes001, + "SCSI PARITY ERROR DETECTED DURING ST DATA PHASE" + }, + { + 0x47, 0x03, + SenseDevTypes001, + "INFORMATION UNIT CRC ERROR DETECTED" + }, + { + 0x47, 0x04, + SenseDevTypes001, + "ASYNCHRONOUS INFORMATION PROTECTION ERROR DETECTED" + }, + { + 0x48, 0x00, + SenseDevTypes001, + "INITIATOR DETECTED ERROR MESSAGE RECEIVED" + }, + { + 0x49, 0x00, + SenseDevTypes001, + "INVALID MESSAGE ERROR" + }, + { + 0x4A, 0x00, + SenseDevTypes001, + "COMMAND PHASE ERROR" + }, + { + 0x4B, 0x00, + SenseDevTypes001, + "DATA PHASE ERROR" + }, + { + 0x4C, 0x00, + SenseDevTypes001, + "LOGICAL UNIT FAILED SELF-CONFIGURATION" + }, + { + 0x4D, 0xFF, + SenseDevTypes001, + "TAGGED OVERLAPPED COMMANDS (NN = QUEUE TAG)" + }, + { + 0x4E, 0x00, + SenseDevTypes001, + "OVERLAPPED COMMANDS ATTEMPTED" + }, + { + 0x50, 0x00, + SenseDevTypes002, + "WRITE APPEND ERROR" + }, + { + 0x50, 0x01, + SenseDevTypes002, + "WRITE APPEND POSITION ERROR" + }, + { + 0x50, 0x02, + SenseDevTypes002, + "POSITION ERROR RELATED TO TIMING" + }, + { + 0x51, 0x00, + SenseDevTypes052, + "ERASE FAILURE" + }, + { + 0x52, 0x00, + SenseDevTypes002, + "CARTRIDGE FAULT" + }, + { + 0x53, 0x00, + SenseDevTypes014, + "MEDIA LOAD OR EJECT FAILED" + }, + { + 0x53, 0x01, + SenseDevTypes002, + "UNLOAD TAPE FAILURE" + }, + { + 0x53, 0x02, + SenseDevTypes034, + "MEDIUM REMOVAL PREVENTED" + }, + { + 0x54, 0x00, + SenseDevTypes053, + "SCSI TO HOST SYSTEM INTERFACE FAILURE" + }, + { + 0x55, 0x00, + SenseDevTypes053, + "SYSTEM RESOURCE FAILURE" + }, + { + 0x55, 0x01, + SenseDevTypes033, + "SYSTEM BUFFER FULL" + }, + { + 0x55, 0x02, + SenseDevTypes054, + "INSUFFICIENT RESERVATION RESOURCES" + }, + { + 0x55, 0x03, + SenseDevTypes041, + "INSUFFICIENT RESOURCES" + }, + { + 0x55, 0x04, + SenseDevTypes055, + "INSUFFICIENT REGISTRATION RESOURCES" + }, + { + 0x55, 0x05, + SenseDevTypes012, + "access controls code 4 (99-314) [proposed]" + }, + { + 0x55, 0x06, + SenseDevTypes012, + "auxiliary memory code 1 (99-148) [proposed]" + }, + { + 0x57, 0x00, + SenseDevTypes005, + "UNABLE TO RECOVER TABLE-OF-CONTENTS" + }, + { + 0x58, 0x00, + SenseDevTypes056, + "GENERATION DOES NOT EXIST" + }, + { + 0x59, 0x00, + SenseDevTypes056, + "UPDATED BLOCK READ" + }, + { + 0x5A, 0x00, + SenseDevTypes057, + "OPERATOR REQUEST OR STATE CHANGE INPUT" + }, + { + 0x5A, 0x01, + SenseDevTypes034, + "OPERATOR MEDIUM REMOVAL REQUEST" + }, + { + 0x5A, 0x02, + SenseDevTypes058, + "OPERATOR SELECTED WRITE PROTECT" + }, + { + 0x5A, 0x03, + SenseDevTypes058, + "OPERATOR SELECTED WRITE PERMIT" + }, + { + 0x5B, 0x00, + SenseDevTypes059, + "LOG EXCEPTION" + }, + { + 0x5B, 0x01, + SenseDevTypes059, + "THRESHOLD CONDITION MET" + }, + { + 0x5B, 0x02, + SenseDevTypes059, + "LOG COUNTER AT MAXIMUM" + }, + { + 0x5B, 0x03, + SenseDevTypes059, + "LOG LIST CODES EXHAUSTED" + }, + { + 0x5C, 0x00, + SenseDevTypes060, + "RPL STATUS CHANGE" + }, + { + 0x5C, 0x01, + SenseDevTypes060, + "SPINDLES SYNCHRONIZED" + }, + { + 0x5C, 0x02, + SenseDevTypes060, + "SPINDLES NOT SYNCHRONIZED" + }, + { + 0x5D, 0x00, + SenseDevTypes001, + "FAILURE PREDICTION THRESHOLD EXCEEDED" + }, + { + 0x5D, 0x01, + SenseDevTypes061, + "MEDIA FAILURE PREDICTION THRESHOLD EXCEEDED" + }, + { + 0x5D, 0x02, + SenseDevTypes005, + "LOGICAL UNIT FAILURE PREDICTION THRESHOLD EXCEEDED" + }, + { + 0x5D, 0x10, + SenseDevTypes062, + "HARDWARE IMPENDING FAILURE GENERAL HARD DRIVE FAILURE" + }, + { + 0x5D, 0x11, + SenseDevTypes062, + "HARDWARE IMPENDING FAILURE DRIVE ERROR RATE TOO HIGH" + }, + { + 0x5D, 0x12, + SenseDevTypes062, + "HARDWARE IMPENDING FAILURE DATA ERROR RATE TOO HIGH" + }, + { + 0x5D, 0x13, + SenseDevTypes062, + "HARDWARE IMPENDING FAILURE SEEK ERROR RATE TOO HIGH" + }, + { + 0x5D, 0x14, + SenseDevTypes062, + "HARDWARE IMPENDING FAILURE TOO MANY BLOCK REASSIGNS" + }, + { + 0x5D, 0x15, + SenseDevTypes062, + "HARDWARE IMPENDING FAILURE ACCESS TIMES TOO HIGH" + }, + { + 0x5D, 0x16, + SenseDevTypes062, + "HARDWARE IMPENDING FAILURE START UNIT TIMES TOO HIGH" + }, + { + 0x5D, 0x17, + SenseDevTypes062, + "HARDWARE IMPENDING FAILURE CHANNEL PARAMETRICS" + }, + { + 0x5D, 0x18, + SenseDevTypes062, + "HARDWARE IMPENDING FAILURE CONTROLLER DETECTED" + }, + { + 0x5D, 0x19, + SenseDevTypes062, + "HARDWARE IMPENDING FAILURE THROUGHPUT PERFORMANCE" + }, + { + 0x5D, 0x1A, + SenseDevTypes062, + "HARDWARE IMPENDING FAILURE SEEK TIME PERFORMANCE" + }, + { + 0x5D, 0x1B, + SenseDevTypes062, + "HARDWARE IMPENDING FAILURE SPIN-UP RETRY COUNT" + }, + { + 0x5D, 0x1C, + SenseDevTypes062, + "HARDWARE IMPENDING FAILURE DRIVE CALIBRATION RETRY COUNT" + }, + { + 0x5D, 0x20, + SenseDevTypes062, + "CONTROLLER IMPENDING FAILURE GENERAL HARD DRIVE FAILURE" + }, + { + 0x5D, 0x21, + SenseDevTypes062, + "CONTROLLER IMPENDING FAILURE DRIVE ERROR RATE TOO HIGH" + }, + { + 0x5D, 0x22, + SenseDevTypes062, + "CONTROLLER IMPENDING FAILURE DATA ERROR RATE TOO HIGH" + }, + { + 0x5D, 0x23, + SenseDevTypes062, + "CONTROLLER IMPENDING FAILURE SEEK ERROR RATE TOO HIGH" + }, + { + 0x5D, 0x24, + SenseDevTypes062, + "CONTROLLER IMPENDING FAILURE TOO MANY BLOCK REASSIGNS" + }, + { + 0x5D, 0x25, + SenseDevTypes062, + "CONTROLLER IMPENDING FAILURE ACCESS TIMES TOO HIGH" + }, + { + 0x5D, 0x26, + SenseDevTypes062, + "CONTROLLER IMPENDING FAILURE START UNIT TIMES TOO HIGH" + }, + { + 0x5D, 0x27, + SenseDevTypes062, + "CONTROLLER IMPENDING FAILURE CHANNEL PARAMETRICS" + }, + { + 0x5D, 0x28, + SenseDevTypes062, + "CONTROLLER IMPENDING FAILURE CONTROLLER DETECTED" + }, + { + 0x5D, 0x29, + SenseDevTypes062, + "CONTROLLER IMPENDING FAILURE THROUGHPUT PERFORMANCE" + }, + { + 0x5D, 0x2A, + SenseDevTypes062, + "CONTROLLER IMPENDING FAILURE SEEK TIME PERFORMANCE" + }, + { + 0x5D, 0x2B, + SenseDevTypes062, + "CONTROLLER IMPENDING FAILURE SPIN-UP RETRY COUNT" + }, + { + 0x5D, 0x2C, + SenseDevTypes062, + "CONTROLLER IMPENDING FAILURE DRIVE CALIBRATION RETRY COUNT" + }, + { + 0x5D, 0x30, + SenseDevTypes062, + "DATA CHANNEL IMPENDING FAILURE GENERAL HARD DRIVE FAILURE" + }, + { + 0x5D, 0x31, + SenseDevTypes062, + "DATA CHANNEL IMPENDING FAILURE DRIVE ERROR RATE TOO HIGH" + }, + { + 0x5D, 0x32, + SenseDevTypes062, + "DATA CHANNEL IMPENDING FAILURE DATA ERROR RATE TOO HIGH" + }, + { + 0x5D, 0x33, + SenseDevTypes062, + "DATA CHANNEL IMPENDING FAILURE SEEK ERROR RATE TOO HIGH" + }, + { + 0x5D, 0x34, + SenseDevTypes062, + "DATA CHANNEL IMPENDING FAILURE TOO MANY BLOCK REASSIGNS" + }, + { + 0x5D, 0x35, + SenseDevTypes062, + "DATA CHANNEL IMPENDING FAILURE ACCESS TIMES TOO HIGH" + }, + { + 0x5D, 0x36, + SenseDevTypes062, + "DATA CHANNEL IMPENDING FAILURE START UNIT TIMES TOO HIGH" + }, + { + 0x5D, 0x37, + SenseDevTypes062, + "DATA CHANNEL IMPENDING FAILURE CHANNEL PARAMETRICS" + }, + { + 0x5D, 0x38, + SenseDevTypes062, + "DATA CHANNEL IMPENDING FAILURE CONTROLLER DETECTED" + }, + { + 0x5D, 0x39, + SenseDevTypes062, + "DATA CHANNEL IMPENDING FAILURE THROUGHPUT PERFORMANCE" + }, + { + 0x5D, 0x3A, + SenseDevTypes062, + "DATA CHANNEL IMPENDING FAILURE SEEK TIME PERFORMANCE" + }, + { + 0x5D, 0x3B, + SenseDevTypes062, + "DATA CHANNEL IMPENDING FAILURE SPIN-UP RETRY COUNT" + }, + { + 0x5D, 0x3C, + SenseDevTypes062, + "DATA CHANNEL IMPENDING FAILURE DRIVE CALIBRATION RETRY COUNT" + }, + { + 0x5D, 0x40, + SenseDevTypes062, + "SERVO IMPENDING FAILURE GENERAL HARD DRIVE FAILURE" + }, + { + 0x5D, 0x41, + SenseDevTypes062, + "SERVO IMPENDING FAILURE DRIVE ERROR RATE TOO HIGH" + }, + { + 0x5D, 0x42, + SenseDevTypes062, + "SERVO IMPENDING FAILURE DATA ERROR RATE TOO HIGH" + }, + { + 0x5D, 0x43, + SenseDevTypes062, + "SERVO IMPENDING FAILURE SEEK ERROR RATE TOO HIGH" + }, + { + 0x5D, 0x44, + SenseDevTypes062, + "SERVO IMPENDING FAILURE TOO MANY BLOCK REASSIGNS" + }, + { + 0x5D, 0x45, + SenseDevTypes062, + "SERVO IMPENDING FAILURE ACCESS TIMES TOO HIGH" + }, + { + 0x5D, 0x46, + SenseDevTypes062, + "SERVO IMPENDING FAILURE START UNIT TIMES TOO HIGH" + }, + { + 0x5D, 0x47, + SenseDevTypes062, + "SERVO IMPENDING FAILURE CHANNEL PARAMETRICS" + }, + { + 0x5D, 0x48, + SenseDevTypes062, + "SERVO IMPENDING FAILURE CONTROLLER DETECTED" + }, + { + 0x5D, 0x49, + SenseDevTypes062, + "SERVO IMPENDING FAILURE THROUGHPUT PERFORMANCE" + }, + { + 0x5D, 0x4A, + SenseDevTypes062, + "SERVO IMPENDING FAILURE SEEK TIME PERFORMANCE" + }, + { + 0x5D, 0x4B, + SenseDevTypes062, + "SERVO IMPENDING FAILURE SPIN-UP RETRY COUNT" + }, + { + 0x5D, 0x4C, + SenseDevTypes062, + "SERVO IMPENDING FAILURE DRIVE CALIBRATION RETRY COUNT" + }, + { + 0x5D, 0x50, + SenseDevTypes062, + "SPINDLE IMPENDING FAILURE GENERAL HARD DRIVE FAILURE" + }, + { + 0x5D, 0x51, + SenseDevTypes062, + "SPINDLE IMPENDING FAILURE DRIVE ERROR RATE TOO HIGH" + }, + { + 0x5D, 0x52, + SenseDevTypes062, + "SPINDLE IMPENDING FAILURE DATA ERROR RATE TOO HIGH" + }, + { + 0x5D, 0x53, + SenseDevTypes062, + "SPINDLE IMPENDING FAILURE SEEK ERROR RATE TOO HIGH" + }, + { + 0x5D, 0x54, + SenseDevTypes062, + "SPINDLE IMPENDING FAILURE TOO MANY BLOCK REASSIGNS" + }, + { + 0x5D, 0x55, + SenseDevTypes062, + "SPINDLE IMPENDING FAILURE ACCESS TIMES TOO HIGH" + }, + { + 0x5D, 0x56, + SenseDevTypes062, + "SPINDLE IMPENDING FAILURE START UNIT TIMES TOO HIGH" + }, + { + 0x5D, 0x57, + SenseDevTypes062, + "SPINDLE IMPENDING FAILURE CHANNEL PARAMETRICS" + }, + { + 0x5D, 0x58, + SenseDevTypes062, + "SPINDLE IMPENDING FAILURE CONTROLLER DETECTED" + }, + { + 0x5D, 0x59, + SenseDevTypes062, + "SPINDLE IMPENDING FAILURE THROUGHPUT PERFORMANCE" + }, + { + 0x5D, 0x5A, + SenseDevTypes062, + "SPINDLE IMPENDING FAILURE SEEK TIME PERFORMANCE" + }, + { + 0x5D, 0x5B, + SenseDevTypes062, + "SPINDLE IMPENDING FAILURE SPIN-UP RETRY COUNT" + }, + { + 0x5D, 0x5C, + SenseDevTypes062, + "SPINDLE IMPENDING FAILURE DRIVE CALIBRATION RETRY COUNT" + }, + { + 0x5D, 0x60, + SenseDevTypes062, + "FIRMWARE IMPENDING FAILURE GENERAL HARD DRIVE FAILURE" + }, + { + 0x5D, 0x61, + SenseDevTypes062, + "FIRMWARE IMPENDING FAILURE DRIVE ERROR RATE TOO HIGH" + }, + { + 0x5D, 0x62, + SenseDevTypes062, + "FIRMWARE IMPENDING FAILURE DATA ERROR RATE TOO HIGH" + }, + { + 0x5D, 0x63, + SenseDevTypes062, + "FIRMWARE IMPENDING FAILURE SEEK ERROR RATE TOO HIGH" + }, + { + 0x5D, 0x64, + SenseDevTypes062, + "FIRMWARE IMPENDING FAILURE TOO MANY BLOCK REASSIGNS" + }, + { + 0x5D, 0x65, + SenseDevTypes062, + "FIRMWARE IMPENDING FAILURE ACCESS TIMES TOO HIGH" + }, + { + 0x5D, 0x66, + SenseDevTypes062, + "FIRMWARE IMPENDING FAILURE START UNIT TIMES TOO HIGH" + }, + { + 0x5D, 0x67, + SenseDevTypes062, + "FIRMWARE IMPENDING FAILURE CHANNEL PARAMETRICS" + }, + { + 0x5D, 0x68, + SenseDevTypes062, + "FIRMWARE IMPENDING FAILURE CONTROLLER DETECTED" + }, + { + 0x5D, 0x69, + SenseDevTypes062, + "FIRMWARE IMPENDING FAILURE THROUGHPUT PERFORMANCE" + }, + { + 0x5D, 0x6A, + SenseDevTypes062, + "FIRMWARE IMPENDING FAILURE SEEK TIME PERFORMANCE" + }, + { + 0x5D, 0x6B, + SenseDevTypes062, + "FIRMWARE IMPENDING FAILURE SPIN-UP RETRY COUNT" + }, + { + 0x5D, 0x6C, + SenseDevTypes062, + "FIRMWARE IMPENDING FAILURE DRIVE CALIBRATION RETRY COUNT" + }, + { + 0x5D, 0xFF, + SenseDevTypes001, + "FAILURE PREDICTION THRESHOLD EXCEEDED (FALSE)" + }, + { + 0x5E, 0x00, + SenseDevTypes044, + "LOW POWER CONDITION ON" + }, + { + 0x5E, 0x01, + SenseDevTypes044, + "IDLE CONDITION ACTIVATED BY TIMER" + }, + { + 0x5E, 0x02, + SenseDevTypes044, + "STANDBY CONDITION ACTIVATED BY TIMER" + }, + { + 0x5E, 0x03, + SenseDevTypes044, + "IDLE CONDITION ACTIVATED BY COMMAND" + }, + { + 0x5E, 0x04, + SenseDevTypes044, + "STANDBY CONDITION ACTIVATED BY COMMAND" + }, + { + 0x5E, 0x41, + SenseDevTypes043, + "POWER STATE CHANGE TO ACTIVE" + }, + { + 0x5E, 0x42, + SenseDevTypes043, + "POWER STATE CHANGE TO IDLE" + }, + { + 0x5E, 0x43, + SenseDevTypes043, + "POWER STATE CHANGE TO STANDBY" + }, + { + 0x5E, 0x45, + SenseDevTypes043, + "POWER STATE CHANGE TO SLEEP" + }, + { + 0x5E, 0x47, + SenseDevTypes063, + "POWER STATE CHANGE TO DEVICE CONTROL" + }, + { + 0x60, 0x00, + SenseDevTypes042, + "LAMP FAILURE" + }, + { + 0x61, 0x00, + SenseDevTypes042, + "VIDEO ACQUISITION ERROR" + }, + { + 0x61, 0x01, + SenseDevTypes042, + "UNABLE TO ACQUIRE VIDEO" + }, + { + 0x61, 0x02, + SenseDevTypes042, + "OUT OF FOCUS" + }, + { + 0x62, 0x00, + SenseDevTypes042, + "SCAN HEAD POSITIONING ERROR" + }, + { + 0x63, 0x00, + SenseDevTypes005, + "END OF USER AREA ENCOUNTERED ON THIS TRACK" + }, + { + 0x63, 0x01, + SenseDevTypes005, + "PACKET DOES NOT FIT IN AVAILABLE SPACE" + }, + { + 0x64, 0x00, + SenseDevTypes005, + "ILLEGAL MODE FOR THIS TRACK" + }, + { + 0x64, 0x01, + SenseDevTypes005, + "INVALID PACKET SIZE" + }, + { + 0x65, 0x00, + SenseDevTypes001, + "VOLTAGE FAULT" + }, + { + 0x66, 0x00, + SenseDevTypes042, + "AUTOMATIC DOCUMENT FEEDER COVER UP" + }, + { + 0x66, 0x01, + SenseDevTypes042, + "AUTOMATIC DOCUMENT FEEDER LIFT UP" + }, + { + 0x66, 0x02, + SenseDevTypes042, + "DOCUMENT JAM IN AUTOMATIC DOCUMENT FEEDER" + }, + { + 0x66, 0x03, + SenseDevTypes042, + "DOCUMENT MISS FEED AUTOMATIC IN DOCUMENT FEEDER" + }, + { + 0x67, 0x00, + SenseDevTypes064, + "CONFIGURATION FAILURE" + }, + { + 0x67, 0x01, + SenseDevTypes064, + "CONFIGURATION OF INCAPABLE LOGICAL UNITS FAILED" + }, + { + 0x67, 0x02, + SenseDevTypes064, + "ADD LOGICAL UNIT FAILED" + }, + { + 0x67, 0x03, + SenseDevTypes064, + "MODIFICATION OF LOGICAL UNIT FAILED" + }, + { + 0x67, 0x04, + SenseDevTypes064, + "EXCHANGE OF LOGICAL UNIT FAILED" + }, + { + 0x67, 0x05, + SenseDevTypes064, + "REMOVE OF LOGICAL UNIT FAILED" + }, + { + 0x67, 0x06, + SenseDevTypes064, + "ATTACHMENT OF LOGICAL UNIT FAILED" + }, + { + 0x67, 0x07, + SenseDevTypes064, + "CREATION OF LOGICAL UNIT FAILED" + }, + { + 0x67, 0x08, + SenseDevTypes064, + "ASSIGN FAILURE OCCURRED" + }, + { + 0x67, 0x09, + SenseDevTypes064, + "MULTIPLY ASSIGNED LOGICAL UNIT" + }, + { + 0x68, 0x00, + SenseDevTypes064, + "LOGICAL UNIT NOT CONFIGURED" + }, + { + 0x69, 0x00, + SenseDevTypes064, + "DATA LOSS ON LOGICAL UNIT" + }, + { + 0x69, 0x01, + SenseDevTypes064, + "MULTIPLE LOGICAL UNIT FAILURES" + }, + { + 0x69, 0x02, + SenseDevTypes064, + "PARITY/DATA MISMATCH" + }, + { + 0x6A, 0x00, + SenseDevTypes064, + "INFORMATIONAL, REFER TO LOG" + }, + { + 0x6B, 0x00, + SenseDevTypes064, + "STATE CHANGE HAS OCCURRED" + }, + { + 0x6B, 0x01, + SenseDevTypes064, + "REDUNDANCY LEVEL GOT BETTER" + }, + { + 0x6B, 0x02, + SenseDevTypes064, + "REDUNDANCY LEVEL GOT WORSE" + }, + { + 0x6C, 0x00, + SenseDevTypes064, + "REBUILD FAILURE OCCURRED" + }, + { + 0x6D, 0x00, + SenseDevTypes064, + "RECALCULATE FAILURE OCCURRED" + }, + { + 0x6E, 0x00, + SenseDevTypes064, + "COMMAND TO LOGICAL UNIT FAILED" + }, + { + 0x6F, 0x00, + SenseDevTypes005, + "COPY PROTECTION KEY EXCHANGE FAILURE - AUTHENTICATION FAILURE" + }, + { + 0x6F, 0x01, + SenseDevTypes005, + "COPY PROTECTION KEY EXCHANGE FAILURE - KEY NOT PRESENT" + }, + { + 0x6F, 0x02, + SenseDevTypes005, + "COPY PROTECTION KEY EXCHANGE FAILURE - KEY NOT ESTABLISHED" + }, + { + 0x6F, 0x03, + SenseDevTypes005, + "READ OF SCRAMBLED SECTOR WITHOUT AUTHENTICATION" + }, + { + 0x6F, 0x04, + SenseDevTypes005, + "MEDIA REGION CODE IS MISMATCHED TO LOGICAL UNIT REGION" + }, + { + 0x6F, 0x05, + SenseDevTypes005, + "DRIVE REGION MUST BE PERMANENT/REGION RESET COUNT ERROR" + }, + { + 0x70, 0xFF, + SenseDevTypes002, + "DECOMPRESSION EXCEPTION SHORT ALGORITHM ID OF NN" + }, + { + 0x71, 0x00, + SenseDevTypes002, + "DECOMPRESSION EXCEPTION LONG ALGORITHM ID" + }, + { + 0x72, 0x00, + SenseDevTypes005, + "SESSION FIXATION ERROR" + }, + { + 0x72, 0x01, + SenseDevTypes005, + "SESSION FIXATION ERROR WRITING LEAD-IN" + }, + { + 0x72, 0x02, + SenseDevTypes005, + "SESSION FIXATION ERROR WRITING LEAD-OUT" + }, + { + 0x72, 0x03, + SenseDevTypes005, + "SESSION FIXATION ERROR - INCOMPLETE TRACK IN SESSION" + }, + { + 0x72, 0x04, + SenseDevTypes005, + "EMPTY OR PARTIALLY WRITTEN RESERVED TRACK" + }, + { + 0x72, 0x05, + SenseDevTypes005, + "NO MORE TRACK RESERVATIONS ALLOWED" + }, + { + 0x73, 0x00, + SenseDevTypes005, + "CD CONTROL ERROR" + }, + { + 0x73, 0x01, + SenseDevTypes005, + "POWER CALIBRATION AREA ALMOST FULL" + }, + { + 0x73, 0x02, + SenseDevTypes005, + "POWER CALIBRATION AREA IS FULL" + }, + { + 0x73, 0x03, + SenseDevTypes005, + "POWER CALIBRATION AREA ERROR" + }, + { + 0x73, 0x04, + SenseDevTypes005, + "PROGRAM MEMORY AREA UPDATE FAILURE" + }, + { + 0x73, 0x05, + SenseDevTypes005, + "PROGRAM MEMORY AREA IS FULL" + }, + { + 0x73, 0x06, + SenseDevTypes005, + "RMA/PMA IS FULL" + }, +}; + +static int ASCQ_TableSize = 463; + + +#endif diff -u --recursive --new-file v2.4.6/linux/drivers/message/fusion/ascq_tbl.sh linux/drivers/message/fusion/ascq_tbl.sh --- v2.4.6/linux/drivers/message/fusion/ascq_tbl.sh Wed Dec 31 16:00:00 1969 +++ linux/drivers/message/fusion/ascq_tbl.sh Fri Jul 6 17:03:11 2001 @@ -0,0 +1,109 @@ +#!/bin/sh +# +# ascq_tbl.sh - Translate SCSI t10.org's "asc-num.txt" file of +# SCSI Additional Sense Code & Qualifiers (ASC/ASCQ's) +# into something useful in C, creating "ascq_tbl.c" file. +# +#*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*# + +PREF_INFILE="t10.org/asc-num.txt" # From SCSI t10.org +PREF_OUTFILE="ascq_tbl.c" + +#*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*# + +xlate_ascq() { + cat | awk ' + BEGIN { + DQ = "\042"; + OUTFILE = "'"${PREF_OUTFILE}"'"; + TRUE = 1; + FALSE = 0; + #debug = TRUE; + + # read and discard all lines up to and including the one that begins + # with the "magic token" of "------- -------------- ---"... + headers_gone = FALSE; + while (!headers_gone) { + if (getline <= 0) + exit 1; + header_line[++hdrs] = $0; + if (debug) + printf("header_line[%d] = :%s:\n", ++hdrs, $0); + if ($0 ~ /^------- -------------- ---/) { + headers_gone = TRUE; + } + } + outcount = 0; + } + + (NF > 1) { + ++outcount; + if (debug) + printf( "DBG: %s\n", $0 ); + ASC[outcount] = substr($0,1,2); + ASCQ[outcount] = substr($0,5,2); + devtypes = substr($0,10,14); + gsub(/ /, ".", devtypes); + DESCRIP[outcount] = substr($0,26); + + if (!(devtypes in DevTypesVoodoo)) { + DevTypesVoodoo[devtypes] = ++voodoo; + DevTypesIdx[voodoo] = devtypes; + } + DEVTYPES[outcount] = DevTypesVoodoo[devtypes]; + + # Handle 0xNN exception stuff... + if (ASCQ[outcount] == "NN" || ASCQ[outcount] == "nn") + ASCQ[outcount] = "FF"; + } + + END { + printf("#ifndef SCSI_ASCQ_TBL_C_INCLUDED\n") > OUTFILE; + printf("#define SCSI_ASCQ_TBL_C_INCLUDED\n") >> OUTFILE; + + printf("\n/* AuToMaGiCaLlY generated from: %s'"${FIN}"'%s\n", DQ, DQ) >> OUTFILE; + printf(" *******************************************************************************\n") >> OUTFILE; + for (i=1; i<=hdrs; i++) { + printf(" * %s\n", header_line[i]) >> OUTFILE; + } + printf(" */\n") >> OUTFILE; + + printf("\n") >> OUTFILE; + for (i=1; i<=voodoo; i++) { + printf("static char SenseDevTypes%03d[] = %s%s%s;\n", i, DQ, DevTypesIdx[i], DQ) >> OUTFILE; + } + + printf("\nstatic ASCQ_Table_t ASCQ_Table[] = {\n") >> OUTFILE; + for (i=1; i<=outcount; i++) { + printf(" {\n") >> OUTFILE; + printf(" 0x%s, 0x%s,\n", ASC[i], ASCQ[i]) >> OUTFILE; + printf(" SenseDevTypes%03d,\n", DEVTYPES[i]) >> OUTFILE; + printf(" %s%s%s\n", DQ, DESCRIP[i], DQ) >> OUTFILE; + printf(" },\n") >> OUTFILE; + } + printf( "};\n\n" ) >> OUTFILE; + + printf( "static int ASCQ_TableSize = %d;\n\n", outcount ) >> OUTFILE; + printf( "Total of %d ASC/ASCQ records generated\n", outcount ); + printf("\n#endif\n") >> OUTFILE; + close(OUTFILE); + }' + return +} + +#*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*# + +# main() +if [ $# -lt 1 ]; then + echo "INFO: No input filename supplied - using: $PREF_INFILE" >&2 + FIN=$PREF_INFILE +else + FIN="$1" + if [ "$FIN" != "$PREF_INFILE" ]; then + echo "INFO: Ok, I'll try chewing on '$FIN' for SCSI ASC/ASCQ combos..." >&2 + fi + shift +fi + +cat $FIN | xlate_ascq +exit 0 diff -u --recursive --new-file v2.4.6/linux/drivers/message/fusion/isense.c linux/drivers/message/fusion/isense.c --- v2.4.6/linux/drivers/message/fusion/isense.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/message/fusion/isense.c Fri Jul 6 17:03:11 2001 @@ -0,0 +1,122 @@ +/* + * linux/drivers/message/fusion/isense.c + * Little linux driver / shim that interfaces with the Fusion MPT + * Linux base driver to provide english readable strings in SCSI + * Error Report logging output. This module implements SCSI-3 + * Opcode lookup and a sorted table of SCSI-3 ASC/ASCQ strings. + * + * Copyright (c) 1991-2001 Steven J. Ralston + * Written By: Steven J. Ralston + * (yes I wrote some of the orig. code back in 1991!) + * (mailto:Steve.Ralston@lsil.com) + * + * $Id: isense.c,v 1.28 2001/01/14 23:11:09 sralston Exp $ + */ +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + 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; version 2 of the License. + + 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. + + NO WARRANTY + THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR + CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT + LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, + MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is + solely responsible for determining the appropriateness of using and + distributing the Program and assumes all risks associated with its + exercise of rights under this Agreement, including but not limited to + the risks and costs of program errors, damage to or loss of data, + programs or equipment, and unavailability or interruption of operations. + + DISCLAIMER OF LIABILITY + NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), 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 OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED + HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/init.h> +#include <linux/version.h> + +/* Hmmm, avoid undefined spinlock_t on lk-2.2.14-5.0 */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0) +#include <asm/spinlock.h> +#endif + +#define MODULEAUTHOR "Steven J. Ralston" +#define COPYRIGHT "Copyright (c) 2000 " MODULEAUTHOR +#include "mptbase.h" + +#include "isense.h" + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * Private data... + */ + +/* + * YIKES! I don't usually #include C source files, but.. + * The following #include's pulls in our needed ASCQ_Table[] array, + * ASCQ_TableSz integer, and ScsiOpcodeString[] array! + */ +#include "ascq_tbl.c" +#include "scsiops.c" + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +#define my_NAME "SCSI-3 Opcodes & ASC/ASCQ Strings" +#define my_VERSION MPT_LINUX_VERSION_COMMON +#define MYNAM "isense" + +EXPORT_NO_SYMBOLS; +MODULE_AUTHOR(MODULEAUTHOR); +MODULE_DESCRIPTION(my_NAME); + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +int __init isense_init(void) +{ + show_mptmod_ver(my_NAME, my_VERSION); + + /* + * Install our handler + */ + if (mpt_register_ascqops_strings(&ASCQ_Table[0], ASCQ_TableSize, ScsiOpcodeString) != 1) + { + printk(KERN_ERR MYNAM ": ERROR: Can't register with Fusion MPT base driver!\n"); + return -EBUSY; + } + printk(KERN_INFO MYNAM ": Registered SCSI-3 Opcodes & ASC/ASCQ Strings\n"); + return 0; +} + + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +static void isense_exit(void) +{ +#ifdef MODULE + mpt_deregister_ascqops_strings(); +#endif + printk(KERN_INFO MYNAM ": Deregistered SCSI-3 Opcodes & ASC/ASCQ Strings\n"); +} + +module_init(isense_init); +module_exit(isense_exit); + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + diff -u --recursive --new-file v2.4.6/linux/drivers/message/fusion/isense.h linux/drivers/message/fusion/isense.h --- v2.4.6/linux/drivers/message/fusion/isense.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/message/fusion/isense.h Fri Jul 6 17:03:11 2001 @@ -0,0 +1,95 @@ +#ifndef ISENSE_H_INCLUDED +#define ISENSE_H_INCLUDED +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + +#ifdef __KERNEL__ +#include <linux/types.h> /* needed for u8, etc. */ +#include <linux/string.h> /* needed for strcat */ +#include <linux/kernel.h> /* needed for sprintf */ +#else + #ifndef U_STUFF_DEFINED + #define U_STUFF_DEFINED + typedef unsigned char u8; + typedef unsigned short u16; + typedef unsigned int u32; + #endif +#endif + +#include "scsi3.h" /* needed for all things SCSI */ + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * Defines and typedefs... + */ + +#ifdef __KERNEL__ +#define PrintF(x) printk x +#else +#define PrintF(x) printf x +#endif + +#ifndef TRUE +#define TRUE 1 +#define FALSE 0 +#endif + +#define RETRY_STATUS ((int) 1) +#define PUT_STATUS ((int) 0) + +/* + * A generic structure to hold info about IO request that caused + * a Request Sense to be performed, and the resulting Sense Data. + */ +typedef struct IO_Info +{ + char *DevIDStr; /* String of chars which identifies the device. */ + u8 *cdbPtr; /* Pointer (Virtual/Logical addr) to CDB bytes of + IO request that caused ContAllegianceCond. */ + u8 *sensePtr; /* Pointer (Virtual/Logical addr) to Sense Data + returned by Request Sense operation. */ + u8 *dataPtr; /* Pointer (Virtual/Logical addr) to Data buffer + of IO request caused ContAllegianceCondition. */ + u8 *inqPtr; /* Pointer (Virtual/Logical addr) to Inquiry Data for + IO *Device* that caused ContAllegianceCondition. */ + u8 SCSIStatus; /* SCSI status byte of IO request that caused + Contingent Allegiance Condition. */ + u8 DoDisplay; /* Shall we display any messages? */ + u16 rsvd_align1; + u32 ComplCode; /* Four-byte OS-dependent completion code. */ + u32 NotifyL; /* Four-byte OS-dependent notification field. */ +} IO_Info_t; + +/* + * SCSI Additional Sense Code and Additional Sense Code Qualifier table. + */ +typedef struct ASCQ_Table +{ + u8 ASC; + u8 ASCQ; + char *DevTypes; + char *Description; +} ASCQ_Table_t; + +#if 0 +/* + * SCSI Opcodes table. + */ +typedef struct SCSI_OPS_Table +{ + u8 OpCode; + char *DevTypes; + char *ScsiCmndStr; +} SCSI_OPS_Table_t; +#endif + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * Public entry point prototypes + */ + +/* in scsiherr.c, needed by mptscsih.c */ +extern int mpt_ScsiHost_ErrorReport(IO_Info_t *ioop); + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +#endif + diff -u --recursive --new-file v2.4.6/linux/drivers/message/fusion/linux_compat.h linux/drivers/message/fusion/linux_compat.h --- v2.4.6/linux/drivers/message/fusion/linux_compat.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/message/fusion/linux_compat.h Fri Jul 6 17:03:11 2001 @@ -0,0 +1,199 @@ +/* drivers/message/fusion/linux_compat.h */ + +#ifndef FUSION_LINUX_COMPAT_H +#define FUSION_LINUX_COMPAT_H +/*{-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + +#include <linux/version.h> +#include <linux/config.h> +#include <linux/kernel.h> +#include <linux/pci.h> + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0) +# if LINUX_VERSION_CODE < KERNEL_VERSION(2,2,18) + typedef unsigned int dma_addr_t; +# endif +#else +# if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,42) + typedef unsigned int dma_addr_t; +# endif +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,2,18) +/*{-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + +/* This block snipped from lk-2.2.18/include/linux/init.h { */ +/* + * Used for initialization calls.. + */ +typedef int (*initcall_t)(void); +typedef void (*exitcall_t)(void); + +#define __init_call __attribute__ ((unused,__section__ (".initcall.init"))) +#define __exit_call __attribute__ ((unused,__section__ (".exitcall.exit"))) + +extern initcall_t __initcall_start, __initcall_end; + +#define __initcall(fn) \ + static initcall_t __initcall_##fn __init_call = fn +#define __exitcall(fn) \ + static exitcall_t __exitcall_##fn __exit_call = fn + +#ifdef MODULE +/* These macros create a dummy inline: gcc 2.9x does not count alias + as usage, hence the `unused function' warning when __init functions + are declared static. We use the dummy __*_module_inline functions + both to kill the warning and check the type of the init/cleanup + function. */ +typedef int (*__init_module_func_t)(void); +typedef void (*__cleanup_module_func_t)(void); +#define module_init(x) \ + int init_module(void) __attribute__((alias(#x))); \ + extern inline __init_module_func_t __init_module_inline(void) \ + { return x; } +#define module_exit(x) \ + void cleanup_module(void) __attribute__((alias(#x))); \ + extern inline __cleanup_module_func_t __cleanup_module_inline(void) \ + { return x; } + +#else +#define module_init(x) __initcall(x); +#define module_exit(x) __exitcall(x); +#endif +/* } block snipped from lk-2.2.18/include/linux/init.h */ + +/* Wait queues. */ +#define DECLARE_WAIT_QUEUE_HEAD(name) \ + struct wait_queue * (name) = NULL +#define DECLARE_WAITQUEUE(name, task) \ + struct wait_queue (name) = { (task), NULL } + +#if defined(__sparc__) && defined(__sparc_v9__) +/* The sparc64 ioremap implementation is wrong in 2.2.x, + * but fixing it would break all of the drivers which + * workaround it. Fixed in 2.3.x onward. -DaveM + */ +#define ARCH_IOREMAP(base) ((unsigned long) (base)) +#else +#define ARCH_IOREMAP(base) ioremap(base) +#endif + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +#else /* LINUX_VERSION_CODE must be >= KERNEL_VERSION(2,2,18) */ + +/* No ioremap bugs in >2.3.x kernels. */ +#define ARCH_IOREMAP(base) ioremap(base) + +/*}-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2,2,18) */ + + +/* PCI/driver subsystem { */ +#ifndef pci_for_each_dev +#define pci_for_each_dev(dev) for((dev)=pci_devices; (dev)!=NULL; (dev)=(dev)->next) +#define pci_peek_next_dev(dev) ((dev)->next ? (dev)->next : NULL) +#define DEVICE_COUNT_RESOURCE 6 +#define PCI_BASEADDR_FLAGS(idx) base_address[idx] +#define PCI_BASEADDR_START(idx) base_address[idx] & ~0xFUL +/* + * We have to keep track of the original value using + * a temporary, and not by just sticking pdev->base_address[x] + * back. pdev->base_address[x] is an opaque cookie that can + * be used by the PCI implementation on a given Linux port + * for any purpose. -DaveM + */ +#define PCI_BASEADDR_SIZE(__pdev, __idx) \ +({ unsigned int size, tmp; \ + pci_read_config_dword(__pdev, PCI_BASE_ADDRESS_0 + (4*(__idx)), &tmp); \ + pci_write_config_dword(__pdev, PCI_BASE_ADDRESS_0 + (4*(__idx)), 0xffffffff); \ + pci_read_config_dword(__pdev, PCI_BASE_ADDRESS_0 + (4*(__idx)), &size); \ + pci_write_config_dword(__pdev, PCI_BASE_ADDRESS_0 + (4*(__idx)), tmp); \ + (4 - size); \ +}) +#else +#define pci_peek_next_dev(dev) ((dev) != pci_dev_g(&pci_devices) ? pci_dev_g((dev)->global_list.next) : NULL) +#define PCI_BASEADDR_FLAGS(idx) resource[idx].flags +#define PCI_BASEADDR_START(idx) resource[idx].start +#define PCI_BASEADDR_SIZE(dev,idx) (dev)->resource[idx].end - (dev)->resource[idx].start + 1 +#endif /* } ifndef pci_for_each_dev */ + + +/* procfs compat stuff... */ +#ifdef CONFIG_PROC_FS +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,28) +#define CREATE_PROCDIR_ENTRY(x,y) create_proc_entry(x, S_IFDIR, y) +/* This is a macro so we don't need to pull all the procfs + * headers into this file. -DaveM + */ +#define create_proc_read_entry(name, mode, base, __read_proc, __data) \ +({ struct proc_dir_entry *__res=create_proc_entry(name,mode,base); \ + if (__res) { \ + __res->read_proc=(__read_proc); \ + __res->data=(__data); \ + } \ + __res; \ +}) +#else +#define CREATE_PROCDIR_ENTRY(x,y) proc_mkdir(x, y) +#endif +#endif + +/* Compatability for the 2.3.x PCI DMA API. */ +#ifndef PCI_DMA_BIDIRECTIONAL +/*{-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + +#define PCI_DMA_BIDIRECTIONAL 0 +#define PCI_DMA_TODEVICE 1 +#define PCI_DMA_FROMDEVICE 2 +#define PCI_DMA_NONE 3 + +#ifdef __KERNEL__ +#include <asm/page.h> +/* Pure 2^n version of get_order */ +static __inline__ int __get_order(unsigned long size) +{ + int order; + + size = (size-1) >> (PAGE_SHIFT-1); + order = -1; + do { + size >>= 1; + order++; + } while (size); + return order; +} +#endif + +#define pci_alloc_consistent(hwdev, size, dma_handle) \ +({ void *__ret = (void *)__get_free_pages(GFP_ATOMIC, __get_order(size)); \ + if (__ret != NULL) { \ + memset(__ret, 0, size); \ + *(dma_handle) = virt_to_bus(__ret); \ + } \ + __ret; \ +}) + +#define pci_free_consistent(hwdev, size, vaddr, dma_handle) \ + free_pages((unsigned long)vaddr, __get_order(size)) + +#define pci_map_single(hwdev, ptr, size, direction) \ + virt_to_bus(ptr); + +#define pci_unmap_single(hwdev, dma_addr, size, direction) \ + do { /* Nothing to do */ } while (0) + +#define pci_map_sg(hwdev, sg, nents, direction) (nents) +#define pci_unmap_sg(hwdev, sg, nents, direction) \ + do { /* Nothing to do */ } while(0) + +#define sg_dma_address(sg) (virt_to_bus((sg)->address)) +#define sg_dma_len(sg) ((sg)->length) + +/*}-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +#endif /* PCI_DMA_BIDIRECTIONAL */ + +/*}-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +#endif /* _LINUX_COMPAT_H */ + diff -u --recursive --new-file v2.4.6/linux/drivers/message/fusion/lsi/fc_log.h linux/drivers/message/fusion/lsi/fc_log.h --- v2.4.6/linux/drivers/message/fusion/lsi/fc_log.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/message/fusion/lsi/fc_log.h Fri Jul 6 17:03:11 2001 @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2000-2001 LSI Logic Corporation. All rights reserved. + * + * NAME: fc_log.h + * SUMMARY: MPI IocLogInfo definitions for the SYMFC9xx chips + * DESCRIPTION: Contains the enumerated list of values that may be returned + * in the IOCLogInfo field of a MPI Default Reply Message. + * + * CREATION DATE: 6/02/2000 + * ID: $Id: fc_log.h,v 4.2 2001/03/01 18:28:59 fibre Exp $ + */ + + +/* + * MpiIocLogInfo_t enum + * + * These 32 bit values are used in the IOCLogInfo field of the MPI reply + * messages. + * The value is 0xabcccccc where + * a = The type of log info as per the MPI spec. Since these codes are + * all for Fibre Channel this value will always be 2. + * b = Specifies a subclass of the firmware where + * 0 = FCP Initiator + * 1 = FCP Target + * 2 = LAN + * 3 = MPI Message Layer + * 4 = FC Link + * 5 = Context Manager + * 6 = Invalid Field Offset + * 7 = State Change Info + * all others are reserved for future use + * c = A specific value within the subclass. + * + * NOTE: Any new values should be added to the end of each subclass so that the + * codes remain consistent across firmware releases. + */ +typedef enum _MpiIocLogInfoFc +{ + MPI_IOCLOGINFO_FC_INIT_BASE = 0x20000000, + MPI_IOCLOGINFO_FC_INIT_ERROR_OUT_OF_ORDER_FRAME = 0x20000001, /* received an out of order frame - unsupported */ + MPI_IOCLOGINFO_FC_INIT_ERROR_BAD_START_OF_FRAME = 0x20000002, /* bad start of frame primative */ + MPI_IOCLOGINFO_FC_INIT_ERROR_BAD_END_OF_FRAME = 0x20000003, /* bad end of frame primative */ + MPI_IOCLOGINFO_FC_INIT_ERROR_OVER_RUN = 0x20000004, /* Receiver hardware detected overrun */ + MPI_IOCLOGINFO_FC_INIT_ERROR_RX_OTHER = 0x20000005, /* Other errors caught by IOC which require retries */ + MPI_IOCLOGINFO_FC_INIT_ERROR_SUBPROC_DEAD = 0x20000006, /* Main processor could not initialize sub-processor */ + + MPI_IOCLOGINFO_FC_TARGET_BASE = 0x21000000, + MPI_IOCLOGINFO_FC_TARGET_NO_PDISC = 0x21000001, /* not sent because we are waiting for a PDISC from the initiator */ + MPI_IOCLOGINFO_FC_TARGET_NO_LOGIN = 0x21000002, /* not sent because we are not logged in to the remote node */ + MPI_IOCLOGINFO_FC_TARGET_DOAR_KILLED_BY_LIP = 0x21000003, /* Data Out, Auto Response, not sent due to a LIP */ + MPI_IOCLOGINFO_FC_TARGET_DIAR_KILLED_BY_LIP = 0x21000004, /* Data In, Auto Response, not sent due to a LIP */ + MPI_IOCLOGINFO_FC_TARGET_DIAR_MISSING_DATA = 0x21000005, /* Data In, Auto Response, missing data frames */ + MPI_IOCLOGINFO_FC_TARGET_DONR_KILLED_BY_LIP = 0x21000006, /* Data Out, No Response, not sent due to a LIP */ + MPI_IOCLOGINFO_FC_TARGET_WRSP_KILLED_BY_LIP = 0x21000007, /* Auto-response after a write not sent due to a LIP */ + MPI_IOCLOGINFO_FC_TARGET_DINR_KILLED_BY_LIP = 0x21000008, /* Data In, No Response, not completed due to a LIP */ + MPI_IOCLOGINFO_FC_TARGET_DINR_MISSING_DATA = 0x21000009, /* Data In, No Response, missing data frames */ + MPI_IOCLOGINFO_FC_TARGET_MRSP_KILLED_BY_LIP = 0x2100000a, /* Manual Response not sent due to a LIP */ + MPI_IOCLOGINFO_FC_TARGET_NO_CLASS_3 = 0x2100000b, /* not sent because remote node does not support Class 3 */ + MPI_IOCLOGINFO_FC_TARGET_LOGIN_NOT_VALID = 0x2100000c, /* not sent because login to remote node not validated */ + MPI_IOCLOGINFO_FC_TARGET_FROM_OUTBOUND = 0x2100000e, /* cleared from the outbound after a logout */ + MPI_IOCLOGINFO_FC_TARGET_WAITING_FOR_DATA_IN = 0x2100000f, /* cleared waiting for data after a logout */ + + MPI_IOCLOGINFO_FC_LAN_BASE = 0x22000000, + MPI_IOCLOGINFO_FC_LAN_TRANS_SGL_MISSING = 0x22000001, /* Transaction Context Sgl Missing */ + MPI_IOCLOGINFO_FC_LAN_TRANS_WRONG_PLACE = 0x22000002, /* Transaction Context found before an EOB */ + MPI_IOCLOGINFO_FC_LAN_TRANS_RES_BITS_SET = 0x22000003, /* Transaction Context value has reserved bits set */ + MPI_IOCLOGINFO_FC_LAN_WRONG_SGL_FLAG = 0x22000004, /* Invalid SGL Flags */ + + MPI_IOCLOGINFO_FC_MSG_BASE = 0x23000000, + + MPI_IOCLOGINFO_FC_LINK_BASE = 0x24000000, + MPI_IOCLOGINFO_FC_LINK_LOOP_INIT_TIMEOUT = 0x24000001, /* Loop initialization timed out */ + MPI_IOCLOGINFO_FC_LINK_ALREADY_INITIALIZED = 0x24000002, /* Another system controller already initialized the loop */ + MPI_IOCLOGINFO_FC_LINK_LINK_NOT_ESTABLISHED = 0x24000003, /* Not synchronized to signal or still negotiating (possible cable problem) */ + + MPI_IOCLOGINFO_FC_CTX_BASE = 0x25000000, + + MPI_IOCLOGINFO_FC_INVALID_FIELD_BYTE_OFFSET = 0x26000000, /* The lower 24 bits give the byte offset of the field in the request message that is invalid. */ + MPI_IOCLOGINFO_FC_INVALID_FIELD_MAX_OFFSET = 0x26ffffff, + + MPI_IOCLOGINFO_FC_STATE_CHANGE = 0x27000000 /* The lower 24 bits give additional information concerning state change */ + +} MpiIocLogInfoFc_t; diff -u --recursive --new-file v2.4.6/linux/drivers/message/fusion/lsi/mpi.h linux/drivers/message/fusion/lsi/mpi.h --- v2.4.6/linux/drivers/message/fusion/lsi/mpi.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/message/fusion/lsi/mpi.h Fri Jul 6 17:03:11 2001 @@ -0,0 +1,643 @@ +/* + * Copyright (c) 2000-2001 LSI Logic Corporation. + * + * + * Name: MPI.H + * Title: MPI Message independent structures and definitions + * Creation Date: July 27, 2000 + * + * MPI Version: 01.01.06 + * + * Version History + * --------------- + * + * Date Version Description + * -------- -------- ------------------------------------------------------ + * 05-08-00 00.10.01 Original release for 0.10 spec dated 4/26/2000. + * 05-24-00 00.10.02 Added MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH definition. + * 06-06-00 01.00.01 Update MPI_VERSION_MAJOR and MPI_VERSION_MINOR. + * 06-22-00 01.00.02 Added MPI_IOCSTATUS_LAN_ definitions. + * Removed LAN_SUSPEND function definition. + * Added MPI_MSGFLAGS_CONTINUATION_REPLY definition. + * 06-30-00 01.00.03 Added MPI_CONTEXT_REPLY_TYPE_LAN definition. + * Added MPI_GET/SET_CONTEXT_REPLY_TYPE macros. + * 07-27-00 01.00.04 Added MPI_FAULT_ definitions. + * Removed MPI_IOCSTATUS_MSG/DATA_XFER_ERROR definitions. + * Added MPI_IOCSTATUS_INTERNAL_ERROR definition. + * Added MPI_IOCSTATUS_TARGET_XFER_COUNT_MISMATCH. + * 11-02-00 01.01.01 Original release for post 1.0 work. + * 12-04-00 01.01.02 Added new function codes. + * 01-09-01 01.01.03 Added more definitions to the system interface section + * Added MPI_IOCSTATUS_TARGET_STS_DATA_NOT_SENT. + * 01-25-01 01.01.04 Changed MPI_VERSION_MINOR from 0x00 to 0x01. + * 02-20-01 01.01.05 Started using MPI_POINTER. + * Fixed value for MPI_DIAG_RW_ENABLE. + * Added defines for MPI_DIAG_PREVENT_IOC_BOOT and + * MPI_DIAG_CLEAR_FLASH_BAD_SIG. + * Obsoleted MPI_IOCSTATUS_TARGET_FC_ defines. + * 02-27-01 01.01.06 Removed MPI_HOST_INDEX_REGISTER define. + * Added function codes for RAID. + * -------------------------------------------------------------------------- + */ + +#ifndef MPI_H +#define MPI_H + + +/***************************************************************************** +* +* M P I V e r s i o n D e f i n i t i o n s +* +*****************************************************************************/ + +#define MPI_VERSION_MAJOR (0x01) +#define MPI_VERSION_MINOR (0x01) +#define MPI_VERSION ((MPI_VERSION_MAJOR << 8) | MPI_VERSION_MINOR) + +/* Note: The major versions of 0xe0 through 0xff are reserved */ + +/***************************************************************************** +* +* I O C S t a t e D e f i n i t i o n s +* +*****************************************************************************/ + +#define MPI_IOC_STATE_RESET (0x00000000) +#define MPI_IOC_STATE_READY (0x10000000) +#define MPI_IOC_STATE_OPERATIONAL (0x20000000) +#define MPI_IOC_STATE_FAULT (0x40000000) + +#define MPI_IOC_STATE_MASK (0xF0000000) +#define MPI_IOC_STATE_SHIFT (28) + +/* Fault state codes (product independent range 0x8000-0xFFFF) */ + +#define MPI_FAULT_REQUEST_MESSAGE_PCI_PARITY_ERROR (0x8111) +#define MPI_FAULT_REQUEST_MESSAGE_PCI_BUS_FAULT (0x8112) +#define MPI_FAULT_REPLY_MESSAGE_PCI_PARITY_ERROR (0x8113) +#define MPI_FAULT_REPLY_MESSAGE_PCI_BUS_FAULT (0x8114) +#define MPI_FAULT_DATA_SEND_PCI_PARITY_ERROR (0x8115) +#define MPI_FAULT_DATA_SEND_PCI_BUS_FAULT (0x8116) +#define MPI_FAULT_DATA_RECEIVE_PCI_PARITY_ERROR (0x8117) +#define MPI_FAULT_DATA_RECEIVE_PCI_BUS_FAULT (0x8118) + + +/***************************************************************************** +* +* P C I S y s t e m I n t e r f a c e R e g i s t e r s +* +*****************************************************************************/ + +/* S y s t e m D o o r b e l l */ +#define MPI_DOORBELL_OFFSET (0x00000000) +#define MPI_DOORBELL_ACTIVE (0x08000000) +#define MPI_DOORBELL_ACTIVE_SHIFT (27) +#define MPI_DOORBELL_WHO_INIT_MASK (0x07000000) +#define MPI_DOORBELL_WHO_INIT_SHIFT (24) +#define MPI_DOORBELL_FUNCTION_MASK (0xFF000000) +#define MPI_DOORBELL_FUNCTION_SHIFT (24) +#define MPI_DOORBELL_ADD_DWORDS_MASK (0x00FF0000) +#define MPI_DOORBELL_ADD_DWORDS_SHIFT (16) +#define MPI_DOORBELL_DATA_MASK (0x0000FFFF) + + +#define MPI_WRITE_SEQUENCE_OFFSET (0x00000004) +#define MPI_WRSEQ_KEY_VALUE_MASK (0x0000000F) +#define MPI_WRSEQ_1ST_KEY_VALUE (0x04) +#define MPI_WRSEQ_2ND_KEY_VALUE (0x0B) +#define MPI_WRSEQ_3RD_KEY_VALUE (0x02) +#define MPI_WRSEQ_4TH_KEY_VALUE (0x07) +#define MPI_WRSEQ_5TH_KEY_VALUE (0x0D) + +#define MPI_DIAGNOSTIC_OFFSET (0x00000008) +#define MPI_DIAG_CLEAR_FLASH_BAD_SIG (0x00000400) +#define MPI_DIAG_PREVENT_IOC_BOOT (0x00000200) +#define MPI_DIAG_DRWE (0x00000080) +#define MPI_DIAG_FLASH_BAD_SIG (0x00000040) +#define MPI_DIAG_RESET_HISTORY (0x00000020) +#define MPI_DIAG_RW_ENABLE (0x00000010) +#define MPI_DIAG_RESET_ADAPTER (0x00000004) +#define MPI_DIAG_DISABLE_ARM (0x00000002) +#define MPI_DIAG_MEM_ENABLE (0x00000001) + +#define MPI_TEST_BASE_ADDRESS_OFFSET (0x0000000C) + +#define MPI_DIAG_RW_DATA_OFFSET (0x00000010) + +#define MPI_DIAG_RW_ADDRESS_OFFSET (0x00000014) + +#define MPI_HOST_INTERRUPT_STATUS_OFFSET (0x00000030) +#define MPI_HIS_IOP_DOORBELL_STATUS (0x80000000) +#define MPI_HIS_REPLY_MESSAGE_INTERRUPT (0x00000008) +#define MPI_HIS_DOORBELL_INTERRUPT (0x00000001) + +#define MPI_HOST_INTERRUPT_MASK_OFFSET (0x00000034) +#define MPI_HIM_RIM (0x00000008) +#define MPI_HIM_DIM (0x00000001) + +#define MPI_REQUEST_QUEUE_OFFSET (0x00000040) +#define MPI_REQUEST_POST_FIFO_OFFSET (0x00000040) + +#define MPI_REPLY_QUEUE_OFFSET (0x00000044) +#define MPI_REPLY_POST_FIFO_OFFSET (0x00000044) +#define MPI_REPLY_FREE_FIFO_OFFSET (0x00000044) + + + +/***************************************************************************** +* +* M e s s a g e F r a m e D e s c r i p t o r s +* +*****************************************************************************/ + +#define MPI_REQ_MF_DESCRIPTOR_NB_MASK (0x00000003) +#define MPI_REQ_MF_DESCRIPTOR_F_BIT (0x00000004) +#define MPI_REQ_MF_DESCRIPTOR_ADDRESS_MASK (0xFFFFFFF8) + +#define MPI_ADDRESS_REPLY_A_BIT (0x80000000) +#define MPI_ADDRESS_REPLY_ADDRESS_MASK (0x7FFFFFFF) + +#define MPI_CONTEXT_REPLY_A_BIT (0x80000000) +#define MPI_CONTEXT_REPLY_TYPE_MASK (0x60000000) +#define MPI_CONTEXT_REPLY_TYPE_SCSI_INIT (0x00) +#define MPI_CONTEXT_REPLY_TYPE_SCSI_TARGET (0x01) +#define MPI_CONTEXT_REPLY_TYPE_LAN (0x02) +#define MPI_CONTEXT_REPLY_TYPE_SHIFT (29) +#define MPI_CONTEXT_REPLY_CONTEXT_MASK (0x1FFFFFFF) + + +/****************************************************************************/ +/* Context Reply macros */ +/****************************************************************************/ + +#define MPI_GET_CONTEXT_REPLY_TYPE(x) (((x) & MPI_CONTEXT_REPLY_TYPE_MASK) \ + >> MPI_CONTEXT_REPLY_TYPE_SHIFT) + +#define MPI_SET_CONTEXT_REPLY_TYPE(x, typ) \ + ((x) = ((x) & ~MPI_CONTEXT_REPLY_TYPE_MASK) | \ + (((typ) << MPI_CONTEXT_REPLY_TYPE_SHIFT) & \ + MPI_CONTEXT_REPLY_TYPE_MASK)) + + +/***************************************************************************** +* +* M e s s a g e F u n c t i o n s +* 0x80 -> 0x8F reserved for private message use per product +* +* +*****************************************************************************/ + +#define MPI_FUNCTION_SCSI_IO_REQUEST (0x00) +#define MPI_FUNCTION_SCSI_TASK_MGMT (0x01) +#define MPI_FUNCTION_IOC_INIT (0x02) +#define MPI_FUNCTION_IOC_FACTS (0x03) +#define MPI_FUNCTION_CONFIG (0x04) +#define MPI_FUNCTION_PORT_FACTS (0x05) +#define MPI_FUNCTION_PORT_ENABLE (0x06) +#define MPI_FUNCTION_EVENT_NOTIFICATION (0x07) +#define MPI_FUNCTION_EVENT_ACK (0x08) +#define MPI_FUNCTION_FW_DOWNLOAD (0x09) +#define MPI_FUNCTION_TARGET_CMD_BUFFER_POST (0x0A) +#define MPI_FUNCTION_TARGET_ASSIST (0x0B) +#define MPI_FUNCTION_TARGET_STATUS_SEND (0x0C) +#define MPI_FUNCTION_TARGET_MODE_ABORT (0x0D) +#define MPI_FUNCTION_TARGET_FC_BUF_POST_LINK_SRVC (0x0E) /* obsolete name */ +#define MPI_FUNCTION_TARGET_FC_RSP_LINK_SRVC (0x0F) /* obsolete name */ +#define MPI_FUNCTION_TARGET_FC_EX_SEND_LINK_SRVC (0x10) /* obsolete name */ +#define MPI_FUNCTION_TARGET_FC_ABORT (0x11) /* obsolete name */ +#define MPI_FUNCTION_FC_LINK_SRVC_BUF_POST (0x0E) +#define MPI_FUNCTION_FC_LINK_SRVC_RSP (0x0F) +#define MPI_FUNCTION_FC_EX_LINK_SRVC_SEND (0x10) +#define MPI_FUNCTION_FC_ABORT (0x11) +#define MPI_FUNCTION_FW_UPLOAD (0x12) +#define MPI_FUNCTION_FC_COMMON_TRANSPORT_SEND (0x13) +#define MPI_FUNCTION_FC_PRIMITIVE_SEND (0x14) + +#define MPI_FUNCTION_RAID_VOLUME (0x15) +#define MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH (0x16) + +#define MPI_FUNCTION_LAN_SEND (0x20) +#define MPI_FUNCTION_LAN_RECEIVE (0x21) +#define MPI_FUNCTION_LAN_RESET (0x22) + +#define MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET (0x40) +#define MPI_FUNCTION_IO_UNIT_RESET (0x41) +#define MPI_FUNCTION_HANDSHAKE (0x42) +#define MPI_FUNCTION_REPLY_FRAME_REMOVAL (0x43) + + + +/***************************************************************************** +* +* S c a t t e r G a t h e r E l e m e n t s +* +*****************************************************************************/ + +/****************************************************************************/ +/* Simple element structures */ +/****************************************************************************/ + +typedef struct _SGE_SIMPLE32 +{ + U32 FlagsLength; + U32 Address; +} SGE_SIMPLE32, MPI_POINTER PTR_SGE_SIMPLE32, + SGESimple32_t, MPI_POINTER pSGESimple32_t; + +typedef struct _SGE_SIMPLE64 +{ + U32 FlagsLength; + U64 Address; +} SGE_SIMPLE64, MPI_POINTER PTR_SGE_SIMPLE64, + SGESimple64_t, MPI_POINTER pSGESimple64_t; + +typedef struct _SGE_SIMPLE_UNION +{ + U32 FlagsLength; + union + { + U32 Address32; + U64 Address64; + }u; +} SGESimpleUnion_t, MPI_POINTER pSGESimpleUnion_t, + SGE_SIMPLE_UNION, MPI_POINTER PTR_SGE_SIMPLE_UNION; + +/****************************************************************************/ +/* Chain element structures */ +/****************************************************************************/ + +typedef struct _SGE_CHAIN32 +{ + U16 Length; + U8 NextChainOffset; + U8 Flags; + U32 Address; +} SGE_CHAIN32, MPI_POINTER PTR_SGE_CHAIN32, + SGEChain32_t, MPI_POINTER pSGEChain32_t; + +typedef struct _SGE_CHAIN64 +{ + U16 Length; + U8 NextChainOffset; + U8 Flags; + U64 Address; +} SGE_CHAIN64, MPI_POINTER PTR_SGE_CHAIN64, + SGEChain64_t, MPI_POINTER pSGEChain64_t; + +typedef struct _SGE_CHAIN_UNION +{ + U16 Length; + U8 NextChainOffset; + U8 Flags; + union + { + U32 Address32; + U64 Address64; + }u; +} SGE_CHAIN_UNION, MPI_POINTER PTR_SGE_CHAIN_UNION, + SGEChainUnion_t, MPI_POINTER pSGEChainUnion_t; + +/****************************************************************************/ +/* Transaction Context element */ +/****************************************************************************/ + +typedef struct _SGE_TRANSACTION32 +{ + U8 Reserved; + U8 ContextSize; + U8 DetailsLength; + U8 Flags; + U32 TransactionContext[1]; + U32 TransactionDetails[1]; +} SGE_TRANSACTION32, MPI_POINTER PTR_SGE_TRANSACTION32, + SGETransaction32_t, MPI_POINTER pSGETransaction32_t; + +typedef struct _SGE_TRANSACTION64 +{ + U8 Reserved; + U8 ContextSize; + U8 DetailsLength; + U8 Flags; + U32 TransactionContext[2]; + U32 TransactionDetails[1]; +} SGE_TRANSACTION64, MPI_POINTER PTR_SGE_TRANSACTION64, + SGETransaction64_t, MPI_POINTER pSGETransaction64_t; + +typedef struct _SGE_TRANSACTION96 +{ + U8 Reserved; + U8 ContextSize; + U8 DetailsLength; + U8 Flags; + U32 TransactionContext[3]; + U32 TransactionDetails[1]; +} SGE_TRANSACTION96, MPI_POINTER PTR_SGE_TRANSACTION96, + SGETransaction96_t, MPI_POINTER pSGETransaction96_t; + +typedef struct _SGE_TRANSACTION128 +{ + U8 Reserved; + U8 ContextSize; + U8 DetailsLength; + U8 Flags; + U32 TransactionContext[4]; + U32 TransactionDetails[1]; +} SGE_TRANSACTION128, MPI_POINTER PTR_SGE_TRANSACTION128, + SGETransaction_t128, MPI_POINTER pSGETransaction_t128; + +typedef struct _SGE_TRANSACTION_UNION +{ + U8 Reserved; + U8 ContextSize; + U8 DetailsLength; + U8 Flags; + union + { + U32 TransactionContext32[1]; + U32 TransactionContext64[2]; + U32 TransactionContext96[3]; + U32 TransactionContext128[4]; + }u; + U32 TransactionDetails[1]; +} SGE_TRANSACTION_UNION, MPI_POINTER PTR_SGE_TRANSACTION_UNION, + SGETransactionUnion_t, MPI_POINTER pSGETransactionUnion_t; + + +/****************************************************************************/ +/* SGE IO types union for IO SGL's */ +/****************************************************************************/ + +typedef struct _SGE_IO_UNION +{ + union + { + SGE_SIMPLE_UNION Simple; + SGE_CHAIN_UNION Chain; + } u; +} SGE_IO_UNION, MPI_POINTER PTR_SGE_IO_UNION, + SGEIOUnion_t, MPI_POINTER pSGEIOUnion_t; + +/****************************************************************************/ +/* SGE union for SGL's with Simple and Transaction elements */ +/****************************************************************************/ + +typedef struct _SGE_TRANS_SIMPLE_UNION +{ + union + { + SGE_SIMPLE_UNION Simple; + SGE_TRANSACTION_UNION Transaction; + } u; +} SGE_TRANS_SIMPLE_UNION, MPI_POINTER PTR_SGE_TRANS_SIMPLE_UNION, + SGETransSimpleUnion_t, MPI_POINTER pSGETransSimpleUnion_t; + +/****************************************************************************/ +/* All SGE types union */ +/****************************************************************************/ + +typedef struct _SGE_MPI_UNION +{ + union + { + SGE_SIMPLE_UNION Simple; + SGE_CHAIN_UNION Chain; + SGE_TRANSACTION_UNION Transaction; + } u; +} SGE_MPI_UNION, MPI_POINTER PTR_SGE_MPI_UNION, + MPI_SGE_UNION_t, MPI_POINTER pMPI_SGE_UNION_t, + SGEAllUnion_t, MPI_POINTER pSGEAllUnion_t; + + +/****************************************************************************/ +/* SGE field definition and masks */ +/****************************************************************************/ + +/* Flags field bit definitions */ + +#define MPI_SGE_FLAGS_LAST_ELEMENT (0x80) +#define MPI_SGE_FLAGS_END_OF_BUFFER (0x40) +#define MPI_SGE_FLAGS_ELEMENT_TYPE_MASK (0x30) +#define MPI_SGE_FLAGS_LOCAL_ADDRESS (0x08) +#define MPI_SGE_FLAGS_DIRECTION (0x04) +#define MPI_SGE_FLAGS_ADDRESS_SIZE (0x02) +#define MPI_SGE_FLAGS_END_OF_LIST (0x01) + +#define MPI_SGE_FLAGS_SHIFT (24) + +#define MPI_SGE_LENGTH_MASK (0x00FFFFFF) +#define MPI_SGE_CHAIN_LENGTH_MASK (0x0000FFFF) + +/* Element Type */ + +#define MPI_SGE_FLAGS_TRANSACTION_ELEMENT (0x00) +#define MPI_SGE_FLAGS_SIMPLE_ELEMENT (0x10) +#define MPI_SGE_FLAGS_CHAIN_ELEMENT (0x30) +#define MPI_SGE_FLAGS_ELEMENT_MASK (0x30) + +/* Address location */ + +#define MPI_SGE_FLAGS_SYSTEM_ADDRESS (0x00) + +/* Direction */ + +#define MPI_SGE_FLAGS_IOC_TO_HOST (0x00) +#define MPI_SGE_FLAGS_HOST_TO_IOC (0x04) + +/* Address Size */ + +#define MPI_SGE_FLAGS_32_BIT_ADDRESSING (0x00) +#define MPI_SGE_FLAGS_64_BIT_ADDRESSING (0x02) + +/* Context Size */ + +#define MPI_SGE_FLAGS_32_BIT_CONTEXT (0x00) +#define MPI_SGE_FLAGS_64_BIT_CONTEXT (0x02) +#define MPI_SGE_FLAGS_96_BIT_CONTEXT (0x04) +#define MPI_SGE_FLAGS_128_BIT_CONTEXT (0x06) + +#define MPI_SGE_CHAIN_OFFSET_MASK (0x00FF0000) +#define MPI_SGE_CHAIN_OFFSET_SHIFT (16) + + +/****************************************************************************/ +/* SGE operation Macros */ +/****************************************************************************/ + + /* SIMPLE FlagsLength manipulations... */ +#define MPI_SGE_SET_FLAGS(f) ((U32)(f) << MPI_SGE_FLAGS_SHIFT) +#define MPI_SGE_GET_FLAGS(fl) (((fl) & ~MPI_SGE_LENGTH_MASK) >> MPI_SGE_FLAGS_SHIFT) +#define MPI_SGE_LENGTH(fl) ((fl) & MPI_SGE_LENGTH_MASK) +#define MPI_SGE_CHAIN_LENGTH(fl) ((fl) & MPI_SGE_CHAIN_LENGTH_MASK) + +#define MPI_SGE_SET_FLAGS_LENGTH(f,l) (MPI_SGE_SET_FLAGS(f) | MPI_SGE_LENGTH(l)) + +#define MPI_pSGE_GET_FLAGS(psg) MPI_SGE_GET_FLAGS((psg)->FlagsLength) +#define MPI_pSGE_GET_LENGTH(psg) MPI_SGE_LENGTH((psg)->FlagsLength) +#define MPI_pSGE_SET_FLAGS_LENGTH(psg,f,l) (psg)->FlagsLength = MPI_SGE_SET_FLAGS_LENGTH(f,l) + /* CAUTION - The following are READ-MODIFY-WRITE! */ +#define MPI_pSGE_SET_FLAGS(psg,f) (psg)->FlagsLength |= MPI_SGE_SET_FLAGS(f) +#define MPI_pSGE_SET_LENGTH(psg,l) (psg)->FlagsLength |= MPI_SGE_LENGTH(l) + +#define MPI_GET_CHAIN_OFFSET(x) ((x&MPI_SGE_CHAIN_OFFSET_MASK)>>MPI_SGE_CHAIN_OFFSET_SHIFT) + + + +/***************************************************************************** +* +* S t a n d a r d M e s s a g e S t r u c t u r e s +* +*****************************************************************************/ + +/****************************************************************************/ +/* Standard message request header for all request messages */ +/****************************************************************************/ + +typedef struct _MSG_REQUEST_HEADER +{ + U8 Reserved[2]; /* function specific */ + U8 ChainOffset; + U8 Function; + U8 Reserved1[3]; /* function specific */ + U8 MsgFlags; + U32 MsgContext; +} MSG_REQUEST_HEADER, MPI_POINTER PTR_MSG_REQUEST_HEADER, + MPIHeader_t, MPI_POINTER pMPIHeader_t; + + +/****************************************************************************/ +/* Default Reply */ +/****************************************************************************/ + +typedef struct _MSG_DEFAULT_REPLY +{ + U8 Reserved[2]; /* function specific */ + U8 MsgLength; + U8 Function; + U8 Reserved1[3]; /* function specific */ + U8 MsgFlags; + U32 MsgContext; + U8 Reserved2[2]; /* function specific */ + U16 IOCStatus; + U32 IOCLogInfo; +} MSG_DEFAULT_REPLY, MPI_POINTER PTR_MSG_DEFAULT_REPLY, + MPIDefaultReply_t, MPI_POINTER pMPIDefaultReply_t; + + +/* MsgFlags definition for all replies */ + +#define MPI_MSGFLAGS_CONTINUATION_REPLY (0x80) + + +/***************************************************************************** +* +* I O C S t a t u s V a l u e s +* +*****************************************************************************/ + +/****************************************************************************/ +/* Common IOCStatus values for all replies */ +/****************************************************************************/ + +#define MPI_IOCSTATUS_SUCCESS (0x0000) +#define MPI_IOCSTATUS_INVALID_FUNCTION (0x0001) +#define MPI_IOCSTATUS_BUSY (0x0002) +#define MPI_IOCSTATUS_INVALID_SGL (0x0003) +#define MPI_IOCSTATUS_INTERNAL_ERROR (0x0004) +#define MPI_IOCSTATUS_RESERVED (0x0005) +#define MPI_IOCSTATUS_INSUFFICIENT_RESOURCES (0x0006) +#define MPI_IOCSTATUS_INVALID_FIELD (0x0007) +#define MPI_IOCSTATUS_INVALID_STATE (0x0008) + +/****************************************************************************/ +/* Config IOCStatus values */ +/****************************************************************************/ + +#define MPI_IOCSTATUS_CONFIG_INVALID_ACTION (0x0020) +#define MPI_IOCSTATUS_CONFIG_INVALID_TYPE (0x0021) +#define MPI_IOCSTATUS_CONFIG_INVALID_PAGE (0x0022) +#define MPI_IOCSTATUS_CONFIG_INVALID_DATA (0x0023) +#define MPI_IOCSTATUS_CONFIG_NO_DEFAULTS (0x0024) +#define MPI_IOCSTATUS_CONFIG_CANT_COMMIT (0x0025) + +/****************************************************************************/ +/* SCSIIO Reply (SPI & FCP) initiator values */ +/****************************************************************************/ + +#define MPI_IOCSTATUS_SCSI_RECOVERED_ERROR (0x0040) +#define MPI_IOCSTATUS_SCSI_INVALID_BUS (0x0041) +#define MPI_IOCSTATUS_SCSI_INVALID_TARGETID (0x0042) +#define MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE (0x0043) +#define MPI_IOCSTATUS_SCSI_DATA_OVERRUN (0x0044) +#define MPI_IOCSTATUS_SCSI_DATA_UNDERRUN (0x0045) +#define MPI_IOCSTATUS_SCSI_IO_DATA_ERROR (0x0046) +#define MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR (0x0047) +#define MPI_IOCSTATUS_SCSI_TASK_TERMINATED (0x0048) +#define MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH (0x0049) +#define MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED (0x004A) +#define MPI_IOCSTATUS_SCSI_IOC_TERMINATED (0x004B) +#define MPI_IOCSTATUS_SCSI_EXT_TERMINATED (0x004C) + +/****************************************************************************/ +/* SCSI (SPI & FCP) target values */ +/****************************************************************************/ + +#define MPI_IOCSTATUS_TARGET_PRIORITY_IO (0x0060) +#define MPI_IOCSTATUS_TARGET_INVALID_PORT (0x0061) +#define MPI_IOCSTATUS_TARGET_INVALID_IOCINDEX (0x0062) +#define MPI_IOCSTATUS_TARGET_ABORTED (0x0063) +#define MPI_IOCSTATUS_TARGET_NO_CONN_RETRYABLE (0x0064) +#define MPI_IOCSTATUS_TARGET_NO_CONNECTION (0x0065) +#define MPI_IOCSTATUS_TARGET_XFER_COUNT_MISMATCH (0x006A) +#define MPI_IOCSTATUS_TARGET_STS_DATA_NOT_SENT (0x006B) + +/****************************************************************************/ +/* Additional FCP target values */ +/****************************************************************************/ + +#define MPI_IOCSTATUS_TARGET_FC_ABORTED (0x0066) /* obsolete */ +#define MPI_IOCSTATUS_TARGET_FC_RX_ID_INVALID (0x0067) /* obsolete */ +#define MPI_IOCSTATUS_TARGET_FC_DID_INVALID (0x0068) /* obsolete */ +#define MPI_IOCSTATUS_TARGET_FC_NODE_LOGGED_OUT (0x0069) /* obsolete */ + +/****************************************************************************/ +/* Fibre Channel Direct Access values */ +/****************************************************************************/ + +#define MPI_IOCSTATUS_FC_ABORTED (0x0066) +#define MPI_IOCSTATUS_FC_RX_ID_INVALID (0x0067) +#define MPI_IOCSTATUS_FC_DID_INVALID (0x0068) +#define MPI_IOCSTATUS_FC_NODE_LOGGED_OUT (0x0069) + +/****************************************************************************/ +/* LAN values */ +/****************************************************************************/ + +#define MPI_IOCSTATUS_LAN_DEVICE_NOT_FOUND (0x0080) +#define MPI_IOCSTATUS_LAN_DEVICE_FAILURE (0x0081) +#define MPI_IOCSTATUS_LAN_TRANSMIT_ERROR (0x0082) +#define MPI_IOCSTATUS_LAN_TRANSMIT_ABORTED (0x0083) +#define MPI_IOCSTATUS_LAN_RECEIVE_ERROR (0x0084) +#define MPI_IOCSTATUS_LAN_RECEIVE_ABORTED (0x0085) +#define MPI_IOCSTATUS_LAN_PARTIAL_PACKET (0x0086) +#define MPI_IOCSTATUS_LAN_CANCELED (0x0087) + + +/****************************************************************************/ +/* IOCStatus flag to indicate that log info is available */ +/****************************************************************************/ + +#define MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE (0x8000) +#define MPI_IOCSTATUS_MASK (0x7FFF) + +/****************************************************************************/ +/* LogInfo Types */ +/****************************************************************************/ + +#define MPI_IOCLOGINFO_TYPE_MASK (0xF0000000) +#define MPI_IOCLOGINFO_TYPE_NONE (0x00) +#define MPI_IOCLOGINFO_TYPE_SCSI (0x01) +#define MPI_IOCLOGINFO_TYPE_FC (0x02) +#define MPI_IOCLOGINFO_LOG_DATA_MASK (0x0FFFFFFF) + + +#endif diff -u --recursive --new-file v2.4.6/linux/drivers/message/fusion/lsi/mpi_cnfg.h linux/drivers/message/fusion/lsi/mpi_cnfg.h --- v2.4.6/linux/drivers/message/fusion/lsi/mpi_cnfg.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/message/fusion/lsi/mpi_cnfg.h Fri Jul 6 17:03:11 2001 @@ -0,0 +1,971 @@ +/* + * Copyright (c) 2000-2001 LSI Logic Corporation. + * + * + * Name: MPI_CNFG.H + * Title: MPI Config message, structures, and Pages + * Creation Date: July 27, 2000 + * + * MPI Version: 01.01.09 + * + * Version History + * --------------- + * + * Date Version Description + * -------- -------- ------------------------------------------------------ + * 05-08-00 00.10.01 Original release for 0.10 spec dated 4/26/2000. + * 06-06-00 01.00.01 Update version number for 1.0 release. + * 06-08-00 01.00.02 Added _PAGEVERSION definitions for all pages. + * Added FcPhLowestVersion, FcPhHighestVersion, Reserved2 + * fields to FC_DEVICE_0 page, updated the page version. + * Changed _FREE_RUNNING_CLOCK to _PACING_TRANSFERS in + * SCSI_PORT_0, SCSI_DEVICE_0 and SCSI_DEVICE_1 pages + * and updated the page versions. + * Added _RESPONSE_ID_MASK definition to SCSI_PORT_1 + * page and updated the page version. + * Added Information field and _INFO_PARAMS_NEGOTIATED + * definitionto SCSI_DEVICE_0 page. + * 06-22-00 01.00.03 Removed batch controls from LAN_0 page and updated the + * page version. + * Added BucketsRemaining to LAN_1 page, redefined the + * state values, and updated the page version. + * Revised bus width definitions in SCSI_PORT_0, + * SCSI_DEVICE_0 and SCSI_DEVICE_1 pages. + * 06-30-00 01.00.04 Added MaxReplySize to LAN_1 page and updated the page + * version. + * Moved FC_DEVICE_0 PageAddress description to spec. + * 07-27-00 01.00.05 Corrected the SubsystemVendorID and SubsystemID field + * widths in IOC_0 page and updated the page version. + * 11-02-00 01.01.01 Original release for post 1.0 work + * Added Manufacturing pages, IO Unit Page 2, SCSI SPI + * Port Page 2, FC Port Page 4, FC Port Page 5 + * 11-15-00 01.01.02 Interim changes to match proposals + * 12-04-00 01.01.03 Config page changes to match MPI rev 1.00.01. + * 12-05-00 01.01.04 Modified config page actions. + * 01-09-01 01.01.05 Added defines for page address formats. + * Data size for Manufacturing pages 2 and 3 no longer + * defined here. + * Io Unit Page 2 size is fixed at 4 adapters and some + * flags were changed. + * SCSI Port Page 2 Device Settings modified. + * New fields added to FC Port Page 0 and some flags + * cleaned up. + * Removed impedance flash from FC Port Page 1. + * Added FC Port pages 6 and 7. + * 01-25-01 01.01.06 Added MaxInitiators field to FcPortPage0. + * 01-29-01 01.01.07 Changed some defines to make them 32 character unique. + * Added some LinkType defines for FcPortPage0. + * 02-20-01 01.01.08 Started using MPI_POINTER. + * 02-27-01 01.01.09 Replaced MPI_CONFIG_PAGETYPE_SCSI_LUN with + * MPI_CONFIG_PAGETYPE_RAID_VOLUME. + * Added definitions and structures for IOC Page 2 and + * RAID Volume Page 2. + * -------------------------------------------------------------------------- + */ + +#ifndef MPI_CNFG_H +#define MPI_CNFG_H + + +/***************************************************************************** +* +* C o n f i g M e s s a g e a n d S t r u c t u r e s +* +*****************************************************************************/ + +typedef struct _CONFIG_PAGE_HEADER +{ + U8 PageVersion; + U8 PageLength; + U8 PageNumber; + U8 PageType; +} fCONFIG_PAGE_HEADER, MPI_POINTER PTR_CONFIG_PAGE_HEADER, + ConfigPageHeader_t, MPI_POINTER pConfigPageHeader_t; + +typedef union _CONFIG_PAGE_HEADER_UNION +{ + ConfigPageHeader_t Struct; + U8 Bytes[4]; + U16 Word16[2]; + U32 Word32; +} ConfigPageHeaderUnion, MPI_POINTER pConfigPageHeaderUnion, + fCONFIG_PAGE_HEADER_UNION, MPI_POINTER PTR_CONFIG_PAGE_HEADER_UNION; + + +/****************************************************************************/ +/* PageType field values */ +/****************************************************************************/ +#define MPI_CONFIG_PAGEATTR_READ_ONLY (0x00) +#define MPI_CONFIG_PAGEATTR_CHANGEABLE (0x10) +#define MPI_CONFIG_PAGEATTR_PERSISTENT (0x20) +#define MPI_CONFIG_PAGEATTR_MASK (0xF0) + +#define MPI_CONFIG_PAGETYPE_IO_UNIT (0x00) +#define MPI_CONFIG_PAGETYPE_IOC (0x01) +#define MPI_CONFIG_PAGETYPE_BIOS (0x02) +#define MPI_CONFIG_PAGETYPE_SCSI_PORT (0x03) +#define MPI_CONFIG_PAGETYPE_SCSI_DEVICE (0x04) +#define MPI_CONFIG_PAGETYPE_FC_PORT (0x05) +#define MPI_CONFIG_PAGETYPE_FC_DEVICE (0x06) +#define MPI_CONFIG_PAGETYPE_LAN (0x07) +#define MPI_CONFIG_PAGETYPE_RAID_VOLUME (0x08) +#define MPI_CONFIG_PAGETYPE_MANUFACTURING (0x09) +#define MPI_CONFIG_PAGETYPE_MASK (0x0F) + +#define MPI_CONFIG_TYPENUM_MASK (0x0FFF) + + +/**************************************************************************** + * PageAddres field values + ****************************************************************************/ +#define MPI_SCSI_PORT_PGAD_PORT_MASK (0x000000FF) + +#define MPI_SCSI_DEVICE_TARGET_ID_MASK (0x000000FF) +#define MPI_SCSI_DEVICE_TARGET_ID_SHIFT (0) +#define MPI_SCSI_DEVICE_BUS_MASK (0x0000FF00) +#define MPI_SCSI_DEVICE_BUS_SHIFT (8) + +#define MPI_SCSI_LUN_TARGET_ID_MASK (0x000000FF) +#define MPI_SCSI_LUN_TARGET_ID_SHIFT (0) +#define MPI_SCSI_LUN_BUS_MASK (0x0000FF00) +#define MPI_SCSI_LUN_BUS_SHIFT (8) +#define MPI_SCSI_LUN_LUN_MASK (0x00FF0000) +#define MPI_SCSI_LUN_LUN_SHIFT (16) + +#define MPI_FC_PORT_PGAD_PORT_MASK (0xF0000000) +#define MPI_FC_PORT_PGAD_PORT_SHIFT (28) +#define MPI_FC_PORT_PGAD_FORM_MASK (0x0F000000) +#define MPI_FC_PORT_PGAD_FORM_INDEX (0x01000000) +#define MPI_FC_PORT_PGAD_INDEX_MASK (0x0000FFFF) +#define MPI_FC_PORT_PGAD_INDEX_SHIFT (0) + +#define MPI_FC_DEVICE_PGAD_PORT_MASK (0xF0000000) +#define MPI_FC_DEVICE_PGAD_PORT_SHIFT (28) +#define MPI_FC_DEVICE_PGAD_FORM_MASK (0x0F000000) +#define MPI_FC_DEVICE_PGAD_FORM_NEXT_DID (0x00000000) +#define MPI_FC_DEVICE_PGAD_ND_PORT_MASK (0xF0000000) +#define MPI_FC_DEVICE_PGAD_ND_PORT_SHIFT (28) +#define MPI_FC_DEVICE_PGAD_ND_DID_MASK (0x00FFFFFF) +#define MPI_FC_DEVICE_PGAD_ND_DID_SHIFT (0) +#define MPI_FC_DEVICE_PGAD_FORM_BUS_TID (0x01000000) +#define MPI_FC_DEVICE_PGAD_BT_BUS_MASK (0x0000FF00) +#define MPI_FC_DEVICE_PGAD_BT_BUS_SHIFT (8) +#define MPI_FC_DEVICE_PGAD_BT_TID_MASK (0x000000FF) +#define MPI_FC_DEVICE_PGAD_BT_TID_SHIFT (0) + + +/****************************************************************************/ +/* Config Request Message */ +/****************************************************************************/ +typedef struct _MSG_CONFIG +{ + U8 Action; + U8 Reserved; + U8 ChainOffset; + U8 Function; + U8 Reserved1[3]; + U8 MsgFlags; + U32 MsgContext; + U8 Reserved2[8]; + fCONFIG_PAGE_HEADER Header; + U32 PageAddress; + SGE_IO_UNION PageBufferSGE; +} MSG_CONFIG, MPI_POINTER PTR_MSG_CONFIG, + Config_t, MPI_POINTER pConfig_t; + + +/****************************************************************************/ +/* Action field values */ +/****************************************************************************/ +#define MPI_CONFIG_ACTION_PAGE_HEADER (0x00) +/*#define MPI_CONFIG_ACTION_PAGE_READ (0x01) *//* obsolete */ +#define MPI_CONFIG_ACTION_PAGE_READ_CURRENT (0x01) +/*#define MPI_CONFIG_ACTION_PAGE_WRITE (0x02) *//* obsolete */ +#define MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT (0x02) +#define MPI_CONFIG_ACTION_PAGE_DEFAULT (0x03) +/*#define MPI_CONFIG_ACTION_PAGE_WRITE_COMMIT (0x04) */ /* obsolete */ +#define MPI_CONFIG_ACTION_PAGE_WRITE_NVRAM (0x04) +#define MPI_CONFIG_ACTION_PAGE_READ_DEFAULT (0x05) +#define MPI_CONFIG_ACTION_PAGE_READ_NVRAM (0x06) + + +/* Config Reply Message */ +typedef struct _MSG_CONFIG_REPLY +{ + U8 Action; + U8 Reserved; + U8 MsgLength; + U8 Function; + U8 Reserved1[3]; + U8 MsgFlags; + U32 MsgContext; + U8 Reserved2[2]; + U16 IOCStatus; + U32 IOCLogInfo; + fCONFIG_PAGE_HEADER Header; +} MSG_CONFIG_REPLY, MPI_POINTER PTR_MSG_CONFIG_REPLY, + ConfigReply_t, MPI_POINTER pConfigReply_t; + + + +/***************************************************************************** +* +* C o n f i g u r a t i o n P a g e s +* +*****************************************************************************/ + +/****************************************************************************/ +/* Manufacturing Config pages */ +/****************************************************************************/ +#define MPI_MANUFACTPAGE_DEVICEID_FC909 (0x0621) +#define MPI_MANUFACTPAGE_DEVICEID_FC919 (0x0624) +#define MPI_MANUFACTPAGE_DEVICEID_FC929 (0x0622) +#define MPI_MANUFACTPAGE_DEVID_53C1030 (0x0030) +#define MPI_MANUFACTPAGE_DEVID_53C1030ZC (0x0031) +#define MPI_MANUFACTPAGE_DEVID_53C1035 (0x0035) + +typedef struct _CONFIG_PAGE_MANUFACTURING_0 +{ + fCONFIG_PAGE_HEADER Header; + U8 ChipName[16]; + U8 ChipRevision[8]; + U8 BoardName[16]; + U8 BoardAssembly[16]; + U8 BoardTracerNumber[16]; + +} fCONFIG_PAGE_MANUFACTURING_0, MPI_POINTER PTR_CONFIG_PAGE_MANUFACTURING_0, + ManufacturingPage0_t, MPI_POINTER pManufacturingPage0_t; + +#define MPI_MANUFACTURING0_PAGEVERSION (0x00) + + +typedef struct _CONFIG_PAGE_MANUFACTURING_1 +{ + fCONFIG_PAGE_HEADER Header; + U8 VPD[256]; +} fCONFIG_PAGE_MANUFACTURING_1, MPI_POINTER PTR_CONFIG_PAGE_MANUFACTURING_1, + ManufacturingPage1_t, MPI_POINTER pManufacturingPage1_t; + +#define MPI_MANUFACTURING1_PAGEVERSION (0x00) + + +typedef struct _MPI_CHIP_REVISION_ID +{ + U16 DeviceID; + U8 PCIRevisionID; + U8 Reserved; +} MPI_CHIP_REVISION_ID, MPI_POINTER PTR_MPI_CHIP_REVISION_ID, + MpiChipRevisionId_t, MPI_POINTER pMpiChipRevisionId_t; + + +typedef struct _CONFIG_PAGE_MANUFACTURING_2 +{ + fCONFIG_PAGE_HEADER Header; + MPI_CHIP_REVISION_ID ChipId; + U32 HwSettings[1]; +} fCONFIG_PAGE_MANUFACTURING_2, MPI_POINTER PTR_CONFIG_PAGE_MANUFACTURING_2, + ManufacturingPage2_t, MPI_POINTER pManufacturingPage2_t; + +#define MPI_MANUFACTURING2_PAGEVERSION (0x00) + + +typedef struct _CONFIG_PAGE_MANUFACTURING_3 +{ + fCONFIG_PAGE_HEADER Header; + MPI_CHIP_REVISION_ID ChipId; + U32 Info[1]; +} fCONFIG_PAGE_MANUFACTURING_3, MPI_POINTER PTR_CONFIG_PAGE_MANUFACTURING_3, + ManufacturingPage3_t, MPI_POINTER pManufacturingPage3_t; + +#define MPI_MANUFACTURING3_PAGEVERSION (0x00) + + +/****************************************************************************/ +/* IO Unit Config Pages */ +/****************************************************************************/ + +typedef struct _CONFIG_PAGE_IO_UNIT_0 +{ + fCONFIG_PAGE_HEADER Header; + U64 UniqueValue; +} fCONFIG_PAGE_IO_UNIT_0, MPI_POINTER PTR_CONFIG_PAGE_IO_UNIT_0, + IOUnitPage0_t, MPI_POINTER pIOUnitPage0_t; + +#define MPI_IOUNITPAGE0_PAGEVERSION (0x00) + + +typedef struct _CONFIG_PAGE_IO_UNIT_1 +{ + fCONFIG_PAGE_HEADER Header; + U32 Flags; +} fCONFIG_PAGE_IO_UNIT_1, MPI_POINTER PTR_CONFIG_PAGE_IO_UNIT_1, + IOUnitPage1_t, MPI_POINTER pIOUnitPage1_t; + +#define MPI_IOUNITPAGE1_PAGEVERSION (0x00) + +#define MPI_IOUNITPAGE1_MULTI_FUNCTION (0x00000000) +#define MPI_IOUNITPAGE1_SINGLE_FUNCTION (0x00000001) +#define MPI_IOUNITPAGE1_MULTI_PATHING (0x00000002) +#define MPI_IOUNITPAGE1_SINGLE_PATHING (0x00000000) + +#define MPI_IOUNITPAGE1_FORCE_32 (0x00000080) + + +typedef struct _MPI_ADAPTER_INFO +{ + U8 PciBusNumber; + U8 PciDeviceAndFunctionNumber; + U16 AdapterFlags; +} MPI_ADAPTER_INFO, MPI_POINTER PTR_MPI_ADAPTER_INFO, + MpiAdapterInfo_t, MPI_POINTER pMpiAdapterInfo_t; + +#define MPI_ADAPTER_INFO_FLAGS_EMBEDDED (0x0001) +#define MPI_ADAPTER_INFO_FLAGS_INIT_STATUS (0x0002) + +typedef struct _CONFIG_PAGE_IO_UNIT_2 +{ + fCONFIG_PAGE_HEADER Header; + U32 Flags; + U32 BiosVersion; + MPI_ADAPTER_INFO AdapterOrder[4]; +} fCONFIG_PAGE_IO_UNIT_2, MPI_POINTER PTR_CONFIG_PAGE_IO_UNIT_2, + IOUnitPage2_t, MPI_POINTER pIOUnitPage2_t; + +#define MPI_IOUNITPAGE2_PAGEVERSION (0x00) + +#define MPI_IOUNITPAGE2_FLAGS_RAID_DISABLE (0x00000001) +#define MPI_IOUNITPAGE2_FLAGS_PAUSE_ON_ERROR (0x00000002) +#define MPI_IOUNITPAGE2_FLAGS_VERBOSE_ENABLE (0x00000004) +#define MPI_IOUNITPAGE2_FLAGS_COLOR_VIDEO_DISABLE (0x00000008) +#define MPI_IOUNITPAGE2_FLAGS_DONT_HOOK_INT_40 (0x00000010) + + +/****************************************************************************/ +/* IOC Config Pages */ +/****************************************************************************/ + +typedef struct _CONFIG_PAGE_IOC_0 +{ + fCONFIG_PAGE_HEADER Header; + U32 TotalNVStore; + U32 FreeNVStore; + U16 VendorID; + U16 DeviceID; + U8 RevisionID; + U8 Reserved[3]; + U32 ClassCode; + U16 SubsystemVendorID; + U16 SubsystemID; +} fCONFIG_PAGE_IOC_0, MPI_POINTER PTR_CONFIG_PAGE_IOC_0, + IOCPage0_t, MPI_POINTER pIOCPage0_t; + +#define MPI_IOCPAGE0_PAGEVERSION (0x01) + +typedef struct _CONFIG_PAGE_IOC_1 +{ + fCONFIG_PAGE_HEADER Header; + U32 Flags; + U32 CoalescingTimeout; + U8 CoalescingDepth; + U8 Reserved[3]; +} fCONFIG_PAGE_IOC_1, MPI_POINTER PTR_CONFIG_PAGE_IOC_1, + IOCPage1_t, MPI_POINTER pIOCPage1_t; + +#define MPI_IOCPAGE1_PAGEVERSION (0x00) + +#define MPI_IOCPAGE1_REPLY_COALESCING (0x00000001) + +typedef struct _CONFIG_PAGE_IOC_2_RAID_VOL +{ + U8 VolumeTargetID; + U8 VolumeBus; + U16 Reserved; + U8 VolumeVersionMinor; + U8 VolumeVersionMajor; + U8 VolumeRaidType; + U8 Reserved1; +} fCONFIG_PAGE_IOC_2_RAID_VOL, MPI_POINTER PTR_CONFIG_PAGE_IOC_2_RAID_VOL, + ConfigPageIoc2RaidVol_t, MPI_POINTER pConfigPageIoc2RaidVol_t; + +typedef struct _CONFIG_PAGE_IOC_2 +{ + fCONFIG_PAGE_HEADER Header; + U32 CapabilitiesFlags; + U8 NumActiveVolumes; + U8 MaxVolumes; + U16 Reserved; + fCONFIG_PAGE_IOC_2_RAID_VOL RaidVolume[1]; +} fCONFIG_PAGE_IOC_2, MPI_POINTER PTR_CONFIG_PAGE_IOC_2, + IOCPage2_t, MPI_POINTER pIOCPage2_t; + +#define MPI_IOCPAGE2_PAGEVERSION (0x00) + +/* IOC Page 2 Capabilities flags */ + +#define MPI_IOCPAGE2_CAP_FLAGS_RAID_0_SUPPORT (0x00000001) +#define MPI_IOCPAGE2_CAP_FLAGS_RAID_1_SUPPORT (0x00000002) +#define MPI_IOCPAGE2_CAP_FLAGS_LSI_MIRROR_SUPPORT (0x00000004) +#define MPI_IOCPAGE2_CAP_FLAGS_RAID_5_SUPPORT (0x00000008) +#define MPI_IOCPAGE2_CAP_FLAGS_RAID_10_SUPPORT (0x00000010) + +/* IOC Page 2 Volume RAID Type values */ + +#define MPI_IOCPAGE2_VOL_TYPE_RAID_0 (0x00) +#define MPI_IOCPAGE2_VOL_TYPE_RAID_1 (0x01) +#define MPI_IOCPAGE2_VOL_TYPE_LSI_MIRROR (0x02) +#define MPI_IOCPAGE2_VOL_TYPE_RAID_5 (0x05) +#define MPI_IOCPAGE2_VOL_TYPE_RAID_10 (0x0A) + + +/****************************************************************************/ +/* SCSI Port Config Pages */ +/****************************************************************************/ + +typedef struct _CONFIG_PAGE_SCSI_PORT_0 +{ + fCONFIG_PAGE_HEADER Header; + U32 Capabilities; + U32 PhysicalInterface; +} fCONFIG_PAGE_SCSI_PORT_0, MPI_POINTER PTR_CONFIG_PAGE_SCSI_PORT_0, + SCSIPortPage0_t, MPI_POINTER pSCSIPortPage0_t; + +#define MPI_SCSIPORTPAGE0_PAGEVERSION (0x01) + +#define MPI_SCSIPORTPAGE0_CAP_IU (0x00000001) +#define MPI_SCSIPORTPAGE0_CAP_DT (0x00000002) +#define MPI_SCSIPORTPAGE0_CAP_QAS (0x00000004) +#define MPI_SCSIPORTPAGE0_CAP_PACING_TRANSFERS (0x00000008) +#define MPI_SCSIPORTPAGE0_CAP_MIN_SYNC_PERIOD_MASK (0x0000FF00) +#define MPI_SCSIPORTPAGE0_CAP_MAX_SYNC_OFFSET_MASK (0x00FF0000) +#define MPI_SCSIPORTPAGE0_CAP_WIDE (0x20000000) +#define MPI_SCSIPORTPAGE0_CAP_AIP (0x80000000) + +#define MPI_SCSIPORTPAGE0_PHY_SIGNAL_TYPE_MASK (0x00000003) +#define MPI_SCSIPORTPAGE0_PHY_SIGNAL_HVD (0x01) +#define MPI_SCSIPORTPAGE0_PHY_SIGNAL_SE (0x02) +#define MPI_SCSIPORTPAGE0_PHY_SIGNAL_LVD (0x03) + +typedef struct _CONFIG_PAGE_SCSI_PORT_1 +{ + fCONFIG_PAGE_HEADER Header; + U32 Configuration; +} fCONFIG_PAGE_SCSI_PORT_1, MPI_POINTER PTR_CONFIG_PAGE_SCSI_PORT_1, + SCSIPortPage1_t, MPI_POINTER pSCSIPortPage1_t; + +#define MPI_SCSIPORTPAGE1_PAGEVERSION (0x01) + +#define MPI_SCSIPORTPAGE1_CFG_PORT_SCSI_ID_MASK (0x000000FF) +#define MPI_SCSIPORTPAGE1_CFG_PORT_RESPONSE_ID_MASK (0xFFFF0000) + +typedef struct _MPI_DEVICE_INFO +{ + U8 Timeout; + U8 SyncFactor; + U16 DeviceFlags; +} MPI_DEVICE_INFO, MPI_POINTER PTR_MPI_DEVICE_INFO, + MpiDeviceInfo_t, MPI_POINTER pMpiDeviceInfo_t; + +typedef struct _CONFIG_PAGE_SCSI_PORT_2 +{ + fCONFIG_PAGE_HEADER Header; + U32 PortFlags; + U32 PortSettings; + MPI_DEVICE_INFO DeviceSettings[16]; +} fCONFIG_PAGE_SCSI_PORT_2, MPI_POINTER PTR_CONFIG_PAGE_SCSI_PORT_2, + SCSIPortPage2_t, MPI_POINTER pSCSIPortPage2_t; + +#define MPI_SCSIPORTPAGE2_PAGEVERSION (0x01) + +#define MPI_SCSIPORTPAGE2_PORT_FLAGS_SCAN_HIGH_TO_LOW (0x00000001) +#define MPI_SCSIPORTPAGE2_PORT_FLAGS_PARITY_ENABLE (0x00000002) +#define MPI_SCSIPORTPAGE2_PORT_FLAGS_AVOID_SCSI_RESET (0x00000004) +#define MPI_SCSIPORTPAGE2_PORT_FLAGS_ALTERNATE_CHS (0x00000008) +#define MPI_SCSIPORTPAGE2_PORT_FLAGS_TERMINATION_DISABLE (0x00000010) + +#define MPI_SCSIPORTPAGE2_PORT_HOST_ID_MASK (0x0000000F) +#define MPI_SCSIPORTPAGE2_PORT_MASK_INIT_HBA (0x00000030) +#define MPI_SCSIPORTPAGE2_PORT_DISABLE_INIT_HBA (0x00000000) +#define MPI_SCSIPORTPAGE2_PORT_BIOS_INIT_HBA (0x00000010) +#define MPI_SCSIPORTPAGE2_PORT_OS_INIT_HBA (0x00000020) +#define MPI_SCSIPORTPAGE2_PORT_BIOS_OS_INIT_HBA (0x00000030) +#define MPI_SCSIPORTPAGE2_PORT_REMOVABLE_MEDIA (0x000000C0) +#define MPI_SCSIPORTPAGE2_PORT_SPINUP_DELAY_MASK (0x00000F00) +#define MPI_SCSIPORTPAGE2_PORT_MASK_NEGO_MASTER_SETTINGS (0x00003000) +#define MPI_SCSIPORTPAGE2_PORT_NEGO_MASTER_SETTINGS (0x00000000) +#define MPI_SCSIPORTPAGE2_PORT_NONE_MASTER_SETTINGS (0x00000001) +#define MPI_SCSIPORTPAGE2_PORT_ALL_MASTER_SETTINGS (0x00000003) + +#define MPI_SCSIPORTPAGE2_DEVICE_DISCONNECT_ENABLE (0x00000001) +#define MPI_SCSIPORTPAGE2_DEVICE_ID_SCAN_ENABLE (0x00000002) +#define MPI_SCSIPORTPAGE2_DEVICE_LUN_SCAN_ENABLE (0x00000004) +#define MPI_SCSIPORTPAGE2_DEVICE_TAG_QUEUE_ENABLE (0x00000008) +#define MPI_SCSIPORTPAGE2_DEVICE_WIDE_DISABLE (0x00000010) +#define MPI_SCSIPORTPAGE2_DEVICE_BOOT_CHOICE (0x00000020) + + +/****************************************************************************/ +/* SCSI Target Device Config Pages */ +/****************************************************************************/ + +typedef struct _CONFIG_PAGE_SCSI_DEVICE_0 +{ + fCONFIG_PAGE_HEADER Header; + U32 NegotiatedParameters; + U32 Information; +} fCONFIG_PAGE_SCSI_DEVICE_0, MPI_POINTER PTR_CONFIG_PAGE_SCSI_DEVICE_0, + SCSIDevicePage0_t, MPI_POINTER pSCSIDevicePage0_t; + +#define MPI_SCSIDEVPAGE0_PAGEVERSION (0x01) + +#define MPI_SCSIDEVPAGE0_NP_IU (0x00000001) +#define MPI_SCSIDEVPAGE0_NP_DT (0x00000002) +#define MPI_SCSIDEVPAGE0_NP_QAS (0x00000004) +#define MPI_SCSIDEVPAGE0_NP_PACING_TRANSFERS (0x00000008) +#define MPI_SCSIDEVPAGE0_NP_NEG_SYNC_PERIOD_MASK (0x0000FF00) +#define MPI_SCSIDEVPAGE0_NP_NEG_SYNC_OFFSET_MASK (0x00FF0000) +#define MPI_SCSIDEVPAGE0_NP_WIDE (0x20000000) +#define MPI_SCSIDEVPAGE0_NP_AIP (0x80000000) + +#define MPI_SCSIDEVPAGE0_INFO_PARAMS_NEGOTIATED (0x00000001) + +typedef struct _CONFIG_PAGE_SCSI_DEVICE_1 +{ + fCONFIG_PAGE_HEADER Header; + U32 RequestedParameters; + U32 DomainValidation; + U32 Configuration; +} fCONFIG_PAGE_SCSI_DEVICE_1, MPI_POINTER PTR_CONFIG_PAGE_SCSI_DEVICE_1, + SCSIDevicePage1_t, MPI_POINTER pSCSIDevicePage1_t; + +#define MPI_SCSIDEVPAGE1_PAGEVERSION (0x01) + +#define MPI_SCSIDEVPAGE1_RP_IU (0x00000001) +#define MPI_SCSIDEVPAGE1_RP_DT (0x00000002) +#define MPI_SCSIDEVPAGE1_RP_QAS (0x00000004) +#define MPI_SCSIDEVPAGE1_RP_PACING_TRANSFERS (0x00000008) +#define MPI_SCSIDEVPAGE1_RP_MIN_SYNC_PERIOD_MASK (0x0000FF00) +#define MPI_SCSIDEVPAGE1_RP_MAX_SYNC_OFFSET_MASK (0x00FF0000) +#define MPI_SCSIDEVPAGE1_RP_WIDE (0x20000000) +#define MPI_SCSIDEVPAGE1_RP_AIP (0x80000000) + +#define MPI_SCSIDEVPAGE1_DV_LVD_DRIVE_STRENGTH_MASK (0x00000003) +#define MPI_SCSIDEVPAGE1_DV_SE_SLEW_RATE_MASK (0x00000300) + +#define MPI_SCSIDEVPAGE1_CONF_PPR_ALLOWED (0x00000001) + +/****************************************************************************/ +/* FC Port Config Pages */ +/****************************************************************************/ + +typedef struct _CONFIG_PAGE_FC_PORT_0 +{ + fCONFIG_PAGE_HEADER Header; + U32 Flags; + U8 MPIPortNumber; + U8 LinkType; + U8 PortState; + U8 Reserved; + U32 PortIdentifier; + U64 WWNN; + U64 WWPN; + U32 SupportedServiceClass; + U32 SupportedSpeeds; + U32 CurrentSpeed; + U32 MaxFrameSize; + U64 FabricWWNN; + U64 FabricWWPN; + U32 DiscoveredPortsCount; + U32 MaxInitiators; +} fCONFIG_PAGE_FC_PORT_0, MPI_POINTER PTR_CONFIG_PAGE_FC_PORT_0, + FCPortPage0_t, MPI_POINTER pFCPortPage0_t; + +#define MPI_FCPORTPAGE0_PAGEVERSION (0x01) + +#define MPI_FCPORTPAGE0_FLAGS_PROT_MASK (0x0000000F) +#define MPI_FCPORTPAGE0_FLAGS_PROT_FCP_INIT (MPI_PORTFACTS_PROTOCOL_INITIATOR) +#define MPI_FCPORTPAGE0_FLAGS_PROT_FCP_TARG (MPI_PORTFACTS_PROTOCOL_TARGET) +#define MPI_FCPORTPAGE0_FLAGS_PROT_LAN (MPI_PORTFACTS_PROTOCOL_LAN) +#define MPI_FCPORTPAGE0_FLAGS_PROT_LOGBUSADDR (MPI_PORTFACTS_PROTOCOL_LOGBUSADDR) + +#define MPI_FCPORTPAGE0_FLAGS_ALIAS_ALPA_SUPPORTED (0x00000010) +#define MPI_FCPORTPAGE0_FLAGS_ALIAS_WWN_SUPPORTED (0x00000020) +#define MPI_FCPORTPAGE0_FLAGS_FABRIC_WWN_VALID (0x00000030) + +#define MPI_FCPORTPAGE0_FLAGS_ATTACH_TYPE_MASK (0x00000700) +#define MPI_FCPORTPAGE0_FLAGS_ATTACH_POINT_TO_POINT (0x00000000) +#define MPI_FCPORTPAGE0_FLAGS_ATTACH_PRIVATE_LOOP (0x00000100) +#define MPI_FCPORTPAGE0_FLAGS_ATTACH_FABRIC_DIRECT (0x00000200) +#define MPI_FCPORTPAGE0_FLAGS_ATTACH_PUBLIC_LOOP (0x00000300) +#define MPI_FCPORTPAGE0_FLAGS_ATTACH_NO_INIT (0x00000700) + +#define MPI_FCPORTPAGE0_LTYPE_RESERVED (0x00) +#define MPI_FCPORTPAGE0_LTYPE_OTHER (0x01) +#define MPI_FCPORTPAGE0_LTYPE_UNKNOWN (0x02) +#define MPI_FCPORTPAGE0_LTYPE_COPPER (0x03) +#define MPI_FCPORTPAGE0_LTYPE_SINGLE_1300 (0x04) +#define MPI_FCPORTPAGE0_LTYPE_SINGLE_1500 (0x05) +#define MPI_FCPORTPAGE0_LTYPE_50_LASER_MULTI (0x06) +#define MPI_FCPORTPAGE0_LTYPE_50_LED_MULTI (0x07) +#define MPI_FCPORTPAGE0_LTYPE_62_LASER_MULTI (0x08) +#define MPI_FCPORTPAGE0_LTYPE_62_LED_MULTI (0x09) +#define MPI_FCPORTPAGE0_LTYPE_MULTI_LONG_WAVE (0x0A) +#define MPI_FCPORTPAGE0_LTYPE_MULTI_SHORT_WAVE (0x0B) +#define MPI_FCPORTPAGE0_LTYPE_LASER_SHORT_WAVE (0x0C) +#define MPI_FCPORTPAGE0_LTYPE_LED_SHORT_WAVE (0x0D) +#define MPI_FCPORTPAGE0_LTYPE_1300_LONG_WAVE (0x0E) +#define MPI_FCPORTPAGE0_LTYPE_1500_LONG_WAVE (0x0F) + +#define MPI_FCPORTPAGE0_PORTSTATE_UNKNOWN (0x01) /*(SNIA)HBA_PORTSTATE_UNKNOWN 1 Unknown */ +#define MPI_FCPORTPAGE0_PORTSTATE_ONLINE (0x02) /*(SNIA)HBA_PORTSTATE_ONLINE 2 Operational */ +#define MPI_FCPORTPAGE0_PORTSTATE_OFFLINE (0x03) /*(SNIA)HBA_PORTSTATE_OFFLINE 3 User Offline */ +#define MPI_FCPORTPAGE0_PORTSTATE_BYPASSED (0x04) /*(SNIA)HBA_PORTSTATE_BYPASSED 4 Bypassed */ +#define MPI_FCPORTPAGE0_PORTSTATE_DIAGNOST (0x05) /*(SNIA)HBA_PORTSTATE_DIAGNOSTICS 5 In diagnostics mode */ +#define MPI_FCPORTPAGE0_PORTSTATE_LINKDOWN (0x06) /*(SNIA)HBA_PORTSTATE_LINKDOWN 6 Link Down */ +#define MPI_FCPORTPAGE0_PORTSTATE_ERROR (0x07) /*(SNIA)HBA_PORTSTATE_ERROR 7 Port Error */ +#define MPI_FCPORTPAGE0_PORTSTATE_LOOPBACK (0x08) /*(SNIA)HBA_PORTSTATE_LOOPBACK 8 Loopback */ + +#define MPI_FCPORTPAGE0_SUPPORT_CLASS_1 (0x00000001) +#define MPI_FCPORTPAGE0_SUPPORT_CLASS_2 (0x00000002) +#define MPI_FCPORTPAGE0_SUPPORT_CLASS_3 (0x00000004) + +#define MPI_FCPORTPAGE0_SUPPORT_1GBIT_SPEED (0x00000001) /* (SNIA)HBA_PORTSPEED_1GBIT 1 1 GBit/sec */ +#define MPI_FCPORTPAGE0_SUPPORT_2GBIT_SPEED (0x00000002) /* (SNIA)HBA_PORTSPEED_2GBIT 2 2 GBit/sec */ +#define MPI_FCPORTPAGE0_SUPPORT_10GBIT_SPEED (0x00000004) /* (SNIA)HBA_PORTSPEED_10GBIT 4 10 GBit/sec */ + +#define MPI_FCPORTPAGE0_CURRENT_SPEED_1GBIT MPI_FCPORTPAGE0_SUPPORT_1GBIT_SPEED +#define MPI_FCPORTPAGE0_CURRENT_SPEED_2GBIT MPI_FCPORTPAGE0_SUPPORT_2GBIT_SPEED +#define MPI_FCPORTPAGE0_CURRENT_SPEED_10GBIT MPI_FCPORTPAGE0_SUPPORT_10GBIT_SPEED + + +typedef struct _CONFIG_PAGE_FC_PORT_1 +{ + fCONFIG_PAGE_HEADER Header; + U32 Flags; + U64 NoSEEPROMWWNN; + U64 NoSEEPROMWWPN; + U8 HardALPA; + U8 LinkConfig; + U8 TopologyConfig; + U8 Reserved; +} fCONFIG_PAGE_FC_PORT_1, MPI_POINTER PTR_CONFIG_PAGE_FC_PORT_1, + FCPortPage1_t, MPI_POINTER pFCPortPage1_t; + +#define MPI_FCPORTPAGE1_PAGEVERSION (0x01) + +#define MPI_FCPORTPAGE1_FLAGS_SORT_BY_DID (0x00000001) +#define MPI_FCPORTPAGE1_FLAGS_SORT_BY_WWN (0x00000000) + +#define MPI_FCPORTPAGE1_FLAGS_PROT_MASK (0xF0000000) +#define MPI_FCPORTPAGE1_FLAGS_PROT_SHIFT (28) +#define MPI_FCPORTPAGE1_FLAGS_PROT_FCP_INIT ((U32)MPI_PORTFACTS_PROTOCOL_INITIATOR << MPI_FCPORTPAGE1_FLAGS_PROT_SHIFT) +#define MPI_FCPORTPAGE1_FLAGS_PROT_FCP_TARG ((U32)MPI_PORTFACTS_PROTOCOL_TARGET << MPI_FCPORTPAGE1_FLAGS_PROT_SHIFT) +#define MPI_FCPORTPAGE1_FLAGS_PROT_LAN ((U32)MPI_PORTFACTS_PROTOCOL_LAN << MPI_FCPORTPAGE1_FLAGS_PROT_SHIFT) +#define MPI_FCPORTPAGE1_FLAGS_PROT_LOGBUSADDR ((U32)MPI_PORTFACTS_PROTOCOL_LOGBUSADDR << MPI_FCPORTPAGE1_FLAGS_PROT_SHIFT) + +#define MPI_FCPORTPAGE1_HARD_ALPA_NOT_USED (0xFF) + +#define MPI_FCPORTPAGE1_LCONFIG_SPEED_MASK (0x0F) +#define MPI_FCPORTPAGE1_LCONFIG_SPEED_1GIG (0x00) +#define MPI_FCPORTPAGE1_LCONFIG_SPEED_2GIG (0x01) +#define MPI_FCPORTPAGE1_LCONFIG_SPEED_4GIG (0x02) +#define MPI_FCPORTPAGE1_LCONFIG_SPEED_10GIG (0x03) +#define MPI_FCPORTPAGE1_LCONFIG_SPEED_AUTO (0x0F) + +#define MPI_FCPORTPAGE1_TOPOLGY_MASK (0x0F) +#define MPI_FCPORTPAGE1_TOPOLGY_NLPORT (0x01) +#define MPI_FCPORTPAGE1_TOPOLGY_NPORT (0x02) +#define MPI_FCPORTPAGE1_TOPOLGY_AUTO (0x0F) + + +typedef struct _CONFIG_PAGE_FC_PORT_2 +{ + fCONFIG_PAGE_HEADER Header; + U8 NumberActive; + U8 ALPA[126]; + U8 Reserved; +} fCONFIG_PAGE_FC_PORT_2, MPI_POINTER PTR_CONFIG_PAGE_FC_PORT_2, + FCPortPage2_t, MPI_POINTER pFCPortPage2_t; + +#define MPI_FCPORTPAGE2_PAGEVERSION (0x00) + + +typedef struct _FC_PORT_PERSISTENT +{ + U64 WWNN; + U64 WWPN; + U8 TargetID; + U8 Bus; + U16 Flags; +} FC_PORT_PERSISTENT, MPI_POINTER PTR_FC_PORT_PERSISTENT, + PersistentData_t, MPI_POINTER pPersistentData_t; + +#define MPI_PERSISTENT_FLAGS_SHIFT (16) +#define MPI_PERSISTENT_FLAGS_ENTRY_VALID (0x0001) +#define MPI_PERSISTENT_FLAGS_SCAN_ID (0x0002) +#define MPI_PERSISTENT_FLAGS_SCAN_LUNS (0x0004) +#define MPI_PERSISTENT_FLAGS_BOOT_DEVICE (0x0008) + +typedef struct _CONFIG_PAGE_FC_PORT_3 +{ + fCONFIG_PAGE_HEADER Header; + FC_PORT_PERSISTENT Entry[1]; +} fCONFIG_PAGE_FC_PORT_3, MPI_POINTER PTR_CONFIG_PAGE_FC_PORT_3, + FCPortPage3_t, MPI_POINTER pFCPortPage3_t; + +#define MPI_FCPORTPAGE3_PAGEVERSION (0x00) + + +typedef struct _CONFIG_PAGE_FC_PORT_4 +{ + fCONFIG_PAGE_HEADER Header; + U32 PortFlags; + U32 PortSettings; +} fCONFIG_PAGE_FC_PORT_4, MPI_POINTER PTR_CONFIG_PAGE_FC_PORT_4, + FCPortPage4_t, MPI_POINTER pFCPortPage4_t; + +#define MPI_FCPORTPAGE4_PAGEVERSION (0x00) + +#define MPI_FCPORTPAGE4_PORT_FLAGS_ALTERNATE_CHS (0x00000008) + +#define MPI_FCPORTPAGE4_PORT_MASK_INIT_HBA (0x00000030) +#define MPI_FCPORTPAGE4_PORT_DISABLE_INIT_HBA (0x00000000) +#define MPI_FCPORTPAGE4_PORT_BIOS_INIT_HBA (0x00000010) +#define MPI_FCPORTPAGE4_PORT_OS_INIT_HBA (0x00000020) +#define MPI_FCPORTPAGE4_PORT_BIOS_OS_INIT_HBA (0x00000030) +#define MPI_FCPORTPAGE4_PORT_REMOVABLE_MEDIA (0x000000C0) +#define MPI_FCPORTPAGE4_PORT_SPINUP_DELAY_MASK (0x00000F00) + + +typedef struct _CONFIG_PAGE_FC_PORT_5_ALIAS_INFO +{ + U8 Flags; + U8 AliasAlpa; + U16 Reserved; + U64 AliasWWNN; + U64 AliasWWPN; +} fCONFIG_PAGE_FC_PORT_5_ALIAS_INFO, MPI_POINTER PTR_CONFIG_PAGE_FC_PORT_5_ALIAS_INFO, + FcPortPage5AliasInfo_t, MPI_POINTER pFcPortPage5AliasInfo_t; + +typedef struct _CONFIG_PAGE_FC_PORT_5 +{ + fCONFIG_PAGE_HEADER Header; + fCONFIG_PAGE_FC_PORT_5_ALIAS_INFO AliasInfo[1]; +} fCONFIG_PAGE_FC_PORT_5, MPI_POINTER PTR_CONFIG_PAGE_FC_PORT_5, + FCPortPage5_t, MPI_POINTER pFCPortPage5_t; + +#define MPI_FCPORTPAGE5_PAGEVERSION (0x00) + +#define MPI_FCPORTPAGE5_FLAGS_ALIAS_ALPA_VALID (0x01) +#define MPI_FCPORTPAGE5_FLAGS_ALIAS_WWN_VALID (0x02) + + +typedef struct _CONFIG_PAGE_FC_PORT_6 +{ + fCONFIG_PAGE_HEADER Header; + U32 Reserved; + U64 TimeSinceReset; + U64 TxFrames; + U64 RxFrames; + U64 TxWords; + U64 RxWords; + U64 LipCount; + U64 NosCount; + U64 ErrorFrames; + U64 DumpedFrames; + U64 LinkFailureCount; + U64 LossOfSyncCount; + U64 LossOfSignalCount; + U64 PrimativeSeqErrCount; + U64 InvalidTxWordCount; + U64 InvalidCrcCount; + U64 FcpInitiatorIoCount; +} fCONFIG_PAGE_FC_PORT_6, MPI_POINTER PTR_CONFIG_PAGE_FC_PORT_6, + FCPortPage6_t, MPI_POINTER pFCPortPage6_t; + +#define MPI_FCPORTPAGE6_PAGEVERSION (0x00) + + +typedef struct _CONFIG_PAGE_FC_PORT_7 +{ + fCONFIG_PAGE_HEADER Header; + U32 Reserved; + U8 PortSymbolicName[256]; +} fCONFIG_PAGE_FC_PORT_7, MPI_POINTER PTR_CONFIG_PAGE_FC_PORT_7, + FCPortPage7_t, MPI_POINTER pFCPortPage7_t; + +#define MPI_FCPORTPAGE7_PAGEVERSION (0x00) + + +/****************************************************************************/ +/* FC Device Config Pages */ +/****************************************************************************/ + +typedef struct _CONFIG_PAGE_FC_DEVICE_0 +{ + fCONFIG_PAGE_HEADER Header; + U64 WWNN; + U64 WWPN; + U32 PortIdentifier; + U8 Protocol; + U8 Flags; + U16 BBCredit; + U16 MaxRxFrameSize; + U8 Reserved1; + U8 PortNumber; + U8 FcPhLowestVersion; + U8 FcPhHighestVersion; + U8 CurrentTargetID; + U8 CurrentBus; +} fCONFIG_PAGE_FC_DEVICE_0, MPI_POINTER PTR_CONFIG_PAGE_FC_DEVICE_0, + FCDevicePage0_t, MPI_POINTER pFCDevicePage0_t; + +#define MPI_FC_DEVICE_PAGE0_PAGEVERSION (0x02) + +#define MPI_FC_DEVICE_PAGE0_FLAGS_TARGETID_BUS_VALID (0x01) + +#define MPI_FC_DEVICE_PAGE0_PROT_IP (0x01) +#define MPI_FC_DEVICE_PAGE0_PROT_FCP_TARGET (0x02) +#define MPI_FC_DEVICE_PAGE0_PROT_FCP_INITIATOR (0x04) + +#define MPI_FC_DEVICE_PAGE0_PGAD_PORT_MASK (MPI_FC_DEVICE_PGAD_PORT_MASK) +#define MPI_FC_DEVICE_PAGE0_PGAD_FORM_MASK (MPI_FC_DEVICE_PGAD_FORM_MASK) +#define MPI_FC_DEVICE_PAGE0_PGAD_FORM_NEXT_DID (MPI_FC_DEVICE_PGAD_FORM_NEXT_DID) +#define MPI_FC_DEVICE_PAGE0_PGAD_FORM_BUS_TID (MPI_FC_DEVICE_PGAD_FORM_BUS_TID) +#define MPI_FC_DEVICE_PAGE0_PGAD_DID_MASK (MPI_FC_DEVICE_PGAD_ND_DID_MASK) +#define MPI_FC_DEVICE_PAGE0_PGAD_BUS_MASK (MPI_FC_DEVICE_PGAD_BT_BUS_MASK) +#define MPI_FC_DEVICE_PAGE0_PGAD_BUS_SHIFT (MPI_FC_DEVICE_PGAD_BT_BUS_SHIFT) +#define MPI_FC_DEVICE_PAGE0_PGAD_TID_MASK (MPI_FC_DEVICE_PGAD_BT_TID_MASK) + + +/****************************************************************************/ +/* RAID Volume Config Pages */ +/****************************************************************************/ + +typedef struct _RAIDVOL2_EM_PHYS_ID +{ + U8 TargetID; + U8 Bus; + U8 IocNumber; + U8 PhysDiskNumber; + U8 Reserved[8]; + U8 PhysicalDiskIdentifier[16]; + U8 ProductId[16]; + U8 InfoOffset0; + U8 InfoSize0; + U8 InfoOffset1; + U8 InfoSize1; + U8 Info[32]; +} RAIDVOL2_EM_PHYS_ID, MPI_POINTER PTR_RAIDVOL2_EM_PHYS_ID, + RaidVol2EmPhysicalID_t, MPI_POINTER pRaidVol2EmPhysicalID_t; + +typedef struct _RAIDVOL2_EM_DISK_INFO +{ + U32 DiskStatus; + U32 DeviceSettings; + U16 ErrorCount; + U16 Reserved; + U8 ErrorCdbByte; + U8 ErrorSenseKey; + U8 ErrorASC; + U8 ErrorASCQ; + U16 SmartCount; + U8 SmartASC; + U8 SmartASCQ; +} RAIDVOL2_EM_DISK_INFO, MPI_POINTER PTR_RAIDVOL2_EM_DISK_INFO, + RaidVol2EmDiskInfo_t, MPI_POINTER pRaidVol2EmDiskInfo_t; + +/* RAID Volume 2 EM Physical Disk DiskStatus flags */ + +#define MPI_RAIDVOLPAGE2_PHYS_DISK_PRIMARY (0x00000001) +#define MPI_RAIDVOLPAGE2_PHYS_DISK_SECONDARY (0x00000002) +#define MPI_RAIDVOLPAGE2_PHYS_DISK_HOT_SPARE (0x00000004) +#define MPI_RAIDVOLPAGE2_PHYS_DISK_OUT_OF_SYNC (0x00000008) +#define MPI_RAIDVOLPAGE2_PHYS_DISK_OFFLINE (0x00000010) +#define MPI_RAIDVOLPAGE2_PHYS_DISK_NOT_RESPONDING (0x00000020) + +typedef struct _RAIDVOL2_EM_PHYSICAL_DISK +{ + RAIDVOL2_EM_PHYS_ID Id; + RAIDVOL2_EM_DISK_INFO Info; +} RAIDVOL2_EM_PHYSICAL_DISK, MPI_POINTER PTR_RAIDVOL2_EM_PHYSICAL_DISK, + RaidVol2EmPhysicalDisk_t, MPI_POINTER pRaidVol2EmPhysicalDisk_t; + +#define MPI_RAIDVOLPAGE2_MAX_DISKS (3) + +typedef struct _CONFIG_PAGE_RAID_VOL_2 +{ + fCONFIG_PAGE_HEADER Header; + U32 VolumeStatus; + U32 VolumeSettings; + U32 Reserved; + U64 MaxLba; + U32 BlockSize; + U8 InquirySize; + U8 NumPhysicalDisks; + U16 Reserved1; + U8 InquiryData[56]; + RAIDVOL2_EM_PHYSICAL_DISK EMPhysicalDisk[MPI_RAIDVOLPAGE2_MAX_DISKS]; +} fCONFIG_PAGE_RAID_VOL_2, MPI_POINTER PTR_CONFIG_PAGE_RAID_VOL_2, + RaidVolumePage2_t, MPI_POINTER pRaidVolumePage2_t; + +#define MPI_RAIDVOLPAGE2_PAGEVERSION (0x00) + +/* RAID Volume Page 2 VolumeStatus defines */ + +#define MPI_RAIDVOLPAGE2_STATUS_ENABLED (0x00000001) +#define MPI_RAIDVOLPAGE2_STATUS_QUIESCED (0x00000002) +#define MPI_RAIDVOLPAGE2_STATUS_RESYNC_IN_PROGRESS (0x00000004) +#define MPI_RAIDVOLPAGE2_STATUS_DEGRADED (0x00000008) + +/* RAID Volume Page 2 VolumeSettings defines */ + +#define MPI_RAIDVOLPAGE2_SETTING_WRITE_CACHING_ENABLE (0x00000001) +#define MPI_RAIDVOLPAGE2_SETTING_OFFLINE_ON_SMART (0x00000002) +#define MPI_RAIDVOLPAGE2_SETTING_AUTO_CONFIGURE (0x00000004) + + +/****************************************************************************/ +/* LAN Config Pages */ +/****************************************************************************/ + +typedef struct _CONFIG_PAGE_LAN_0 +{ + ConfigPageHeader_t Header; + U16 TxRxModes; + U16 Reserved; + U32 PacketPrePad; +} fCONFIG_PAGE_LAN_0, MPI_POINTER PTR_CONFIG_PAGE_LAN_0, + LANPage0_t, MPI_POINTER pLANPage0_t; + +#define MPI_LAN_PAGE0_PAGEVERSION (0x01) + +#define MPI_LAN_PAGE0_RETURN_LOOPBACK (0x0000) +#define MPI_LAN_PAGE0_SUPPRESS_LOOPBACK (0x0001) +#define MPI_LAN_PAGE0_LOOPBACK_MASK (0x0001) + +typedef struct _CONFIG_PAGE_LAN_1 +{ + ConfigPageHeader_t Header; + U16 Reserved; + U8 CurrentDeviceState; + U8 Reserved1; + U32 MinPacketSize; + U32 MaxPacketSize; + U32 HardwareAddressLow; + U32 HardwareAddressHigh; + U32 MaxWireSpeedLow; + U32 MaxWireSpeedHigh; + U32 BucketsRemaining; + U32 MaxReplySize; + U32 NegWireSpeedHigh; + U32 NegWireSpeedLow; +} fCONFIG_PAGE_LAN_1, MPI_POINTER PTR_CONFIG_PAGE_LAN_1, + LANPage1_t, MPI_POINTER pLANPage1_t; + +#define MPI_LAN_PAGE1_PAGEVERSION (0x03) + +#define MPI_LAN_PAGE1_DEV_STATE_RESET (0x00) +#define MPI_LAN_PAGE1_DEV_STATE_OPERATIONAL (0x01) + +#endif + diff -u --recursive --new-file v2.4.6/linux/drivers/message/fusion/lsi/mpi_fc.h linux/drivers/message/fusion/lsi/mpi_fc.h --- v2.4.6/linux/drivers/message/fusion/lsi/mpi_fc.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/message/fusion/lsi/mpi_fc.h Fri Jul 6 17:03:11 2001 @@ -0,0 +1,350 @@ +/* + * Copyright (c) 2000-2001 LSI Logic Corporation. + * + * + * Name: MPI_FC.H + * Title: MPI Fibre Channel messages and structures + * Creation Date: June 12, 2000 + * + * MPI Version: 01.01.05 + * + * Version History + * --------------- + * + * Date Version Description + * -------- -------- ------------------------------------------------------ + * 05-08-00 00.10.01 Original release for 0.10 spec dated 4/26/2000. + * 06-06-00 01.00.01 Update version number for 1.0 release. + * 06-12-00 01.00.02 Added _MSG_FC_ABORT_REPLY structure. + * 11-02-00 01.01.01 Original release for post 1.0 work + * 12-04-00 01.01.02 Added messages for Common Transport Send and + * Primitive Send. + * 01-09-01 01.01.03 Modifed some of the new flags to have an MPI prefix + * and modified the FcPrimitiveSend flags. + * 01-25-01 01.01.04 Move InitiatorIndex in LinkServiceRsp reply to a larger + * field. + * Added FC_ABORT_TYPE_CT_SEND_REQUEST and + * FC_ABORT_TYPE_EXLINKSEND_REQUEST for FcAbort request. + * Added MPI_FC_PRIM_SEND_FLAGS_STOP_SEND. + * 02-20-01 01.01.05 Started using MPI_POINTER. + * -------------------------------------------------------------------------- + */ + +#ifndef MPI_FC_H +#define MPI_FC_H + + +/***************************************************************************** +* +* F C T a r g e t M o d e M e s s a g e s +* +*****************************************************************************/ + +/****************************************************************************/ +/* Link Service Buffer Post messages */ +/****************************************************************************/ + +typedef struct _MSG_LINK_SERVICE_BUFFER_POST_REQUEST +{ + U8 BufferPostFlags; /* 00h */ + U8 BufferCount; /* 01h */ + U8 ChainOffset; /* 02h */ + U8 Function; /* 03h */ + U16 Reserved; /* 04h */ + U8 Reserved1; /* 06h */ + U8 MsgFlags; /* 07h */ + U32 MsgContext; /* 08h */ + SGE_TRANS_SIMPLE_UNION SGL; +} MSG_LINK_SERVICE_BUFFER_POST_REQUEST, + MPI_POINTER PTR_MSG_LINK_SERVICE_BUFFER_POST_REQUEST, + LinkServiceBufferPostRequest_t, MPI_POINTER pLinkServiceBufferPostRequest_t; + +#define LINK_SERVICE_BUFFER_POST_FLAGS_PORT_MASK (0x01) + +typedef struct _WWNFORMAT +{ + U32 PortNameHigh; /* 00h */ + U32 PortNameLow; /* 04h */ + U32 NodeNameHigh; /* 08h */ + U32 NodeNameLow; /* 0Ch */ +} WWNFORMAT, + WwnFormat_t; + +/* Link Service Buffer Post Reply */ +typedef struct _MSG_LINK_SERVICE_BUFFER_POST_REPLY +{ + U8 Flags; /* 00h */ + U8 Reserved; /* 01h */ + U8 MsgLength; /* 02h */ + U8 Function; /* 03h */ + U16 Reserved1; /* 04h */ + U8 PortNumber; /* 06h */ + U8 MsgFlags; /* 07h */ + U32 MsgContext; /* 08h */ + U16 Reserved2; /* 0Ch */ + U16 IOCStatus; /* 0Eh */ + U32 IOCLogInfo; /* 10h */ + U32 TransferLength; /* 14h */ + U32 TransactionContext; /* 18h */ + U32 Rctl_Did; /* 1Ch */ + U32 Csctl_Sid; /* 20h */ + U32 Type_Fctl; /* 24h */ + U16 SeqCnt; /* 28h */ + U8 Dfctl; /* 2Ah */ + U8 SeqId; /* 2Bh */ + U16 Rxid; /* 2Ch */ + U16 Oxid; /* 2Eh */ + U32 Parameter; /* 30h */ + WWNFORMAT Wwn; /* 34h */ +} MSG_LINK_SERVICE_BUFFER_POST_REPLY, MPI_POINTER PTR_MSG_LINK_SERVICE_BUFFER_POST_REPLY, + LinkServiceBufferPostReply_t, MPI_POINTER pLinkServiceBufferPostReply_t; + +#define MPI_LS_BUF_POST_REPLY_FLAG_NO_RSP_NEEDED (0x80) + +#define MPI_FC_DID_MASK (0x00FFFFFF) +#define MPI_FC_DID_SHIFT (0) +#define MPI_FC_RCTL_MASK (0xFF000000) +#define MPI_FC_RCTL_SHIFT (24) +#define MPI_FC_SID_MASK (0x00FFFFFF) +#define MPI_FC_SID_SHIFT (0) +#define MPI_FC_CSCTL_MASK (0xFF000000) +#define MPI_FC_CSCTL_SHIFT (24) +#define MPI_FC_FCTL_MASK (0x00FFFFFF) +#define MPI_FC_FCTL_SHIFT (0) +#define MPI_FC_TYPE_MASK (0xFF000000) +#define MPI_FC_TYPE_SHIFT (24) + +/* obsolete name for the above */ +#define FCP_TARGET_DID_MASK (0x00FFFFFF) +#define FCP_TARGET_DID_SHIFT (0) +#define FCP_TARGET_RCTL_MASK (0xFF000000) +#define FCP_TARGET_RCTL_SHIFT (24) +#define FCP_TARGET_SID_MASK (0x00FFFFFF) +#define FCP_TARGET_SID_SHIFT (0) +#define FCP_TARGET_CSCTL_MASK (0xFF000000) +#define FCP_TARGET_CSCTL_SHIFT (24) +#define FCP_TARGET_FCTL_MASK (0x00FFFFFF) +#define FCP_TARGET_FCTL_SHIFT (0) +#define FCP_TARGET_TYPE_MASK (0xFF000000) +#define FCP_TARGET_TYPE_SHIFT (24) + + +/****************************************************************************/ +/* Link Service Response messages */ +/****************************************************************************/ + +typedef struct _MSG_LINK_SERVICE_RSP_REQUEST +{ + U8 RspFlags; /* 00h */ + U8 Reserved; /* 01h */ + U8 ChainOffset; /* 02h */ + U8 Function; /* 03h */ + U16 Reserved1; /* 04h */ + U8 Reserved2; /* 06h */ + U8 MsgFlags; /* 07h */ + U32 MsgContext; /* 08h */ + U32 Rctl_Did; /* 0Ch */ + U32 Csctl_Sid; /* 10h */ + U32 Type_Fctl; /* 14h */ + U16 SeqCnt; /* 18h */ + U8 Dfctl; /* 1Ah */ + U8 SeqId; /* 1Bh */ + U16 Rxid; /* 1Ch */ + U16 Oxid; /* 1Eh */ + U32 Parameter; /* 20h */ + SGE_SIMPLE_UNION SGL; /* 24h */ +} MSG_LINK_SERVICE_RSP_REQUEST, MPI_POINTER PTR_MSG_LINK_SERVICE_RSP_REQUEST, + LinkServiceRspRequest_t, MPI_POINTER pLinkServiceRspRequest_t; + +#define LINK_SERVICE_RSP_FLAGS_IMMEDIATE (0x80) +#define LINK_SERVICE_RSP_FLAGS_PORT_MASK (0x01) + + +/* Link Service Response Reply */ +typedef struct _MSG_LINK_SERVICE_RSP_REPLY +{ + U16 Reserved; /* 00h */ + U8 MsgLength; /* 02h */ + U8 Function; /* 03h */ + U16 Reserved1; /* 04h */ + U8 Reserved2; /* 06h */ + U8 MsgFlags; /* 07h */ + U32 MsgContext; /* 08h */ + U16 Reserved3; /* 0Ch */ + U16 IOCStatus; /* 0Eh */ + U32 IOCLogInfo; /* 10h */ + U32 InitiatorIndex; /* 14h */ +} MSG_LINK_SERVICE_RSP_REPLY, MPI_POINTER PTR_MSG_LINK_SERVICE_RSP_REPLY, + LinkServiceRspReply_t, MPI_POINTER pLinkServiceRspReply_t; + + +/****************************************************************************/ +/* Extended Link Service Send messages */ +/****************************************************************************/ + +typedef struct _MSG_EXLINK_SERVICE_SEND_REQUEST +{ + U8 SendFlags; /* 00h */ + U8 Reserved; /* 01h */ + U8 ChainOffset; /* 02h */ + U8 Function; /* 03h */ + U32 MsgFlags_Did; /* 04h */ + U32 MsgContext; /* 08h */ + U32 ElsCommandCode; /* 0Ch */ + SGE_SIMPLE_UNION SGL; /* 10h */ +} MSG_EXLINK_SERVICE_SEND_REQUEST, MPI_POINTER PTR_MSG_EXLINK_SERVICE_SEND_REQUEST, + ExLinkServiceSendRequest_t, MPI_POINTER pExLinkServiceSendRequest_t; + +#define EX_LINK_SERVICE_SEND_DID_MASK (0x00FFFFFF) +#define EX_LINK_SERVICE_SEND_DID_SHIFT (0) +#define EX_LINK_SERVICE_SEND_MSGFLAGS_MASK (0xFF000000) +#define EX_LINK_SERVICE_SEND_MSGFLAGS_SHIFT (24) + + +/* Extended Link Service Send Reply */ +typedef struct _MSG_EXLINK_SERVICE_SEND_REPLY +{ + U16 Reserved; /* 00h */ + U8 MsgLength; /* 02h */ + U8 Function; /* 03h */ + U16 Reserved1; /* 04h */ + U8 Reserved2; /* 06h */ + U8 MsgFlags; /* 07h */ + U32 MsgContext; /* 08h */ + U16 Reserved3; /* 0Ch */ + U16 IOCStatus; /* 0Eh */ + U32 IOCLogInfo; /* 10h */ + U32 ResponseLength; /* 14h */ +} MSG_EXLINK_SERVICE_SEND_REPLY, MPI_POINTER PTR_MSG_EXLINK_SERVICE_SEND_REPLY, + ExLinkServiceSendReply_t, MPI_POINTER pExLinkServiceSendReply_t; + +/****************************************************************************/ +/* FC Abort messages */ +/****************************************************************************/ + +typedef struct _MSG_FC_ABORT_REQUEST +{ + U8 AbortFlags; /* 00h */ + U8 AbortType; /* 01h */ + U8 ChainOffset; /* 02h */ + U8 Function; /* 03h */ + U16 Reserved1; /* 04h */ + U8 Reserved2; /* 06h */ + U8 MsgFlags; /* 07h */ + U32 MsgContext; /* 08h */ + U32 TransactionContextToAbort; /* 0Ch */ +} MSG_FC_ABORT_REQUEST, MPI_POINTER PTR_MSG_FC_ABORT_REQUEST, + FcAbortRequest_t, MPI_POINTER pFcAbortRequest_t; + +#define FC_ABORT_FLAG_PORT_MASK (0x01) + +#define FC_ABORT_TYPE_ALL_FC_BUFFERS (0x00) +#define FC_ABORT_TYPE_EXACT_FC_BUFFER (0x01) +#define FC_ABORT_TYPE_CT_SEND_REQUEST (0x02) +#define FC_ABORT_TYPE_EXLINKSEND_REQUEST (0x03) + +/* FC Abort Reply */ +typedef struct _MSG_FC_ABORT_REPLY +{ + U16 Reserved; /* 00h */ + U8 MsgLength; /* 02h */ + U8 Function; /* 03h */ + U16 Reserved1; /* 04h */ + U8 Reserved2; /* 06h */ + U8 MsgFlags; /* 07h */ + U32 MsgContext; /* 08h */ + U16 Reserved3; /* 0Ch */ + U16 IOCStatus; /* 0Eh */ + U32 IOCLogInfo; /* 10h */ +} MSG_FC_ABORT_REPLY, MPI_POINTER PTR_MSG_FC_ABORT_REPLY, + FcAbortReply_t, MPI_POINTER pFcAbortReply_t; + + +/****************************************************************************/ +/* FC Common Transport Send messages */ +/****************************************************************************/ + +typedef struct _MSG_FC_COMMON_TRANSPORT_SEND_REQUEST +{ + U8 SendFlags; /* 00h */ + U8 Reserved; /* 01h */ + U8 ChainOffset; /* 02h */ + U8 Function; /* 03h */ + U32 MsgFlags_Did; /* 04h */ + U32 MsgContext; /* 08h */ + U16 CTCommandCode; /* 0Ch */ + U8 FsType; /* 0Eh */ + U8 Reserved1; /* 0Fh */ + SGE_SIMPLE_UNION SGL; /* 10h */ +} MSG_FC_COMMON_TRANSPORT_SEND_REQUEST, + MPI_POINTER PTR_MSG_FC_COMMON_TRANSPORT_SEND_REQUEST, + FcCommonTransportSendRequest_t, MPI_POINTER pFcCommonTransportSendRequest_t; + +#define MPI_FC_CT_SEND_DID_MASK (0x00FFFFFF) +#define MPI_FC_CT_SEND_DID_SHIFT (0) +#define MPI_FC_CT_SEND_MSGFLAGS_MASK (0xFF000000) +#define MPI_FC_CT_SEND_MSGFLAGS_SHIFT (24) + + +/* FC Common Transport Send Reply */ +typedef struct _MSG_FC_COMMON_TRANSPORT_SEND_REPLY +{ + U16 Reserved; /* 00h */ + U8 MsgLength; /* 02h */ + U8 Function; /* 03h */ + U16 Reserved1; /* 04h */ + U8 Reserved2; /* 06h */ + U8 MsgFlags; /* 07h */ + U32 MsgContext; /* 08h */ + U16 Reserved3; /* 0Ch */ + U16 IOCStatus; /* 0Eh */ + U32 IOCLogInfo; /* 10h */ + U32 ResponseLength; /* 14h */ +} MSG_FC_COMMON_TRANSPORT_SEND_REPLY, MPI_POINTER PTR_MSG_FC_COMMON_TRANSPORT_SEND_REPLY, + FcCommonTransportSendReply_t, MPI_POINTER pFcCommonTransportSendReply_t; + + +/****************************************************************************/ +/* FC Primitive Send messages */ +/****************************************************************************/ + +typedef struct _MSG_FC_PRIMITIVE_SEND_REQUEST +{ + U8 SendFlags; /* 00h */ + U8 Reserved; /* 01h */ + U8 ChainOffset; /* 02h */ + U8 Function; /* 03h */ + U16 Reserved1; /* 04h */ + U8 Reserved2; /* 06h */ + U8 MsgFlags; /* 07h */ + U32 MsgContext; /* 08h */ + U8 FcPrimitive[4]; /* 0Ch */ +} MSG_FC_PRIMITIVE_SEND_REQUEST, MPI_POINTER PTR_MSG_FC_PRIMITIVE_SEND_REQUEST, + FcPrimitiveSendRequest_t, MPI_POINTER pFcPrimitiveSendRequest_t; + +#define MPI_FC_PRIM_SEND_FLAGS_PORT_MASK (0x01) +#define MPI_FC_PRIM_SEND_FLAGS_STOP_SEND (0x08) +#define MPI_FC_PRIM_SEND_FLAGS_SEND_ONCE (0x10) +#define MPI_FC_PRIM_SEND_FLAGS_SEND_AROUND (0x20) +#define MPI_FC_PRIM_SEND_FLAGS_UNTIL_FULL (0x40) +#define MPI_FC_PRIM_SEND_FLAGS_FOREVER (0x80) + +/* FC Primitive Send Reply */ +typedef struct _MSG_FC_PRIMITIVE_SEND_REPLY +{ + U8 SendFlags; /* 00h */ + U8 Reserved; /* 01h */ + U8 MsgLength; /* 02h */ + U8 Function; /* 03h */ + U16 Reserved1; /* 04h */ + U8 Reserved2; /* 06h */ + U8 MsgFlags; /* 07h */ + U32 MsgContext; /* 08h */ + U16 Reserved3; /* 0Ch */ + U16 IOCStatus; /* 0Eh */ + U32 IOCLogInfo; /* 10h */ +} MSG_FC_PRIMITIVE_SEND_REPLY, MPI_POINTER PTR_MSG_FC_PRIMITIVE_SEND_REPLY, + FcPrimitiveSendReply_t, MPI_POINTER pFcPrimitiveSendReply_t; + +#endif + diff -u --recursive --new-file v2.4.6/linux/drivers/message/fusion/lsi/mpi_history.txt linux/drivers/message/fusion/lsi/mpi_history.txt --- v2.4.6/linux/drivers/message/fusion/lsi/mpi_history.txt Wed Dec 31 16:00:00 1969 +++ linux/drivers/message/fusion/lsi/mpi_history.txt Fri Jul 6 17:03:11 2001 @@ -0,0 +1,237 @@ + + ============================== + MPI Header File Change History + ============================== + + Copyright (c) 2000-2001 LSI Logic Corporation. + + --------------------------------------- + Header Set Release Version: 01.01.08 + Header Set Release Date: 02-27-01 + --------------------------------------- + + Filename Current version Prior version + ---------- --------------- ------------- + mpi.h 01.01.06 01.01.05 + mpi_ioc.h 01.01.05 01.01.04 + mpi_cnfg.h 01.01.09 01.01.08 + mpi_init.h 01.01.03 01.01.03 + mpi_targ.h 01.01.03 01.01.03 + mpi_fc.h 01.01.05 01.01.05 + mpi_lan.h 01.01.02 01.01.02 + mpi_raid.h 01.01.01 none + mpi_type.h 01.01.02 01.01.02 + mpi_history.txt 01.01.08 01.01.07 + + + * Date Version Description + * -------- -------- ------------------------------------------------------ + +mpi.h + * 05-08-00 00.10.01 Original release for 0.10 spec dated 4/26/2000. + * 05-24-00 00.10.02 Added MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH definition. + * 06-06-00 01.00.01 Update MPI_VERSION_MAJOR and MPI_VERSION_MINOR. + * 06-22-00 01.00.02 Added MPI_IOCSTATUS_LAN_ definitions. + * Removed LAN_SUSPEND function definition. + * Added MPI_MSGFLAGS_CONTINUATION_REPLY definition. + * 06-30-00 01.00.03 Added MPI_CONTEXT_REPLY_TYPE_LAN definition. + * Added MPI_GET/SET_CONTEXT_REPLY_TYPE macros. + * 07-27-00 01.00.04 Added MPI_FAULT_ definitions. + * Removed MPI_IOCSTATUS_MSG/DATA_XFER_ERROR definitions. + * Added MPI_IOCSTATUS_INTERNAL_ERROR definition. + * Added MPI_IOCSTATUS_TARGET_XFER_COUNT_MISMATCH. + * 11-02-00 01.01.01 Original release for post 1.0 work + * 12-04-00 01.01.02 Added new function codes. + * 01-09-01 01.01.03 Added more definitions to the system interface section + * Added MPI_IOCSTATUS_TARGET_STS_DATA_NOT_SENT. + * 01-25-01 01.01.04 Changed MPI_VERSION_MINOR from 0x00 to 0x01. + * 02-20-01 01.01.05 Started using MPI_POINTER. + * Added defines for MPI_DIAG_PREVENT_IOC_BOOT and + * MPI_DIAG_CLEAR_FLASH_BAD_SIG. + * Obsoleted MPI_IOCSTATUS_TARGET_FC_ defines. + * 02-27-01 01.01.06 Removed MPI_HOST_INDEX_REGISTER define. + * Added function codes for RAID. + * -------------------------------------------------------------------------- + +mpi_ioc.h + * 05-08-00 00.10.01 Original release for 0.10 spec dated 4/26/2000. + * 05-24-00 00.10.02 Added _MSG_IOC_INIT_REPLY structure. + * 06-06-00 01.00.01 Added CurReplyFrameSize field to _MSG_IOC_FACTS_REPLY. + * 06-12-00 01.00.02 Added _MSG_PORT_ENABLE_REPLY structure. + * Added _MSG_EVENT_ACK_REPLY structure. + * Added _MSG_FW_DOWNLOAD_REPLY structure. + * Added _MSG_TOOLBOX_REPLY structure. + * 06-30-00 01.00.03 Added MaxLanBuckets to _PORT_FACT_REPLY structure. + * 07-27-00 01.00.04 Added _EVENT_DATA structure definitions for _SCSI, + * _LINK_STATUS, _LOOP_STATE and _LOGOUT. + * 08-11-00 01.00.05 Switched positions of MsgLength and Function fields in + * _MSG_EVENT_ACK_REPLY structure to match specification. + * 11-02-00 01.01.01 Original release for post 1.0 work + * Added a value for Manufacturer to WhoInit + * 12-04-00 01.01.02 Modified IOCFacts reply, added FWUpload messages, and + * removed toolbox message. + * 01-09-01 01.01.03 Added event enabled and disabled defines. + * Added structures for FwHeader and DataHeader. + * Added ImageType to FwUpload reply. + * 02-20-01 01.01.04 Started using MPI_POINTER. + * 02-27-01 01.01.05 Added event for RAID status change and its event data. + * Added IocNumber field to MSG_IOC_FACTS_REPLY. + * -------------------------------------------------------------------------- + +mpi_cnfg.h + * 05-08-00 00.10.01 Original release for 0.10 spec dated 4/26/2000. + * 06-06-00 01.00.01 Update version number for 1.0 release. + * 06-08-00 01.00.02 Added _PAGEVERSION definitions for all pages. + * Added FcPhLowestVersion, FcPhHighestVersion, Reserved2 + * fields to FC_DEVICE_0 page, updated the page version. + * Changed _FREE_RUNNING_CLOCK to _PACING_TRANSFERS in + * SCSI_PORT_0, SCSI_DEVICE_0 and SCSI_DEVICE_1 pages + * and updated the page versions. + * Added _RESPONSE_ID_MASK definition to SCSI_PORT_1 + * page and updated the page version. + * Added Information field and _INFO_PARAMS_NEGOTIATED + * definitionto SCSI_DEVICE_0 page. + * 06-22-00 01.00.03 Removed batch controls from LAN_0 page and updated the + * page version. + * Added BucketsRemaining to LAN_1 page, redefined the + * state values, and updated the page version. + * Revised bus width definitions in SCSI_PORT_0, + * SCSI_DEVICE_0 and SCSI_DEVICE_1 pages. + * 06-30-00 01.00.04 Added MaxReplySize to LAN_1 page and updated the page + * version. + * Moved FC_DEVICE_0 PageAddress description to spec. + * 07-27-00 01.00.05 Corrected the SubsystemVendorID and SubsystemID field + * widths in IOC_0 page and updated the page version. + * 11-02-00 01.01.01 Original release for post 1.0 work + * Added Manufacturing pages, IO Unit Page 2, SCSI SPI + * Port Page 2, FC Port Page 4, FC Port Page 5 + * 12-04-00 01.01.03 Config page changes to match MPI rev 1.00.01. + * 12-05-00 01.01.04 Modified config page actions. + * 01-09-01 01.01.05 Added defines for page address formats. + * Data size for Manufacturing pages 2 and 3 no longer + * defined here. + * Io Unit Page 2 size is fixed at 4 adapters and some + * flags were changed. + * SCSI Port Page 2 Device Settings modified. + * New fields added to FC Port Page 0 and some flags + * cleaned up. + * Removed impedance flash from FC Port Page 1. + * Added FC Port pages 6 and 7. + * 01-25-01 01.01.06 Added MaxInitiators field to FcPortPage0. + * 01-29-01 01.01.07 Changed some defines to make them 32 character unique. + * Added some LinkType defines for FcPortPage0. + * 02-20-01 01.01.08 Started using MPI_POINTER. + * 02-27-01 01.01.09 Replaced MPI_CONFIG_PAGETYPE_SCSI_LUN with + * MPI_CONFIG_PAGETYPE_RAID_VOLUME. + * Added definitions and structures for IOC Page 2 and + * RAID Volume Page 2. + * -------------------------------------------------------------------------- + +mpi_init.h + * 05-08-00 00.10.01 Original release for 0.10 spec dated 4/26/2000. + * 05-24-00 00.10.02 Added SenseBufferLength to _MSG_SCSI_IO_REPLY. + * 06-06-00 01.00.01 Update version number for 1.0 release. + * 06-08-00 01.00.02 Added MPI_SCSI_RSP_INFO_ definitions. + * 11-02-00 01.01.01 Original release for post 1.0 work + * 12-04-00 01.01.02 Added MPI_SCSIIO_CONTROL_NO_DISCONNECT. + * 02-20-01 01.01.03 Started using MPI_POINTER. + * -------------------------------------------------------------------------- + +mpi_targ.h + * 05-08-00 00.10.01 Original release for 0.10 spec dated 4/26/2000. + * 06-06-00 01.00.01 Update version number for 1.0 release. + * 06-22-00 01.00.02 Added _MSG_TARGET_CMD_BUFFER_POST_REPLY structure. + * Corrected DECSRIPTOR typo to DESCRIPTOR. + * 11-02-00 01.01.01 Original release for post 1.0 work + * Modified target mode to use IoIndex instead of + * HostIndex and IocIndex. Added Alias. + * 01-09-01 01.01.02 Added defines for TARGET_ASSIST_FLAGS_REPOST_CMD_BUFFER + * and TARGET_STATUS_SEND_FLAGS_REPOST_CMD_BUFFER. + * 02-20-01 01.01.03 Started using MPI_POINTER. + * Added structures for MPI_TARGET_SCSI_SPI_CMD_BUFFER and + * MPI_TARGET_FCP_CMD_BUFFER. + * -------------------------------------------------------------------------- + +mpi_fc.h + * 05-08-00 00.10.01 Original release for 0.10 spec dated 4/26/2000. + * 06-06-00 01.00.01 Update version number for 1.0 release. + * 06-12-00 01.00.02 Added _MSG_FC_ABORT_REPLY structure. + * 11-02-00 01.01.01 Original release for post 1.0 work + * 12-04-00 01.01.02 Added messages for Common Transport Send and + * Primitive Send. + * 01-09-01 01.01.03 Modifed some of the new flags to have an MPI prefix + * and modified the FcPrimitiveSend flags. + * 01-25-01 01.01.04 Move InitiatorIndex in LinkServiceRsp reply to a larger + * field. + * Added FC_ABORT_TYPE_CT_SEND_REQUEST and + * FC_ABORT_TYPE_EXLINKSEND_REQUEST for FcAbort request. + * Added MPI_FC_PRIM_SEND_FLAGS_STOP_SEND. + * 02-20-01 01.01.05 Started using MPI_POINTER. + * -------------------------------------------------------------------------- + +mpi_lan.h + * 05-08-00 00.10.01 Original release for 0.10 spec dated 4/26/2000. + * 05-24-00 00.10.02 Added LANStatus field to _MSG_LAN_SEND_REPLY. + * Added LANStatus field to _MSG_LAN_RECEIVE_POST_REPLY. + * Moved ListCount field in _MSG_LAN_RECEIVE_POST_REPLY. + * 06-06-00 01.00.01 Update version number for 1.0 release. + * 06-12-00 01.00.02 Added MPI_ to BUCKETSTATUS_ definitions. + * 06-22-00 01.00.03 Major changes to match new LAN definition in 1.0 spec. + * 06-30-00 01.00.04 Added Context Reply definitions per revised proposal. + * Changed transaction context usage to bucket/buffer. + * 07-05-00 01.00.05 Removed LAN_RECEIVE_POST_BUCKET_CONTEXT_MASK definition + * to lan private header file + * 11-02-00 01.01.01 Original release for post 1.0 work + * 02-20-01 01.01.02 Started using MPI_POINTER. + * -------------------------------------------------------------------------- + +mpi_raid.h + * 02-27-01 01.01.01 Original release for this file. + * -------------------------------------------------------------------------- + +mpi_type.h + * 05-08-00 00.10.01 Original release for 0.10 spec dated 4/26/2000. + * 06-06-00 01.00.01 Update version number for 1.0 release. + * 11-02-00 01.01.01 Original release for post 1.0 work + * 02-20-01 01.01.02 Added define and ifdef for MPI_POINTER. + * -------------------------------------------------------------------------- + +mpi_history.txt Parts list history + +Filename 01.01.08 01.01.07 01.01.06 01.01.05 01.01.04 +---------- -------- -------- -------- -------- -------- +mpi.h 01.01.06 01.01.05 01.01.04 01.01.04 01.01.03 +mpi_ioc.h 01.01.05 01.01.04 01.01.03 01.01.03 01.01.03 +mpi_cnfg.h 01.01.09 01.01.08 01.01.07 01.01.06 01.01.05 +mpi_init.h 01.01.03 01.01.03 01.01.02 01.01.02 01.01.02 +mpi_targ.h 01.01.03 01.01.03 01.01.02 01.01.02 01.01.02 +mpi_fc.h 01.01.05 01.01.05 01.01.04 01.01.04 01.01.03 +mpi_lan.h 01.01.02 01.01.02 01.01.01 01.01.01 01.01.01 +mpi_raid.h 01.01.01 +mpi_type.h 01.01.02 01.01.02 01.01.01 01.01.01 01.01.01 + +Filename 01.01.03 01.01.02 01.01.01 01.00.07 01.00.06 01.00.05 +---------- -------- -------- -------- -------- -------- -------- +mpi.h 01.01.02 01.01.02 01.01.01 01.00.04 01.00.04 01.00.03 +mpi_ioc.h 01.01.02 01.01.02 01.01.01 01.00.05 01.00.04 01.00.03 +mpi_cnfg.h 01.01.04 01.01.03 01.01.01 01.00.05 01.00.05 01.00.04 +mpi_init.h 01.01.02 01.01.02 01.01.01 01.00.02 01.00.02 01.00.02 +mpi_targ.h 01.01.01 01.01.01 01.01.01 01.00.02 01.00.02 01.00.02 +mpi_fc.h 01.01.02 01.01.02 01.01.01 01.00.02 01.00.02 01.00.02 +mpi_lan.h 01.01.01 01.01.01 01.01.01 01.00.05 01.00.05 01.00.05 +mpi_type.h 01.01.01 01.01.01 01.01.01 01.00.01 01.00.01 01.00.01 + +Filename 01.00.04 01.00.03 01.00.02 01.00.01 00.10.02 00.10.01 +---------- -------- -------- -------- -------- -------- -------- +mpi.h 01.00.02 01.00.01 01.00.01 01.00.01 00.10.02 00.10.01 +mpi_ioc.h 01.00.02 01.00.02 01.00.01 01.00.01 00.10.02 00.10.01 +mpi_cnfg.h 01.00.03 01.00.02 01.00.02 01.00.01 00.10.01 00.10.01 +mpi_init.h 01.00.02 01.00.02 01.00.02 01.00.01 00.10.02 00.10.01 +mpi_targ.h 01.00.02 01.00.01 01.00.01 01.00.01 00.10.01 00.10.01 +mpi_fc.h 01.00.02 01.00.02 01.00.01 01.00.01 00.10.01 00.10.01 +mpi_lan.h 01.00.03 01.00.02 01.00.01 01.00.01 00.10.02 00.10.01 +mpi_type.h 01.00.01 01.00.01 01.00.01 01.00.01 00.10.01 00.10.01 + + + * -------------------------------------------------------------------------- + diff -u --recursive --new-file v2.4.6/linux/drivers/message/fusion/lsi/mpi_init.h linux/drivers/message/fusion/lsi/mpi_init.h --- v2.4.6/linux/drivers/message/fusion/lsi/mpi_init.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/message/fusion/lsi/mpi_init.h Fri Jul 6 17:03:11 2001 @@ -0,0 +1,215 @@ +/* + * Copyright (c) 2000-2001 LSI Logic Corporation. + * + * + * Name: MPI_INIT.H + * Title: MPI initiator mode messages and structures + * Creation Date: June 8, 2000 + * + * MPI Version: 01.01.03 + * + * Version History + * --------------- + * + * Date Version Description + * -------- -------- ------------------------------------------------------ + * 05-08-00 00.10.01 Original release for 0.10 spec dated 4/26/2000. + * 05-24-00 00.10.02 Added SenseBufferLength to _MSG_SCSI_IO_REPLY. + * 06-06-00 01.00.01 Update version number for 1.0 release. + * 06-08-00 01.00.02 Added MPI_SCSI_RSP_INFO_ definitions. + * 11-02-00 01.01.01 Original release for post 1.0 work. + * 12-04-00 01.01.02 Added MPI_SCSIIO_CONTROL_NO_DISCONNECT. + * 02-20-01 01.01.03 Started using MPI_POINTER. + * -------------------------------------------------------------------------- + */ + +#ifndef MPI_INIT_H +#define MPI_INIT_H + + +/***************************************************************************** +* +* S C S I I n i t i a t o r M e s s a g e s +* +*****************************************************************************/ + +/****************************************************************************/ +/* SCSI IO messages and assocaited structures */ +/****************************************************************************/ + +typedef struct _MSG_SCSI_IO_REQUEST +{ + U8 TargetID; + U8 Bus; + U8 ChainOffset; + U8 Function; + U8 CDBLength; + U8 SenseBufferLength; + U8 Reserved; + U8 MsgFlags; + U32 MsgContext; + U8 LUN[8]; + U32 Control; + U8 CDB[16]; + U32 DataLength; + U32 SenseBufferLowAddr; + SGE_IO_UNION SGL; +} MSG_SCSI_IO_REQUEST, MPI_POINTER PTR_MSG_SCSI_IO_REQUEST, + SCSIIORequest_t, MPI_POINTER pSCSIIORequest_t; + + +/* SCSIO MsgFlags bits */ + +#define MPI_SCSIIO_MSGFLGS_SENSE_WIDTH (0x01) +#define MPI_SCSIIO_MSGFLGS_SENSE_WIDTH_32 (0x00) +#define MPI_SCSIIO_MSGFLGS_SENSE_WIDTH_64 (0x01) +#define MPI_SCSIIO_MSGFLGS_SENSE_LOCATION (0x02) +#define MPI_SCSIIO_MSGFLGS_SENSE_LOC_HOST (0x00) +#define MPI_SCSIIO_MSGFLGS_SENSE_LOC_IOC (0x02) + +/* SCSIIO LUN fields */ + +#define MPI_SCSIIO_LUN_FIRST_LEVEL_ADDRESSING (0x0000FFFF) +#define MPI_SCSIIO_LUN_SECOND_LEVEL_ADDRESSING (0xFFFF0000) +#define MPI_SCSIIO_LUN_THIRD_LEVEL_ADDRESSING (0x0000FFFF) +#define MPI_SCSIIO_LUN_FOURTH_LEVEL_ADDRESSING (0xFFFF0000) +#define MPI_SCSIIO_LUN_LEVEL_1_WORD (0xFF00) +#define MPI_SCSIIO_LUN_LEVEL_1_DWORD (0x0000FF00) + +/* SCSIO Control bits */ + +#define MPI_SCSIIO_CONTROL_DATADIRECTION_MASK (0x03000000) +#define MPI_SCSIIO_CONTROL_NODATATRANSFER (0x00000000) +#define MPI_SCSIIO_CONTROL_WRITE (0x01000000) +#define MPI_SCSIIO_CONTROL_READ (0x02000000) + +#define MPI_SCSIIO_CONTROL_ADDCDBLEN_MASK (0x3C000000) +#define MPI_SCSIIO_CONTROL_ADDCDBLEN_SHIFT (26) + +#define MPI_SCSIIO_CONTROL_TASKATTRIBUTE_MASK (0x00000700) +#define MPI_SCSIIO_CONTROL_SIMPLEQ (0x00000000) +#define MPI_SCSIIO_CONTROL_HEADOFQ (0x00000100) +#define MPI_SCSIIO_CONTROL_ORDEREDQ (0x00000200) +#define MPI_SCSIIO_CONTROL_ACAQ (0x00000400) +#define MPI_SCSIIO_CONTROL_UNTAGGED (0x00000500) +#define MPI_SCSIIO_CONTROL_NO_DISCONNECT (0x00000700) + +#define MPI_SCSIIO_CONTROL_TASKMANAGE_MASK (0x00FF0000) +#define MPI_SCSIIO_CONTROL_OBSOLETE (0x00800000) +#define MPI_SCSIIO_CONTROL_CLEAR_ACA_RSV (0x00400000) +#define MPI_SCSIIO_CONTROL_TARGET_RESET (0x00200000) +#define MPI_SCSIIO_CONTROL_LUN_RESET_RSV (0x00100000) +#define MPI_SCSIIO_CONTROL_RESERVED (0x00080000) +#define MPI_SCSIIO_CONTROL_CLR_TASK_SET_RSV (0x00040000) +#define MPI_SCSIIO_CONTROL_ABORT_TASK_SET (0x00020000) +#define MPI_SCSIIO_CONTROL_RESERVED2 (0x00010000) + + +/* SCSIIO reply structure */ +typedef struct _MSG_SCSI_IO_REPLY +{ + U8 TargetID; + U8 Bus; + U8 MsgLength; + U8 Function; + U8 CDBLength; + U8 SenseBufferLength; + U8 Reserved; + U8 MsgFlags; + U32 MsgContext; + U8 SCSIStatus; + U8 SCSIState; + U16 IOCStatus; + U32 IOCLogInfo; + U32 TransferCount; + U32 SenseCount; + U32 ResponseInfo; +} MSG_SCSI_IO_REPLY, MPI_POINTER PTR_MSG_SCSI_IO_REPLY, + SCSIIOReply_t, MPI_POINTER pSCSIIOReply_t; + + +/* SCSIIO Reply SCSIStatus values (SAM-2 status codes) */ + +#define MPI_SCSI_STATUS_SUCCESS (0x00) +#define MPI_SCSI_STATUS_CHECK_CONDITION (0x02) +#define MPI_SCSI_STATUS_CONDITION_MET (0x04) +#define MPI_SCSI_STATUS_BUSY (0x08) +#define MPI_SCSI_STATUS_INTERMEDIATE (0x10) +#define MPI_SCSI_STATUS_INTERMEDIATE_CONDMET (0x14) +#define MPI_SCSI_STATUS_RESERVATION_CONFLICT (0x18) +#define MPI_SCSI_STATUS_COMMAND_TERMINATED (0x22) +#define MPI_SCSI_STATUS_TASK_SET_FULL (0x28) +#define MPI_SCSI_STATUS_ACA_ACTIVE (0x30) + + +/* SCSIIO Reply SCSIState values */ + +#define MPI_SCSI_STATE_AUTOSENSE_VALID (0x01) +#define MPI_SCSI_STATE_AUTOSENSE_FAILED (0x02) +#define MPI_SCSI_STATE_NO_SCSI_STATUS (0x04) +#define MPI_SCSI_STATE_TERMINATED (0x08) +#define MPI_SCSI_STATE_RESPONSE_INFO_VALID (0x10) + +/* SCSIIO Reply ResponseInfo values */ +/* (FCP-1 RSP_CODE values and SPI-3 Packetized Failure codes) */ + +#define MPI_SCSI_RSP_INFO_FUNCTION_COMPLETE (0x00000000) +#define MPI_SCSI_RSP_INFO_FCP_BURST_LEN_ERROR (0x01000000) +#define MPI_SCSI_RSP_INFO_CMND_FIELDS_INVALID (0x02000000) +#define MPI_SCSI_RSP_INFO_FCP_DATA_RO_ERROR (0x03000000) +#define MPI_SCSI_RSP_INFO_TASK_MGMT_UNSUPPORTED (0x04000000) +#define MPI_SCSI_RSP_INFO_TASK_MGMT_FAILED (0x05000000) +#define MPI_SCSI_RSP_INFO_SPI_LQ_INVALID_TYPE (0x06000000) + + +/****************************************************************************/ +/* SCSI Task Management messages */ +/****************************************************************************/ + +typedef struct _MSG_SCSI_TASK_MGMT +{ + U8 TargetID; + U8 Bus; + U8 ChainOffset; + U8 Function; + U8 Reserved; + U8 TaskType; + U8 Reserved1; + U8 MsgFlags; + U32 MsgContext; + U8 LUN[8]; + U32 Reserved2[7]; + U32 TaskMsgContext; +} MSG_SCSI_TASK_MGMT, MPI_POINTER PTR_SCSI_TASK_MGMT, + SCSITaskMgmt_t, MPI_POINTER pSCSITaskMgmt_t; + +/* TaskType values */ + +#define MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK (0x00000001) +#define MPI_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET (0x00000002) +#define MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET (0x00000003) +#define MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS (0x00000004) + +/* MsgFlags bits */ +#define MPI_SCSITASKMGMT_MSGFLAGS_LIP_RESET_OPTION (0x00000002) + +/* SCSI Task Management Reply */ +typedef struct _MSG_SCSI_TASK_MGMT_REPLY +{ + U8 TargetID; + U8 Bus; + U8 MsgLength; + U8 Function; + U8 Reserved; + U8 TaskType; + U8 Reserved1; + U8 MsgFlags; + U32 MsgContext; + U8 Reserved2[2]; + U16 IOCStatus; + U32 IOCLogInfo; + U32 TerminationCount; +} MSG_SCSI_TASK_MGMT_REPLY, MPI_POINTER PTR_MSG_SCSI_TASK_MGMT_REPLY, + SCSITaskMgmtReply_t, MPI_POINTER pSCSITaskMgmtReply_t; + +#endif diff -u --recursive --new-file v2.4.6/linux/drivers/message/fusion/lsi/mpi_ioc.h linux/drivers/message/fusion/lsi/mpi_ioc.h --- v2.4.6/linux/drivers/message/fusion/lsi/mpi_ioc.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/message/fusion/lsi/mpi_ioc.h Fri Jul 6 17:03:11 2001 @@ -0,0 +1,583 @@ +/* + * Copyright (c) 2000-2001 LSI Logic Corporation. + * + * + * Name: MPI_IOC.H + * Title: MPI IOC, Port, Event, FW Load, and ToolBox messages + * Creation Date: August 11, 2000 + * + * MPI Version: 01.01.05 + * + * Version History + * --------------- + * + * Date Version Description + * -------- -------- ------------------------------------------------------ + * 05-08-00 00.10.01 Original release for 0.10 spec dated 4/26/2000. + * 05-24-00 00.10.02 Added _MSG_IOC_INIT_REPLY structure. + * 06-06-00 01.00.01 Added CurReplyFrameSize field to _MSG_IOC_FACTS_REPLY. + * 06-12-00 01.00.02 Added _MSG_PORT_ENABLE_REPLY structure. + * Added _MSG_EVENT_ACK_REPLY structure. + * Added _MSG_FW_DOWNLOAD_REPLY structure. + * Added _MSG_TOOLBOX_REPLY structure. + * 06-30-00 01.00.03 Added MaxLanBuckets to _PORT_FACT_REPLY structure. + * 07-27-00 01.00.04 Added _EVENT_DATA structure definitions for _SCSI, + * _LINK_STATUS, _LOOP_STATE and _LOGOUT. + * 08-11-00 01.00.05 Switched positions of MsgLength and Function fields in + * _MSG_EVENT_ACK_REPLY structure to match specification. + * 11-02-00 01.01.01 Original release for post 1.0 work. + * Added a value for Manufacturer to WhoInit. + * 12-04-00 01.01.02 Modified IOCFacts reply, added FWUpload messages, and + * removed toolbox message. + * 01-09-01 01.01.03 Added event enabled and disabled defines. + * Added structures for FwHeader and DataHeader. + * Added ImageType to FwUpload reply. + * 02-20-01 01.01.04 Started using MPI_POINTER. + * 02-27-01 01.01.05 Added event for RAID status change and its event data. + * Added IocNumber field to MSG_IOC_FACTS_REPLY. + * -------------------------------------------------------------------------- + */ + +#ifndef MPI_IOC_H +#define MPI_IOC_H + + +/***************************************************************************** +* +* I O C M e s s a g e s +* +*****************************************************************************/ + +/****************************************************************************/ +/* IOCInit message */ +/****************************************************************************/ + +typedef struct _MSG_IOC_INIT +{ + U8 WhoInit; + U8 Reserved; + U8 ChainOffset; + U8 Function; + U8 Flags; + U8 MaxDevices; + U8 MaxBuses; + U8 MsgFlags; + U32 MsgContext; + U16 ReplyFrameSize; + U8 Reserved1[2]; + U32 HostMfaHighAddr; + U32 SenseBufferHighAddr; +} MSG_IOC_INIT, MPI_POINTER PTR_MSG_IOC_INIT, + IOCInit_t, MPI_POINTER pIOCInit_t; + +typedef struct _MSG_IOC_INIT_REPLY +{ + U8 WhoInit; + U8 Reserved; + U8 MsgLength; + U8 Function; + U8 Flags; + U8 MaxDevices; + U8 MaxBuses; + U8 MsgFlags; + U32 MsgContext; + U16 Reserved2; + U16 IOCStatus; + U32 IOCLogInfo; +} MSG_IOC_INIT_REPLY, MPI_POINTER PTR_MSG_IOC_INIT_REPLY, + IOCInitReply_t, MPI_POINTER pIOCInitReply_t; + +/* WhoInit values */ + +#define MPI_WHOINIT_NO_ONE (0x00) +#define MPI_WHOINIT_SYSTEM_BIOS (0x01) +#define MPI_WHOINIT_ROM_BIOS (0x02) +#define MPI_WHOINIT_PCI_PEER (0x03) +#define MPI_WHOINIT_HOST_DRIVER (0x04) +#define MPI_WHOINIT_MANUFACTURER (0x05) + + +/****************************************************************************/ +/* IOC Facts message */ +/****************************************************************************/ + +typedef struct _MSG_IOC_FACTS +{ + U8 Reserved[2]; + U8 ChainOffset; + U8 Function; + U8 Reserved1[3]; + U8 MsgFlags; + U32 MsgContext; +} MSG_IOC_FACTS, MPI_POINTER PTR_IOC_FACTS, + IOCFacts_t, MPI_POINTER pIOCFacts_t; + +/* IOC Facts Reply */ + +typedef struct _MSG_IOC_FACTS_REPLY +{ + U16 MsgVersion; + U8 MsgLength; + U8 Function; + U16 Reserved; + U8 IOCNumber; + U8 MsgFlags; + U32 MsgContext; + U16 Reserved2; + U16 IOCStatus; + U32 IOCLogInfo; + U8 MaxChainDepth; + U8 WhoInit; + U8 BlockSize; + U8 Flags; + U16 ReplyQueueDepth; + U16 RequestFrameSize; + U16 FWVersion; + U16 ProductID; + U32 CurrentHostMfaHighAddr; + U16 GlobalCredits; + U8 NumberOfPorts; + U8 EventState; + U32 CurrentSenseBufferHighAddr; + U16 CurReplyFrameSize; + U8 MaxDevices; + U8 MaxBuses; + U32 FWImageSize; + U32 DataImageSize; +} MSG_IOC_FACTS_REPLY, MPI_POINTER PTR_MSG_IOC_FACTS_REPLY, + IOCFactsReply_t, MPI_POINTER pIOCFactsReply_t; + +#define MPI_IOCFACTS_MSGVERSION_MAJOR_MASK (0xFF00) +#define MPI_IOCFACTS_MSGVERSION_MINOR_MASK (0x00FF) + +#define MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT (0x01) +#define MPI_IOCFACTS_FLAGS_DATA_IMAGE_UPLOAD (0x02) + +#define MPI_IOCFACTS_EVENTSTATE_DISABLED (0x00) +#define MPI_IOCFACTS_EVENTSTATE_ENABLED (0x01) + + + +/***************************************************************************** +* +* P o r t M e s s a g e s +* +*****************************************************************************/ + +/****************************************************************************/ +/* Port Facts message and Reply */ +/****************************************************************************/ + +typedef struct _MSG_PORT_FACTS +{ + U8 Reserved[2]; + U8 ChainOffset; + U8 Function; + U8 Reserved1[2]; + U8 PortNumber; + U8 MsgFlags; + U32 MsgContext; +} MSG_PORT_FACTS, MPI_POINTER PTR_MSG_PORT_FACTS, + PortFacts_t, MPI_POINTER pPortFacts_t; + +typedef struct _MSG_PORT_FACTS_REPLY +{ + U16 Reserved; + U8 MsgLength; + U8 Function; + U16 Reserved1; + U8 PortNumber; + U8 MsgFlags; + U32 MsgContext; + U16 Reserved2; + U16 IOCStatus; + U32 IOCLogInfo; + U8 Reserved3; + U8 PortType; + U16 MaxDevices; + U16 PortSCSIID; + U16 ProtocolFlags; + U16 MaxPostedCmdBuffers; + U16 MaxPersistentIDs; + U16 MaxLanBuckets; + U16 Reserved4; + U32 Reserved5; +} MSG_PORT_FACTS_REPLY, MPI_POINTER PTR_MSG_PORT_FACTS_REPLY, + PortFactsReply_t, MPI_POINTER pPortFactsReply_t; + + +/* PortTypes values */ + +#define MPI_PORTFACTS_PORTTYPE_INACTIVE (0x00) +#define MPI_PORTFACTS_PORTTYPE_SCSI (0x01) +#define MPI_PORTFACTS_PORTTYPE_FC (0x10) + +/* ProtocolFlags values */ + +#define MPI_PORTFACTS_PROTOCOL_LOGBUSADDR (0x01) +#define MPI_PORTFACTS_PROTOCOL_LAN (0x02) +#define MPI_PORTFACTS_PROTOCOL_TARGET (0x04) +#define MPI_PORTFACTS_PROTOCOL_INITIATOR (0x08) + + +/****************************************************************************/ +/* Port Enable Message */ +/****************************************************************************/ + +typedef struct _MSG_PORT_ENABLE +{ + U8 Reserved[2]; + U8 ChainOffset; + U8 Function; + U8 Reserved1[2]; + U8 PortNumber; + U8 MsgFlags; + U32 MsgContext; +} MSG_PORT_ENABLE, MPI_POINTER PTR_MSG_PORT_ENABLE, + PortEnable_t, MPI_POINTER pPortEnable_t; + +typedef struct _MSG_PORT_ENABLE_REPLY +{ + U8 Reserved[2]; + U8 MsgLength; + U8 Function; + U8 Reserved1[2]; + U8 PortNumber; + U8 MsgFlags; + U32 MsgContext; + U16 Reserved2; + U16 IOCStatus; + U32 IOCLogInfo; +} MSG_PORT_ENABLE_REPLY, MPI_POINTER PTR_MSG_PORT_ENABLE_REPLY, + PortEnableReply_t, MPI_POINTER pPortEnableReply_t; + + +/***************************************************************************** +* +* E v e n t M e s s a g e s +* +*****************************************************************************/ + +/****************************************************************************/ +/* Event Notification messages */ +/****************************************************************************/ + +typedef struct _MSG_EVENT_NOTIFY +{ + U8 Switch; + U8 Reserved; + U8 ChainOffset; + U8 Function; + U8 Reserved1[3]; + U8 MsgFlags; + U32 MsgContext; +} MSG_EVENT_NOTIFY, MPI_POINTER PTR_MSG_EVENT_NOTIFY, + EventNotification_t, MPI_POINTER pEventNotification_t; + +/* Event Notification Reply */ + +typedef struct _MSG_EVENT_NOTIFY_REPLY +{ + U16 EventDataLength; + U8 MsgLength; + U8 Function; + U8 Reserved1[2]; + U8 AckRequired; + U8 MsgFlags; + U32 MsgContext; + U8 Reserved2[2]; + U16 IOCStatus; + U32 IOCLogInfo; + U32 Event; + U32 EventContext; + U32 Data[1]; +} MSG_EVENT_NOTIFY_REPLY, MPI_POINTER PTR_MSG_EVENT_NOTIFY_REPLY, + EventNotificationReply_t, MPI_POINTER pEventNotificationReply_t; + +/* Event Acknowledge */ + +typedef struct _MSG_EVENT_ACK +{ + U8 Reserved[2]; + U8 ChainOffset; + U8 Function; + U8 Reserved1[3]; + U8 MsgFlags; + U32 MsgContext; + U32 Event; + U32 EventContext; +} MSG_EVENT_ACK, MPI_POINTER PTR_MSG_EVENT_ACK, + EventAck_t, MPI_POINTER pEventAck_t; + +typedef struct _MSG_EVENT_ACK_REPLY +{ + U8 Reserved[2]; + U8 MsgLength; + U8 Function; + U8 Reserved1[3]; + U8 MsgFlags; + U32 MsgContext; + U16 Reserved2; + U16 IOCStatus; + U32 IOCLogInfo; +} MSG_EVENT_ACK_REPLY, MPI_POINTER PTR_MSG_EVENT_ACK_REPLY, + EventAckReply_t, MPI_POINTER pEventAckReply_t; + + +/* Switch */ + +#define MPI_EVENT_NOTIFICATION_SWITCH_OFF (0x00) +#define MPI_EVENT_NOTIFICATION_SWITCH_ON (0x01) + +/* Event */ + +#define MPI_EVENT_NONE (0x00000000) +#define MPI_EVENT_LOG_DATA (0x00000001) +#define MPI_EVENT_STATE_CHANGE (0x00000002) +#define MPI_EVENT_UNIT_ATTENTION (0x00000003) +#define MPI_EVENT_IOC_BUS_RESET (0x00000004) +#define MPI_EVENT_EXT_BUS_RESET (0x00000005) +#define MPI_EVENT_RESCAN (0x00000006) +#define MPI_EVENT_LINK_STATUS_CHANGE (0x00000007) +#define MPI_EVENT_LOOP_STATE_CHANGE (0x00000008) +#define MPI_EVENT_LOGOUT (0x00000009) +#define MPI_EVENT_EVENT_CHANGE (0x0000000A) +#define MPI_EVENT_RAID_STATUS_CHANGE (0x0000000B) + +/* AckRequired field values */ + +#define MPI_EVENT_NOTIFICATION_ACK_NOT_REQUIRED (0x00) +#define MPI_EVENT_NOTIFICATION_ACK_REQUIRED (0x01) + +/* SCSI Event data for Port, Bus and Device forms) */ + +typedef struct _EVENT_DATA_SCSI +{ + U8 TargetID; + U8 BusPort; + U16 Reserved; +} EVENT_DATA_SCSI, MPI_POINTER PTR_EVENT_DATA_SCSI, + EventDataScsi_t, MPI_POINTER pEventDataScsi_t; + +/* MPI Link Status Change Event data */ + +typedef struct _EVENT_DATA_LINK_STATUS +{ + U8 State; + U8 Reserved; + U16 Reserved1; + U8 Reserved2; + U8 Port; + U16 Reserved3; +} EVENT_DATA_LINK_STATUS, MPI_POINTER PTR_EVENT_DATA_LINK_STATUS, + EventDataLinkStatus_t, MPI_POINTER pEventDataLinkStatus_t; + +#define MPI_EVENT_LINK_STATUS_FAILURE (0x00000000) +#define MPI_EVENT_LINK_STATUS_ACTIVE (0x00000001) + +/* MPI Loop State Change Event data */ + +typedef struct _EVENT_DATA_LOOP_STATE +{ + U8 Character4; + U8 Character3; + U8 Type; + U8 Reserved; + U8 Reserved1; + U8 Port; + U16 Reserved2; +} EVENT_DATA_LOOP_STATE, MPI_POINTER PTR_EVENT_DATA_LOOP_STATE, + EventDataLoopState_t, MPI_POINTER pEventDataLoopState_t; + +#define MPI_EVENT_LOOP_STATE_CHANGE_LIP (0x0001) +#define MPI_EVENT_LOOP_STATE_CHANGE_LPE (0x0002) +#define MPI_EVENT_LOOP_STATE_CHANGE_LPB (0x0003) + +/* MPI LOGOUT Event data */ + +typedef struct _EVENT_DATA_LOGOUT +{ + U32 NPortID; + U8 Reserved; + U8 Port; + U16 Reserved1; +} EVENT_DATA_LOGOUT, MPI_POINTER PTR_EVENT_DATA_LOGOUT, + EventDataLogout_t, MPI_POINTER pEventDataLogout_t; + +/* MPI RAID Status Change Event data */ + +typedef struct _EVENT_DATA_RAID_STATUS_CHANGE +{ + U8 VolumeTargetID; + U8 VolumeBus; + U8 ReasonCode; + U8 PhysDiskNum; + U8 ASC; + U8 ASCQ; + U16 Reserved; +} EVENT_DATA_RAID_STATUS_CHANGE, MPI_POINTER PTR_EVENT_DATA_RAID_STATUS_CHANGE, + MpiEventDataRaidStatusChange_t, MPI_POINTER pMpiEventDataRaidStatusChange_t; + + +/* MPI RAID Status Change Event data ReasonCode values */ + +#define MPI_EVENT_RAID_DATA_RC_VOLUME_OPTIMAL (0x00) +#define MPI_EVENT_RAID_DATA_RC_VOLUME_DEGRADED (0x01) +#define MPI_EVENT_RAID_DATA_RC_STARTED_RESYNC (0x02) +#define MPI_EVENT_RAID_DATA_RC_DISK_ADDED (0x03) +#define MPI_EVENT_RAID_DATA_RC_DISK_NOT_RESPONDING (0x04) +#define MPI_EVENT_RAID_DATA_RC_SMART_DATA (0x05) + + +/***************************************************************************** +* +* F i r m w a r e L o a d M e s s a g e s +* +*****************************************************************************/ + +/****************************************************************************/ +/* Firmware Download message and associated structures */ +/****************************************************************************/ + +typedef struct _MSG_FW_DOWNLOAD +{ + U8 ImageType; + U8 Reserved; + U8 ChainOffset; + U8 Function; + U8 Reserved1[3]; + U8 MsgFlags; + U32 MsgContext; + SGE_MPI_UNION SGL; +} MSG_FW_DOWNLOAD, MPI_POINTER PTR_MSG_FW_DOWNLOAD, + FWDownload_t, MPI_POINTER pFWDownload_t; + +#define MPI_FW_DOWNLOAD_ITYPE_RESERVED (0x00) +#define MPI_FW_DOWNLOAD_ITYPE_FW (0x01) +#define MPI_FW_DOWNLOAD_ITYPE_BIOS (0x02) + + +typedef struct _FWDownloadTCSGE +{ + U8 Reserved; + U8 ContextSize; + U8 DetailsLength; + U8 Flags; + U32 Reserved1; + U32 ImageOffset; + U32 ImageSize; +} FW_DOWNLOAD_TCSGE, MPI_POINTER PTR_FW_DOWNLOAD_TCSGE, + FWDownloadTCSGE_t, MPI_POINTER pFWDownloadTCSGE_t; + +/* Firmware Download reply */ +typedef struct _MSG_FW_DOWNLOAD_REPLY +{ + U8 ImageType; + U8 Reserved; + U8 MsgLength; + U8 Function; + U8 Reserved1[3]; + U8 MsgFlags; + U32 MsgContext; + U16 Reserved2; + U16 IOCStatus; + U32 IOCLogInfo; +} MSG_FW_DOWNLOAD_REPLY, MPI_POINTER PTR_MSG_FW_DOWNLOAD_REPLY, + FWDownloadReply_t, MPI_POINTER pFWDownloadReply_t; + + +/****************************************************************************/ +/* Firmware Upload message and associated structures */ +/****************************************************************************/ + +typedef struct _MSG_FW_UPLOAD +{ + U8 ImageType; + U8 Reserved; + U8 ChainOffset; + U8 Function; + U8 Reserved1[3]; + U8 MsgFlags; + U32 MsgContext; + SGE_MPI_UNION SGL; +} MSG_FW_UPLOAD, MPI_POINTER PTR_MSG_FW_UPLOAD, + FWUpload_t, MPI_POINTER pFWUpload_t; + +#define MPI_FW_UPLOAD_ITYPE_FW_IOC_MEM (0x00) +#define MPI_FW_UPLOAD_ITYPE_FW_FLASH (0x01) +#define MPI_FW_UPLOAD_ITYPE_BIOS_FLASH (0x02) +#define MPI_FW_UPLOAD_ITYPE_DATA_IOC_MEM (0x03) + +typedef struct _FWUploadTCSGE +{ + U8 Reserved; + U8 ContextSize; + U8 DetailsLength; + U8 Flags; + U32 Reserved1; + U32 ImageOffset; + U32 ImageSize; +} FW_UPLOAD_TCSGE, MPI_POINTER PTR_FW_UPLOAD_TCSGE, + FWUploadTCSGE_t, MPI_POINTER pFWUploadTCSGE_t; + +/* Firmware Upload reply */ +typedef struct _MSG_FW_UPLOAD_REPLY +{ + U8 ImageType; + U8 Reserved; + U8 MsgLength; + U8 Function; + U8 Reserved1[3]; + U8 MsgFlags; + U32 MsgContext; + U16 Reserved2; + U16 IOCStatus; + U32 IOCLogInfo; + U32 ActualImageSize; +} MSG_FW_UPLOAD_REPLY, MPI_POINTER PTR_MSG_FW_UPLOAD_REPLY, + FWUploadReply_t, MPI_POINTER pFWUploadReply_t; + + +typedef struct _MPI_FW_HEADER +{ + U32 ArmBranchInstruction0; + U32 Signature0; + U32 Signature1; + U32 Signature2; + U32 ArmBranchInstruction1; + U32 ArmBranchInstruction2; + U32 Reserved; + U32 Checksum; + U16 VendorId; + U16 ProductId; + U16 FwVersion; + U16 Reserved1; + U32 SeqCodeVersion; + U32 ImageSize; + U32 Reserved2; + U32 LoadStartAddress; + U32 IopResetVectorValue; + U32 IopResetRegAddr; + U32 VersionNameWhat; + U8 VersionName[32]; + U32 VendorNameWhat; + U8 VendorName[32]; +} MPI_FW_HEADER, MPI_POINTER PTR_MPI_FW_HEADER, + MpiFwHeader_t, MPI_POINTER pMpiFwHeader_t; + +#define MPI_FW_HEADER_WHAT_SIGNATURE (0x29232840) + + +typedef struct _MPI_DATA_HEADER +{ + U32 Signature; + U16 FunctionNumber; + U16 Length; + U32 Checksum; + U32 LoadStartAddress; +} MPI_DATA_HEADER, MPI_POINTER PTR_MPI_DATA_HEADER, + MpiDataHeader_t, MPI_POINTER pMpiDataHeader_t; + +#define MPI_DATA_HEADER_SIGNATURE (0x43504147) + +#endif diff -u --recursive --new-file v2.4.6/linux/drivers/message/fusion/lsi/mpi_lan.h linux/drivers/message/fusion/lsi/mpi_lan.h --- v2.4.6/linux/drivers/message/fusion/lsi/mpi_lan.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/message/fusion/lsi/mpi_lan.h Fri Jul 6 17:03:11 2001 @@ -0,0 +1,204 @@ +/* + * Copyright (c) 2000-2001 LSI Logic Corporation. + * + * + * Name: MPI_LAN.H + * Title: MPI LAN messages and structures + * Creation Date: June 30, 2000 + * + * MPI Version: 01.01.02 + * + * Version History + * --------------- + * + * Date Version Description + * -------- -------- ------------------------------------------------------ + * 05-08-00 00.10.01 Original release for 0.10 spec dated 4/26/2000. + * 05-24-00 00.10.02 Added LANStatus field to _MSG_LAN_SEND_REPLY. + * Added LANStatus field to _MSG_LAN_RECEIVE_POST_REPLY. + * Moved ListCount field in _MSG_LAN_RECEIVE_POST_REPLY. + * 06-06-00 01.00.01 Update version number for 1.0 release. + * 06-12-00 01.00.02 Added MPI_ to BUCKETSTATUS_ definitions. + * 06-22-00 01.00.03 Major changes to match new LAN definition in 1.0 spec. + * 06-30-00 01.00.04 Added Context Reply definitions per revised proposal. + * Changed transaction context usage to bucket/buffer. + * 07-05-00 01.00.05 Removed LAN_RECEIVE_POST_BUCKET_CONTEXT_MASK definition + * to lan private header file + * 11-02-00 01.01.01 Original release for post 1.0 work + * 02-20-01 01.01.02 Started using MPI_POINTER. + * -------------------------------------------------------------------------- + */ + +#ifndef MPI_LAN_H +#define MPI_LAN_H + + +/****************************************************************************** +* +* L A N M e s s a g e s +* +*******************************************************************************/ + +/* LANSend messages */ + +typedef struct _MSG_LAN_SEND_REQUEST +{ + U16 Reserved; + U8 ChainOffset; + U8 Function; + U16 Reserved2; + U8 PortNumber; + U8 MsgFlags; + U32 MsgContext; + SGE_MPI_UNION SG_List[1]; +} MSG_LAN_SEND_REQUEST, MPI_POINTER PTR_MSG_LAN_SEND_REQUEST, + LANSendRequest_t, MPI_POINTER pLANSendRequest_t; + + +typedef struct _MSG_LAN_SEND_REPLY +{ + U16 Reserved; + U8 MsgLength; + U8 Function; + U8 Reserved2; + U8 NumberOfContexts; + U8 PortNumber; + U8 MsgFlags; + U32 MsgContext; + U16 Reserved3; + U16 IOCStatus; + U32 IOCLogInfo; + U32 BufferContext; +} MSG_LAN_SEND_REPLY, MPI_POINTER PTR_MSG_LAN_SEND_REPLY, + LANSendReply_t, MPI_POINTER pLANSendReply_t; + + +/* LANReceivePost */ + +typedef struct _MSG_LAN_RECEIVE_POST_REQUEST +{ + U16 Reserved; + U8 ChainOffset; + U8 Function; + U16 Reserved2; + U8 PortNumber; + U8 MsgFlags; + U32 MsgContext; + U32 BucketCount; + SGE_MPI_UNION SG_List[1]; +} MSG_LAN_RECEIVE_POST_REQUEST, MPI_POINTER PTR_MSG_LAN_RECEIVE_POST_REQUEST, + LANReceivePostRequest_t, MPI_POINTER pLANReceivePostRequest_t; + + +typedef struct _MSG_LAN_RECEIVE_POST_REPLY +{ + U16 Reserved; + U8 MsgLength; + U8 Function; + U8 Reserved2; + U8 NumberOfContexts; + U8 PortNumber; + U8 MsgFlags; + U32 MsgContext; + U16 Reserved3; + U16 IOCStatus; + U32 IOCLogInfo; + U32 BucketsRemaining; + U32 PacketOffset; + U32 PacketLength; + U32 BucketContext[1]; +} MSG_LAN_RECEIVE_POST_REPLY, MPI_POINTER PTR_MSG_LAN_RECEIVE_POST_REPLY, + LANReceivePostReply_t, MPI_POINTER pLANReceivePostReply_t; + + +/* LANReset */ + +typedef struct _MSG_LAN_RESET_REQUEST +{ + U16 Reserved; + U8 ChainOffset; + U8 Function; + U16 Reserved2; + U8 PortNumber; + U8 MsgFlags; + U32 MsgContext; +} MSG_LAN_RESET_REQUEST, MPI_POINTER PTR_MSG_LAN_RESET_REQUEST, + LANResetRequest_t, MPI_POINTER pLANResetRequest_t; + + +typedef struct _MSG_LAN_RESET_REPLY +{ + U16 Reserved; + U8 MsgLength; + U8 Function; + U16 Reserved2; + U8 PortNumber; + U8 MsgFlags; + U32 MsgContext; + U16 Reserved3; + U16 IOCStatus; + U32 IOCLogInfo; +} MSG_LAN_RESET_REPLY, MPI_POINTER PTR_MSG_LAN_RESET_REPLY, + LANResetReply_t, MPI_POINTER pLANResetReply_t; + + +/****************************************************************************/ +/* LAN Context Reply defines and macros */ +/****************************************************************************/ + +#define LAN_REPLY_PACKET_LENGTH_MASK (0x0000FFFF) +#define LAN_REPLY_PACKET_LENGTH_SHIFT (0) +#define LAN_REPLY_BUCKET_CONTEXT_MASK (0x07FF0000) +#define LAN_REPLY_BUCKET_CONTEXT_SHIFT (16) +#define LAN_REPLY_BUFFER_CONTEXT_MASK (0x07FFFFFF) +#define LAN_REPLY_BUFFER_CONTEXT_SHIFT (0) +#define LAN_REPLY_FORM_MASK (0x18000000) +#define LAN_REPLY_FORM_RECEIVE_SINGLE (0x00) +#define LAN_REPLY_FORM_RECEIVE_MULTIPLE (0x01) +#define LAN_REPLY_FORM_SEND_SINGLE (0x02) +#define LAN_REPLY_FORM_MESSAGE_CONTEXT (0x03) +#define LAN_REPLY_FORM_SHIFT (27) + +#define GET_LAN_PACKET_LENGTH(x) (((x) & LAN_REPLY_PACKET_LENGTH_MASK) \ + >> LAN_REPLY_PACKET_LENGTH_SHIFT) + +#define SET_LAN_PACKET_LENGTH(x, lth) \ + ((x) = ((x) & ~LAN_REPLY_PACKET_LENGTH_MASK) | \ + (((lth) << LAN_REPLY_PACKET_LENGTH_SHIFT) & \ + LAN_REPLY_PACKET_LENGTH_MASK)) + +#define GET_LAN_BUCKET_CONTEXT(x) (((x) & LAN_REPLY_BUCKET_CONTEXT_MASK) \ + >> LAN_REPLY_BUCKET_CONTEXT_SHIFT) + +#define SET_LAN_BUCKET_CONTEXT(x, ctx) \ + ((x) = ((x) & ~LAN_REPLY_BUCKET_CONTEXT_MASK) | \ + (((ctx) << LAN_REPLY_BUCKET_CONTEXT_SHIFT) & \ + LAN_REPLY_BUCKET_CONTEXT_MASK)) + +#define GET_LAN_BUFFER_CONTEXT(x) (((x) & LAN_REPLY_BUFFER_CONTEXT_MASK) \ + >> LAN_REPLY_BUFFER_CONTEXT_SHIFT) + +#define SET_LAN_BUFFER_CONTEXT(x, ctx) \ + ((x) = ((x) & ~LAN_REPLY_BUFFER_CONTEXT_MASK) | \ + (((ctx) << LAN_REPLY_BUFFER_CONTEXT_SHIFT) & \ + LAN_REPLY_BUFFER_CONTEXT_MASK)) + +#define GET_LAN_FORM(x) (((x) & LAN_REPLY_FORM_MASK) \ + >> LAN_REPLY_FORM_SHIFT) + +#define SET_LAN_FORM(x, frm) \ + ((x) = ((x) & ~LAN_REPLY_FORM_MASK) | \ + (((frm) << LAN_REPLY_FORM_SHIFT) & \ + LAN_REPLY_FORM_MASK)) + + +/****************************************************************************/ +/* LAN Current Device State defines */ +/****************************************************************************/ + +#define MPI_LAN_DEVICE_STATE_RESET (0x00) +#define MPI_LAN_DEVICE_STATE_OPERATIONAL (0x01) + + +#endif + diff -u --recursive --new-file v2.4.6/linux/drivers/message/fusion/lsi/mpi_targ.h linux/drivers/message/fusion/lsi/mpi_targ.h --- v2.4.6/linux/drivers/message/fusion/lsi/mpi_targ.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/message/fusion/lsi/mpi_targ.h Fri Jul 6 17:03:11 2001 @@ -0,0 +1,328 @@ +/* + * Copyright (c) 2000-2001 LSI Logic Corporation. + * + * + * Name: MPI_TARG.H + * Title: MPI Target mode messages and structures + * Creation Date: June 22, 2000 + * + * MPI Version: 01.01.03 + * + * Version History + * --------------- + * + * Date Version Description + * -------- -------- ------------------------------------------------------ + * 05-08-00 00.10.01 Original release for 0.10 spec dated 4/26/2000. + * 06-06-00 01.00.01 Update version number for 1.0 release. + * 06-22-00 01.00.02 Added _MSG_TARGET_CMD_BUFFER_POST_REPLY structure. + * Corrected DECSRIPTOR typo to DESCRIPTOR. + * 11-02-00 01.01.01 Original release for post 1.0 work + * Modified target mode to use IoIndex instead of + * HostIndex and IocIndex. Added Alias. + * 01-09-01 01.01.02 Added defines for TARGET_ASSIST_FLAGS_REPOST_CMD_BUFFER + * and TARGET_STATUS_SEND_FLAGS_REPOST_CMD_BUFFER. + * 02-20-01 01.01.03 Started using MPI_POINTER. + * Added structures for MPI_TARGET_SCSI_SPI_CMD_BUFFER and + * MPI_TARGET_FCP_CMD_BUFFER. + * -------------------------------------------------------------------------- + */ + +#ifndef MPI_TARG_H +#define MPI_TARG_H + + +/****************************************************************************** +* +* S C S I T a r g e t M e s s a g e s +* +*******************************************************************************/ + +typedef struct _CMD_BUFFER_DESCRIPTOR +{ + U16 IoIndex; + U16 Reserved; + union + { + U32 PhysicalAddress32; + U64 PhysicalAddress64; + } u; +} CMD_BUFFER_DESCRIPTOR, MPI_POINTER PTR_CMD_BUFFER_DESCRIPTOR, + CmdBufferDescriptor_t, MPI_POINTER pCmdBufferDescriptor_t; + + +/****************************************************************************/ +/* Target Command Buffer Post Request */ +/****************************************************************************/ + +typedef struct _MSG_TARGET_CMD_BUFFER_POST_REQUEST +{ + U8 BufferPostFlags; + U8 BufferCount; + U8 ChainOffset; + U8 Function; + U8 BufferLength; + U8 Reserved; + U8 Reserved1; + U8 MsgFlags; + U32 MsgContext; + CMD_BUFFER_DESCRIPTOR Buffer[1]; +} MSG_TARGET_CMD_BUFFER_POST_REQUEST, MPI_POINTER PTR_MSG_TARGET_CMD_BUFFER_POST_REQUEST, + TargetCmdBufferPostRequest_t, MPI_POINTER pTargetCmdBufferPostRequest_t; + +#define CMD_BUFFER_POST_FLAGS_PORT_MASK (0x01) +#define CMD_BUFFER_POST_FLAGS_ADDR_MODE_MASK (0x80) +#define CMD_BUFFER_POST_FLAGS_ADDR_MODE_32 (0) +#define CMD_BUFFER_POST_FLAGS_ADDR_MODE_64 (1) +#define CMD_BUFFER_POST_FLAGS_64_BIT_ADDR (0x80) + +#define CMD_BUFFER_POST_IO_INDEX_MASK (0x00003FFF) + + +typedef struct _MSG_TARGET_CMD_BUFFER_POST_REPLY +{ + U8 BufferPostFlags; + U8 BufferCount; + U8 MsgLength; + U8 Function; + U8 BufferLength; + U8 Reserved; + U8 Reserved1; + U8 MsgFlags; + U32 MsgContext; + U16 Reserved2; + U16 IOCStatus; + U32 IOCLogInfo; +} MSG_TARGET_CMD_BUFFER_POST_REPLY, MPI_POINTER PTR_MSG_TARGET_CMD_BUFFER_POST_REPLY, + TargetCmdBufferPostReply_t, MPI_POINTER pTargetCmdBufferPostReply_t; + + +typedef struct _MSG_PRIORITY_CMD_RECEIVED_REPLY +{ + U16 Reserved; + U8 MsgLength; + U8 Function; + U16 Reserved1; + U8 Reserved2; + U8 MsgFlags; + U32 MsgContext; + U8 PriorityReason; + U8 Reserved3; + U16 IOCStatus; + U32 IOCLogInfo; + U32 ReplyWord; +} MSG_PRIORITY_CMD_RECEIVED_REPLY, MPI_POINTER PTR_MSG_PRIORITY_CMD_RECEIVED_REPLY, + PriorityCommandReceivedReply_t, MPI_POINTER pPriorityCommandReceivedReply_t; + +#define PRIORITY_REASON_NO_DISCONNECT (0x00) +#define PRIORITY_REASON_SCSI_TASK_MANAGEMENT (0x01) +#define PRIORITY_REASON_UNKNOWN (0xFF) + + +typedef struct _MSG_TARGET_CMD_BUFFER_POST_ERROR_REPLY +{ + U16 Reserved; + U8 MsgLength; + U8 Function; + U16 Reserved1; + U8 Reserved2; + U8 MsgFlags; + U32 MsgContext; + U16 Reserved3; + U16 IOCStatus; + U32 IOCLogInfo; + U32 ReplyWord; +} MSG_TARGET_CMD_BUFFER_POST_ERROR_REPLY, + MPI_POINTER PTR_MSG_TARGET_CMD_BUFFER_POST_ERROR_REPLY, + TargetCmdBufferPostErrorReply_t, MPI_POINTER pTargetCmdBufferPostErrorReply_t; + + +typedef struct _MPI_TARGET_FCP_CMD_BUFFER +{ + U8 FcpLun[8]; + U8 FcpCntl[4]; + U8 FcpCdb[16]; + U32 FcpDl; +} MPI_TARGET_FCP_CMD_BUFFER, MPI_POINTER PTR_MPI_TARGET_FCP_CMD_BUFFER, + MpiTargetFcpCmdBuffer, MPI_POINTER pMpiTargetFcpCmdBuffer; + + +typedef struct _MPI_TARGET_SCSI_SPI_CMD_BUFFER +{ + /* SPI L_Q information unit */ + U8 L_QType; + U8 Reserved; + U16 Tag; + U8 LogicalUnitNumber[8]; + U32 DataLength; + /* SPI command information unit */ + U8 ReservedFirstByteOfCommandIU; + U8 TaskAttribute; + U8 TaskManagementFlags; + U8 AdditionalCDBLength; + U8 CDB[16]; +} MPI_TARGET_SCSI_SPI_CMD_BUFFER, + MPI_POINTER PTR_MPI_TARGET_SCSI_SPI_CMD_BUFFER, + MpiTargetScsiSpiCmdBuffer, MPI_POINTER pMpiTargetScsiSpiCmdBuffer; + + +/****************************************************************************/ +/* Target Assist Request */ +/****************************************************************************/ + +typedef struct _MSG_TARGET_ASSIST_REQUEST +{ + U8 StatusCode; + U8 TargetAssistFlags; + U8 ChainOffset; + U8 Function; + U16 QueueTag; + U8 Reserved; + U8 MsgFlags; + U32 MsgContext; + U32 ReplyWord; + U8 LUN[8]; + U32 RelativeOffset; + U32 DataLength; + SGE_IO_UNION SGL[1]; +} MSG_TARGET_ASSIST_REQUEST, MPI_POINTER PTR_MSG_TARGET_ASSIST_REQUEST, + TargetAssistRequest_t, MPI_POINTER pTargetAssistRequest_t; + +#define TARGET_ASSIST_FLAGS_DATA_DIRECTION (0x01) +#define TARGET_ASSIST_FLAGS_AUTO_STATUS (0x02) +#define TARGET_ASSIST_FLAGS_HIGH_PRIORITY (0x04) +#define TARGET_ASSIST_FLAGS_REPOST_CMD_BUFFER (0x80) + + +typedef struct _MSG_TARGET_ERROR_REPLY +{ + U16 Reserved; + U8 MsgLength; + U8 Function; + U16 Reserved1; + U8 Reserved2; + U8 MsgFlags; + U32 MsgContext; + U16 Reserved3; + U16 IOCStatus; + U32 IOCLogInfo; + U32 ReplyWord; + U32 TransferCount; +} MSG_TARGET_ERROR_REPLY, MPI_POINTER PTR_MSG_TARGET_ERROR_REPLY, + TargetErrorReply_t, MPI_POINTER pTargetErrorReply_t; + + +/****************************************************************************/ +/* Target Status Send Request */ +/****************************************************************************/ + +typedef struct _MSG_TARGET_STATUS_SEND_REQUEST +{ + U8 StatusCode; + U8 StatusFlags; + U8 ChainOffset; + U8 Function; + U16 QueueTag; + U8 Reserved; + U8 MsgFlags; + U32 MsgContext; + U32 ReplyWord; + U8 LUN[8]; + SGE_SIMPLE_UNION StatusDataSGE; +} MSG_TARGET_STATUS_SEND_REQUEST, MPI_POINTER PTR_MSG_TARGET_STATUS_SEND_REQUEST, + TargetStatusSendRequest_t, MPI_POINTER pTargetStatusSendRequest_t; + +#define TARGET_STATUS_SEND_FLAGS_AUTO_GOOD_STATUS (0x01) +#define TARGET_STATUS_SEND_FLAGS_REPOST_CMD_BUFFER (0x80) + + +/****************************************************************************/ +/* Target Mode Abort Request */ +/****************************************************************************/ + +typedef struct _MSG_TARGET_MODE_ABORT_REQUEST +{ + U8 AbortType; + U8 Reserved; + U8 ChainOffset; + U8 Function; + U16 Reserved1; + U8 Reserved2; + U8 MsgFlags; + U32 MsgContext; + U32 ReplyWord; + U32 MsgContextToAbort; +} MSG_TARGET_MODE_ABORT, MPI_POINTER PTR_MSG_TARGET_MODE_ABORT, + TargetModeAbort_t, MPI_POINTER pTargetModeAbort_t; + +#define TARGET_MODE_ABORT_TYPE_ALL_CMD_BUFFERS (0x00) +#define TARGET_MODE_ABORT_TYPE_ALL_IO (0x01) +#define TARGET_MODE_ABORT_TYPE_EXACT_IO (0x02) +#define TARGET_MODE_ABORT_TYPE_EXACT_IO_REQUEST (0x03) + +/* Target Mode Abort Reply */ + +typedef struct _MSG_TARGET_MODE_ABORT_REPLY +{ + U16 Reserved; + U8 MsgLength; + U8 Function; + U16 Reserved1; + U8 Reserved2; + U8 MsgFlags; + U32 MsgContext; + U16 Reserved3; + U16 IOCStatus; + U32 IOCLogInfo; + U32 AbortCount; +} MSG_TARGET_MODE_ABORT_REPLY, MPI_POINTER PTR_MSG_TARGET_MODE_ABORT_REPLY, + TargetModeAbortReply_t, MPI_POINTER pTargetModeAbortReply_t; + + +/****************************************************************************/ +/* Target Mode Context Reply */ +/****************************************************************************/ + +#define TARGET_MODE_REPLY_IO_INDEX_MASK (0x00003FFF) +#define TARGET_MODE_REPLY_IO_INDEX_SHIFT (0) +#define TARGET_MODE_REPLY_INITIATOR_INDEX_MASK (0x03FFC000) +#define TARGET_MODE_REPLY_INITIATOR_INDEX_SHIFT (14) +#define TARGET_MODE_REPLY_ALIAS_MASK (0x0C000000) +#define TARGET_MODE_REPLY_ALIAS_SHIFT (26) +#define TARGET_MODE_REPLY_PORT_MASK (0x10000000) +#define TARGET_MODE_REPLY_PORT_SHIFT (28) + + +#define GET_IO_INDEX(x) (((x) & TARGET_MODE_REPLY_IO_INDEX_MASK) \ + >> TARGET_MODE_REPLY_IO_INDEX_SHIFT) + +#define SET_IO_INDEX(t, i) \ + ((t) = ((t) & ~TARGET_MODE_REPLY_IO_INDEX_MASK) | \ + (((i) << TARGET_MODE_REPLY_IO_INDEX_SHIFT) & \ + TARGET_MODE_REPLY_IO_INDEX_MASK)) + +#define GET_INITIATOR_INDEX(x) (((x) & TARGET_MODE_REPLY_INITIATOR_INDEX_MASK) \ + >> TARGET_MODE_REPLY_INITIATOR_INDEX_SHIFT) + +#define SET_INITIATOR_INDEX(t, ii) \ + ((t) = ((t) & ~TARGET_MODE_REPLY_INITIATOR_INDEX_MASK) | \ + (((ii) << TARGET_MODE_REPLY_INITIATOR_INDEX_SHIFT) & \ + TARGET_MODE_REPLY_INITIATOR_INDEX_MASK)) + +#define GET_ALIAS(x) (((x) & TARGET_MODE_REPLY_ALIAS_MASK) \ + >> TARGET_MODE_REPLY_ALIAS_SHIFT) + +#define SET_ALIAS(t, a) ((t) = ((t) & ~TARGET_MODE_REPLY_ALIAS_MASK) | \ + (((a) << TARGET_MODE_REPLY_ALIAS_SHIFT) & \ + TARGET_MODE_REPLY_ALIAS_MASK)) + +#define GET_PORT(x) (((x) & TARGET_MODE_REPLY_PORT_MASK) \ + >> TARGET_MODE_REPLY_PORT_SHIFT) + +#define SET_PORT(t, p) ((t) = ((t) & ~TARGET_MODE_REPLY_PORT_MASK) | \ + (((p) << TARGET_MODE_REPLY_PORT_SHIFT) & \ + TARGET_MODE_REPLY_PORT_MASK)) + + +#endif + diff -u --recursive --new-file v2.4.6/linux/drivers/message/fusion/lsi/mpi_type.h linux/drivers/message/fusion/lsi/mpi_type.h --- v2.4.6/linux/drivers/message/fusion/lsi/mpi_type.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/message/fusion/lsi/mpi_type.h Fri Jul 6 17:03:11 2001 @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2000-2001 LSI Logic Corporation. + * + * + * Name: MPI_TYPE.H + * Title: MPI Basic type definitions + * Creation Date: June 6, 2000 + * + * MPI Version: 01.01.02 + * + * Version History + * --------------- + * + * Date Version Description + * -------- -------- ------------------------------------------------------ + * 05-08-00 00.10.01 Original release for 0.10 spec dated 4/26/2000. + * 06-06-00 01.00.01 Update version number for 1.0 release. + * 11-02-00 01.01.01 Original release for post 1.0 work + * 02-20-01 01.01.02 Added define and ifdef for MPI_POINTER. + * -------------------------------------------------------------------------- + */ + +#ifndef MPI_TYPE_H +#define MPI_TYPE_H + + +/******************************************************************************* + * Define MPI_POINTER if it hasn't already been defined. By default MPI_POINTER + * is defined to be a near pointer. MPI_POINTER can be defined as a far pointer + * by defining MPI_POINTER as "far *" before this header file is included. + */ +#ifndef MPI_POINTER +#define MPI_POINTER * +#endif + + +/***************************************************************************** +* +* B a s i c T y p e s +* +*****************************************************************************/ + +typedef signed char S8; +typedef unsigned char U8; +typedef signed short S16; +typedef unsigned short U16; + + +#if defined(unix) || defined(__arm) || defined(ALPHA) + + typedef signed int S32; + typedef unsigned int U32; + +#else + + typedef signed long S32; + typedef unsigned long U32; + +#endif + + +typedef struct _S64 +{ + U32 Low; + S32 High; +} S64; + +typedef struct _U64 +{ + U32 Low; + U32 High; +} U64; + + +/****************************************************************************/ +/* Pointers */ +/****************************************************************************/ + +typedef S8 *PS8; +typedef U8 *PU8; +typedef S16 *PS16; +typedef U16 *PU16; +typedef S32 *PS32; +typedef U32 *PU32; +typedef S64 *PS64; +typedef U64 *PU64; + + +#endif + diff -u --recursive --new-file v2.4.6/linux/drivers/message/fusion/mptbase.c linux/drivers/message/fusion/mptbase.c --- v2.4.6/linux/drivers/message/fusion/mptbase.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/message/fusion/mptbase.c Fri Jul 6 17:03:11 2001 @@ -0,0 +1,3360 @@ +/* + * linux/drivers/message/fusion/mptbase.c + * High performance SCSI + LAN / Fibre Channel device drivers. + * This is the Fusion MPT base driver which supports multiple + * (SCSI + LAN) specialized protocol drivers. + * For use with PCI chip/adapter(s): + * LSIFC9xx/LSI409xx Fibre Channel + * running LSI Logic Fusion MPT (Message Passing Technology) firmware. + * + * Credits: + * There are lots of people not mentioned below that deserve credit + * and thanks but won't get it here - sorry in advance that you + * got overlooked. + * + * This driver would not exist if not for Alan Cox's development + * of the linux i2o driver. + * + * A special thanks to Noah Romer (LSI Logic) for tons of work + * and tough debugging on the LAN driver, especially early on;-) + * And to Roger Hickerson (LSI Logic) for tirelessly supporting + * this driver project. + * + * All manner of help from Stephen Shirron (LSI Logic): + * low-level FC analysis, debug + various fixes in FCxx firmware, + * initial port to alpha platform, various driver code optimizations, + * being a faithful sounding board on all sorts of issues & ideas, + * etc. + * + * A huge debt of gratitude is owed to David S. Miller (DaveM) + * for fixing much of the stupid and broken stuff in the early + * driver while porting to sparc64 platform. THANK YOU! + * + * Special thanks goes to the I2O LAN driver people at the + * University of Helsinki, who, unbeknownst to them, provided + * the inspiration and initial structure for this driver. + * + * A really huge debt of gratitude is owed to Eddie C. Dost + * for gobs of hard work fixing and optimizing LAN code. + * THANK YOU! + * + * Copyright (c) 1999-2001 LSI Logic Corporation + * Originally By: Steven J. Ralston + * (mailto:Steve.Ralston@lsil.com) + * + * $Id: mptbase.c,v 1.47 2001/03/22 10:32:23 sralston Exp $ + */ +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + 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; version 2 of the License. + + 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. + + NO WARRANTY + THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR + CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT + LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, + MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is + solely responsible for determining the appropriateness of using and + distributing the Program and assumes all risks associated with its + exercise of rights under this Agreement, including but not limited to + the risks and costs of program errors, damage to or loss of data, + programs or equipment, and unavailability or interruption of operations. + + DISCLAIMER OF LIABILITY + NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), 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 OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED + HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + +#include <linux/config.h> +#include <linux/version.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/errno.h> +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/types.h> +#include <linux/pci.h> +#include <linux/kdev_t.h> +#include <linux/blkdev.h> +#include <linux/delay.h> +#include <linux/proc_fs.h> +#include <asm/io.h> +#ifdef CONFIG_MTRR +#include <asm/mtrr.h> +#endif + +#include "mptbase.h" + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +#define my_NAME "Fusion MPT base driver" +#define my_VERSION MPT_LINUX_VERSION_COMMON +#define MYNAM "mptbase" + +MODULE_AUTHOR(MODULEAUTHOR); +MODULE_DESCRIPTION(my_NAME); + +/* + * cmd line parameters + */ +MODULE_PARM(PortIo, "0-1i"); +MODULE_PARM_DESC(PortIo, "[0]=Use mmap, 1=Use port io"); +MODULE_PARM(HardReset, "0-1i"); +MODULE_PARM_DESC(HardReset, "0=Disable HardReset, [1]=Enable HardReset"); +static int PortIo = 0; +static int HardReset = 1; + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * Public data... + */ +int mpt_lan_index = 0; +int mpt_stm_index = 0; + +void *mpt_v_ASCQ_TablePtr = NULL; +const char **mpt_ScsiOpcodesPtr = NULL; +int mpt_ASCQ_TableSz = 0; + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * Private data... + */ + /* Adapter lookup table */ +static MPT_ADAPTER *mpt_adapters[MPT_MAX_ADAPTERS] = {0}; +static MPT_ADAPTER_TRACKER MptAdapters; + /* Callback lookup table */ +static MPT_CALLBACK MptCallbacks[MPT_MAX_PROTOCOL_DRIVERS]; + /* Protocol driver class lookup table */ +static int MptDriverClass[MPT_MAX_PROTOCOL_DRIVERS]; + /* Event handler lookup table */ +static MPT_EVHANDLER MptEvHandlers[MPT_MAX_PROTOCOL_DRIVERS]; + +static int FusionInitCalled = 0; +static int mpt_base_index = -1; + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * Forward protos... + */ +static void mpt_interrupt(int irq, void *bus_id, struct pt_regs *r); +static int mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply); + +static int mpt_adapter_install(struct pci_dev *pdev); +static void mpt_detect_929_bound_ports(MPT_ADAPTER *this, struct pci_dev *pdev); +static void mpt_adapter_disable(MPT_ADAPTER *ioc); +static void mpt_adapter_dispose(MPT_ADAPTER *ioc); + +static void MptDisplayIocCapabilities(MPT_ADAPTER *ioc); +static u32 GetIocState(MPT_ADAPTER *ioc, int cooked); +static int GetIocFacts(MPT_ADAPTER *ioc); +static int GetPortFacts(MPT_ADAPTER *ioc); +static int SendIocInit(MPT_ADAPTER *ioc); +static int SendPortEnable(MPT_ADAPTER *ioc, int portnum); +static int mpt_fc9x9_reset(MPT_ADAPTER *ioc); +static int KickStart(MPT_ADAPTER *ioc); +static int SendIocReset(MPT_ADAPTER *ioc, u8 reset_type); +static int PrimeIocFifos(MPT_ADAPTER *ioc); +static int HandShakeReqAndReply(MPT_ADAPTER *ioc, int reqBytes, u32 *req, int replyBytes, u16 *u16reply); +static int WaitForDoorbellAck(MPT_ADAPTER *ioc); +static int WaitForDoorbellInt(MPT_ADAPTER *ioc); +static int WaitForDoorbellReply(MPT_ADAPTER *ioc); +static int GetLanConfigPages(MPT_ADAPTER *ioc); +static int SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch); +static int SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp); + +static int procmpt_create(void); +#ifdef CONFIG_PROC_FS +static int procmpt_destroy(void); +#endif +static int procmpt_read_summary(char *page, char **start, off_t off, int count, int *eof, void *data); +static int procmpt_read_dbg(char *page, char **start, off_t off, int count, int *eof, void *data); +/*static int procmpt_info(char *buf, char **start, off_t offset, int len);*/ + +static int ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *evReply, int *evHandlers); +static void mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info); +static void mpt_sp_log_info(MPT_ADAPTER *ioc, u32 log_info); + +static struct proc_dir_entry *procmpt_root_dir = NULL; + +int fusion_init(void); + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* 20000207 -sralston + * GRRRRR... IOSpace (port i/o) register access (for the 909) is back! + * 20000517 -sralston + * Let's trying going back to default mmap register access... + */ + +static inline u32 CHIPREG_READ32(volatile u32 *a) +{ + if (PortIo) + return inl((unsigned long)a); + else + return readl(a); +} + +static inline void CHIPREG_WRITE32(volatile u32 *a, u32 v) +{ + if (PortIo) + outl(v, (unsigned long)a); + else + writel(v, a); +} + + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/** + * mpt_interrupt - MPT adapter (IOC) specific interrupt handler. + * @irq: irq number (not used) + * @bus_id: bus identifier cookie == pointer to MPT_ADAPTER structure + * @r: pt_regs pointer (not used) + * + * This routine is registered via the request_irq() kernel API call, + * and handles all interrupts generated from a specific MPT adapter + * (also referred to as a IO Controller or IOC). + * This routine must clear the interrupt from the adapter and does + * so by reading the reply FIFO. Multiple replies may be processed + * per single call to this routine; up to MPT_MAX_REPLIES_PER_ISR + * which is currently set to 32 in mptbase.h. + * + * This routine handles register-level access of the adapter but + * dispatches (calls) a protocol-specific callback routine to handle + * the protocol-specific details of the MPT request completion. + */ +static void +mpt_interrupt(int irq, void *bus_id, struct pt_regs *r) +{ + MPT_ADAPTER *ioc; + MPT_FRAME_HDR *mf; + MPT_FRAME_HDR *mr; + u32 pa; + u32 *m; + int req_idx; + int cb_idx; + int type; + int freeme; + int count = 0; + + ioc = bus_id; + + /* + * Drain the reply FIFO! + * + * NOTES: I've seen up to 10 replies processed in this loop, so far... + * Update: I've seen up to 9182 replies processed in this loop! ?? + * Update: Limit ourselves to processing max of N replies + * (bottom of loop). + */ + while (1) { + + if ((pa = CHIPREG_READ32(&ioc->chip->ReplyFifo)) == 0xFFFFFFFF) + return; + + cb_idx = 0; + freeme = 0; + + /* + * Check for non-TURBO reply! + */ + if (pa & MPI_ADDRESS_REPLY_A_BIT) { + dma_addr_t reply_dma_addr; + u16 ioc_stat; + + /* non-TURBO reply! Hmmm, something may be up... + * Newest turbo reply mechanism; get address + * via left shift 1 (get rid of MPI_ADDRESS_REPLY_A_BIT)! + */ + reply_dma_addr = (pa = (pa << 1)); + + /* Map DMA address of reply header to cpu address. */ + m = (u32 *) ((u8 *)ioc->reply_frames + + (reply_dma_addr - ioc->reply_frames_dma)); + + mr = (MPT_FRAME_HDR *) m; + req_idx = le16_to_cpu(mr->u.frame.hwhdr.msgctxu.fld.req_idx); + cb_idx = mr->u.frame.hwhdr.msgctxu.fld.cb_idx; + mf = MPT_INDEX_2_MFPTR(ioc, req_idx); + + dprintk((KERN_INFO MYNAM ": %s: Got non-TURBO reply=%p\n", + ioc->name, mr)); + DBG_DUMP_REPLY_FRAME(mr) + + /* NEW! 20010301 -sralston + * Check/log IOC log info + */ + ioc_stat = le16_to_cpu(mr->u.reply.IOCStatus); + if (ioc_stat & MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) { + u32 log_info = le32_to_cpu(mr->u.reply.IOCLogInfo); + if ((int)ioc->chip_type <= (int)FC929) + mpt_fc_log_info(ioc, log_info); + else + mpt_sp_log_info(ioc, log_info); + } + } else { + /* + * Process turbo (context) reply... + */ + dirqprintk((KERN_INFO MYNAM ": %s: Got TURBO reply(=%08x)\n", ioc->name, pa)); + type = (pa >> MPI_CONTEXT_REPLY_TYPE_SHIFT); + if (type == MPI_CONTEXT_REPLY_TYPE_SCSI_TARGET) { + cb_idx = mpt_stm_index; + mf = NULL; + mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa); + } else if (type == MPI_CONTEXT_REPLY_TYPE_LAN) { + cb_idx = mpt_lan_index; + /* + * BUG FIX! 20001218 -sralston + * Blind set of mf to NULL here was fatal + * after lan_reply says "freeme" + * Fix sort of combined with an optimization here; + * added explicit check for case where lan_reply + * was just returning 1 and doing nothing else. + * For this case skip the callback, but set up + * proper mf value first here:-) + */ + if ((pa & 0x58000000) == 0x58000000) { + req_idx = pa & 0x0000FFFF; + mf = MPT_INDEX_2_MFPTR(ioc, req_idx); + freeme = 1; + /* + * IMPORTANT! Invalidate the callback! + */ + cb_idx = 0; + } else { + mf = NULL; + } + mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa); + } else { + req_idx = pa & 0x0000FFFF; + cb_idx = (pa & 0x00FF0000) >> 16; + mf = MPT_INDEX_2_MFPTR(ioc, req_idx); + mr = NULL; + } + pa = 0; /* No reply flush! */ + } + + /* Check for (valid) IO callback! */ + if (cb_idx) { + /* Do the callback! */ + freeme = (*(MptCallbacks[cb_idx]))(ioc, mf, mr); + } + + if (pa) { + /* Flush (non-TURBO) reply with a WRITE! */ + CHIPREG_WRITE32(&ioc->chip->ReplyFifo, pa); + } + + if (freeme) { + unsigned long flags; + + /* Put Request back on FreeQ! */ + spin_lock_irqsave(&ioc->FreeQlock, flags); + Q_ADD_TAIL(&ioc->FreeQ, &mf->u.frame.linkage, MPT_FRAME_HDR); + spin_unlock_irqrestore(&ioc->FreeQlock, flags); + } + + count++; + dirqprintk((KERN_INFO MYNAM ": %s: ISR processed frame #%d\n", ioc->name, count)); + mb(); + + if (count >= MPT_MAX_REPLIES_PER_ISR) { + dirqprintk((KERN_INFO MYNAM ": %s: ISR processed %d replies.", + ioc->name, count)); + dirqprintk((" Giving this ISR a break!\n")); + return; + } + + } /* drain reply FIFO */ +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * mpt_base_reply - MPT base driver's callback routine; all base driver + * "internal" request/reply processing is routed here. + * Currently used for EventNotification and EventAck handling. + * @ioc: Pointer to MPT_ADAPTER structure + * @mf: Pointer to original MPT request frame + * @reply: Pointer to MPT reply frame (NULL if TurboReply) + * + * Returns 1 indicating original alloc'd request frame ptr + * should be freed, or 0 if it shouldn't. + */ +static int +mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *reply) +{ + int freereq = 1; + u8 func; + + dprintk((KERN_INFO MYNAM ": %s: mpt_base_reply() called\n", ioc->name)); + + if ((mf == NULL) || + (mf >= MPT_INDEX_2_MFPTR(ioc, ioc->req_depth))) { + printk(KERN_ERR MYNAM ": %s: ERROR - NULL or BAD request frame ptr! (=%p)\n", + ioc->name, mf); + return 1; + } + + if (reply == NULL) { + dprintk((KERN_ERR MYNAM ": %s: ERROR - Unexpected NULL Event (turbo?) reply!\n", + ioc->name)); + return 1; + } + + if (!(reply->u.hdr.MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY)) { + dmfprintk((KERN_INFO MYNAM ": Original request frame (@%p) header\n", mf)); + DBG_DUMP_REQUEST_FRAME_HDR(mf) + } + + func = reply->u.hdr.Function; + dprintk((KERN_INFO MYNAM ": %s: mpt_base_reply, Function=%02Xh\n", + ioc->name, func)); + + if (func == MPI_FUNCTION_EVENT_NOTIFICATION) { + EventNotificationReply_t *pEvReply = (EventNotificationReply_t *) reply; + int evHandlers = 0; + int results; + + results = ProcessEventNotification(ioc, pEvReply, &evHandlers); + if (results != evHandlers) { + /* CHECKME! Any special handling needed here? */ + dprintk((KERN_WARNING MYNAM ": %s: Hmmm... Called %d event handlers, sum results = %d\n", + ioc->name, evHandlers, results)); + } + + /* + * Hmmm... It seems that EventNotificationReply is an exception + * to the rule of one reply per request. + */ + if (pEvReply->MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY) + freereq = 0; +#ifdef CONFIG_PROC_FS +// LogEvent(ioc, pEvReply); +#endif + } else if (func == MPI_FUNCTION_EVENT_ACK) { + dprintk((KERN_INFO MYNAM ": %s: mpt_base_reply, EventAck reply received\n", + ioc->name)); + } else { + printk(KERN_ERR MYNAM ": %s: ERROR - Unexpected msg function (=%02Xh) reply received!\n", + ioc->name, func); + } + + /* + * Conditionally tell caller to free the original + * EventNotification/EventAck/unexpected request frame! + */ + return freereq; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/** + * mpt_register - Register protocol-specific main callback handler. + * @cbfunc: callback function pointer + * @dclass: Protocol driver's class (%MPT_DRIVER_CLASS enum value) + * + * This routine is called by a protocol-specific driver (SCSI host, + * LAN, SCSI target) to register it's reply callback routine. Each + * protocol-specific driver must do this before it will be able to + * use any IOC resources, such as obtaining request frames. + * + * NOTES: The SCSI protocol driver currently calls this routine twice + * in order to register separate callbacks; one for "normal" SCSI IO + * and another for MptScsiTaskMgmt requests. + * + * Returns a positive integer valued "handle" in the + * range (and S.O.D. order) {7,6,...,1} if successful. + * Any non-positive return value (including zero!) should be considered + * an error by the caller. + */ +int +mpt_register(MPT_CALLBACK cbfunc, MPT_DRIVER_CLASS dclass) +{ + int r = -1; + int i; + +#ifndef MODULE + /* + * Handle possibility of the mptscsih_detect() routine getting + * called *before* fusion_init! + */ + if (!FusionInitCalled) { + dprintk((KERN_INFO MYNAM ": Hmmm, calling fusion_init from mpt_register!\n")); + /* + * NOTE! We'll get recursion here, as fusion_init() + * calls mpt_register()! + */ + fusion_init(); + FusionInitCalled++; + } +#endif + + /* + * Search for empty callback slot in this order: {7,6,...,1} + * (slot/handle 0 is reserved!) + */ + for (i = MPT_MAX_PROTOCOL_DRIVERS-1; i; i--) { + if (MptCallbacks[i] == NULL) { + MptCallbacks[i] = cbfunc; + MptDriverClass[i] = dclass; + MptEvHandlers[i] = NULL; + r = i; + if (cbfunc != mpt_base_reply) { + MOD_INC_USE_COUNT; + } + break; + } + } + + return r; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/** + * mpt_deregister - Deregister a protocol drivers resources. + * @cb_idx: previously registered callback handle + * + * Each protocol-specific driver should call this routine when it's + * module is unloaded. + */ +void +mpt_deregister(int cb_idx) +{ + if (cb_idx && (cb_idx < MPT_MAX_PROTOCOL_DRIVERS)) { + MptCallbacks[cb_idx] = NULL; + MptDriverClass[cb_idx] = MPTUNKNOWN_DRIVER; + MptEvHandlers[cb_idx] = NULL; + if (cb_idx != mpt_base_index) { + MOD_DEC_USE_COUNT; + } + } +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/** + * mpt_event_register - Register protocol-specific event callback + * handler. + * @cb_idx: previously registered (via mpt_register) callback handle + * @ev_cbfunc: callback function + * + * This routine can be called by one or more protocol-specific drivers + * if/when they choose to be notified of MPT events. + * + * Returns 0 for success. + */ +int +mpt_event_register(int cb_idx, MPT_EVHANDLER ev_cbfunc) +{ + if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS) + return -1; + + MptEvHandlers[cb_idx] = ev_cbfunc; + return 0; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/** + * mpt_event_deregister - Deregister protocol-specific event callback + * handler. + * @cb_idx: previously registered callback handle + * + * Each protocol-specific driver should call this routine + * when it does not (or can no longer) handle events, + * or when it's module is unloaded. + */ +void +mpt_event_deregister(int cb_idx) +{ + if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS) + return; + + MptEvHandlers[cb_idx] = NULL; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/** + * mpt_get_msg_frame - Obtain a MPT request frame from the pool (of 1024) + * allocated per MPT adapter. + * @handle: Handle of registered MPT protocol driver + * @iocid: IOC unique identifier (integer) + * + * Returns pointer to a MPT request frame or %NULL if none are available. + */ +MPT_FRAME_HDR* +mpt_get_msg_frame(int handle, int iocid) +{ + MPT_FRAME_HDR *mf = NULL; + MPT_ADAPTER *iocp; + unsigned long flags; + + /* validate handle and ioc identifier */ + iocp = mpt_adapters[iocid]; + spin_lock_irqsave(&iocp->FreeQlock, flags); + if (! Q_IS_EMPTY(&iocp->FreeQ)) { + int req_offset; + + mf = iocp->FreeQ.head; + Q_DEL_ITEM(&mf->u.frame.linkage); + mf->u.frame.hwhdr.msgctxu.fld.cb_idx = handle; /* byte */ + req_offset = (u8 *)mf - (u8 *)iocp->req_frames; + /* u16! */ + mf->u.frame.hwhdr.msgctxu.fld.req_idx = + cpu_to_le16(req_offset / iocp->req_sz); + mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0; + } + spin_unlock_irqrestore(&iocp->FreeQlock, flags); + dmfprintk((KERN_INFO MYNAM ": %s: mpt_get_msg_frame(%d,%d), got mf=%p\n", + iocp->name, handle, iocid, mf)); + return mf; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/** + * mpt_put_msg_frame - Send a protocol specific MPT request frame + * to a IOC. + * @handle: Handle of registered MPT protocol driver + * @iocid: IOC unique identifier (integer) + * @mf: Pointer to MPT request frame + * + * This routine posts a MPT request frame to the request post FIFO of a + * specific MPT adapter. + */ +void +mpt_put_msg_frame(int handle, int iocid, MPT_FRAME_HDR *mf) +{ + MPT_ADAPTER *iocp; + + iocp = mpt_adapters[iocid]; + if (iocp != NULL) { + dma_addr_t mf_dma_addr; + int req_offset; + + /* ensure values are reset properly! */ + mf->u.frame.hwhdr.msgctxu.fld.cb_idx = handle; /* byte */ + req_offset = (u8 *)mf - (u8 *)iocp->req_frames; + /* u16! */ + mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_offset / iocp->req_sz); + mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0; + +#ifdef MPT_DEBUG_MSG_FRAME + { + u32 *m = mf->u.frame.hwhdr.__hdr; + int i, n; + + printk(KERN_INFO MYNAM ": %s: About to Put msg frame @ %p:\n" KERN_INFO " ", + iocp->name, m); + n = iocp->req_sz/4 - 1; + while (m[n] == 0) + n--; + for (i=0; i<=n; i++) { + if (i && ((i%8)==0)) + printk("\n" KERN_INFO " "); + printk(" %08x", le32_to_cpu(m[i])); + } + printk("\n"); + } +#endif + + mf_dma_addr = iocp->req_frames_dma + req_offset; + CHIPREG_WRITE32(&iocp->chip->RequestFifo, mf_dma_addr); + } +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/** + * mpt_free_msg_frame - Place MPT request frame back on FreeQ. + * @handle: Handle of registered MPT protocol driver + * @iocid: IOC unique identifier (integer) + * @mf: Pointer to MPT request frame + * + * This routine places a MPT request frame back on the MPT adapter's + * FreeQ. + */ +void +mpt_free_msg_frame(int handle, int iocid, MPT_FRAME_HDR *mf) +{ + MPT_ADAPTER *iocp; + unsigned long flags; + + iocp = mpt_adapters[iocid]; + if (iocp != NULL) { + /* Put Request back on FreeQ! */ + spin_lock_irqsave(&iocp->FreeQlock, flags); + Q_ADD_TAIL(&iocp->FreeQ, &mf->u.frame.linkage, MPT_FRAME_HDR); + spin_unlock_irqrestore(&iocp->FreeQlock, flags); + } +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/** + * mpt_send_handshake_request - Send MPT request via doorbell + * handshake method. + * @handle: Handle of registered MPT protocol driver + * @iocid: IOC unique identifier (integer) + * @reqBytes: Size of the request in bytes + * @req: Pointer to MPT request frame + * + * This routine is used exclusively by mptscsih to send MptScsiTaskMgmt + * requests since they are required to be sent via doorbell handshake. + * + * NOTE: It is the callers responsibility to byte-swap fields in the + * request which are greater than 1 byte in size. + * + * Returns 0 for success, non-zero for failure. + */ +int +mpt_send_handshake_request(int handle, int iocid, int reqBytes, u32 *req) +{ + MPT_ADAPTER *iocp; + int r = 0; + + iocp = mpt_adapters[iocid]; + if (iocp != NULL) { + u8 *req_as_bytes; + int i; + + /* + * Emulate what mpt_put_msg_frame() does /wrt to sanity + * setting cb_idx/req_idx. But ONLY if this request + * is in proper (pre-alloc'd) request buffer range... + */ + i = MFPTR_2_MPT_INDEX(iocp,(MPT_FRAME_HDR*)req); + if (reqBytes >= 12 && i >= 0 && i < iocp->req_depth) { + MPT_FRAME_HDR *mf = (MPT_FRAME_HDR*)req; + mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(i); + mf->u.frame.hwhdr.msgctxu.fld.cb_idx = handle; + } + + /* Make sure there are no doorbells */ + CHIPREG_WRITE32(&iocp->chip->IntStatus, 0); + + CHIPREG_WRITE32(&iocp->chip->Doorbell, + ((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) | + ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT))); + + /* Wait for IOC doorbell int */ + if ((i = WaitForDoorbellInt(iocp)) < 0) { + /* FIXME! Recovery action(s)? */ + /*i = unresponsive_ioc(i);*/ + return i; + } + + dhsprintk((KERN_INFO MYNAM ": %s: mpt_send_handshake_request start, WaitCnt=%d\n", + iocp->name, i)); + + CHIPREG_WRITE32(&iocp->chip->IntStatus, 0); + + if ((r = WaitForDoorbellAck(iocp)) < 0) + return -2; + + /* Send request via doorbell handshake */ + req_as_bytes = (u8 *) req; + for (i = 0; i < reqBytes/4; i++) { + u32 word; + + word = ((req_as_bytes[(i*4) + 0] << 0) | + (req_as_bytes[(i*4) + 1] << 8) | + (req_as_bytes[(i*4) + 2] << 16) | + (req_as_bytes[(i*4) + 3] << 24)); + CHIPREG_WRITE32(&iocp->chip->Doorbell, word); + if ((r = WaitForDoorbellAck(iocp)) < 0) { + r = -3; + break; + } + } + + /* Make sure there are no doorbells */ + CHIPREG_WRITE32(&iocp->chip->IntStatus, 0); + + } + + return r; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/** + * mpt_adapter_find_first - Find first MPT adapter pointer. + * + * Returns first MPT adapter pointer or %NULL if no MPT adapters + * are present. + */ +MPT_ADAPTER * +mpt_adapter_find_first(void) +{ + MPT_ADAPTER *this = NULL; + + if (! Q_IS_EMPTY(&MptAdapters)) + this = MptAdapters.head; + + return this; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/** + * mpt_adapter_find_next - Find next MPT adapter pointer. + * @prev: Pointer to previous MPT adapter + * + * Returns next MPT adapter pointer or %NULL if there are no more. + */ +MPT_ADAPTER * +mpt_adapter_find_next(MPT_ADAPTER *prev) +{ + MPT_ADAPTER *next = NULL; + + if (prev && (prev->forw != (MPT_ADAPTER*)&MptAdapters.head)) + next = prev->forw; + + return next; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/** + * mpt_pci_scan - Scan PCI devices for MPT adapters. + * + * Returns count of MPT adapters found, keying off of PCI vendor and + * device_id's. + */ +int __init +mpt_pci_scan(void) +{ + struct pci_dev *pdev; + struct pci_dev *pdev2; + int found = 0; + int count = 0; + int r; + + dprintk((KERN_INFO MYNAM ": Checking for MPT adapters...\n")); + + /* + * NOTE: The 929 (I believe) will appear as 2 separate PCI devices, + * one for each channel. + */ + pci_for_each_dev(pdev) { + pdev2 = NULL; + if (pdev->vendor != 0x1000) + continue; + + if ((pdev->device != MPI_MANUFACTPAGE_DEVICEID_FC909) && + (pdev->device != MPI_MANUFACTPAGE_DEVICEID_FC929) && +#if 0 + /* FIXME! FC919 */ + (pdev->device != MPI_MANUFACTPAGE_DEVICEID_FC919) && + /* FIXME! C103x family */ + (pdev->device != MPI_MANUFACTPAGE_DEVID_53C1030) && + (pdev->device != MPI_MANUFACTPAGE_DEVID_53C1030_ZC) && + (pdev->device != MPI_MANUFACTPAGE_DEVID_53C1035) && +#endif + 1) { + dprintk((KERN_INFO MYNAM ": Skipping LSI device=%04xh\n", pdev->device)); + continue; + } + + /* GRRRRR + * 929 dual function devices may be presented in Func 1,0 order, + * but we'd really really rather have them in Func 0,1 order. + * Do some kind of look ahead here... + */ + if (pdev->devfn & 1) { + pdev2 = pci_peek_next_dev(pdev); + if (pdev2 && (pdev2->vendor == 0x1000) && + (PCI_SLOT(pdev2->devfn) == PCI_SLOT(pdev->devfn)) && + (pdev2->device == MPI_MANUFACTPAGE_DEVICEID_FC929) && + (pdev2->bus->number == pdev->bus->number) && + !(pdev2->devfn & 1)) { + dprintk((KERN_INFO MYNAM ": MPT adapter found: PCI bus/dfn=%02x/%02xh, class=%08x, id=%xh\n", + pdev2->bus->number, pdev2->devfn, pdev2->class, pdev2->device)); + found++; + if ((r = mpt_adapter_install(pdev2)) == 0) + count++; + } else { + pdev2 = NULL; + } + } + + dprintk((KERN_INFO MYNAM ": MPT adapter found: PCI bus/dfn=%02x/%02xh, class=%08x, id=%xh\n", + pdev->bus->number, pdev->devfn, pdev->class, pdev->device)); + found++; + if ((r = mpt_adapter_install(pdev)) == 0) + count++; + + if (pdev2) + pdev = pdev2; + } + + printk(KERN_INFO MYNAM ": %d MPT adapter%s found, %d installed.\n", + found, (found==1) ? "" : "s", count); + + if (count == 0) + return -ENODEV; + +#ifdef CONFIG_PROC_FS + if (procmpt_create() != 0) + printk(KERN_WARNING MYNAM ": WARNING! - %s creation failed!\n", + MPT_PROCFS_MPTBASEDIR); +#endif + + return count; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/** + * mpt_verify_adapter - Given a unique IOC identifier, set pointer to + * the associated MPT adapter structure. + * @iocid: IOC unique identifier (integer) + * @iocpp: Pointer to pointer to IOC adapter + * + * Returns iocid and sets iocpp. + */ +int +mpt_verify_adapter(int iocid, MPT_ADAPTER **iocpp) +{ + MPT_ADAPTER *p; + + *iocpp = NULL; + if (iocid >= MPT_MAX_ADAPTERS) + return -1; + + p = mpt_adapters[iocid]; + if (p == NULL) + return -1; + + *iocpp = p; + return iocid; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/** + * mpt_adapter_install - Install a PCI intelligent MPT adapter. + * @pdev: Pointer to pci_dev structure + * + * This routine performs all the steps necessary to bring the IOC of + * a MPT adapter to a OPERATIONAL state. This includes registering + * memory regions, registering the interrupt, and allocating request + * and reply memory pools. + * + * This routine also pre-fetches the LAN MAC address of a Fibre Channel + * MPT adapter. + * + * Returns 0 for success, non-zero for failure. + * + * TODO: Add support for polled controllers + */ +static int __init +mpt_adapter_install(struct pci_dev *pdev) +{ + MPT_ADAPTER *ioc; + char *myname; + u8 *mem; + unsigned long mem_phys; + unsigned long port; + u32 msize; + u32 psize; + u32 ioc_state; + int i; + int r = -ENODEV; + int cntdn; + int len; + int statefault = 0; + + ioc = kmalloc(sizeof(MPT_ADAPTER), GFP_KERNEL); + if (ioc == NULL) { + printk(KERN_ERR MYNAM ": ERROR - Insufficient memory to add adapter!\n"); + return -ENOMEM; + } + memset(ioc, 0, sizeof(*ioc)); + ioc->req_sz = MPT_REQ_SIZE; /* avoid div by zero! */ + ioc->alloc_total = sizeof(MPT_ADAPTER); + + ioc->pcidev = pdev; + + /* Find lookup slot. GRRRR... */ + for (i=0; i < MPT_MAX_ADAPTERS; i++) { + if (mpt_adapters[i] == NULL) { + ioc->id = i; /* Assign adapter unique id (lookup) */ + break; + } + } + if (i == MPT_MAX_ADAPTERS) { + printk(KERN_ERR MYNAM ": ERROR - mpt_adapters[%d] table overflow!\n", i); + kfree(ioc); + return -ENFILE; + } + + mem_phys = msize = 0; + port = psize = 0; + for (i=0; i < DEVICE_COUNT_RESOURCE; i++) { + if (pdev->PCI_BASEADDR_FLAGS(i) & PCI_BASE_ADDRESS_SPACE_IO) { + /* Get I/O space! */ + port = pdev->PCI_BASEADDR_START(i); + psize = PCI_BASEADDR_SIZE(pdev,i); + } else { + /* Get memmap */ + mem_phys = pdev->PCI_BASEADDR_START(i); + msize = PCI_BASEADDR_SIZE(pdev,i); + break; + } + } + ioc->mem_size = msize; + + if (i == DEVICE_COUNT_RESOURCE) { + printk(KERN_ERR MYNAM ": ERROR - MPT adapter has no memory regions defined!\n"); + kfree(ioc); + return -EINVAL; + } + + dprintk((KERN_INFO MYNAM ": MPT adapter @ %lx, msize=%dd bytes\n", mem_phys, msize)); + dprintk((KERN_INFO MYNAM ": (port i/o @ %lx, psize=%dd bytes)\n", port, psize)); + dprintk((KERN_INFO MYNAM ": Using %s register access method\n", PortIo ? "PortIo" : "MemMap")); + + mem = NULL; + if (! PortIo) { + /* Get logical ptr for PciMem0 space */ + /*mem = ioremap(mem_phys, msize);*/ + mem = ioremap(mem_phys, 0x100); + if (mem == NULL) { + printk(KERN_ERR MYNAM ": ERROR - Unable to map adapter memory!\n"); + kfree(ioc); + return -EINVAL; + } + ioc->memmap = mem; + } + dprintk((KERN_INFO MYNAM ": mem = %p, mem_phys = %lx\n", mem, mem_phys)); + + if (PortIo) { + u8 *pmem = (u8*)port; + ioc->mem_phys = port; + ioc->chip = (SYSIF_REGS*)pmem; + } else { + ioc->mem_phys = mem_phys; + ioc->chip = (SYSIF_REGS*)mem; + } + + ioc->chip_type = FCUNK; + if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC909) { + ioc->chip_type = FC909; + ioc->prod_name = "LSIFC909"; + } + else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC929) { + ioc->chip_type = FC929; + ioc->prod_name = "LSIFC929"; + } +#if 0 + else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC919) { + ioc->chip_type = C1030; + ioc->prod_name = "LSIFC919"; + } + else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_53C1030) { + ioc->chip_type = C1030; + ioc->prod_name = "LSI53C1030"; + } +#endif + + myname = "iocN"; + len = strlen(myname); + memcpy(ioc->name, myname, len+1); + ioc->name[len-1] = '0' + ioc->id; + + Q_INIT(&ioc->FreeQ, MPT_FRAME_HDR); + spin_lock_init(&ioc->FreeQlock); + + /* Disable all! */ + CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF); + CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); + ioc->active = 0; + + ioc->pci_irq = -1; + if (pdev->irq) { + r = request_irq(pdev->irq, mpt_interrupt, SA_SHIRQ, ioc->name, ioc); + + if (r < 0) { + printk(KERN_ERR MYNAM ": %s: ERROR - Unable to allocate interrupt %d!\n", + ioc->name, pdev->irq); + iounmap(mem); + kfree(ioc); + return -EBUSY; + } + + ioc->pci_irq = pdev->irq; + + pci_set_master(pdev); /* ?? */ + + dprintk((KERN_INFO MYNAM ": %s installed at interrupt %d\n", ioc->name, pdev->irq)); + } + + /* tack onto tail of our MPT adapter list */ + Q_ADD_TAIL(&MptAdapters, ioc, MPT_ADAPTER); + + /* Set lookup ptr. */ + mpt_adapters[ioc->id] = ioc; + + /* NEW! 20010220 -sralston + * Check for "929 bound ports" to reduce redundant resets. + */ + if (ioc->chip_type == FC929) + mpt_detect_929_bound_ports(ioc, pdev); + + /* Get current [raw] IOC state */ + ioc_state = GetIocState(ioc, 0); + dhsprintk((KERN_INFO MYNAM ": %s initial [raw] state=%08x\n", ioc->name, ioc_state)); + + /* + * Check to see if IOC got left/stuck in doorbell handshake + * grip of death. If so, hard reset the IOC. + */ + if (ioc_state & MPI_DOORBELL_ACTIVE) { + statefault = 1; + printk(KERN_WARNING MYNAM ": %s: Uh-oh, unexpected doorbell active!\n", + ioc->name); + } + + /* + * Check to see if IOC is in FAULT state. + * If so, hard reset the IOC. + */ + if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) { + statefault = 2; + printk(KERN_WARNING MYNAM ": %s: Uh-oh, IOC is in FAULT state!!!\n", + ioc->name); + printk(KERN_WARNING " FAULT code = %04xh\n", + ioc_state & MPI_DOORBELL_DATA_MASK); + } + + if (HardReset || statefault) { + if ((r = KickStart(ioc)) != 0) { + r = -ENODEV; + goto ioc_up_fail; + } + } + + /* + * Loop here waiting for IOC to come READY. + */ + i = 0; + cntdn = HZ * 10; + while ((ioc_state = GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) { + if (ioc_state == MPI_IOC_STATE_OPERATIONAL) { + /* + * BIOS or previous driver load left IOC in OP state. + * Reset messaging FIFOs. + */ + dprintk((KERN_WARNING MYNAM ": %s: Sending IOC msg unit reset!\n", ioc->name)); + if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET)) != 0) { + printk(KERN_ERR MYNAM ": %s: ERROR - IOC msg unit reset failed!\n", ioc->name); + r = -ENODEV; + goto ioc_up_fail; + } + } else if (ioc_state == MPI_IOC_STATE_RESET) { + /* + * Something is wrong. Try to get IOC back + * to a known state. + */ + dprintk((KERN_WARNING MYNAM ": %s: Sending IO unit reset!\n", ioc->name)); + if ((r = SendIocReset(ioc, MPI_FUNCTION_IO_UNIT_RESET)) != 0) { + printk(KERN_ERR MYNAM ": %s: ERROR - IO unit reset failed!\n", ioc->name); + r = -ENODEV; + goto ioc_up_fail; + } + } + + i++; cntdn--; + if (!cntdn) { + printk(KERN_ERR MYNAM ": %s: ERROR - Wait IOC_READY state timeout(%d)!\n", + ioc->name, (i+5)/HZ); + r = -ETIME; + goto ioc_up_fail; + } + + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(1); + } + + if (statefault) { + printk(KERN_WARNING MYNAM ": %s: Whew! Recovered from %s\n", + ioc->name, statefault==1 ? "stuck handshake" : "IOC FAULT"); + } + + /* Enable! (reply interrupt) */ + CHIPREG_WRITE32(&ioc->chip->IntMask, ~(MPI_HIM_RIM)); + ioc->active = 1; + + /* Get IOC facts! (first time, ioc->facts0 and ioc->pfacts0) */ + if ((r = GetIocFacts(ioc)) != 0) + goto ioc_up_fail; + + /* Does IocFacts.EventState need any looking at / attention here? */ + + if ((r = SendIocInit(ioc)) != 0) + goto ioc_up_fail; + + /* + * Prime reply & request queues! + * (mucho alloc's) + */ + if ((r = PrimeIocFifos(ioc)) != 0) + goto ioc_up_fail; + + /* Get IOC facts again! (2nd time, ioc->factsN and ioc->pfactsN) */ + if ((r = GetIocFacts(ioc)) != 0) + goto ioc_up_fail; + + /* Does IocFacts.EventState need any looking at / attention here? */ + + MptDisplayIocCapabilities(ioc); + + if (ioc->pfacts0.ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) { + /* + * Pre-fetch the ports LAN MAC address! + * (LANPage1_t stuff) + */ + (void) GetLanConfigPages(ioc); +#ifdef MPT_DEBUG + { + u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow; + dprintk((KERN_INFO MYNAM ": %s: LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n", + ioc->name, a[5], a[4], a[3], a[2], a[1], a[0] )); + } +#endif + } + + /* NEW! 20010120 -sralston + * Enable MPT base driver management of EventNotification + * and EventAck handling. + */ + (void) SendEventNotification(ioc, 1); /* 1=Enable EventNotification */ + + return 0; + +ioc_up_fail: + //Q_DEL_ITEM(ioc); + //mpt_adapter_dispose(ioc); + mpt_adapter_disable(ioc); + return r; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * mpt_detect_929_bound_ports - Search for PCI bus/dev_function + * which matches PCI bus/dev_function (+/-1) for newly discovered 929. + * @ioc: Pointer to MPT adapter structure + * @pdev: Pointer to (struct pci_dev) structure + * + * If match on PCI dev_function +/-1 is found, bind the two MPT adapters + * using alt_ioc pointer fields in their %MPT_ADAPTER structures. + */ +static void +mpt_detect_929_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev) +{ + MPT_ADAPTER *ioc_srch = mpt_adapter_find_first(); + unsigned int match_lo, match_hi; + + match_lo = pdev->devfn-1; + match_hi = pdev->devfn+1; + dprintk((KERN_INFO MYNAM ": %s: PCI bus/devfn=%x/%x, searching for devfn match on %x or %x\n", + ioc->name, pdev->bus->number, pdev->devfn, match_lo, match_hi)); + + while (ioc_srch != NULL) { + struct pci_dev *_pcidev = ioc_srch->pcidev; + + if ( (_pcidev->device == MPI_MANUFACTPAGE_DEVICEID_FC929) && + (_pcidev->bus->number == pdev->bus->number) && + (_pcidev->devfn == match_lo || _pcidev->devfn == match_hi) ) { + /* Paranoia checks */ + if (ioc->alt_ioc != NULL) { + printk(KERN_WARNING MYNAM ": Oops, already bound (%s <==> %s)!\n", + ioc->name, ioc->alt_ioc->name); + break; + } else if (ioc_srch->alt_ioc != NULL) { + printk(KERN_WARNING MYNAM ": Oops, already bound (%s <==> %s)!\n", + ioc_srch->name, ioc_srch->alt_ioc->name); + break; + } + dprintk((KERN_INFO MYNAM ": FOUND! binding %s <==> %s\n", + ioc->name, ioc_srch->name)); + ioc_srch->alt_ioc = ioc; + ioc->alt_ioc = ioc_srch; + ioc->sod_reset = ioc->alt_ioc->sod_reset; + ioc->last_kickstart = ioc->alt_ioc->last_kickstart; + break; + } + ioc_srch = mpt_adapter_find_next(ioc_srch); + } +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * mpt_adapter_disable - Disable misbehaving MPT adapter. + * @this: Pointer to MPT adapter structure + */ +static void +mpt_adapter_disable(MPT_ADAPTER *this) +{ + if (this != NULL) { + int sz; + + /* Disable adapter interrupts! */ + CHIPREG_WRITE32(&this->chip->IntMask, 0xFFFFFFFF); + /* Clear any lingering interrupt */ + CHIPREG_WRITE32(&this->chip->IntStatus, 0); + this->active = 0; + + if (this->reply_alloc != NULL) { + sz = (this->reply_sz * this->reply_depth) + 128; + pci_free_consistent(this->pcidev, sz, + this->reply_alloc, this->reply_alloc_dma); + this->reply_frames = NULL; + this->reply_alloc = NULL; + this->alloc_total -= sz; + } + + if (this->req_alloc != NULL) { + sz = (this->req_sz * this->req_depth) + 128; + /* + * Rounding UP to nearest 4-kB boundary here... + */ + sz = ((sz + 0x1000UL - 1UL) / 0x1000) * 0x1000; + pci_free_consistent(this->pcidev, sz, + this->req_alloc, this->req_alloc_dma); + this->req_frames = NULL; + this->req_alloc = NULL; + this->alloc_total -= sz; + } + + if (this->sense_buf_pool != NULL) { + sz = (this->req_depth * 256); + pci_free_consistent(this->pcidev, sz, + this->sense_buf_pool, this->sense_buf_pool_dma); + this->sense_buf_pool = NULL; + this->alloc_total -= sz; + } + } +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * mpt_adapter_dispose - Free all resources associated with a MPT + * adapter. + * @this: Pointer to MPT adapter structure + * + * This routine unregisters h/w resources and frees all alloc'd memory + * associated with a MPT adapter structure. + */ +static void +mpt_adapter_dispose(MPT_ADAPTER *this) +{ + if (this != NULL) { + int sz_first, sz_last; + + sz_first = this->alloc_total; + + mpt_adapter_disable(this); + + if (this->pci_irq != -1) { + free_irq(this->pci_irq, this); + this->pci_irq = -1; + } + + if (this->memmap != NULL) + iounmap((u8 *) this->memmap); + +#if defined(CONFIG_MTRR) && 0 + if (this->mtrr_reg > 0) { + mtrr_del(this->mtrr_reg, 0, 0); + dprintk((KERN_INFO MYNAM ": %s: MTRR region de-registered\n", this->name)); + } +#endif + + /* Zap the adapter lookup ptr! */ + mpt_adapters[this->id] = NULL; + + sz_last = this->alloc_total; + dprintk((KERN_INFO MYNAM ": %s: free'd %d of %d bytes\n", + this->name, sz_first-sz_last+(int)sizeof(*this), sz_first)); + kfree(this); + } +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * MptDisplayIocCapabilities - Disply IOC's capacilities. + * @ioc: Pointer to MPT adapter structure + */ +static void +MptDisplayIocCapabilities(MPT_ADAPTER *ioc) +{ + int i = 0; + + printk(KERN_INFO "%s: ", ioc->name); + if (ioc->prod_name && strlen(ioc->prod_name) > 3) + printk("%s: ", ioc->prod_name+3); + printk("Capabilities={"); + + if (ioc->pfacts0.ProtocolFlags & MPI_PORTFACTS_PROTOCOL_INITIATOR) { + printk("Initiator"); + i++; + } + + if (ioc->pfacts0.ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) { + printk("%sTarget", i ? "," : ""); + i++; + } + + if (ioc->pfacts0.ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) { + printk("%sLAN", i ? "," : ""); + i++; + } + +#if 0 + /* + * This would probably evoke more questions than it's worth + */ + if (ioc->pfacts0.ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) { + printk("%sLogBusAddr", i ? "," : ""); + i++; + } +#endif + + printk("}\n"); +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * GetIocState - Get the current state of a MPT adapter. + * @ioc: Pointer to MPT_ADAPTER structure + * @cooked: Request raw or cooked IOC state + * + * Returns all IOC Doorbell register bits if cooked==0, else just the + * Doorbell bits in MPI_IOC_STATE_MASK. + */ +static u32 +GetIocState(MPT_ADAPTER *ioc, int cooked) +{ + u32 s, sc; + + /* Get! */ + s = CHIPREG_READ32(&ioc->chip->Doorbell); + dprintk((KERN_INFO MYNAM ": %s: raw state = %08x\n", ioc->name, s)); + sc = s & MPI_IOC_STATE_MASK; + + /* Save! */ + ioc->last_state = sc; + + return cooked ? sc : s; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * GetIocFacts - Send IOCFacts request to MPT adapter. + * @ioc: Pointer to MPT_ADAPTER structure + * + * Returns 0 for success, non-zero for failure. + */ +static int +GetIocFacts(MPT_ADAPTER *ioc) +{ + IOCFacts_t get_facts; + IOCFactsReply_t *facts; + int r; + int req_sz; + int reply_sz; + u32 status; + + /* IOC *must* NOT be in RESET state! */ + if (ioc->last_state == MPI_IOC_STATE_RESET) { + printk(KERN_ERR MYNAM ": ERROR - Can't get IOCFacts, %s NOT READY! (%08x)\n", + ioc->name, + ioc->last_state ); + return -44; + } + + facts = &ioc->facts0; + /* Nth (2,3,...) time thru? (been here, done that?) */ + if (ioc->facts0.Function == MPI_FUNCTION_IOC_FACTS) { + facts = &ioc->factsN; + } + + /* Destination (reply area)... */ + reply_sz = sizeof(*facts); + memset(facts, 0, reply_sz); + + /* Request area (get_facts on the stack right now!) */ + req_sz = sizeof(get_facts); + memset(&get_facts, 0, req_sz); + + get_facts.Function = MPI_FUNCTION_IOC_FACTS; + /* Assert: All other get_facts fields are zero! */ + + dprintk((KERN_INFO MYNAM ": %s: Sending IocFacts%s request\n", + ioc->name, facts == &ioc->facts0 ? "0" : "N" )); + + /* No non-zero fields in the get_facts request are greater than + * 1 byte in size, so we can just fire it off as is. + */ + r = HandShakeReqAndReply(ioc, + req_sz, (u32*)&get_facts, + reply_sz, (u16*)facts); + if (r != 0) + return r; + + /* + * Now byte swap the necessary fields before any further + * inspection of reply contents. + * + * But need to do some sanity checks on MsgLength (byte) field + * to make sure we don't zero IOC's req_sz! + */ + /* Did we get a valid reply? */ + if (facts->MsgLength > offsetof(IOCFactsReply_t, RequestFrameSize)/sizeof(u32)) { + facts->MsgVersion = le16_to_cpu(facts->MsgVersion); + facts->MsgContext = le32_to_cpu(facts->MsgContext); + facts->IOCStatus = le16_to_cpu(facts->IOCStatus); + facts->IOCLogInfo = le32_to_cpu(facts->IOCLogInfo); + status = facts->IOCStatus & MPI_IOCSTATUS_MASK; + /* CHECKME! IOCStatus, IOCLogInfo */ + + facts->ReplyQueueDepth = le16_to_cpu(facts->ReplyQueueDepth); + facts->RequestFrameSize = le16_to_cpu(facts->RequestFrameSize); + facts->FWVersion = le16_to_cpu(facts->FWVersion); + facts->ProductID = le16_to_cpu(facts->ProductID); + facts->CurrentHostMfaHighAddr = + le32_to_cpu(facts->CurrentHostMfaHighAddr); + facts->GlobalCredits = le16_to_cpu(facts->GlobalCredits); + facts->CurrentSenseBufferHighAddr = + le32_to_cpu(facts->CurrentSenseBufferHighAddr); + facts->CurReplyFrameSize = + le16_to_cpu(facts->CurReplyFrameSize); + + /* + * Handle NEW (!) IOCFactsReply fields in MPI-1.01.xx + * Older MPI-1.00.xx struct had 13 dwords, and enlarged + * to 14 in MPI-1.01.0x. + */ + if (facts->MsgLength >= sizeof(IOCFactsReply_t)/sizeof(u32) && facts->MsgVersion > 0x0100) { + facts->FWImageSize = le32_to_cpu(facts->FWImageSize); + facts->DataImageSize = le32_to_cpu(facts->DataImageSize); + } + + if (facts->RequestFrameSize) { + /* + * Set values for this IOC's REQUEST queue size & depth... + */ + ioc->req_sz = MIN(MPT_REQ_SIZE, facts->RequestFrameSize * 4); + + /* + * Set values for this IOC's REPLY queue size & depth... + * + * BUG? FIX? 20000516 -nromer & sralston + * GRRR... The following did not translate well from MPI v0.09: + * ioc->reply_sz = MIN(MPT_REPLY_SIZE, facts->ReplySize * 4); + * to 0.10: + * ioc->reply_sz = MIN(MPT_REPLY_SIZE, facts->BlockSize * 4); + * Was trying to minimally optimize to smallest possible reply size + * (and greatly reduce kmalloc size). But LAN may need larger reply? + * + * So for now, just set reply size to request size. FIXME? + */ + ioc->reply_sz = ioc->req_sz; + } else { + /* Something is wrong! */ + printk(KERN_ERR MYNAM ": %s: ERROR - IOC reported invalid 0 request size!\n", + ioc->name); + ioc->req_sz = MPT_REQ_SIZE; + ioc->reply_sz = MPT_REPLY_SIZE; + return -55; + } + ioc->req_depth = MIN(MPT_REQ_DEPTH, facts->GlobalCredits); + ioc->reply_depth = MIN(MPT_REPLY_DEPTH, facts->ReplyQueueDepth); + + dprintk((KERN_INFO MYNAM ": %s: reply_sz=%3d, reply_depth=%4d\n", + ioc->name, ioc->reply_sz, ioc->reply_depth)); + dprintk((KERN_INFO MYNAM ": %s: req_sz =%3d, req_depth =%4d\n", + ioc->name, ioc->req_sz, ioc->req_depth)); + + /* Get port facts! */ + if ( (r = GetPortFacts(ioc)) != 0 ) + return r; + } else { + printk(KERN_ERR MYNAM ": %s: ERROR - Invalid IOC facts reply!\n", + ioc->name); + return -66; + } + + return 0; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * GetPortFacts - Send PortFacts request to MPT adapter. + * @ioc: Pointer to MPT_ADAPTER structure + * + * Returns 0 for success, non-zero for failure. + */ +static int +GetPortFacts(MPT_ADAPTER *ioc) +{ + PortFacts_t get_pfacts; + PortFactsReply_t *pfacts; + int i; + int req_sz; + int reply_sz; + + /* IOC *must* NOT be in RESET state! */ + if (ioc->last_state == MPI_IOC_STATE_RESET) { + printk(KERN_ERR MYNAM ": ERROR - Can't get PortFacts, %s NOT READY! (%08x)\n", + ioc->name, + ioc->last_state ); + return -4; + } + + pfacts = &ioc->pfacts0; + /* Nth (2,3,...) time thru? (been here, done that?) */ + if (ioc->pfacts0.Function == MPI_FUNCTION_PORT_FACTS) { + pfacts = &ioc->pfactsN; + } + + /* Destination (reply area)... */ + reply_sz = sizeof(*pfacts); + memset(pfacts, 0, reply_sz); + + /* Request area (get_pfacts on the stack right now!) */ + req_sz = sizeof(get_pfacts); + memset(&get_pfacts, 0, req_sz); + + get_pfacts.Function = MPI_FUNCTION_PORT_FACTS; + /* Assert: All other get_pfacts fields are zero! */ + + dprintk((KERN_INFO MYNAM ": %s: Sending PortFacts%s request\n", + ioc->name, pfacts == &ioc->pfacts0 ? "0" : "N" )); + + /* No non-zero fields in the get_pfacts request are greater than + * 1 byte in size, so we can just fire it off as is. + */ + i = HandShakeReqAndReply(ioc, req_sz, (u32*)&get_pfacts, + reply_sz, (u16*)pfacts); + if (i != 0) + return i; + + /* Did we get a valid reply? */ + + /* Now byte swap the necessary fields in the response. */ + pfacts->MsgContext = le32_to_cpu(pfacts->MsgContext); + pfacts->IOCStatus = le16_to_cpu(pfacts->IOCStatus); + pfacts->IOCLogInfo = le32_to_cpu(pfacts->IOCLogInfo); + pfacts->MaxDevices = le16_to_cpu(pfacts->MaxDevices); + pfacts->PortSCSIID = le16_to_cpu(pfacts->PortSCSIID); + pfacts->ProtocolFlags = le16_to_cpu(pfacts->ProtocolFlags); + pfacts->MaxPostedCmdBuffers = le16_to_cpu(pfacts->MaxPostedCmdBuffers); + pfacts->MaxPersistentIDs = le16_to_cpu(pfacts->MaxPersistentIDs); + pfacts->MaxLanBuckets = le16_to_cpu(pfacts->MaxLanBuckets); + + return 0; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * SendIocInit - Send IOCInit request to MPT adapter. + * @ioc: Pointer to MPT_ADAPTER structure + * + * Send IOCInit followed by PortEnable to bring IOC to OPERATIONAL state. + * + * Returns 0 for success, non-zero for failure. + */ +static int +SendIocInit(MPT_ADAPTER *ioc) +{ + IOCInit_t ioc_init; + MPIDefaultReply_t init_reply; + u32 state; + int r; + int count; + int cntdn; + + memset(&ioc_init, 0, sizeof(ioc_init)); + memset(&init_reply, 0, sizeof(init_reply)); + + ioc_init.WhoInit = MPI_WHOINIT_HOST_DRIVER; +/* ioc_init.ChainOffset = 0; */ + ioc_init.Function = MPI_FUNCTION_IOC_INIT; +/* ioc_init.Flags = 0; */ + + /*ioc_init.MaxDevices = 16;*/ + ioc_init.MaxDevices = 255; +/* ioc_init.MaxBuses = 16; */ + ioc_init.MaxBuses = 1; + +/* ioc_init.MsgFlags = 0; */ +/* ioc_init.MsgContext = cpu_to_le32(0x00000000); */ + ioc_init.ReplyFrameSize = cpu_to_le16(ioc->reply_sz); /* in BYTES */ + ioc_init.HostMfaHighAddr = cpu_to_le32(0); /* Say we 32-bit! for now */ + + dprintk((KERN_INFO MYNAM ": %s: Sending IOCInit (req @ %p)\n", ioc->name, &ioc_init)); + + r = HandShakeReqAndReply(ioc, sizeof(IOCInit_t), (u32*)&ioc_init, + sizeof(MPIDefaultReply_t), (u16*)&init_reply); + if (r != 0) + return r; + + /* No need to byte swap the multibyte fields in the reply + * since we don't even look at it's contents. + */ + + if ((r = SendPortEnable(ioc, 0)) != 0) + return r; + + /* YIKES! SUPER IMPORTANT!!! + * Poll IocState until _OPERATIONAL while IOC is doing + * LoopInit and TargetDiscovery! + */ + count = 0; + cntdn = HZ * 60; /* chg'd from 30 to 60 seconds */ + state = GetIocState(ioc, 1); + while (state != MPI_IOC_STATE_OPERATIONAL && --cntdn) { + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(1); + + if (!cntdn) { + printk(KERN_ERR MYNAM ": %s: ERROR - Wait IOC_OP state timeout(%d)!\n", + ioc->name, (count+5)/HZ); + return -9; + } + + state = GetIocState(ioc, 1); + count++; + } + dhsprintk((KERN_INFO MYNAM ": %s: INFO - Wait IOC_OPERATIONAL state (cnt=%d)\n", + ioc->name, count)); + + return r; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * SendPortEnable - Send PortEnable request to MPT adapter port. + * @ioc: Pointer to MPT_ADAPTER structure + * @portnum: Port number to enable + * + * Send PortEnable to bring IOC to OPERATIONAL state. + * + * Returns 0 for success, non-zero for failure. + */ +static int +SendPortEnable(MPT_ADAPTER *ioc, int portnum) +{ + PortEnable_t port_enable; + MPIDefaultReply_t reply_buf; + int i; + int req_sz; + int reply_sz; + + /* Destination... */ + reply_sz = sizeof(MPIDefaultReply_t); + memset(&reply_buf, 0, reply_sz); + + req_sz = sizeof(PortEnable_t); + memset(&port_enable, 0, req_sz); + + port_enable.Function = MPI_FUNCTION_PORT_ENABLE; + port_enable.PortNumber = portnum; +/* port_enable.ChainOffset = 0; */ +/* port_enable.MsgFlags = 0; */ +/* port_enable.MsgContext = 0; */ + + dprintk((KERN_INFO MYNAM ": %s: Sending Port(%d)Enable (req @ %p)\n", + ioc->name, portnum, &port_enable)); + + i = HandShakeReqAndReply(ioc, req_sz, (u32*)&port_enable, + reply_sz, (u16*)&reply_buf); + if (i != 0) + return i; + + /* We do not even look at the reply, so we need not + * swap the multi-byte fields. + */ + + return 0; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * KickStart - Perform hard reset of MPT adapter. + * @ioc: Pointer to MPT_ADAPTER structure + * + * This routine places MPT adapter in diagnostic mode via the + * WriteSequence register, and then performs a hard reset of adapter + * via the Diagnostic register. + * + * Returns 0 for success, non-zero for failure. + */ +static int +KickStart(MPT_ADAPTER *ioc) +{ + int r; + u32 ioc_state; + int cnt = 0; + + dprintk((KERN_WARNING MYNAM ": KickStarting %s!\n", ioc->name)); + + if (ioc->chip_type == FC909) { + r = mpt_fc9x9_reset(ioc); + } else if (ioc->chip_type == FC929) { + unsigned long delta; + + delta = jiffies - ioc->last_kickstart; + dprintk((KERN_INFO MYNAM ": %s: 929 KickStart, last=%ld, delta = %ld\n", + ioc->name, ioc->last_kickstart, delta)); + if ((ioc->sod_reset == 0) || (delta >= 10*HZ)) + r = mpt_fc9x9_reset(ioc); + else { + dprintk((KERN_INFO MYNAM ": %s: Skipping KickStart (delta=%ld)!\n", + ioc->name, delta)); + return 0; + } + /* TODO! Add FC919! + } else if (ioc->chip_type == FC919) { + */ + /* TODO! Add C1030! + } else if (ioc->chip_type == C1030) { + */ + } else { + printk(KERN_ERR MYNAM ": %s: ERROR - Bad chip_type (0x%x)\n", + ioc->name, ioc->chip_type); + return -5; + } + + if (r != 0) + return -r; + + dprintk((KERN_INFO MYNAM ": %s: Diagnostic reset successful\n", + ioc->name)); + + for (cnt=0; cnt<HZ*20; cnt++) { + if ((ioc_state = GetIocState(ioc, 1)) == MPI_IOC_STATE_READY) { + dprintk((KERN_INFO MYNAM ": %s: KickStart successful! (cnt=%d)\n", + ioc->name, cnt)); + return 0; + } + /* udelay(10000) ? */ + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(1); + } + + printk(KERN_ERR MYNAM ": %s: ERROR - Failed to come READY after reset!\n", + ioc->name); + return -1; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * mpt_fc9x9_reset - Perform hard reset of FC9x9 adapter. + * @ioc: Pointer to MPT_ADAPTER structure + * + * This routine places FC9x9 adapter in diagnostic mode via the + * WriteSequence register, and then performs a hard reset of adapter + * via the Diagnostic register. + * + * Returns 0 for success, non-zero for failure. + */ +static int +mpt_fc9x9_reset(MPT_ADAPTER *ioc) +{ + u32 diagval; + + /* Use "Diagnostic reset" method! (only thing available!) */ + + /* + * Extra read to handle 909 B.0 chip problem with reset + * logic not finishing the RAM access before hard reset hits. + * (? comment taken from NT SYMMPI source) + */ + (void) CHIPREG_READ32(&ioc->chip->Fubar); + + /* + * Write magic sequence to WriteSequence register. + * But, send 0x0F first to insure a reset to the beginning of the sequence. + */ + CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_KEY_VALUE_MASK); + + /* Now write magic sequence */ + CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE); + CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE); + CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE); + CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE); + CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE); + dprintk((KERN_INFO MYNAM ": %s: Wrote magic DiagWriteEn sequence\n", + ioc->name)); + + /* Now hit the reset bit in the Diagnostic register */ + CHIPREG_WRITE32(&ioc->chip->Diagnostic, MPI_DIAG_RESET_ADAPTER); + + udelay(100); + + if ((diagval = CHIPREG_READ32(&ioc->chip->Diagnostic)) & + (MPI_DIAG_FLASH_BAD_SIG | MPI_DIAG_DISABLE_ARM)) { + printk(KERN_ERR MYNAM ": %s: ERROR - Diagnostic reset FAILED!\n", + ioc->name); + return -9; + } + + /* TODO! + * Cleanup all event stuff for this IOC; + * re-issue EventNotification request if needed. + */ + if (ioc->factsN.Function) + ioc->factsN.EventState = 0; + + /* NEW! 20010220 -sralston + * Try to avoid redundant resets of the 929. + */ + ioc->sod_reset++; + ioc->last_kickstart = jiffies; + if (ioc->alt_ioc) { + ioc->alt_ioc->sod_reset = ioc->sod_reset; + ioc->alt_ioc->last_kickstart = ioc->last_kickstart; + } + + return 0; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * SendIocReset - Send IOCReset request to MPT adapter. + * @ioc: Pointer to MPT_ADAPTER structure + * @reset_type: reset type, expected values are + * %MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET or %MPI_FUNCTION_IO_UNIT_RESET + * + * Send IOCReset request to the MPT adapter. + * + * Returns 0 for success, non-zero for failure. + */ +static int +SendIocReset(MPT_ADAPTER *ioc, u8 reset_type) +{ + int r; + + printk(KERN_WARNING MYNAM ": %s: Sending IOC reset(0x%02x)!\n", + ioc->name, reset_type); + CHIPREG_WRITE32(&ioc->chip->Doorbell, reset_type<<MPI_DOORBELL_FUNCTION_SHIFT); + if ((r = WaitForDoorbellAck(ioc)) < 0) + return r; + + /* TODO! + * Cleanup all event stuff for this IOC; re-issue EventNotification + * request if needed. + */ + if (ioc->factsN.Function) + ioc->factsN.EventState = 0; + + return 0; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * PrimeIocFifos - Initialize IOC request and reply FIFOs. + * @ioc: Pointer to MPT_ADAPTER structure + * + * This routine allocates memory for the MPT reply and request frame + * pools, and primes the IOC reply FIFO with reply frames. + * + * Returns 0 for success, non-zero for failure. + */ +static int +PrimeIocFifos(MPT_ADAPTER *ioc) +{ + MPT_FRAME_HDR *mf; + unsigned long b; + dma_addr_t aligned_mem_dma; + u8 *mem, *aligned_mem; + int i, sz; + + /* Prime reply FIFO... */ + + if (ioc->reply_frames == NULL) { + sz = (ioc->reply_sz * ioc->reply_depth) + 128; + mem = pci_alloc_consistent(ioc->pcidev, sz, &ioc->reply_alloc_dma); + if (mem == NULL) + goto out_fail; + + memset(mem, 0, sz); + ioc->alloc_total += sz; + ioc->reply_alloc = mem; + dprintk((KERN_INFO MYNAM ": %s.reply_alloc @ %p[%08x], sz=%d bytes\n", + ioc->name, mem, ioc->reply_alloc_dma, sz)); + + b = (unsigned long) mem; + b = (b + (0x80UL - 1UL)) & ~(0x80UL - 1UL); /* round up to 128-byte boundary */ + aligned_mem = (u8 *) b; + ioc->reply_frames = (MPT_FRAME_HDR *) aligned_mem; + ioc->reply_frames_dma = + (ioc->reply_alloc_dma + (aligned_mem - mem)); + aligned_mem_dma = ioc->reply_frames_dma; + dprintk((KERN_INFO MYNAM ": %s.reply_frames @ %p[%08x]\n", + ioc->name, aligned_mem, aligned_mem_dma)); + + for (i = 0; i < ioc->reply_depth; i++) { + /* Write each address to the IOC! */ + CHIPREG_WRITE32(&ioc->chip->ReplyFifo, aligned_mem_dma); + aligned_mem_dma += ioc->reply_sz; + } + } + + + /* Request FIFO - WE manage this! */ + + if (ioc->req_frames == NULL) { + sz = (ioc->req_sz * ioc->req_depth) + 128; + /* + * Rounding UP to nearest 4-kB boundary here... + */ + sz = ((sz + 0x1000UL - 1UL) / 0x1000) * 0x1000; + + mem = pci_alloc_consistent(ioc->pcidev, sz, &ioc->req_alloc_dma); + if (mem == NULL) + goto out_fail; + + memset(mem, 0, sz); + ioc->alloc_total += sz; + ioc->req_alloc = mem; + dprintk((KERN_INFO MYNAM ": %s.req_alloc @ %p[%08x], sz=%d bytes\n", + ioc->name, mem, ioc->req_alloc_dma, sz)); + + b = (unsigned long) mem; + b = (b + (0x80UL - 1UL)) & ~(0x80UL - 1UL); /* round up to 128-byte boundary */ + aligned_mem = (u8 *) b; + ioc->req_frames = (MPT_FRAME_HDR *) aligned_mem; + ioc->req_frames_dma = + (ioc->req_alloc_dma + (aligned_mem - mem)); + aligned_mem_dma = ioc->req_frames_dma; + + dprintk((KERN_INFO MYNAM ": %s.req_frames @ %p[%08x]\n", + ioc->name, aligned_mem, aligned_mem_dma)); + + for (i = 0; i < ioc->req_depth; i++) { + mf = (MPT_FRAME_HDR *) aligned_mem; + + /* Queue REQUESTs *internally*! */ + Q_ADD_TAIL(&ioc->FreeQ.head, &mf->u.frame.linkage, MPT_FRAME_HDR); + aligned_mem += ioc->req_sz; + } + +#if defined(CONFIG_MTRR) && 0 + /* + * Enable Write Combining MTRR for IOC's memory region. + * (at least as much as we can; "size and base must be + * multiples of 4 kiB" + */ + ioc->mtrr_reg = mtrr_add(ioc->req_alloc_dma, + sz, + MTRR_TYPE_WRCOMB, 1); + dprintk((KERN_INFO MYNAM ": %s: MTRR region registered (base:size=%08x:%x)\n", + ioc->name, ioc->req_alloc_dma, + sz )); +#endif + + } + + if (ioc->sense_buf_pool == NULL) { + sz = (ioc->req_depth * 256); + ioc->sense_buf_pool = + pci_alloc_consistent(ioc->pcidev, sz, &ioc->sense_buf_pool_dma); + if (ioc->sense_buf_pool == NULL) + goto out_fail; + + ioc->alloc_total += sz; + } + + return 0; + +out_fail: + if (ioc->reply_alloc != NULL) { + sz = (ioc->reply_sz * ioc->reply_depth) + 128; + pci_free_consistent(ioc->pcidev, + sz, + ioc->reply_alloc, ioc->reply_alloc_dma); + ioc->reply_frames = NULL; + ioc->reply_alloc = NULL; + ioc->alloc_total -= sz; + } + if (ioc->req_alloc != NULL) { + sz = (ioc->req_sz * ioc->req_depth) + 128; + /* + * Rounding UP to nearest 4-kB boundary here... + */ + sz = ((sz + 0x1000UL - 1UL) / 0x1000) * 0x1000; + pci_free_consistent(ioc->pcidev, + sz, + ioc->req_alloc, ioc->req_alloc_dma); +#if defined(CONFIG_MTRR) && 0 + if (ioc->mtrr_reg > 0) { + mtrr_del(ioc->mtrr_reg, 0, 0); + dprintk((KERN_INFO MYNAM ": %s: MTRR region de-registered\n", + ioc->name)); + } +#endif + ioc->req_frames = NULL; + ioc->req_alloc = NULL; + ioc->alloc_total -= sz; + } + if (ioc->sense_buf_pool != NULL) { + sz = (ioc->req_depth * 256); + pci_free_consistent(ioc->pcidev, + sz, + ioc->sense_buf_pool, ioc->sense_buf_pool_dma); + ioc->sense_buf_pool = NULL; + } + return -1; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * HandShakeReqAndReply - Send MPT request to and receive reply from + * IOC via doorbell handshake method. + * @ioc: Pointer to MPT_ADAPTER structure + * @reqBytes: Size of the request in bytes + * @req: Pointer to MPT request frame + * @replyBytes: Expected size of the reply in bytes + * @u16reply: Pointer to area where reply should be written + * + * NOTES: It is the callers responsibility to byte-swap fields in the + * request which are greater than 1 byte in size. It is also the + * callers responsibility to byte-swap response fields which are + * greater than 1 byte in size. + * + * Returns 0 for success, non-zero for failure. + */ +static int +HandShakeReqAndReply(MPT_ADAPTER *ioc, int reqBytes, u32 *req, int replyBytes, u16 *u16reply) +{ + MPIDefaultReply_t *mptReply; + int failcnt = 0; + int t; + + /* + * Get ready to cache a handshake reply + */ + ioc->hs_reply_idx = 0; + mptReply = (MPIDefaultReply_t *) ioc->hs_reply; + mptReply->MsgLength = 0; + + /* + * Make sure there are no doorbells (WRITE 0 to IntStatus reg), + * then tell IOC that we want to handshake a request of N words. + * (WRITE u32val to Doorbell reg). + */ + CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); + CHIPREG_WRITE32(&ioc->chip->Doorbell, + ((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) | + ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT))); + + /* + * Wait for IOC's doorbell handshake int + */ + if ((t = WaitForDoorbellInt(ioc)) < 0) + failcnt++; + + dhsprintk((KERN_INFO MYNAM ": %s: HandShake request start, WaitCnt=%d%s\n", + ioc->name, t, failcnt ? " - MISSING DOORBELL HANDSHAKE!" : "")); + + /* + * Clear doorbell int (WRITE 0 to IntStatus reg), + * then wait for IOC to ACKnowledge that it's ready for + * our handshake request. + */ + CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); + if (!failcnt && (t = WaitForDoorbellAck(ioc)) < 0) + failcnt++; + + if (!failcnt) { + int i; + u8 *req_as_bytes = (u8 *) req; + + /* + * Stuff request words via doorbell handshake, + * with ACK from IOC for each. + */ + for (i = 0; !failcnt && i < reqBytes/4; i++) { + u32 word = ((req_as_bytes[(i*4) + 0] << 0) | + (req_as_bytes[(i*4) + 1] << 8) | + (req_as_bytes[(i*4) + 2] << 16) | + (req_as_bytes[(i*4) + 3] << 24)); + + CHIPREG_WRITE32(&ioc->chip->Doorbell, word); + if ((t = WaitForDoorbellAck(ioc)) < 0) + failcnt++; + } + + dmfprintk((KERN_INFO MYNAM ": Handshake request frame (@%p) header\n", req)); + DBG_DUMP_REQUEST_FRAME_HDR(req) + + dhsprintk((KERN_INFO MYNAM ": %s: HandShake request post done, WaitCnt=%d%s\n", + ioc->name, t, failcnt ? " - MISSING DOORBELL ACK!" : "")); + + /* + * Wait for completion of doorbell handshake reply from the IOC + */ + if (!failcnt && (t = WaitForDoorbellReply(ioc)) < 0) + failcnt++; + + /* + * Copy out the cached reply... + */ + for(i=0; i < MIN(replyBytes/2,mptReply->MsgLength*2); i++) + u16reply[i] = ioc->hs_reply[i]; + } else { + return -99; + } + + return -failcnt; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * WaitForDoorbellAck - Wait for IOC to clear the IOP_DOORBELL_STATUS bit + * in it's IntStatus register. + * @ioc: Pointer to MPT_ADAPTER structure + * + * This routine waits (up to ~30 seconds max) for IOC doorbell + * handshake ACKnowledge. + * + * Returns a negative value on failure, else wait loop count. + */ +static int +WaitForDoorbellAck(MPT_ADAPTER *ioc) +{ + int cntdn = HZ * 30; /* ~30 seconds */ + int count = 0; + u32 intstat; + + while (--cntdn) { + intstat = CHIPREG_READ32(&ioc->chip->IntStatus); + if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS)) + break; + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(1); + count++; + } + + if (cntdn) { + dhsprintk((KERN_INFO MYNAM ": %s: WaitForDoorbell ACK (cnt=%d)\n", + ioc->name, count)); + return count; + } + + printk(KERN_ERR MYNAM ": %s: ERROR - Doorbell ACK timeout(%d)!\n", + ioc->name, (count+5)/HZ); + return -1; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * WaitForDoorbellInt - Wait for IOC to set the HIS_DOORBELL_INTERRUPT bit + * in it's IntStatus register. + * @ioc: Pointer to MPT_ADAPTER structure + * + * This routine waits (up to ~30 seconds max) for IOC doorbell interrupt. + * + * Returns a negative value on failure, else wait loop count. + */ +static int +WaitForDoorbellInt(MPT_ADAPTER *ioc) +{ + int cntdn = HZ * 30; /* ~30 seconds */ + int count = 0; + u32 intstat; + + while (--cntdn) { + intstat = CHIPREG_READ32(&ioc->chip->IntStatus); + if (intstat & MPI_HIS_DOORBELL_INTERRUPT) + break; + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(1); + count++; + } + + if (cntdn) { + dhsprintk((KERN_INFO MYNAM ": %s: WaitForDoorbell INT (cnt=%d)\n", + ioc->name, count)); + return count; + } + + printk(KERN_ERR MYNAM ": %s: ERROR - Doorbell INT timeout(%d)!\n", + ioc->name, (count+5)/HZ); + return -1; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * WaitForDoorbellReply - Wait for and capture a IOC handshake reply. + * @ioc: Pointer to MPT_ADAPTER structure + * + * This routine polls the IOC for a handshake reply, 16 bits at a time. + * Reply is cached to IOC private area large enough to hold a maximum + * of 128 bytes of reply data. + * + * Returns a negative value on failure, else size of reply in WORDS. + */ +static int +WaitForDoorbellReply(MPT_ADAPTER *ioc) +{ + int u16cnt = 0; + int failcnt = 0; + int t; + u16 *hs_reply = ioc->hs_reply; + volatile MPIDefaultReply_t *mptReply = (MPIDefaultReply_t *) ioc->hs_reply; + u16 hword; + + hs_reply[0] = hs_reply[1] = hs_reply[7] = 0; + + /* + * Get first two u16's so we can look at IOC's intended reply MsgLength + */ + for (u16cnt=0; !failcnt && u16cnt < 2; u16cnt++) { + if ((t = WaitForDoorbellInt(ioc)) < 0) + failcnt++; + hs_reply[u16cnt] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF); + CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); + } + + dhsprintk((KERN_INFO MYNAM ": %s: First handshake reply word=%08x%s\n", + ioc->name, le32_to_cpu(*(u32 *)hs_reply), + failcnt ? " - MISSING DOORBELL HANDSHAKE!" : "")); + + /* + * If no error (and IOC said MsgLength is > 0), piece together + * reply 16 bits at a time. + */ + for (u16cnt=2; !failcnt && u16cnt < (2 * mptReply->MsgLength); u16cnt++) { + if ((t = WaitForDoorbellInt(ioc)) < 0) + failcnt++; + hword = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF); + /* don't overflow our IOC hs_reply[] buffer! */ + if (u16cnt < sizeof(ioc->hs_reply) / sizeof(ioc->hs_reply[0])) + hs_reply[u16cnt] = hword; + CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); + } + + if (!failcnt && (t = WaitForDoorbellInt(ioc)) < 0) + failcnt++; + CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); + + if (failcnt) { + printk(KERN_ERR MYNAM ": %s: ERROR - Handshake reply failure!\n", + ioc->name); + return -failcnt; + } +#if 0 + else if (u16cnt != (2 * mptReply->MsgLength)) { + return -101; + } + else if ((mptReply->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) { + return -102; + } +#endif + + dmfprintk((KERN_INFO MYNAM ": %s: Got Handshake reply:\n", ioc->name)); + DBG_DUMP_REPLY_FRAME(mptReply) + + dhsprintk((KERN_INFO MYNAM ": %s: WaitForDoorbell REPLY (sz=%d)\n", + ioc->name, u16cnt/2)); + return u16cnt/2; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * GetLanConfigPages - Fetch LANConfig pages. + * @ioc: Pointer to MPT_ADAPTER structure + * + * Returns 0 for success, non-zero for failure. + */ +static int +GetLanConfigPages(MPT_ADAPTER *ioc) +{ + Config_t config_req; + ConfigReply_t config_reply; + LANPage0_t *page0; + dma_addr_t page0_dma; + LANPage1_t *page1; + dma_addr_t page1_dma; + int i; + int req_sz; + int reply_sz; + int data_sz; + +/* LANPage0 */ + /* Immediate destination (reply area)... */ + reply_sz = sizeof(config_reply); + memset(&config_reply, 0, reply_sz); + + /* Ultimate destination... */ + page0 = &ioc->lan_cnfg_page0; + data_sz = sizeof(*page0); + memset(page0, 0, data_sz); + + /* Request area (config_req on the stack right now!) */ + req_sz = sizeof(config_req); + memset(&config_req, 0, req_sz); + config_req.Function = MPI_FUNCTION_CONFIG; + config_req.Action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; + /* config_req.Header.PageVersion = 0; */ + /* config_req.Header.PageLength = 0; */ + config_req.Header.PageNumber = 0; + config_req.Header.PageType = MPI_CONFIG_PAGETYPE_LAN; + /* config_req.PageAddress = 0; */ + config_req.PageBufferSGE.u.Simple.FlagsLength = cpu_to_le32( + ((MPI_SGE_FLAGS_LAST_ELEMENT | + MPI_SGE_FLAGS_END_OF_BUFFER | + MPI_SGE_FLAGS_END_OF_LIST | + MPI_SGE_FLAGS_SIMPLE_ELEMENT | + MPI_SGE_FLAGS_SYSTEM_ADDRESS | + MPI_SGE_FLAGS_32_BIT_ADDRESSING | + MPI_SGE_FLAGS_32_BIT_CONTEXT) << MPI_SGE_FLAGS_SHIFT) | + (u32)data_sz + ); + page0_dma = pci_map_single(ioc->pcidev, page0, data_sz, PCI_DMA_FROMDEVICE); + config_req.PageBufferSGE.u.Simple.u.Address32 = cpu_to_le32(page0_dma); + + dprintk((KERN_INFO MYNAM ": %s: Sending Config request LAN_PAGE_0\n", + ioc->name)); + + i = HandShakeReqAndReply(ioc, req_sz, (u32*)&config_req, + reply_sz, (u16*)&config_reply); + pci_unmap_single(ioc->pcidev, page0_dma, data_sz, PCI_DMA_FROMDEVICE); + if (i != 0) + return i; + + /* Now byte swap the necessary LANPage0 fields */ + +/* LANPage1 */ + /* Immediate destination (reply area)... */ + reply_sz = sizeof(config_reply); + memset(&config_reply, 0, reply_sz); + + /* Ultimate destination... */ + page1 = &ioc->lan_cnfg_page1; + data_sz = sizeof(*page1); + memset(page1, 0, data_sz); + + /* Request area (config_req on the stack right now!) */ + req_sz = sizeof(config_req); + memset(&config_req, 0, req_sz); + config_req.Function = MPI_FUNCTION_CONFIG; + config_req.Action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; + /* config_req.Header.PageVersion = 0; */ + /* config_req.Header.PageLength = 0; */ + config_req.Header.PageNumber = 1; + config_req.Header.PageType = MPI_CONFIG_PAGETYPE_LAN; + /* config_req.PageAddress = 0; */ + config_req.PageBufferSGE.u.Simple.FlagsLength = cpu_to_le32( + ((MPI_SGE_FLAGS_LAST_ELEMENT | + MPI_SGE_FLAGS_END_OF_BUFFER | + MPI_SGE_FLAGS_END_OF_LIST | + MPI_SGE_FLAGS_SIMPLE_ELEMENT | + MPI_SGE_FLAGS_SYSTEM_ADDRESS | + MPI_SGE_FLAGS_32_BIT_ADDRESSING | + MPI_SGE_FLAGS_32_BIT_CONTEXT) << MPI_SGE_FLAGS_SHIFT) | + (u32)data_sz + ); + page1_dma = pci_map_single(ioc->pcidev, page1, data_sz, PCI_DMA_FROMDEVICE); + config_req.PageBufferSGE.u.Simple.u.Address32 = cpu_to_le32(page1_dma); + + dprintk((KERN_INFO MYNAM ": %s: Sending Config request LAN_PAGE_1\n", + ioc->name)); + + i = HandShakeReqAndReply(ioc, req_sz, (u32*)&config_req, + reply_sz, (u16*)&config_reply); + pci_unmap_single(ioc->pcidev, page1_dma, data_sz, PCI_DMA_FROMDEVICE); + if (i != 0) + return i; + + /* Now byte swap the necessary LANPage1 fields */ + + return 0; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/** + * SendEventNotification - Send EventNotification (on or off) request + * to MPT adapter. + * @ioc: Pointer to MPT_ADAPTER structure + * @EvSwitch: Event switch flags + */ +static int +SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch) +{ + EventNotification_t *evnp; + + evnp = (EventNotification_t *) mpt_get_msg_frame(mpt_base_index, ioc->id); + if (evnp == NULL) { + dprintk((KERN_WARNING MYNAM ": %s: WARNING - Unable to allocate a event request frame!\n", + ioc->name)); + return 0; + } + memset(evnp, 0, sizeof(*evnp)); + + dprintk((KERN_INFO MYNAM ": %s: Sending EventNotification(%d)\n", ioc->name, EvSwitch)); + + evnp->Function = MPI_FUNCTION_EVENT_NOTIFICATION; + evnp->ChainOffset = 0; + evnp->MsgFlags = 0; + evnp->Switch = EvSwitch; + + mpt_put_msg_frame(mpt_base_index, ioc->id, (MPT_FRAME_HDR *)evnp); + + return 0; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/** + * SendEventAck - Send EventAck request to MPT adapter. + * @ioc: Pointer to MPT_ADAPTER structure + * @evnp: Pointer to original EventNotification request + */ +static int +SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp) +{ + EventAck_t *pAck; + + if ((pAck = (EventAck_t *) mpt_get_msg_frame(mpt_base_index, ioc->id)) == NULL) { + printk(KERN_WARNING MYNAM ": %s: WARNING - Unable to allocate event ACK request frame!\n", + ioc->name); + return -1; + } + memset(pAck, 0, sizeof(*pAck)); + + dprintk((KERN_INFO MYNAM ": %s: Sending EventAck\n", ioc->name)); + + pAck->Function = MPI_FUNCTION_EVENT_ACK; + pAck->ChainOffset = 0; + pAck->MsgFlags = 0; + pAck->Event = evnp->Event; + pAck->EventContext = evnp->EventContext; + + mpt_put_msg_frame(mpt_base_index, ioc->id, (MPT_FRAME_HDR *)pAck); + + return 0; +} + +#ifdef CONFIG_PROC_FS /* { */ +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * procfs (%MPT_PROCFS_MPTBASEDIR/...) support stuff... + */ + +#define PROC_MPT_READ_RETURN(page,start,off,count,eof,len) \ +{ \ + len -= off; \ + if (len < count) { \ + *eof = 1; \ + if (len <= 0) \ + return 0; \ + } else \ + len = count; \ + *start = page + off; \ + return len; \ +} + + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * procmpt_create - Create %MPT_PROCFS_MPTBASEDIR entries. + * + * Returns 0 for success, non-zero for failure. + */ +static int +procmpt_create(void) +{ + MPT_ADAPTER *ioc; + struct proc_dir_entry *ent; + int errcnt = 0; + + /* + * BEWARE: If/when MPT_PROCFS_MPTBASEDIR changes from "mpt" + * (single level) to multi level (e.g. "driver/message/fusion") + * something here needs to change. -sralston + */ + procmpt_root_dir = CREATE_PROCDIR_ENTRY(MPT_PROCFS_MPTBASEDIR, NULL); + if (procmpt_root_dir == NULL) + return -ENOTDIR; + + if ((ioc = mpt_adapter_find_first()) != NULL) { + ent = create_proc_read_entry(MPT_PROCFS_SUMMARY_NODE, 0, NULL, procmpt_read_summary, NULL); + if (ent == NULL) { + printk(KERN_WARNING MYNAM ": WARNING - Could not create %s entry!\n", + MPT_PROCFS_SUMMARY_PATHNAME); + errcnt++; + } + } + + while (ioc != NULL) { + char pname[32]; + int namelen; + /* + * Create "/proc/mpt/iocN" subdirectory entry for each MPT adapter. + */ + namelen = sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s", ioc->name); + if ((ent = CREATE_PROCDIR_ENTRY(pname, NULL)) != NULL) { + /* + * And populate it with: "summary" and "dbg" file entries. + */ + (void) sprintf(pname+namelen, "/summary"); + ent = create_proc_read_entry(pname, 0, NULL, procmpt_read_summary, ioc); + if (ent == NULL) { + errcnt++; + printk(KERN_WARNING MYNAM ": %s: WARNING - Could not create /proc/%s entry!\n", + ioc->name, pname); + } +//#ifdef MPT_DEBUG + /* DEBUG aid! */ + (void) sprintf(pname+namelen, "/dbg"); + ent = create_proc_read_entry(pname, 0, NULL, procmpt_read_dbg, ioc); + if (ent == NULL) { + errcnt++; + printk(KERN_WARNING MYNAM ": %s: WARNING - Could not create /proc/%s entry!\n", + ioc->name, pname); + } +//#endif + } else { + errcnt++; + printk(KERN_WARNING MYNAM ": %s: WARNING - Could not create /proc/%s entry!\n", + ioc->name, pname); + + } + + ioc = mpt_adapter_find_next(ioc); + } + + if (errcnt) { +// remove_proc_entry("mpt", 0); + return -ENOTDIR; + } + + return 0; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * procmpt_destroy - Tear down %MPT_PROCFS_MPTBASEDIR entries. + * + * Returns 0 for success, non-zero for failure. + */ +static int +procmpt_destroy(void) +{ + MPT_ADAPTER *ioc; + + /* + * BEWARE: If/when MPT_PROCFS_MPTBASEDIR changes from "mpt" + * (single level) to multi level (e.g. "driver/message/fusion") + * something here needs to change. -sralston + */ + + ioc = mpt_adapter_find_first(); + if (ioc != NULL) { + remove_proc_entry(MPT_PROCFS_SUMMARY_NODE, 0); + } + + while (ioc != NULL) { + char pname[32]; + int namelen; + /* + * Tear down each "/proc/mpt/iocN" subdirectory. + */ + namelen = sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s", ioc->name); + (void) sprintf(pname+namelen, "/summary"); + remove_proc_entry(pname, 0); +//#ifdef MPT_DEBUG + (void) sprintf(pname+namelen, "/dbg"); + remove_proc_entry(pname, 0); +//#endif + (void) sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s", ioc->name); + remove_proc_entry(pname, 0); + + ioc = mpt_adapter_find_next(ioc); + } + + if (atomic_read((atomic_t *)&procmpt_root_dir->count) == 0) { + remove_proc_entry(MPT_PROCFS_MPTBASEDIR, 0); + return 0; + } + + return -1; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/** + * procmpt_read_summary - Handle read request from /proc/mpt/summary + * or from /proc/mpt/iocN/summary. + * @page: Pointer to area to write information + * @start: Pointer to start pointer + * @off: Offset to start writing + * @count: + * @eof: Pointer to EOF integer + * @data: Pointer + * + * Returns numbers of characters written to process performing the read. + */ +static int +procmpt_read_summary(char *page, char **start, off_t off, int count, int *eof, void *data) +{ + MPT_ADAPTER *ioc; + char *out = page; + int len; + + if (data == NULL) + ioc = mpt_adapter_find_first(); + else + ioc = data; + +// Too verbose! +// out += sprintf(out, "Attached Fusion MPT I/O Controllers:%s\n", ioc ? "" : " none"); + + while (ioc) { + int more = 0; + +// Too verbose! +// mpt_print_ioc_facts(ioc, out, &more, 0); + mpt_print_ioc_summary(ioc, out, &more, 0); + + out += more; + if ((out-page) >= count) { + break; + } + + if (data == NULL) + ioc = mpt_adapter_find_next(ioc); + else + ioc = NULL; /* force exit for iocN */ + } + len = out - page; + + PROC_MPT_READ_RETURN(page,start,off,count,eof,len); +} + +// debug aid! +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/** + * procmpt_read_dbg - Handle read request from /proc/mpt/iocN/dbg. + * @page: Pointer to area to write information + * @start: Pointer to start pointer + * @off: Offset to start writing + * @count: + * @eof: Pointer to EOF integer + * @data: Pointer + * + * Returns numbers of characters written to process performing the read. + */ +static int +procmpt_read_dbg(char *page, char **start, off_t off, int count, int *eof, void *data) +{ + MPT_ADAPTER *ioc; + char *out = page; + int len; + + ioc = data; + + while (ioc) { + int more = 0; + + mpt_print_ioc_facts(ioc, out, &more, 0); + + out += more; + if ((out-page) >= count) { + break; + } + ioc = NULL; + } + len = out - page; + + PROC_MPT_READ_RETURN(page,start,off,count,eof,len); +} +#endif /* CONFIG_PROC_FS } */ + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +static void +mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc) +{ + if ((ioc->facts0.FWVersion & 0xF000) == 0xE000) + sprintf(buf, " (Exp %02d%02d)", + (ioc->facts0.FWVersion & 0x0F00) >> 8, /* Month */ + ioc->facts0.FWVersion & 0x001F); /* Day */ + else + buf[0] ='\0'; + + /* insider hack! */ + if (ioc->facts0.FWVersion & 0x0080) { + strcat(buf, " [MDBG]"); + } +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/** + * mpt_print_ioc_summary - Write ASCII summary of IOC to a buffer. + * @ioc: Pointer to MPT_ADAPTER structure + * @buffer: Pointer to buffer where IOC summary info should be written + * @size: Pointer to number of bytes we wrote (set by this routine) + * @len: Offset at which to start writing in buffer + * + * This routine writes (english readable) ASCII text, which represents + * a summary of IOC information, to a buffer. + */ +void +mpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buffer, int *size, int len) +{ + char expVer[32]; + int y; + + + mpt_get_fw_exp_ver(expVer, ioc); + + /* + * Shorter summary of attached ioc's... + */ + y = sprintf(buffer+len, "%s: %s, %s%04xh%s, Ports=%d, MaxQ=%d", + ioc->name, + ioc->prod_name, + MPT_FW_REV_MAGIC_ID_STRING, /* "FwRev=" or somesuch */ + ioc->facts0.FWVersion, + expVer, + ioc->facts0.NumberOfPorts, + ioc->req_depth); + + if (ioc->pfacts0.ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) { + u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow; + y += sprintf(buffer+len+y, ", LanAddr=%02X:%02X:%02X:%02X:%02X:%02X", + a[5], a[4], a[3], a[2], a[1], a[0]); + } + + if (!ioc->active) + y += sprintf(buffer+len+y, " (disabled)"); + + y += sprintf(buffer+len+y, "\n"); + + *size = y; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/** + * mpt_print_ioc_facts - Write ASCII summary of IOC facts to a buffer. + * @ioc: Pointer to MPT_ADAPTER structure + * @buffer: Pointer to buffer where IOC facts should be written + * @size: Pointer to number of bytes we wrote (set by this routine) + * @len: Offset at which to start writing in buffer + * + * This routine writes (english readable) ASCII text, which represents + * a summary of the IOC facts, to a buffer. + */ +void +mpt_print_ioc_facts(MPT_ADAPTER *ioc, char *buffer, int *size, int len) +{ + char expVer[32]; + char iocName[16]; + int sz; + int y; + + + mpt_get_fw_exp_ver(expVer, ioc); + + strcpy(iocName, ioc->name); + y = sprintf(buffer+len, "%s:\n", iocName); + + y += sprintf(buffer+len+y, " ProductID = 0x%04x\n", ioc->facts0.ProductID); + y += sprintf(buffer+len+y, " PortNumber = %d (of %d)\n", + ioc->pfacts0.PortNumber+1, + ioc->facts0.NumberOfPorts); + if (ioc->pfacts0.ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) { + u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow; + y += sprintf(buffer+len+y, " LanAddr = 0x%02x:%02x:%02x:%02x:%02x:%02x\n", + a[5], a[4], a[3], a[2], a[1], a[0]); + } + y += sprintf(buffer+len+y, " FWVersion = 0x%04x%s\n", ioc->facts0.FWVersion, expVer); + y += sprintf(buffer+len+y, " MsgVersion = 0x%04x\n", ioc->facts0.MsgVersion); + y += sprintf(buffer+len+y, " WhoInit = 0x%02x\n", ioc->facts0.WhoInit); + y += sprintf(buffer+len+y, " EventState = 0x%02x\n", ioc->facts0.EventState); + y += sprintf(buffer+len+y, " CurrentHostMfaHighAddr = 0x%08x\n", + ioc->facts0.CurrentHostMfaHighAddr); + y += sprintf(buffer+len+y, " CurrentSenseBufferHighAddr = 0x%08x\n", + ioc->facts0.CurrentSenseBufferHighAddr); + y += sprintf(buffer+len+y, " MaxChainDepth = 0x%02x frames\n", ioc->facts0.MaxChainDepth); + y += sprintf(buffer+len+y, " MinBlockSize = 0x%02x bytes\n", 4*ioc->facts0.BlockSize); + + y += sprintf(buffer+len+y, " RequestFrames @ 0x%p (Dma @ 0x%08x)\n", + ioc->req_alloc, ioc->req_alloc_dma); + /* + * Rounding UP to nearest 4-kB boundary here... + */ + sz = (ioc->req_sz * ioc->req_depth) + 128; + sz = ((sz + 0x1000UL - 1UL) / 0x1000) * 0x1000; + y += sprintf(buffer+len+y, " {CurReqSz=%d} x {CurReqDepth=%d} = %d bytes ^= 0x%x\n", + ioc->req_sz, ioc->req_depth, ioc->req_sz*ioc->req_depth, sz); + y += sprintf(buffer+len+y, " {MaxReqSz=%d} {MaxReqDepth=%d}\n", + 4*ioc->facts0.RequestFrameSize, + ioc->facts0.GlobalCredits); + + y += sprintf(buffer+len+y, " ReplyFrames @ 0x%p (Dma @ 0x%08x)\n", + ioc->reply_alloc, ioc->reply_alloc_dma); + sz = (ioc->reply_sz * ioc->reply_depth) + 128; + y += sprintf(buffer+len+y, " {CurRepSz=%d} x {CurRepDepth=%d} = %d bytes ^= 0x%x\n", + ioc->reply_sz, ioc->reply_depth, ioc->reply_sz*ioc->reply_depth, sz); + y += sprintf(buffer+len+y, " {MaxRepSz=%d} {MaxRepDepth=%d}\n", + ioc->factsN.CurReplyFrameSize, + ioc->facts0.ReplyQueueDepth); + + *size = y; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +static char * +EventDescriptionStr(u8 event, u32 evData0) +{ + char *ds = NULL; + + switch(event) { + case MPI_EVENT_NONE: + ds = "None"; + break; + case MPI_EVENT_LOG_DATA: + ds = "Log Data"; + break; + case MPI_EVENT_STATE_CHANGE: + ds = "State Change"; + break; + case MPI_EVENT_UNIT_ATTENTION: + ds = "Unit Attention"; + break; + case MPI_EVENT_IOC_BUS_RESET: + ds = "IOC Bus Reset"; + break; + case MPI_EVENT_EXT_BUS_RESET: + ds = "External Bus Reset"; + break; + case MPI_EVENT_RESCAN: + ds = "Bus Rescan Event"; + /* Ok, do we need to do anything here? As far as + I can tell, this is when a new device gets added + to the loop. */ + break; + case MPI_EVENT_LINK_STATUS_CHANGE: + if (evData0 == MPI_EVENT_LINK_STATUS_FAILURE) + ds = "Link Status(FAILURE) Change"; + else + ds = "Link Status(ACTIVE) Change"; + break; + case MPI_EVENT_LOOP_STATE_CHANGE: + if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LIP) + ds = "Loop State(LIP) Change"; + else if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LPE) + ds = "Loop State(LPE) Change"; /* ??? */ + else + ds = "Loop State(LPB) Change"; /* ??? */ + break; + case MPI_EVENT_LOGOUT: + ds = "Logout"; + break; + case MPI_EVENT_EVENT_CHANGE: + if (evData0) + ds = "Events(ON) Change"; + else + ds = "Events(OFF) Change"; + break; + /* + * MPT base "custom" events may be added here... + */ + default: + ds = "Unknown"; + break; + } + return ds; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/** + * ProcessEventNotification - Route a received EventNotificationReply to + * all currently regeistered event handlers. + * @ioc: Pointer to MPT_ADAPTER structure + * @pEventReply: Pointer to EventNotification reply frame + * @evHandlers: Pointer to integer, number of event handlers + * + * Returns sum of event handlers return values. + */ +static int +ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply, int *evHandlers) +{ + u16 evDataLen; + u32 evData0 = 0; +// u32 evCtx; + int i; + int r = 0; + int handlers = 0; + char *evStr; + u8 event; + + /* + * Do platform normalization of values + */ + event = le32_to_cpu(pEventReply->Event) & 0xFF; +// evCtx = le32_to_cpu(pEventReply->EventContext); + evDataLen = le16_to_cpu(pEventReply->EventDataLength); + if (evDataLen) { + evData0 = le32_to_cpu(pEventReply->Data[0]); + } + + evStr = EventDescriptionStr(event, evData0); + dprintk((KERN_INFO MYNAM ": %s: MPT event (%s=%02Xh) detected!\n", + ioc->name, + evStr, + event)); + +#if defined(MPT_DEBUG) || defined(MPT_DEBUG_EVENTS) + printk(KERN_INFO MYNAM ": Event data:\n" KERN_INFO); + for (i = 0; i < evDataLen; i++) + printk(" %08x", le32_to_cpu(pEventReply->Data[i])); + printk("\n"); +#endif + + /* + * Do general / base driver event processing + */ + switch(event) { + case MPI_EVENT_NONE: /* 00 */ + case MPI_EVENT_LOG_DATA: /* 01 */ + case MPI_EVENT_STATE_CHANGE: /* 02 */ + case MPI_EVENT_UNIT_ATTENTION: /* 03 */ + case MPI_EVENT_IOC_BUS_RESET: /* 04 */ + case MPI_EVENT_EXT_BUS_RESET: /* 05 */ + case MPI_EVENT_RESCAN: /* 06 */ + case MPI_EVENT_LINK_STATUS_CHANGE: /* 07 */ + case MPI_EVENT_LOOP_STATE_CHANGE: /* 08 */ + case MPI_EVENT_LOGOUT: /* 09 */ + default: + break; + case MPI_EVENT_EVENT_CHANGE: /* 0A */ + if (evDataLen) { + u8 evState = evData0 & 0xFF; + + /* CHECKME! What if evState unexpectedly says OFF (0)? */ + + /* Update EventState field in cached IocFacts */ + if (ioc->factsN.Function) { + ioc->factsN.EventState = evState; + } + } + break; + } + + /* + * Call each currently registered protocol event handler. + */ + for (i=MPT_MAX_PROTOCOL_DRIVERS-1; i; i--) { + if (MptEvHandlers[i]) { + dprintk((KERN_INFO MYNAM ": %s: Routing Event to event handler #%d\n", + ioc->name, i)); + r += (*(MptEvHandlers[i]))(ioc, pEventReply); + handlers++; + } + } + /* FIXME? Examine results here? */ + + /* + * If needed, send (a single) EventAck. + */ + if (pEventReply->AckRequired == MPI_EVENT_NOTIFICATION_ACK_REQUIRED) { + if ((i = SendEventAck(ioc, pEventReply)) != 0) { + } + } + + *evHandlers = handlers; + return r; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * mpt_fc_log_info - Log information returned from Fibre Channel IOC. + * @ioc: Pointer to MPT_ADAPTER structure + * @log_info: U32 LogInfo reply word from the IOC + * + * Refer to lsi/fc_log.h. + */ +static void +mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info) +{ + static char *subcl_str[8] = { + "FCP Initiator", "FCP Target", "LAN", "MPI Message Layer", + "FC Link", "Context Manager", "Invalid Field Offset", "State Change Info" + }; + char *desc = "unknown"; + u8 subcl = (log_info >> 24) & 0x7; + u32 SubCl = log_info & 0x27000000; + + switch(log_info) { +/* FCP Initiator */ + case MPI_IOCLOGINFO_FC_INIT_ERROR_OUT_OF_ORDER_FRAME: + desc = "Received an out of order frame - unsupported"; + break; + case MPI_IOCLOGINFO_FC_INIT_ERROR_BAD_START_OF_FRAME: + desc = "Bad start of frame primative"; + break; + case MPI_IOCLOGINFO_FC_INIT_ERROR_BAD_END_OF_FRAME: + desc = "Bad end of frame primative"; + break; + case MPI_IOCLOGINFO_FC_INIT_ERROR_OVER_RUN: + desc = "Receiver hardware detected overrun"; + break; + case MPI_IOCLOGINFO_FC_INIT_ERROR_RX_OTHER: + desc = "Other errors caught by IOC which require retries"; + break; + case MPI_IOCLOGINFO_FC_INIT_ERROR_SUBPROC_DEAD: + desc = "Main processor could not initialize sub-processor"; + break; +/* FC Target */ + case MPI_IOCLOGINFO_FC_TARGET_NO_PDISC: + desc = "Not sent because we are waiting for a PDISC from the initiator"; + break; + case MPI_IOCLOGINFO_FC_TARGET_NO_LOGIN: + desc = "Not sent because we are not logged in to the remote node"; + break; + case MPI_IOCLOGINFO_FC_TARGET_DOAR_KILLED_BY_LIP: + desc = "Data Out, Auto Response, not sent due to a LIP"; + break; + case MPI_IOCLOGINFO_FC_TARGET_DIAR_KILLED_BY_LIP: + desc = "Data In, Auto Response, not sent due to a LIP"; + break; + case MPI_IOCLOGINFO_FC_TARGET_DIAR_MISSING_DATA: + desc = "Data In, Auto Response, missing data frames"; + break; + case MPI_IOCLOGINFO_FC_TARGET_DONR_KILLED_BY_LIP: + desc = "Data Out, No Response, not sent due to a LIP"; + break; + case MPI_IOCLOGINFO_FC_TARGET_WRSP_KILLED_BY_LIP: + desc = "Auto-response after a write not sent due to a LIP"; + break; + case MPI_IOCLOGINFO_FC_TARGET_DINR_KILLED_BY_LIP: + desc = "Data In, No Response, not completed due to a LIP"; + break; + case MPI_IOCLOGINFO_FC_TARGET_DINR_MISSING_DATA: + desc = "Data In, No Response, missing data frames"; + break; + case MPI_IOCLOGINFO_FC_TARGET_MRSP_KILLED_BY_LIP: + desc = "Manual Response not sent due to a LIP"; + break; + case MPI_IOCLOGINFO_FC_TARGET_NO_CLASS_3: + desc = "Not sent because remote node does not support Class 3"; + break; + case MPI_IOCLOGINFO_FC_TARGET_LOGIN_NOT_VALID: + desc = "Not sent because login to remote node not validated"; + break; + case MPI_IOCLOGINFO_FC_TARGET_FROM_OUTBOUND: + desc = "Cleared from the outbound after a logout"; + break; + case MPI_IOCLOGINFO_FC_TARGET_WAITING_FOR_DATA_IN: + desc = "Cleared waiting for data after a logout"; + break; +/* LAN */ + case MPI_IOCLOGINFO_FC_LAN_TRANS_SGL_MISSING: + desc = "Transaction Context Sgl Missing"; + break; + case MPI_IOCLOGINFO_FC_LAN_TRANS_WRONG_PLACE: + desc = "Transaction Context found before an EOB"; + break; + case MPI_IOCLOGINFO_FC_LAN_TRANS_RES_BITS_SET: + desc = "Transaction Context value has reserved bits set"; + break; + case MPI_IOCLOGINFO_FC_LAN_WRONG_SGL_FLAG: + desc = "Invalid SGL Flags"; + break; +/* FC Link */ + case MPI_IOCLOGINFO_FC_LINK_LOOP_INIT_TIMEOUT: + desc = "Loop initialization timed out"; + break; + case MPI_IOCLOGINFO_FC_LINK_ALREADY_INITIALIZED: + desc = "Another system controller already initialized the loop"; + break; + case MPI_IOCLOGINFO_FC_LINK_LINK_NOT_ESTABLISHED: + desc = "Not synchronized to signal or still negotiating (possible cable problem)"; + break; + } + + printk(KERN_INFO MYNAM ": %s: LogInfo(0x%08x): SubCl={%s}", + ioc->name, log_info, subcl_str[subcl]); + if (SubCl == MPI_IOCLOGINFO_FC_INVALID_FIELD_BYTE_OFFSET) + printk(", byte_offset=%d\n", log_info & MPI_IOCLOGINFO_FC_INVALID_FIELD_MAX_OFFSET); + else if (SubCl == MPI_IOCLOGINFO_FC_STATE_CHANGE) + printk("\n"); /* StateChg in LogInfo & 0x00FFFFFF, above */ + else + printk("\n" KERN_INFO " %s\n", desc); +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * mpt_sp_log_info - Log information returned from SCSI Parallel IOC. + * @ioc: Pointer to MPT_ADAPTER structure + * @mr: Pointer to MPT reply frame + * @log_info: U32 LogInfo word from the IOC + * + * Refer to lsi/sp_log.h. + */ +static void +mpt_sp_log_info(MPT_ADAPTER *ioc, u32 log_info) +{ + /* FIXME! */ + printk(KERN_INFO MYNAM ": %s: LogInfo(0x%08x)\n", ioc->name, log_info); +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/** + * mpt_register_ascqops_strings - Register SCSI ASC/ASCQ and SCSI + * OpCode strings from the (optional) isense module. + * @ascqTable: Pointer to ASCQ_Table_t structure + * @ascqtbl_sz: Number of entries in ASCQ_Table + * @opsTable: Pointer to array of SCSI OpCode strings (char pointers) + * + * Specialized driver registration routine for the isense driver. + */ +int +mpt_register_ascqops_strings(/*ASCQ_Table_t*/void *ascqTable, int ascqtbl_sz, const char **opsTable) +{ + int r = 0; + + if (ascqTable && ascqtbl_sz && opsTable) { + mpt_v_ASCQ_TablePtr = ascqTable; + mpt_ASCQ_TableSz = ascqtbl_sz; + mpt_ScsiOpcodesPtr = opsTable; + printk(KERN_INFO MYNAM ": English readable SCSI-3 strings enabled:-)\n"); + r = 1; + } + MOD_INC_USE_COUNT; + return r; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/** + * mpt_deregister_ascqops_strings - Deregister SCSI ASC/ASCQ and SCSI + * OpCode strings from the isense driver. + * + * Specialized driver deregistration routine for the isense driver. + */ +void +mpt_deregister_ascqops_strings(void) +{ + mpt_v_ASCQ_TablePtr = NULL; + mpt_ASCQ_TableSz = 0; + mpt_ScsiOpcodesPtr = NULL; + printk(KERN_INFO MYNAM ": English readable SCSI-3 strings disabled)-:\n"); + MOD_DEC_USE_COUNT; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + +EXPORT_SYMBOL(mpt_register); +EXPORT_SYMBOL(mpt_deregister); +EXPORT_SYMBOL(mpt_event_register); +EXPORT_SYMBOL(mpt_event_deregister); +EXPORT_SYMBOL(mpt_get_msg_frame); +EXPORT_SYMBOL(mpt_put_msg_frame); +EXPORT_SYMBOL(mpt_free_msg_frame); +EXPORT_SYMBOL(mpt_send_handshake_request); +EXPORT_SYMBOL(mpt_adapter_find_first); +EXPORT_SYMBOL(mpt_adapter_find_next); +EXPORT_SYMBOL(mpt_verify_adapter); +EXPORT_SYMBOL(mpt_print_ioc_summary); +EXPORT_SYMBOL(mpt_lan_index); +EXPORT_SYMBOL(mpt_stm_index); + +EXPORT_SYMBOL(mpt_register_ascqops_strings); +EXPORT_SYMBOL(mpt_deregister_ascqops_strings); +EXPORT_SYMBOL(mpt_v_ASCQ_TablePtr); +EXPORT_SYMBOL(mpt_ASCQ_TableSz); +EXPORT_SYMBOL(mpt_ScsiOpcodesPtr); + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/** + * fusion_init - Fusion MPT base driver initialization routine. + * + * Returns 0 for success, non-zero for failure. + */ +int __init fusion_init(void) +{ + int i; + + if (FusionInitCalled++) { + dprintk((KERN_INFO MYNAM ": INFO - Driver late-init entry point called\n")); + return 0; + } + + show_mptmod_ver(my_NAME, my_VERSION); + printk(KERN_INFO COPYRIGHT "\n"); + + Q_INIT(&MptAdapters, MPT_ADAPTER); /* set to empty */ + for (i = 0; i < MPT_MAX_PROTOCOL_DRIVERS; i++) { + MptCallbacks[i] = NULL; + MptDriverClass[i] = MPTUNKNOWN_DRIVER; + MptEvHandlers[i] = NULL; + } + + /* NEW! 20010120 -sralston + * Register ourselves (mptbase) in order to facilitate + * EventNotification handling. + */ + mpt_base_index = mpt_register(mpt_base_reply, MPTBASE_DRIVER); + + if ((i = mpt_pci_scan()) < 0) + return i; + + return 0; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/** + * fusion_exit - Perform driver unload cleanup. + * + * This routine frees all resources associated with each MPT adapter + * and removes all %MPT_PROCFS_MPTBASEDIR entries. + */ +static void fusion_exit(void) +{ + MPT_ADAPTER *this; + int i; + + dprintk((KERN_INFO MYNAM ": fusion_exit() called!\n")); + + /* + * Paranoia; disable interrupts on all MPT adapters. + */ + for (i=0; i<MPT_MAX_ADAPTERS; i++) { + if ((this = mpt_adapters[i]) != NULL) { + /* Disable adapter interrupts! */ + CHIPREG_WRITE32(&this->chip->IntMask, 0xFFFFFFFF); + /* Clear any lingering interrupt */ + CHIPREG_WRITE32(&this->chip->IntStatus, 0); + this->active = 0; + } + } + + /* Whups? 20010120 -sralston + * Moved this *above* removal of all MptAdapters! + */ +#ifdef CONFIG_PROC_FS + procmpt_destroy(); +#endif + + while (! Q_IS_EMPTY(&MptAdapters)) { + this = MptAdapters.head; + Q_DEL_ITEM(this); + mpt_adapter_dispose(this); + } +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + +module_init(fusion_init); +module_exit(fusion_exit); diff -u --recursive --new-file v2.4.6/linux/drivers/message/fusion/mptbase.h linux/drivers/message/fusion/mptbase.h --- v2.4.6/linux/drivers/message/fusion/mptbase.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/message/fusion/mptbase.h Fri Jul 6 17:03:11 2001 @@ -0,0 +1,581 @@ +/* + * linux/drivers/message/fusion/mptbase.h + * High performance SCSI + LAN / Fibre Channel device drivers. + * For use with PCI chip/adapter(s): + * LSIFC9xx/LSI409xx Fibre Channel + * running LSI Logic Fusion MPT (Message Passing Technology) firmware. + * + * Credits: + * (see mptbase.c) + * + * Copyright (c) 1999-2001 LSI Logic Corporation + * Originally By: Steven J. Ralston + * (mailto:Steve.Ralston@lsil.com) + * + * $Id: mptbase.h,v 1.38 2001/03/22 10:54:30 sralston Exp $ + */ +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + 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; version 2 of the License. + + 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. + + NO WARRANTY + THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR + CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT + LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, + MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is + solely responsible for determining the appropriateness of using and + distributing the Program and assumes all risks associated with its + exercise of rights under this Agreement, including but not limited to + the risks and costs of program errors, damage to or loss of data, + programs or equipment, and unavailability or interruption of operations. + + DISCLAIMER OF LIABILITY + NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), 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 OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED + HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES + + 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 MPTBASE_H_INCLUDED +#define MPTBASE_H_INCLUDED +/*{-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + +#include "linux_compat.h" /* linux-2.2.x (vs. -2.4.x) tweaks */ + +#include "lsi/mpi_type.h" +#include "lsi/mpi.h" /* Fusion MPI(nterface) basic defs */ +#include "lsi/mpi_ioc.h" /* Fusion MPT IOC(ontroller) defs */ +#include "lsi/mpi_cnfg.h" /* IOC configuration support */ +#include "lsi/mpi_init.h" /* SCSI Host (initiator) protocol support */ +#include "lsi/mpi_lan.h" /* LAN over FC protocol support */ + +//#include "lsi/mpi_fc.h" /* Fibre Channel (lowlevel) support */ +//#include "lsi/mpi_targ.h" /* SCSI/FCP Target protcol support */ +#include "lsi/fc_log.h" + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + +#ifndef MODULEAUTHOR +#define MODULEAUTHOR "LSI Logic Corporation" +#endif + +#ifndef COPYRIGHT +#define COPYRIGHT "Copyright (c) 1999-2001 " MODULEAUTHOR +#endif + +#define MPT_LINUX_VERSION_COMMON "1.00.11" +#define MPT_LINUX_VERSION_EXP "0.09.66-EXP" +#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-1.00.11" +#define WHAT_MAGIC_STRING "@" "(" "#" ")" + +#define show_mptmod_ver(s,ver) \ + printk(KERN_INFO "%s %s\n", s, ver); + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * Fusion MPT(linux) driver configurable stuff... + */ +#define MPT_MAX_ADAPTERS 16 +#define MPT_MAX_PROTOCOL_DRIVERS 8 + +#define MPT_MISCDEV_BASENAME "mptctl" +#define MPT_MISCDEV_PATHNAME "/dev/" MPT_MISCDEV_BASENAME + +#define MPT_PROCFS_MPTBASEDIR "mpt" + /* chg it to "driver/fusion" ? */ +#define MPT_PROCFS_SUMMARY_NODE MPT_PROCFS_MPTBASEDIR "/summary" +#define MPT_PROCFS_SUMMARY_PATHNAME "/proc/" MPT_PROCFS_SUMMARY_NODE +#define MPT_FW_REV_MAGIC_ID_STRING "FwRev=" + +#ifdef __KERNEL__ /* { */ +#define MPT_MAX_REQ_DEPTH 1023 +#define MPT_REQ_DEPTH 256 +#define MPT_MIN_REQ_DEPTH 128 + +#define MPT_MAX_REPLY_DEPTH MPT_MAX_REQ_DEPTH +#define MPT_REPLY_DEPTH 128 +#define MPT_MIN_REPLY_DEPTH 8 +#define MPT_MAX_REPLIES_PER_ISR 32 + +#define MPT_MAX_FRAME_SIZE 128 +#define MPT_REQ_SIZE 128 +#define MPT_REPLY_SIZE 128 + +#define MPT_SG_BUCKETS_PER_HUNK 1 + +#ifdef MODULE +#define MPT_REQ_DEPTH_RANGE_STR __MODULE_STRING(MPT_MIN_REQ_DEPTH) "-" __MODULE_STRING(MPT_MAX_REQ_DEPTH) +#define MPT_REPLY_DEPTH_RANGE_STR __MODULE_STRING(MPT_MIN_REPLY_DEPTH) "-" __MODULE_STRING(MPT_MAX_REPLY_DEPTH) +#define MPT_REPLY_SIZE_RANGE_STR __MODULE_STRING(MPT_MIN_REPLY_SIZE) "-" __MODULE_STRING(MPT_MAX_FRAME_SIZE) +#endif + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * MPT protocol driver defs... + */ +typedef enum { + MPTBASE_DRIVER, /* MPT base class */ + MPTCTL_DRIVER, /* MPT ioctl class */ + MPTSCSIH_DRIVER, /* MPT SCSI host (initiator) class */ + MPTLAN_DRIVER, /* MPT LAN class */ + MPTSTM_DRIVER, /* MPT SCSI target mode class */ + MPTUNKNOWN_DRIVER +} MPT_DRIVER_CLASS; + +/* + * MPT adapter / port / bus / device info structures... + */ + +typedef union _MPT_FRAME_TRACKER { + struct { + struct _MPT_FRAME_HDR *forw; + struct _MPT_FRAME_HDR *back; + u32 arg1; + void *argp1; + } linkage; + /* + * NOTE: On non-32-bit systems, where pointers are LARGE, + * using the linkage pointers destroys our sacred MsgContext + * field contents. But we don't care anymore because these + * are now reset in mpt_put_msg_frame() just prior to sending + * a request off to the IOC. + */ + struct { + u32 __hdr[2]; + /* + * The following _MUST_ match the location of the + * MsgContext field in the MPT message headers. + */ + union { + u32 MsgContext; + struct { + u16 req_idx; /* Request index */ + u8 cb_idx; /* callback function index */ + u8 rsvd; + } fld; + } msgctxu; + } hwhdr; +} MPT_FRAME_TRACKER; + +/* + * We might want to view/access a frame as: + * 1) generic request header + * 2) SCSIIORequest + * 3) SCSIIOReply + * 4) MPIDefaultReply + * 5) frame tracker + */ +typedef struct _MPT_FRAME_HDR { + union { + MPIHeader_t hdr; + SCSIIORequest_t scsireq; + SCSIIOReply_t sreply; + MPIDefaultReply_t reply; + MPT_FRAME_TRACKER frame; + } u; +} MPT_FRAME_HDR; + +typedef struct _MPT_Q_TRACKER { + MPT_FRAME_HDR *head; + MPT_FRAME_HDR *tail; +} MPT_Q_TRACKER; + + +typedef struct _MPT_SGL_HDR { + SGESimple32_t sge[1]; +} MPT_SGL_HDR; + +typedef struct _MPT_SGL64_HDR { + SGESimple64_t sge[1]; +} MPT_SGL64_HDR; + + +typedef struct _Q_ITEM { + struct _Q_ITEM *forw; + struct _Q_ITEM *back; +} Q_ITEM; + +typedef struct _Q_TRACKER { + struct _Q_ITEM *head; + struct _Q_ITEM *tail; +} Q_TRACKER; + + +/* + * Chip-specific stuff... + */ + +typedef enum { + FC909 = 0x0909, + FC919 = 0x0919, + FC929 = 0x0929, + C1030 = 0x1030, + FCUNK = 0xFBAD +} CHIP_TYPE; + +/* + * System interface register set + */ + +typedef struct _SYSIF_REGS +{ + u32 Doorbell; /* 00 System<->IOC Doorbell reg */ + u32 WriteSequence; /* 04 Write Sequence register */ + u32 Diagnostic; /* 08 Diagnostic register */ + u32 TestBase; /* 0C Test Base Address */ + u32 Reserved1[8]; /* 10-2F reserved for future use */ + u32 IntStatus; /* 30 Interrupt Status */ + u32 IntMask; /* 34 Interrupt Mask */ + u32 Reserved2[2]; /* 38-3F reserved for future use */ + u32 RequestFifo; /* 40 Request Post/Free FIFO */ + u32 ReplyFifo; /* 44 Reply Post/Free FIFO */ + u32 Reserved3[2]; /* 48-4F reserved for future use */ + u32 HostIndex; /* 50 Host Index register */ + u32 Reserved4[15]; /* 54-8F */ + u32 Fubar; /* 90 For Fubar usage */ + u32 Reserved5[27]; /* 94-FF */ +} SYSIF_REGS; + +/* + * NOTE: Use MPI_{DOORBELL,WRITESEQ,DIAG}_xxx defs in lsi/mpi.h + * in conjunction with SYSIF_REGS accesses! + */ + + +typedef struct _MPT_ADAPTER +{ + struct _MPT_ADAPTER *forw; + struct _MPT_ADAPTER *back; + int id; /* Unique adapter id {0,1,2,...} */ + int pci_irq; + IOCFactsReply_t facts0; + IOCFactsReply_t factsN; + char name[32]; /* "iocN" */ + char *prod_name; /* "LSIFC9x9" */ + u32 mem_phys; /* == f4020000 (mmap) */ + volatile SYSIF_REGS *chip; /* == c8817000 (mmap) */ + CHIP_TYPE chip_type; + int mem_size; + int alloc_total; + u32 last_state; + int active; + int sod_reset; + unsigned long last_kickstart; + PortFactsReply_t pfacts0; + PortFactsReply_t pfactsN; + LANPage0_t lan_cnfg_page0; + LANPage1_t lan_cnfg_page1; + u8 *reply_alloc; /* Reply frames alloc ptr */ + dma_addr_t reply_alloc_dma; + MPT_FRAME_HDR *reply_frames; /* Reply frames - rounded up! */ + dma_addr_t reply_frames_dma; + int reply_depth; + int reply_sz; + /* We (host driver) get to manage our own RequestQueue! */ + u8 *req_alloc; /* Request frames alloc ptr */ + dma_addr_t req_alloc_dma; + MPT_FRAME_HDR *req_frames; /* Request msg frames for PULL mode! */ + dma_addr_t req_frames_dma; + int req_depth; + int req_sz; + spinlock_t FreeQlock; + MPT_Q_TRACKER FreeQ; + /* Pool of SCSI sense buffers for commands coming from + * the SCSI mid-layer. We have one 256 byte sense buffer + * for each REQ entry. + */ + u8 *sense_buf_pool; + dma_addr_t sense_buf_pool_dma; + int hs_reply_idx; + u32 hs_req[MPT_MAX_FRAME_SIZE/sizeof(u32)]; + u16 hs_reply[MPT_MAX_FRAME_SIZE/sizeof(u16)]; + struct pci_dev *pcidev; + struct _MPT_ADAPTER *alt_ioc; +/* atomic_t userCnt; */ + u8 *memmap; + int mtrr_reg; + struct Scsi_Host *sh; + struct proc_dir_entry *ioc_dentry; +} MPT_ADAPTER; + + +typedef struct _MPT_ADAPTER_TRACKER { + MPT_ADAPTER *head; + MPT_ADAPTER *tail; +} MPT_ADAPTER_TRACKER; + +/* + * New return value convention: + * 1 = Ok to free associated request frame + * 0 = not Ok ... + */ +typedef int (*MPT_CALLBACK)(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply); +typedef int (*MPT_EVHANDLER)(MPT_ADAPTER *ioc, EventNotificationReply_t *evReply); + +/* + * Fibre Channel (SCSI) target device... + */ +typedef struct _FC_TARGET { + struct _FC_TARGET *forw; + struct _FC_TARGET *back; + int bus_id; + int target_id; + int lun_exists[32]; + u8 inquiry_data[36]; + u8 last_sense[256]; +} FC_TARGET; + +typedef struct _FCDEV_TRACKER { + FC_TARGET *head; + FC_TARGET *tail; +} FCDEV_TRACKER; + + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * Funky (private) macros... + */ +#ifdef MPT_DEBUG +#define dprintk(x) printk x +#else +#define dprintk(x) +#endif + +#ifdef MPT_DEBUG_HANDSHAKE +#define dhsprintk(x) printk x +#else +#define dhsprintk(x) +#endif + +#if defined(MPT_DEBUG) || defined(MPT_DEBUG_MSG_FRAME) +#define dmfprintk(x) printk x +#else +#define dmfprintk(x) +#endif + +#ifdef MPT_DEBUG_IRQ +#define dirqprintk(x) printk x +#else +#define dirqprintk(x) +#endif + +#ifdef MPT_DEBUG_EVENTS +#define deventprintk(x) printk x +#else +#define deventprintk(x) +#endif + +#ifdef MPT_DEBUG_SPINLOCK +#define dslprintk(x) printk x +#else +#define dslprintk(x) +#endif + +#ifdef MPT_DEBUG_SG +#define dsgprintk(x) printk x +#else +#define dsgprintk(x) +#endif + + +#define MPT_INDEX_2_MFPTR(ioc,idx) \ + (MPT_FRAME_HDR*)( (u8*)(ioc)->req_frames + (ioc)->req_sz * (idx) ) + +#define MFPTR_2_MPT_INDEX(ioc,mf) \ + (int)( ((u8*)mf - (u8*)(ioc)->req_frames) / (ioc)->req_sz ) + +#define Q_INIT(q,type) (q)->head = (q)->tail = (type*)(q) +#define Q_IS_EMPTY(q) ((Q_ITEM*)(q)->head == (Q_ITEM*)(q)) + +#define Q_ADD_TAIL(qt,i,type) { \ + Q_TRACKER *_qt = (Q_TRACKER*)(qt); \ + Q_ITEM *oldTail = _qt->tail; \ + (i)->forw = (type*)_qt; \ + (i)->back = (type*)oldTail; \ + oldTail->forw = (Q_ITEM*)(i); \ + _qt->tail = (Q_ITEM*)(i); \ +} + +#define Q_ADD_HEAD(qt,i,type) { \ + Q_TRACKER *_qt = (Q_TRACKER*)(qt); \ + Q_ITEM *oldHead = _qt->head; \ + (i)->forw = (type*)oldHead; \ + (i)->back = (type*)_qt; \ + oldHead->back = (Q_ITEM*)(i); \ + _qt->head = (Q_ITEM*)(i); \ +} + +#define Q_DEL_ITEM(i) { \ + Q_ITEM *_forw = (Q_ITEM*)(i)->forw; \ + Q_ITEM *_back = (Q_ITEM*)(i)->back; \ + _back->forw = _forw; \ + _forw->back = _back; \ +} + + +#define SWAB4(value) \ + (u32)( (((value) & 0x000000ff) << 24) \ + | (((value) & 0x0000ff00) << 8) \ + | (((value) & 0x00ff0000) >> 8) \ + | (((value) & 0xff000000) >> 24) ) + + +#if defined(MPT_DEBUG) || defined(MPT_DEBUG_MSG_FRAME) +#define DBG_DUMP_REPLY_FRAME(mfp) \ + { u32 *m = (u32 *)(mfp); \ + int i, n = (le32_to_cpu(m[0]) & 0x00FF0000) >> 16; \ + printk(KERN_INFO " "); \ + for (i=0; i<n; i++) \ + printk(" %08x", le32_to_cpu(m[i])); \ + printk("\n"); \ + } +#define DBG_DUMP_REQUEST_FRAME_HDR(mfp) \ + { int i, n = 3; \ + u32 *m = (u32 *)(mfp); \ + printk(KERN_INFO " "); \ + for (i=0; i<n; i++) \ + printk(" %08x", le32_to_cpu(m[i])); \ + printk("\n"); \ + } +#else +#define DBG_DUMP_REPLY_FRAME(mfp) +#define DBG_DUMP_REQUEST_FRAME_HDR(mfp) +#endif + + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +#endif /* } __KERNEL__ */ + + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + +/* + * MPT Control IOCTLs and structures + */ +#define MPT_MAGIC_NUMBER 'm' +#define MPTRWPERF _IOWR(MPT_MAGIC_NUMBER,0,struct mpt_raw_r_w) +#define MPTRWPERF_CHK _IOR(MPT_MAGIC_NUMBER,13,struct mpt_raw_r_w) +#define MPTRWPERF_RESET _IOR(MPT_MAGIC_NUMBER,14,struct mpt_raw_r_w) +#define MPTFWDOWNLOAD _IOWR(MPT_MAGIC_NUMBER,15,struct mpt_fw_xfer) +#define MPTSCSICMD _IOWR(MPT_MAGIC_NUMBER,16,struct mpt_scsi_cmd) + +/* + * Define something *vague* enough that caller doesn't + * really need to know anything about device parameters + * (blk_size, capacity, etc.) + */ +struct mpt_raw_r_w { + unsigned int iocnum; /* IOC unit number */ + unsigned int port; /* IOC port number */ + unsigned int target; /* SCSI Target */ + unsigned int lun; /* SCSI LUN */ + unsigned int iters; /* N iterations */ + unsigned short nblks; /* number of blocks per IO */ + unsigned short qdepth; /* max Q depth on this device */ + unsigned char range; /* 0-100% of FULL disk capacity, 0=use (nblks X iters) */ + unsigned char skip; /* % of disk to skip */ + unsigned char rdwr; /* 0-100%, 0=pure ReaDs, 100=pure WRites */ + unsigned char seqran; /* 0-100%, 0=pure SEQential, 100=pure RANdom */ + unsigned int cache_sz; /* In Kb! Optimize hits to N Kb cache size */ +}; + +struct mpt_fw_xfer { + unsigned int iocnum; /* IOC unit number */ +/* u8 flags;*/ /* Message flags - bit field */ + unsigned int fwlen; + void *bufp; /* Pointer to firmware buffer */ +}; + +struct mpt_scsi_cmd { + unsigned int iocnum; /* IOC unit number */ + unsigned int port; /* IOC port number */ + unsigned int target; /* SCSI Target */ + unsigned int lun; /* SCSI LUN */ + SCSIIORequest_t scsi_req; + SCSIIOReply_t scsi_reply; +}; + +struct mpt_ioctl_sanity { + unsigned int iocnum; +}; + +#ifdef __KERNEL__ /* { */ +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + +/* + * Public entry points... + */ +extern int mpt_register(MPT_CALLBACK cbfunc, MPT_DRIVER_CLASS dclass); +extern void mpt_deregister(int cb_idx); +extern int mpt_event_register(int cb_idx, MPT_EVHANDLER ev_cbfunc); +extern void mpt_event_deregister(int cb_idx); +extern int mpt_register_ascqops_strings(/*ASCQ_Table_t*/void *ascqTable, int ascqtbl_sz, const char **opsTable); +extern void mpt_deregister_ascqops_strings(void); +extern MPT_FRAME_HDR *mpt_get_msg_frame(int handle, int iocid); +extern void mpt_free_msg_frame(int handle, int iocid, MPT_FRAME_HDR *mf); +extern void mpt_put_msg_frame(int handle, int iocid, MPT_FRAME_HDR *mf); +extern int mpt_send_handshake_request(int handle, int iocid, int reqBytes, u32 *req); +extern int mpt_verify_adapter(int iocid, MPT_ADAPTER **iocpp); +extern MPT_ADAPTER *mpt_adapter_find_first(void); +extern MPT_ADAPTER *mpt_adapter_find_next(MPT_ADAPTER *prev); +extern void mpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buf, int *size, int len); +extern void mpt_print_ioc_facts(MPT_ADAPTER *ioc, char *buf, int *size, int len); + +/* + * Public data decl's... + */ +extern int mpt_lan_index; /* needed by mptlan.c */ +extern int mpt_stm_index; /* needed by mptstm.c */ + +extern void *mpt_v_ASCQ_TablePtr; +extern const char **mpt_ScsiOpcodesPtr; +extern int mpt_ASCQ_TableSz; + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +#endif /* } __KERNEL__ */ + +/* + * More (public) macros... + */ +#ifndef MIN +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) +#endif +#ifndef MAX +#define MAX(a, b) (((a) > (b)) ? (a) : (b)) +#endif + +#ifndef offsetof +#define offsetof(t, m) ((size_t) (&((t *)0)->m)) +#endif + +#if defined(__alpha__) || defined(__sparc_v9__) +#define CAST_U32_TO_PTR(x) ((void *)(u64)x) +#define CAST_PTR_TO_U32(x) ((u32)(u64)x) +#else +#define CAST_U32_TO_PTR(x) ((void *)x) +#define CAST_PTR_TO_U32(x) ((u32)x) +#endif + +#define MPT_PROTOCOL_FLAGS_c_c_c_c(pflags) \ + ((pflags) & MPI_PORTFACTS_PROTOCOL_INITIATOR) ? 'I' : 'i', \ + ((pflags) & MPI_PORTFACTS_PROTOCOL_TARGET) ? 'T' : 't', \ + ((pflags) & MPI_PORTFACTS_PROTOCOL_LAN) ? 'L' : 'l', \ + ((pflags) & MPI_PORTFACTS_PROTOCOL_LOGBUSADDR) ? 'B' : 'b' + +/*}-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +#endif + diff -u --recursive --new-file v2.4.6/linux/drivers/message/fusion/mptctl.c linux/drivers/message/fusion/mptctl.c --- v2.4.6/linux/drivers/message/fusion/mptctl.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/message/fusion/mptctl.c Fri Jul 6 17:03:11 2001 @@ -0,0 +1,1296 @@ +/* + * linux/drivers/message/fusion/mptctl.c + * Fusion MPT misc device (ioctl) driver. + * For use with PCI chip/adapter(s): + * LSIFC9xx/LSI409xx Fibre Channel + * running LSI Logic Fusion MPT (Message Passing Technology) firmware. + * + * Credits: + * This driver would not exist if not for Alan Cox's development + * of the linux i2o driver. + * + * A huge debt of gratitude is owed to David S. Miller (DaveM) + * for fixing much of the stupid and broken stuff in the early + * driver while porting to sparc64 platform. THANK YOU! + * + * A big THANKS to Eddie C. Dost for fixing the ioctl path + * and most importantly f/w download on sparc64 platform! + * (plus Eddie's other helpful hints and insights) + * + * Thanks to Arnaldo Carvalho de Melo for finding and patching + * a potential memory leak in mpt_ioctl_do_fw_download(), + * and for some kmalloc insight:-) + * + * (see also mptbase.c) + * + * Copyright (c) 1999-2001 LSI Logic Corporation + * Originally By: Steven J. Ralston, Noah Romer + * (mailto:Steve.Ralston@lsil.com) + * + * $Id: mptctl.c,v 1.23 2001/03/21 19:42:31 sralston Exp $ + */ +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + 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; version 2 of the License. + + 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. + + NO WARRANTY + THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR + CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT + LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, + MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is + solely responsible for determining the appropriateness of using and + distributing the Program and assumes all risks associated with its + exercise of rights under this Agreement, including but not limited to + the risks and costs of program errors, damage to or loss of data, + programs or equipment, and unavailability or interruption of operations. + + DISCLAIMER OF LIABILITY + NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), 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 OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED + HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + +#include <linux/version.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/errno.h> +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/types.h> +#include <linux/pci.h> +#include <linux/miscdevice.h> + +#include <asm/io.h> +#include <asm/uaccess.h> + +#include <linux/proc_fs.h> + +#define COPYRIGHT "Copyright (c) 1999-2001 LSI Logic Corporation" +#define MODULEAUTHOR "Steven J. Ralston, Noah Romer" +#include "mptbase.h" + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +#define my_NAME "Fusion MPT misc device (ioctl) driver" +#define my_VERSION MPT_LINUX_VERSION_COMMON +#define MYNAM "mptctl" + +EXPORT_NO_SYMBOLS; +MODULE_AUTHOR(MODULEAUTHOR); +MODULE_DESCRIPTION(my_NAME); + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + +static int mptctl_id = -1; +static int rwperf_reset = 0; +static struct semaphore mptctl_syscall_sem_ioc[MPT_MAX_ADAPTERS]; + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + +static int mpt_ioctl_rwperf(unsigned long arg); +static int mpt_ioctl_rwperf_status(unsigned long arg); +static int mpt_ioctl_rwperf_reset(unsigned long arg); +static int mpt_ioctl_fw_download(unsigned long arg); +static int mpt_ioctl_do_fw_download(int ioc, char *ufwbuf, size_t fwlen); +static int mpt_ioctl_scsi_cmd(unsigned long arg); + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * Scatter gather list (SGL) sizes and limits... + */ +//#define MAX_SCSI_FRAGS 9 +#define MAX_FRAGS_SPILL1 9 +#define MAX_FRAGS_SPILL2 15 +#define FRAGS_PER_BUCKET (MAX_FRAGS_SPILL2 + 1) + +//#define MAX_CHAIN_FRAGS 64 +//#define MAX_CHAIN_FRAGS (15+15+15+16) +#define MAX_CHAIN_FRAGS (4 * MAX_FRAGS_SPILL2 + 1) + +// Define max sg LIST bytes ( == (#frags + #chains) * 8 bytes each) +// Works out to: 592d bytes! (9+1)*8 + 4*(15+1)*8 +// ^----------------- 80 + 512 +#define MAX_SGL_BYTES ((MAX_FRAGS_SPILL1 + 1 + (4 * FRAGS_PER_BUCKET)) * 8) + +/* linux only seems to ever give 128kB MAX contiguous (GFP_USER) mem bytes */ +#define MAX_KMALLOC_SZ (128*1024) + +struct buflist { + u8 *kptr; + int len; +}; + +#define myMAX_TARGETS (1<<4) +#define myMAX_LUNS (1<<3) +#define myMAX_T_MASK (myMAX_TARGETS-1) +#define myMAX_L_MASK (myMAX_LUNS-1) +static u8 DevInUse[myMAX_TARGETS][myMAX_LUNS] = {{0,0}}; +static u32 DevIosCount[myMAX_TARGETS][myMAX_LUNS] = {{0,0}}; + +static u32 fwReplyBuffer[16]; +static pMPIDefaultReply_t ReplyMsg = NULL; + +/* some private forw protos */ +static SGESimple32_t *kbuf_alloc_2_sgl( int bytes, u32 dir, int *frags, + struct buflist **blp, dma_addr_t *sglbuf_dma, MPT_ADAPTER *ioc); +static void kfree_sgl( SGESimple32_t *sgl, dma_addr_t sgl_dma, + struct buflist *buflist, MPT_ADAPTER *ioc); + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/** + * mptctl_syscall_down - Down the MPT adapter syscall semaphore. + * @ioc: Pointer to MPT adapter + * @nonblock: boolean, non-zero if O_NONBLOCK is set + * + * All of the mptctl commands can potentially sleep, which is illegal + * with a spinlock held, thus we perform mutual exclusion here. + * + * Returns negative errno on error, or zero for success. + */ +static inline int +mptctl_syscall_down(MPT_ADAPTER *ioc, int nonblock) +{ + dprintk((KERN_INFO MYNAM "::mpt_syscall_down(%p,%d) called\n", ioc, nonblock)); + + if (nonblock) { + if (down_trylock(&mptctl_syscall_sem_ioc[ioc->id])) + return -EAGAIN; + } else { + if (down_interruptible(&mptctl_syscall_sem_ioc[ioc->id])) + return -ERESTARTSYS; + } + return 0; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * This is the callback for any message we have posted. The message itself + * will be returned to the message pool when we return from the IRQ + * + * This runs in irq context so be short and sweet. + */ +static int +mptctl_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply) +{ + u8 targ; + + //dprintk((KERN_DEBUG MYNAM ": Got mptctl_reply()!\n")); + + if (req && req->u.hdr.Function == MPI_FUNCTION_SCSI_IO_REQUEST) { + targ = req->u.scsireq.TargetID & myMAX_T_MASK; + DevIosCount[targ][0]--; + } else if (reply && req && req->u.hdr.Function == MPI_FUNCTION_FW_DOWNLOAD) { + // NOTE: Expects/requires non-Turbo reply! + dprintk((KERN_INFO MYNAM ": Caching MPI_FUNCTION_FW_DOWNLOAD reply!\n")); + memcpy(fwReplyBuffer, reply, MIN(sizeof(fwReplyBuffer), 4*reply->u.reply.MsgLength)); + ReplyMsg = (pMPIDefaultReply_t) fwReplyBuffer; + } + + return 1; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +static loff_t +mptctl_llseek(struct file *file, loff_t offset, int origin) +{ + return -ESPIPE; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +static ssize_t +mptctl_write(struct file *file, const char *buf, size_t count, loff_t *ppos) +{ + printk(KERN_ERR MYNAM ": ioctl WRITE not yet supported\n"); + return 0; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +static ssize_t +mptctl_read(struct file *file, char *buf, size_t count, loff_t *ptr) +{ + return 0; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * MPT ioctl handler + */ +static int +mpt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) +{ + struct mpt_ioctl_sanity *usanity = (struct mpt_ioctl_sanity *) arg; + struct mpt_ioctl_sanity ksanity; + int iocnum; + unsigned iocnumX; + int nonblock = (file->f_flags & O_NONBLOCK); + int ret; + MPT_ADAPTER *iocp = NULL; + + dprintk((KERN_INFO MYNAM "::mpt_ioctl() called\n")); + + if (copy_from_user(&ksanity, usanity, sizeof(ksanity))) { + printk(KERN_ERR "%s::mpt_ioctl() @%d - " + "Unable to copy mpt_ioctl_sanity data @ %p\n", + __FILE__, __LINE__, (void*)usanity); + return -EFAULT; + } + ret = -ENXIO; /* (-6) No such device or address */ + + /* Verify intended MPT adapter */ + iocnumX = ksanity.iocnum & 0xFF; + if (((iocnum = mpt_verify_adapter(iocnumX, &iocp)) < 0) || + (iocp == NULL)) { + printk(KERN_ERR "%s::mpt_ioctl() @%d - ioc%d not found!\n", + __FILE__, __LINE__, iocnumX); + return -ENODEV; + } + + if ((ret = mptctl_syscall_down(iocp, nonblock)) != 0) + return ret; + + dprintk((KERN_INFO MYNAM "::mpt_ioctl() - Using %s\n", iocp->name)); + + switch(cmd) { + case MPTRWPERF: + ret = mpt_ioctl_rwperf(arg); + break; + case MPTRWPERF_CHK: + ret = mpt_ioctl_rwperf_status(arg); + break; + case MPTRWPERF_RESET: + ret = mpt_ioctl_rwperf_reset(arg); + break; + case MPTFWDOWNLOAD: + ret = mpt_ioctl_fw_download(arg); + break; + case MPTSCSICMD: + ret = mpt_ioctl_scsi_cmd(arg); + break; + default: + ret = -EINVAL; + } + + up(&mptctl_syscall_sem_ioc[iocp->id]); + + return ret; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +static int mptctl_open(struct inode *inode, struct file *file) +{ + /* + * Should support multiple management users + */ + return 0; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +static int mptctl_release(struct inode *inode, struct file *file) +{ + return 0; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +static int +mpt_ioctl_fw_download(unsigned long arg) +{ + struct mpt_fw_xfer *ufwdl = (struct mpt_fw_xfer *) arg; + struct mpt_fw_xfer kfwdl; + + dprintk((KERN_INFO "mpt_ioctl_fwdl called. mptctl_id = %xh\n", mptctl_id)); //tc + if (copy_from_user(&kfwdl, ufwdl, sizeof(struct mpt_fw_xfer))) { + printk(KERN_ERR "%s@%d::_ioctl_fwdl - " + "Unable to copy mpt_fw_xfer struct @ %p\n", + __FILE__, __LINE__, (void*)ufwdl); + return -EFAULT; + } + + return mpt_ioctl_do_fw_download(kfwdl.iocnum, kfwdl.bufp, kfwdl.fwlen); +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * MPT FW Download + */ +static int +mpt_ioctl_do_fw_download(int ioc, char *ufwbuf, size_t fwlen) +{ + FWDownload_t *dlmsg; + MPT_FRAME_HDR *mf; + MPT_ADAPTER *iocp; +// char *fwbuf; +// dma_addr_t fwbuf_dma; + FWDownloadTCSGE_t *fwVoodoo; +// SGEAllUnion_t *fwSgl; + int ret; + + SGESimple32_t *sgl; + SGESimple32_t *sgOut, *sgIn; + dma_addr_t sgl_dma; + struct buflist *buflist; + struct buflist *bl; + int numfrags = 0; + int maxfrags; + int n = 0; + u32 sgdir; + u32 nib; + int fw_bytes_copied = 0; + u16 iocstat; + int i; + + dprintk((KERN_INFO "mpt_ioctl_do_fwdl called. mptctl_id = %xh.\n", mptctl_id)); + + dprintk((KERN_INFO "DbG: kfwdl.bufp = %p\n", ufwbuf)); + dprintk((KERN_INFO "DbG: kfwdl.fwlen = %d\n", (int)fwlen)); + dprintk((KERN_INFO "DbG: kfwdl.ioc = %04xh\n", ioc)); + + if ((ioc = mpt_verify_adapter(ioc, &iocp)) < 0) { + printk("%s@%d::_ioctl_fwdl - ioc%d not found!\n", + __FILE__, __LINE__, ioc); + return -ENXIO; /* (-6) No such device or address */ + } + + if ((mf = mpt_get_msg_frame(mptctl_id, ioc)) == NULL) + return -EAGAIN; + dlmsg = (FWDownload_t*) mf; + fwVoodoo = (FWDownloadTCSGE_t *) &dlmsg->SGL; + sgOut = (SGESimple32_t *) (fwVoodoo + 1); + + /* + * Construct f/w download request + */ + dlmsg->ImageType = MPI_FW_DOWNLOAD_ITYPE_FW; + dlmsg->Reserved = 0; + dlmsg->ChainOffset = 0; + dlmsg->Function = MPI_FUNCTION_FW_DOWNLOAD; + dlmsg->Reserved1[0] = dlmsg->Reserved1[1] = dlmsg->Reserved1[2] = 0; + dlmsg->MsgFlags = 0; + + fwVoodoo->Reserved = 0; + fwVoodoo->ContextSize = 0; + fwVoodoo->DetailsLength = 12; + fwVoodoo->Flags = MPI_SGE_FLAGS_TRANSACTION_ELEMENT; + fwVoodoo->Reserved1 = 0; + fwVoodoo->ImageOffset = 0; + fwVoodoo->ImageSize = cpu_to_le32(fwlen); + + /* + * Need to kmalloc area(s) for holding firmware image bytes. + * But we need to do it piece meal, using a proper + * scatter gather list (with 128kB MAX hunks). + * + * A practical limit here might be # of sg hunks that fit into + * a single IOC request frame; 12 or 8 (see below), so: + * For FC9xx: 12 x 128kB == 1.5 mB (max) + * For C1030: 8 x 128kB == 1 mB (max) + * We could support chaining, but things get ugly(ier:) + */ + sgdir = 0x04000000; /* IOC will READ from sys mem */ + if ((sgl = kbuf_alloc_2_sgl(fwlen, sgdir, &numfrags, &buflist, &sgl_dma, iocp)) == NULL) + return -ENOMEM; + + /* + * We should only need SGL with 2 simple_32bit entries (up to 256 kB) + * for FC9xx f/w image, but calculate max number of sge hunks + * we can fit into a request frame, and limit ourselves to that. + * (currently no chain support) + * For FC9xx: (128-12-16)/8 = 12.5 = 12 + * For C1030: (96-12-16)/8 = 8.5 = 8 + */ + maxfrags = (iocp->req_sz - sizeof(MPIHeader_t) - sizeof(FWDownloadTCSGE_t)) / sizeof(SGESimple32_t); + if (numfrags > maxfrags) { + ret = -EMLINK; + goto fwdl_out; + } + + dprintk((KERN_INFO "DbG: sgl buffer = %p, sgfrags = %d\n", sgl, numfrags)); + + /* + * Parse SG list, copying sgl itself, + * plus f/w image hunks from user space as we go... + */ + ret = -EFAULT; + sgIn = sgl; + bl = buflist; + for (i=0; i < numfrags; i++) { + nib = (sgIn->FlagsLength & 0xF0000000) >> 28; + /* skip ignore/chain. */ + if (nib == 0 || nib == 3) { + ; + } else if (sgIn->Address) { + *sgOut = *sgIn; + n++; + if (copy_from_user(bl->kptr, ufwbuf+fw_bytes_copied, bl->len)) { + printk(KERN_ERR "%s@%d::_ioctl_fwdl - " + "Unable to copy f/w buffer hunk#%d @ %p\n", + __FILE__, __LINE__, n, (void*)ufwbuf); + goto fwdl_out; + } + fw_bytes_copied += bl->len; + } + sgIn++; + bl++; + sgOut++; + } + +#ifdef MPT_DEBUG + { + u32 *m = (u32 *)mf; + printk(KERN_INFO MYNAM ": F/W download request:\n" KERN_INFO " "); + for (i=0; i < 7+numfrags*2; i++) + printk(" %08x", le32_to_cpu(m[i])); + printk("\n"); + } +#endif + + /* + * Finally, perform firmware download. + */ + ReplyMsg = NULL; + mpt_put_msg_frame(mptctl_id, ioc, mf); + + /* + * Wait until the reply has been received + */ + { + int foo = 0; + + while (ReplyMsg == NULL) { + if (!(foo%1000000)) { + dprintk((KERN_INFO "DbG::_do_fwdl: " + "In ReplyMsg loop - iteration %d\n", + foo)); //tc + } + ret = -ETIME; + if (++foo > 60000000) + goto fwdl_out; + mb(); + schedule(); + barrier(); + } + } + + if (sgl) + kfree_sgl(sgl, sgl_dma, buflist, iocp); + + iocstat = le16_to_cpu(ReplyMsg->IOCStatus) & MPI_IOCSTATUS_MASK; + if (iocstat == MPI_IOCSTATUS_SUCCESS) { + printk(KERN_INFO MYNAM ": F/W update successfully sent to %s!\n", iocp->name); + return 0; + } else if (iocstat == MPI_IOCSTATUS_INVALID_FUNCTION) { + printk(KERN_WARNING MYNAM ": ?Hmmm... %s says it doesn't support F/W download!?!\n", + iocp->name); + printk(KERN_WARNING MYNAM ": (time to go bang on somebodies door)\n"); + return -EBADRQC; + } else if (iocstat == MPI_IOCSTATUS_BUSY) { + printk(KERN_WARNING MYNAM ": Warning! %s says: IOC_BUSY!\n", iocp->name); + printk(KERN_WARNING MYNAM ": (try again later?)\n"); + return -EBUSY; + } else { + printk(KERN_WARNING MYNAM "::ioctl_fwdl() ERROR! %s returned [bad] status = %04xh\n", + iocp->name, iocstat); + printk(KERN_WARNING MYNAM ": (bad VooDoo)\n"); + return -ENOMSG; + } + return 0; + +fwdl_out: + kfree_sgl(sgl, sgl_dma, buflist, iocp); + return ret; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * NEW rwperf (read/write performance) stuff starts here... + */ + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +static SGESimple32_t * +kbuf_alloc_2_sgl(int bytes, u32 sgdir, int *frags, + struct buflist **blp, dma_addr_t *sglbuf_dma, MPT_ADAPTER *ioc) +{ + SGESimple32_t *sglbuf = NULL; + struct buflist *buflist = NULL; + int numfrags = 0; + int fragcnt = 0; + int alloc_sz = MIN(bytes,MAX_KMALLOC_SZ); // avoid kernel warning msg! + int bytes_allocd = 0; + int this_alloc; + SGESimple32_t *sgl; + u32 pa; // phys addr + SGEChain32_t *last_chain = NULL; + SGEChain32_t *old_chain = NULL; + int chaincnt = 0; + int i, buflist_ent; + int sg_spill = MAX_FRAGS_SPILL1; + int dir; + + *frags = 0; + *blp = NULL; + i = MAX_SGL_BYTES / 8; + buflist = kmalloc(i, GFP_USER); + if (buflist == NULL) + return NULL; + memset(buflist, 0, i); + buflist_ent = 0; + + sglbuf = pci_alloc_consistent(ioc->pcidev, MAX_SGL_BYTES, sglbuf_dma); + if (sglbuf == NULL) + goto free_and_fail; + + if (sgdir & 0x04000000) + dir = PCI_DMA_TODEVICE; + else + dir = PCI_DMA_FROMDEVICE; + + sgl = sglbuf; + while (bytes_allocd < bytes) { + this_alloc = MIN(alloc_sz, bytes-bytes_allocd); + buflist[buflist_ent].len = this_alloc; + buflist[buflist_ent].kptr = pci_alloc_consistent(ioc->pcidev, + this_alloc, + &pa); + if (buflist[buflist_ent].kptr == NULL) { + alloc_sz = alloc_sz / 2; + if (alloc_sz == 0) { + printk(KERN_WARNING MYNAM "-SG: No can do - " + "not enough memory! :-(\n"); + printk(KERN_WARNING MYNAM "-SG: (freeing %d frags)\n", + numfrags); + goto free_and_fail; + } + continue; + } else { + dma_addr_t dma_addr; + + bytes_allocd += this_alloc; + + /* Write one SIMPLE sge */ + sgl->FlagsLength = cpu_to_le32(0x10000000|sgdir|this_alloc); + dma_addr = pci_map_single(ioc->pcidev, buflist[buflist_ent].kptr, this_alloc, dir); + sgl->Address = cpu_to_le32(dma_addr); + + fragcnt++; + numfrags++; + sgl++; + buflist_ent++; + } + + if (bytes_allocd >= bytes) + break; + + /* Need to chain? */ + if (fragcnt == sg_spill) { + dma_addr_t chain_link; + + if (last_chain != NULL) + last_chain->NextChainOffset = 0x1E; + + fragcnt = 0; + sg_spill = MAX_FRAGS_SPILL2; + + /* fixup previous SIMPLE sge */ + sgl[-1].FlagsLength |= cpu_to_le32(0x80000000); + + chain_link = (*sglbuf_dma) + + ((u8 *)(sgl+1) - (u8 *)sglbuf); + + /* Write one CHAIN sge */ + sgl->FlagsLength = cpu_to_le32(0x30000080); + sgl->Address = cpu_to_le32(chain_link); + + old_chain = last_chain; + last_chain = (SGEChain32_t*)sgl; + chaincnt++; + numfrags++; + sgl++; + } + + /* overflow check... */ + if (numfrags*8 > MAX_SGL_BYTES) { + /* GRRRRR... */ + printk(KERN_WARNING MYNAM "-SG: No can do - " + "too many SG frags! :-(\n"); + printk(KERN_WARNING MYNAM "-SG: (freeing %d frags)\n", + numfrags); + goto free_and_fail; + } + } + + /* Last sge fixup: set LE+eol+eob bits */ + sgl[-1].FlagsLength |= cpu_to_le32(0xC1000000); + + /* Chain fixup needed? */ + if (last_chain != NULL && fragcnt < 16) + last_chain->Length = cpu_to_le16(fragcnt * 8); + + *frags = numfrags; + *blp = buflist; + + dprintk((KERN_INFO MYNAM "-SG: kbuf_alloc_2_sgl() - " + "%d SG frags generated! (%d CHAIN%s)\n", + numfrags, chaincnt, chaincnt>1?"s":"")); + + dprintk((KERN_INFO MYNAM "-SG: kbuf_alloc_2_sgl() - " + "last (big) alloc_sz=%d\n", + alloc_sz)); + + return sglbuf; + +free_and_fail: + if (sglbuf != NULL) { + int i; + + for (i = 0; i < numfrags; i++) { + dma_addr_t dma_addr; + u8 *kptr; + int len; + + if ((sglbuf[i].FlagsLength >> 24) == 0x30) + continue; + + dma_addr = le32_to_cpu(sglbuf[i].Address); + kptr = buflist[i].kptr; + len = buflist[i].len; + + pci_free_consistent(ioc->pcidev, len, kptr, dma_addr); + } + pci_free_consistent(ioc->pcidev, MAX_SGL_BYTES, sglbuf, *sglbuf_dma); + } + kfree(buflist); + return NULL; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +static void +kfree_sgl(SGESimple32_t *sgl, dma_addr_t sgl_dma, struct buflist *buflist, MPT_ADAPTER *ioc) +{ + SGESimple32_t *sg = sgl; + struct buflist *bl = buflist; + u32 nib; + int dir; + int n = 0; + + if (sg->FlagsLength & 0x04000000) + dir = PCI_DMA_TODEVICE; + else + dir = PCI_DMA_FROMDEVICE; + + nib = (sg->FlagsLength & 0xF0000000) >> 28; + while (! (nib & 0x4)) { /* eob */ + /* skip ignore/chain. */ + if (nib == 0 || nib == 3) { + ; + } else if (sg->Address) { + dma_addr_t dma_addr; + void *kptr; + int len; + + dma_addr = le32_to_cpu(sg->Address); + kptr = bl->kptr; + len = bl->len; + pci_unmap_single(ioc->pcidev, dma_addr, len, dir); + pci_free_consistent(ioc->pcidev, len, kptr, dma_addr); + n++; + } + sg++; + bl++; + nib = (sg->FlagsLength & 0xF0000000) >> 28; + } + + /* we're at eob! */ + if (sg->Address) { + dma_addr_t dma_addr; + void *kptr; + int len; + + dma_addr = le32_to_cpu(sg->Address); + kptr = bl->kptr; + len = bl->len; + pci_unmap_single(ioc->pcidev, dma_addr, len, dir); + pci_free_consistent(ioc->pcidev, len, kptr, dma_addr); + n++; + } + + pci_free_consistent(ioc->pcidev, MAX_SGL_BYTES, sgl, sgl_dma); + kfree(buflist); + dprintk((KERN_INFO MYNAM "-SG: Free'd 1 SGL buf + %d kbufs!\n", n)); +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +static int +mpt_ioctl_rwperf_init(struct mpt_raw_r_w *dest, unsigned long src, + char *caller, MPT_ADAPTER **iocpp) +{ + char *myname = "_rwperf_init()"; + int ioc; + + /* get copy of structure passed from user space */ + if (copy_from_user(dest, (void*)src, sizeof(*dest))) { + printk(KERN_ERR MYNAM "::%s() @%d - Can't copy mpt_raw_r_w data @ %p\n", + myname, __LINE__, (void*)src); + return -EFAULT; /* (-14) Bad address */ + } else { + dprintk((KERN_INFO MYNAM "-perf: PerfInfo.{ioc,targ,qd,iters,nblks}" + ": %d %d %d %d %d\n", + dest->iocnum, dest->target, + (int)dest->qdepth, dest->iters, dest->nblks )); + dprintk((KERN_INFO MYNAM "-perf: PerfInfo.{cache,skip,range,rdwr,seqran}" + ": %d %d %d %d %d\n", + dest->cache_sz, dest->skip, dest->range, + dest->rdwr, dest->seqran )); + + /* Get the MPT adapter id. */ + if ((ioc = mpt_verify_adapter(dest->iocnum, iocpp)) < 0) { + printk(KERN_ERR MYNAM "::%s() @%d - ioc%d not found!\n", + myname, __LINE__, dest->iocnum); + return -ENXIO; /* (-6) No such device or address */ + } else { + dprintk((MYNAM "-perf: %s using mpt/ioc%x, target %02xh\n", + caller, dest->iocnum, dest->target)); + } + } + + return ioc; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + +/* Treat first N blocks of disk as sacred! */ +#define SACRED_BLOCKS 100 + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +static int +mpt_ioctl_rwperf(unsigned long arg) +{ + struct mpt_raw_r_w kPerfInfo; + /* NOTE: local copy, on stack==KERNEL_SPACE! */ + u8 target, targetM; + u8 lun, lunM; + u8 scsiop; + int qdepth; + int iters; + int cache_sz; + u32 xferbytes; + u32 scsidir; + u32 qtag; + u32 scsictl; + u32 sgdir; + u32 blkno; + u32 sbphys; + SGESimple32_t *sgl; + dma_addr_t sgl_dma; + struct buflist *buflist; + SGESimple32_t *sgOut, *sgIn; + int numfrags; + u32 *msg; + int i; + int ioc; + MPT_FRAME_HDR *mf; + MPT_ADAPTER *iocp; + int sgfragcpycnt; + int blklo, blkhi; + u8 nextchainoffset; + u8 *SenseBuf; + dma_addr_t SenseBufDMA; + char *myname = "_rwperf()"; + + dprintk((KERN_INFO "%s - starting...\n", myname)); + + /* Validate target device */ + if ((ioc = mpt_ioctl_rwperf_init(&kPerfInfo, arg, myname, &iocp)) < 0) + return ioc; + + /* Allocate DMA'able memory for the sense buffer. */ + SenseBuf = pci_alloc_consistent(iocp->pcidev, 256, &SenseBufDMA); + + /* set perf parameters from input */ + target = kPerfInfo.target & 0x0FF; + targetM = target & myMAX_T_MASK; + lun = kPerfInfo.lun & 0x1F; // LUN=31 max + lunM = lun & myMAX_L_MASK; + qdepth = kPerfInfo.qdepth; + iters = kPerfInfo.iters; + xferbytes = ((u32)kPerfInfo.nblks)<<9; + + DevInUse[targetM][lunM] = 1; + DevIosCount[targetM][lunM] = 0; + + cache_sz = kPerfInfo.cache_sz * 1024; // CacheSz in kB! + + /* ToDo: */ + /* get capacity (?) */ + + + // pre-build, one time, everything we can for speed in the loops below... + + scsiop = 0x28; // default to SCSI READ! + scsidir = MPI_SCSIIO_CONTROL_READ; // DATA IN (host<--ioc<--dev) + // 02000000 + qtag = MPI_SCSIIO_CONTROL_SIMPLEQ; // 00000000 + + if (xferbytes == 0) { + // Do 0-byte READ!!! + // IMPORTANT! Need to set no SCSI DIR for this! + scsidir = MPI_SCSIIO_CONTROL_NODATATRANSFER; + } + + scsictl = scsidir | qtag; + + /* + * Set sgdir for DMA transfer. + */ +// sgdir = 0x04000000; // SCSI WRITE + sgdir = 0x00000000; // SCSI READ + + if ((sgl = kbuf_alloc_2_sgl(MAX(512,xferbytes), sgdir, &numfrags, &buflist, &sgl_dma, iocp)) == NULL) + return -ENOMEM; + + sgfragcpycnt = MIN(10,numfrags); + nextchainoffset = 0; + if (numfrags > 10) + nextchainoffset = 0x1E; + + sbphys = SenseBufDMA; + + rwperf_reset = 0; + +// do { // target-loop + + blkno = SACRED_BLOCKS; // Treat first N blocks as sacred! + // FIXME! Skip option + blklo = blkno; + blkhi = blkno; + + do { // inner-loop + + while ((mf = mpt_get_msg_frame(mptctl_id, ioc)) == NULL) { + mb(); + schedule(); + barrier(); + } + msg = (u32*)mf; + + /* Start piecing the SCSIIORequest together */ + msg[0] = 0x00000000 | nextchainoffset<<16 | target; + msg[1] = 0x0000FF0A; // 255 sense bytes, 10-byte CDB! + msg[3] = lun << 8; + msg[4] = 0; + msg[5] = scsictl; + + // 16 bytes of CDB @ msg[6,7,8,9] are below... + + msg[6] = ( ((blkno & 0xFF000000) >> 8) + | ((blkno & 0x00FF0000) << 8) + | scsiop ); + msg[7] = ( (((u32)kPerfInfo.nblks & 0x0000FF00) << 16) + | ((blkno & 0x000000FF) << 8) + | ((blkno & 0x0000FF00) >> 8) ); + msg[8] = (kPerfInfo.nblks & 0x00FF); + msg[9] = 0; + + msg[10] = xferbytes; + +// msg[11] = 0xD0000100; +// msg[12] = sbphys; +// msg[13] = 0; + msg[11] = sbphys; + + // Copy the SGL... + if (xferbytes) { + sgOut = (SGESimple32_t*)&msg[12]; + sgIn = sgl; + for (i=0; i < sgfragcpycnt; i++) + *sgOut++ = *sgIn++; + } + + // fubar! QueueDepth issue!!! + while ( !rwperf_reset + && (DevIosCount[targetM][lunM] >= MIN(qdepth,64)) ) + { + mb(); + schedule(); + barrier(); + } + +// blkno += kPerfInfo.nblks; +// EXP Stuff! +// Try optimizing to certain cache size for the target! +// by keeping blkno within cache range if at all possible +#if 0 + if ( cache_sz + && ((2 * kPerfInfo.nblks) <= (cache_sz>>9)) + && ((blkno + kPerfInfo.nblks) > ((cache_sz>>9) + SACRED_BLOCKS)) ) + blkno = SACRED_BLOCKS; + else + blkno += kPerfInfo.nblks; +#endif +// Ok, cheat! + if (cache_sz && ((blkno + kPerfInfo.nblks) > ((cache_sz>>9) + SACRED_BLOCKS)) ) + blkno = SACRED_BLOCKS; + else + blkno += kPerfInfo.nblks; + + if (blkno > blkhi) + blkhi = blkno; + + DevIosCount[targetM][lunM]++; + + /* + * Finally, post the request + */ + mpt_put_msg_frame(mptctl_id, ioc, mf); + + + /* let linux breath! */ + mb(); + schedule(); + barrier(); + + //dprintk((KERN_DEBUG MYNAM "-perf: inner-loop, cnt=%d\n", iters)); + + } while ((--iters > 0) && !rwperf_reset); + + dprintk((KERN_INFO MYNAM "-perf: DbG: blklo=%d, blkhi=%d\n", blklo, blkhi)); + dprintk((KERN_INFO MYNAM "-perf: target-loop, thisTarget=%d\n", target)); + +// // TEMPORARY! +// target = 0; + +// } while (target); + + + if (DevIosCount[targetM][lunM]) { + dprintk((KERN_INFO " DbG: DevIosCount[%d][%d]=%d\n", + targetM, lunM, DevIosCount[targetM][lunM])); + } + + while (DevIosCount[targetM][lunM]) { + //dprintk((KERN_DEBUG " DbG: Waiting... DevIosCount[%d][%d]=%d\n", + // targetM, lunM, DevIosCount[targetM][lunM])); + mb(); + schedule(); + barrier(); + } + DevInUse[targetM][lunM] = 0; + + pci_free_consistent(iocp->pcidev, 256, SenseBuf, SenseBufDMA); + + if (sgl) + kfree_sgl(sgl, sgl_dma, buflist, iocp); + + dprintk((KERN_INFO " *** done ***\n")); + + return 0; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +static int +mpt_ioctl_rwperf_status(unsigned long arg) +{ + struct mpt_raw_r_w kPerfInfo; + /* NOTE: local copy, on stack==KERNEL_SPACE! */ + MPT_ADAPTER *iocp; + int ioc; +// u8 targ; +// u8 lun; + int T, L; + char *myname = "_rwperf_status()"; + + + dprintk((KERN_INFO "%s - starting...\n", myname)); + + /* Get a pointer to the MPT adapter. */ + if ((ioc = mpt_ioctl_rwperf_init(&kPerfInfo, arg, myname, &iocp)) < 0) + return ioc; + + /* set perf parameters from input */ +// targ = kPerfInfo.target & 0xFF; +// lun = kPerfInfo.lun & 0x1F; + + for (T=0; T < myMAX_TARGETS; T++) + for (L=0; L < myMAX_LUNS; L++) + if (DevIosCount[T][L]) { + printk(KERN_INFO "%s: ioc%d->00:%02x:%02x" + ", IosCnt=%d\n", + myname, ioc, T, L, DevIosCount[T][L] ); + } + + return 0; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +static int +mpt_ioctl_rwperf_reset(unsigned long arg) +{ + struct mpt_raw_r_w kPerfInfo; + /* NOTE: local copy, on stack==KERNEL_SPACE! */ + MPT_ADAPTER *iocp; + int ioc; +// u8 targ; +// u8 lun; + int T, L; + int i; + char *myname = "_rwperf_reset()"; + + dprintk((KERN_INFO "%s - starting...\n", myname)); + + /* Get MPT adapter id. */ + if ((ioc = mpt_ioctl_rwperf_init(&kPerfInfo, arg, myname, &iocp)) < 0) + return ioc; + + /* set perf parameters from input */ +// targ = kPerfInfo.target & 0xFF; +// lun = kPerfInfo.lun & 0x1F; + + rwperf_reset = 1; + for (i=0; i < 1000000; i++) { + mb(); + schedule(); + barrier(); + } + rwperf_reset = 0; + + for (T=0; T < myMAX_TARGETS; T++) + for (L=0; L < myMAX_LUNS; L++) + if (DevIosCount[T][L]) { + printk(KERN_INFO "%s: ioc%d->00:%02x:%02x, " + "IosCnt RESET! (from %d to 0)\n", + myname, ioc, T, L, DevIosCount[T][L] ); + DevIosCount[T][L] = 0; + DevInUse[T][L] = 0; + } + + return 0; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +static int +mpt_ioctl_scsi_cmd(unsigned long arg) +{ + return -ENOSYS; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + +static struct file_operations mptctl_fops = { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,51) + owner: THIS_MODULE, +#endif + llseek: mptctl_llseek, + read: mptctl_read, + write: mptctl_write, + ioctl: mpt_ioctl, + open: mptctl_open, + release: mptctl_release, +}; + +static struct miscdevice mptctl_miscdev = { + MPT_MINOR, + MYNAM, + &mptctl_fops +}; + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + +#if defined(__sparc__) && defined(__sparc_v9__) /*{*/ + +/* The dynamic ioctl32 compat. registry only exists in >2.3.x sparc64 kernels */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) /*{*/ +extern int register_ioctl32_conversion(unsigned int cmd, + int (*handler)(unsigned int, + unsigned int, + unsigned long, + struct file *)); +int unregister_ioctl32_conversion(unsigned int cmd); + +struct mpt_fw_xfer32 { + unsigned int iocnum; + unsigned int fwlen; + u32 bufp; +}; + +#define MPTFWDOWNLOAD32 _IOWR(MPT_MAGIC_NUMBER,15,struct mpt_fw_xfer32) + +extern asmlinkage int sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg); + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +static int +sparc32_mptfwxfer_ioctl(unsigned int fd, unsigned int cmd, + unsigned long arg, struct file *filp) +{ + struct mpt_fw_xfer32 kfw32; + struct mpt_fw_xfer kfw; + MPT_ADAPTER *iocp = NULL; + int iocnum, iocnumX; + int nonblock = (filp->f_flags & O_NONBLOCK); + int ret; + + dprintk((KERN_INFO MYNAM "::sparc32_mptfwxfer_ioctl() called\n")); + + if (copy_from_user(&kfw32, (char *)arg, sizeof(kfw32))) + return -EFAULT; + + /* Verify intended MPT adapter */ + iocnumX = kfw32.iocnum & 0xFF; + if (((iocnum = mpt_verify_adapter(iocnumX, &iocp)) < 0) || + (iocp == NULL)) { + printk(KERN_ERR MYNAM "::sparc32_mptfwxfer_ioctl @%d - ioc%d not found!\n", + __LINE__, iocnumX); + return -ENODEV; + } + + if ((ret = mptctl_syscall_down(iocp, nonblock)) != 0) + return ret; + + kfw.iocnum = iocnum; + kfw.fwlen = kfw32.fwlen; + kfw.bufp = (void *)(unsigned long)kfw32.bufp; + + ret = mpt_ioctl_do_fw_download(kfw.iocnum, kfw.bufp, kfw.fwlen); + + up(&mptctl_syscall_sem_ioc[iocp->id]); + + return ret; +} + +#if 0 /* { */ +static int +sparc32_mptfwxfer_ioctl(unsigned int fd, unsigned int cmd, + unsigned long arg, struct file *filp) +{ + struct mpt_fw_xfer32 kfw32; + struct mpt_fw_xfer kfw; + mm_segment_t old_fs; + int ret; + + dprintk((KERN_INFO MYNAM "::sparc32_mptfwxfer_ioctl() called\n")); + + if (copy_from_user(&kfw32, (char *)arg, sizeof(kfw32))) + return -EFAULT; + + /* Verify intended MPT adapter */ + iocnumX = kfw32.iocnum & 0xFF; + if (((iocnum = mpt_verify_adapter(iocnumX, &iocp)) < 0) || + (iocp == NULL)) { + printk(KERN_ERR MYNAM "::sparc32_mptfwxfer_ioctl @%d - ioc%d not found!\n", + __LINE__, iocnumX); + return -ENODEV; + } + + if ((ret = mptctl_syscall_down(iocp, nonblock)) != 0) + return ret; + + kfw.iocnum = iocnum; + kfw.fwlen = kfw32.fwlen; + kfw.bufp = (void *)(unsigned long)kfw32.bufp; + + old_fs = get_fs(); + set_fs(KERNEL_DS); + ret = sys_ioctl(fd, MPTFWDOWNLOAD, (unsigned long)&kfw); + set_fs(old_fs); + + up(&mptctl_syscall_sem_ioc[iocp->id]); + + return ret; +} +#endif /* #if 0 } */ + +#endif /*} linux >= 2.3.x */ +#endif /*} sparc */ + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +int __init mptctl_init(void) +{ + int err; + int i; + int where = 1; + + show_mptmod_ver(my_NAME, my_VERSION); + + for (i=0; i<MPT_MAX_ADAPTERS; i++) { + sema_init(&mptctl_syscall_sem_ioc[i], 1); + } + +#if defined(__sparc__) && defined(__sparc_v9__) /*{*/ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) /*{*/ + err = register_ioctl32_conversion(MPTRWPERF, NULL); + if (++where && err) goto out_fail; + err = register_ioctl32_conversion(MPTRWPERF_CHK, NULL); + if (++where && err) goto out_fail; + err = register_ioctl32_conversion(MPTRWPERF_RESET, NULL); + if (++where && err) goto out_fail; + err = register_ioctl32_conversion(MPTFWDOWNLOAD32, + sparc32_mptfwxfer_ioctl); + if (++where && err) goto out_fail; +#endif /*} linux >= 2.3.x */ +#endif /*} sparc */ + + if (misc_register(&mptctl_miscdev) == -1) { + printk(KERN_ERR MYNAM ": Can't register misc device [minor=%d].\n", MPT_MINOR); + err = -EBUSY; + goto out_fail; + } + printk(KERN_INFO MYNAM ": Registered with Fusion MPT base driver\n"); + printk(KERN_INFO MYNAM ": /dev/%s @ (major,minor=%d,%d)\n", + mptctl_miscdev.name, MISC_MAJOR, mptctl_miscdev.minor); + + /* + * Install our handler + */ + ++where; + if ((mptctl_id = mpt_register(mptctl_reply, MPTCTL_DRIVER)) < 0) { + printk(KERN_ERR MYNAM ": ERROR: Failed to register with Fusion MPT base driver\n"); + misc_deregister(&mptctl_miscdev); + err = -EBUSY; + goto out_fail; + } + + return 0; + +out_fail: + +#if defined(__sparc__) && defined(__sparc_v9__) /*{*/ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) /*{*/ + printk(KERN_ERR MYNAM ": ERROR: Failed to register ioctl32_conversion!" + " (%d:err=%d)\n", where, err); + unregister_ioctl32_conversion(MPTRWPERF); + unregister_ioctl32_conversion(MPTRWPERF_CHK); + unregister_ioctl32_conversion(MPTRWPERF_RESET); + unregister_ioctl32_conversion(MPTFWDOWNLOAD32); +#endif /*} linux >= 2.3.x */ +#endif /*} sparc */ + + return err; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +void mptctl_exit(void) +{ + misc_deregister(&mptctl_miscdev); + printk(KERN_INFO MYNAM ": /dev/%s @ (major,minor=%d,%d)\n", + mptctl_miscdev.name, MISC_MAJOR, mptctl_miscdev.minor); + printk(KERN_INFO MYNAM ": Deregistered from Fusion MPT base driver\n"); + + mpt_deregister(mptctl_id); +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + +module_init(mptctl_init); +module_exit(mptctl_exit); diff -u --recursive --new-file v2.4.6/linux/drivers/message/fusion/mptlan.c linux/drivers/message/fusion/mptlan.c --- v2.4.6/linux/drivers/message/fusion/mptlan.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/message/fusion/mptlan.c Fri Jul 6 17:03:11 2001 @@ -0,0 +1,1462 @@ +/* + * linux/drivers/message/fusion/mptlan.c + * IP Over Fibre Channel device driver. + * For use with PCI chip/adapter(s): + * LSIFC9xx/LSI409xx Fibre Channel + * running LSI Logic Fusion MPT (Message Passing Technology) firmware. + * + * Credits: + * This driver would not exist if not for Alan Cox's development + * of the linux i2o driver. + * + * Special thanks goes to the I2O LAN driver people at the + * University of Helsinki, who, unbeknownst to them, provided + * the inspiration and initial structure for this driver. + * + * A huge debt of gratitude is owed to David S. Miller (DaveM) + * for fixing much of the stupid and broken stuff in the early + * driver while porting to sparc64 platform. THANK YOU! + * + * A really huge debt of gratitude is owed to Eddie C. Dost + * for gobs of hard work fixing and optimizing LAN code. + * THANK YOU! + * + * (see also mptbase.c) + * + * Copyright (c) 2000-2001 LSI Logic Corporation + * Originally By: Noah Romer + * + * $Id: mptlan.c,v 1.25 2001/03/02 22:12:04 sralston Exp $ + */ +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + 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; version 2 of the License. + + 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. + + NO WARRANTY + THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR + CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT + LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, + MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is + solely responsible for determining the appropriateness of using and + distributing the Program and assumes all risks associated with its + exercise of rights under this Agreement, including but not limited to + the risks and costs of program errors, damage to or loss of data, + programs or equipment, and unavailability or interruption of operations. + + DISCLAIMER OF LIABILITY + NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), 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 OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED + HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES + + 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 +*/ + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * Define statements used for debugging + */ +//#define MPT_LAN_IO_DEBUG + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + +#include "mptlan.h" +#include <linux/init.h> +#include <linux/module.h> +#include <linux/fs.h> + +#define MYNAM "mptlan" + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * MPT LAN message sizes without variable part. + */ +#define MPT_LAN_RECEIVE_POST_REQUEST_SIZE \ + (sizeof(LANReceivePostRequest_t) - sizeof(SGE_MPI_UNION)) + +#define MPT_LAN_TRANSACTION32_SIZE \ + (sizeof(SGETransaction32_t) - sizeof(u32)) + +/* + * Fusion MPT LAN private structures + */ + +struct BufferControl { + struct sk_buff *skb; + dma_addr_t dma; + unsigned int len; +}; + +struct mpt_lan_priv { + MPT_ADAPTER *mpt_dev; + u8 pnum; /* Port number in the IOC. This is not a Unix network port! */ + + atomic_t buckets_out; /* number of unused buckets on IOC */ + int bucketthresh; /* Send more when this many used */ + + int *mpt_txfidx; /* Free Tx Context list */ + int mpt_txfidx_tail; + spinlock_t txfidx_lock; + + int *mpt_rxfidx; /* Free Rx Context list */ + int mpt_rxfidx_tail; + spinlock_t rxfidx_lock; + + struct BufferControl *RcvCtl; /* Receive BufferControl structs */ + struct BufferControl *SendCtl; /* Send BufferControl structs */ + + int max_buckets_out; /* Max buckets to send to IOC */ + int tx_max_out; /* IOC's Tx queue len */ + + u32 total_posted; + u32 total_received; + struct net_device_stats stats; /* Per device statistics */ + + struct tq_struct post_buckets_task; + unsigned long post_buckets_active; +}; + +struct mpt_lan_ohdr { + u16 dtype; + u8 daddr[FC_ALEN]; + u16 stype; + u8 saddr[FC_ALEN]; +}; + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + +/* + * Forward protos... + */ +static int lan_reply (MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, + MPT_FRAME_HDR *reply); +static int mpt_lan_open(struct net_device *dev); +static int mpt_lan_reset(struct net_device *dev); +static int mpt_lan_close(struct net_device *dev); +static void mpt_lan_post_receive_buckets(void *dev_id); +static void mpt_lan_wake_post_buckets_task(struct net_device *dev); +static int mpt_lan_receive_post_turbo(struct net_device *dev, u32 tmsg); +static int mpt_lan_receive_post_reply(struct net_device *dev, + LANReceivePostReply_t *pRecvRep); +static int mpt_lan_send_turbo(struct net_device *dev, u32 tmsg); +static int mpt_lan_send_reply(struct net_device *dev, + LANSendReply_t *pSendRep); +static int mpt_lan_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply); +static unsigned short mpt_lan_type_trans(struct sk_buff *skb, + struct net_device *dev); + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * Fusion MPT LAN private data + */ +static int LanCtx = -1; + +static u32 max_buckets_out = 127; +static u32 tx_max_out_p = 127 - 16; + +static struct net_device *mpt_landev[MPT_MAX_ADAPTERS+1]; + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * Fusion MPT LAN external data + */ +extern int mpt_lan_index; + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/** + * lan_reply - Handle all data sent from the hardware. + * @ioc: Pointer to MPT_ADAPTER structure + * @mf: Pointer to original MPT request frame (NULL if TurboReply) + * @reply: Pointer to MPT reply frame + * + * Returns 1 indicating original alloc'd request frame ptr + * should be freed, or 0 if it shouldn't. + */ +static int +lan_reply (MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *reply) +{ + struct net_device *dev = mpt_landev[ioc->id]; + int FreeReqFrame = 0; + + dioprintk((KERN_INFO MYNAM ": %s/%s: Got reply.\n", + IOC_AND_NETDEV_NAMES_s_s(dev))); + +// dioprintk((KERN_INFO MYNAM "@lan_reply: mf = %p, reply = %p\n", +// mf, reply)); + + if (mf == NULL) { + u32 tmsg = CAST_PTR_TO_U32(reply); + + dioprintk((KERN_INFO MYNAM ": %s/%s: @lan_reply, tmsg %08x\n", + IOC_AND_NETDEV_NAMES_s_s(dev), + tmsg)); + + switch (GET_LAN_FORM(tmsg)) { + + // NOTE! (Optimization) First case here is now caught in + // mptbase.c::mpt_interrupt() routine and callcack here + // is now skipped for this case! 20001218 -sralston +#if 0 + case LAN_REPLY_FORM_MESSAGE_CONTEXT: +// dioprintk((KERN_INFO MYNAM "/lan_reply: " +// "MessageContext turbo reply received\n")); + FreeReqFrame = 1; + break; +#endif + + case LAN_REPLY_FORM_SEND_SINGLE: +// dioprintk((MYNAM "/lan_reply: " +// "calling mpt_lan_send_reply (turbo)\n")); + + // Potential BUG here? -sralston + // FreeReqFrame = mpt_lan_send_turbo(dev, tmsg); + // If/when mpt_lan_send_turbo would return 1 here, + // calling routine (mptbase.c|mpt_interrupt) + // would Oops because mf has already been set + // to NULL. So after return from this func, + // mpt_interrupt() will attempt to put (NULL) mf ptr + // item back onto it's adapter FreeQ - Oops!:-( + // It's Ok, since mpt_lan_send_turbo() *currently* + // always returns 0, but..., just in case: + + (void) mpt_lan_send_turbo(dev, tmsg); + FreeReqFrame = 0; + + break; + + case LAN_REPLY_FORM_RECEIVE_SINGLE: +// dioprintk((KERN_INFO MYNAM "@lan_reply: " +// "rcv-Turbo = %08x\n", tmsg)); + mpt_lan_receive_post_turbo(dev, tmsg); + break; + + default: + printk (KERN_ERR MYNAM "/lan_reply: Got a turbo reply " + "that I don't know what to do with\n"); + + /* CHECKME! Hmmm... FreeReqFrame is 0 here; is that right? */ + + break; + } + + return FreeReqFrame; + } + +// msg = (u32 *) reply; +// dioprintk((KERN_INFO MYNAM "@lan_reply: msg = %08x %08x %08x %08x\n", +// le32_to_cpu(msg[0]), le32_to_cpu(msg[1]), +// le32_to_cpu(msg[2]), le32_to_cpu(msg[3]))); +// dioprintk((KERN_INFO MYNAM "@lan_reply: Function = %02xh\n", +// reply->u.hdr.Function)); + + switch (reply->u.hdr.Function) { + + case MPI_FUNCTION_LAN_SEND: + { + LANSendReply_t *pSendRep; + + pSendRep = (LANSendReply_t *) reply; + FreeReqFrame = mpt_lan_send_reply(dev, pSendRep); + break; + } + + case MPI_FUNCTION_LAN_RECEIVE: + { + LANReceivePostReply_t *pRecvRep; + + pRecvRep = (LANReceivePostReply_t *) reply; + if (pRecvRep->NumberOfContexts) { + mpt_lan_receive_post_reply(dev, pRecvRep); + if (!(pRecvRep->MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY)) + FreeReqFrame = 1; + } else + dioprintk((KERN_INFO MYNAM "@lan_reply: zero context " + "ReceivePostReply received.\n")); + break; + } + + case MPI_FUNCTION_LAN_RESET: + /* Just a default reply. Might want to check it to + * make sure that everything went ok. + */ + FreeReqFrame = 1; + break; + + case MPI_FUNCTION_EVENT_NOTIFICATION: + case MPI_FUNCTION_EVENT_ACK: + /* UPDATE! 20010120 -sralston + * _EVENT_NOTIFICATION should NOT come down this path any more. + * Should be routed to mpt_lan_event_process(), but just in case... + */ + FreeReqFrame = 1; + break; + + default: + printk (KERN_ERR MYNAM "/lan_reply: Got a non-turbo " + "reply that I don't know what to do with\n"); + + /* CHECKME! Hmmm... FreeReqFrame is 0 here; is that right? */ + FreeReqFrame = 1; + + break; + } + + return FreeReqFrame; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +static int +mpt_lan_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply) +{ + dprintk((KERN_INFO MYNAM ": MPT event routed to LAN driver!\n")); + + switch (le32_to_cpu(pEvReply->Event)) { + case MPI_EVENT_NONE: /* 00 */ + case MPI_EVENT_LOG_DATA: /* 01 */ + case MPI_EVENT_STATE_CHANGE: /* 02 */ + case MPI_EVENT_UNIT_ATTENTION: /* 03 */ + case MPI_EVENT_IOC_BUS_RESET: /* 04 */ + case MPI_EVENT_EXT_BUS_RESET: /* 05 */ + case MPI_EVENT_RESCAN: /* 06 */ + /* Ok, do we need to do anything here? As far as + I can tell, this is when a new device gets added + to the loop. */ + case MPI_EVENT_LINK_STATUS_CHANGE: /* 07 */ + case MPI_EVENT_LOOP_STATE_CHANGE: /* 08 */ + case MPI_EVENT_LOGOUT: /* 09 */ + case MPI_EVENT_EVENT_CHANGE: /* 0A */ + default: + break; + } + + /* + * NOTE: pEvent->AckRequired handling now done in mptbase.c; + * Do NOT do it here now! + */ + + return 1; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +static int +mpt_lan_open(struct net_device *dev) +{ + struct mpt_lan_priv *priv = (struct mpt_lan_priv *) dev->priv; + int i; + + mpt_lan_reset(dev); + + priv->mpt_txfidx = kmalloc(priv->tx_max_out * sizeof(int), GFP_KERNEL); + if (priv->mpt_txfidx == NULL) + goto out; + priv->mpt_txfidx_tail = -1; + + priv->SendCtl = kmalloc(priv->tx_max_out * sizeof(struct BufferControl), + GFP_KERNEL); + if (priv->SendCtl == NULL) + goto out_mpt_txfidx; + for (i = 0; i < priv->tx_max_out; i++) { + memset(&priv->SendCtl[i], 0, sizeof(struct BufferControl)); + priv->mpt_txfidx[++priv->mpt_txfidx_tail] = i; + } + + dprintk((KERN_INFO MYNAM "@lo: Finished initializing SendCtl\n")); + + priv->mpt_rxfidx = kmalloc(priv->max_buckets_out * sizeof(int), + GFP_KERNEL); + if (priv->mpt_rxfidx == NULL) + goto out_SendCtl; + priv->mpt_rxfidx_tail = -1; + + priv->RcvCtl = kmalloc(priv->max_buckets_out * + sizeof(struct BufferControl), + GFP_KERNEL); + if (priv->RcvCtl == NULL) + goto out_mpt_rxfidx; + for (i = 0; i < priv->max_buckets_out; i++) { + memset(&priv->RcvCtl[i], 0, sizeof(struct BufferControl)); + priv->mpt_rxfidx[++priv->mpt_rxfidx_tail] = i; + } + +/**/ dprintk((KERN_INFO MYNAM "/lo: txfidx contains - ")); +/**/ for (i = 0; i < priv->tx_max_out; i++) +/**/ dprintk((" %xh", priv->mpt_txfidx[i])); +/**/ dprintk(("\n")); + + dprintk((KERN_INFO MYNAM "/lo: Finished initializing RcvCtl\n")); + + mpt_lan_post_receive_buckets(dev); + printk(KERN_INFO MYNAM ": %s/%s: interface up & active\n", + IOC_AND_NETDEV_NAMES_s_s(dev)); + + if (mpt_event_register(LanCtx, mpt_lan_event_process) != 0) { + /* FIXME! */ + } + + netif_start_queue(dev); + dprintk((KERN_INFO MYNAM "/lo: Done.\n")); + + return 0; +out_mpt_rxfidx: + kfree(priv->mpt_rxfidx); + priv->mpt_rxfidx = NULL; +out_SendCtl: + kfree(priv->SendCtl); + priv->SendCtl = NULL; +out_mpt_txfidx: + kfree(priv->mpt_txfidx); + priv->mpt_txfidx = NULL; +out: return -ENOMEM; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +static int +mpt_lan_reset(struct net_device *dev) +{ + MPT_FRAME_HDR *mf; + LANResetRequest_t *pResetReq; + struct mpt_lan_priv *priv = (struct mpt_lan_priv *)dev->priv; + + mf = mpt_get_msg_frame(LanCtx, priv->mpt_dev->id); + + if (mf == NULL) { +/* dprintk((KERN_ERR MYNAM "/reset: Evil funkiness abounds! " + "Unable to allocate a request frame.\n")); +*/ + return -1; + } + + pResetReq = (LANResetRequest_t *) mf; + + pResetReq->Function = MPI_FUNCTION_LAN_RESET; + pResetReq->ChainOffset = 0; + pResetReq->Reserved = 0; + pResetReq->PortNumber = priv->pnum; + pResetReq->MsgFlags = 0; + pResetReq->Reserved2 = 0; + + mpt_put_msg_frame(LanCtx, priv->mpt_dev->id, mf); + + return 0; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +static int +mpt_lan_close(struct net_device *dev) +{ + struct mpt_lan_priv *priv = (struct mpt_lan_priv *) dev->priv; + MPT_ADAPTER *mpt_dev = priv->mpt_dev; + unsigned int timeout; + int i; + + dprintk((KERN_INFO MYNAM ": mpt_lan_close called\n")); + + mpt_event_deregister(LanCtx); + + dprintk((KERN_INFO MYNAM ":lan_close: Posted %d buckets " + "since driver was loaded, %d still out\n", + priv->total_posted,atomic_read(&priv->buckets_out))); + + netif_stop_queue(dev); + + mpt_lan_reset(dev); + + timeout = 2 * HZ; + while (atomic_read(&priv->buckets_out) && --timeout) { + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(1); + } + + for (i = 0; i < priv->max_buckets_out; i++) { + if (priv->RcvCtl[i].skb != NULL) { +/**/ dprintk((KERN_INFO MYNAM "/lan_close: bucket %05x " +/**/ "is still out\n", i)); + pci_unmap_single(mpt_dev->pcidev, priv->RcvCtl[i].dma, + priv->RcvCtl[i].len, + PCI_DMA_FROMDEVICE); + dev_kfree_skb(priv->RcvCtl[i].skb); + } + } + + kfree (priv->RcvCtl); + kfree (priv->mpt_rxfidx); + + for (i = 0; i < priv->tx_max_out; i++) { + if (priv->SendCtl[i].skb != NULL) { + pci_unmap_single(mpt_dev->pcidev, priv->SendCtl[i].dma, + priv->SendCtl[i].len, + PCI_DMA_TODEVICE); + dev_kfree_skb(priv->SendCtl[i].skb); + } + } + + kfree(priv->SendCtl); + kfree(priv->mpt_txfidx); + + atomic_set(&priv->buckets_out, 0); + + printk(KERN_INFO MYNAM ": %s/%s: interface down & inactive\n", + IOC_AND_NETDEV_NAMES_s_s(dev)); + + return 0; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +static struct net_device_stats * +mpt_lan_get_stats(struct net_device *dev) +{ + struct mpt_lan_priv *priv = (struct mpt_lan_priv *)dev->priv; + + return (struct net_device_stats *) &priv->stats; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +static int +mpt_lan_change_mtu(struct net_device *dev, int new_mtu) +{ + if ((new_mtu < MPT_LAN_MIN_MTU) || (new_mtu > MPT_LAN_MAX_MTU)) + return -EINVAL; + dev->mtu = new_mtu; + return 0; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* Tx timeout handler. */ +static void +mpt_lan_tx_timeout(struct net_device *dev) +{ + netif_wake_queue(dev); +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +//static inline int +static int +mpt_lan_send_turbo(struct net_device *dev, u32 tmsg) +{ + struct mpt_lan_priv *priv = (struct mpt_lan_priv *) dev->priv; + MPT_ADAPTER *mpt_dev = priv->mpt_dev; + struct sk_buff *sent; + unsigned long flags; + u32 ctx; + + ctx = GET_LAN_BUFFER_CONTEXT(tmsg); + sent = priv->SendCtl[ctx].skb; + + priv->stats.tx_packets++; + priv->stats.tx_bytes += sent->len; + + dioprintk((KERN_INFO MYNAM ": %s/%s: @%s, skb %p sent.\n", + IOC_AND_NETDEV_NAMES_s_s(dev), + __FUNCTION__, sent)); + + priv->SendCtl[ctx].skb = NULL; + pci_unmap_single(mpt_dev->pcidev, priv->SendCtl[ctx].dma, + priv->SendCtl[ctx].len, PCI_DMA_TODEVICE); + dev_kfree_skb_irq(sent); + + spin_lock_irqsave(&priv->txfidx_lock, flags); + priv->mpt_txfidx[++priv->mpt_txfidx_tail] = ctx; + spin_unlock_irqrestore(&priv->txfidx_lock, flags); + + netif_wake_queue(dev); + return 0; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +static int +mpt_lan_send_reply(struct net_device *dev, LANSendReply_t *pSendRep) +{ + struct mpt_lan_priv *priv = (struct mpt_lan_priv *) dev->priv; + MPT_ADAPTER *mpt_dev = priv->mpt_dev; + struct sk_buff *sent; + unsigned long flags; + int FreeReqFrame = 0; + u32 *pContext; + u32 ctx; + u8 count; + + count = pSendRep->NumberOfContexts; + + dioprintk((KERN_INFO MYNAM ": send_reply: IOCStatus: %04x\n", + le16_to_cpu(pSendRep->IOCStatus))); + + /* Add check for Loginfo Flag in IOCStatus */ + + switch (le16_to_cpu(pSendRep->IOCStatus)) { + case MPI_IOCSTATUS_SUCCESS: + priv->stats.tx_packets += count; + break; + + case MPI_IOCSTATUS_LAN_CANCELED: + case MPI_IOCSTATUS_LAN_TRANSMIT_ABORTED: + break; + + case MPI_IOCSTATUS_INVALID_SGL: + priv->stats.tx_errors += count; + printk (KERN_ERR MYNAM ": %s/%s: ERROR - Invalid SGL sent to IOC!\n", + IOC_AND_NETDEV_NAMES_s_s(dev)); + goto out; + + default: + priv->stats.tx_errors += count; + break; + } + + pContext = &pSendRep->BufferContext; + + spin_lock_irqsave(&priv->txfidx_lock, flags); + while (count > 0) { + ctx = GET_LAN_BUFFER_CONTEXT(le32_to_cpu(*pContext)); + + sent = priv->SendCtl[ctx].skb; + priv->stats.tx_bytes += sent->len; + + dioprintk((KERN_INFO MYNAM ": %s/%s: @%s, skb %p sent.\n", + IOC_AND_NETDEV_NAMES_s_s(dev), + __FUNCTION__, sent)); + + priv->SendCtl[ctx].skb = NULL; + pci_unmap_single(mpt_dev->pcidev, priv->SendCtl[ctx].dma, + priv->SendCtl[ctx].len, PCI_DMA_TODEVICE); + dev_kfree_skb_irq(sent); + + priv->mpt_txfidx[++priv->mpt_txfidx_tail] = ctx; + + pContext++; + count--; + } + spin_unlock_irqrestore(&priv->txfidx_lock, flags); + +out: + if (!(pSendRep->MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY)) + FreeReqFrame = 1; + + netif_wake_queue(dev); + return FreeReqFrame; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +static int +mpt_lan_sdu_send (struct sk_buff *skb, struct net_device *dev) +{ + struct mpt_lan_priv *priv = (struct mpt_lan_priv *) dev->priv; + MPT_ADAPTER *mpt_dev = priv->mpt_dev; + MPT_FRAME_HDR *mf; + LANSendRequest_t *pSendReq; + SGETransaction32_t *pTrans; + SGESimple64_t *pSimple; + dma_addr_t dma; + unsigned long flags; + int ctx; + + dioprintk((KERN_INFO MYNAM ": %s called, skb_addr = %p\n", + __FUNCTION__, skb)); + + spin_lock_irqsave(&priv->txfidx_lock, flags); + if (priv->mpt_txfidx_tail < 0) { + netif_stop_queue(dev); + spin_unlock_irqrestore(&priv->txfidx_lock, flags); + + printk (KERN_ERR "%s: no tx context available: %u\n", + __FUNCTION__, priv->mpt_txfidx_tail); + return 1; + } + + mf = mpt_get_msg_frame(LanCtx, mpt_dev->id); + if (mf == NULL) { + netif_stop_queue(dev); + dev_kfree_skb(skb); + spin_unlock_irqrestore(&priv->txfidx_lock, flags); + + printk (KERN_ERR "%s: Unable to alloc request frame\n", + __FUNCTION__); + return 1; + } + + ctx = priv->mpt_txfidx[priv->mpt_txfidx_tail--]; + spin_unlock_irqrestore(&priv->txfidx_lock, flags); + +// dioprintk((KERN_INFO MYNAM ": %s/%s: Creating new msg frame (send).\n", +// IOC_AND_NETDEV_NAMES_s_s(dev))); + + pSendReq = (LANSendRequest_t *) mf; + + /* Set the mac.raw pointer, since this apparently isn't getting + * done before we get the skb. Pull the data pointer past the mac data. + */ + skb->mac.raw = skb->data; + skb_pull(skb, 12); + + dma = pci_map_single(mpt_dev->pcidev, skb->data, skb->len, + PCI_DMA_TODEVICE); + + priv->SendCtl[ctx].skb = skb; + priv->SendCtl[ctx].dma = dma; + priv->SendCtl[ctx].len = skb->len; + + /* Message Header */ + pSendReq->Function = MPI_FUNCTION_LAN_SEND; + pSendReq->ChainOffset = 0; + pSendReq->MsgFlags = 0; + pSendReq->PortNumber = priv->pnum; + + /* Transaction Context Element */ + pTrans = (SGETransaction32_t *) pSendReq->SG_List; + + /* No Flags, 8 bytes of Details, 32bit Context (bloody turbo replies) */ + pTrans->ContextSize = sizeof(u32); + pTrans->DetailsLength = 2 * sizeof(u32); + pTrans->Flags = 0; + pTrans->TransactionContext[0] = cpu_to_le32(ctx); + +// dioprintk((KERN_INFO MYNAM ": %s/%s: BC = %08x, skb = %p, buff = %p\n", +// IOC_AND_NETDEV_NAMES_s_s(dev), +// ctx, skb, skb->data)); + + pTrans->TransactionDetails[0] = cpu_to_le32((0x1000 << 16) | + (skb->mac.raw[0] << 8) | + (skb->mac.raw[1] << 0)); + pTrans->TransactionDetails[1] = cpu_to_le32((skb->mac.raw[2] << 24) | + (skb->mac.raw[3] << 16) | + (skb->mac.raw[4] << 8) | + (skb->mac.raw[5] << 0)); + + pSimple = (SGESimple64_t *) &pTrans->TransactionDetails[2]; + + pSimple->FlagsLength = cpu_to_le32( + ((MPI_SGE_FLAGS_END_OF_BUFFER | + MPI_SGE_FLAGS_SIMPLE_ELEMENT | + MPI_SGE_FLAGS_64_BIT_ADDRESSING | + MPI_SGE_FLAGS_END_OF_LIST) << MPI_SGE_FLAGS_SHIFT) | + skb->len); + pSimple->Address.Low = cpu_to_le32((u32) dma); + if (sizeof(dma_addr_t) > sizeof(u32)) + pSimple->Address.High = cpu_to_le32((u32) ((u64) dma >> 32)); + else + pSimple->Address.High = 0; + + mpt_put_msg_frame (LanCtx, mpt_dev->id, mf); + dev->trans_start = jiffies; + + dioprintk((KERN_INFO MYNAM ": %s/%s: Sending packet. FlagsLength = %08x.\n", + IOC_AND_NETDEV_NAMES_s_s(dev), + le32_to_cpu(pSimple->FlagsLength))); + + return 0; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +static inline void +mpt_lan_wake_post_buckets_task(struct net_device *dev) +{ + struct mpt_lan_priv *priv = dev->priv; + + if (test_and_set_bit(0, &priv->post_buckets_active) == 0) { + queue_task(&priv->post_buckets_task, &tq_immediate); + mark_bh(IMMEDIATE_BH); + dioprintk((KERN_INFO MYNAM ": %s/%s: Queued post_buckets task.\n", + IOC_AND_NETDEV_NAMES_s_s(dev) )); + } +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +static inline int +mpt_lan_receive_skb(struct net_device *dev, struct sk_buff *skb) +{ + struct mpt_lan_priv *priv = dev->priv; + + skb->protocol = mpt_lan_type_trans(skb, dev); + + dioprintk((KERN_INFO MYNAM ": %s/%s: Incoming packet (%d bytes) " + "delivered to upper level.\n", + IOC_AND_NETDEV_NAMES_s_s(dev), skb->len)); + + priv->stats.rx_bytes += skb->len; + priv->stats.rx_packets++; + + skb->dev = dev; + netif_rx(skb); + + dioprintk((MYNAM "/receive_skb: %d buckets remaining\n", + atomic_read(&priv->buckets_out))); + + if (atomic_read(&priv->buckets_out) < priv->bucketthresh) + mpt_lan_wake_post_buckets_task(dev); + + dioprintk((KERN_INFO MYNAM "/receive_post_reply: %d buckets " + "remaining, %d received back since sod\n", + atomic_read(&priv->buckets_out), priv->total_received)); + + return 0; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +//static inline int +static int +mpt_lan_receive_post_turbo(struct net_device *dev, u32 tmsg) +{ + struct mpt_lan_priv *priv = dev->priv; + MPT_ADAPTER *mpt_dev = priv->mpt_dev; + struct sk_buff *skb, *old_skb; + unsigned long flags; + u32 ctx, len; + + ctx = GET_LAN_BUCKET_CONTEXT(tmsg); + skb = priv->RcvCtl[ctx].skb; + + len = GET_LAN_PACKET_LENGTH(tmsg); + + if (len < MPT_LAN_RX_COPYBREAK) { + old_skb = skb; + + skb = (struct sk_buff *)dev_alloc_skb(len); + if (!skb) { + printk (KERN_ERR MYNAM ": %s/%s: ERROR - Can't allocate skb! (%s@%d)\n", + IOC_AND_NETDEV_NAMES_s_s(dev), + __FILE__, __LINE__); + return -ENOMEM; + } + + pci_dma_sync_single(mpt_dev->pcidev, priv->RcvCtl[ctx].dma, + priv->RcvCtl[ctx].len, PCI_DMA_FROMDEVICE); + + memcpy(skb_put(skb, len), old_skb->data, len); + + goto out; + } + + skb_put(skb, len); + + priv->RcvCtl[ctx].skb = NULL; + + pci_unmap_single(mpt_dev->pcidev, priv->RcvCtl[ctx].dma, + priv->RcvCtl[ctx].len, PCI_DMA_FROMDEVICE); + +out: + spin_lock_irqsave(&priv->rxfidx_lock, flags); + priv->mpt_rxfidx[++priv->mpt_rxfidx_tail] = ctx; + spin_unlock_irqrestore(&priv->rxfidx_lock, flags); + + atomic_dec(&priv->buckets_out); + priv->total_received++; + + return mpt_lan_receive_skb(dev, skb); +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +static int +mpt_lan_receive_post_free(struct net_device *dev, + LANReceivePostReply_t *pRecvRep) +{ + struct mpt_lan_priv *priv = dev->priv; + MPT_ADAPTER *mpt_dev = priv->mpt_dev; + unsigned long flags; + struct sk_buff *skb; + u32 ctx; + u8 count; + int i; + + count = pRecvRep->NumberOfContexts; + +/**/ dprintk((KERN_INFO MYNAM "/receive_post_reply: " + "IOC returned %d buckets, freeing them...\n", count)); + + spin_lock_irqsave(&priv->rxfidx_lock, flags); + for (i = 0; i < count; i++) { + ctx = le32_to_cpu(pRecvRep->BucketContext[i]); + + skb = priv->RcvCtl[ctx].skb; + +// dprintk((KERN_INFO MYNAM ": %s: dev_name = %s\n", +// IOC_AND_NETDEV_NAMES_s_s(dev))); +// dprintk((KERN_INFO MYNAM "@rpr[2], priv = %p, buckets_out addr = %p", +// priv, &(priv->buckets_out))); +// dprintk((KERN_INFO MYNAM "@rpr[2] TC + 3\n")); + + priv->RcvCtl[ctx].skb = NULL; + pci_unmap_single(mpt_dev->pcidev, priv->RcvCtl[ctx].dma, + priv->RcvCtl[ctx].len, PCI_DMA_FROMDEVICE); + dev_kfree_skb_any(skb); + + priv->mpt_rxfidx[++priv->mpt_rxfidx_tail] = ctx; + } + spin_unlock_irqrestore(&priv->rxfidx_lock, flags); + + atomic_sub(count, &priv->buckets_out); + +// for (i = 0; i < priv->max_buckets_out; i++) +// if (priv->RcvCtl[i].skb != NULL) +// dprintk((KERN_INFO MYNAM "@rpr: bucket %03x " +// "is still out\n", i)); + +/* dprintk((KERN_INFO MYNAM "/receive_post_reply: freed %d buckets\n", + count)); +*/ +/**/ dprintk((KERN_INFO MYNAM "@receive_post_reply: %d buckets " +/**/ "remaining, %d received back since sod.\n", +/**/ atomic_read(&priv->buckets_out), priv->total_received)); + return 0; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +static int +mpt_lan_receive_post_reply(struct net_device *dev, + LANReceivePostReply_t *pRecvRep) +{ + struct mpt_lan_priv *priv = dev->priv; + MPT_ADAPTER *mpt_dev = priv->mpt_dev; + struct sk_buff *skb, *old_skb; + unsigned long flags; + u32 len, ctx; + u32 offset; + u8 count; + int i, l; + + dioprintk((KERN_INFO MYNAM ": mpt_lan_receive_post_reply called\n")); + dioprintk((KERN_INFO MYNAM ": receive_post_reply: IOCStatus: %04x\n", + le16_to_cpu(pRecvRep->IOCStatus))); + + if (le16_to_cpu(pRecvRep->IOCStatus) & MPI_IOCSTATUS_LAN_CANCELED) + return mpt_lan_receive_post_free(dev, pRecvRep); + + len = le32_to_cpu(pRecvRep->PacketLength); + if (len == 0) { + printk (KERN_ERR MYNAM ": %s/%s: ERROR - Got a non-TURBO " + "ReceivePostReply w/ PacketLength zero!\n", + IOC_AND_NETDEV_NAMES_s_s(dev)); + printk (KERN_ERR MYNAM ": MsgFlags = %02x, IOCStatus = %04x\n", + pRecvRep->MsgFlags, le16_to_cpu(pRecvRep->IOCStatus)); + return -1; + } + + ctx = le32_to_cpu(pRecvRep->BucketContext[0]); + count = pRecvRep->NumberOfContexts; + skb = priv->RcvCtl[ctx].skb; + + offset = le32_to_cpu(pRecvRep->PacketOffset); +// if (offset != 0) { +// printk (KERN_INFO MYNAM ": %s/%s: Got a ReceivePostReply " +// "w/ PacketOffset %u\n", +// IOC_AND_NETDEV_NAMES_s_s(dev), +// offset); +// } + + dioprintk((KERN_INFO MYNAM ": %s/%s: @rpr, offset = %d, len = %d\n", + IOC_AND_NETDEV_NAMES_s_s(dev), + offset, len)); + + if (count > 1) { + int szrem = len; + +// dioprintk((KERN_INFO MYNAM ": %s/%s: Multiple buckets returned " +// "for single packet, concatenating...\n", +// IOC_AND_NETDEV_NAMES_s_s(dev))); + + skb = (struct sk_buff *)dev_alloc_skb(len); + if (!skb) { + printk (KERN_ERR MYNAM ": %s/%s: ERROR - Can't allocate skb! (%s@%d)\n", + IOC_AND_NETDEV_NAMES_s_s(dev), + __FILE__, __LINE__); + return -ENOMEM; + } + + spin_lock_irqsave(&priv->rxfidx_lock, flags); + for (i = 0; i < count; i++) { + + ctx = le32_to_cpu(pRecvRep->BucketContext[i]); + old_skb = priv->RcvCtl[ctx].skb; + + l = priv->RcvCtl[ctx].len; + if (szrem < l) + l = szrem; + +// dioprintk((KERN_INFO MYNAM ": %s/%s: Buckets = %d, len = %u\n", +// IOC_AND_NETDEV_NAMES_s_s(dev), +// i, l)); + + pci_dma_sync_single(mpt_dev->pcidev, + priv->RcvCtl[ctx].dma, + priv->RcvCtl[ctx].len, + PCI_DMA_FROMDEVICE); + memcpy(skb_put(skb, l), old_skb->data, l); + + priv->mpt_rxfidx[++priv->mpt_rxfidx_tail] = ctx; + szrem -= l; + } + spin_unlock_irqrestore(&priv->rxfidx_lock, flags); + + } else if (len < MPT_LAN_RX_COPYBREAK) { + + old_skb = skb; + + skb = (struct sk_buff *)dev_alloc_skb(len); + if (!skb) { + printk (KERN_ERR MYNAM ": %s/%s: ERROR - Can't allocate skb! (%s@%d)\n", + IOC_AND_NETDEV_NAMES_s_s(dev), + __FILE__, __LINE__); + return -ENOMEM; + } + + pci_dma_sync_single(mpt_dev->pcidev, priv->RcvCtl[ctx].dma, + priv->RcvCtl[ctx].len, PCI_DMA_FROMDEVICE); + + memcpy(skb_put(skb, len), old_skb->data, len); + + spin_lock_irqsave(&priv->rxfidx_lock, flags); + priv->mpt_rxfidx[++priv->mpt_rxfidx_tail] = ctx; + spin_unlock_irqrestore(&priv->rxfidx_lock, flags); + + } else { + spin_lock_irqsave(&priv->rxfidx_lock, flags); + + priv->RcvCtl[ctx].skb = NULL; + + pci_unmap_single(mpt_dev->pcidev, priv->RcvCtl[ctx].dma, + priv->RcvCtl[ctx].len, PCI_DMA_FROMDEVICE); + priv->RcvCtl[ctx].dma = 0; + + priv->mpt_rxfidx[++priv->mpt_rxfidx_tail] = ctx; + spin_unlock_irqrestore(&priv->rxfidx_lock, flags); + + skb_put(skb,len); + } + + atomic_sub(count, &priv->buckets_out); + priv->total_received += count; + + if (priv->mpt_rxfidx_tail >= MPT_LAN_MAX_BUCKETS_OUT) { + printk (KERN_ERR MYNAM ": %s/%s: Yoohoo! mpt_rxfidx_tail = %d, " + "MPT_LAN_MAX_BUCKETS_OUT = %d\n", + IOC_AND_NETDEV_NAMES_s_s(dev), + priv->mpt_rxfidx_tail, + MPT_LAN_MAX_BUCKETS_OUT); + + panic("Damn it Jim! I'm a doctor, not a programmer! " + "Oh, wait a sec, I am a programmer. " + "And, who's Jim?!?!\n" + "Arrgghh! We've done it again!\n"); + } + +#if 0 + { + u32 remaining = le32_to_cpu(pRecvRep->BucketsRemaining); + if (remaining < priv->bucketthresh) + mpt_lan_wake_post_buckets_task(dev); + + if (remaining == 0) + printk (KERN_WARNING MYNAM ": %s/%s: WARNING - IOC out of buckets! " + "(priv->buckets_out = %d)\n", + IOC_AND_NETDEV_NAMES_s_s(dev), + atomic_read(&priv->buckets_out)); + else + printk (KERN_INFO MYNAM ": %s/%s: IOC says %d buckets left. " + "(priv->buckets_out = %d)\n", + IOC_AND_NETDEV_NAMES_s_s(dev), + remaining, atomic_read(&priv->buckets_out)); + } +#endif + + return mpt_lan_receive_skb(dev, skb); +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* Simple SGE's only at the moment */ + +static void +mpt_lan_post_receive_buckets(void *dev_id) +{ + struct net_device *dev = dev_id; + struct mpt_lan_priv *priv = dev->priv; + MPT_ADAPTER *mpt_dev = priv->mpt_dev; + MPT_FRAME_HDR *mf; + LANReceivePostRequest_t *pRecvReq; + SGETransaction32_t *pTrans; + SGESimple64_t *pSimple; + struct sk_buff *skb; + dma_addr_t dma; + u32 curr, buckets, count, max; + u32 len = (dev->mtu + dev->hard_header_len + 4); + unsigned long flags; + int i; + + curr = atomic_read(&priv->buckets_out); + buckets = (priv->max_buckets_out - curr); + + dioprintk((KERN_INFO MYNAM ": %s/%s: @%s, Start_buckets = %u, buckets_out = %u\n", + IOC_AND_NETDEV_NAMES_s_s(dev), + __FUNCTION__, buckets, curr)); + + max = (mpt_dev->req_sz - MPT_LAN_RECEIVE_POST_REQUEST_SIZE) / + (MPT_LAN_TRANSACTION32_SIZE + sizeof(SGESimple64_t)); + + while (buckets) { + mf = mpt_get_msg_frame(LanCtx, mpt_dev->id); + if (mf == NULL) { + printk (KERN_ERR "%s: Unable to alloc request frame\n", + __FUNCTION__); + dioprintk((KERN_ERR "%s: %u buckets remaining\n", + __FUNCTION__, buckets)); + goto out; + } + pRecvReq = (LANReceivePostRequest_t *) mf; + + count = buckets; + if (count > max) + count = max; + + pRecvReq->Function = MPI_FUNCTION_LAN_RECEIVE; + pRecvReq->ChainOffset = 0; + pRecvReq->MsgFlags = 0; + pRecvReq->PortNumber = priv->pnum; + + pTrans = (SGETransaction32_t *) pRecvReq->SG_List; + pSimple = NULL; + + for (i = 0; i < count; i++) { + int ctx; + + spin_lock_irqsave(&priv->rxfidx_lock, flags); + if (priv->mpt_rxfidx_tail < 0) { + printk (KERN_ERR "%s: Can't alloc context\n", + __FUNCTION__); + spin_unlock_irqrestore(&priv->rxfidx_lock, + flags); + break; + } + + ctx = priv->mpt_rxfidx[priv->mpt_rxfidx_tail--]; + + skb = priv->RcvCtl[ctx].skb; + if (skb && (priv->RcvCtl[ctx].len != len)) { + pci_unmap_single(mpt_dev->pcidev, + priv->RcvCtl[ctx].dma, + priv->RcvCtl[ctx].len, + PCI_DMA_FROMDEVICE); + dev_kfree_skb(priv->RcvCtl[ctx].skb); + skb = priv->RcvCtl[ctx].skb = NULL; + } + + if (skb == NULL) { + skb = dev_alloc_skb(len); + if (skb == NULL) { +/**/ printk (KERN_WARNING +/**/ MYNAM "/%s: Can't alloc skb\n", +/**/ __FUNCTION__); + priv->mpt_rxfidx[++priv->mpt_rxfidx_tail] = ctx; + spin_unlock_irqrestore(&priv->rxfidx_lock, flags); + break; + } + + dma = pci_map_single(mpt_dev->pcidev, skb->data, + len, PCI_DMA_FROMDEVICE); + + priv->RcvCtl[ctx].skb = skb; + priv->RcvCtl[ctx].dma = dma; + priv->RcvCtl[ctx].len = len; + } + + spin_unlock_irqrestore(&priv->rxfidx_lock, flags); + + pTrans->ContextSize = sizeof(u32); + pTrans->DetailsLength = 0; + pTrans->Flags = 0; + pTrans->TransactionContext[0] = cpu_to_le32(ctx); + + pSimple = (SGESimple64_t *) pTrans->TransactionDetails; + + pSimple->FlagsLength = cpu_to_le32( + ((MPI_SGE_FLAGS_END_OF_BUFFER | + MPI_SGE_FLAGS_SIMPLE_ELEMENT | + MPI_SGE_FLAGS_64_BIT_ADDRESSING) << MPI_SGE_FLAGS_SHIFT) | len); + pSimple->Address.Low = cpu_to_le32((u32) priv->RcvCtl[ctx].dma); + if (sizeof(dma_addr_t) > sizeof(u32)) + pSimple->Address.High = cpu_to_le32((u32) ((u64) priv->RcvCtl[ctx].dma >> 32)); + else + pSimple->Address.High = 0; + + pTrans = (SGETransaction32_t *) (pSimple + 1); + } + + if (pSimple == NULL) { +/**/ printk (KERN_WARNING MYNAM "/%s: No buckets posted\n", +/**/ __FUNCTION__); + mpt_free_msg_frame(LanCtx, mpt_dev->id, mf); + goto out; + } + + pSimple->FlagsLength |= cpu_to_le32(MPI_SGE_FLAGS_END_OF_LIST << MPI_SGE_FLAGS_SHIFT); + + pRecvReq->BucketCount = cpu_to_le32(i); + +/* printk(KERN_INFO MYNAM ": posting buckets\n "); + * for (i = 0; i < j + 2; i ++) + * printk (" %08x", le32_to_cpu(msg[i])); + * printk ("\n"); + */ + + mpt_put_msg_frame(LanCtx, mpt_dev->id, mf); + + priv->total_posted += i; + buckets -= i; + atomic_add(i, &priv->buckets_out); + } + +out: + dioprintk((KERN_INFO MYNAM "/%s: End_buckets = %u, priv->buckets_out = %u\n", + __FUNCTION__, buckets, atomic_read(&priv->buckets_out))); + dioprintk((KERN_INFO MYNAM "/%s: Posted %u buckets and received %u back\n", + __FUNCTION__, priv->total_posted, priv->total_received)); + + clear_bit(0, &priv->post_buckets_active); +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +struct net_device * +mpt_register_lan_device (MPT_ADAPTER *mpt_dev, int pnum) +{ + struct net_device *dev = NULL; + struct mpt_lan_priv *priv = NULL; + u8 HWaddr[FC_ALEN], *a; + + dev = init_fcdev(NULL, sizeof(struct mpt_lan_priv)); + if (!dev) + return (NULL); + dev->mtu = MPT_LAN_MTU; + + priv = (struct mpt_lan_priv *) dev->priv; + + priv->mpt_dev = mpt_dev; + priv->pnum = pnum; + + memset(&priv->post_buckets_task, 0, sizeof(struct tq_struct)); + priv->post_buckets_task.routine = mpt_lan_post_receive_buckets; + priv->post_buckets_task.data = dev; + priv->post_buckets_active = 0; + + dprintk((KERN_INFO MYNAM "@%d: bucketlen = %d\n", + __LINE__, dev->mtu + dev->hard_header_len + 4)); + + atomic_set(&priv->buckets_out, 0); + priv->total_posted = 0; + priv->total_received = 0; + priv->max_buckets_out = max_buckets_out; + if (mpt_dev->pfacts0.MaxLanBuckets < max_buckets_out) + priv->max_buckets_out = mpt_dev->pfacts0.MaxLanBuckets; + + dprintk((KERN_INFO MYNAM "@%d: MaxLanBuckets=%d, max_buckets_out/priv=%d/%d\n", + __LINE__, + mpt_dev->pfacts0.MaxLanBuckets, + max_buckets_out, + priv->max_buckets_out)); + + priv->bucketthresh = priv->max_buckets_out * 2 / 3; + priv->txfidx_lock = SPIN_LOCK_UNLOCKED; + priv->rxfidx_lock = SPIN_LOCK_UNLOCKED; + + memset(&priv->stats, 0, sizeof(priv->stats)); + + /* Grab pre-fetched LANPage1 stuff. :-) */ + a = (u8 *) &mpt_dev->lan_cnfg_page1.HardwareAddressLow; + + HWaddr[0] = a[5]; + HWaddr[1] = a[4]; + HWaddr[2] = a[3]; + HWaddr[3] = a[2]; + HWaddr[4] = a[1]; + HWaddr[5] = a[0]; + + dev->addr_len = FC_ALEN; + memcpy(dev->dev_addr, HWaddr, FC_ALEN); + memset(dev->broadcast, 0xff, FC_ALEN); + + /* The Tx queue is 127 deep on the 909. + * Give ourselves some breathing room. + */ + priv->tx_max_out = (tx_max_out_p <= MPT_TX_MAX_OUT_LIM) ? + tx_max_out_p : MPT_TX_MAX_OUT_LIM; + + dev->open = mpt_lan_open; + dev->stop = mpt_lan_close; + dev->get_stats = mpt_lan_get_stats; + dev->set_multicast_list = NULL; + dev->change_mtu = mpt_lan_change_mtu; + dev->hard_start_xmit = mpt_lan_sdu_send; + +/* Not in 2.3.42. Need 2.3.45+ */ + dev->tx_timeout = mpt_lan_tx_timeout; + dev->watchdog_timeo = MPT_LAN_TX_TIMEOUT; + + dprintk((KERN_INFO MYNAM ": Finished registering dev " + "and setting initial values\n")); + + SET_MODULE_OWNER(dev); + + return dev; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +int __init +mpt_lan_init (void) +{ + struct net_device *dev; + MPT_ADAPTER *curadapter; + int i = 0, j; + + show_mptmod_ver(LANAME, LANVER); + + if ((LanCtx = mpt_register(lan_reply, MPTLAN_DRIVER)) < 0) { + printk (KERN_ERR MYNAM ": Failed to register with MPT base driver\n"); + return -EBUSY; + } + + /* Set the callback index to be used by driver core for turbo replies */ + mpt_lan_index = LanCtx; + + dprintk((KERN_INFO MYNAM ": assigned context of %d\n", LanCtx)); + + for (j = 0; j < MPT_MAX_ADAPTERS; j++) { + mpt_landev[j] = NULL; + } + j = 0; + + curadapter = mpt_adapter_find_first(); + while (curadapter != NULL) { + for (i = 0; i < curadapter->facts0.NumberOfPorts; i++) { + printk (KERN_INFO MYNAM ": %s: PortNum=%x, ProtocolFlags=%02Xh (%c%c%c%c)\n", + curadapter->name, + curadapter->pfacts0.PortNumber, + curadapter->pfacts0.ProtocolFlags, + MPT_PROTOCOL_FLAGS_c_c_c_c(curadapter->pfacts0.ProtocolFlags)); + + if (curadapter->pfacts0.ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) { + dev = mpt_register_lan_device (curadapter, i); + if (dev != NULL) { + printk (KERN_INFO MYNAM ": %s: Fusion MPT LAN device registered as '%s'\n", + curadapter->name, dev->name); + printk (KERN_INFO MYNAM ": %s/%s: LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n", + IOC_AND_NETDEV_NAMES_s_s(dev), + dev->dev_addr[0], dev->dev_addr[1], + dev->dev_addr[2], dev->dev_addr[3], + dev->dev_addr[4], dev->dev_addr[5]); +// printk (KERN_INFO MYNAM ": %s/%s: Max_TX_outstanding = %d\n", +// IOC_AND_NETDEV_NAMES_s_s(dev), +// NETDEV_TO_LANPRIV_PTR(dev)->tx_max_out); + mpt_landev[j] = dev; + dprintk((KERN_INFO MYNAM "/init: dev_addr=%p, mpt_landev[%d]=%p\n", + dev, j, mpt_landev[j])); + + j++; + } else { + printk (KERN_ERR MYNAM ": %s: Unable to register port%d as a LAN device\n", + curadapter->name, + curadapter->pfacts0.PortNumber); + } + } else { + printk (KERN_INFO MYNAM ": %s: Hmmm... LAN protocol seems to be disabled on this adapter port!\n", + curadapter->name); + } + } + curadapter = mpt_adapter_find_next(curadapter); + } + + return 0; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +void __init mpt_lan_exit(void) +{ + int i; + + for (i = 0; mpt_landev[i] != NULL; i++) { + struct net_device *dev = mpt_landev[i]; + + printk (KERN_INFO MYNAM ": %s/%s: Fusion MPT LAN device unregistered\n", + IOC_AND_NETDEV_NAMES_s_s(dev)); + unregister_fcdev(dev); + mpt_landev[i] = (struct net_device *) 0xdeadbeef; /* Debug */ + } + + if (LanCtx >= 0) { + mpt_deregister(LanCtx); + LanCtx = -1; + mpt_lan_index = 0; + } + + /* deregister any send/receive handler structs. I2Oism? */ +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + +MODULE_PARM(tx_max_out_p, "i"); +MODULE_PARM(max_buckets_out, "i"); // Debug stuff. FIXME! + +module_init(mpt_lan_init); +module_exit(mpt_lan_exit); + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +static unsigned short +mpt_lan_type_trans(struct sk_buff *skb, struct net_device *dev) +{ + struct mpt_lan_ohdr *fch = (struct mpt_lan_ohdr *)skb->data; + struct fcllc *fcllc; + + skb->mac.raw = skb->data; + skb_pull(skb, sizeof(struct mpt_lan_ohdr)); + + if (fch->dtype == htons(0xffff)) { + u32 *p = (u32 *) fch; + + swab32s(p + 0); + swab32s(p + 1); + swab32s(p + 2); + swab32s(p + 3); + + printk (KERN_WARNING MYNAM ": %s: WARNING - Broadcast swap F/W bug detected!\n", + NETDEV_PTR_TO_IOC_NAME_s(dev)); + printk (KERN_WARNING MYNAM ": Please update sender @ MAC_addr = %02x:%02x:%02x:%02x:%02x:%02x\n", + fch->saddr[0], fch->saddr[1], fch->saddr[2], + fch->saddr[3], fch->saddr[4], fch->saddr[5]); + } + + if (*fch->daddr & 1) { + if (!memcmp(fch->daddr, dev->broadcast, FC_ALEN)) { + skb->pkt_type = PACKET_BROADCAST; + } else { + skb->pkt_type = PACKET_MULTICAST; + } + } else { + if (memcmp(fch->daddr, dev->dev_addr, FC_ALEN)) { + skb->pkt_type = PACKET_OTHERHOST; + } else { + skb->pkt_type = PACKET_HOST; + } + } + + /* Strip the SNAP header from ARP packets since we don't + * pass them through to the 802.2/SNAP layers. + */ + fcllc = (struct fcllc *)skb->data; + + if (fcllc->dsap == EXTENDED_SAP && + (fcllc->ethertype == htons(ETH_P_IP) || + fcllc->ethertype == htons(ETH_P_ARP))) { + skb_pull(skb, sizeof(struct fcllc)); + return fcllc->ethertype; + } + + return htons(ETH_P_802_2); +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ diff -u --recursive --new-file v2.4.6/linux/drivers/message/fusion/mptlan.h linux/drivers/message/fusion/mptlan.h --- v2.4.6/linux/drivers/message/fusion/mptlan.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/message/fusion/mptlan.h Fri Jul 6 17:03:11 2001 @@ -0,0 +1,72 @@ +/* mptlan.h */ + +#ifndef LINUX_MPTLAN_H_INCLUDED +#define LINUX_MPTLAN_H_INCLUDED +/*****************************************************************************/ + +#if !defined(__GENKSYMS__) +#include <linux/module.h> +#endif + +#include <linux/netdevice.h> +#include <linux/errno.h> +// #include <linux/etherdevice.h> +#include <linux/fcdevice.h> +// #include <linux/fddidevice.h> +#include <linux/skbuff.h> +#include <linux/if_arp.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/miscdevice.h> +#include <linux/spinlock.h> +#include <linux/tqueue.h> +// #include <linux/trdevice.h> + +#include <asm/uaccess.h> +#include <asm/io.h> + + /* Override mptbase.h by pre-defining these! */ + #define MODULEAUTHOR "Noah Romer, Eddie C. Dost" + +#include "mptbase.h" + +/*****************************************************************************/ +#define LANAME "Fusion MPT LAN driver" +#define LANVER MPT_LINUX_VERSION_COMMON + +#ifdef MODULE +MODULE_AUTHOR(MODULEAUTHOR); +MODULE_DESCRIPTION(LANAME); +#endif +/*****************************************************************************/ + +#define MPT_LAN_MAX_BUCKETS_OUT 256 +#define MPT_LAN_BUCKET_THRESH 18 /* 9 buckets in one message */ +#define MPT_LAN_RX_COPYBREAK 200 +#define MPT_LAN_TX_TIMEOUT (1*HZ) +#define MPT_TX_MAX_OUT_LIM 127 + +#define MPT_LAN_MIN_MTU 96 /* RFC2625 */ +#define MPT_LAN_MAX_MTU 65280 /* RFC2625 */ +#define MPT_LAN_MTU 16128 /* be nice to slab allocator */ + +/* MPT LAN Reset and Suspend Resource Flags Defines */ + +#define MPT_LAN_RESOURCE_FLAG_RETURN_POSTED_BUCKETS 0x01 +#define MPT_LAN_RESOURCE_FLAG_RETURN_PEND_TRANSMITS 0x02 + +/*****************************************************************************/ +#ifdef MPT_LAN_IO_DEBUG +#define dioprintk(x) printk x +#else +#define dioprintk(x) +#endif + +#define NETDEV_TO_LANPRIV_PTR(d) ((struct mpt_lan_priv *)(d)->priv) +#define NETDEV_PTR_TO_IOC_NAME_s(d) (NETDEV_TO_LANPRIV_PTR(d)->mpt_dev->name) +#define IOC_AND_NETDEV_NAMES_s_s(d) NETDEV_PTR_TO_IOC_NAME_s(d), (d)->name + +/*****************************************************************************/ +#endif + diff -u --recursive --new-file v2.4.6/linux/drivers/message/fusion/mptscsih.c linux/drivers/message/fusion/mptscsih.c --- v2.4.6/linux/drivers/message/fusion/mptscsih.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/message/fusion/mptscsih.c Fri Jul 6 17:03:11 2001 @@ -0,0 +1,2508 @@ +/* + * linux/drivers/message/fusion/mptscsih.c + * High performance SCSI / Fibre Channel SCSI Host device driver. + * For use with PCI chip/adapter(s): + * LSIFC9xx/LSI409xx Fibre Channel + * running LSI Logic Fusion MPT (Message Passing Technology) firmware. + * + * Credits: + * This driver would not exist if not for Alan Cox's development + * of the linux i2o driver. + * + * A huge debt of gratitude is owed to David S. Miller (DaveM) + * for fixing much of the stupid and broken stuff in the early + * driver while porting to sparc64 platform. THANK YOU! + * + * (see mptbase.c) + * + * Copyright (c) 1999-2001 LSI Logic Corporation + * Original author: Steven J. Ralston + * (mailto:Steve.Ralston@lsil.com) + * + * $Id: mptscsih.c,v 1.24 2001/03/22 08:45:08 sralston Exp $ + */ +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + 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; version 2 of the License. + + 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. + + NO WARRANTY + THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR + CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT + LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, + MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is + solely responsible for determining the appropriateness of using and + distributing the Program and assumes all risks associated with its + exercise of rights under this Agreement, including but not limited to + the risks and costs of program errors, damage to or loss of data, + programs or equipment, and unavailability or interruption of operations. + + DISCLAIMER OF LIABILITY + NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), 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 OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED + HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + +#include <linux/module.h> +#include <linux/version.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/errno.h> +#include <linux/kdev_t.h> +#include <linux/blkdev.h> +#include <linux/blk.h> /* for io_request_lock (spinlock) decl */ +#include "../../scsi/scsi.h" +#include "../../scsi/hosts.h" +#include "../../scsi/sd.h" + +#include "mptbase.h" +#include "mptscsih.h" +#include "isense.h" + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +#define my_NAME "Fusion MPT SCSI Host driver" +#define my_VERSION MPT_LINUX_VERSION_COMMON +#define MYNAM "mptscsih" + +MODULE_AUTHOR(MODULEAUTHOR); +MODULE_DESCRIPTION(my_NAME); + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + +typedef struct _BIG_SENSE_BUF { + u8 data[256]; +} BIG_SENSE_BUF; + +typedef struct _MPT_SCSI_HOST { + MPT_ADAPTER *ioc; + int port; + struct scsi_cmnd **ScsiLookup; + u8 *SgHunks; + dma_addr_t SgHunksDMA; + u32 qtag_tick; + FCDEV_TRACKER TargetsQ; +} MPT_SCSI_HOST; + +typedef struct _MPT_SCSI_DEV { + struct _MPT_SCSI_DEV *forw; + struct _MPT_SCSI_DEV *back; + MPT_ADAPTER *ioc; + int sense_sz; + BIG_SENSE_BUF CachedSense; + unsigned long io_cnt; + unsigned long read_cnt; +} MPT_SCSI_DEV; + +/* + * Other private/forward protos... + */ + +static int mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r); +static void mptscsih_report_queue_full(Scsi_Cmnd *sc, SCSIIOReply_t *pScsiReply, SCSIIORequest_t *pScsiReq); +static int mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r); +static int mptscsih_io_direction(Scsi_Cmnd *cmd); +static void copy_sense_data(Scsi_Cmnd *sc, MPT_SCSI_HOST *hd, MPT_FRAME_HDR *mf, SCSIIOReply_t *pScsiReply); +static u32 SCPNT_TO_MSGCTX(Scsi_Cmnd *sc); + +static int mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply); + + +static int mpt_scsi_hosts = 0; +static atomic_t queue_depth; + +static int ScsiDoneCtx = -1; +static int ScsiTaskCtx = -1; + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,28) +static struct proc_dir_entry proc_mpt_scsihost = +{ + low_ino: PROC_SCSI_MPT, + namelen: 8, + name: "mptscsih", + mode: S_IFDIR | S_IRUGO | S_IXUGO, + nlink: 2, +}; +#endif + +#define SNS_LEN(scp) sizeof((scp)->sense_buffer) + +#ifndef MPT_SCSI_USE_NEW_EH +/* + * Stuff to handle single-threading SCSI TaskMgmt + * (abort/reset) requests... + */ +static spinlock_t mpt_scsih_taskQ_lock = SPIN_LOCK_UNLOCKED; +static MPT_Q_TRACKER mpt_scsih_taskQ = { + (MPT_FRAME_HDR*) &mpt_scsih_taskQ, + (MPT_FRAME_HDR*) &mpt_scsih_taskQ +}; +static int mpt_scsih_taskQ_cnt = 0; +static int mpt_scsih_taskQ_bh_active = 0; +static MPT_FRAME_HDR *mpt_scsih_active_taskmgmt_mf = NULL; +#endif + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * mptscsih_io_done - Main SCSI IO callback routine registered to + * Fusion MPT (base) driver + * @ioc: Pointer to MPT_ADAPTER structure + * @mf: Pointer to original MPT request frame + * @r: Pointer to MPT reply frame (NULL if TurboReply) + * + * This routine is called from mpt.c::mpt_interrupt() at the completion + * of any SCSI IO request. + * This routine is registered with the Fusion MPT (base) driver at driver + * load/init time via the mpt_register() API call. + * + * Returns 1 indicating alloc'd request frame ptr should be freed. + */ +static int +mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r) +{ + Scsi_Cmnd *sc; + MPT_SCSI_HOST *hd; + MPT_SCSI_DEV *mpt_sdev = NULL; + u16 req_idx; + + if ((mf == NULL) || + (mf >= MPT_INDEX_2_MFPTR(ioc, ioc->req_depth))) { + printk(KERN_ERR MYNAM ": ERROR! NULL or BAD req frame ptr (=%p)!\n", mf); + return 1; + } + + hd = (MPT_SCSI_HOST *) ioc->sh->hostdata; + req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx); + sc = hd->ScsiLookup[req_idx]; + hd->ScsiLookup[req_idx] = NULL; + + dmfprintk((KERN_INFO MYNAM ": ScsiDone (req:sc:reply=%p:%p:%p)\n", mf, sc, r)); + + atomic_dec(&queue_depth); + + /* + * Check for {1st} {IO} completion to "new" device. + * How do we know it's a new device? + * If we haven't set SDpnt->hostdata I guess... + */ + if (sc && sc->device) { + mpt_sdev = (MPT_SCSI_DEV*)sc->device->hostdata; + if (!mpt_sdev) { + dprintk((KERN_INFO MYNAM ": *NEW* SCSI device (%d:%d:%d)!\n", + sc->device->id, sc->device->lun, sc->device->channel)); + if ((sc->device->hostdata = kmalloc(sizeof(MPT_SCSI_DEV), GFP_ATOMIC)) == NULL) { + printk(KERN_ERR MYNAM ": ERROR: kmalloc(%d) FAILED!\n", (int)sizeof(MPT_SCSI_DEV)); + } else { + memset(sc->device->hostdata, 0, sizeof(MPT_SCSI_DEV)); + mpt_sdev = (MPT_SCSI_DEV *) sc->device->hostdata; + mpt_sdev->ioc = ioc; + } + } else { + if (++mpt_sdev->io_cnt && mptscsih_io_direction(sc) < 0) { + if (++mpt_sdev->read_cnt == 3) { + dprintk((KERN_INFO MYNAM ": 3rd DATA_IN, CDB[0]=%02x\n", + sc->cmnd[0])); + } + } +#if 0 + if (mpt_sdev->sense_sz) { + /* + * Completion of first IO down this path + * *should* invalidate device SenseData... + */ + mpt_sdev->sense_sz = 0; + } +#endif + } + } + +#if 0 +{ + MPT_FRAME_HDR *mf_chk; + + /* This, I imagine, is a costly check, but... + * If abort/reset active, check to see if this is a IO + * that completed while ABORT/RESET for it is waiting + * on our taskQ! + */ + if (! Q_IS_EMPTY(&mpt_scsih_taskQ)) { + /* If ABORT for this IO is queued, zap it! */ + mf_chk = search_taskQ(1,sc,MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK); + if (mf_chk != NULL) { + sc->result = DID_ABORT << 16; + spin_lock_irqsave(&io_request_lock, flags); + sc->scsi_done(sc); + spin_unlock_irqrestore(&io_request_lock, flags); + return 1; + } + } +} +#endif + + if (r != NULL && sc != NULL) { + SCSIIOReply_t *pScsiReply; + SCSIIORequest_t *pScsiReq; + u16 status; + + pScsiReply = (SCSIIOReply_t *) r; + pScsiReq = (SCSIIORequest_t *) mf; + + status = le16_to_cpu(pScsiReply->IOCStatus) & MPI_IOCSTATUS_MASK; + + dprintk((KERN_NOTICE MYNAM ": Uh-Oh! (req:sc:reply=%p:%p:%p)\n", mf, sc, r)); + dprintk((KERN_NOTICE " IOCStatus=%04xh, SCSIState=%02xh" + ", SCSIStatus=%02xh, IOCLogInfo=%08xh\n", + status, pScsiReply->SCSIState, pScsiReply->SCSIStatus, + le32_to_cpu(pScsiReply->IOCLogInfo))); + + /* + * Look for + dump FCP ResponseInfo[]! + */ + if (pScsiReply->SCSIState & MPI_SCSI_STATE_RESPONSE_INFO_VALID) { + dprintk((KERN_NOTICE " FCP_ResponseInfo=%08xh\n", + le32_to_cpu(pScsiReply->ResponseInfo))); + } + + switch(status) { + case MPI_IOCSTATUS_BUSY: /* 0x0002 */ + /*sc->result = DID_BUS_BUSY << 16;*/ /* YIKES! - Seems to + * kill linux interrupt + * handler + */ + sc->result = STS_BUSY; /* Try SCSI BUSY! */ + break; + + case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */ + /* Not real sure here... */ + sc->result = DID_OK << 16; + break; + + case MPI_IOCSTATUS_SCSI_INVALID_BUS: /* 0x0041 */ + case MPI_IOCSTATUS_SCSI_INVALID_TARGETID: /* 0x0042 */ + sc->result = DID_BAD_TARGET << 16; + break; + + case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */ + /* Spoof to SCSI Selection Timeout! */ + sc->result = DID_NO_CONNECT << 16; + break; + + case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */ + /* + * YIKES! I just discovered that SCSI IO which + * returns check condition, SenseKey=05 (ILLEGAL REQUEST) + * and ASC/ASCQ=94/01 (LSI Logic RAID vendor specific), + * comes down this path! + * Do upfront check for valid SenseData and give it + * precedence! + */ + if (pScsiReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID) { + copy_sense_data(sc, hd, mf, pScsiReply); + sc->result = pScsiReply->SCSIStatus; + break; + } + + dprintk((KERN_NOTICE MYNAM ": sc->underflow={report ERR if < %02xh bytes xfer'd}\n", sc->underflow)); + dprintk((KERN_NOTICE MYNAM ": ActBytesXferd=%02xh\n", le32_to_cpu(pScsiReply->TransferCount))); + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) + sc->resid = sc->request_bufflen - le32_to_cpu(pScsiReply->TransferCount); + dprintk((KERN_NOTICE MYNAM ": SET sc->resid=%02xh\n", sc->resid)); +#endif + +#if 0 + if (sc->underflow && (le32_to_cpu(pScsiReply->TransferCount) < sc->underflow)) { + sc->result = DID_ERROR << 16; + sc->resid = sc->request_bufflen - le32_to_cpu(pScsiReply->TransferCount); + } else { + sc->result = 0; + } +#endif + + /* workaround attempts... */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) + if (sc->resid >= 0x200) { + /* GRRRRR... + * //sc->result = DID_SOFT_ERROR << 16; + * Try spoofing to BUSY + */ + sc->result = STS_BUSY; + } else { + sc->result = 0; + } +#else + sc->result = 0; +#endif + break; + + case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */ + sc->result = DID_ABORT << 16; + break; + + case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */ + case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */ + sc->result = DID_RESET << 16; + break; + + case MPI_IOCSTATUS_SUCCESS: /* 0x0000 */ + sc->result = pScsiReply->SCSIStatus; + + if (pScsiReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID) { + copy_sense_data(sc, hd, mf, pScsiReply); + + /* If running agains circa 200003dd 909 MPT f/w, + * may get this (AUTOSENSE_VALID) for actual TASK_SET_FULL + * (QUEUE_FULL) returned from device! --> get 0x0000?128 + * and with SenseBytes set to 0. + */ + if (pScsiReply->SCSIStatus == MPI_SCSI_STATUS_TASK_SET_FULL) + mptscsih_report_queue_full(sc, pScsiReply, pScsiReq); + } + else if (pScsiReply->SCSIState & (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS)) { + /* + * What to do? + */ + sc->result = DID_SOFT_ERROR << 16; + } + else if (pScsiReply->SCSIState & MPI_SCSI_STATE_TERMINATED) { + /* Not real sure here either... */ + sc->result = DID_ABORT << 16; + } + + if (sc->result == MPI_SCSI_STATUS_TASK_SET_FULL) + mptscsih_report_queue_full(sc, pScsiReply, pScsiReq); + + break; + + case MPI_IOCSTATUS_INVALID_FUNCTION: /* 0x0001 */ + case MPI_IOCSTATUS_INVALID_SGL: /* 0x0003 */ + case MPI_IOCSTATUS_INTERNAL_ERROR: /* 0x0004 */ + case MPI_IOCSTATUS_RESERVED: /* 0x0005 */ + case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES: /* 0x0006 */ + case MPI_IOCSTATUS_INVALID_FIELD: /* 0x0007 */ + case MPI_IOCSTATUS_INVALID_STATE: /* 0x0008 */ + case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: /* 0x0044 */ + case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */ + case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */ + case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */ + case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: /* 0x004A */ + default: + /* + * What to do? + */ + sc->result = DID_SOFT_ERROR << 16; + break; + + } /* switch(status) */ + + dprintk((KERN_NOTICE MYNAM ": sc->result set to %08xh\n", sc->result)); + } + + if (sc != NULL) { + unsigned long flags; + + /* Unmap the DMA buffers, if any. */ + if (sc->use_sg) { + pci_unmap_sg(ioc->pcidev, + (struct scatterlist *) sc->request_buffer, + sc->use_sg, + scsi_to_pci_dma_dir(sc->sc_data_direction)); + } else if (sc->request_bufflen) { + pci_unmap_single(ioc->pcidev, + (dma_addr_t)((long)sc->SCp.ptr), + sc->request_bufflen, + scsi_to_pci_dma_dir(sc->sc_data_direction)); + } + + spin_lock_irqsave(&io_request_lock, flags); + sc->scsi_done(sc); + spin_unlock_irqrestore(&io_request_lock, flags); + } + + return 1; +} + +#ifndef MPT_SCSI_USE_NEW_EH +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * search_taskQ - Search SCSI task mgmt request queue for specific + * request type + * @remove: (Boolean) Should request be removed if found? + * @sc: Pointer to Scsi_Cmnd structure + * @task_type: Task type to search for + * + * Returns pointer to MPT request frame if found, or %NULL if request + * was not found. + */ +static MPT_FRAME_HDR * +search_taskQ(int remove, Scsi_Cmnd *sc, u8 task_type) +{ + MPT_FRAME_HDR *mf = NULL; + unsigned long flags; + int count = 0; + int list_sz; + + dslprintk((KERN_INFO MYNAM ": spinlock#1\n")); + spin_lock_irqsave(&mpt_scsih_taskQ_lock, flags); + list_sz = mpt_scsih_taskQ_cnt; + if (! Q_IS_EMPTY(&mpt_scsih_taskQ)) { + mf = mpt_scsih_taskQ.head; + do { + count++; + if (mf->u.frame.linkage.argp1 == sc && + mf->u.frame.linkage.arg1 == task_type) { + if (remove) { + Q_DEL_ITEM(&mf->u.frame.linkage); + mpt_scsih_taskQ_cnt--; + } + break; + } + } while ((mf = mf->u.frame.linkage.forw) != (MPT_FRAME_HDR*)&mpt_scsih_taskQ); + if (mf == (MPT_FRAME_HDR*)&mpt_scsih_taskQ) { + mf = NULL; + } + } + spin_unlock_irqrestore(&mpt_scsih_taskQ_lock, flags); + + if (list_sz) { + dprintk((KERN_INFO MYNAM ": search_taskQ(%d,%p,%d) results=%p (%sFOUND%s)!\n", + remove, sc, task_type, + mf, + mf ? "" : "NOT_", + (mf && remove) ? "+REMOVED" : "" )); + dprintk((KERN_INFO MYNAM ": (searched thru %d of %d items on taskQ)\n", + count, + list_sz )); + } + + return mf; +} + +#endif + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + +/* + * Hack! I'd like to report if a device is returning QUEUE_FULL + * but maybe not each and every time... + */ +static long last_queue_full = 0; + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * mptscsih_report_queue_full - Report QUEUE_FULL status returned + * from a SCSI target device. + * @sc: Pointer to Scsi_Cmnd structure + * @pScsiReply: Pointer to SCSIIOReply_t + * @pScsiReq: Pointer to original SCSI request + * + * This routine periodically reports QUEUE_FULL status returned from a + * SCSI target device. It reports this to the console via kernel + * printk() API call, not more than once every 10 seconds. + */ +static void +mptscsih_report_queue_full(Scsi_Cmnd *sc, SCSIIOReply_t *pScsiReply, SCSIIORequest_t *pScsiReq) +{ + long time = jiffies; + + if (time - last_queue_full > 10 * HZ) { + printk(KERN_WARNING MYNAM ": Device reported QUEUE_FULL! SCSI bus:target:lun = %d:%d:%d\n", + 0, sc->target, sc->lun); + last_queue_full = time; + } +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +static int BeenHereDoneThat = 0; + +/* SCSI fops start here... */ +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/** + * mptscsih_detect - Register MPT adapter(s) as SCSI host(s) with + * linux scsi mid-layer. + * @tpnt: Pointer to Scsi_Host_Template structure + * + * (linux Scsi_Host_Template.detect routine) + * + * Returns number of SCSI host adapters that were successfully + * registered with the linux scsi mid-layer via the scsi_register() + * API call. + */ +int +mptscsih_detect(Scsi_Host_Template *tpnt) +{ + struct Scsi_Host *sh = NULL; + MPT_SCSI_HOST *hd = NULL; + MPT_ADAPTER *this; + unsigned long flags; + int sz; + u8 *mem; + + if (! BeenHereDoneThat++) { + show_mptmod_ver(my_NAME, my_VERSION); + + ScsiDoneCtx = mpt_register(mptscsih_io_done, MPTSCSIH_DRIVER); + ScsiTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTSCSIH_DRIVER); + +#ifndef MPT_SCSI_USE_NEW_EH + Q_INIT(&mpt_scsih_taskQ, MPT_FRAME_HDR); + spin_lock_init(&mpt_scsih_taskQ_lock); +#endif + + if (mpt_event_register(ScsiDoneCtx, mptscsih_event_process) == 0) { + dprintk((KERN_INFO MYNAM ": Registered for IOC event notifications\n")); + } else { + /* FIXME! */ + } + } + + dprintk((KERN_INFO MYNAM ": mpt_scsih_detect()\n")); + + this = mpt_adapter_find_first(); + while (this != NULL) { + /* FIXME! Multi-port (aka FC929) support... + * for (i = 0; i < this->facts.NumberOfPorts; i++) + */ + + /* 20010215 -sralston + * Added sanity check on SCSI Initiator-mode enabled + * for this MPT adapter. + */ + if (!(this->pfacts0.ProtocolFlags & MPI_PORTFACTS_PROTOCOL_INITIATOR)) { + printk(KERN_ERR MYNAM ": Skipping %s because SCSI Initiator mode is NOT enabled!\n", + this->name); + this = mpt_adapter_find_next(this); + continue; + } + + /* 20010202 -sralston + * Added sanity check on readiness of the MPT adapter. + */ + if (this->last_state != MPI_IOC_STATE_OPERATIONAL) { + printk(KERN_ERR MYNAM ": ERROR - Skipping %s because it's not operational!\n", + this->name); + this = mpt_adapter_find_next(this); + continue; + } + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0) + tpnt->proc_dir = &proc_mpt_scsihost; +#endif + sh = scsi_register(tpnt, sizeof(MPT_SCSI_HOST)); + if (sh != NULL) { + save_flags(flags); + cli(); + sh->io_port = 0; + sh->n_io_port = 0; + sh->irq = 0; + + /* Yikes! This is important! + * Otherwise, by default, linux only scans target IDs 0-7! + */ + sh->max_id = this->pfacts0.MaxDevices - 1; + + sh->this_id = this->pfacts0.PortSCSIID; + + restore_flags(flags); + + hd = (MPT_SCSI_HOST *) sh->hostdata; + hd->ioc = this; + hd->port = 0; /* FIXME! */ + + /* SCSI needs Scsi_Cmnd lookup table! + * (with size equal to req_depth*PtrSz!) + */ + sz = hd->ioc->req_depth * sizeof(void *); + mem = kmalloc(sz, GFP_KERNEL); + if (mem == NULL) + return mpt_scsi_hosts; + + memset(mem, 0, sz); + hd->ScsiLookup = (struct scsi_cmnd **) mem; + + dprintk((KERN_INFO MYNAM ": ScsiLookup @ %p, sz=%d\n", + hd->ScsiLookup, sz)); + + /* SCSI also needs SG buckets/hunk management! + * (with size equal to N * req_sz * req_depth!) + * (where N is number of SG buckets per hunk) + */ + sz = MPT_SG_BUCKETS_PER_HUNK * hd->ioc->req_sz * hd->ioc->req_depth; + mem = pci_alloc_consistent(hd->ioc->pcidev, sz, + &hd->SgHunksDMA); + if (mem == NULL) + return mpt_scsi_hosts; + + memset(mem, 0, sz); + hd->SgHunks = (u8*)mem; + + dprintk((KERN_INFO MYNAM ": SgHunks @ %p(%08x), sz=%d\n", + hd->SgHunks, hd->SgHunksDMA, sz)); + + hd->qtag_tick = jiffies; + + this->sh = sh; + mpt_scsi_hosts++; + } + this = mpt_adapter_find_next(this); + } + + return mpt_scsi_hosts; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + static char *info_kbuf = NULL; +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/** + * mptscsih_release - Unregister SCSI host from linux scsi mid-layer + * @host: Pointer to Scsi_Host structure + * + * (linux Scsi_Host_Template.release routine) + * This routine releases all resources associated with the SCSI host + * adapter. + * + * Returns 0 for success. + */ +int +mptscsih_release(struct Scsi_Host *host) +{ + MPT_SCSI_HOST *hd; +#ifndef MPT_SCSI_USE_NEW_EH + unsigned long flags; + + spin_lock_irqsave(&mpt_scsih_taskQ_lock, flags); + if (mpt_scsih_taskQ_bh_active) { + int count = 10 * HZ; + + dprintk((KERN_INFO MYNAM ": Info: Zapping TaskMgmt thread!\n")); + + /* Zap the taskQ! */ + Q_INIT(&mpt_scsih_taskQ, MPT_FRAME_HDR); + spin_unlock_irqrestore(&mpt_scsih_taskQ_lock, flags); + + while(mpt_scsih_taskQ_bh_active && --count) { + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(1); + } + if (!count) + printk(KERN_ERR MYNAM ": ERROR! TaskMgmt thread still active!\n"); + } + spin_unlock_irqrestore(&mpt_scsih_taskQ_lock, flags); +#endif + + hd = (MPT_SCSI_HOST *) host->hostdata; + if (hd != NULL) { + int sz1, sz2; + + sz1 = sz2 = 0; + if (hd->ScsiLookup != NULL) { + sz1 = hd->ioc->req_depth * sizeof(void *); + kfree(hd->ScsiLookup); + hd->ScsiLookup = NULL; + } + + if (hd->SgHunks != NULL) { + + sz2 = MPT_SG_BUCKETS_PER_HUNK * hd->ioc->req_sz * hd->ioc->req_depth; + pci_free_consistent(hd->ioc->pcidev, sz2, + hd->SgHunks, hd->SgHunksDMA); + hd->SgHunks = NULL; + } + dprintk((KERN_INFO MYNAM ": Free'd ScsiLookup (%d) and SgHunks (%d) memory\n", sz1, sz2)); + } + + if (mpt_scsi_hosts) { + if (--mpt_scsi_hosts == 0) { +#if 0 + mptscsih_flush_pending(); +#endif + mpt_event_deregister(ScsiDoneCtx); + dprintk((KERN_INFO MYNAM ": Deregistered for IOC event notifications\n")); + + mpt_deregister(ScsiDoneCtx); + mpt_deregister(ScsiTaskCtx); + + if (info_kbuf != NULL) + kfree(info_kbuf); + } + } + + return 0; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/** + * mptscsih_info - Return information about MPT adapter + * @SChost: Pointer to Scsi_Host structure + * + * (linux Scsi_Host_Template.info routine) + * + * Returns pointer to buffer where information was written. + */ +const char * +mptscsih_info(struct Scsi_Host *SChost) +{ + MPT_SCSI_HOST *h; + int size = 0; + + if (info_kbuf == NULL) + if ((info_kbuf = kmalloc(0x1000 /* 4Kb */, GFP_KERNEL)) == NULL) + return info_kbuf; + + h = (MPT_SCSI_HOST *)SChost->hostdata; + info_kbuf[0] = '\0'; + mpt_print_ioc_summary(h->ioc, info_kbuf, &size, 0); + info_kbuf[size-1] = '\0'; + + return info_kbuf; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + static int max_qd = 1; +#ifdef MPT_DEBUG + static int max_sges = 0; + static int max_xfer = 0; +#endif +#if 0 + static int max_num_sges = 0; + static int max_sgent_len = 0; +#endif +#if 0 +static int index_log[128]; +static int index_ent = 0; +static __inline__ void ADD_INDEX_LOG(int req_ent) +{ + int i = index_ent++; + + index_log[i & (128 - 1)] = req_ent; +} +#else +#define ADD_INDEX_LOG(req_ent) do { } while(0) +#endif +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/** + * mptscsih_qcmd - Primary Fusion MPT SCSI initiator IO start routine. + * @SCpnt: Pointer to Scsi_Cmnd structure + * @done: Pointer SCSI mid-layer IO completion function + * + * (linux Scsi_Host_Template.queuecommand routine) + * This is the primary SCSI IO start routine. Create a MPI SCSIIORequest + * from a linux Scsi_Cmnd request and send it to the IOC. + * + * Returns 0. (rtn value discarded by linux scsi mid-layer) + */ +int +mptscsih_qcmd(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) +{ + struct Scsi_Host *host; + MPT_SCSI_HOST *hd; + MPT_FRAME_HDR *mf; + SCSIIORequest_t *pScsiReq; + int datadir; + u32 len; + u32 sgdir; + u32 scsictl; + u32 scsidir; + u32 qtag; + u32 *mptr; + int sge_spill1; + int frm_sz; + int sges_left; + u32 chain_offset; + int my_idx; + int i; + + dmfprintk((KERN_INFO MYNAM "_qcmd: SCpnt=%p, done()=%p\n", + SCpnt, done)); + + host = SCpnt->host; + hd = (MPT_SCSI_HOST *) host->hostdata; + +#if 0 + if (host->host_busy >= 60) { + MPT_ADAPTER *ioc = hd->ioc; + u16 pci_command, pci_status; + + /* The IOC is probably hung, investigate status. */ + printk("MPI: IOC probably hung IOCSTAT[%08x] INTSTAT[%08x] REPLYFIFO[%08x]\n", + readl(&ioc->chip.fc9xx->DoorbellValue), + readl(&ioc->chip.fc9xx->IntStatus), + readl(&ioc->chip.fc9xx->ReplyFifo)); + pci_read_config_word(ioc->pcidev, PCI_COMMAND, &pci_command); + pci_read_config_word(ioc->pcidev, PCI_STATUS, &pci_status); + printk("MPI: PCI command[%04x] status[%04x]\n", pci_command, pci_status); + { + /* DUMP req index logger. */ + int begin, end; + + begin = (index_ent - 65) & (128 - 1); + end = index_ent & (128 - 1); + printk("MPI: REQ_INDEX_HIST["); + while (begin != end) { + printk("(%04x)", index_log[begin]); + begin = (begin + 1) & (128 - 1); + } + printk("\n"); + } + sti(); + while(1) + barrier(); + } +#endif + + SCpnt->scsi_done = done; + + /* 20000617 -sralston + * GRRRRR... Shouldn't have to do this but... + * Do explicit check for REQUEST_SENSE and cached SenseData. + * If yes, return cached SenseData. + */ +#ifdef MPT_SCSI_CACHE_AUTOSENSE + { + MPT_SCSI_DEV *mpt_sdev; + + mpt_sdev = (MPT_SCSI_DEV *) SCpnt->device->hostdata; + if (mpt_sdev && SCpnt->cmnd[0] == REQUEST_SENSE) { + u8 *dest = NULL; + + if (!SCpnt->use_sg) + dest = SCpnt->request_buffer; + else { + struct scatterlist *sg = (struct scatterlist *) SCpnt->request_buffer; + if (sg) + dest = (u8 *) (unsigned long)sg_dma_address(sg); + } + + if (dest && mpt_sdev->sense_sz) { + memcpy(dest, mpt_sdev->CachedSense.data, mpt_sdev->sense_sz); +#ifdef MPT_DEBUG + { + int i; + u8 *sb; + + sb = mpt_sdev->CachedSense.data; + if (sb && ((sb[0] & 0x70) == 0x70)) { + printk(KERN_WARNING MYNAM ": Returning last cached SCSI (hex) SenseData:\n"); + printk(KERN_WARNING " "); + for (i = 0; i < (8 + sb[7]); i++) + printk("%s%02x", i == 13 ? "-" : " ", sb[i]); + printk("\n"); + } + } +#endif + } + SCpnt->resid = SCpnt->request_bufflen - mpt_sdev->sense_sz; + SCpnt->result = 0; +/* spin_lock(&io_request_lock); */ + SCpnt->scsi_done(SCpnt); +/* spin_unlock(&io_request_lock); */ + return 0; + } + } +#endif + + if ((mf = mpt_get_msg_frame(ScsiDoneCtx, hd->ioc->id)) == NULL) { +/* SCpnt->result = DID_SOFT_ERROR << 16; */ + SCpnt->result = STS_BUSY; + SCpnt->scsi_done(SCpnt); +/* return 1; */ + return 0; + } + pScsiReq = (SCSIIORequest_t *) mf; + + my_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx); + + ADD_INDEX_LOG(my_idx); + + /* Map the data portion, if any. */ + sges_left = SCpnt->use_sg; + if (sges_left) { + sges_left = pci_map_sg(hd->ioc->pcidev, + (struct scatterlist *) SCpnt->request_buffer, + sges_left, + scsi_to_pci_dma_dir(SCpnt->sc_data_direction)); + } else if (SCpnt->request_bufflen) { + dma_addr_t buf_dma_addr; + + buf_dma_addr = pci_map_single(hd->ioc->pcidev, + SCpnt->request_buffer, + SCpnt->request_bufflen, + scsi_to_pci_dma_dir(SCpnt->sc_data_direction)); + + /* We hide it here for later unmap. */ + SCpnt->SCp.ptr = (char *)(unsigned long) buf_dma_addr; + } + + /* + * Put together a MPT SCSI request... + */ + + /* Assume SimpleQ, NO DATA XFER for now */ + + len = SCpnt->request_bufflen; + sgdir = 0x00000000; /* SGL IN (host<--ioc) */ + scsidir = MPI_SCSIIO_CONTROL_NODATATRANSFER; + + /* + * The scsi layer should be handling this stuff + * (In 2.3.x it does -DaveM) + */ + + /* BUG FIX! 19991030 -sralston + * TUR's being issued with scsictl=0x02000000 (DATA_IN)! + * Seems we may receive a buffer (len>0) even when there + * will be no data transfer! GRRRRR... + */ + datadir = mptscsih_io_direction(SCpnt); + if (datadir < 0) { + scsidir = MPI_SCSIIO_CONTROL_READ; /* DATA IN (host<--ioc<--dev) */ + } else if (datadir > 0) { + sgdir = 0x04000000; /* SGL OUT (host-->ioc) */ + scsidir = MPI_SCSIIO_CONTROL_WRITE; /* DATA OUT (host-->ioc-->dev) */ + } else { + len = 0; + } + + qtag = MPI_SCSIIO_CONTROL_SIMPLEQ; + + /* + * Attach tags to the devices + */ + if (SCpnt->device->tagged_supported) { + /* + * Some drives are too stupid to handle fairness issues + * with tagged queueing. We throw in the odd ordered + * tag to stop them starving themselves. + */ + if ((jiffies - hd->qtag_tick) > (5*HZ)) { + qtag = MPI_SCSIIO_CONTROL_ORDEREDQ; + hd->qtag_tick = jiffies; + +#if 0 + /* These are ALWAYS zero! + * (Because this is a place for the device driver to dynamically + * assign tag numbers any way it sees fit. That's why -DaveM) + */ + dprintk((KERN_DEBUG MYNAM ": sc->device->current_tag = %08x\n", + SCpnt->device->current_tag)); + dprintk((KERN_DEBUG MYNAM ": sc->tag = %08x\n", + SCpnt->tag)); +#endif + } +#if 0 + else { + /* Hmmm... I always see value of 0 here, + * of which {HEAD_OF, ORDERED, SIMPLE} are NOT! -sralston + * (Because this is a place for the device driver to dynamically + * assign tag numbers any way it sees fit. That's why -DaveM) + * + * if (SCpnt->tag == HEAD_OF_QUEUE_TAG) + */ + if (SCpnt->device->current_tag == HEAD_OF_QUEUE_TAG) + qtag = MPI_SCSIIO_CONTROL_HEADOFQ; + else if (SCpnt->tag == ORDERED_QUEUE_TAG) + qtag = MPI_SCSIIO_CONTROL_ORDEREDQ; + } +#endif + } + + scsictl = scsidir | qtag; + + frm_sz = hd->ioc->req_sz; + + /* Ack! + * sge_spill1 = 9; + */ + sge_spill1 = (frm_sz - (sizeof(SCSIIORequest_t) - sizeof(SGEIOUnion_t) + sizeof(SGEChain32_t))) / 8; + /* spill1: for req_sz == 128 (128-48==80, 80/8==10 SGEs max, first time!), --> use 9 + * spill1: for req_sz == 96 ( 96-48==48, 48/8== 6 SGEs max, first time!), --> use 5 + */ + dsgprintk((KERN_INFO MYNAM ": SG: %x spill1 = %d\n", + my_idx, sge_spill1)); + +#ifdef MPT_DEBUG + if (sges_left > max_sges) { + max_sges = sges_left; + dprintk((KERN_INFO MYNAM ": MPT_MaxSges = %d\n", max_sges)); + } +#endif +#if 0 + if (sges_left > max_num_sges) { + max_num_sges = sges_left; + printk(KERN_INFO MYNAM ": MPT_MaxNumSges = %d\n", max_num_sges); + } +#endif + + dsgprintk((KERN_INFO MYNAM ": SG: %x sges_left = %d (initially)\n", + my_idx, sges_left)); + + chain_offset = 0; + if (sges_left > (sge_spill1+1)) { +#if 0 + chain_offset = 0x1E; +#endif + chain_offset = (frm_sz - 8) / 4; + } + + pScsiReq->TargetID = SCpnt->target; + pScsiReq->Bus = hd->port; + pScsiReq->ChainOffset = chain_offset; + pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST; + pScsiReq->CDBLength = SCpnt->cmd_len; + +/* We have 256 bytes alloc'd per IO; let's use it. */ +/* pScsiReq->SenseBufferLength = SNS_LEN(SCpnt); */ + pScsiReq->SenseBufferLength = 255; + + pScsiReq->Reserved = 0; + pScsiReq->MsgFlags = 0; + pScsiReq->LUN[0] = 0; + pScsiReq->LUN[1] = SCpnt->lun; + pScsiReq->LUN[2] = 0; + pScsiReq->LUN[3] = 0; + pScsiReq->LUN[4] = 0; + pScsiReq->LUN[5] = 0; + pScsiReq->LUN[6] = 0; + pScsiReq->LUN[7] = 0; + pScsiReq->Control = cpu_to_le32(scsictl); + + /* + * Write SCSI CDB into the message + */ + for (i = 0; i < 12; i++) + pScsiReq->CDB[i] = SCpnt->cmnd[i]; + for (i = 12; i < 16; i++) + pScsiReq->CDB[i] = 0; + + /* DataLength */ + pScsiReq->DataLength = cpu_to_le32(len); + + /* SenseBuffer low address */ + pScsiReq->SenseBufferLowAddr = cpu_to_le32(hd->ioc->sense_buf_pool_dma + (my_idx * 256)); + + mptr = (u32 *) &pScsiReq->SGL; + + /* + * Now fill in the SGList... + * NOTES: For 128 byte req_sz, we can hold up to 10 simple SGE's + * in the remaining request frame. We -could- do unlimited chains + * but each chain buffer can only be req_sz bytes in size, and + * we lose one SGE whenever we chain. + * For 128 req_sz, we can hold up to 16 SGE's per chain buffer. + * For practical reasons, limit ourselves to 1 overflow chain buffer; + * giving us 9 + 16 == 25 SGE's max. + * At 4 Kb per SGE, that yields 100 Kb max transfer. + * + * (This code needs to be completely changed when/if 64-bit DMA + * addressing is used, since we will be able to fit much less than + * 10 embedded SG entries. -DaveM) + */ + if (sges_left) { + struct scatterlist *sg = (struct scatterlist *) SCpnt->request_buffer; + u32 v1, v2; + int sge_spill2; + int sge_cur_spill; + int sgCnt; + u8 *pSgBucket; + int chain_sz; + + len = 0; + + /* sge_spill2 = 15; + * spill2: for req_sz == 128 (128/8==16 SGEs max, first time!), --> use 15 + * spill2: for req_sz == 96 ( 96/8==12 SGEs max, first time!), --> use 11 + */ + sge_spill2 = frm_sz / 8 - 1; + dsgprintk((KERN_INFO MYNAM ": SG: %x spill2 = %d\n", + my_idx, sge_spill2)); + + pSgBucket = NULL; + sgCnt = 0; + sge_cur_spill = sge_spill1; + while (sges_left) { +#if 0 + if (sg_dma_len(sg) > max_sgent_len) { + max_sgent_len = sg_dma_len(sg); + printk(KERN_INFO MYNAM ": MPT_MaxSgentLen = %d\n", max_sgent_len); + } +#endif + /* Write one simple SGE */ + v1 = sgdir | 0x10000000 | sg_dma_len(sg); + len += sg_dma_len(sg); + v2 = sg_dma_address(sg); + dsgprintk((KERN_INFO MYNAM ": SG: %x Writing SGE @%p: %08x %08x, sges_left=%d\n", + my_idx, mptr, v1, v2, sges_left)); + *mptr++ = cpu_to_le32(v1); + *mptr++ = cpu_to_le32(v2); + sg++; + sgCnt++; + + if (--sges_left == 0) { + /* re-write 1st word of previous SGE with SIMPLE, + * LE, EOB, and EOL bits! + */ + v1 = 0xD1000000 | sgdir | sg_dma_len(sg-1); + dsgprintk((KERN_INFO MYNAM ": SG: %x (re)Writing SGE @%p: %08x (VERY LAST SGE!)\n", + my_idx, mptr-2, v1)); + *(mptr - 2) = cpu_to_le32(v1); + } else { + if ((sges_left > 1) && ((sgCnt % sge_cur_spill) == 0)) { + dsgprintk((KERN_INFO MYNAM ": SG: %x SG spill at modulo 0!\n", + my_idx)); + + /* Fixup previous SGE with LE bit! */ + v1 = sgdir | 0x90000000 | sg_dma_len(sg-1); + dsgprintk((KERN_INFO MYNAM ": SG: %x (re)Writing SGE @%p: %08x (LAST BUCKET SGE!)\n", + my_idx, mptr-2, v1)); + *(mptr - 2) = cpu_to_le32(v1); + + chain_offset = 0; + /* Going to need another chain? */ + if (sges_left > (sge_spill2+1)) { +#if 0 + chain_offset = 0x1E; +#endif + chain_offset = (frm_sz - 8) / 4; + chain_sz = frm_sz; + } else { + chain_sz = sges_left * 8; + } + + /* write chain SGE at mptr. */ + v1 = 0x30000000 | chain_offset<<16 | chain_sz; + if (pSgBucket == NULL) { + pSgBucket = hd->SgHunks + + (my_idx * frm_sz * MPT_SG_BUCKETS_PER_HUNK); + } else { + pSgBucket += frm_sz; + } + v2 = (hd->SgHunksDMA + + ((u8 *)pSgBucket - (u8 *)hd->SgHunks)); + dsgprintk((KERN_INFO MYNAM ": SG: %x Writing SGE @%p: %08x %08x (CHAIN!)\n", + my_idx, mptr, v1, v2)); + *(mptr++) = cpu_to_le32(v1); + *(mptr) = cpu_to_le32(v2); + + mptr = (u32 *) pSgBucket; + sgCnt = 0; + sge_cur_spill = sge_spill2; + } + } + } + } else { + dsgprintk((KERN_INFO MYNAM ": SG: non-SG for %p, len=%d\n", + SCpnt, SCpnt->request_bufflen)); + + if (len > 0) { + dma_addr_t buf_dma_addr; + + buf_dma_addr = (dma_addr_t) (unsigned long)SCpnt->SCp.ptr; + *(mptr++) = cpu_to_le32(0xD1000000|sgdir|SCpnt->request_bufflen); + *(mptr++) = cpu_to_le32(buf_dma_addr); + } + } + +#ifdef MPT_DEBUG + /* if (SCpnt->request_bufflen > max_xfer) */ + if (len > max_xfer) { + max_xfer = len; + dprintk((KERN_INFO MYNAM ": MPT_MaxXfer = %d\n", max_xfer)); + } +#endif + + hd->ScsiLookup[my_idx] = SCpnt; + + /* Main banana... */ + mpt_put_msg_frame(ScsiDoneCtx, hd->ioc->id, mf); + + atomic_inc(&queue_depth); + if (atomic_read(&queue_depth) > max_qd) { + max_qd = atomic_read(&queue_depth); + dprintk((KERN_INFO MYNAM ": Queue depth now %d.\n", max_qd)); + } + + mb(); + dmfprintk((KERN_INFO MYNAM ": Issued SCSI cmd (%p)\n", SCpnt)); + + return 0; +} + +#ifdef MPT_SCSI_USE_NEW_EH /* { */ +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + mptscsih_abort + Returns: 0=SUCCESS, else FAILED +*/ +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/** + * mptscsih_abort - Abort linux Scsi_Cmnd routine, new_eh variant + * @SCpnt: Pointer to Scsi_Cmnd structure, IO to be aborted + * + * (linux Scsi_Host_Template.eh_abort_handler routine) + * + * Returns SUCCESS or FAILED. + */ +int +mptscsih_abort(Scsi_Cmnd * SCpnt) +{ + MPT_FRAME_HDR *mf; + SCSITaskMgmt_t *pScsiTm; + MPT_SCSI_HOST *hd; + u32 *msg; + u32 ctx2abort; + int i; + + printk(KERN_WARNING MYNAM ": Attempting _ABORT SCSI IO (=%p)\n", SCpnt); + printk(KERN_WARNING MYNAM ": IOs outstanding = %d\n", atomic_read(&queue_depth)); + + hd = (MPT_SCSI_HOST *) SCpnt->host->hostdata; + + if ((mf = mpt_get_msg_frame(ScsiTaskCtx, hd->ioc->id)) == NULL) { +/* SCpnt->result = DID_SOFT_ERROR << 16; */ + SCpnt->result = STS_BUSY; + SCpnt->scsi_done(SCpnt); + return FAILED; + } + + pScsiTm = (SCSITaskMgmt_t *) mf; + msg = (u32 *) mf; + + pScsiTm->TargetID = SCpnt->target; + pScsiTm->Bus = hd->port; + pScsiTm->ChainOffset = 0; + pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT; + + pScsiTm->Reserved = 0; + pScsiTm->TaskType = MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK; + pScsiTm->Reserved1 = 0; + pScsiTm->MsgFlags = 0; + + for (i = 0; i < 8; i++) { + u8 val = 0; + if (i == 1) + val = SCpnt->lun; + pScsiTm->LUN[i] = val; + } + + for (i = 0; i < 7; i++) + pScsiTm->Reserved2[i] = 0; + + /* Most important! Set TaskMsgContext to SCpnt's MsgContext! + * (the IO to be ABORT'd) + * + * NOTE: Since we do not byteswap MsgContext, we do not + * swap it here either. It is an opaque cookie to + * the controller, so it does not matter. -DaveM + */ + ctx2abort = SCPNT_TO_MSGCTX(SCpnt); + dprintk((KERN_INFO MYNAM ":DbG: ctx2abort = %08x\n", ctx2abort)); + pScsiTm->TaskMsgContext = ctx2abort; + + wmb(); + +/* MPI v0.10 requires SCSITaskMgmt requests be sent via Doorbell/handshake + mpt_put_msg_frame(hd->ioc->id, mf); +*/ +/* FIXME! Check return status! */ + (void) mpt_send_handshake_request(ScsiTaskCtx, hd->ioc->id, sizeof(SCSITaskMgmt_t), msg); + + wmb(); + + return SUCCESS; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/** + * mptscsih_bus_reset - Perform a SCSI BUS_RESET! new_eh variant + * @SCpnt: Pointer to Scsi_Cmnd structure, IO which reset is due to + * + * (linux Scsi_Host_Template.eh_bus_reset_handler routine) + * + * Returns SUCCESS or FAILED. + */ +int +mptscsih_bus_reset(Scsi_Cmnd * SCpnt) +{ + MPT_FRAME_HDR *mf; + SCSITaskMgmt_t *pScsiTm; + MPT_SCSI_HOST *hd; + u32 *msg; + int i; + + printk(KERN_WARNING MYNAM ": Attempting _BUS_RESET (%p)\n", SCpnt); + printk(KERN_WARNING MYNAM ": IOs outstanding = %d\n", atomic_read(&queue_depth)); + + hd = (MPT_SCSI_HOST *) SCpnt->host->hostdata; + + if ((mf = mpt_get_msg_frame(ScsiTaskCtx, hd->ioc->id)) == NULL) { +/* SCpnt->result = DID_SOFT_ERROR << 16; */ + SCpnt->result = STS_BUSY; + SCpnt->scsi_done(SCpnt); + return FAILED; + } + + pScsiTm = (SCSITaskMgmt_t *) mf; + msg = (u32 *) mf; + + pScsiTm->TargetID = SCpnt->target; + pScsiTm->Bus = hd->port; + pScsiTm->ChainOffset = 0; + pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT; + + pScsiTm->Reserved = 0; + pScsiTm->TaskType = MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS; + pScsiTm->Reserved1 = 0; + pScsiTm->MsgFlags = 0; + + for (i = 0; i < 8; i++) + pScsiTm->LUN[i] = 0; + + /* Control: No data direction, set task mgmt bit? */ + for (i = 0; i < 7; i++) + pScsiTm->Reserved2[i] = 0; + + pScsiTm->TaskMsgContext = cpu_to_le32(0); + + wmb(); + +/* MPI v0.10 requires SCSITaskMgmt requests be sent via Doorbell/handshake + mpt_put_msg_frame(hd->ioc->id, mf); +*/ +/* FIXME! Check return status! */ + (void) mpt_send_handshake_request(ScsiTaskCtx, hd->ioc->id, sizeof(SCSITaskMgmt_t), msg); + + wmb(); + + return SUCCESS; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/** + * mptscsih_dev_reset - Perform a SCSI TARGET_RESET! new_eh variant + * @SCpnt: Pointer to Scsi_Cmnd structure, IO which reset is due to + * + * (linux Scsi_Host_Template.eh_dev_reset_handler routine) + * + * Returns SUCCESS or FAILED. + */ +int +mptscsih_dev_reset(Scsi_Cmnd * SCpnt) +{ + MPT_FRAME_HDR *mf; + SCSITaskMgmt_t *pScsiTm; + MPT_SCSI_HOST *hd; + u32 *msg; + int i; + + printk(KERN_WARNING MYNAM ": Attempting _TARGET_RESET (%p)\n", SCpnt); + printk(KERN_WARNING MYNAM ": IOs outstanding = %d\n", atomic_read(&queue_depth)); + + hd = (MPT_SCSI_HOST *) SCpnt->host->hostdata; + + if ((mf = mpt_get_msg_frame(ScsiTaskCtx, hd->ioc->id)) == NULL) { +/* SCpnt->result = DID_SOFT_ERROR << 16; */ + SCpnt->result = STS_BUSY; + SCpnt->scsi_done(SCpnt); + return FAILED; + } + + pScsiTm = (SCSITaskMgmt_t *) mf; + msg = (u32*)mf; + + pScsiTm->TargetID = SCpnt->target; + pScsiTm->Bus = hd->port; + pScsiTm->ChainOffset = 0; + pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT; + + pScsiTm->Reserved = 0; + pScsiTm->TaskType = MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET; + pScsiTm->Reserved1 = 0; + pScsiTm->MsgFlags = 0; + + /* _TARGET_RESET goes to LUN 0 always! */ + for (i = 0; i < 8; i++) + pScsiTm->LUN[i] = 0; + + /* Control: No data direction, set task mgmt bit? */ + for (i = 0; i < 7; i++) + pScsiTm->Reserved2[i] = 0; + + pScsiTm->TaskMsgContext = cpu_to_le32(0); + + wmb(); + +/* MPI v0.10 requires SCSITaskMgmt requests be sent via Doorbell/handshake + mpt_put_msg_frame(hd->ioc->id, mf); +*/ +/* FIXME! Check return status! */ + (void) mpt_send_handshake_request(ScsiTaskCtx, hd->ioc->id, sizeof(SCSITaskMgmt_t), msg); + + wmb(); + + return SUCCESS; +} + +#if 0 /* { */ +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/** + * mptscsih_host_reset - Perform a SCSI host adapter RESET! + * new_eh variant + * @SCpnt: Pointer to Scsi_Cmnd structure, IO which reset is due to + * + * (linux Scsi_Host_Template.eh_host_reset_handler routine) + * + * Returns SUCCESS or FAILED. + */ +int +mptscsih_host_reset(Scsi_Cmnd * SCpnt) +{ + return FAILED; +} +#endif /* } */ + +#else /* MPT_SCSI old EH stuff... */ +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/** + * mptscsih_old_abort - Abort linux Scsi_Cmnd routine + * @SCpnt: Pointer to Scsi_Cmnd structure, IO to be aborted + * + * (linux Scsi_Host_Template.abort routine) + * + * Returns SCSI_ABORT_{SUCCESS,BUSY,PENDING}. + */ +int +mptscsih_old_abort(Scsi_Cmnd *SCpnt) +{ + MPT_SCSI_HOST *hd; + MPT_FRAME_HDR *mf; + struct tq_struct *ptaskfoo; + unsigned long flags; + + printk(KERN_WARNING MYNAM ": Scheduling _ABORT SCSI IO (=%p)\n", SCpnt); + printk(KERN_WARNING MYNAM ": IOs outstanding = %d\n", atomic_read(&queue_depth)); + + if ((hd = (MPT_SCSI_HOST *) SCpnt->host->hostdata) == NULL) { + SCpnt->result = DID_ABORT << 16; + SCpnt->scsi_done(SCpnt); + return SCSI_ABORT_SUCCESS; + } + + /* + * Check to see if there's already an ABORT queued for this guy. + */ + mf = search_taskQ(0,SCpnt,MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK); + if (mf != NULL) { + return SCSI_ABORT_PENDING; + } + + if ((mf = mpt_get_msg_frame(ScsiTaskCtx, hd->ioc->id)) == NULL) { +/* SCpnt->result = DID_SOFT_ERROR << 16; */ + SCpnt->result = STS_BUSY; + SCpnt->scsi_done(SCpnt); + return SCSI_ABORT_BUSY; + } + + /* + * Add ourselves to (end of) mpt_scsih_taskQ. + * Check to see if our _bh is running. If NOT, schedule it. + */ + dslprintk((KERN_INFO MYNAM ": spinlock#2\n")); + spin_lock_irqsave(&mpt_scsih_taskQ_lock, flags); + Q_ADD_TAIL(&mpt_scsih_taskQ, &mf->u.frame.linkage, MPT_FRAME_HDR); + mpt_scsih_taskQ_cnt++; + /* Yikes - linkage! */ +/* SCpnt->host_scribble = (unsigned char *)mf; */ + mf->u.frame.linkage.arg1 = MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK; + mf->u.frame.linkage.argp1 = SCpnt; + if (! mpt_scsih_taskQ_bh_active) { + mpt_scsih_taskQ_bh_active = 1; + /* + * Oh how cute, no alloc/free/mgmt needed if we use + * (bottom/unused portion of) MPT request frame. + */ + ptaskfoo = (struct tq_struct *) ((u8*)mf + hd->ioc->req_sz - sizeof(*ptaskfoo)); + ptaskfoo->sync = 0; + ptaskfoo->routine = mptscsih_taskmgmt_bh; + ptaskfoo->data = SCpnt; + + SCHEDULE_TASK(ptaskfoo); + } + spin_unlock_irqrestore(&mpt_scsih_taskQ_lock, flags); + + return SCSI_ABORT_PENDING; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/** + * mptscsih_old_reset - Perform a SCSI BUS_RESET! + * @SCpnt: Pointer to Scsi_Cmnd structure, IO which reset is due to + * @reset_flags: (not used?) + * + * (linux Scsi_Host_Template.reset routine) + * + * Returns SCSI_RESET_{SUCCESS,PUNT,PENDING}. + */ +int +mptscsih_old_reset(Scsi_Cmnd *SCpnt, unsigned int reset_flags) +{ + MPT_SCSI_HOST *hd; + MPT_FRAME_HDR *mf; + struct tq_struct *ptaskfoo; + unsigned long flags; + + printk(KERN_WARNING MYNAM ": Scheduling _BUS_RESET (=%p)\n", SCpnt); + printk(KERN_WARNING MYNAM ": IOs outstanding = %d\n", atomic_read(&queue_depth)); + + if ((hd = (MPT_SCSI_HOST *) SCpnt->host->hostdata) == NULL) { + SCpnt->result = DID_RESET << 16; + SCpnt->scsi_done(SCpnt); + return SCSI_RESET_SUCCESS; + } + + /* + * Check to see if there's already a BUS_RESET queued for this guy. + */ + mf = search_taskQ(0,SCpnt,MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS); + if (mf != NULL) { + return SCSI_RESET_PENDING; + } + + if ((mf = mpt_get_msg_frame(ScsiTaskCtx, hd->ioc->id)) == NULL) { +/* SCpnt->result = DID_SOFT_ERROR << 16; */ + SCpnt->result = STS_BUSY; + SCpnt->scsi_done(SCpnt); + return SCSI_RESET_PUNT; + } + + /* + * Add ourselves to (end of) mpt_scsih_taskQ. + * Check to see if our _bh is running. If NOT, schedule it. + */ + dslprintk((KERN_INFO MYNAM ": spinlock#3\n")); + spin_lock_irqsave(&mpt_scsih_taskQ_lock, flags); + Q_ADD_TAIL(&mpt_scsih_taskQ, &mf->u.frame.linkage, MPT_FRAME_HDR); + mpt_scsih_taskQ_cnt++; + /* Yikes - linkage! */ +/* SCpnt->host_scribble = (unsigned char *)mf; */ + mf->u.frame.linkage.arg1 = MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS; + mf->u.frame.linkage.argp1 = SCpnt; + if (! mpt_scsih_taskQ_bh_active) { + mpt_scsih_taskQ_bh_active = 1; + /* + * Oh how cute, no alloc/free/mgmt needed if we use + * (bottom/unused portion of) MPT request frame. + */ + ptaskfoo = (struct tq_struct *) ((u8*)mf + hd->ioc->req_sz - sizeof(*ptaskfoo)); + ptaskfoo->sync = 0; + ptaskfoo->routine = mptscsih_taskmgmt_bh; + ptaskfoo->data = SCpnt; + + SCHEDULE_TASK(ptaskfoo); + } + spin_unlock_irqrestore(&mpt_scsih_taskQ_lock, flags); + + return SCSI_RESET_PENDING; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * mptscsih_taskmgmt_bh - SCSI task mgmt bottom half handler + * @sc: (unused) + * + * This routine (thread) is active whenever there are any outstanding + * SCSI task management requests for a SCSI host adapter. + * IMPORTANT! This routine is scheduled therefore should never be + * running in ISR context. i.e., it's safe to sleep here. + */ +void +mptscsih_taskmgmt_bh(void *sc) +{ + Scsi_Cmnd *SCpnt; + MPT_FRAME_HDR *mf; + SCSITaskMgmt_t *pScsiTm; + MPT_SCSI_HOST *hd; + u32 ctx2abort = 0; + int i; + unsigned long flags; + u8 task_type; + + dslprintk((KERN_INFO MYNAM ": spinlock#4\n")); + spin_lock_irqsave(&mpt_scsih_taskQ_lock, flags); + mpt_scsih_taskQ_bh_active = 1; + spin_unlock_irqrestore(&mpt_scsih_taskQ_lock, flags); + + while (1) { + /* + * We MUST remove item from taskQ *before* we format the + * frame as a SCSITaskMgmt request and send it down to the IOC. + */ + dslprintk((KERN_INFO MYNAM ": spinlock#5\n")); + spin_lock_irqsave(&mpt_scsih_taskQ_lock, flags); + if (Q_IS_EMPTY(&mpt_scsih_taskQ)) { + spin_unlock_irqrestore(&mpt_scsih_taskQ_lock, flags); + break; + } + mf = mpt_scsih_taskQ.head; + Q_DEL_ITEM(&mf->u.frame.linkage); + mpt_scsih_taskQ_cnt--; + mpt_scsih_active_taskmgmt_mf = mf; + spin_unlock_irqrestore(&mpt_scsih_taskQ_lock, flags); + + SCpnt = (Scsi_Cmnd*)mf->u.frame.linkage.argp1; + if (SCpnt == NULL) { + printk(KERN_ERR MYNAM ": ERROR: TaskMgmt has NULL SCpnt! (%p:%p)\n", mf, SCpnt); + continue; + } + pScsiTm = (SCSITaskMgmt_t *) mf; + + for (i = 0; i < 8; i++) { + pScsiTm->LUN[i] = 0; + } + + task_type = mf->u.frame.linkage.arg1; + if (task_type == MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK) + { + printk(KERN_WARNING MYNAM ": Attempting _ABORT SCSI IO! (mf:sc=%p:%p)\n", mf, SCpnt); + + /* Most important! Set TaskMsgContext to SCpnt's MsgContext! + * (the IO to be ABORT'd) + * + * NOTE: Since we do not byteswap MsgContext, we do not + * swap it here either. It is an opaque cookie to + * the controller, so it does not matter. -DaveM + */ + ctx2abort = SCPNT_TO_MSGCTX(SCpnt); + pScsiTm->LUN[1] = SCpnt->lun; + } + else if (task_type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) + { + printk(KERN_WARNING MYNAM ": Attempting _BUS_RESET! (against SCSI IO mf:sc=%p:%p)\n", mf, SCpnt); + } +#if 0 + else if (task_type == MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET) {} + else if (task_type == MPI_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET) {} +#endif + + printk(KERN_WARNING MYNAM ": IOs outstanding = %d\n", atomic_read(&queue_depth)); + + hd = (MPT_SCSI_HOST *) SCpnt->host->hostdata; + + pScsiTm->TargetID = SCpnt->target; + pScsiTm->Bus = hd->port; + pScsiTm->ChainOffset = 0; + pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT; + + pScsiTm->Reserved = 0; + pScsiTm->TaskType = task_type; + pScsiTm->Reserved1 = 0; + pScsiTm->MsgFlags = 0; + + for (i = 0; i < 7; i++) + pScsiTm->Reserved2[i] = 0; + + dprintk((KERN_INFO MYNAM ":DbG: ctx2abort = %08x\n", ctx2abort)); + pScsiTm->TaskMsgContext = ctx2abort; + + /* Control: No data direction, set task mgmt bit? */ + + /* + * As of MPI v0.10 this request can NOT be sent (normally) + * via FIFOs. So we can't: + * mpt_put_msg_frame(ScsiTaskCtx, hd->ioc->id, mf); + * SCSITaskMgmt requests MUST be sent ONLY via + * Doorbell/handshake now. :-( + * + * FIXME! Check return status! + */ + (void) mpt_send_handshake_request(ScsiTaskCtx, hd->ioc->id, sizeof(SCSITaskMgmt_t), (u32*)mf); + + /* Spin-Wait for TaskMgmt complete!!! */ + while (mpt_scsih_active_taskmgmt_mf != NULL) { + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(HZ/2); + } + } + + dslprintk((KERN_INFO MYNAM ": spinlock#6\n")); + spin_lock_irqsave(&mpt_scsih_taskQ_lock, flags); + mpt_scsih_taskQ_bh_active = 0; + spin_unlock_irqrestore(&mpt_scsih_taskQ_lock, flags); + + return; +} + +#endif /* } */ + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/** + * mptscsih_taskmgmt_complete - Callback routine, gets registered to + * Fusion MPT base driver + * @ioc: Pointer to MPT_ADAPTER structure + * @mf: Pointer to SCSI task mgmt request frame + * @r: Pointer to SCSI task mgmt reply frame + * + * This routine is called from mptbase.c::mpt_interrupt() at the completion + * of any SCSI task management request. + * This routine is registered with the MPT (base) driver at driver + * load/init time via the mpt_register() API call. + * + * Returns 1 indicating alloc'd request frame ptr should be freed. + */ +static int +mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r) +{ + SCSITaskMgmtReply_t *pScsiTmReply; + SCSITaskMgmt_t *pScsiTmReq; + u8 tmType; +#ifndef MPT_SCSI_USE_NEW_EH + unsigned long flags; +#endif + + dprintk((KERN_INFO MYNAM ": SCSI TaskMgmt completed mf=%p, r=%p\n", + mf, r)); + +#ifndef MPT_SCSI_USE_NEW_EH + dslprintk((KERN_INFO MYNAM ": spinlock#7\n")); + spin_lock_irqsave(&mpt_scsih_taskQ_lock, flags); + /* It better be the active one! */ + if (mf != mpt_scsih_active_taskmgmt_mf) { + printk(KERN_ERR MYNAM ": ERROR! Non-active TaskMgmt (=%p) completed!\n", mf); + mpt_scsih_active_taskmgmt_mf = NULL; + spin_unlock_irqrestore(&mpt_scsih_taskQ_lock, flags); + return 1; + } + +#ifdef MPT_DEBUG + if ((mf == NULL) || + (mf >= MPT_INDEX_2_MFPTR(ioc, ioc->req_depth))) { + printk(KERN_ERR MYNAM ": ERROR! NULL or BAD TaskMgmt ptr (=%p)!\n", mf); + mpt_scsih_active_taskmgmt_mf = NULL; + spin_unlock_irqrestore(&mpt_scsih_taskQ_lock, flags); + return 1; + } +#endif + spin_unlock_irqrestore(&mpt_scsih_taskQ_lock, flags); +#endif + + if (r != NULL) { + pScsiTmReply = (SCSITaskMgmtReply_t*)r; + pScsiTmReq = (SCSITaskMgmt_t*)mf; + + /* Figure out if this was ABORT_TASK, TARGET_RESET, or BUS_RESET! */ + tmType = pScsiTmReq->TaskType; + + dprintk((KERN_INFO MYNAM ": TaskType = %d\n", tmType)); + dprintk((KERN_INFO MYNAM ": TerminationCount = %d\n", + le32_to_cpu(pScsiTmReply->TerminationCount))); + + /* Error? (anything non-zero?) */ + if (*(u32 *)&pScsiTmReply->Reserved2[0]) { + dprintk((KERN_INFO MYNAM ": SCSI TaskMgmt (%d) - Oops!\n", tmType)); + dprintk((KERN_INFO MYNAM ": IOCStatus = %04xh\n", + le16_to_cpu(pScsiTmReply->IOCStatus))); + dprintk((KERN_INFO MYNAM ": IOCLogInfo = %08xh\n", + le32_to_cpu(pScsiTmReply->IOCLogInfo))); + } else { + dprintk((KERN_INFO MYNAM ": SCSI TaskMgmt (%d) SUCCESS!\n", tmType)); + } + } + +#ifndef MPT_SCSI_USE_NEW_EH + /* + * Signal to _bh thread that we finished. + */ + dslprintk((KERN_INFO MYNAM ": spinlock#8\n")); + spin_lock_irqsave(&mpt_scsih_taskQ_lock, flags); + mpt_scsih_active_taskmgmt_mf = NULL; + spin_unlock_irqrestore(&mpt_scsih_taskQ_lock, flags); +#endif + + return 1; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * This is anyones guess quite frankly. + */ + +int +mptscsih_bios_param(Disk * disk, kdev_t dev, int *ip) +{ + int size; + + size = disk->capacity; + ip[0] = 64; /* heads */ + ip[1] = 32; /* sectors */ + if ((ip[2] = size >> 11) > 1024) { /* cylinders, test for big disk */ + ip[0] = 255; /* heads */ + ip[1] = 63; /* sectors */ + ip[2] = size / (255 * 63); /* cylinders */ + } + return 0; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * Private routines... + */ +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* 19991030 -sralston + * Return absolute SCSI data direction: + * 1 = _DATA_OUT + * 0 = _DIR_NONE + * -1 = _DATA_IN + */ +static int +mptscsih_io_direction(Scsi_Cmnd *cmd) +{ + switch (cmd->cmnd[0]) { + /* _DATA_OUT commands */ + case WRITE_6: case WRITE_10: case WRITE_12: + case WRITE_LONG: case WRITE_SAME: case WRITE_BUFFER: + case WRITE_VERIFY: case WRITE_VERIFY_12: + case COMPARE: case COPY: case COPY_VERIFY: + case SEARCH_EQUAL: case SEARCH_HIGH: case SEARCH_LOW: + case SEARCH_EQUAL_12: case SEARCH_HIGH_12: case SEARCH_LOW_12: + case MODE_SELECT: case MODE_SELECT_10: case LOG_SELECT: + case SEND_DIAGNOSTIC: case CHANGE_DEFINITION: case UPDATE_BLOCK: + case SET_WINDOW: case MEDIUM_SCAN: case SEND_VOLUME_TAG: + case REASSIGN_BLOCKS: + case PERSISTENT_RESERVE_OUT: + case 0xea: + return 1; + + /* No data transfer commands */ + case SEEK_6: case SEEK_10: + case RESERVE: case RELEASE: + case TEST_UNIT_READY: + case START_STOP: + case ALLOW_MEDIUM_REMOVAL: + return 0; + + /* Conditional data transfer commands */ + case FORMAT_UNIT: + if (cmd->cmnd[1] & 0x10) /* FmtData (data out phase)? */ + return 1; + else + return 0; + + case VERIFY: + if (cmd->cmnd[1] & 0x02) /* VERIFY:BYTCHK (data out phase)? */ + return 1; + else + return 0; + + case RESERVE_10: + if (cmd->cmnd[1] & 0x03) /* RESERSE:{LongID|Extent} (data out phase)? */ + return 1; + else + return 0; + +#if 0 + case REZERO_UNIT: /* (or REWIND) */ + case SPACE: + case ERASE: case ERASE_10: + case SYNCHRONIZE_CACHE: + case LOCK_UNLOCK_CACHE: +#endif + + /* Must be data _IN! */ + default: + return -1; + } +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +static void +copy_sense_data(Scsi_Cmnd *sc, MPT_SCSI_HOST *hd, MPT_FRAME_HDR *mf, SCSIIOReply_t *pScsiReply) +{ + MPT_SCSI_DEV *mpt_sdev = NULL; + u32 sense_count = le32_to_cpu(pScsiReply->SenseCount); + char devFoo[32]; + IO_Info_t thisIo; + + if (sc && sc->device) + mpt_sdev = (MPT_SCSI_DEV*) sc->device->hostdata; + + if (sense_count) { + u8 *sense_data; + int req_index; + + /* Copy the sense received into the scsi command block. */ + req_index = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx); + sense_data = ((u8 *)hd->ioc->sense_buf_pool + (req_index * 256)); + memcpy(sc->sense_buffer, sense_data, SNS_LEN(sc)); + /* Cache SenseData for this SCSI device! */ + if (mpt_sdev) { + memcpy(mpt_sdev->CachedSense.data, sense_data, sense_count); + mpt_sdev->sense_sz = sense_count; + } + } else { + dprintk((KERN_INFO MYNAM ": Hmmm... SenseData len=0! (?)\n")); + } + + + thisIo.cdbPtr = sc->cmnd; + thisIo.sensePtr = sc->sense_buffer; + thisIo.SCSIStatus = pScsiReply->SCSIStatus; + thisIo.DoDisplay = 1; + sprintf(devFoo, "ioc%d,scsi%d:%d", hd->ioc->id, sc->target, sc->lun); + thisIo.DevIDStr = devFoo; +/* fubar */ + thisIo.dataPtr = NULL; + thisIo.inqPtr = NULL; + if (sc->device) { + thisIo.inqPtr = sc->device->vendor-8; /* FIXME!!! */ + } + (void) mpt_ScsiHost_ErrorReport(&thisIo); + + return; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +static u32 +SCPNT_TO_MSGCTX(Scsi_Cmnd *sc) +{ + MPT_SCSI_HOST *hd; + MPT_FRAME_HDR *mf; + int i; + + hd = (MPT_SCSI_HOST *) sc->host->hostdata; + + for (i = 0; i < hd->ioc->req_depth; i++) { + if (hd->ScsiLookup[i] == sc) { + mf = MPT_INDEX_2_MFPTR(hd->ioc, i); + return mf->u.frame.hwhdr.msgctxu.MsgContext; + } + } + + return -1; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + +/* see mptscsih.h */ + +#ifdef MPT_SCSIHOST_NEED_ENTRY_EXIT_HOOKUPS + static Scsi_Host_Template driver_template = MPT_SCSIHOST; +# include "../../scsi/scsi_module.c" +#endif + + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +static int +mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply) +{ + u8 event = le32_to_cpu(pEvReply->Event) & 0xFF; + + dprintk((KERN_INFO MYNAM ": MPT event (=%02Xh) routed to SCSI host driver!\n", event)); + + switch (event) { + case MPI_EVENT_UNIT_ATTENTION: /* 03 */ + /* FIXME! */ + break; + case MPI_EVENT_IOC_BUS_RESET: /* 04 */ + /* FIXME! */ + break; + case MPI_EVENT_EXT_BUS_RESET: /* 05 */ + /* FIXME! */ + break; + case MPI_EVENT_LOGOUT: /* 09 */ + /* FIXME! */ + break; + + /* + * CHECKME! Don't think we need to do + * anything for these, but... + */ + case MPI_EVENT_RESCAN: /* 06 */ + case MPI_EVENT_LINK_STATUS_CHANGE: /* 07 */ + case MPI_EVENT_LOOP_STATE_CHANGE: /* 08 */ + /* + * CHECKME! Falling thru... + */ + + case MPI_EVENT_NONE: /* 00 */ + case MPI_EVENT_LOG_DATA: /* 01 */ + case MPI_EVENT_STATE_CHANGE: /* 02 */ + case MPI_EVENT_EVENT_CHANGE: /* 0A */ + default: + dprintk((KERN_INFO MYNAM ": Ignoring event (=%02Xh)\n", event)); + break; + } + + return 1; /* currently means nothing really */ +} + +#if 0 /* { */ +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * scsiherr.c - Fusion MPT SCSI Host driver error handling/reporting. + * + * drivers/message/fusion/scsiherr.c + */ + +//extern const char **mpt_ScsiOpcodesPtr; /* needed by mptscsih.c */ +//extern ASCQ_Table_t *mpt_ASCQ_TablePtr; +//extern int mpt_ASCQ_TableSz; + +/* Lie! */ +#define MYNAM "mptscsih" + +#endif /* } */ + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * Private data... + */ +static ASCQ_Table_t *mptscsih_ASCQ_TablePtr; + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* old symsense.c stuff... */ +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * Private data... + * To protect ourselves against those that would pass us bogus pointers + */ +static u8 dummyInqData[SCSI_STD_INQUIRY_BYTES] + = { 0x1F, 0x00, 0x00, 0x00, + 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; +static u8 dummySenseData[SCSI_STD_SENSE_BYTES] + = { 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00 }; +static u8 dummyCDB[16] + = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; +static u8 dummyScsiData[16] + = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + +#if 0 +static const char *PeripheralDeviceTypeString[32] = { + "Direct-access", /* 00h */ + "Sequential-access", /* 01h */ + "Printer", /* 02h */ + "Processor", /* 03h */ + /*"Write-Once-Read-Multiple",*/ /* 04h */ + "WORM", /* 04h */ + "CD-ROM", /* 05h */ + "Scanner", /* 06h */ + "Optical memory", /* 07h */ + "Media Changer", /* 08h */ + "Communications", /* 09h */ + "(Graphics arts pre-press)", /* 0Ah */ + "(Graphics arts pre-press)", /* 0Bh */ + "Array controller", /* 0Ch */ + "Enclosure services", /* 0Dh */ + "Simplified direct-access", /* 0Eh */ + "Reserved-0Fh", /* 0Fh */ + "Reserved-10h", /* 10h */ + "Reserved-11h", /* 11h */ + "Reserved-12h", /* 12h */ + "Reserved-13h", /* 13h */ + "Reserved-14h", /* 14h */ + "Reserved-15h", /* 15h */ + "Reserved-16h", /* 16h */ + "Reserved-17h", /* 17h */ + "Reserved-18h", /* 18h */ + "Reserved-19h", /* 19h */ + "Reserved-1Ah", /* 1Ah */ + "Reserved-1Bh", /* 1Bh */ + "Reserved-1Ch", /* 1Ch */ + "Reserved-1Dh", /* 1Dh */ + "Reserved-1Eh", /* 1Eh */ + "Unknown" /* 1Fh */ +}; +#endif + +static char *ScsiStatusString[] = { + "GOOD", /* 00h */ + NULL, /* 01h */ + "CHECK CONDITION", /* 02h */ + NULL, /* 03h */ + "CONDITION MET", /* 04h */ + NULL, /* 05h */ + NULL, /* 06h */ + NULL, /* 07h */ + "BUSY", /* 08h */ + NULL, /* 09h */ + NULL, /* 0Ah */ + NULL, /* 0Bh */ + NULL, /* 0Ch */ + NULL, /* 0Dh */ + NULL, /* 0Eh */ + NULL, /* 0Fh */ + "INTERMEDIATE", /* 10h */ + NULL, /* 11h */ + NULL, /* 12h */ + NULL, /* 13h */ + "INTERMEDIATE-CONDITION MET", /* 14h */ + NULL, /* 15h */ + NULL, /* 16h */ + NULL, /* 17h */ + "RESERVATION CONFLICT", /* 18h */ + NULL, /* 19h */ + NULL, /* 1Ah */ + NULL, /* 1Bh */ + NULL, /* 1Ch */ + NULL, /* 1Dh */ + NULL, /* 1Eh */ + NULL, /* 1Fh */ + NULL, /* 20h */ + NULL, /* 21h */ + "COMMAND TERMINATED", /* 22h */ + NULL, /* 23h */ + NULL, /* 24h */ + NULL, /* 25h */ + NULL, /* 26h */ + NULL, /* 27h */ + "TASK SET FULL", /* 28h */ + NULL, /* 29h */ + NULL, /* 2Ah */ + NULL, /* 2Bh */ + NULL, /* 2Ch */ + NULL, /* 2Dh */ + NULL, /* 2Eh */ + NULL, /* 2Fh */ + "ACA ACTIVE", /* 30h */ + NULL +}; + +static const char *ScsiCommonOpString[] = { + "TEST UNIT READY", /* 00h */ + "REZERO UNIT (REWIND)", /* 01h */ + NULL, /* 02h */ + "REQUEST_SENSE", /* 03h */ + "FORMAT UNIT (MEDIUM)", /* 04h */ + "READ BLOCK LIMITS", /* 05h */ + NULL, /* 06h */ + "REASSIGN BLOCKS", /* 07h */ + "READ(6)", /* 08h */ + NULL, /* 09h */ + "WRITE(6)", /* 0Ah */ + "SEEK(6)", /* 0Bh */ + NULL, /* 0Ch */ + NULL, /* 0Dh */ + NULL, /* 0Eh */ + "READ REVERSE", /* 0Fh */ + "WRITE_FILEMARKS", /* 10h */ + "SPACE(6)", /* 11h */ + "INQUIRY", /* 12h */ + NULL +}; + +static const char *SenseKeyString[] = { + "NO SENSE", /* 0h */ + "RECOVERED ERROR", /* 1h */ + "NOT READY", /* 2h */ + "MEDIUM ERROR", /* 3h */ + "HARDWARE ERROR", /* 4h */ + "ILLEGAL REQUEST", /* 5h */ + "UNIT ATTENTION", /* 6h */ + "DATA PROTECT", /* 7h */ + "BLANK CHECK", /* 8h */ + "VENDOR-SPECIFIC", /* 9h */ + "ABORTED COPY", /* Ah */ + "ABORTED COMMAND", /* Bh */ + "EQUAL (obsolete)", /* Ch */ + "VOLUME OVERFLOW", /* Dh */ + "MISCOMPARE", /* Eh */ + "RESERVED", /* Fh */ + NULL +}; + +#define SPECIAL_ASCQ(c,q) \ + (((c) == 0x40 && (q) != 0x00) || ((c) == 0x4D) || ((c) == 0x70)) + +#if 0 +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * Sense_Key_Specific() - If Sense_Key_Specific_Valid bit is set, + * then print additional information via + * a call to SDMS_SystemAlert(). + * + * Return: nothing + */ +static void Sense_Key_Specific(IO_Info_t *ioop, char *msg1) +{ + u8 *sd; + u8 BadValue; + u8 SenseKey; + int Offset; + int len = strlen(msg1); + + sd = ioop->sensePtr; + if (SD_Additional_Sense_Length(sd) < 8) + return; + + SenseKey = SD_Sense_Key(sd); + + if (SD_Sense_Key_Specific_Valid(sd)) { + if (SenseKey == SK_ILLEGAL_REQUEST) { + Offset = SD_Bad_Byte(sd); + if (SD_Was_Illegal_Request(sd)) { + BadValue = ioop->cdbPtr[Offset]; + len += sprintf(msg1+len, "\n Illegal CDB value=%02Xh found at CDB ", + BadValue); + } else { + BadValue = ioop->dataPtr[Offset]; + len += sprintf(msg1+len, "\n Illegal DATA value=%02Xh found at DATA ", + BadValue); + } + len += sprintf(msg1+len, "byte=%02Xh", Offset); + if (SD_SKS_Bit_Pointer_Valid(sd)) + len += sprintf(msg1+len, "/bit=%1Xh", SD_SKS_Bit_Pointer(sd)); + } else if ((SenseKey == SK_RECOVERED_ERROR) || + (SenseKey == SK_HARDWARE_ERROR) || + (SenseKey == SK_MEDIUM_ERROR)) { + len += sprintf(msg1+len, "\n Recovery algorithm Actual_Retry_Count=%02Xh", + SD_Actual_Retry_Count(sd)); + } + } +} +#endif + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +static int dump_cdb(char *foo, unsigned char *cdb) +{ + int i, grpCode, cdbLen; + int l = 0; + + grpCode = cdb[0] >> 5; + if (grpCode < 1) + cdbLen = 6; + else if (grpCode < 3) + cdbLen = 10; + else if (grpCode == 5) + cdbLen = 12; + else + cdbLen = 16; + + for (i=0; i < cdbLen; i++) + l += sprintf(foo+l, " %02X", cdb[i]); + + return l; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +static int dump_sd(char *foo, unsigned char *sd) +{ + int snsLen = 8 + SD_Additional_Sense_Length(sd); + int l = 0; + int i; + + for (i=0; i < MIN(snsLen,18); i++) + l += sprintf(foo+l, " %02X", sd[i]); + l += sprintf(foo+l, "%s", snsLen>18 ? " ..." : ""); + + return l; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* Do ASC/ASCQ lookup/grindage to English readable string(s) */ +static const char * ascq_set_strings_4max( + u8 ASC, u8 ASCQ, + const char **s1, const char **s2, const char **s3, const char **s4) +{ + static const char *asc_04_part1_string = "LOGICAL UNIT "; + static const char *asc_04_part2a_string = "NOT READY, "; + static const char *asc_04_part2b_string = "IS "; + static const char *asc_04_ascq_NN_part3_strings[] = { /* ASC ASCQ (hex) */ + "CAUSE NOT REPORTABLE", /* 04 00 */ + "IN PROCESS OF BECOMING READY", /* 04 01 */ + "INITIALIZING CMD. REQUIRED", /* 04 02 */ + "MANUAL INTERVENTION REQUIRED", /* 04 03 */ + /* Add " IN PROGRESS" to all the following... */ + "FORMAT", /* 04 04 */ + "REBUILD", /* 04 05 */ + "RECALCULATION", /* 04 06 */ + "OPERATION", /* 04 07 */ + "LONG WRITE", /* 04 08 */ + "SELF-TEST", /* 04 09 */ + NULL + }; + static char *asc_04_part4_string = " IN PROGRESS"; + + static char *asc_29_ascq_NN_strings[] = { /* ASC ASCQ (hex) */ + "POWER ON, RESET, OR BUS DEVICE RESET OCCURRED", /* 29 00 */ + "POWER ON OCCURRED", /* 29 01 */ + "SCSI BUS RESET OCCURRED", /* 29 02 */ + "BUS DEVICE RESET FUNCTION OCCURRED", /* 29 03 */ + "DEVICE INTERNAL RESET", /* 29 04 */ + "TRANSCEIVER MODE CHANGED TO SINGLE-ENDED", /* 29 05 */ + "TRANSCEIVER MODE CHANGED TO LVD", /* 29 06 */ + NULL + }; + static char *ascq_vendor_uniq = "(Vendor Unique)"; + static char *ascq_noone = "(no matching ASC/ASCQ description found)"; + int idx; + + *s1 = *s2 = *s3 = *s4 = ""; /* set'em all to the empty "" string */ + + /* CHECKME! Need lock/sem? + * Update and examine for isense module presense. + */ + mptscsih_ASCQ_TablePtr = (ASCQ_Table_t *)mpt_v_ASCQ_TablePtr; + + if (mptscsih_ASCQ_TablePtr == NULL) { + /* 2nd chances... */ + if (ASC == 0x04 && (ASCQ < sizeof(asc_04_ascq_NN_part3_strings)/sizeof(char*)-1)) { + *s1 = asc_04_part1_string; + *s2 = (ASCQ == 0x01) ? asc_04_part2b_string : asc_04_part2a_string; + *s3 = asc_04_ascq_NN_part3_strings[ASCQ]; + /* check for " IN PROGRESS" ones */ + if (ASCQ >= 0x04) + *s4 = asc_04_part4_string; + } else if (ASC == 0x29 && (ASCQ < sizeof(asc_29_ascq_NN_strings)/sizeof(char*)-1)) + *s1 = asc_29_ascq_NN_strings[ASCQ]; + /* + * else { leave all *s[1-4] values pointing to the empty "" string } + */ + return *s1; + } + + /* + * Need to check ASC here; if it is "special," then + * the ASCQ is variable, and indicates failed component number. + * We must treat the ASCQ as a "don't care" while searching the + * mptscsih_ASCQ_Table[] by masking it off, and then restoring it later + * on when we actually need to identify the failed component. + */ + if (SPECIAL_ASCQ(ASC,ASCQ)) + ASCQ = 0xFF; + + /* OK, now search mptscsih_ASCQ_Table[] for a matching entry */ + for (idx = 0; mptscsih_ASCQ_TablePtr && idx < mpt_ASCQ_TableSz; idx++) + if ((ASC == mptscsih_ASCQ_TablePtr[idx].ASC) && (ASCQ == mptscsih_ASCQ_TablePtr[idx].ASCQ)) + return (*s1 = mptscsih_ASCQ_TablePtr[idx].Description); + + if ((ASC >= 0x80) || (ASCQ >= 0x80)) + *s1 = ascq_vendor_uniq; + else + *s1 = ascq_noone; + + return *s1; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * SCSI Error Report; desired output format... + *--- +SCSI Error Report =-=-=-=-=-=-=-=-=-=-=-=-=-= (ioc0,scsi0:0) + SCSI_Status=02h (CHECK CONDITION) + Original_CDB[]: 00 00 00 00 00 00 - TestUnitReady + SenseData[12h]: 70 00 06 00 00 00 00 0A 00 00 00 00 29 00 03 00 00 00 + SenseKey=6h (UNIT ATTENTION); FRU=03h + ASC/ASCQ=29h/00h, "POWER ON, RESET, OR BUS DEVICE RESET OCCURRED" + *--- + */ + +int mpt_ScsiHost_ErrorReport(IO_Info_t *ioop) +{ + char foo[512]; + char buf2[32]; + char *statstr; + const char *opstr; + int sk = SD_Sense_Key(ioop->sensePtr); + const char *skstr = SenseKeyString[sk]; + unsigned char asc = SD_ASC(ioop->sensePtr); + unsigned char ascq = SD_ASCQ(ioop->sensePtr); + int l; + + /* + * More quiet mode. + * Filter out common, repetitive, warning-type errors... like: + * POWER ON (06,29/00 or 06,29/01), + * SPINNING UP (02,04/01), + * LOGICAL UNIT NOT SUPPORTED (05,25/00), etc. + */ + if ( (sk==SK_UNIT_ATTENTION && asc==0x29 && (ascq==0x00 || ascq==0x01)) + || (sk==SK_NOT_READY && asc==0x04 && ascq==0x01) + || (sk==SK_ILLEGAL_REQUEST && asc==0x25 && ascq==0x00) + ) + { + /* Do nothing! */ + return 0; + } + + /* + * Protect ourselves... + */ + if (ioop->cdbPtr == NULL) + ioop->cdbPtr = dummyCDB; + if (ioop->sensePtr == NULL) + ioop->sensePtr = dummySenseData; + if (ioop->inqPtr == NULL) + ioop->inqPtr = dummyInqData; + if (ioop->dataPtr == NULL) + ioop->dataPtr = dummyScsiData; + + statstr = NULL; + if ((ioop->SCSIStatus >= sizeof(ScsiStatusString)/sizeof(char*)-1) || + ((statstr = (char*)ScsiStatusString[ioop->SCSIStatus]) == NULL)) { + (void) sprintf(buf2, "Bad-Reserved-%02Xh", ioop->SCSIStatus); + statstr = buf2; + } + + opstr = NULL; + if (1+ioop->cdbPtr[0] <= sizeof(ScsiCommonOpString)/sizeof(char*)) + opstr = ScsiCommonOpString[ioop->cdbPtr[0]]; + else if (mpt_ScsiOpcodesPtr) + opstr = mpt_ScsiOpcodesPtr[ioop->cdbPtr[0]]; + + l = sprintf(foo, "SCSI Error Report =-=-= (%s)\n" + " SCSI_Status=%02Xh (%s)\n" + " Original_CDB[]:", + ioop->DevIDStr, + ioop->SCSIStatus, + statstr); + l += dump_cdb(foo+l, ioop->cdbPtr); + if (opstr) + l += sprintf(foo+l, " - \"%s\"", opstr); + l += sprintf(foo+l, "\n SenseData[%02Xh]:", 8+SD_Additional_Sense_Length(ioop->sensePtr)); + l += dump_sd(foo+l, ioop->sensePtr); + l += sprintf(foo+l, "\n SenseKey=%Xh (%s); FRU=%02Xh\n ASC/ASCQ=%02Xh/%02Xh", + sk, skstr, SD_FRU(ioop->sensePtr), asc, ascq ); + + { + const char *x1, *x2, *x3, *x4; + x1 = x2 = x3 = x4 = ""; + x1 = ascq_set_strings_4max(asc, ascq, &x1, &x2, &x3, &x4); + if (x1 != NULL) { + if (x1[0] != '(') + l += sprintf(foo+l, " \"%s%s%s%s\"", x1,x2,x3,x4); + else + l += sprintf(foo+l, " %s%s%s%s", x1,x2,x3,x4); + } + } + +#if 0 + if (SPECIAL_ASCQ(asc,ascq)) + l += sprintf(foo+l, " (%02Xh)", ascq); +#endif + + PrintF(("%s\n", foo)); + + return l; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + diff -u --recursive --new-file v2.4.6/linux/drivers/message/fusion/mptscsih.h linux/drivers/message/fusion/mptscsih.h --- v2.4.6/linux/drivers/message/fusion/mptscsih.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/message/fusion/mptscsih.h Fri Jul 6 17:03:11 2001 @@ -0,0 +1,247 @@ +/* + * linux/drivers/message/fusion/mptscsih.h + * High performance SCSI / Fibre Channel SCSI Host device driver. + * For use with PCI chip/adapter(s): + * LSIFC9xx/LSI409xx Fibre Channel + * running LSI Logic Fusion MPT (Message Passing Technology) firmware. + * + * Credits: + * This driver would not exist if not for Alan Cox's development + * of the linux i2o driver. + * + * A huge debt of gratitude is owed to David S. Miller (DaveM) + * for fixing much of the stupid and broken stuff in the early + * driver while porting to sparc64 platform. THANK YOU! + * + * (see also mptbase.c) + * + * Copyright (c) 1999-2001 LSI Logic Corporation + * Originally By: Steven J. Ralston + * (mailto:Steve.Ralston@lsil.com) + * + * $Id: mptscsih.h,v 1.7 2001/01/11 16:56:43 sralston Exp $ + */ +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + 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; version 2 of the License. + + 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. + + NO WARRANTY + THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR + CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT + LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, + MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is + solely responsible for determining the appropriateness of using and + distributing the Program and assumes all risks associated with its + exercise of rights under this Agreement, including but not limited to + the risks and costs of program errors, damage to or loss of data, + programs or equipment, and unavailability or interruption of operations. + + DISCLAIMER OF LIABILITY + NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), 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 OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED + HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES + + 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 SCSIHOST_H_INCLUDED +#define SCSIHOST_H_INCLUDED +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + +#include "linux/version.h" + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * SCSI Public stuff... + */ + +#ifdef __sparc__ +#define MPT_SCSI_CAN_QUEUE 63 +#define MPT_SCSI_CMD_PER_LUN 63 + /* FIXME! Still investigating qd=64 hang on sparc64... */ +#else +#define MPT_SCSI_CAN_QUEUE 64 +#define MPT_SCSI_CMD_PER_LUN 64 +#endif + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * Various bits and pieces broke within the lk-2.4.0-testN series:-( + * So here are various HACKS to work around them. + */ + +/* + * Conditionalizing with "#ifdef MODULE/#endif" around: + * static Scsi_Host_Template driver_template = XX; + * #include <../../scsi/scsi_module.c> + * lines was REMOVED @ lk-2.4.0-test9 + * Issue discovered 20001213 by: sshirron + */ +#define MPT_SCSIHOST_NEED_ENTRY_EXIT_HOOKUPS 1 +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,4,0) +# if LINUX_VERSION_CODE == KERNEL_VERSION(2,4,0) + /* + * Super HACK! -by sralston:-( + * (good grief; heaven help me!) + */ +# include <linux/capability.h> +# if !defined(CAP_LEASE) && !defined(MODULE) +# undef MPT_SCSIHOST_NEED_ENTRY_EXIT_HOOKUPS +# endif +# else +# ifndef MODULE +# undef MPT_SCSIHOST_NEED_ENTRY_EXIT_HOOKUPS +# endif +# endif +#endif + +/* + * tq_scheduler disappeared @ lk-2.4.0-test12 + * (right when <linux/sched.h> newly defined TQ_ACTIVE) + */ +#define HAVE_TQ_SCHED 1 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) +# include <linux/sched.h> +# ifdef TQ_ACTIVE +# undef HAVE_TQ_SCHED +# endif +#endif +#ifdef HAVE_TQ_SCHED +#define SCHEDULE_TASK(x) \ + /*MOD_INC_USE_COUNT*/; \ + (x)->next = NULL; \ + queue_task(x, &tq_scheduler) +#else +#define SCHEDULE_TASK(x) \ + /*MOD_INC_USE_COUNT*/; \ + if (schedule_task(x) == 0) { \ + /*MOD_DEC_USE_COUNT*/; \ + } +#endif + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + +#define x_scsi_detect mptscsih_detect +#define x_scsi_release mptscsih_release +#define x_scsi_info mptscsih_info +#define x_scsi_queuecommand mptscsih_qcmd +#define x_scsi_abort mptscsih_abort +#define x_scsi_bus_reset mptscsih_bus_reset +#define x_scsi_dev_reset mptscsih_dev_reset +#define x_scsi_host_reset mptscsih_host_reset +#define x_scsi_bios_param mptscsih_bios_param + +#define x_scsi_taskmgmt_bh mptscsih_taskmgmt_bh +#define x_scsi_old_abort mptscsih_old_abort +#define x_scsi_old_reset mptscsih_old_reset + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * MPT SCSI Host / Initiator decls... + */ +extern int x_scsi_detect(Scsi_Host_Template *); +extern int x_scsi_release(struct Scsi_Host *host); +extern const char *x_scsi_info(struct Scsi_Host *); +/*extern int x_scsi_command(Scsi_Cmnd *);*/ +extern int x_scsi_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); +#ifdef MPT_SCSI_USE_NEW_EH +extern int x_scsi_abort(Scsi_Cmnd *); +extern int x_scsi_bus_reset(Scsi_Cmnd *); +extern int x_scsi_dev_reset(Scsi_Cmnd *); +/*extern int x_scsi_host_reset(Scsi_Cmnd *);*/ +#else +extern int x_scsi_old_abort(Scsi_Cmnd *); +extern int x_scsi_old_reset(Scsi_Cmnd *, unsigned int); +#endif +extern int x_scsi_bios_param(Disk *, kdev_t, int *); +extern void x_scsi_taskmgmt_bh(void *); + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0) +#define PROC_SCSI_DECL +#else +#define PROC_SCSI_DECL proc_name: "mptscsih", +#endif + +#ifdef MPT_SCSI_USE_NEW_EH + +#define MPT_SCSIHOST { \ + next: NULL, \ + PROC_SCSI_DECL \ + name: "MPT SCSI Host", \ + detect: x_scsi_detect, \ + release: x_scsi_release, \ + info: x_scsi_info, \ + command: NULL, \ + queuecommand: x_scsi_queuecommand, \ + eh_strategy_handler: NULL, \ + eh_abort_handler: x_scsi_abort, \ + eh_device_reset_handler: x_scsi_dev_reset, \ + eh_bus_reset_handler: x_scsi_bus_reset, \ + eh_host_reset_handler: NULL, \ + bios_param: x_scsi_bios_param, \ + can_queue: MPT_SCSI_CAN_QUEUE, \ + this_id: -1, \ + sg_tablesize: 25, \ + cmd_per_lun: MPT_SCSI_CMD_PER_LUN, \ + unchecked_isa_dma: 0, \ + use_clustering: ENABLE_CLUSTERING, \ + use_new_eh_code: 1 \ +} + +#else + +#define MPT_SCSIHOST { \ + next: NULL, \ + PROC_SCSI_DECL \ + name: "MPT SCSI Host", \ + detect: x_scsi_detect, \ + release: x_scsi_release, \ + info: x_scsi_info, \ + command: NULL, \ + queuecommand: x_scsi_queuecommand, \ + abort: x_scsi_old_abort, \ + reset: x_scsi_old_reset, \ + bios_param: x_scsi_bios_param, \ + can_queue: MPT_SCSI_CAN_QUEUE, \ + this_id: -1, \ + sg_tablesize: 25, \ + cmd_per_lun: MPT_SCSI_CMD_PER_LUN, \ + unchecked_isa_dma: 0, \ + use_clustering: ENABLE_CLUSTERING \ +} +#endif + + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + +/* include/scsi/scsi.h may not be quite complete... */ +#ifndef RESERVE_10 +#define RESERVE_10 0x56 +#endif +#ifndef RELEASE_10 +#define RELEASE_10 0x57 +#endif +#ifndef PERSISTENT_RESERVE_IN +#define PERSISTENT_RESERVE_IN 0x5e +#endif +#ifndef PERSISTENT_RESERVE_OUT +#define PERSISTENT_RESERVE_OUT 0x5f +#endif + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + +#endif + diff -u --recursive --new-file v2.4.6/linux/drivers/message/fusion/scsi3.h linux/drivers/message/fusion/scsi3.h --- v2.4.6/linux/drivers/message/fusion/scsi3.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/message/fusion/scsi3.h Fri Jul 6 17:03:11 2001 @@ -0,0 +1,700 @@ +/* + * linux/drivers/message/fusion/scsi3.h + * SCSI-3 definitions and macros. + * (Ultimately) SCSI-3 definitions; for now, inheriting + * SCSI-2 definitions. + * + * Copyright (c) 1996-2001 Steven J. Ralston + * Written By: Steven J. Ralston (19960517) + * (mailto:Steve.Ralston@lsil.com) + * + * $Id: scsi3.h,v 1.4 2001/01/06 15:54:25 sralston Exp $ + */ + +#ifndef SCSI3_H_INCLUDED +#define SCSI3_H_INCLUDED +/***************************************************************************/ + +/**************************************************************************** + * + * Includes + */ +#ifdef __KERNEL__ +#include <linux/types.h> +#else + #ifndef U_STUFF_DEFINED + #define U_STUFF_DEFINED + typedef unsigned char u8; + typedef unsigned short u16; + typedef unsigned int u32; + #endif +#endif + +/**************************************************************************** + * + * Defines + */ + +/* + * SCSI Commands + */ +#define CMD_TestUnitReady 0x00 +#define CMD_RezeroUnit 0x01 /* direct-access devices */ +#define CMD_Rewind 0x01 /* sequential-access devices */ +#define CMD_RequestSense 0x03 +#define CMD_FormatUnit 0x04 +#define CMD_ReassignBlock 0x07 +#define CMD_Read6 0x08 +#define CMD_Write6 0x0A +#define CMD_WriteFilemark 0x10 +#define CMD_Space 0x11 +#define CMD_Inquiry 0x12 +#define CMD_ModeSelect6 0x15 +#define CMD_ModeSense6 0x1A +#define CMD_Reserve6 0x16 +#define CMD_Release6 0x17 +#define CMD_Erase 0x19 +#define CMD_StartStopUnit 0x1b /* direct-access devices */ +#define CMD_LoadUnload 0x1b /* sequential-access devices */ +#define CMD_ReceiveDiagnostic 0x1C +#define CMD_SendDiagnostic 0x1D +#define CMD_ReadCapacity 0x25 +#define CMD_Read10 0x28 +#define CMD_Write10 0x2A +#define CMD_WriteVerify 0x2E +#define CMD_Verify 0x2F +#define CMD_ReadDefectData 0x37 +#define CMD_LogSelect 0x4C +#define CMD_LogSense 0x4D +#define CMD_ModeSelect10 0x55 +#define CMD_Reserve10 0x56 +#define CMD_Release10 0x57 +#define CMD_ModeSense10 0x5A +#define CMD_ReportLuns 0xA0 + +/* + * Control byte field + */ +#define CONTROL_BYTE_NACA_BIT 0x04 +#define CONTROL_BYTE_Flag_BIT 0x02 +#define CONTROL_BYTE_Link_BIT 0x01 + +/* + * SCSI Messages + */ +#define MSG_COMPLETE 0x00 +#define MSG_EXTENDED 0x01 +#define MSG_SAVE_POINTERS 0x02 +#define MSG_RESTORE_POINTERS 0x03 +#define MSG_DISCONNECT 0x04 +#define MSG_IDERROR 0x05 +#define MSG_ABORT 0x06 +#define MSG_REJECT 0x07 +#define MSG_NOP 0x08 +#define MSG_PARITY_ERROR 0x09 +#define MSG_LINKED_CMD_COMPLETE 0x0a +#define MSG_LCMD_COMPLETE_W_FLG 0x0b +#define MSG_BUS_DEVICE_RESET 0x0c +#define MSG_ABORT_TAG 0x0d +#define MSG_CLEAR_QUEUE 0x0e +#define MSG_INITIATE_RECOVERY 0x0f + +#define MSG_RELEASE_RECOVRY 0x10 +#define MSG_TERMINATE_IO 0x11 + +#define MSG_SIMPLE_QUEUE 0x20 +#define MSG_HEAD_OF_QUEUE 0x21 +#define MSG_ORDERED_QUEUE 0x22 +#define MSG_IGNORE_WIDE_RESIDUE 0x23 + +#define MSG_IDENTIFY 0x80 +#define MSG_IDENTIFY_W_DISC 0xc0 + +/* + * SCSI Phases + */ +#define PHS_DATA_OUT 0x00 +#define PHS_DATA_IN 0x01 +#define PHS_COMMAND 0x02 +#define PHS_STATUS 0x03 +#define PHS_MSG_OUT 0x06 +#define PHS_MSG_IN 0x07 + +/* + * Statuses + */ +#define STS_GOOD 0x00 +#define STS_CHECK_CONDITION 0x02 +#define STS_CONDITION_MET 0x04 +#define STS_BUSY 0x08 +#define STS_INTERMEDIATE 0x10 +#define STS_INTERMEDIATE_CONDITION_MET 0x14 +#define STS_RESERVATION_CONFLICT 0x18 +#define STS_COMMAND_TERMINATED 0x22 +#define STS_TASK_SET_FULL 0x28 +#define STS_QUEUE_FULL 0x28 +#define STS_ACA_ACTIVE 0x30 + +#define STS_VALID_MASK 0x3e + +#define SCSI_STATUS(x) ((x) & STS_VALID_MASK) + +/* + * SCSI QTag Types + */ +#define QTAG_SIMPLE 0x20 +#define QTAG_HEAD_OF_Q 0x21 +#define QTAG_ORDERED 0x22 + +/* + * SCSI Sense Key Definitons + */ +#define SK_NO_SENSE 0x00 +#define SK_RECOVERED_ERROR 0x01 +#define SK_NOT_READY 0x02 +#define SK_MEDIUM_ERROR 0x03 +#define SK_HARDWARE_ERROR 0x04 +#define SK_ILLEGAL_REQUEST 0x05 +#define SK_UNIT_ATTENTION 0x06 +#define SK_DATA_PROTECT 0x07 +#define SK_BLANK_CHECK 0x08 +#define SK_VENDOR_SPECIFIC 0x09 +#define SK_COPY_ABORTED 0x0a +#define SK_ABORTED_COMMAND 0x0b +#define SK_EQUAL 0x0c +#define SK_VOLUME_OVERFLOW 0x0d +#define SK_MISCOMPARE 0x0e +#define SK_RESERVED 0x0f + + + +#define SCSI_MAX_INQUIRY_BYTES 96 +#define SCSI_STD_INQUIRY_BYTES 36 + +#undef USE_SCSI_COMPLETE_INQDATA +/* + * Structure definition for SCSI Inquiry Data + * + * NOTE: The following structure is 96 bytes in size + * iff USE_SCSI_COMPLETE_INQDATA IS defined above (i.e. w/ "#define"). + * If USE_SCSI_COMPLETE_INQDATA is NOT defined above (i.e. w/ "#undef") + * then the following structure is only 36 bytes in size. + * THE CHOICE IS YOURS! + */ +typedef struct SCSI_Inquiry_Data +{ +#ifdef USE_SCSI_COMPLETE_INQDATA + u8 InqByte[SCSI_MAX_INQUIRY_BYTES]; +#else + u8 InqByte[SCSI_STD_INQUIRY_BYTES]; +#endif + +/* + * the following structure works only for little-endian (Intel, + * LSB first (1234) byte order) systems with 4-byte ints. + * + u32 Periph_Device_Type : 5, + Periph_Qualifier : 3, + Device_Type_Modifier : 7, + Removable_Media : 1, + ANSI_Version : 3, + ECMA_Version : 3, + ISO_Version : 2, + Response_Data_Format : 4, + reserved_0 : 3, + AERC : 1 ; + u32 Additional_Length : 8, + reserved_1 :16, + SftReset : 1, + CmdQue : 1, + reserved_2 : 1, + Linked : 1, + Sync : 1, + WBus16 : 1, + WBus32 : 1, + RelAdr : 1 ; + u8 Vendor_ID[8]; + u8 Product_ID[16]; + u8 Revision_Level [4]; +#ifdef USE_SCSI_COMPLETE_INQDATA + u8 Vendor_Specific[20]; + u8 reserved_3[40]; +#endif + * + */ + +} SCSI_Inquiry_Data_t; + +#define INQ_PERIPHINFO_BYTE 0 +#define INQ_Periph_Qualifier_MASK 0xe0 +#define INQ_Periph_Device_Type_MASK 0x1f + +#define INQ_Peripheral_Qualifier(inqp) \ + (int)((*((u8*)(inqp)+INQ_PERIPHINFO_BYTE) & INQ_Periph_Qualifier_MASK) >> 5) +#define INQ_Peripheral_Device_Type(inqp) \ + (int)(*((u8*)(inqp)+INQ_PERIPHINFO_BYTE) & INQ_Periph_Device_Type_MASK) + + +#define INQ_DEVTYPEMOD_BYTE 1 +#define INQ_RMB_BIT 0x80 +#define INQ_Device_Type_Modifier_MASK 0x7f + +#define INQ_Removable_Medium(inqp) \ + (int)(*((u8*)(inqp)+INQ_DEVTYPEMOD_BYTE) & INQ_RMB_BIT) +#define INQ_Device_Type_Modifier(inqp) \ + (int)(*((u8*)(inqp)+INQ_DEVTYPEMOD_BYTE) & INQ_Device_Type_Modifier_MASK) + + +#define INQ_VERSIONINFO_BYTE 2 +#define INQ_ISO_Version_MASK 0xc0 +#define INQ_ECMA_Version_MASK 0x38 +#define INQ_ANSI_Version_MASK 0x07 + +#define INQ_ISO_Version(inqp) \ + (int)(*((u8*)(inqp)+INQ_VERSIONINFO_BYTE) & INQ_ISO_Version_MASK) +#define INQ_ECMA_Version(inqp) \ + (int)(*((u8*)(inqp)+INQ_VERSIONINFO_BYTE) & INQ_ECMA_Version_MASK) +#define INQ_ANSI_Version(inqp) \ + (int)(*((u8*)(inqp)+INQ_VERSIONINFO_BYTE) & INQ_ANSI_Version_MASK) + + +#define INQ_BYTE3 3 +#define INQ_AERC_BIT 0x80 +#define INQ_TrmTsk_BIT 0x40 +#define INQ_NormACA_BIT 0x20 +#define INQ_RDF_MASK 0x0F + +#define INQ_AER_Capable(inqp) \ + (int)(*((u8*)(inqp)+INQ_BYTE3) & INQ_AERC_BIT) +#define INQ_TrmTsk(inqp) \ + (int)(*((u8*)(inqp)+INQ_BYTE3) & INQ_TrmTsk_BIT) +#define INQ_NormACA(inqp) \ + (int)(*((u8*)(inqp)+INQ_BYTE3) & INQ_NormACA_BIT) +#define INQ_Response_Data_Format(inqp) \ + (int)(*((u8*)(inqp)+INQ_BYTE3) & INQ_RDF_MASK) + + +#define INQ_CAPABILITY_BYTE 7 +#define INQ_RelAdr_BIT 0x80 +#define INQ_WBus32_BIT 0x40 +#define INQ_WBus16_BIT 0x20 +#define INQ_Sync_BIT 0x10 +#define INQ_Linked_BIT 0x08 + /* INQ_Reserved BIT 0x40 */ +#define INQ_CmdQue_BIT 0x02 +#define INQ_SftRe_BIT 0x01 + +#define IS_RelAdr_DEV(inqp) \ + (int)(*((u8*)(inqp)+INQ_CAPABILITY_BYTE) & INQ_RelAdr_BIT) +#define IS_WBus32_DEV(inqp) \ + (int)(*((u8*)(inqp)+INQ_CAPABILITY_BYTE) & INQ_WBus32_BIT) +#define IS_WBus16_DEV(inqp) \ + (int)(*((u8*)(inqp)+INQ_CAPABILITY_BYTE) & INQ_WBus16_BIT) +#define IS_Sync_DEV(inqp) \ + (int)(*((u8*)(inqp)+INQ_CAPABILITY_BYTE) & INQ_Sync_BIT) +#define IS_Linked_DEV(inqp) \ + (int)(*((u8*)(inqp)+INQ_CAPABILITY_BYTE) & INQ_Linked_BIT) +#define IS_CmdQue_DEV(inqp) \ + (int)(*((u8*)(inqp)+INQ_CAPABILITY_BYTE) & INQ_CmdQue_BIT) +#define IS_SftRe_DEV(inqp) \ + (int)(*((u8*)(inqp)+INQ_CAPABILITY_BYTE) & INQ_SftRe_BIT) + +#define INQ_Width_BITS \ + (INQ_WBus32_BIT | INQ_WBus16_BIT) +#define IS_Wide_DEV(inqp) \ + (int)(*((u8*)(inqp)+INQ_CAPABILITY_BYTE) & INQ_Width_BITS) + + +/* + * SCSI peripheral device types + */ +#define SCSI_TYPE_DAD 0x00 /* Direct Access Device */ +#define SCSI_TYPE_SAD 0x01 /* Sequential Access Device */ +#define SCSI_TYPE_TAPE SCSI_TYPE_SAD +#define SCSI_TYPE_PRT 0x02 /* Printer */ +#define SCSI_TYPE_PROC 0x03 /* Processor */ +#define SCSI_TYPE_WORM 0x04 +#define SCSI_TYPE_CDROM 0x05 +#define SCSI_TYPE_SCAN 0x06 /* Scanner */ +#define SCSI_TYPE_OPTICAL 0x07 /* Magneto/Optical */ +#define SCSI_TYPE_CHANGER 0x08 +#define SCSI_TYPE_COMM 0x09 /* Communications device */ +#define SCSI_TYPE_UNKNOWN 0x1f +#define SCSI_TYPE_UNCONFIGURED_LUN 0x7f + +#define SCSI_TYPE_MAX_KNOWN SCSI_TYPE_COMM + +/* + * Peripheral Qualifiers + */ +#define DEVICE_PRESENT 0x00 +#define LUN_NOT_PRESENT 0x01 +#define LUN_NOT_SUPPORTED 0x03 + +/* + * ANSI Versions + */ +#ifndef SCSI_1 +#define SCSI_1 0x01 +#endif +#ifndef SCSI_2 +#define SCSI_2 0x02 +#endif +#ifndef SCSI_3 +#define SCSI_3 0x03 +#endif + + +#define SCSI_MAX_SENSE_BYTES 255 +#define SCSI_STD_SENSE_BYTES 18 +#define SCSI_PAD_SENSE_BYTES (SCSI_MAX_SENSE_BYTES - SCSI_STD_SENSE_BYTES) + +#undef USE_SCSI_COMPLETE_SENSE +/* + * Structure definition for SCSI Sense Data + * + * NOTE: The following structure is 255 bytes in size + * iiff USE_SCSI_COMPLETE_SENSE IS defined above (i.e. w/ "#define"). + * If USE_SCSI_COMPLETE_SENSE is NOT defined above (i.e. w/ "#undef") + * then the following structure is only 19 bytes in size. + * THE CHOICE IS YOURS! + * + */ +typedef struct SCSI_Sense_Data +{ +#ifdef USE_SCSI_COMPLETE_SENSE + u8 SenseByte[SCSI_MAX_SENSE_BYTES]; +#else + u8 SenseByte[SCSI_STD_SENSE_BYTES]; +#endif + +/* + * the following structure works only for little-endian (Intel, + * LSB first (1234) byte order) systems with 4-byte ints. + * + u8 Error_Code :4, // 0x00 + Error_Class :3, + Valid :1 + ; + u8 Segment_Number // 0x01 + ; + u8 Sense_Key :4, // 0x02 + Reserved :1, + Incorrect_Length_Indicator:1, + End_Of_Media :1, + Filemark :1 + ; + u8 Information_MSB; // 0x03 + u8 Information_Byte2; // 0x04 + u8 Information_Byte1; // 0x05 + u8 Information_LSB; // 0x06 + u8 Additional_Length; // 0x07 + + u32 Command_Specific_Information; // 0x08 - 0x0b + + u8 Additional_Sense_Code; // 0x0c + u8 Additional_Sense_Code_Qualifier; // 0x0d + u8 Field_Replaceable_Unit_Code; // 0x0e + u8 Illegal_Req_Bit_Pointer :3, // 0x0f + Illegal_Req_Bit_Valid :1, + Illegal_Req_Reserved :2, + Illegal_Req_Cmd_Data :1, + Sense_Key_Specific_Valid :1 + ; + u16 Sense_Key_Specific_Data; // 0x10 - 0x11 + +#ifdef USE_SCSI_COMPLETE_SENSE + u8 Additional_Sense_Data[SCSI_PAD_SENSE_BYTES]; +#else + u8 Additional_Sense_Data[1]; +#endif + * + */ + +} SCSI_Sense_Data_t; + + +#define SD_ERRCODE_BYTE 0 +#define SD_Valid_BIT 0x80 +#define SD_Error_Code_MASK 0x7f +#define SD_Valid(sdp) \ + (int)(*((u8*)(sdp)+SD_ERRCODE_BYTE) & SD_Valid_BIT) +#define SD_Error_Code(sdp) \ + (int)(*((u8*)(sdp)+SD_ERRCODE_BYTE) & SD_Error_Code_MASK) + + +#define SD_SEGNUM_BYTE 1 +#define SD_Segment_Number(sdp) (int)(*((u8*)(sdp)+SD_SEGNUM_BYTE)) + + +#define SD_SENSEKEY_BYTE 2 +#define SD_Filemark_BIT 0x80 +#define SD_EOM_BIT 0x40 +#define SD_ILI_BIT 0x20 +#define SD_Sense_Key_MASK 0x0f +#define SD_Filemark(sdp) \ + (int)(*((u8*)(sdp)+SD_SENSEKEY_BYTE) & SD_Filemark_BIT) +#define SD_EOM(sdp) \ + (int)(*((u8*)(sdp)+SD_SENSEKEY_BYTE) & SD_EOM_BIT) +#define SD_ILI(sdp) \ + (int)(*((u8*)(sdp)+SD_SENSEKEY_BYTE) & SD_ILI_BIT) +#define SD_Sense_Key(sdp) \ + (int)(*((u8*)(sdp)+SD_SENSEKEY_BYTE) & SD_Sense_Key_MASK) + + +#define SD_INFO3_BYTE 3 +#define SD_INFO2_BYTE 4 +#define SD_INFO1_BYTE 5 +#define SD_INFO0_BYTE 6 +#define SD_Information3(sdp) (int)(*((u8*)(sdp)+SD_INFO3_BYTE)) +#define SD_Information2(sdp) (int)(*((u8*)(sdp)+SD_INFO2_BYTE)) +#define SD_Information1(sdp) (int)(*((u8*)(sdp)+SD_INFO1_BYTE)) +#define SD_Information0(sdp) (int)(*((u8*)(sdp)+SD_INFO0_BYTE)) + + +#define SD_ADDL_LEN_BYTE 7 +#define SD_Additional_Sense_Length(sdp) \ + (int)(*((u8*)(sdp)+SD_ADDL_LEN_BYTE)) +#define SD_Addl_Sense_Len SD_Additional_Sense_Length + + +#define SD_CMD_SPECIFIC3_BYTE 8 +#define SD_CMD_SPECIFIC2_BYTE 9 +#define SD_CMD_SPECIFIC1_BYTE 10 +#define SD_CMD_SPECIFIC0_BYTE 11 +#define SD_Cmd_Specific_Info3(sdp) (int)(*((u8*)(sdp)+SD_CMD_SPECIFIC3_BYTE)) +#define SD_Cmd_Specific_Info2(sdp) (int)(*((u8*)(sdp)+SD_CMD_SPECIFIC2_BYTE)) +#define SD_Cmd_Specific_Info1(sdp) (int)(*((u8*)(sdp)+SD_CMD_SPECIFIC1_BYTE)) +#define SD_Cmd_Specific_Info0(sdp) (int)(*((u8*)(sdp)+SD_CMD_SPECIFIC0_BYTE)) + + +#define SD_ADDL_SENSE_CODE_BYTE 12 +#define SD_Additional_Sense_Code(sdp) \ + (int)(*((u8*)(sdp)+SD_ADDL_SENSE_CODE_BYTE)) +#define SD_Addl_Sense_Code SD_Additional_Sense_Code +#define SD_ASC SD_Additional_Sense_Code + + +#define SD_ADDL_SENSE_CODE_QUAL_BYTE 13 +#define SD_Additional_Sense_Code_Qualifier(sdp) \ + (int)(*((u8*)(sdp)+SD_ADDL_SENSE_CODE_QUAL_BYTE)) +#define SD_Addl_Sense_Code_Qual SD_Additional_Sense_Code_Qualifier +#define SD_ASCQ SD_Additional_Sense_Code_Qualifier + + +#define SD_FIELD_REPL_UNIT_CODE_BYTE 14 +#define SD_Field_Replaceable_Unit_Code(sdp) \ + (int)(*((u8*)(sdp)+SD_FIELD_REPL_UNIT_CODE_BYTE)) +#define SD_Field_Repl_Unit_Code SD_Field_Replaceable_Unit_Code +#define SD_FRUC SD_Field_Replaceable_Unit_Code +#define SD_FRU SD_Field_Replaceable_Unit_Code + + +/* + * Sense-Key Specific offsets and macros. + */ +#define SD_SKS2_BYTE 15 +#define SD_SKS_Valid_BIT 0x80 +#define SD_SKS_Cmd_Data_BIT 0x40 +#define SD_SKS_Bit_Ptr_Valid_BIT 0x08 +#define SD_SKS_Bit_Ptr_MASK 0x07 +#define SD_SKS1_BYTE 16 +#define SD_SKS0_BYTE 17 +#define SD_Sense_Key_Specific_Valid(sdp) \ + (int)(*((u8*)(sdp)+SD_SKS2_BYTE) & SD_SKS_Valid_BIT) +#define SD_SKS_Valid SD_Sense_Key_Specific_Valid +#define SD_SKS_CDB_Error(sdp) \ + (int)(*((u8*)(sdp)+SD_SKS2_BYTE) & SD_SKS_Cmd_Data_BIT) +#define SD_Was_Illegal_Request SD_SKS_CDB_Error +#define SD_SKS_Bit_Pointer_Valid(sdp) \ + (int)(*((u8*)(sdp)+SD_SKS2_BYTE) & SD_SKS_Bit_Ptr_Valid_BIT) +#define SD_SKS_Bit_Pointer(sdp) \ + (int)(*((u8*)(sdp)+SD_SKS2_BYTE) & SD_SKS_Bit_Ptr_MASK) +#define SD_Field_Pointer(sdp) \ + (int)( ((u16)(*((u8*)(sdp)+SD_SKS1_BYTE)) << 8) \ + + *((u8*)(sdp)+SD_SKS0_BYTE) ) +#define SD_Bad_Byte SD_Field_Pointer +#define SD_Actual_Retry_Count SD_Field_Pointer +#define SD_Progress_Indication SD_Field_Pointer + +/* + * Mode Sense Write Protect Mask + */ +#define WRITE_PROTECT_MASK 0X80 + +/* + * Medium Type Codes + */ +#define OPTICAL_DEFAULT 0x00 +#define OPTICAL_READ_ONLY_MEDIUM 0x01 +#define OPTICAL_WRITE_ONCE_MEDIUM 0x02 +#define OPTICAL_READ_WRITABLE_MEDIUM 0x03 +#define OPTICAL_RO_OR_WO_MEDIUM 0x04 +#define OPTICAL_RO_OR_RW_MEDIUM 0x05 +#define OPTICAL_WO_OR_RW_MEDIUM 0x06 + + + +/* + * Structure definition for READ6, WRITE6 (6-byte CDB) + */ +typedef struct SCSI_RW6_CDB +{ + u32 OpCode :8, + LBA_HI :5, /* 5 MSBit's of the LBA */ + Lun :3, + LBA_MID :8, /* NOTE: total of 21 bits in LBA */ + LBA_LO :8 ; /* Max LBA = 0x001fffff */ + u8 BlockCount; + u8 Control; +} SCSI_RW6_t; + +#define MAX_RW6_LBA ((u32)0x001fffff) + +/* + * Structure definition for READ10, WRITE10 (10-byte CDB) + * + * NOTE: ParityCheck bit is applicable only for VERIFY and WRITE VERIFY for + * the ADP-92 DAC only. In the SCSI2 spec. this same bit is defined as a + * FUA (forced unit access) bit for READs and WRITEs. Since this driver + * does not use the FUA, this bit is defined as it is used by the ADP-92. + * Also, for READ CAPACITY, only the OpCode field is used. + */ +typedef struct SCSI_RW10_CDB +{ + u8 OpCode; + u8 Reserved1; + u32 LBA; + u8 Reserved2; + u16 BlockCount; + u8 Control; +} SCSI_RW10_t; + +#define PARITY_CHECK 0x08 /* parity check bit - byte[1], bit 3 */ + + /* + * Structure definition for data returned by READ CAPACITY cmd; + * READ CAPACITY data + */ + typedef struct READ_CAP_DATA + { + u32 MaxLBA; + u32 BlockBytes; + } SCSI_READ_CAP_DATA_t, *pSCSI_READ_CAP_DATA_t; + + +/* + * Structure definition for FORMAT UNIT CDB (6-byte CDB) + */ +typedef struct _SCSI_FORMAT_UNIT +{ + u8 OpCode; + u8 Reserved1; + u8 VendorSpecific; + u16 Interleave; + u8 Control; +} SCSI_FORMAT_UNIT_t; + +/* + * Structure definition for REQUEST SENSE (6-byte CDB) + */ +typedef struct _SCSI_REQUEST_SENSE +{ + u8 OpCode; + u8 Reserved1; + u8 Reserved2; + u8 Reserved3; + u8 AllocLength; + u8 Control; +} SCSI_REQ_SENSE_t; + +/* + * Structure definition for REPORT LUNS (12-byte CDB) + */ +typedef struct _SCSI_REPORT_LUNS +{ + u8 OpCode; + u8 Reserved1[5]; + u32 AllocationLength; + u8 Reserved2; + u8 Control; +} SCSI_REPORT_LUNS_t, *pSCSI_REPORT_LUNS_t; + + /* + * (per-level) LUN information bytes + */ +/* + * Following doesn't work on ARMCC compiler + * [apparently] because it pads every struct + * to be multiple of 4 bytes! + * So SCSI_LUN_LEVELS_t winds up being 16 + * bytes instead of 8! + * + typedef struct LUN_INFO + { + u8 AddrMethod_plus_LunOrBusNumber; + u8 LunOrTarget; + } SCSI_LUN_INFO_t, *pSCSI_LUN_INFO_t; + + typedef struct LUN_LEVELS + { + SCSI_LUN_INFO_t LUN_0; + SCSI_LUN_INFO_t LUN_1; + SCSI_LUN_INFO_t LUN_2; + SCSI_LUN_INFO_t LUN_3; + } SCSI_LUN_LEVELS_t, *pSCSI_LUN_LEVELS_t; +*/ + /* + * All 4 levels (8 bytes) of LUN information + */ + typedef struct LUN_LEVELS + { + u8 LVL1_AddrMethod_plus_LunOrBusNumber; + u8 LVL1_LunOrTarget; + u8 LVL2_AddrMethod_plus_LunOrBusNumber; + u8 LVL2_LunOrTarget; + u8 LVL3_AddrMethod_plus_LunOrBusNumber; + u8 LVL3_LunOrTarget; + u8 LVL4_AddrMethod_plus_LunOrBusNumber; + u8 LVL4_LunOrTarget; + } SCSI_LUN_LEVELS_t, *pSCSI_LUN_LEVELS_t; + + /* + * Structure definition for data returned by REPORT LUNS cmd; + * LUN reporting parameter list format + */ + typedef struct LUN_REPORT + { + u32 LunListLength; + u32 Reserved; + SCSI_LUN_LEVELS_t LunInfo[1]; + } SCSI_LUN_REPORT_t, *pSCSI_LUN_REPORT_t; + +/**************************************************************************** + * + * Externals + */ + +/**************************************************************************** + * + * Public Typedefs & Related Defines + */ + +/**************************************************************************** + * + * Macros (embedded, above) + */ + +/**************************************************************************** + * + * Public Variables + */ + +/**************************************************************************** + * + * Public Prototypes (module entry points) + */ + + +/***************************************************************************/ +#endif diff -u --recursive --new-file v2.4.6/linux/drivers/message/fusion/scsiops.c linux/drivers/message/fusion/scsiops.c --- v2.4.6/linux/drivers/message/fusion/scsiops.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/message/fusion/scsiops.c Fri Jul 6 17:03:11 2001 @@ -0,0 +1,309 @@ + +static const char *ScsiOpcodeString[256] = { + "TEST UNIT READY\0\01", /* 00h */ + "REWIND\0\002" + "\001REZERO UNIT", /* 01h */ + "\0\0", /* 02h */ + "REQUEST SENSE\0\01", /* 03h */ + "FORMAT UNIT\0\03" + "\001FORMAT MEDIUM\0" + "\002FORMAT", /* 04h */ + "READ BLOCK LIMITS\0\1", /* 05h */ + "\0\0", /* 06h */ + "REASSIGN BLOCKS\0\02" + "\010INITIALIZE ELEMENT STATUS", /* 07h */ + "READ(06)\0\04" + "\001READ\0" + "\003RECEIVE\0" + "\011GET MESSAGE(06)", /* 08h */ + "\0\0", /* 09h */ + "WRITE(06)\0\05" + "\001WRITE\0" + "\002PRINT\0" + "\003SEND(6)\0" + "\011SEND MESSAGE(06)", /* 0Ah */ + "SEEK(06)\0\02" + "\003SLEW AND PRINT", /* 0Bh */ + "\0\0", /* 0Ch */ + "\0\0", /* 0Dh */ + "\0\0", /* 0Eh */ + "READ REVERSE\0\01", /* 0Fh */ + "WRITE FILEMARKS\0\02" + "\003SYNCRONIZE BUFFER", /* 10h */ + "SPACE(6)\0\01", /* 11h */ + "INQUIRY\0\01", /* 12h */ + "VERIFY\0\01", /* 13h */ + "RECOVER BUFFERED DATA\0\01", /* 14h */ + "MODE SELECT(06)\0\01", /* 15h */ + "RESERVE(06)\0\02" + "\010RESERVE ELEMENT(06)", /* 16h */ + "RELEASE(06)\0\02" + "\010RELEASE ELEMENT(06)", /* 17h */ + "COPY\0\01", /* 18h */ + "ERASE\0\01", /* 19h */ + "MODE SENSE(06)\0\01", /* 1Ah */ + "STOP START UNIT\0\04" + "\001LOAD UNLOAD\0" + "\002STOP PRINT\0" + "\006SCAN\0\002", /* 1Bh */ + "RECEIVE DIAGNOSTIC RESULTS\0\01", /* 1Ch */ + "SEND DIAGNOSTIC\0\01", /* 1Dh */ + "PREVENT ALLOW MEDIUM REMOVAL\0\01", /* 1Eh */ + "\0\0", /* 1Fh */ + "\0\0", /* 20h */ + "\0\0", /* 21h */ + "\0\0", /* 22h */ + "READ FORMAT CAPACITIES\0\01", /* 23h */ + "SET WINDOW\0\01", /* 24h */ + "READ CAPACITY\0\03" + "\006GET WINDOW\0" + "\037FREAD CARD CAPACITY", /* 25h */ + "\0\0", /* 26h */ + "\0\0", /* 27h */ + "READ(10)\0\02" + "\011GET MESSAGE(10)", /* 28h */ + "READ GENERATION\0\01", /* 29h */ + "WRITE(10)\0\03" + "\011SEND(10)\0" + "\011SEND MESSAGE(10)", /* 2Ah */ + "SEEK(10)\0\03" + "LOCATE(10)\0" + "POSITION TO ELEMENT", /* 2Bh */ + "ERASE(10)\0\01", /* 2Ch */ + "READ UPDATED BLOCK\0\01", /* 2Dh */ + "WRITE AND VERIFY(10)\0\01", /* 2Eh */ + "VERIFY(10)\0\01", /* 2Fh */ + "SEARCH DATA HIGH(10)\0\01", /* 30h */ + "SEARCH DATA EQUAL(10)\0\02" + "OBJECT POSITION", /* 31h */ + "SEARCH DATA LOW(10)\0\01", /* 32h */ + "SET LIMITS(10)\0\01", /* 33h */ + "PRE-FETCH(10)\0\03" + "READ POSITION\0" + "GET DATA BUFFER STATUS", /* 34h */ + "SYNCHRONIZE CACHE(10)\0\01", /* 35h */ + "LOCK UNLOCK CACHE(10)\0\01", /* 36h */ + "READ DEFECT DATA(10)\0\01", /* 37h */ + "MEDIUM SCAN\0\01", /* 38h */ + "COMPARE\0\01", /* 39h */ + "COPY AND VERIFY\0\01", /* 3Ah */ + "WRITE BUFFER\0\01", /* 3Bh */ + "READ BUFFER\0\01", /* 3Ch */ + "UPDATE BLOCK\0\01", /* 3Dh */ + "READ LONG\0\01", /* 3Eh */ + "WRITE LONG\0\01", /* 3Fh */ + "CHANGE DEFINITION\0\01", /* 40h */ + "WRITE SAME(10)\0\01", /* 41h */ + "READ SUB-CHANNEL\0\01", /* 42h */ + "READ TOC/PMA/ATIP\0\01", /* 43h */ + "REPORT DENSITY SUPPORT\0\01", /* 44h */ + "READ HEADER\0\01", /* 44h */ + "PLAY AUDIO(10)\0\01", /* 45h */ + "GET CONFIGURATION\0\01", /* 46h */ + "PLAY AUDIO MSF\0\01", /* 47h */ + "PLAY AUDIO TRACK INDEX\0\01", /* 48h */ + "PLAY TRACK RELATIVE(10)\0\01", /* 49h */ + "GET EVENT STATUS NOTIFICATION\0\01", /* 4Ah */ + "PAUSE/RESUME\0\01", /* 4Bh */ + "LOG SELECT\0\01", /* 4Ch */ + "LOG SENSE\0\01", /* 4Dh */ + "STOP PLAY/SCAN\0\01", /* 4Eh */ + "\0\0", /* 4Fh */ + "XDWRITE(10)\0\01", /* 50h */ + "XPWRITE(10)\0\02" + "READ DISC INFORMATION", /* 51h */ + "XDREAD(10)\0\01" + "READ TRACK INFORMATION", /* 52h */ + "RESERVE TRACK\0\01", /* 53h */ + "SEND OPC INFORMATION\0\01", /* 54h */ + "MODE SELECT(10)\0\01", /* 55h */ + "RESERVE(10)\0\02" + "RESERVE ELEMENT(10)", /* 56h */ + "RELEASE(10)\0\02" + "RELEASE ELEMENT(10)", /* 57h */ + "REPAIR TRACK\0\01", /* 58h */ + "READ MASTER CUE\0\01", /* 59h */ + "MODE SENSE(10)\0\01", /* 5Ah */ + "CLOSE TRACK/SESSION\0\01", /* 5Bh */ + "READ BUFFER CAPACITY\0\01", /* 5Ch */ + "SEND CUE SHEET\0\01", /* 5Dh */ + "PERSISTENT RESERVE IN\0\01", /* 5Eh */ + "PERSISTENT RESERVE OUT\0\01", /* 5Fh */ + "\0\0", /* 60h */ + "\0\0", /* 61h */ + "\0\0", /* 62h */ + "\0\0", /* 63h */ + "\0\0", /* 64h */ + "\0\0", /* 65h */ + "\0\0", /* 66h */ + "\0\0", /* 67h */ + "\0\0", /* 68h */ + "\0\0", /* 69h */ + "\0\0", /* 6Ah */ + "\0\0", /* 6Bh */ + "\0\0", /* 6Ch */ + "\0\0", /* 6Dh */ + "\0\0", /* 6Eh */ + "\0\0", /* 6Fh */ + "\0\0", /* 70h */ + "\0\0", /* 71h */ + "\0\0", /* 72h */ + "\0\0", /* 73h */ + "\0\0", /* 74h */ + "\0\0", /* 75h */ + "\0\0", /* 76h */ + "\0\0", /* 77h */ + "\0\0", /* 78h */ + "\0\0", /* 79h */ + "\0\0", /* 7Ah */ + "\0\0", /* 7Bh */ + "\0\0", /* 7Ch */ + "\0\0", /* 7Eh */ + "\0\0", /* 7Eh */ + "\0\0", /* 7Fh */ + "XDWRITE EXTENDED(16)\0\01", /* 80h */ + "REBUILD(16)\0\01", /* 81h */ + "REGENERATE(16)\0\01", /* 82h */ + "EXTENDED COPY\0\01", /* 83h */ + "RECEIVE COPY RESULTS\0\01", /* 84h */ + "ACCESS CONTROL IN [proposed]\0\01", /* 86h */ + "ACCESS CONTROL OUT [proposed]\0\01", /* 87h */ + "READ(16)\0\01", /* 88h */ + "DEVICE LOCKS [proposed]\0\01", /* 89h */ + "WRITE(16)\0\01", /* 8Ah */ + "\0\0", /* 8Bh */ + "READ ATTRIBUTES [proposed]\0\01", /* 8Ch */ + "WRITE ATTRIBUTES [proposed]\0\01", /* 8Dh */ + "WRITE AND VERIFY(16)\0\01", /* 8Eh */ + "VERIFY(16)\0\01", /* 8Fh */ + "PRE-FETCH(16)\0\01", /* 90h */ + "SYNCHRONIZE CACHE(16)\0\02" + "SPACE(16) [1]", /* 91h */ + "LOCK UNLOCK CACHE(16)\0\02" + "LOCATE(16) [1]", /* 92h */ + "WRITE SAME(16)\0\01", /* 93h */ + "[usage proposed by SCSI Socket Services project]\0\01", /* 94h */ + "[usage proposed by SCSI Socket Services project]\0\01", /* 95h */ + "[usage proposed by SCSI Socket Services project]\0\01", /* 96h */ + "[usage proposed by SCSI Socket Services project]\0\01", /* 97h */ + "MARGIN CONTROL [proposed]\0\01", /* 98h */ + "\0\0", /* 99h */ + "\0\0", /* 9Ah */ + "\0\0", /* 9Bh */ + "\0\0", /* 9Ch */ + "\0\0", /* 9Dh */ + "SERVICE ACTION IN [proposed]\0\01", /* 9Eh */ + "SERVICE ACTION OUT [proposed]\0\01", /* 9Fh */ + "REPORT LUNS\0\01", /* A0h */ + "BLANK\0\01", /* A1h */ + "SEND EVENT\0\01", /* A2h */ + "MAINTENANCE (IN)\0\02" + "SEND KEY", /* A3h */ + "MAINTENANCE (OUT)\0\02" + "REPORT KEY", /* A4h */ + "MOVE MEDIUM\0\02" + "PLAY AUDIO(12)", /* A5h */ + "EXCHANGE MEDIUM\0\02" + "LOAD/UNLOAD C/DVD", /* A6h */ + "MOVE MEDIUM ATTACHED\0\02" + "SET READ AHEAD\0\01", /* A7h */ + "READ(12)\0\02" + "GET MESSAGE(12)", /* A8h */ + "PLAY TRACK RELATIVE(12)\0\01", /* A9h */ + "WRITE(12)\0\02" + "SEND MESSAGE(12)", /* AAh */ + "\0\0", /* ABh */ + "ERASE(12)\0\02" + "GET PERFORMANCE", /* ACh */ + "READ DVD STRUCTURE\0\01", /* ADh */ + "WRITE AND VERIFY(12)\0\01", /* AEh */ + "VERIFY(12)\0\01", /* AFh */ + "SEARCH DATA HIGH(12)\0\01", /* B0h */ + "SEARCH DATA EQUAL(12)\0\01", /* B1h */ + "SEARCH DATA LOW(12)\0\01", /* B2h */ + "SET LIMITS(12)\0\01", /* B3h */ + "READ ELEMENT STATUS ATTACHED\0\01", /* B4h */ + "REQUEST VOLUME ELEMENT ADDRESS\0\01", /* B5h */ + "SEND VOLUME TAG\0\02" + "SET STREAMING", /* B6h */ + "READ DEFECT DATA(12)\0\01", /* B7h */ + "READ ELEMENT STATUS\0\01", /* B8h */ + "READ CD MSF\0\01", /* B9h */ + "REDUNDANCY GROUP (IN)\0\02" + "SCAN", /* BAh */ + "REDUNDANCY GROUP (OUT)\0\02" + "SET CD-ROM SPEED", /* BBh */ + "SPARE (IN)\0\02" + "PLAY CD", /* BCh */ + "SPARE (OUT)\0\02" + "MECHANISM STATUS", /* BDh */ + "VOLUME SET (IN)\0\02" + "READ CD", /* BEh */ + "VOLUME SET (OUT)\0\0\02" + "SEND DVD STRUCTURE", /* BFh */ + "\0\0", /* C0h */ + "\0\0", /* C1h */ + "\0\0", /* C2h */ + "\0\0", /* C3h */ + "\0\0", /* C4h */ + "\0\0", /* C5h */ + "\0\0", /* C6h */ + "\0\0", /* C7h */ + "\0\0", /* C8h */ + "\0\0", /* C9h */ + "\0\0", /* CAh */ + "\0\0", /* CBh */ + "\0\0", /* CCh */ + "\0\0", /* CDh */ + "\0\0", /* CEh */ + "\0\0", /* CFh */ + "\0\0", /* D0h */ + "\0\0", /* D1h */ + "\0\0", /* D2h */ + "\0\0", /* D3h */ + "\0\0", /* D4h */ + "\0\0", /* D5h */ + "\0\0", /* D6h */ + "\0\0", /* D7h */ + "\0\0", /* D8h */ + "\0\0", /* D9h */ + "\0\0", /* DAh */ + "\0\0", /* DBh */ + "\0\0", /* DCh */ + "\0\0", /* DEh */ + "\0\0", /* DEh */ + "\0\0", /* DFh */ + "\0\0", /* E0h */ + "\0\0", /* E1h */ + "\0\0", /* E2h */ + "\0\0", /* E3h */ + "\0\0", /* E4h */ + "\0\0", /* E5h */ + "\0\0", /* E6h */ + "\0\0", /* E7h */ + "\0\0", /* E8h */ + "\0\0", /* E9h */ + "\0\0", /* EAh */ + "\0\0", /* EBh */ + "\0\0", /* ECh */ + "\0\0", /* EDh */ + "\0\0", /* EEh */ + "\0\0", /* EFh */ + "\0\0", /* F0h */ + "\0\0", /* F1h */ + "\0\0", /* F2h */ + "\0\0", /* F3h */ + "\0\0", /* F4h */ + "\0\0", /* F5h */ + "\0\0", /* F6h */ + "\0\0", /* F7h */ + "\0\0", /* F8h */ + "\0\0", /* F9h */ + "\0\0", /* FAh */ + "\0\0", /* FBh */ + "\0\0", /* FEh */ + "\0\0", /* FEh */ + "\0\0", /* FEh */ + "\0\0" /* FFh */ +}; + diff -u --recursive --new-file v2.4.6/linux/drivers/net/3c501.c linux/drivers/net/3c501.c --- v2.4.6/linux/drivers/net/3c501.c Tue Jul 3 17:08:20 2001 +++ linux/drivers/net/3c501.c Tue Jul 17 18:53:55 2001 @@ -11,9 +11,11 @@ Do not purchase this card, even as a joke. It's performance is horrible, and it breaks in many ways. - The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O - Center of Excellence in Space Data and Information Sciences - Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771 + The author may be reached as becker@scyld.com, or C/O + Scyld Computing Corporation + 410 Severn Ave., Suite 210 + Annapolis MD 21403 + Fixed (again!) the missing interrupt locking on TX/RX shifting. Alan Cox <Alan.Cox@linux.org> diff -u --recursive --new-file v2.4.6/linux/drivers/net/3c503.c linux/drivers/net/3c503.c --- v2.4.6/linux/drivers/net/3c503.c Tue Jul 3 17:08:20 2001 +++ linux/drivers/net/3c503.c Tue Jul 17 18:53:55 2001 @@ -7,9 +7,11 @@ distributed according to the terms of the GNU General Public License, incorporated herein by reference. - The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O - Center of Excellence in Space Data and Information Sciences - Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771 + The author may be reached as becker@scyld.com, or C/O + Scyld Computing Corporation + 410 Severn Ave., Suite 210 + Annapolis MD 21403 + This driver should work with the 3c503 and 3c503/16. It should be used in shared memory mode for best performance, although it may also work diff -u --recursive --new-file v2.4.6/linux/drivers/net/3c505.c linux/drivers/net/3c505.c --- v2.4.6/linux/drivers/net/3c505.c Tue Jul 3 17:08:20 2001 +++ linux/drivers/net/3c505.c Tue Jul 17 18:53:55 2001 @@ -20,6 +20,7 @@ * Juha Laiho, <jlaiho@ichaos.nullnet.fi> * Linux 3C509 driver by * Donald Becker, <becker@super.org> + * (Now at <becker@scyld.com>) * Crynwr packet driver by * Krishnan Gopalan and Gregg Stefancik, * Clemson University Engineering Computer Operations. diff -u --recursive --new-file v2.4.6/linux/drivers/net/3c507.c linux/drivers/net/3c507.c --- v2.4.6/linux/drivers/net/3c507.c Tue Jul 3 17:08:20 2001 +++ linux/drivers/net/3c507.c Tue Jul 17 18:53:55 2001 @@ -8,9 +8,11 @@ This software may be used and distributed according to the terms of the GNU General Public License, incorporated herein by reference. - The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O - Center of Excellence in Space Data and Information Sciences - Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771 + The author may be reached as becker@scyld.com, or C/O + Scyld Computing Corporation + 410 Severn Ave., Suite 210 + Annapolis MD 21403 + Thanks go to jennings@Montrouge.SMR.slb.com ( Patrick Jennings) and jrs@world.std.com (Rick Sladkey) for testing and bugfixes. diff -u --recursive --new-file v2.4.6/linux/drivers/net/3c509.c linux/drivers/net/3c509.c --- v2.4.6/linux/drivers/net/3c509.c Tue Jul 3 17:08:20 2001 +++ linux/drivers/net/3c509.c Tue Jul 17 18:53:55 2001 @@ -10,9 +10,10 @@ This driver is for the 3Com EtherLinkIII series. - The author may be reached as becker@cesdis.gsfc.nasa.gov or - C/O Center of Excellence in Space Data and Information Sciences - Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771 + The author may be reached as becker@scyld.com, or C/O + Scyld Computing Corporation + 410 Severn Ave., Suite 210 + Annapolis MD 21403 Known limitations: Because of the way 3c509 ISA detection works it's difficult to predict @@ -174,7 +175,7 @@ }; #endif /* CONFIG_MCA */ -#ifdef CONFIG_ISAPNP +#if defined(CONFIG_ISAPNP) || defined(CONFIG_ISAPNP_MODULE) static struct isapnp_device_id el3_isapnp_adapters[] __initdata = { { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('T', 'C', 'M'), ISAPNP_FUNCTION(0x5090), @@ -203,8 +204,8 @@ MODULE_DEVICE_TABLE(isapnp, el3_isapnp_adapters); static u16 el3_isapnp_phys_addr[8][3]; +#endif /* CONFIG_ISAPNP || CONFIG_ISAPNP_MODULE */ static int nopnp; -#endif /* CONFIG_ISAPNP */ int __init el3_probe(struct net_device *dev) { @@ -214,9 +215,9 @@ u16 phys_addr[3]; static int current_tag; int mca_slot = -1; -#ifdef CONFIG_ISAPNP +#if defined(CONFIG_ISAPNP) || defined(CONFIG_ISAPNP_MODULE) static int pnp_cards; -#endif /* CONFIG_ISAPNP */ +#endif /* CONFIG_ISAPNP || CONFIG_ISAPNP_MODULE */ if (dev) SET_MODULE_OWNER(dev); @@ -320,7 +321,7 @@ } #endif /* CONFIG_MCA */ -#ifdef CONFIG_ISAPNP +#if defined(CONFIG_ISAPNP) || defined(CONFIG_ISAPNP_MODULE) if (nopnp == 1) goto no_pnp; @@ -356,7 +357,7 @@ } } no_pnp: -#endif /* CONFIG_ISAPNP */ +#endif /* CONFIG_ISAPNP || CONFIG_ISAPNP_MODULE */ /* Select an open I/O location at 0x1*0 to do contention select. */ for ( ; id_port < 0x200; id_port += 0x10) { @@ -402,7 +403,7 @@ phys_addr[i] = htons(id_read_eeprom(i)); } -#ifdef CONFIG_ISAPNP +#if defined(CONFIG_ISAPNP) || defined(CONFIG_ISAPNP_MODULE) if (nopnp == 0) { /* The ISA PnP 3c509 cards respond to the ID sequence. This check is needed in order not to register them twice. */ @@ -422,7 +423,7 @@ } } } -#endif /* CONFIG_ISAPNP */ +#endif /* CONFIG_ISAPNP || CONFIG_ISAPNP_MODULE */ { unsigned int iobase = id_read_eeprom(8); diff -u --recursive --new-file v2.4.6/linux/drivers/net/3c515.c linux/drivers/net/3c515.c --- v2.4.6/linux/drivers/net/3c515.c Tue Jul 3 17:08:20 2001 +++ linux/drivers/net/3c515.c Tue Jul 17 18:53:55 2001 @@ -7,9 +7,11 @@ This driver is for the 3Com ISA EtherLink XL "Corkscrew" 3c515 ethercard. - The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O - Center of Excellence in Space Data and Information Sciences - Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771 + The author may be reached as becker@scyld.com, or C/O + Scyld Computing Corporation + 410 Severn Ave., Suite 210 + Annapolis MD 21403 + 2/2/00- Added support for kernel-level ISAPnP by Stephen Frost <sfrost@snowman.net> and Alessandro Zummo @@ -78,7 +80,7 @@ #define REQUEST_IRQ(i,h,f,n, instance) request_irq(i,h,f,n, instance) #define IRQ(irq, dev_id, pt_regs) (irq, dev_id, pt_regs) -MODULE_AUTHOR("Donald Becker <becker@cesdis.gsfc.nasa.gov>"); +MODULE_AUTHOR("Donald Becker <becker@scyld.com>"); MODULE_DESCRIPTION("3Com 3c515 Corkscrew driver"); MODULE_PARM(debug, "i"); MODULE_PARM(options, "1-" __MODULE_STRING(8) "i"); diff -u --recursive --new-file v2.4.6/linux/drivers/net/8139too.c linux/drivers/net/8139too.c --- v2.4.6/linux/drivers/net/8139too.c Tue Jul 3 17:08:20 2001 +++ linux/drivers/net/8139too.c Tue Jul 17 18:53:55 2001 @@ -137,7 +137,7 @@ */ #define DRV_NAME "8139too" -#define DRV_VERSION "0.9.18-pre4" +#define DRV_VERSION "0.9.18" #include <linux/config.h> @@ -209,7 +209,7 @@ #define RX_BUF_PAD 16 #define RX_BUF_WRAP_PAD 2048 /* spare padding to handle lack of packet wrap */ #define RX_BUF_TOT_LEN (RX_BUF_LEN + RX_BUF_PAD + RX_BUF_WRAP_PAD) -#define RX_EARLY_THRESH 2 +#define RX_EARLY_THRESH 14 /* Number of Tx descriptor registers. */ #define NUM_TX_DESC 4 @@ -294,6 +294,7 @@ * so we simply don't match on the main vendor id. */ {PCI_ANY_ID, 0x8139, 0x10ec, 0x8139, 0, 0, RTL8139 }, + {PCI_ANY_ID, 0x8139, 0x1186, 0x1300, 0, 0, DFE538TX }, {0,} }; @@ -1168,6 +1169,7 @@ }; +#ifdef CONFIG_8139TOO_8129 /* Syncronize the MII management interface by shifting 32 one bits out. */ static void mdio_sync (void *mdio_addr) { @@ -1184,15 +1186,17 @@ DPRINTK ("EXIT\n"); } - +#endif static int mdio_read (struct net_device *dev, int phy_id, int location) { struct rtl8139_private *tp = dev->priv; + int retval = 0; +#ifdef CONFIG_8139TOO_8129 void *mdio_addr = tp->mmio_addr + Config4; int mii_cmd = (0xf6 << 10) | (phy_id << 5) | location; - int retval = 0; int i; +#endif DPRINTK ("ENTER\n"); @@ -1233,9 +1237,11 @@ int value) { struct rtl8139_private *tp = dev->priv; +#ifdef CONFIG_8139TOO_8129 void *mdio_addr = tp->mmio_addr + Config4; int mii_cmd = (0x5002 << 16) | (phy_id << 23) | (location << 18) | value; int i; +#endif DPRINTK ("ENTER\n"); @@ -1732,7 +1738,6 @@ RTL_W32_F (TxAddr0 + (entry * 4), dma_addr); RTL_W32_F (TxStatus0 + (entry * sizeof (u32)), tp->tx_flag | (skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN)); - spin_unlock_irq(&tp->lock); dev->trans_start = jiffies; @@ -1740,6 +1745,7 @@ mb(); if ((tp->cur_tx - NUM_TX_DESC) == tp->dirty_tx) netif_stop_queue (dev); + spin_unlock_irq(&tp->lock); DPRINTK ("%s: Queued Tx packet at %p size %u to slot %d.\n", dev->name, skb->data, skb->len, entry); diff -u --recursive --new-file v2.4.6/linux/drivers/net/82596.c linux/drivers/net/82596.c --- v2.4.6/linux/drivers/net/82596.c Tue Jul 3 17:08:20 2001 +++ linux/drivers/net/82596.c Tue Jul 17 18:53:55 2001 @@ -35,8 +35,8 @@ according to the terms of the GNU General Public License as modified by SRC, incorporated herein by reference. - The author may be reached as becker@super.org or - C/O Supercomputing Research Ctr., 17100 Science Dr., Bowie MD 20715 + The author may be reached as becker@scyld.com, or C/O + Scyld Computing Corporation, 410 Severn Ave., Suite 210, Annapolis MD 21403 */ diff -u --recursive --new-file v2.4.6/linux/drivers/net/8390.c linux/drivers/net/8390.c --- v2.4.6/linux/drivers/net/8390.c Wed May 16 10:25:38 2001 +++ linux/drivers/net/8390.c Tue Jul 17 18:53:55 2001 @@ -8,9 +8,11 @@ This software may be used and distributed according to the terms of the GNU General Public License, incorporated herein by reference. - The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O - Center of Excellence in Space Data and Information Sciences - Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771 + The author may be reached as becker@scyld.com, or C/O + Scyld Computing Corporation + 410 Severn Ave., Suite 210 + Annapolis MD 21403 + This is the chip-specific code for many 8390-based ethernet adaptors. This is not a complete driver, it must be combined with board-specific diff -u --recursive --new-file v2.4.6/linux/drivers/net/Config.in linux/drivers/net/Config.in --- v2.4.6/linux/drivers/net/Config.in Tue Jul 3 17:08:20 2001 +++ linux/drivers/net/Config.in Tue Jul 17 18:53:55 2001 @@ -207,6 +207,7 @@ dep_tristate 'Alteon AceNIC/3Com 3C985/NetGear GA620 Gigabit support' CONFIG_ACENIC $CONFIG_PCI dep_mbool ' Omit support for old Tigon I based AceNICs' CONFIG_ACENIC_OMIT_TIGON_I $CONFIG_ACENIC +dep_tristate 'D-Link DL2000-based Gigabit Ethernet support' CONFIG_DL2K $CONFIG_PCI dep_tristate 'MyriCOM Gigabit Ethernet support' CONFIG_MYRI_SBUS $CONFIG_SBUS dep_tristate 'Packet Engines Hamachi GNIC-II support' CONFIG_HAMACHI $CONFIG_PCI dep_tristate 'Packet Engines Yellowfin Gigabit-NIC support (EXPERIMENTAL)' CONFIG_YELLOWFIN $CONFIG_PCI $CONFIG_EXPERIMENTAL diff -u --recursive --new-file v2.4.6/linux/drivers/net/Makefile linux/drivers/net/Makefile --- v2.4.6/linux/drivers/net/Makefile Tue Jul 3 17:08:20 2001 +++ linux/drivers/net/Makefile Fri Jul 6 16:48:50 2001 @@ -207,6 +207,7 @@ obj-$(CONFIG_MACMACE) += macmace.o obj-$(CONFIG_MAC89x0) += mac89x0.o obj-$(CONFIG_TUN) += tun.o +obj-$(CONFIG_DL2K) += dl2k.o ifeq ($(CONFIG_ARCH_ACORN),y) mod-subdirs += ../acorn/net diff -u --recursive --new-file v2.4.6/linux/drivers/net/Space.c linux/drivers/net/Space.c --- v2.4.6/linux/drivers/net/Space.c Wed Apr 18 11:39:21 2001 +++ linux/drivers/net/Space.c Tue Jul 17 18:53:55 2001 @@ -9,7 +9,7 @@ * * Authors: Ross Biro, <bir7@leland.Stanford.Edu> * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> - * Donald J. Becker, <becker@super.org> + * Donald J. Becker, <becker@scyld.com> * * Changelog: * Arnaldo Carvalho de Melo <acme@conectiva.com.br> - 09/1999 diff -u --recursive --new-file v2.4.6/linux/drivers/net/ac3200.c linux/drivers/net/ac3200.c --- v2.4.6/linux/drivers/net/ac3200.c Tue Jul 3 17:08:20 2001 +++ linux/drivers/net/ac3200.c Tue Jul 17 18:53:55 2001 @@ -6,8 +6,10 @@ according to the terms of the GNU General Public License as modified by SRC, incorporated herein by reference. - The author may be reached as becker@cesdis.gsfc.nasa.gov, or - C/O Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771 + The author may be reached as becker@scyld.com, or C/O + Scyld Computing Corporation + 410 Severn Ave., Suite 210 + Annapolis MD 21403 This is driver for the Ansel Communications Model 3200 EISA Ethernet LAN Adapter. The programming information is from the users manual, as related diff -u --recursive --new-file v2.4.6/linux/drivers/net/acenic.c linux/drivers/net/acenic.c --- v2.4.6/linux/drivers/net/acenic.c Tue Jul 3 17:08:20 2001 +++ linux/drivers/net/acenic.c Wed Jul 4 14:41:33 2001 @@ -2731,7 +2731,7 @@ struct ace_private *ap = dev->priv; struct ace_regs *regs = ap->regs; - if ((new_mtu < 68) || (new_mtu > ACE_JUMBO_MTU)) + if (new_mtu > ACE_JUMBO_MTU) return -EINVAL; writel(new_mtu + ETH_HLEN + 4, ®s->IfMtu); diff -u --recursive --new-file v2.4.6/linux/drivers/net/aironet4500.h linux/drivers/net/aironet4500.h --- v2.4.6/linux/drivers/net/aironet4500.h Mon Dec 11 13:00:51 2000 +++ linux/drivers/net/aironet4500.h Tue Jul 17 18:53:55 2001 @@ -47,10 +47,6 @@ #include <linux/spinlock.h> -typedef spinlock_t my_spinlock_t ; -#define my_spin_lock_init(a) spin_lock_init(a) -#define my_spin_lock_irqsave(a,b) spin_lock_irqsave(a,b) -#define my_spin_unlock_irqrestore(a,b) spin_unlock_irqrestore(a,b) #define AWC_ERROR -1 @@ -111,7 +107,7 @@ volatile int lock; volatile int status; struct semaphore sem; - my_spinlock_t spinlock; + spinlock_t spinlock; unsigned long flags; }; @@ -157,8 +153,8 @@ printk("bap lock under cli but not in int\n");\ */ -#define AWC_LOCK_COMMAND_ISSUING(a) my_spin_lock_irqsave(&a->command_issuing_spinlock,a->command_issuing_spinlock_flags); -#define AWC_UNLOCK_COMMAND_ISSUING(a) my_spin_unlock_irqrestore(&a->command_issuing_spinlock,a->command_issuing_spinlock_flags); +#define AWC_LOCK_COMMAND_ISSUING(a) spin_lock_irqsave(&a->command_issuing_spinlock,a->command_issuing_spinlock_flags); +#define AWC_UNLOCK_COMMAND_ISSUING(a) spin_unlock_irqrestore(&a->command_issuing_spinlock,a->command_issuing_spinlock_flags); #define AWC_BAP_LOCK_UNDER_CLI_REAL(cmd) \ if (!cmd.priv) {\ @@ -166,9 +162,9 @@ }\ cmd.bap = &(cmd.priv->bap1);\ if (both_bap_lock)\ - my_spin_lock_irqsave(&cmd.priv->both_bap_spinlock,cmd.priv->both_bap_spinlock_flags);\ + spin_lock_irqsave(&cmd.priv->both_bap_spinlock,cmd.priv->both_bap_spinlock_flags);\ if (cmd.bap){\ - my_spin_lock_irqsave(&(cmd.bap->spinlock),cmd.bap->flags);\ + spin_lock_irqsave(&(cmd.bap->spinlock),cmd.bap->flags);\ cmd.bap->lock++;\ if (cmd.bap->lock > 1)\ printk("Bap 1 lock high\n");\ @@ -183,8 +179,8 @@ }\ cmd.bap = &(cmd.priv->bap0);\ if (both_bap_lock)\ - my_spin_lock_irqsave(&cmd.priv->both_bap_spinlock,cmd.priv->both_bap_spinlock_flags);\ - my_spin_lock_irqsave(&(cmd.bap->spinlock),cmd.bap->flags);\ + spin_lock_irqsave(&cmd.priv->both_bap_spinlock,cmd.priv->both_bap_spinlock_flags);\ + spin_lock_irqsave(&(cmd.bap->spinlock),cmd.bap->flags);\ DOWN(&(cmd.priv->bap0.sem));\ cmd.bap->lock++;\ if (cmd.bap->lock > 1)\ @@ -195,8 +191,8 @@ #define AWC_BAP_LOCK_NOT_CLI_CLI_REAL(cmd) {\ cmd.bap = &(cmd.priv->bap0);\ if (both_bap_lock)\ - my_spin_lock_irqsave(&cmd.priv->both_bap_spinlock,cmd.priv->both_bap_spinlock_flags);\ - my_spin_lock_irqsave(&(cmd.bap->spinlock),cmd.bap->flags);\ + spin_lock_irqsave(&cmd.priv->both_bap_spinlock,cmd.priv->both_bap_spinlock_flags);\ + spin_lock_irqsave(&(cmd.bap->spinlock),cmd.bap->flags);\ cmd.bap->lock++;\ if (cmd.bap->lock > 1)\ printk("Bap 0 lock high\n");\ @@ -258,15 +254,15 @@ com.bap->lock--; \ com.lock_state &= ~AWC_BAP_SEMALOCKED;\ UP(&(com.bap->sem)); \ - my_spin_unlock_irqrestore(&(cmd.bap->spinlock),cmd.bap->flags);\ + spin_unlock_irqrestore(&(cmd.bap->spinlock),cmd.bap->flags);\ } else if (com.lock_state & AWC_BAP_LOCKED){\ com.bap->lock--; \ com.lock_state &= ~AWC_BAP_LOCKED;\ - my_spin_unlock_irqrestore(&(cmd.bap->spinlock),cmd.bap->flags);\ + spin_unlock_irqrestore(&(cmd.bap->spinlock),cmd.bap->flags);\ }\ }\ if (both_bap_lock)\ - my_spin_unlock_irqrestore(&cmd.priv->both_bap_spinlock,cmd.priv->both_bap_spinlock_flags);\ + spin_unlock_irqrestore(&cmd.priv->both_bap_spinlock,cmd.priv->both_bap_spinlock_flags);\ } #define AWC_RELEASE_COMMAND(com) {\ @@ -450,7 +446,7 @@ struct awc_fid * head; struct awc_fid * tail; int size; - my_spinlock_t spinlock; + spinlock_t spinlock; }; @@ -459,12 +455,12 @@ unsigned long flags; memset(queue,0, sizeof(struct awc_fid_queue)); - my_spin_lock_init(&queue->spinlock); - my_spin_lock_irqsave(&queue->spinlock,flags); + spin_lock_init(&queue->spinlock); + spin_lock_irqsave(&queue->spinlock,flags); queue->head = NULL; queue->tail = NULL; queue->size = 0; - my_spin_unlock_irqrestore(&queue->spinlock,flags); + spin_unlock_irqrestore(&queue->spinlock,flags); }; extern inline void @@ -473,7 +469,7 @@ unsigned long flags; - my_spin_lock_irqsave(&queue->spinlock,flags); + spin_lock_irqsave(&queue->spinlock,flags); fid->prev = queue->tail; fid->next = NULL; @@ -487,7 +483,7 @@ queue->head = fid; queue->size++; - my_spin_unlock_irqrestore(&queue->spinlock,flags); + spin_unlock_irqrestore(&queue->spinlock,flags); }; @@ -498,7 +494,7 @@ unsigned long flags; - my_spin_lock_irqsave(&queue->spinlock,flags); + spin_lock_irqsave(&queue->spinlock,flags); fid->prev = NULL; fid->next = queue->head; @@ -512,9 +508,7 @@ queue->tail = fid; queue->size++; - - my_spin_unlock_irqrestore(&queue->spinlock,flags); - + spin_unlock_irqrestore(&queue->spinlock,flags); }; @@ -551,11 +545,11 @@ awc_fid_queue_remove( struct awc_fid_queue * queue, struct awc_fid * fid){ unsigned long flags; - my_spin_lock_irqsave(&queue->spinlock,flags); + spin_lock_irqsave(&queue->spinlock,flags); awc_fid_queue_rm(queue,fid); - my_spin_unlock_irqrestore(&queue->spinlock,flags); + spin_unlock_irqrestore(&queue->spinlock,flags); }; @@ -567,14 +561,13 @@ unsigned long flags; struct awc_fid * fid; - my_spin_lock_irqsave(&queue->spinlock,flags); + spin_lock_irqsave(&queue->spinlock,flags); fid = queue->head; if (fid) awc_fid_queue_rm(queue,fid); - - my_spin_unlock_irqrestore(&queue->spinlock,flags); + spin_unlock_irqrestore(&queue->spinlock,flags); return fid; }; @@ -588,13 +581,13 @@ unsigned long flags; struct awc_fid * fid; - my_spin_lock_irqsave(&queue->spinlock,flags); + spin_lock_irqsave(&queue->spinlock,flags); fid = queue->tail; if (fid) awc_fid_queue_rm(queue,fid); - my_spin_unlock_irqrestore(&queue->spinlock,flags); + spin_unlock_irqrestore(&queue->spinlock,flags); return fid; }; @@ -1465,7 +1458,7 @@ struct awc_fid_queue tx_large_ready; struct awc_fid_queue tx_post_process; struct awc_fid_queue tx_in_transmit; - my_spinlock_t queues_lock; + spinlock_t queues_lock; struct awc_fid_queue rx_ready; struct awc_fid_queue rx_post_process; @@ -1494,13 +1487,13 @@ // Command serialize stuff //changed to spinlock struct semaphore command_semaphore; - my_spinlock_t both_bap_spinlock; // on SMP, card should theorethically live without that + spinlock_t both_bap_spinlock; // on SMP, card should theorethically live without that unsigned long both_bap_spinlock_flags; - my_spinlock_t bap_setup_spinlock; // on SMP, card should theoretically live without that + spinlock_t bap_setup_spinlock; // on SMP, card should theoretically live without that unsigned long bap_setup_spinlock_flags; - my_spinlock_t command_issuing_spinlock; + spinlock_t command_issuing_spinlock; unsigned long command_issuing_spinlock_flags; - my_spinlock_t interrupt_spinlock; + spinlock_t interrupt_spinlock; volatile int unlock_command_postponed; struct awc_command cmd; diff -u --recursive --new-file v2.4.6/linux/drivers/net/aironet4500_core.c linux/drivers/net/aironet4500_core.c --- v2.4.6/linux/drivers/net/aironet4500_core.c Tue Jul 3 17:08:20 2001 +++ linux/drivers/net/aironet4500_core.c Tue Jul 17 18:53:55 2001 @@ -394,7 +394,7 @@ DEBUG(1,"no bap or bap not locked cmd %d !!", cmd->command); if (bap_setup_spinlock) - my_spin_lock_irqsave(&cmd->priv->bap_setup_spinlock,cmd->priv->bap_setup_spinlock_flags); + spin_lock_irqsave(&cmd->priv->bap_setup_spinlock,cmd->priv->bap_setup_spinlock_flags); status = AWC_IN(cmd->bap->offset); if (status & ~0x2000 ){ @@ -526,19 +526,19 @@ ejected_unlock: if (bap_setup_spinlock) - my_spin_unlock_irqrestore(&cmd->priv->bap_setup_spinlock,cmd->priv->bap_setup_spinlock_flags); + spin_unlock_irqrestore(&cmd->priv->bap_setup_spinlock,cmd->priv->bap_setup_spinlock_flags); AWC_ENTRY_EXIT_DEBUG(" ejected_unlock_exit \n"); return -1; return_AWC_ERROR: if (bap_setup_spinlock) - my_spin_unlock_irqrestore(&cmd->priv->bap_setup_spinlock,cmd->priv->bap_setup_spinlock_flags); + spin_unlock_irqrestore(&cmd->priv->bap_setup_spinlock,cmd->priv->bap_setup_spinlock_flags); AWC_ENTRY_EXIT_DEBUG(" AWC_ERROR_exit \n"); return AWC_ERROR; return_AWC_SUCCESS: if (bap_setup_spinlock) - my_spin_unlock_irqrestore(&cmd->priv->bap_setup_spinlock,cmd->priv->bap_setup_spinlock_flags); + spin_unlock_irqrestore(&cmd->priv->bap_setup_spinlock,cmd->priv->bap_setup_spinlock_flags); AWC_ENTRY_EXIT_DEBUG(" exit \n"); return AWC_SUCCESS; } @@ -1190,7 +1190,7 @@ AWC_ENTRY_EXIT_DEBUG(" entry awc_tx_fid_lookup "); - my_spin_lock_irqsave(&(priv->queues_lock),flags); + spin_lock_irqsave(&(priv->queues_lock),flags); fid = priv->tx_in_transmit.head; @@ -1198,14 +1198,14 @@ while (fid){ if (fid->u.tx.fid == fid_handle){ awc_fid_queue_remove(&priv->tx_in_transmit, fid); - my_spin_unlock_irqrestore(&(priv->queues_lock),flags); + spin_unlock_irqrestore(&(priv->queues_lock),flags); return fid; } fid = fid->next; // printk("iT\n"); if (cnt++ > 200) { // printk("bbb in awc_fid_queue\n"); - my_spin_unlock_irqrestore(&(priv->queues_lock),flags); + spin_unlock_irqrestore(&(priv->queues_lock),flags); return 0; }; }; @@ -1215,14 +1215,14 @@ while (fid){ if (fid->u.tx.fid == fid_handle){ awc_fid_queue_remove(&priv->tx_post_process, fid); - my_spin_unlock_irqrestore(&(priv->queues_lock),flags); + spin_unlock_irqrestore(&(priv->queues_lock),flags); return fid; } fid = fid->next; // printk("pp\n"); if (cnt++ > 200) { // printk("bbb in awc_fid_queue\n"); - my_spin_unlock_irqrestore(&(priv->queues_lock),flags); + spin_unlock_irqrestore(&(priv->queues_lock),flags); return 0; }; @@ -1233,14 +1233,14 @@ while (fid){ if (fid->u.tx.fid == fid_handle){ awc_fid_queue_remove(&priv->tx_large_ready, fid); - my_spin_unlock_irqrestore(&(priv->queues_lock),flags); + spin_unlock_irqrestore(&(priv->queues_lock),flags); return fid; } fid = fid->next; // printk("lr\n"); if (cnt++ > 200) { // printk("bbb in awc_fid_queue\n"); - my_spin_unlock_irqrestore(&(priv->queues_lock),flags); + spin_unlock_irqrestore(&(priv->queues_lock),flags); return 0; }; @@ -1250,20 +1250,20 @@ while (fid){ if (fid->u.tx.fid == fid_handle){ awc_fid_queue_remove(&priv->tx_small_ready, fid); - my_spin_unlock_irqrestore(&(priv->queues_lock),flags); + spin_unlock_irqrestore(&(priv->queues_lock),flags); return fid; } fid = fid->next; // printk("sr\n"); if (cnt++ > 200) { // printk("bbb in awc_fid_queue\n"); - my_spin_unlock_irqrestore(&(priv->queues_lock),flags); + spin_unlock_irqrestore(&(priv->queues_lock),flags); return 0; }; }; - my_spin_unlock_irqrestore(&(priv->queues_lock),flags); + spin_unlock_irqrestore(&(priv->queues_lock),flags); printk(KERN_ERR "%s tx fid %x not found \n",dev->name, fid_handle); AWC_ENTRY_EXIT_DEBUG(" BAD exit \n"); @@ -2792,7 +2792,7 @@ // here we go, bad aironet memset(&priv->SSIDs,0,sizeof(priv->SSIDs)); - my_spin_lock_init(&priv->queues_lock); + spin_lock_init(&priv->queues_lock); priv->SSIDs.ridLen =0; if (!SSID) { priv->SSIDs.SSID[0].SSID[0] ='a'; @@ -2849,29 +2849,29 @@ memset(priv, 0, sizeof(struct awc_private)); - my_spin_lock_init(&priv->queues_lock); + spin_lock_init(&priv->queues_lock); priv->bap0.select = dev->base_addr + awc_Select0_register; priv->bap0.offset = dev->base_addr + awc_Offset0_register; priv->bap0.data = dev->base_addr + awc_Data0_register; priv->bap0.lock = 0; priv->bap0.status = 0; - my_spin_lock_init(&priv->bap0.spinlock); + spin_lock_init(&priv->bap0.spinlock); init_MUTEX(&priv->bap0.sem); priv->bap1.select = dev->base_addr + awc_Select1_register; priv->bap1.offset = dev->base_addr + awc_Offset1_register; priv->bap1.data = dev->base_addr + awc_Data1_register; priv->bap1.lock = 0; priv->bap1.status = 0; - my_spin_lock_init(&priv->bap1.spinlock); + spin_lock_init(&priv->bap1.spinlock); init_MUTEX(&priv->bap1.sem); priv->sleeping_bap = 1; //spinlock now init_MUTEX(&priv->command_semaphore); - my_spin_lock_init(&priv->command_issuing_spinlock); - my_spin_lock_init(&priv->both_bap_spinlock); - my_spin_lock_init(&priv->bap_setup_spinlock); - my_spin_lock_init(&priv->interrupt_spinlock); + spin_lock_init(&priv->command_issuing_spinlock); + spin_lock_init(&priv->both_bap_spinlock); + spin_lock_init(&priv->bap_setup_spinlock); + spin_lock_init(&priv->interrupt_spinlock); priv->command_semaphore_on = 0; priv->unlock_command_postponed = 0; @@ -3098,7 +3098,7 @@ void awc_interrupt(int irq, void *dev_id, struct pt_regs *regs) { - struct net_device *dev = (struct net_device *)dev_id; + struct net_device *dev = dev_id; struct awc_private *priv; unsigned long flags; @@ -3110,11 +3110,11 @@ DEBUG(2, "%s: awc_interrupt \n", dev->name); - my_spin_lock_irqsave(&priv->interrupt_spinlock, flags); + spin_lock_irqsave(&priv->interrupt_spinlock, flags); awc_interrupt_process(dev); - my_spin_unlock_irqrestore(&priv->interrupt_spinlock, flags); + spin_unlock_irqrestore(&priv->interrupt_spinlock, flags); return; } diff -u --recursive --new-file v2.4.6/linux/drivers/net/arlan.c linux/drivers/net/arlan.c --- v2.4.6/linux/drivers/net/arlan.c Tue Jul 3 17:08:20 2001 +++ linux/drivers/net/arlan.c Wed Jul 4 14:41:33 2001 @@ -1144,7 +1144,7 @@ struct arlan_conf_stru *conf = ((struct arlan_private *) dev->priv)->Conf; ARLAN_DEBUG_ENTRY("arlan_change_mtu"); - if ((new_mtu < 68) || (new_mtu > 2032)) + if (new_mtu > 2032) return -EINVAL; dev->mtu = new_mtu; if (new_mtu < 256) diff -u --recursive --new-file v2.4.6/linux/drivers/net/at1700.c linux/drivers/net/at1700.c --- v2.4.6/linux/drivers/net/at1700.c Tue Jul 3 17:08:20 2001 +++ linux/drivers/net/at1700.c Tue Jul 17 18:53:55 2001 @@ -8,9 +8,10 @@ This software may be used and distributed according to the terms of the GNU General Public License, incorporated herein by reference. - The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O - Center of Excellence in Space Data and Information Sciences - Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771 + The author may be reached as becker@scyld.com, or C/O + Scyld Computing Corporation + 410 Severn Ave., Suite 210 + Annapolis MD 21403 This is a device driver for the Allied Telesis AT1700, and Fujitsu FMV-181/182/181A/182A/183/184/183A/184A, which are diff -u --recursive --new-file v2.4.6/linux/drivers/net/au1000_eth.c linux/drivers/net/au1000_eth.c --- v2.4.6/linux/drivers/net/au1000_eth.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/au1000_eth.c Wed Jul 4 14:41:33 2001 @@ -0,0 +1,1266 @@ +/* + * + * Alchemy Semi Au1000 ethernet driver + * + * Copyright 2001 MontaVista Software Inc. + * Author: MontaVista Software, Inc. + * ppopov@mvista.com or source@mvista.com + * + * ######################################################################## + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope 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 __mips__ +#error This driver only works with MIPS architectures! +#endif + + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/string.h> +#include <linux/timer.h> +#include <linux/errno.h> +#include <linux/in.h> +#include <linux/ioport.h> +#include <linux/malloc.h> +#include <linux/interrupt.h> +#include <linux/pci.h> +#include <linux/init.h> +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/skbuff.h> +#include <linux/delay.h> +#include <asm/irq.h> +#include <asm/bitops.h> +#include <asm/io.h> + +#include <asm/au1000.h> +#include "au1000_eth.h" + +#ifdef AU1000_ETH_DEBUG +static int au1000_debug = 10; +#else +static int au1000_debug = 3; +#endif + +// prototypes +static void *dma_alloc(size_t, dma_addr_t *); +static void dma_free(void *, size_t); +static void hard_stop(struct net_device *); +static int __init au1000_probe1(struct net_device *, long, int, int); +static int au1000_init(struct net_device *); +static int au1000_open(struct net_device *); +static int au1000_close(struct net_device *); +static int au1000_tx(struct sk_buff *, struct net_device *); +static int au1000_rx(struct net_device *); +static void au1000_interrupt(int, void *, struct pt_regs *); +static void au1000_tx_timeout(struct net_device *); +static int au1000_set_config(struct net_device *dev, struct ifmap *map); +static void set_rx_mode(struct net_device *); +static struct net_device_stats *au1000_get_stats(struct net_device *); +static inline void update_tx_stats(struct net_device *, u32, u32); +static inline void update_rx_stats(struct net_device *, u32); +static void au1000_timer(unsigned long); +static void cleanup_buffers(struct net_device *); +static int au1000_ioctl(struct net_device *, struct ifreq *, int); +static int mdio_read(struct net_device *, int, int); +static void mdio_write(struct net_device *, int, int, u16); +static inline void sync(void); + +extern void ack_rise_edge_irq(unsigned int); + +static int next_dev; + +/* + * Theory of operation + * + * The Au1000 MACs use a simple rx and tx descriptor ring scheme. + * There are four receive and four transmit descriptors. These + * descriptors are not in memory; rather, they are just a set of + * hardware registers. + * + * Since the Au1000 has a coherent data cache, the receive and + * transmit buffers are allocated from the KSEG0 segment. The + * hardware registers, however, are still mapped at KSEG1 to + * make sure there's no out-of-order writes, and that all writes + * complete immediately. + */ + + +/* + * Base address and interupt of the Au1000 ethernet macs + */ +static struct { + unsigned int port; + int irq; +} au1000_iflist[NUM_INTERFACES] = { + {AU1000_ETH0_BASE, AU1000_ETH0_IRQ}, + {AU1000_ETH1_BASE, AU1000_ETH1_IRQ} +}; + + +static char version[] __devinitdata = + "au1000eth.c:0.1 ppopov@mvista.com\n"; + +// FIX! Need real Ethernet addresses +static unsigned char au1000_mac_addr[2][6] __devinitdata = { + {0x00, 0x50, 0xc2, 0x0c, 0x30, 0x00}, + {0x00, 0x50, 0xc2, 0x0c, 0x40, 0x00} +}; + +#define nibswap(x) ((((x) >> 4) & 0x0f) | (((x) << 4) & 0xf0)) +#define RUN_AT(x) (jiffies + (x)) + +// For reading/writing 32-bit words from/to DMA memory +#define cpu_to_dma32 cpu_to_be32 +#define dma32_to_cpu be32_to_cpu + +/* CPU pipeline flush */ +static inline void sync(void) +{ + asm volatile ("sync"); +} + +/* FIXME + * All of the PHY code really should be detached from the MAC + * code. + */ + +static char *phy_link[] = + {"unknown", + "10Base2", "10BaseT", + "AUI", + "100BaseT", "100BaseTX", "100BaseFX"}; + +int bcm_5201_init(struct net_device *dev, int phy_addr) +{ + s16 data; + + /* Stop auto-negotiation */ + //printk("bcm_5201_init\n"); + data = mdio_read(dev, phy_addr, MII_CONTROL); + mdio_write(dev, phy_addr, MII_CONTROL, data & ~MII_CNTL_AUTO); + + /* Set advertisement to 10/100 and Half/Full duplex + * (full capabilities) */ + data = mdio_read(dev, phy_addr, MII_ANADV); + data |= MII_NWAY_TX | MII_NWAY_TX_FDX | MII_NWAY_T_FDX | MII_NWAY_T; + mdio_write(dev, phy_addr, MII_ANADV, data); + + /* Restart auto-negotiation */ + data = mdio_read(dev, phy_addr, MII_CONTROL); + data |= MII_CNTL_RST_AUTO | MII_CNTL_AUTO; + mdio_write(dev, phy_addr, MII_CONTROL, data); + //dump_mii(dev, phy_addr); + return 0; +} + +int bcm_5201_reset(struct net_device *dev, int phy_addr) +{ + s16 mii_control, timeout; + + //printk("bcm_5201_reset\n"); + mii_control = mdio_read(dev, phy_addr, MII_CONTROL); + mdio_write(dev, phy_addr, MII_CONTROL, mii_control | MII_CNTL_RESET); + mdelay(1); + for (timeout = 100; timeout > 0; --timeout) { + mii_control = mdio_read(dev, phy_addr, MII_CONTROL); + if ((mii_control & MII_CNTL_RESET) == 0) + break; + mdelay(1); + } + if (mii_control & MII_CNTL_RESET) { + printk(KERN_ERR "%s PHY reset timeout !\n", dev->name); + return -1; + } + return 0; +} + +int +bcm_5201_status(struct net_device *dev, int phy_addr, u16 *link, u16 *speed) +{ + u16 mii_data; + struct au1000_private *aup; + + if (!dev) { + printk(KERN_ERR "bcm_5201_status error: NULL dev\n"); + return -1; + } + aup = (struct au1000_private *) dev->priv; + + mii_data = mdio_read(dev, aup->phy_addr, MII_STATUS); + if (mii_data & MII_STAT_LINK) { + *link = 1; + mii_data = mdio_read(dev, aup->phy_addr, MII_AUX_CNTRL); + if (mii_data & MII_AUX_100) { + if (mii_data & MII_AUX_FDX) { + *speed = IF_PORT_100BASEFX; + dev->if_port = IF_PORT_100BASEFX; + } + else { + *speed = IF_PORT_100BASETX; + dev->if_port = IF_PORT_100BASETX; + } + } + else { + *speed = IF_PORT_10BASET; + dev->if_port = IF_PORT_10BASET; + } + + } + else { + *link = 0; + *speed = 0; + } + return 0; +} + + +int am79c901_init(struct net_device *dev, int phy_addr) +{ + printk("am79c901_init\n"); + return 0; +} + +int am79c901_reset(struct net_device *dev, int phy_addr) +{ + printk("am79c901_reset\n"); + return 0; +} + +int +am79c901_status(struct net_device *dev, int phy_addr, u16 *link, u16 *speed) +{ + return 0; +} + +struct phy_ops bcm_5201_ops = { + bcm_5201_init, + bcm_5201_reset, + bcm_5201_status, +}; + +struct phy_ops am79c901_ops = { + am79c901_init, + am79c901_reset, + am79c901_status, +}; + +static struct mii_chip_info { + const char * name; + u16 phy_id0; + u16 phy_id1; + struct phy_ops *phy_ops; +} mii_chip_table[] = { + {"Broadcom BCM5201 10/100 BaseT PHY", 0x0040, 0x6212, &bcm_5201_ops }, + {"AMD 79C901 HomePNA PHY", 0x0000, 0x35c8, &am79c901_ops }, + {0,}, +}; + +static int mdio_read(struct net_device *dev, int phy_id, int reg) +{ + struct au1000_private *aup = (struct au1000_private *) dev->priv; + u32 timedout = 20; + u32 mii_control; + + while (aup->mac->mii_control & MAC_MII_BUSY) { + mdelay(1); + if (--timedout == 0) { + printk(KERN_ERR "%s: read_MII busy timeout!!\n", dev->name); + return -1; + } + } + + mii_control = MAC_SET_MII_SELECT_REG(reg) | + MAC_SET_MII_SELECT_PHY(phy_id) | MAC_MII_READ; + + aup->mac->mii_control = mii_control; + + timedout = 20; + while (aup->mac->mii_control & MAC_MII_BUSY) { + mdelay(1); + if (--timedout == 0) { + printk(KERN_ERR "%s: mdio_read busy timeout!!\n", dev->name); + return -1; + } + } + return (int)aup->mac->mii_data; +} + +static void mdio_write(struct net_device *dev, int phy_id, int reg, u16 value) +{ + struct au1000_private *aup = (struct au1000_private *) dev->priv; + u32 timedout = 20; + u32 mii_control; + + while (aup->mac->mii_control & MAC_MII_BUSY) { + mdelay(1); + if (--timedout == 0) { + printk(KERN_ERR "%s: mdio_write busy timeout!!\n", dev->name); + return; + } + } + + mii_control = MAC_SET_MII_SELECT_REG(reg) | + MAC_SET_MII_SELECT_PHY(phy_id) | MAC_MII_WRITE; + + aup->mac->mii_data = value; + aup->mac->mii_control = mii_control; +} + + +static void dump_mii(struct net_device *dev, int phy_id) +{ + int i, val; + + for (i = 0; i < 7; i++) { + if ((val = mdio_read(dev, phy_id, i)) >= 0) + printk("%s: MII Reg %d=%x\n", dev->name, i, val); + } + for (i = 16; i < 25; i++) { + if ((val = mdio_read(dev, phy_id, i)) >= 0) + printk("%s: MII Reg %d=%x\n", dev->name, i, val); + } +} + +static int __init mii_probe (struct net_device * dev) +{ + struct au1000_private *aup = (struct au1000_private *) dev->priv; + int phy_addr; + + aup->mii = NULL; + + /* search for total of 32 possible mii phy addresses */ + for (phy_addr = 0; phy_addr < 32; phy_addr++) { + u16 mii_status; + u16 phy_id0, phy_id1; + int i; + + mii_status = mdio_read(dev, phy_addr, MII_STATUS); + if (mii_status == 0xffff || mii_status == 0x0000) + /* the mii is not accessable, try next one */ + continue; + + phy_id0 = mdio_read(dev, phy_addr, MII_PHY_ID0); + phy_id1 = mdio_read(dev, phy_addr, MII_PHY_ID1); + + /* search our mii table for the current mii */ + for (i = 0; mii_chip_table[i].phy_id1; i++) + if (phy_id0 == mii_chip_table[i].phy_id0 && + phy_id1 == mii_chip_table[i].phy_id1) { + struct mii_phy * mii_phy; + + printk(KERN_INFO "%s: %s found at phy address %d\n", + dev->name, mii_chip_table[i].name, phy_addr); + if ((mii_phy = kmalloc(sizeof(struct mii_phy), GFP_KERNEL)) != NULL) { + mii_phy->chip_info = mii_chip_table+i; + mii_phy->phy_addr = phy_addr; + //mii_phy->status = mdio_read(dev, phy_addr, MII_STATUS); + mii_phy->next = aup->mii; + aup->phy_ops = mii_chip_table[i].phy_ops; + aup->mii = mii_phy; + } + /* the current mii is on our mii_info_table, + try next address */ + break; + } + } + + if (aup->mii == NULL) { + printk(KERN_ERR "%s: No MII transceivers found!\n", dev->name); + return -1; + } + + /* use last PHY */ + aup->phy_addr = aup->mii->phy_addr; + printk(KERN_INFO "%s: Using %s as default\n", dev->name, aup->mii->chip_info->name); + + return 0; +} + + +/* + * Buffer allocation/deallocation routines. The buffer descriptor returned + * has the virtual and dma address of a buffer suitable for + * both, receive and transmit operations. + */ +static db_dest_t *GetFreeDB(struct au1000_private *aup) +{ + db_dest_t *pDB; + pDB = aup->pDBfree; + + if (pDB) { + aup->pDBfree = pDB->pnext; + } + //printk("GetFreeDB: %x\n", pDB); + return pDB; +} + +void ReleaseDB(struct au1000_private *aup, db_dest_t *pDB) +{ + db_dest_t *pDBfree = aup->pDBfree; + if (pDBfree) + pDBfree->pnext = pDB; + aup->pDBfree = pDB; +} + + +/* + DMA memory allocation, derived from pci_alloc_consistent. + However, the Au1000 data cache is coherent (when programmed + so), therefore we return KSEG0 address, not KSEG1. +*/ +static void *dma_alloc(size_t size, dma_addr_t * dma_handle) +{ + void *ret; + int gfp = GFP_ATOMIC | GFP_DMA; + + ret = (void *) __get_free_pages(gfp, get_order(size)); + + if (ret != NULL) { + memset(ret, 0, size); + *dma_handle = virt_to_bus(ret); + ret = KSEG0ADDR(ret); + } + return ret; +} + + +static void dma_free(void *vaddr, size_t size) +{ + vaddr = KSEG0ADDR(vaddr); + free_pages((unsigned long) vaddr, get_order(size)); +} + + +static void hard_stop(struct net_device *dev) +{ + struct au1000_private *aup = (struct au1000_private *) dev->priv; + + if (au1000_debug > 4) + printk(KERN_INFO "%s: hard stop\n", dev->name); + + aup->mac->control &= ~(MAC_RX_ENABLE | MAC_TX_ENABLE); + sync(); + mdelay(10); +} + + +static void reset_mac(struct net_device *dev) +{ + u32 flags; + struct au1000_private *aup = (struct au1000_private *) dev->priv; + + if (au1000_debug > 4) + printk(KERN_INFO "%s: reset mac, aup %x\n", dev->name, (unsigned)aup); + + spin_lock_irqsave(&aup->lock, flags); + del_timer(&aup->timer); + hard_stop(dev); + *aup->enable |= MAC_DMA_RESET; + sync(); + mdelay(10); + aup->tx_full = 0; + spin_unlock_irqrestore(&aup->lock, flags); +} + +static void cleanup_buffers(struct net_device *dev) +{ + int i; + struct au1000_private *aup = (struct au1000_private *) dev->priv; + + for (i=0; i<NUM_RX_DMA; i++) { + if (aup->rx_db_inuse[i]) { + ReleaseDB(aup, aup->rx_db_inuse[i]); + aup->rx_db_inuse[i] = 0; + } + } + + for (i=0; i<NUM_TX_DMA; i++) { + if (aup->tx_db_inuse[i]) { + ReleaseDB(aup, aup->tx_db_inuse[i]); + aup->tx_db_inuse[i] = 0; + } + } +} + + +/* + * Setup the receive and transmit "rings". These pointers are the addresses + * of the rx and tx MAC DMA registers so they are fixed by the hardware -- + * these are not descriptors sitting in memory. + */ +static void +setup_hw_rings(struct au1000_private *aup, u32 rx_base, u32 tx_base) +{ + int i; + + for (i=0; i<NUM_RX_DMA; i++) { + aup->rx_dma_ring[i] = (volatile rx_dma_t *) ioremap_nocache((unsigned long) + (rx_base + sizeof(rx_dma_t)*i), sizeof(rx_dma_t)); + } + for (i=0; i<NUM_TX_DMA; i++) { + aup->tx_dma_ring[i] = (volatile tx_dma_t *)ioremap_nocache((unsigned long) + (tx_base + sizeof(tx_dma_t)*i), sizeof(tx_dma_t)); + } +} + +/* + * Probe for a AU1000 ethernet controller. + */ +int __init au1000_probe(struct net_device *dev) +{ + int base_addr = au1000_iflist[next_dev].port; + int irq = au1000_iflist[next_dev].irq; + +#ifndef CONFIG_MIPS_AU1000_ENET + return -ENODEV; +#endif + + if (au1000_debug > 4) + printk(KERN_INFO "%s: au1000_probe base_addr %x\n", + dev->name, base_addr); + + if (next_dev >= NUM_INTERFACES) { + return -ENODEV; + } + if (au1000_probe1(dev, base_addr, irq, next_dev) == 0) { + next_dev++; + return 0; + } + next_dev++; + return -ENODEV; +} + + + +static int __init +au1000_probe1(struct net_device *dev, long ioaddr, int irq, int port_num) +{ + static unsigned version_printed = 0; + struct au1000_private *aup = NULL; + int i, retval = 0; + db_dest_t *pDB, *pDBfree; + u16 link, speed; + + if ((ioaddr != AU1000_ETH0_BASE) && (ioaddr != AU1000_ETH1_BASE)) { + return -ENODEV; + } + + if (!request_region(ioaddr, MAC_IOSIZE, "Au1000 ENET")) { + return -ENODEV; + } + + if (version_printed++ == 0) printk(version); + + if (!dev) { + dev = init_etherdev(0, sizeof(struct au1000_private)); + } + if (!dev) { + printk (KERN_ERR "au1000 eth: init_etherdev failed\n"); + return -ENODEV; + } + + printk("%s: Au1000 ethernet found at 0x%lx, irq %d\n", + dev->name, ioaddr, irq); + + + /* Initialize our private structure */ + if (dev->priv == NULL) { + aup = (struct au1000_private *) kmalloc(sizeof(*aup), GFP_KERNEL); + if (aup == NULL) { + retval = -ENOMEM; + goto free_region; + } + dev->priv = aup; + } + + aup = dev->priv; + memset(aup, 0, sizeof(*aup)); + + + /* Allocate the data buffers */ + aup->vaddr = (u32)dma_alloc(MAX_BUF_SIZE * (NUM_TX_BUFFS+NUM_RX_BUFFS), &aup->dma_addr); + if (!aup->vaddr) { + retval = -ENOMEM; + goto free_region; + } + + /* aup->mac is the base address of the MAC's registers */ + aup->mac = (volatile mac_reg_t *)ioremap_nocache((unsigned long)ioaddr, sizeof(*aup->mac)); + /* Setup some variables for quick register address access */ + if (ioaddr == AU1000_ETH0_BASE) { + aup->enable = (volatile u32 *) + ioremap_nocache((unsigned long)MAC0_ENABLE, sizeof(*aup->enable)); + memcpy(dev->dev_addr, au1000_mac_addr[0], sizeof(dev->dev_addr)); + setup_hw_rings(aup, MAC0_RX_DMA_ADDR, MAC0_TX_DMA_ADDR); + } + else if (ioaddr == AU1000_ETH1_BASE) { + aup->enable = (volatile u32 *) + ioremap_nocache((unsigned long)MAC1_ENABLE, sizeof(*aup->enable)); + memcpy(dev->dev_addr, au1000_mac_addr[1], sizeof(dev->dev_addr)); + setup_hw_rings(aup, MAC1_RX_DMA_ADDR, MAC1_TX_DMA_ADDR); + } + else { /* should never happen */ + printk (KERN_ERR "au1000 eth: bad ioaddr %x\n", (unsigned)ioaddr); + retval = -ENODEV; + goto free_region; + } + + aup->phy_addr = PHY_ADDRESS; + /* bring the device out of reset, otherwise probing the mii + * will hang */ + *aup->enable = MAC_EN_RESET0 | MAC_EN_RESET1 | MAC_EN_RESET2 | + MAC_EN_CLOCK_ENABLE | MAC_EN_TOSS; + sync(); + mdelay(2); + if (mii_probe(dev) != 0) { + goto free_region; + } + aup->phy_ops->phy_status(dev, aup->phy_addr, &link, &speed); + if (!link) { + printk(KERN_INFO "%s: link down resetting...\n", dev->name); + aup->phy_ops->phy_reset(dev, aup->phy_addr); + aup->phy_ops->phy_init(dev, aup->phy_addr); + } + else { + printk(KERN_INFO "%s: link up (%s)\n", dev->name, phy_link[speed]); + } + + pDBfree = NULL; + /* setup the data buffer descriptors and attach a buffer to each one */ + pDB = aup->db; + for (i=0; i<(NUM_TX_BUFFS+NUM_RX_BUFFS); i++) { + pDB->pnext = pDBfree; + pDBfree = pDB; + pDB->vaddr = (u32 *)((unsigned)aup->vaddr + MAX_BUF_SIZE*i); + pDB->dma_addr = (dma_addr_t)virt_to_bus(pDB->vaddr); + pDB++; + } + aup->pDBfree = pDBfree; + + for (i=0; i<NUM_RX_DMA; i++) { + pDB = GetFreeDB(aup); + if (!pDB) goto free_region; + aup->rx_dma_ring[i]->buff_stat = (unsigned)pDB->dma_addr; + aup->rx_db_inuse[i] = pDB; + } + for (i=0; i<NUM_TX_DMA; i++) { + pDB = GetFreeDB(aup); + if (!pDB) goto free_region; + aup->tx_dma_ring[i]->buff_stat = (unsigned)pDB->dma_addr; + aup->tx_dma_ring[i]->len = 0; + aup->tx_db_inuse[i] = pDB; + } + + spin_lock_init(&aup->lock); + dev->base_addr = ioaddr; + dev->irq = irq; + dev->open = au1000_open; + dev->hard_start_xmit = au1000_tx; + dev->stop = au1000_close; + dev->get_stats = au1000_get_stats; + dev->set_multicast_list = &set_rx_mode; + dev->do_ioctl = &au1000_ioctl; + dev->set_config = &au1000_set_config; + dev->tx_timeout = au1000_tx_timeout; + dev->watchdog_timeo = ETH_TX_TIMEOUT; + + + /* Fill in the fields of the device structure with ethernet values. */ + ether_setup(dev); + + /* + * The boot code uses the ethernet controller, so reset it to start fresh. + * au1000_init() expects that the device is in reset state. + */ + reset_mac(dev); + + return 0; + +free_region: + release_region(ioaddr, MAC_IOSIZE); + unregister_netdev(dev); + if (aup->vaddr) + dma_free((void *)aup->vaddr, MAX_BUF_SIZE * (NUM_TX_BUFFS+NUM_RX_BUFFS)); + if (dev->priv != NULL) + kfree(dev->priv); + kfree(dev); + printk(KERN_ERR "%s: au1000_probe1 failed. Returns %d\n", + dev->name, retval); + return retval; +} + + +/* + * Initialize the interface. + * + * When the device powers up, the clocks are disabled and the + * mac is in reset state. When the interface is closed, we + * do the same -- reset the device and disable the clocks to + * conserve power. Thus, whenever au1000_init() is called, + * the device should already be in reset state. + */ +static int au1000_init(struct net_device *dev) +{ + struct au1000_private *aup = (struct au1000_private *) dev->priv; + u32 flags; + int i; + u32 value, control; + + if (au1000_debug > 4) printk("%s: au1000_init", dev->name); + + spin_lock_irqsave(&aup->lock, flags); + + /* bring the device out of reset */ + value = MAC_EN_RESET0 | MAC_EN_RESET1 | MAC_EN_RESET2 | + MAC_EN_CLOCK_ENABLE | MAC_EN_TOSS; + *aup->enable = value; + sync(); + mdelay(200); + + aup->mac->control = 0; + aup->tx_head = (aup->tx_dma_ring[0]->buff_stat & 0xC) >> 2; + aup->tx_tail = aup->tx_head; + aup->rx_head = (aup->rx_dma_ring[0]->buff_stat & 0xC) >> 2; + + aup->mac->mac_addr_high = dev->dev_addr[5]<<8 | dev->dev_addr[4]; + aup->mac->mac_addr_low = dev->dev_addr[3]<<24 | dev->dev_addr[2]<<16 | + dev->dev_addr[1]<<8 | dev->dev_addr[0]; + + for (i=0; i<NUM_RX_DMA; i++) { + aup->rx_dma_ring[i]->buff_stat |= RX_DMA_ENABLE; + } + + sync(); + control = MAC_DISABLE_RX_OWN | MAC_RX_ENABLE | MAC_TX_ENABLE; +#ifndef CONFIG_CPU_LITTLE_ENDIAN + control |= MAC_BIG_ENDIAN; +#endif + aup->mac->control = control; + + spin_unlock_irqrestore(&aup->lock, flags); + return 0; +} + +static void au1000_timer(unsigned long data) +{ + struct net_device *dev = (struct net_device *)data; + struct au1000_private *aup = (struct au1000_private *) dev->priv; + u16 mii_data, link, speed; + + if (!dev) { + /* fatal error, don't restart the timer */ + printk(KERN_ERR "au1000_timer error: NULL dev\n"); + return; + } + if (!(dev->flags & IFF_UP)) { + goto set_timer; + } + + if (aup->phy_ops->phy_status(dev, aup->phy_addr, &link, &speed) == 0) { + if (link) { + if (!(dev->flags & IFF_RUNNING)) { + netif_carrier_on(dev); + dev->flags |= IFF_RUNNING; + printk(KERN_DEBUG "%s: link up\n", dev->name); + } + } + else { + if (dev->flags & IFF_RUNNING) { + netif_carrier_off(dev); + dev->flags &= ~IFF_RUNNING; + dev->if_port = 0; + printk(KERN_DEBUG "%s: link down\n", dev->name); + } + } + } + +set_timer: + aup->timer.expires = RUN_AT((1*HZ)); + aup->timer.data = (unsigned long)dev; + aup->timer.function = &au1000_timer; /* timer handler */ + add_timer(&aup->timer); + +} + +static int au1000_open(struct net_device *dev) +{ + int retval; + struct au1000_private *aup = (struct au1000_private *) dev->priv; + + MOD_INC_USE_COUNT; + + if (au1000_debug > 4) + printk("%s: open: dev=%p\n", dev->name, dev); + + if ((retval = au1000_init(dev))) { + printk(KERN_ERR "%s: error in au1000_init\n", dev->name); + free_irq(dev->irq, dev); + MOD_DEC_USE_COUNT; + return retval; + } + netif_start_queue(dev); + + if ((retval = request_irq(dev->irq, &au1000_interrupt, 0, dev->name, dev))) { + printk(KERN_ERR "%s: unable to get IRQ %d\n", dev->name, dev->irq); + MOD_DEC_USE_COUNT; + return retval; + } + + aup->timer.expires = RUN_AT((3*HZ)); + aup->timer.data = (unsigned long)dev; + aup->timer.function = &au1000_timer; /* timer handler */ + add_timer(&aup->timer); + + if (au1000_debug > 4) + printk("%s: open: Initialization done.\n", dev->name); + + return 0; +} + +static int au1000_close(struct net_device *dev) +{ + u32 flags; + struct au1000_private *aup = (struct au1000_private *) dev->priv; + + if (au1000_debug > 4) + printk("%s: close: dev=%p\n", dev->name, dev); + + spin_lock_irqsave(&aup->lock, flags); + + /* stop the device */ + if (netif_device_present(dev)) { + netif_stop_queue(dev); + } + + /* disable the interrupt */ + free_irq(dev->irq, dev); + spin_unlock_irqrestore(&aup->lock, flags); + + reset_mac(dev); + MOD_DEC_USE_COUNT; + return 0; +} + + +static inline void update_tx_stats(struct net_device *dev, u32 status, u32 pkt_len) +{ + struct au1000_private *aup = (struct au1000_private *) dev->priv; + struct net_device_stats *ps = &aup->stats; + + ps->tx_packets++; + ps->tx_bytes += pkt_len; + + if (status & TX_FRAME_ABORTED) { + ps->tx_errors++; + ps->tx_aborted_errors++; + if (status & (TX_NO_CARRIER | TX_LOSS_CARRIER)) + ps->tx_carrier_errors++; + } +} + + +/* + * Called from the interrupt service routine to acknowledge + * the TX DONE bits. This is a must if the irq is setup as + * edge triggered. + */ +static void au1000_tx_ack(struct net_device *dev) +{ + struct au1000_private *aup = (struct au1000_private *) dev->priv; + volatile tx_dma_t *ptxd; + + ptxd = aup->tx_dma_ring[aup->tx_tail]; + + while (ptxd->buff_stat & TX_T_DONE) { + update_tx_stats(dev, ptxd->status, ptxd->len & 0x3ff); + ptxd->buff_stat &= ~TX_T_DONE; + ptxd->len = 0; + sync(); + + aup->tx_tail = (aup->tx_tail + 1) & (NUM_TX_DMA - 1); + ptxd = aup->tx_dma_ring[aup->tx_tail]; + + if (aup->tx_full) { + aup->tx_full = 0; + netif_wake_queue(dev); + } + } +} + + +/* + * Au1000 transmit routine. + */ +static int au1000_tx(struct sk_buff *skb, struct net_device *dev) +{ + struct au1000_private *aup = (struct au1000_private *) dev->priv; + //unsigned long flags; + volatile tx_dma_t *ptxd; + u32 buff_stat; + db_dest_t *pDB; + int i; + + if (au1000_debug > 4) + printk("%s: tx: aup %x len=%d, data=%p, head %d\n", + dev->name, (unsigned)aup, skb->len, skb->data, aup->tx_head); + + /* Prevent interrupts from changing the Tx ring */ + //spin_lock_irqsave(&aup->lock, flags); + + ptxd = aup->tx_dma_ring[aup->tx_head]; + buff_stat = ptxd->buff_stat; + if (buff_stat & TX_DMA_ENABLE) { + /* We've wrapped around and the transmitter is still busy */ + netif_stop_queue(dev); + aup->tx_full = 1; + //spin_unlock_irqrestore(&aup->lock, flags); + return 1; + } + else if (buff_stat & TX_T_DONE) { + update_tx_stats(dev, ptxd->status, ptxd->len & 0x3ff); + ptxd->len = 0; + } + + if (aup->tx_full) { + aup->tx_full = 0; + netif_wake_queue(dev); + } + + pDB = aup->tx_db_inuse[aup->tx_head]; + memcpy((void *)pDB->vaddr, skb->data, skb->len); + if (skb->len < MAC_MIN_PKT_SIZE) { + for (i=skb->len; i<MAC_MIN_PKT_SIZE; i++) { + ((char *)pDB->vaddr)[i] = 0; + } + ptxd->len = MAC_MIN_PKT_SIZE; + } + else + ptxd->len = skb->len; + + ptxd->buff_stat = pDB->dma_addr | TX_DMA_ENABLE; + sync(); + dev_kfree_skb(skb); + aup->tx_head = (aup->tx_head + 1) & (NUM_TX_DMA - 1); + dev->trans_start = jiffies; + //spin_unlock_irqrestore(&aup->lock, flags); + return 0; +} + + +static inline void update_rx_stats(struct net_device *dev, u32 status) +{ + struct au1000_private *aup = (struct au1000_private *) dev->priv; + struct net_device_stats *ps = &aup->stats; + + ps->rx_packets++; + if (status & RX_MCAST_FRAME) + ps->multicast++; + + if (status & RX_ERROR) { + ps->rx_errors++; + if (status & RX_MISSED_FRAME) + ps->rx_missed_errors++; + if (status & (RX_OVERLEN | RX_OVERLEN | RX_LEN_ERROR)) + ps->rx_length_errors++; + if (status & RX_CRC_ERROR) + ps->rx_crc_errors++; + if (status & RX_COLL) + ps->collisions++; + } + else + ps->rx_bytes += status & RX_FRAME_LEN_MASK; + +} + +/* + * Au1000 receive routine. + */ +static int au1000_rx(struct net_device *dev) +{ + struct au1000_private *aup = (struct au1000_private *) dev->priv; + struct sk_buff *skb; + volatile rx_dma_t *prxd; + u32 buff_stat, status; + db_dest_t *pDB; + + if (au1000_debug > 4) + printk("%s: au1000_rx head %d\n", dev->name, aup->rx_head); + + prxd = aup->rx_dma_ring[aup->rx_head]; + buff_stat = prxd->buff_stat; + while (buff_stat & RX_T_DONE) { + status = prxd->status; + pDB = aup->rx_db_inuse[aup->rx_head]; + update_rx_stats(dev, status); + if (!(status & RX_ERROR)) { + + /* good frame */ + skb = dev_alloc_skb((status & RX_FRAME_LEN_MASK) + 2); + if (skb == NULL) { + printk(KERN_ERR + "%s: Memory squeeze, dropping packet.\n", + dev->name); + aup->stats.rx_dropped++; + continue; + } + skb->dev = dev; + skb_reserve(skb, 2); /* 16 byte IP header align */ + eth_copy_and_sum(skb, (unsigned char *)pDB->vaddr, + status & RX_FRAME_LEN_MASK, 0); + skb_put(skb, status & RX_FRAME_LEN_MASK); /* Make room */ + skb->protocol = eth_type_trans(skb, dev); + netif_rx(skb); /* pass the packet to upper layers */ + } + else { + if (au1000_debug > 4) { + if (status & RX_MISSED_FRAME) + printk("rx miss\n"); + if (status & RX_WDOG_TIMER) + printk("rx wdog\n"); + if (status & RX_RUNT) + printk("rx runt\n"); + if (status & RX_OVERLEN) + printk("rx overlen\n"); + if (status & RX_COLL) + printk("rx coll\n"); + if (status & RX_MII_ERROR) + printk("rx mii error\n"); + if (status & RX_CRC_ERROR) + printk("rx crc error\n"); + if (status & RX_LEN_ERROR) + printk("rx len error\n"); + if (status & RX_U_CNTRL_FRAME) + printk("rx u control frame\n"); + if (status & RX_MISSED_FRAME) + printk("rx miss\n"); + } + } + prxd->buff_stat = (u32)(pDB->dma_addr | RX_DMA_ENABLE); + aup->rx_head = (aup->rx_head + 1) & (NUM_RX_DMA - 1); + sync(); + + /* next descriptor */ + prxd = aup->rx_dma_ring[aup->rx_head]; + buff_stat = prxd->buff_stat; + dev->last_rx = jiffies; + } + return 0; +} + + +/* + * Au1000 interrupt service routine. + */ +void au1000_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct net_device *dev = (struct net_device *) dev_id; + + if (dev == NULL) { + printk(KERN_ERR "%s: isr: null dev ptr\n", dev->name); + return; + } + au1000_rx(dev); + au1000_tx_ack(dev); +} + + +/* + * The Tx ring has been full longer than the watchdog timeout + * value. The transmitter must be hung? + */ +static void au1000_tx_timeout(struct net_device *dev) +{ + printk(KERN_ERR "%s: au1000_tx_timeout: dev=%p\n", dev->name, dev); + reset_mac(dev); + au1000_init(dev); +} + + +static unsigned const ethernet_polynomial = 0x04c11db7U; +static inline u32 ether_crc(int length, unsigned char *data) +{ + int crc = -1; + + while(--length >= 0) { + unsigned char current_octet = *data++; + int bit; + for (bit = 0; bit < 8; bit++, current_octet >>= 1) + crc = (crc << 1) ^ + ((crc < 0) ^ (current_octet & 1) ? ethernet_polynomial : 0); + } + return crc; +} + +static void set_rx_mode(struct net_device *dev) +{ + struct au1000_private *aup = (struct au1000_private *) dev->priv; + + /* fixme */ + if (au1000_debug > 4) + printk("%s: set_multicast: flags=%x\n", dev->name, dev->flags); + + if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */ + aup->mac->control |= MAC_PROMISCUOUS; + printk(KERN_INFO "%s: Promiscuous mode enabled.\n", dev->name); + } else if ((dev->flags & IFF_ALLMULTI) || + dev->mc_count > MULTICAST_FILTER_LIMIT) { + aup->mac->control |= MAC_PASS_ALL_MULTI; + aup->mac->control &= ~MAC_PROMISCUOUS; + printk(KERN_INFO "%s: Pass all multicast\n", dev->name); + } else { + int i; + struct dev_mc_list *mclist; + u32 mc_filter[2]; /* Multicast hash filter */ + + mc_filter[1] = mc_filter[0] = 0; + for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; + i++, mclist = mclist->next) { + set_bit(ether_crc(ETH_ALEN, mclist->dmi_addr)>>26, mc_filter); + } + aup->mac->multi_hash_high = mc_filter[1]; + aup->mac->multi_hash_low = mc_filter[0]; + aup->mac->control |= MAC_HASH_MODE; + } +} + + +static int au1000_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +{ + //struct au1000_private *aup = (struct au1000_private *) dev->priv; + u16 *data = (u16 *)&rq->ifr_data; + + /* fixme */ + switch(cmd) { + case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */ + data[0] = PHY_ADDRESS; + case SIOCDEVPRIVATE+1: /* Read the specified MII register. */ + //data[3] = mdio_read(ioaddr, data[0], data[1]); + return 0; + case SIOCDEVPRIVATE+2: /* Write the specified MII register */ + //mdio_write(ioaddr, data[0], data[1], data[2]); + return 0; + default: + return -EOPNOTSUPP; + } +} + + +static int au1000_set_config(struct net_device *dev, struct ifmap *map) +{ + struct au1000_private *aup = (struct au1000_private *) dev->priv; + u16 control; + + if (au1000_debug > 4) { + printk("%s: set_config called: dev->if_port %d map->port %x\n", + dev->name, dev->if_port, map->port); + } + + switch(map->port){ + case IF_PORT_UNKNOWN: /* use auto here */ + printk("auto\\n"); + dev->if_port = map->port; + /* Link Down: the timer will bring it up */ + netif_carrier_off(dev); + + /* read current control */ + control = mdio_read(dev, aup->phy_addr, MII_CONTROL); + control &= ~(MII_CNTL_FDX | MII_CNTL_F100); + + /* enable auto negotiation and reset the negotiation */ + mdio_write(dev, aup->phy_addr, + MII_CONTROL, control | MII_CNTL_AUTO | MII_CNTL_RST_AUTO); + + break; + + case IF_PORT_10BASET: /* 10BaseT */ + printk("10baseT\n"); + dev->if_port = map->port; + + /* Link Down: the timer will bring it up */ + netif_carrier_off(dev); + + /* set Speed to 10Mbps, Half Duplex */ + control = mdio_read(dev, aup->phy_addr, MII_CONTROL); + printk("read control %x\n", control); + control &= ~(MII_CNTL_F100 | MII_CNTL_AUTO | MII_CNTL_FDX); + + /* disable auto negotiation and force 10M/HD mode*/ + mdio_write(dev, aup->phy_addr, MII_CONTROL, control); + break; + + case IF_PORT_100BASET: /* 100BaseT */ + case IF_PORT_100BASETX: /* 100BaseTx */ + printk("100 base T/TX\n"); + dev->if_port = map->port; + + /* Link Down: the timer will bring it up */ + netif_carrier_off(dev); + + /* set Speed to 100Mbps, Half Duplex */ + /* disable auto negotiation and enable 100MBit Mode */ + control = mdio_read(dev, aup->phy_addr, MII_CONTROL); + printk("read control %x\n", control); + control &= ~(MII_CNTL_AUTO | MII_CNTL_FDX); + control |= MII_CNTL_F100; + mdio_write(dev, aup->phy_addr, MII_CONTROL, control); + break; + + case IF_PORT_100BASEFX: /* 100BaseFx */ + printk("100 Base FX\n"); + dev->if_port = map->port; + + /* Link Down: the timer will bring it up */ + netif_carrier_off(dev); + + /* set Speed to 100Mbps, Full Duplex */ + /* disable auto negotiation and enable 100MBit Mode */ + control = mdio_read(dev, aup->phy_addr, MII_CONTROL); + control &= ~MII_CNTL_AUTO; + control |= MII_CNTL_F100 | MII_CNTL_FDX; + mdio_write(dev, aup->phy_addr, MII_CONTROL, control); + break; + case IF_PORT_10BASE2: /* 10Base2 */ + case IF_PORT_AUI: /* AUI */ + /* These Modes are not supported (are they?)*/ + printk(KERN_INFO "Not supported"); + return -EOPNOTSUPP; + break; + + default: + printk("Invalid"); + return -EINVAL; + } + return 0; +} + +static struct net_device_stats *au1000_get_stats(struct net_device *dev) +{ + struct au1000_private *aup = (struct au1000_private *) dev->priv; + + if (au1000_debug > 4) + printk("%s: au1000_get_stats: dev=%p\n", dev->name, dev); + + if (netif_device_present(dev)) { + return &aup->stats; + } + return 0; +} diff -u --recursive --new-file v2.4.6/linux/drivers/net/au1000_eth.h linux/drivers/net/au1000_eth.h --- v2.4.6/linux/drivers/net/au1000_eth.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/au1000_eth.h Wed Jul 4 14:41:33 2001 @@ -0,0 +1,223 @@ +/* + * + * Alchemy Semi Au1000 ethernet driver include file + * + * Author: Pete Popov <ppopov@mvista.com> + * + * Copyright 2001 MontaVista Software Inc. + * + * ######################################################################## + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope 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. + * + * ######################################################################## + * + * + */ + + +#define NUM_INTERFACES 2 +#define MAC_IOSIZE 0x10000 +#define NUM_RX_DMA 4 /* Au1000 has 4 rx hardware descriptors */ +#define NUM_TX_DMA 4 /* Au1000 has 4 tx hardware descriptors */ + +#define NUM_RX_BUFFS 4 +#define NUM_TX_BUFFS 4 +#define MAX_BUF_SIZE 2048 + +#define ETH_TX_TIMEOUT HZ/4 +#define MAC_MIN_PKT_SIZE 64 + +#ifdef CONFIG_MIPS_PB1000 +#define PHY_ADDRESS 0 +#define PHY_CONTROL_DEFAULT 0x3000 +#define PHY_CONTROL_REG_ADDR 0 +#endif + +#define MULTICAST_FILTER_LIMIT 64 + +/* FIXME + * The PHY defines should be in a separate file. + */ + +/* MII register offsets */ +#define MII_CONTROL 0x0000 +#define MII_STATUS 0x0001 +#define MII_PHY_ID0 0x0002 +#define MII_PHY_ID1 0x0003 +#define MII_ANADV 0x0004 +#define MII_ANLPAR 0x0005 +#define MII_AEXP 0x0006 +#define MII_ANEXT 0x0007 +#define MII_AUX_CNTRL 0x18 + +/* mii registers specific to AMD 79C901 */ +#define MII_STATUS_SUMMARY = 0x0018 + +/* MII Control register bit definitions. */ +#define MII_CNTL_FDX 0x0100 +#define MII_CNTL_RST_AUTO 0x0200 +#define MII_CNTL_ISOLATE 0x0400 +#define MII_CNTL_PWRDWN 0x0800 +#define MII_CNTL_AUTO 0x1000 +#define MII_CNTL_F100 0x2000 +#define MII_CNTL_LPBK 0x4000 +#define MII_CNTL_RESET 0x8000 + +/* MII Status register bit */ +#define MII_STAT_EXT 0x0001 +#define MII_STAT_JAB 0x0002 +#define MII_STAT_LINK 0x0004 +#define MII_STAT_CAN_AUTO 0x0008 +#define MII_STAT_FAULT 0x0010 +#define MII_STAT_AUTO_DONE 0x0020 +#define MII_STAT_CAN_T 0x0800 +#define MII_STAT_CAN_T_FDX 0x1000 +#define MII_STAT_CAN_TX 0x2000 +#define MII_STAT_CAN_TX_FDX 0x4000 +#define MII_STAT_CAN_T4 0x8000 + + +#define MII_ID1_OUI_LO 0xFC00 /* low bits of OUI mask */ +#define MII_ID1_MODEL 0x03F0 /* model number */ +#define MII_ID1_REV 0x000F /* model number */ + +/* MII NWAY Register Bits ... + valid for the ANAR (Auto-Negotiation Advertisement) and + ANLPAR (Auto-Negotiation Link Partner) registers */ +#define MII_NWAY_NODE_SEL 0x001f +#define MII_NWAY_CSMA_CD 0x0001 +#define MII_NWAY_T 0x0020 +#define MII_NWAY_T_FDX 0x0040 +#define MII_NWAY_TX 0x0080 +#define MII_NWAY_TX_FDX 0x0100 +#define MII_NWAY_T4 0x0200 +#define MII_NWAY_PAUSE 0x0400 +#define MII_NWAY_RF 0x2000 /* Remote Fault */ +#define MII_NWAY_ACK 0x4000 /* Remote Acknowledge */ +#define MII_NWAY_NP 0x8000 /* Next Page (Enable) */ + +/* mii stsout register bits */ +#define MII_STSOUT_LINK_FAIL 0x4000 +#define MII_STSOUT_SPD 0x0080 +#define MII_STSOUT_DPLX 0x0040 + +/* mii stsics register bits */ +#define MII_STSICS_SPD 0x8000 +#define MII_STSICS_DPLX 0x4000 +#define MII_STSICS_LINKSTS 0x0001 + +/* mii stssum register bits */ +#define MII_STSSUM_LINK 0x0008 +#define MII_STSSUM_DPLX 0x0004 +#define MII_STSSUM_AUTO 0x0002 +#define MII_STSSUM_SPD 0x0001 + +/* Auxilliary Control/Status Register */ +#define MII_AUX_FDX 0x0001 +#define MII_AUX_100 0x0002 +#define MII_AUX_F100 0x0004 +#define MII_AUX_ANEG 0x0008 + +typedef struct mii_phy { + struct mii_phy * next; + struct mii_chip_info * chip_info; + int phy_addr; + u16 status; +} mii_phy_t; + +struct phy_ops { + int (*phy_init) (struct net_device *, int); + int (*phy_reset) (struct net_device *, int); + int (*phy_status) (struct net_device *, int, u16 *, u16 *); +}; + +/* + * Data Buffer Descriptor. Data buffers must be aligned on 32 byte + * boundary for both, receive and transmit. + */ +typedef struct db_dest { + struct db_dest *pnext; + volatile u32 *vaddr; + dma_addr_t dma_addr; +} db_dest_t; + +/* + * The transmit and receive descriptors are memory + * mapped registers. + */ +typedef struct tx_dma { + u32 status; + u32 buff_stat; + u32 len; + u32 pad; +} tx_dma_t; + +typedef struct rx_dma { + u32 status; + u32 buff_stat; + u32 pad[2]; +} rx_dma_t; + + +/* + * MAC control registers, memory mapped. + */ +typedef struct mac_reg { + u32 control; + u32 mac_addr_high; + u32 mac_addr_low; + u32 multi_hash_high; + u32 multi_hash_low; + u32 mii_control; + u32 mii_data; + u32 flow_control; + u32 vlan1_tag; + u32 vlan2_tag; +} mac_reg_t; + + +struct au1000_private { + + db_dest_t *pDBfree; + db_dest_t db[NUM_RX_BUFFS+NUM_TX_BUFFS]; + volatile rx_dma_t *rx_dma_ring[NUM_RX_DMA]; + volatile tx_dma_t *tx_dma_ring[NUM_TX_DMA]; + db_dest_t *rx_db_inuse[NUM_RX_DMA]; + db_dest_t *tx_db_inuse[NUM_TX_DMA]; + u32 rx_head; + u32 tx_head; + u32 tx_tail; + u32 tx_full; + + mii_phy_t *mii; + struct phy_ops *phy_ops; + + /* These variables are just for quick access to certain regs addresses. */ + volatile mac_reg_t *mac; /* mac registers */ + volatile u32 *enable; /* address of MAC Enable Register */ + + u32 vaddr; /* virtual address of rx/tx buffers */ + dma_addr_t dma_addr; /* dma address of rx/tx buffers */ + + u8 *hash_table; + u32 hash_mode; + u32 intr_work_done; /* number of Rx and Tx pkts processed in the isr */ + u32 phy_addr; /* PHY address */ + u32 options; /* User-settable misc. driver options. */ + u32 drv_flags; + struct net_device_stats stats; + struct timer_list timer; + spinlock_t lock; /* Serialise access to device */ +}; diff -u --recursive --new-file v2.4.6/linux/drivers/net/auto_irq.c linux/drivers/net/auto_irq.c --- v2.4.6/linux/drivers/net/auto_irq.c Sun Sep 17 09:45:05 2000 +++ linux/drivers/net/auto_irq.c Tue Jul 17 18:53:55 2001 @@ -2,9 +2,7 @@ /* Written 1994 by Donald Becker. - The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O - Center of Excellence in Space Data and Information Sciences - Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771 + The author may be reached as becker@scyld.com This code is a general-purpose IRQ line detector for devices with jumpered IRQ lines. If you can make the device raise an IRQ (and @@ -29,7 +27,7 @@ #ifdef version static const char *version= -"auto_irq.c:v1.11 Donald Becker (becker@cesdis.gsfc.nasa.gov)"; +"auto_irq.c:v1.11 Donald Becker (becker@scyld.com)"; #endif #include <linux/module.h> diff -u --recursive --new-file v2.4.6/linux/drivers/net/bsd_comp.c linux/drivers/net/bsd_comp.c --- v2.4.6/linux/drivers/net/bsd_comp.c Tue Feb 13 13:15:04 2001 +++ linux/drivers/net/bsd_comp.c Sun Jul 15 16:22:23 2001 @@ -185,7 +185,7 @@ static int bsd_decompress (void *state, unsigned char *ibuf, int isize, unsigned char *obuf, int osize); -/* These are in ppp.c */ +/* These are in ppp_generic.c */ extern int ppp_register_compressor (struct compressor *cp); extern void ppp_unregister_compressor (struct compressor *cp); @@ -1158,7 +1158,7 @@ * Module support routines *************************************************************/ -int bsdcomp_init(void) +int __init bsdcomp_init(void) { int answer = ppp_register_compressor(&ppp_bsd_compress); if (answer == 0) @@ -1166,7 +1166,7 @@ return answer; } -void bsdcomp_cleanup(void) +void __exit bsdcomp_cleanup(void) { ppp_unregister_compressor(&ppp_bsd_compress); } diff -u --recursive --new-file v2.4.6/linux/drivers/net/de600.c linux/drivers/net/de600.c --- v2.4.6/linux/drivers/net/de600.c Tue Jul 3 17:08:20 2001 +++ linux/drivers/net/de600.c Tue Jul 17 18:53:55 2001 @@ -16,7 +16,7 @@ * * Adapted to the sample network driver core for linux, * written by: Donald Becker <becker@super.org> - * C/O Supercomputing Research Ctr., 17100 Science Dr., Bowie MD 20715 + * (Now at <becker@scyld.com>) * * compile-command: * "gcc -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer \ diff -u --recursive --new-file v2.4.6/linux/drivers/net/de620.c linux/drivers/net/de620.c --- v2.4.6/linux/drivers/net/de620.c Tue Jul 3 17:08:20 2001 +++ linux/drivers/net/de620.c Tue Jul 17 18:53:55 2001 @@ -13,7 +13,7 @@ * * Adapted to the sample network driver core for linux, * written by: Donald Becker <becker@super.org> - * (Now at <becker@cesdis.gsfc.nasa.gov> + * (Now at <becker@scyld.com>) * * Valuable assistance from: * J. Joshua Kopper <kopper@rtsg.mot.com> diff -u --recursive --new-file v2.4.6/linux/drivers/net/dl2k.c linux/drivers/net/dl2k.c --- v2.4.6/linux/drivers/net/dl2k.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/dl2k.c Tue Jul 17 18:53:55 2001 @@ -0,0 +1,1512 @@ +/* D-Link DL2000-based Gigabit Ethernet Adapter Linux driver */ +/* + Copyright (c) 2001 by D-Link Corporation + Written by Edward Peng.<edward_peng@dlink.com.tw> + Created 03-May-2001, base on Linux' sundance.c. + + 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. +*/ +/* + Rev Date Description + ========================================================================== + 0.01 2001/05/03 Create DL2000-based linux driver + 0.02 2001/05/21 Add VLAN and hardware checksum support. + 1.00 2001/06/26 Add jumbo frame support. +*/ + +#include "dl2k.h" + + +static char version[] __devinitdata = +KERN_INFO "D-Link DL2000-based linux driver v1.00 2001/06/26\n"; + + + +#define MAX_UNITS 8 +static int mtu[MAX_UNITS]; +static int vlan[MAX_UNITS]; +static int jumbo[MAX_UNITS]; +static char *media[MAX_UNITS]; +static int copy_thresh; + +MODULE_AUTHOR ("Edward Peng"); +MODULE_DESCRIPTION ("D-Link DL2000-based Gigabit Ethernet Adapter"); +MODULE_PARM (mtu, "1-" __MODULE_STRING (MAX_UNITS) "i"); +MODULE_PARM (media, "1-" __MODULE_STRING (MAX_UNITS) "s"); +MODULE_PARM (vlan, "1-" __MODULE_STRING (MAX_UNITS) "i"); +MODULE_PARM (jumbo, "1-" __MODULE_STRING (MAX_UNITS) "i"); +MODULE_PARM (copy_thresh, "i"); + +/* Enable the default interrupts */ +#define EnableInt() \ +writew(RxComplete| RxDMAComplete | HostError | IntRequested | TxComplete| \ + TxDMAComplete| UpdateStats | LinkEvent, ioaddr + IntEnable) +static int max_intrloop = 25; +static int multicast_filter_limit = 0x40; + +static int rio_open (struct net_device *dev); +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); +static void rio_interrupt (int irq, void *dev_instance, struct pt_regs *regs); +static void tx_error (struct net_device *dev, int tx_status); +static int receive_packet (struct net_device *dev); +static void rio_error (struct net_device *dev, int int_status); +static int change_mtu (struct net_device *dev, int new_mtu); +static void set_multicast (struct net_device *dev); +static struct net_device_stats *get_stats (struct net_device *dev); +static int rio_ioctl (struct net_device *dev, struct ifreq *rq, int cmd); +static int rio_close (struct net_device *dev); +static int find_miiphy (struct net_device *dev); +static int parse_eeprom (struct net_device *dev); +static int read_eeprom (long ioaddr, int eep_addr); +static unsigned get_crc (unsigned char *p, int len); +static int mii_wait_link (struct net_device *dev, int wait); +static int mii_set_media (struct net_device *dev); +static int mii_get_media (struct net_device *dev); +static int mii_read (struct net_device *dev, int phy_addr, int reg_num); +static int mii_write (struct net_device *dev, int phy_addr, int reg_num, + u16 data); +#ifdef RIO_DEBUG +static int rio_ioctl_ext (struct net_device *dev, struct ioctl_data *iodata); +#endif + +static int __devinit +rio_probe1 (struct pci_dev *pdev, const struct pci_device_id *ent) +{ + struct net_device *dev; + struct netdev_private *np; + static int card_idx; + int chip_idx = ent->driver_data; + int err, irq = pdev->irq; + long ioaddr; + static int version_printed; + void *ring_space; + dma_addr_t ring_dma; + + if (!version_printed++) + printk ("%s", version); + + err = pci_enable_device (pdev); + if (err) + return err; + + err = pci_request_regions (pdev, "dl2k"); + if (err) + goto err_out_disable; + + pci_set_master (pdev); + + dev = alloc_etherdev (sizeof (*np)); + if (!dev) { + err = -ENOMEM; + goto err_out_res; + } + SET_MODULE_OWNER (dev); + +#ifdef USE_IO_OPS + ioaddr = pci_resource_start (pdev, 0); +#else + ioaddr = pci_resource_start (pdev, 1); + ioaddr = (long) ioremap (ioaddr, RIO_IO_SIZE); + if (!ioaddr) { + err = -ENOMEM; + goto err_out_dev; + } +#endif + dev->base_addr = ioaddr; + dev->irq = irq; + np = dev->priv; + np->chip_id = chip_idx; + np->pdev = pdev; + spin_lock_init (&np->lock); + + /* Parse manual configuration */ + np->an_enable = 1; + if (card_idx < MAX_UNITS) { + if (media[card_idx] != NULL) { + np->an_enable = 0; + if (strcmp (media[card_idx], "100mbps_fd") == 0 || + strcmp (media[card_idx], "4") == 0) { + np->speed = 100; + np->full_duplex = 1; + } else if (strcmp (media[card_idx], "100mbps_hd") == 0 + || strcmp (media[card_idx], "3") == 0) { + np->speed = 100; + np->full_duplex = 0; + } else if (strcmp (media[card_idx], "10mbps_fd") == 0 || + strcmp (media[card_idx], "2") == 0) { + np->speed = 10; + np->full_duplex = 1; + } else if (strcmp (media[card_idx], "10mbps_hd") == 0 || + strcmp (media[card_idx], "1") == 0) { + np->speed = 10; + np->full_duplex = 0; + } + /* Auto-Negotiation is mandatory for 1000BASE-T, + IEEE 802.3ab Annex 28D page 14 */ + else if (strcmp (media[card_idx], "1000mbps_fd") == 0 || + strcmp (media[card_idx], "5") == 0 || + strcmp (media[card_idx], "1000mbps_hd") == 0 || + strcmp (media[card_idx], "6") == 0) { + np->speed = 1000; + np->full_duplex = 1; + np->an_enable = 1; + } else { + np->an_enable = 1; + } + } + if (jumbo[card_idx] != 0) { + np->jumbo = 1; + dev->mtu = 9000; + } else { + np->jumbo = 0; + if (mtu[card_idx] > 0 && mtu[card_idx] < PACKET_SIZE) + dev->mtu = mtu[card_idx]; + } + np->vlan = (vlan[card_idx] > 0 && vlan[card_idx] < 4096) ? + vlan[card_idx] : 0; + } + dev->open = &rio_open; + dev->hard_start_xmit = &start_xmit; + dev->stop = &rio_close; + dev->get_stats = &get_stats; + dev->set_multicast_list = &set_multicast; + dev->do_ioctl = &rio_ioctl; + dev->tx_timeout = &tx_timeout; + dev->watchdog_timeo = TX_TIMEOUT; + dev->change_mtu = &change_mtu; +#ifdef TX_HW_CHECKSUM + dev->features = NETIF_F_SG | NETIF_F_HW_CSUM; +#endif + pci_set_drvdata (pdev, dev); + + ring_space = pci_alloc_consistent(pdev, TX_TOTAL_SIZE, &ring_dma); + if (!ring_space) + goto err_out_iounmap; + np->tx_ring = (struct netdev_desc *)ring_space; + np->tx_ring_dma = ring_dma; + + ring_space = pci_alloc_consistent(pdev, RX_TOTAL_SIZE, &ring_dma); + if (!ring_space) + goto err_out_unmap_tx; + np->rx_ring = (struct netdev_desc *)ring_space; + np->rx_ring_dma = ring_dma; + + /* Parse eeprom data */ + parse_eeprom (dev); + + /* Find PHY address */ + err = find_miiphy (dev); + if (err) + goto err_out_unmap_rx; + + /* Set media and reset PHY */ + mii_set_media (dev); + + /* Reset all logic functions */ + writew (GlobalReset | DMAReset | FIFOReset | NetworkReset | HostReset, + ioaddr + ASICCtrl + 2); + + err = register_netdev (dev); + if (err) + goto err_out_unmap_rx; + + card_idx++; + + printk (KERN_INFO "%s: %s, %2x:%2x:%2x:%2x:%2x:%2x, IRQ %d\n", + dev->name, np->name, + dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], + dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5], + irq); + return 0; + +err_out_unmap_rx: + pci_free_consistent(pdev, RX_TOTAL_SIZE, np->rx_ring, np->rx_ring_dma); +err_out_unmap_tx: + pci_free_consistent(pdev, TX_TOTAL_SIZE, np->tx_ring, np->tx_ring_dma); +err_out_iounmap: +#ifndef USE_IO_OPS + iounmap ((void *) ioaddr); + +err_out_dev: +#endif + kfree (dev); + +err_out_res: + pci_release_regions (pdev); + +err_out_disable: + pci_disable_device (pdev); + return err; +} + +int +find_miiphy (struct net_device *dev) +{ + int i, phy_found = 0; + struct netdev_private *np; + long ioaddr; + np = dev->priv; + ioaddr = dev->base_addr; + np->phy_addr = 1; + + for (i = 31; i >= 0; i--) { + int mii_status = mii_read (dev, i, 1); + if (mii_status != 0xffff && mii_status != 0x0000) { + np->phy_addr = i; + phy_found++; + } + } + if (!phy_found) { + printk (KERN_ERR "%s: No MII PHY found!\n", dev->name); + return -ENODEV; + } + return 0; +} + +int +parse_eeprom (struct net_device *dev) +{ + int i, j; + long ioaddr = dev->base_addr; + u8 sromdata[256]; + u8 *psib; + u32 crc; + PSROM_t psrom = (PSROM_t) sromdata; + struct netdev_private *np = dev->priv; + + int cid, next; + + /* Read eeprom */ + for (i = 0; i < 128; i++) { + ((u16 *) sromdata)[i] = le16_to_cpu (read_eeprom (ioaddr, i)); + } + + /* Check CRC */ + crc = ~get_crc (sromdata, 256 - 4); + if (psrom->crc != ~get_crc (sromdata, 256 - 4)) { + printk (KERN_ERR "%s: EEPROM data CRC error.\n", dev->name); + return -1; + } + + /* Set MAC address */ + for (i = 0; i < 6; i++) + dev->dev_addr[i] = psrom->mac_addr[i]; + + /* Parse Software Infomation Block */ + i = 0x30; + psib = (u8 *) sromdata; + do { + cid = psib[i++]; + next = psib[i++]; + if ((cid == 0 && next == 0) || (cid == 0xff && next == 0xff)) { + printk (KERN_ERR "Cell data error\n"); + return -1; + } + switch (cid) { + case 0: /* Format version */ + break; + case 1: /* End of cell */ + return 0; + case 2: /* Duplex Polarity */ + np->duplex_polarity = psib[i]; + writeb (readb (ioaddr + PhyCtrl) | psib[i], + ioaddr + PhyCtrl); + break; + case 3: /* Wake Polarity */ + np->wake_polarity = psib[i]; + break; + case 9: /* Adapter description */ + j = (next - i > 255) ? 255 : next - i; + memcpy (np->name, &(psib[i]), j); + break; + case 4: + case 5: + case 6: + case 7: + case 8: /* Reversed */ + break; + default: /* Unknown cell */ + return -1; + } + i = next; + } while (1); + + return 0; +} + +static int +rio_open (struct net_device *dev) +{ + struct netdev_private *np = dev->priv; + long ioaddr = dev->base_addr; + int i; + + i = request_irq (dev->irq, &rio_interrupt, SA_SHIRQ, dev->name, dev); + if (i) + return i; + + /* DebugCtrl bit 4, 5, 9 must set */ + writel (readl (ioaddr + DebugCtrl) | 0x0230, ioaddr + DebugCtrl); + + /* Jumbo frame */ + if (np->jumbo != 0) + writew (9014, ioaddr + MaxFrameSize); + + alloc_list (dev); + + /* Get station address */ + for (i = 0; i < 6; i++) + writeb (dev->dev_addr[i], ioaddr + StationAddr0 + i); + + set_multicast (dev); + + /* Set RIO to poll every N*320nsec. */ + writeb (0xff, ioaddr + RxDMAPollPeriod); + writeb (0xff, ioaddr + TxDMAPollPeriod); + netif_start_queue (dev); + writel (StatsEnable | RxEnable | TxEnable, ioaddr + MACCtrl); + + /* VLAN supported */ + if (np->vlan) { + /* priority field in RxDMAIntCtrl */ + writel (0x7 << 10, ioaddr + RxDMAIntCtrl); + /* VLANId */ + writew (np->vlan, ioaddr + VLANId); + /* Length/Type should be 0x8100 */ + writel (0x8100 << 16 | np->vlan, ioaddr + VLANTag); + /* Enable AutoVLANuntagging, but disable AutoVLANtagging. + VLAN information tagged by TFC' VID, CFI fields. */ + writel (readl (ioaddr + MACCtrl) | AutoVLANuntagging, + ioaddr + MACCtrl); + } + + /* Enable default interrupts */ + EnableInt (); + + /* clear statistics */ + get_stats (dev); + return 0; +} + +static void +tx_timeout (struct net_device *dev) +{ + struct netdev_private *np = dev->priv; + long ioaddr = dev->base_addr; + + printk (KERN_WARNING "%s: Transmit timed out, TxStatus %4.4x.\n", + dev->name, readl (ioaddr + TxStatus)); + dev->if_port = 0; + dev->trans_start = jiffies; + np->stats.tx_errors++; + if (!np->tx_full) + netif_wake_queue (dev); +} + + /* allocate and initialize Tx and Rx descriptors */ +static void +alloc_list (struct net_device *dev) +{ + struct netdev_private *np = dev->priv; + int i; + + np->tx_full = 0; + np->cur_rx = np->cur_tx = 0; + np->old_rx = np->old_tx = 0; + np->rx_buf_sz = (dev->mtu <= 1500 ? PACKET_SIZE : dev->mtu + 32); + + /* Initialize Tx descriptors, TFDListPtr leaves in start_xmit(). */ + for (i = 0; i < TX_RING_SIZE; i++) { + np->tx_skbuff[i] = 0; + np->tx_ring[i].status = 0; + } + + /* 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)); + np->rx_ring[i].status = 0; + np->rx_ring[i].fraginfo = 0; + np->rx_skbuff[i] = 0; + } + + /* Allocate the rx buffers */ + for (i = 0; i < RX_RING_SIZE; i++) { + /* Allocated fixed size of skbuff */ + struct sk_buff *skb = dev_alloc_skb (np->rx_buf_sz); + np->rx_skbuff[i] = skb; + if (skb == NULL) { + printk (KERN_ERR + "%s: alloc_list: allocate Rx buffer error! ", + dev->name); + break; + } + skb->dev = dev; /* Mark as being used by this device. */ + 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, + PCI_DMA_FROMDEVICE)); + np->rx_ring[i].fraginfo |= cpu_to_le64 (np->rx_buf_sz) << 48; + } + + /* Set RFDListPtr */ + writel (cpu_to_le32 (np->rx_ring_dma), dev->base_addr + RFDListPtr0); + writel (0, dev->base_addr + RFDListPtr1); + + return; +} + +static int +start_xmit (struct sk_buff *skb, struct net_device *dev) +{ + struct netdev_private *np = dev->priv; + struct netdev_desc *txdesc; + unsigned entry; + u32 ioaddr; + int tx_shift; + unsigned flags; + + ioaddr = dev->base_addr; + entry = np->cur_tx % TX_RING_SIZE; + np->tx_skbuff[entry] = skb; + txdesc = &np->tx_ring[entry]; + txdesc->next_desc = 0; + + /* Set TFDDone to avoid TxDMA gather this descriptor */ + txdesc->status = cpu_to_le64 (TFDDone); + txdesc->status |= + cpu_to_le64 (entry | WordAlignDisable | (1 << FragCountShift)); +#ifdef TX_HW_CHECKSUM + if (skb->ip_summed == CHECKSUM_HW) { + txdesc->status |= + cpu_to_le64 (TCPChecksumEnable | UDPChecksumEnable | + IPChecksumEnable); + } +#endif + if (np->vlan) { + txdesc->status |= + cpu_to_le64 (VLANTagInsert) | + (cpu_to_le64 (np->vlan) << 32) | + (cpu_to_le64 (skb->priority) << 45); + } + + /* Send one packet each time at 10Mbps mode */ + if (entry % 0x08 == 0 || np->speed == 10) + txdesc->status |= cpu_to_le64 (TxIndicate); + txdesc->fraginfo = cpu_to_le64 (pci_map_single(np->pdev, skb->data, + skb->len, PCI_DMA_TODEVICE)); + txdesc->fraginfo |= cpu_to_le64 (skb->len) << 48; + + /* Chain the last descriptor's pointer to this one */ + if (np->last_tx) + np->last_tx->next_desc = cpu_to_le64 (np->tx_ring_dma + + entry*sizeof(struct netdev_desc)); + np->last_tx = txdesc; + + /* Clear TFDDone, then TxDMA start to send this descriptor */ + txdesc->status &= ~cpu_to_le64 (TFDDone); + + DEBUG_TFD_DUMP (np); + + /* TxDMAPollNow */ + writel (readl (ioaddr + DMACtrl) | 0x00001000, ioaddr + DMACtrl); + np->cur_tx++; + + if (np->cur_tx - np->old_tx < TX_QUEUE_LEN - 1 && np->speed != 10) { + /* do nothing */ + } else { + np->tx_full = 1; + netif_stop_queue (dev); + } + + /* The first TFDListPtr */ + if (readl (dev->base_addr + TFDListPtr0) == 0) { + writel (np->tx_ring_dma + entry*sizeof(struct netdev_desc), + dev->base_addr + TFDListPtr0); + writel (0, dev->base_addr + TFDListPtr1); + } + + spin_lock_irqsave (&np->lock, flags); + if (np->old_tx > TX_RING_SIZE) { + tx_shift = TX_RING_SIZE; + np->old_tx -= tx_shift; + np->cur_tx -= tx_shift; + } + spin_unlock_irqrestore (&np->lock, flags); + + /* NETDEV WATCHDOG timer */ + dev->trans_start = jiffies; + return 0; +} + +static void +rio_interrupt (int irq, void *dev_instance, struct pt_regs *rgs) +{ + struct net_device *dev = dev_instance; + struct netdev_private *np; + unsigned int_status; + long ioaddr; + int cnt = max_intrloop; + + ioaddr = dev->base_addr; + np = dev->priv; + spin_lock (&np->lock); + while (1) { + int_status = readw (ioaddr + IntStatus); + writew (int_status & (HostError | TxComplete | RxComplete | + IntRequested | UpdateStats | LinkEvent | + TxDMAComplete | RxDMAComplete | RFDListEnd + | RxDMAPriority), ioaddr + IntStatus); + if (int_status == 0) + break; + /* Processing received packets */ + receive_packet (dev); + /* TxComplete interrupt */ + if (int_status & TxComplete) { + int cnt = 20; + int tx_status = readl (ioaddr + TxStatus); + while (tx_status & 0x80) { /* TxComplete */ + /* Handle TxError */ + if (tx_status & 0x01) + tx_error (dev, tx_status); + tx_status = readl (ioaddr + TxStatus); + /* too much TxError */ + if (--cnt < 0) + break; + } + /* Send one packet each time at 10Mbps mode */ + if (np->speed == 10) { + np->tx_full = 0; + netif_wake_queue (dev); + } + } + /* Free used tx skbuffs */ + for (; np->cur_tx - np->old_tx > 0; np->old_tx++) { + int entry = np->old_tx % TX_RING_SIZE; + struct sk_buff *skb; + + if (!(np->tx_ring[entry].status & TFDDone)) + break; + skb = np->tx_skbuff[entry]; + pci_unmap_single(np->pdev, np->tx_ring[entry].fraginfo, + skb->len, PCI_DMA_TODEVICE); + dev_kfree_skb_irq (skb); + np->tx_skbuff[entry] = 0; + } + /* If the ring is no longer full, clear tx_full and + call netif_wake_queue() */ + if (np->tx_full && np->cur_tx - np->old_tx < TX_QUEUE_LEN - 1) { + np->tx_full = 0; + netif_wake_queue (dev); + } + + /* Handle uncommon events */ + if (int_status & + (IntRequested | HostError | LinkEvent | UpdateStats)) + rio_error (dev, int_status); + /* If too much interrupts here, disable all interrupts except + IntRequest. When CountDown down to 0, IntRequest will + be caught by rio_error() to recovery the interrupts */ + if (--cnt < 0) { + get_stats (dev); + writel (1000, ioaddr + CountDown); + writew (IntRequested, ioaddr + IntEnable); + break; + } + } + spin_unlock (&np->lock); +} + +static void +tx_error (struct net_device *dev, int tx_status) +{ + struct netdev_private *np; + long ioaddr = dev->base_addr; + int frame_id; + int i; + + np = dev->priv; + + frame_id = (tx_status & 0xffff0000) >> 16; + printk (KERN_ERR "%s: Transmit error, TxStatus %4.4x, FrameId %d.\n", + dev->name, tx_status, frame_id); + np->stats.tx_errors++; + np->stats.tx_dropped++; + /* Ttransmit Underrun */ + if (tx_status & 0x10) { + np->stats.tx_fifo_errors++; + /* Transmit Underrun need to set TxReset, DMARest, FIFOReset */ + writew (TxReset | DMAReset | FIFOReset, ioaddr + ASICCtrl + 2); + /* Wait for ResetBusy bit clear */ + for (i = 50; i > 0; i--) { + if ((readw (ioaddr + ASICCtrl + 2) & ResetBusy) == 0) + break; + mdelay (1); + } + /* Reset TFDListPtr */ + writel (np->tx_ring_dma + frame_id*sizeof(struct netdev_desc), + dev->base_addr + TFDListPtr0); + writel (0, dev->base_addr + TFDListPtr1); + + /* Let TxStartThresh stay default value */ + } + /* Late Collision */ + if (tx_status & 0x04) { + np->stats.tx_fifo_errors++; + /* TxReset and clear FIFO */ + writew (TxReset | FIFOReset, ioaddr + ASICCtrl + 2); + /* Wait reset done */ + for (i = 50; i > 0; i--) { + if ((readw (ioaddr + ASICCtrl + 2) & ResetBusy) == 0) + break; + mdelay (1); + } + /* Let TxStartThresh stay default value */ + } + /* Maximum Collisions */ +#ifdef ETHER_STATS + if (tx_status & 0x08) + np->stats.collisions16++; +#else + if (tx_status & 0x08) + np->stats.collisions++; +#endif + + /* Restart the Tx. */ + writel (readw (dev->base_addr + MACCtrl) | TxEnable, ioaddr + MACCtrl); +} + +/* Every interrupts go into here to see if any packet need to process, this + ensure Rx rings keep full in a critical cases of Rx rings ran out */ +static int +receive_packet (struct net_device *dev) +{ + struct netdev_private *np = (struct netdev_private *) dev->priv; + int entry = np->cur_rx % RX_RING_SIZE; + int cnt = np->old_rx + RX_RING_SIZE - np->cur_rx; + int rx_shift; + + if (np->old_rx > RX_RING_SIZE) { + rx_shift = RX_RING_SIZE; + np->old_rx -= rx_shift; + np->cur_rx -= rx_shift; + } + DEBUG_RFD_DUMP (np, 1); + /* If RFDDone, FrameStart and FrameEnd set, there is a new packet in. */ + while (1) { + struct netdev_desc *desc = &np->rx_ring[entry]; + int pkt_len; + u64 frame_status; + + if (!(desc->status & RFDDone) || + !(desc->status & FrameStart) || + !(desc->status & FrameEnd)) + break; + + /* Chip omits the CRC. */ + pkt_len = le64_to_cpu (desc->status & 0xffff); + frame_status = le64_to_cpu (desc->status); + if (--cnt < 0) + break; + DEBUG_PKT_DUMP (np, pkt_len); + pci_dma_sync_single(np->pdev, desc->fraginfo, np->rx_buf_sz, + PCI_DMA_FROMDEVICE); + /* Update rx error statistics, drop packet. */ + if (frame_status & 0x003f0000) { + np->stats.rx_errors++; + if (frame_status & 0x00100000) + np->stats.rx_length_errors++; + if (frame_status & 0x00010000) + np->stats.rx_fifo_errors++; + if (frame_status & 0x00060000) + np->stats.rx_frame_errors++; + if (frame_status & 0x00080000) + np->stats.rx_crc_errors++; + } else { + struct sk_buff *skb; + + /* Small skbuffs for short packets */ + if (pkt_len > copy_thresh) { + pci_unmap_single(np->pdev, desc->fraginfo, + np->rx_buf_sz, PCI_DMA_FROMDEVICE); + skb_put (skb = np->rx_skbuff[entry], pkt_len); + np->rx_skbuff[entry] = NULL; + } else if ((skb = dev_alloc_skb (pkt_len + 2)) != NULL) { + skb->dev = dev; + /* 16 byte align the IP header */ + skb_reserve (skb, 2); + eth_copy_and_sum (skb, + np->rx_skbuff[entry]->tail, + pkt_len, 0); + skb_put (skb, pkt_len); + } + skb->protocol = eth_type_trans (skb, dev); +#ifdef RX_HW_CHECKSUM + /* Checksum done by hw, but csum value unavailable. */ + if (!(frame_status & (TCPError | UDPError | IPError))) { + skb->ip_summed = CHECKSUM_UNNECESSARY; + } +#endif + netif_rx (skb); + dev->last_rx = jiffies; + } + entry = (++np->cur_rx) % RX_RING_SIZE; + } + + /* 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_ERR + "%s: Allocate Rx buffer error!", + dev->name); + 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; + } + /* RxDMAPollNow */ + writel (readl (dev->base_addr + DMACtrl) | 0x00000010, + dev->base_addr + DMACtrl); + + DEBUG_RFD_DUMP (np, 2); + return 0; +} + +static void +rio_error (struct net_device *dev, int int_status) +{ + long ioaddr = dev->base_addr; + struct netdev_private *np = dev->priv; + + /* Stop the down counter and recovery the interrupt */ + if (int_status & IntRequested) { + + writew (0, ioaddr + IntEnable); + writel (0, ioaddr + CountDown); + /* Enable default interrupts */ + EnableInt (); + } + + /* Link change event */ + if (int_status & LinkEvent) { + if (mii_wait_link (dev, 10) == 0) { + printk (KERN_INFO "%s: Link up\n", dev->name); + if (np->an_enable) { + /* Auto-Negotiation mode */ + mii_get_media (dev); + if (np->full_duplex) { + writew (readw (dev->base_addr + MACCtrl) + | DuplexSelect, + ioaddr + MACCtrl); + } + } + } else { + printk (KERN_INFO "%s: Link off\n", dev->name); + } + } + + /* UpdateStats statistics registers */ + if (int_status & UpdateStats) { + get_stats (dev); + } + + /* PCI Error, a catastronphic error related to the bus interface + occurs, set GlobalReset and HostReset to reset. */ + if (int_status & HostError) { + printk (KERN_ERR "%s: PCI Error! IntStatus %4.4x.\n", + dev->name, int_status); + writew (GlobalReset | HostReset, ioaddr + ASICCtrl + 2); + mdelay (500); + } +} + +static struct net_device_stats * +get_stats (struct net_device *dev) +{ + long ioaddr = dev->base_addr; + struct netdev_private *np = dev->priv; + u16 temp1; + u16 temp2; + int i; + /* All statistics registers need to acknowledge, + else overflow could cause some problem */ + np->stats.rx_packets += readl (ioaddr + FramesRcvOk); + np->stats.tx_packets += readl (ioaddr + FramesXmtOk); + np->stats.rx_bytes += readl (ioaddr + OctetRcvOk); + np->stats.tx_bytes += readl (ioaddr + OctetXmtOk); + temp1 = readw (ioaddr + FrameLostRxError); + np->stats.rx_errors += temp1; + np->stats.rx_missed_errors += temp1; + np->stats.tx_dropped += readw (ioaddr + FramesAbortXSColls); + temp1 = readl (ioaddr + SingleColFrames) + + readl (ioaddr + MultiColFrames) + readl (ioaddr + LateCollisions); + temp2 = readw (ioaddr + CarrierSenseErrors); + np->stats.tx_carrier_errors += temp2; + np->stats.tx_errors += readw (ioaddr + FramesWEXDeferal) + + readl (ioaddr + FramesWDeferredXmt) + temp2; + + /* detailed rx_error */ + np->stats.rx_length_errors += readw (ioaddr + InRangeLengthErrors) + + readw (ioaddr + FrameTooLongErrors); + np->stats.rx_crc_errors += readw (ioaddr + FrameCheckSeqError); + + /* Clear all other statistic register. */ + readw (ioaddr + MacControlFramesXmtd); + readw (ioaddr + BcstFramesXmtdOk); + readl (ioaddr + McstFramesXmtdOk); + readl (ioaddr + BcstOctetXmtOk); + readl (ioaddr + McstOctetXmtOk); + readw (ioaddr + MacControlFramesRcvd); + readw (ioaddr + BcstFramesRcvOk); + readl (ioaddr + McstFramesRcvOk); + readl (ioaddr + BcstOctetRcvOk); + + for (i = 0x100; i <= 0x150; i += 4) + readl (ioaddr + i); + readw (ioaddr + TxJumboFrames); + readw (ioaddr + RxJumboFrames); + readw (ioaddr + TCPCheckSumErrors); + readw (ioaddr + UDPCheckSumErrors); + readw (ioaddr + IPCheckSumErrors); + return &np->stats; +} + +int +change_mtu (struct net_device *dev, int new_mtu) +{ + struct netdev_private *np = dev->priv; + int max = (np->jumbo) ? 9000 : 1536; + + if ((new_mtu < 68) || (new_mtu > max)) { + return -EINVAL; + } + + dev->mtu = new_mtu; + + return 0; +} + +#define CRC_POLY 0xedb88320 +static unsigned +get_crc (unsigned char *p, int len) +{ + int bit; + unsigned char byte; + unsigned crc = 0xffffffff; + + while (--len >= 0) { + byte = *p++; + for (bit = 0; bit < 8; bit++, byte >>= 1) { + crc = (crc >> 1) ^ (((crc ^ byte) & 1) ? CRC_POLY : 0); + } + } + return crc; +} + +static void +set_multicast (struct net_device *dev) +{ + long ioaddr = dev->base_addr; + u32 hash_table[2]; + u16 rx_mode = 0; + int i; + struct dev_mc_list *mclist; + struct netdev_private *np = dev->priv; + + /* Default: receive broadcast and unicast */ + rx_mode = ReceiveBroadcast | ReceiveUnicast; + if (dev->flags & IFF_PROMISC) { + /* Receive all frames promiscuously. */ + rx_mode |= ReceiveAllFrames; + } else + if (((dev->flags & IFF_MULTICAST) + && (dev->mc_count > multicast_filter_limit)) + || (dev->flags & IFF_ALLMULTI)) { + /* Receive broadcast and multicast frames */ + rx_mode |= ReceiveBroadcast | ReceiveMulticast | ReceiveUnicast; + } else if ((dev->flags & IFF_MULTICAST) & (dev->mc_count > 0)) { + /* Receive broadcast frames and multicast frames filtering by Hashtable */ + rx_mode |= + ReceiveBroadcast | ReceiveMulticastHash | ReceiveUnicast; + } + if (np->vlan) { + /* ReceiveVLANMatch field in ReceiveMode */ + rx_mode |= ReceiveVLANMatch; + } + hash_table[0] = 0x00000000; + hash_table[1] = 0x00000000; + + for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; + i++, mclist = mclist->next) { + set_bit (get_crc (mclist->dmi_addr, ETH_ALEN) & 0x3f, + hash_table); + } + writel (hash_table[0], ioaddr + HashTable0); + writel (hash_table[1], ioaddr + HashTable1); + writew (rx_mode, ioaddr + ReceiveMode); +} + +static int +rio_ioctl (struct net_device *dev, struct ifreq *rq, int cmd) +{ + int phy_addr; + struct netdev_private *np = dev->priv; + struct mii_data *miidata = (struct mii_data *) &rq->ifr_data; +#ifdef RIO_DEBUG + struct ioctl_data *iodata = (struct ioctl_data *) (rq->ifr_data); +#endif + u16 *data = (u16 *) & rq->ifr_data; + struct netdev_desc *desc; + int i; + + phy_addr = np->phy_addr; + switch (cmd) { + case SIOCDEVPRIVATE: +#ifdef RIO_DEBUG + if (rio_ioctl_ext (dev, iodata) != 0) + return -EOPNOTSUPP; + break; +#else + return -EOPNOTSUPP; +#endif + case SIOCDEVPRIVATE + 1: + miidata->out_value = mii_read (dev, phy_addr, miidata->reg_num); + break; + case SIOCDEVPRIVATE + 2: + mii_write (dev, phy_addr, miidata->reg_num, miidata->in_value); + break; + case SIOCDEVPRIVATE + 3: + np->rx_debug = (data[0] <= 7) ? data[0] : 0; + printk ("rx_debug = %d\n", np->rx_debug); + break; + case SIOCDEVPRIVATE + 4: + np->tx_debug = (data[0] <= 7) ? data[0] : 0; + printk ("tx_debug = %d\n", np->tx_debug); + break; + case SIOCDEVPRIVATE + 5: + np->tx_full = 1; + netif_stop_queue (dev); + break; + case SIOCDEVPRIVATE + 6: + np->tx_full = 0; + netif_wake_queue (dev); + break; + case SIOCDEVPRIVATE + 7: + printk ("tx_full=%x cur_tx=%lx old_tx=%lx cur_rx=%lx old_rx=%lx\n", + np->tx_full, np->cur_tx, np->old_tx, + np->cur_rx, np->old_rx); + break; + case SIOCDEVPRIVATE + 8: + for (i = 0; i < TX_RING_SIZE; i++) { + desc = &np->tx_ring[i]; + printk + ("cur:%08x next:%08x status:%08x frag1:%08x frag0:%08x", + (u32) (np->tx_ring_dma + i*sizeof(*desc)), + (u32) desc->next_desc, + (u32) desc->status, (u32) (desc->fraginfo >> 32), + (u32) desc->fraginfo); + printk ("\n"); + } + printk ("\n"); + break; + default: + return -EOPNOTSUPP; + } + return 0; +} + +#ifdef RIO_DEBUG +int +rio_ioctl_ext (struct net_device *dev, struct ioctl_data *iodata) +{ + struct netdev_private *np = dev->priv; + int phy_addr = np->phy_addr; + u32 hi, lo; + int i; + BMCR_t bmcr; + BMSR_t bmsr; + + if (iodata == NULL) + goto invalid_cmd; + if (strcmp (iodata->signature, "rio") != 0) + goto invalid_cmd; + + switch (iodata->cmd) { + case 0: + for (i = 0; i < TX_RING_SIZE; i++) { + hi = np->tx_ring[i].status >> 32; + lo = np->tx_ring[i].status; + printk ("TFC=%08x %08x \n", hi, lo); + + } + break; + case 1: + for (i = 0; i < RX_RING_SIZE; i++) { + hi = np->rx_ring[i].status >> 32; + lo = np->rx_ring[i].status; + printk ("RFS=%08x %08x \n", hi, lo); + } + break; + case 2: + break; + case 3: + if (iodata->data != NULL) + np->tx_debug = iodata->data[0]; + break; + case 4: + /* Soft reset PHY */ + mii_write (dev, phy_addr, MII_BMCR, MII_BMCR_RESET); + bmcr.image = 0; + bmcr.bits.an_enable = 1; + bmcr.bits.reset = 1; + mii_write (dev, phy_addr, MII_BMCR, bmcr.image); + break; + case 5: + mii_write (dev, phy_addr, MII_BMCR, 0x1940); + mdelay (10); + mii_write (dev, phy_addr, MII_BMCR, 0x1940); + mdelay (100); /* wait a certain time */ + break; + case 6: + /* 5) Set media and Power Up */ + bmcr.image = 0; + bmcr.bits.power_down = 1; + if (np->an_enable) { + bmcr.bits.an_enable = 1; + } else { + if (np->speed == 100) { + bmcr.bits.speed100 = 1; + bmcr.bits.speed1000 = 0; + printk ("Manual 100 Mbps, "); + } else if (np->speed == 10) { + bmcr.bits.speed100 = 0; + bmcr.bits.speed1000 = 0; + printk ("Manual 10 Mbps, "); + } + if (np->full_duplex) { + bmcr.bits.duplex_mode = 1; + printk ("Full duplex. \n"); + } else { + bmcr.bits.duplex_mode = 0; + printk ("Half duplex.\n"); + } + } + mii_write (dev, phy_addr, MII_BMCR, bmcr.image); + break; + case 7: + bmcr.image = mii_read (dev, phy_addr, MII_BMCR); + bmsr.image = mii_read (dev, phy_addr, MII_BMSR); + printk ("BMCR=%x BMSR=%x LinkUp=%d\n", + bmcr.image, bmsr.image, bmsr.bits.link_status); + break; + + default: + return -EOPNOTSUPP; + } + return 0; + +invalid_cmd: + return -1; +} +#endif +#define EEP_READ 0x0200 +#define EEP_BUSY 0x8000 +/* Read the EEPROM word */ +int +read_eeprom (long ioaddr, int eep_addr) +{ + int i = 1000; + writew (EEP_READ | (eep_addr & 0xff), ioaddr + EepromCtrl); + while (i-- > 0) { + if (!(readw (ioaddr + EepromCtrl) & EEP_BUSY)) { + return readw (ioaddr + EepromData); + } + } + return 0; +} + +enum phy_ctrl_bits { + MII_READ = 0x00, MII_CLK = 0x01, MII_DATA1 = 0x02, MII_WRITE = 0x04, + MII_DUPLEX = 0x08, +}; + +#define mii_delay() readb(ioaddr) +static void +mii_sendbit (struct net_device *dev, u32 data) +{ + long ioaddr = dev->base_addr + PhyCtrl; + data = (data) ? MII_DATA1 : 0; + data |= MII_WRITE; + data |= (readb (ioaddr) & 0xf8) | MII_WRITE; + writeb (data, ioaddr); + mii_delay (); + writeb (data | MII_CLK, ioaddr); + mii_delay (); +} + +static int +mii_getbit (struct net_device *dev) +{ + long ioaddr = dev->base_addr + PhyCtrl; + u8 data; + + data = (readb (ioaddr) & 0xf8) | MII_READ; + writeb (data, ioaddr); + mii_delay (); + writeb (data | MII_CLK, ioaddr); + mii_delay (); + return ((readb (ioaddr) >> 1) & 1); +} + +static void +mii_send_bits (struct net_device *dev, u32 data, int len) +{ + int i; + for (i = len - 1; i >= 0; i--) { + mii_sendbit (dev, data & (1 << i)); + } +} + +static int +mii_read (struct net_device *dev, int phy_addr, int reg_num) +{ + u32 cmd; + int i; + u32 retval = 0; + + /* Preamble */ + mii_send_bits (dev, 0xffffffff, 32); + /* ST(2), OP(2), ADDR(5), REG#(5), TA(2), Data(16) total 32 bits */ + /* ST,OP = 0110'b for read operation */ + cmd = (0x06 << 10 | phy_addr << 5 | reg_num); + mii_send_bits (dev, cmd, 14); + /* Turnaround */ + if (mii_getbit (dev)) + goto err_out; + /* Read data */ + for (i = 0; i < 16; i++) { + retval |= mii_getbit (dev); + retval <<= 1; + } + /* End cycle */ + mii_getbit (dev); + return (retval >> 1) & 0xffff; + +err_out: + return 0; +} +static int +mii_write (struct net_device *dev, int phy_addr, int reg_num, u16 data) +{ + u32 cmd; + + /* Preamble */ + mii_send_bits (dev, 0xffffffff, 32); + /* ST(2), OP(2), ADDR(5), REG#(5), TA(2), Data(16) total 32 bits */ + /* ST,OP,AAAAA,RRRRR,TA = 0101xxxxxxxxxx10'b = 0x0502 for write */ + cmd = (0x5002 << 16) | (phy_addr << 23) | (reg_num << 18) | data; + mii_send_bits (dev, cmd, 32); + /* End cycle */ + mii_getbit (dev); + return 0; +} +static int +mii_wait_link (struct net_device *dev, int wait) +{ + BMSR_t bmsr; + int phy_addr; + struct netdev_private *np; + + np = dev->priv; + phy_addr = np->phy_addr; + + do { + bmsr.image = mii_read (dev, phy_addr, MII_BMSR); + if (bmsr.bits.link_status) + return 0; + mdelay (1); + } while (--wait > 0); + return -1; +} +static int +mii_get_media (struct net_device *dev) +{ + ANAR_t negotiate; + BMSR_t bmsr; + BMCR_t bmcr; + MSCR_t mscr; + MSSR_t mssr; + int phy_addr; + struct netdev_private *np; + + np = dev->priv; + phy_addr = np->phy_addr; + + bmsr.image = mii_read (dev, phy_addr, MII_BMSR); + if (np->an_enable) { + if (!bmsr.bits.an_complete) { + /* Auto-Negotiation not completed */ + return -1; + } + negotiate.image = mii_read (dev, phy_addr, MII_ANAR) & + mii_read (dev, phy_addr, MII_ANLPAR); + mscr.image = mii_read (dev, phy_addr, MII_MSCR); + mssr.image = mii_read (dev, phy_addr, MII_MSSR); + if (mscr.bits.media_1000BT_FD & mssr.bits.lp_1000BT_FD) { + np->speed = 1000; + np->full_duplex = 1; + printk (KERN_INFO "Auto 1000BaseT, Full duplex.\n"); + } else if (mscr.bits.media_1000BT_HD & mssr.bits.lp_1000BT_HD) { + np->speed = 1000; + np->full_duplex = 0; + printk (KERN_INFO "Auto 1000BaseT, Half duplex.\n"); + } else if (negotiate.bits.media_100BX_FD) { + np->speed = 100; + np->full_duplex = 1; + printk (KERN_INFO "Auto 100BaseT, Full duplex.\n"); + } else if (negotiate.bits.media_100BX_HD) { + np->speed = 100; + np->full_duplex = 0; + printk (KERN_INFO "Auto 100BaseT, Half duplex.\n"); + } else if (negotiate.bits.media_10BT_FD) { + np->speed = 10; + np->full_duplex = 1; + printk (KERN_INFO "Auto 10BaseT, Full duplex.\n"); + } else if (negotiate.bits.media_10BT_HD) { + np->speed = 10; + np->full_duplex = 0; + printk (KERN_INFO "Auto 10BaseT, Half duplex.\n"); + } + } else { + bmcr.image = mii_read (dev, phy_addr, MII_BMCR); + if (bmcr.bits.speed100 == 1 && bmcr.bits.speed1000 == 0) { + printk (KERN_INFO "Operating at 100 Mbps, "); + } else if (bmcr.bits.speed100 == 0 && bmcr.bits.speed1000 == 0) { + printk (KERN_INFO "Operating at 10 Mbps, "); + } else if (bmcr.bits.speed100 == 0 && bmcr.bits.speed1000 == 1) { + printk (KERN_INFO "Operating at 1000 Mbps, "); + } + if (bmcr.bits.duplex_mode) { + printk ("Full duplex.\n"); + } else { + printk ("Half duplex.\n"); + } + } + return 0; +} + +static int +mii_set_media (struct net_device *dev) +{ + PHY_SCR_t pscr; + BMCR_t bmcr; + BMSR_t bmsr; + ANAR_t anar; + int phy_addr; + struct netdev_private *np; + np = dev->priv; + phy_addr = np->phy_addr; + + /* Does user set speed? */ + if (np->an_enable) { + /* Reset to enable Auto-Negotiation */ + bmsr.image = mii_read (dev, phy_addr, MII_BMSR); + anar.image = mii_read (dev, phy_addr, MII_ANAR); + anar.bits.media_100BX_FD = bmsr.bits.media_100BX_FD; + anar.bits.media_100BX_HD = bmsr.bits.media_100BX_HD; + anar.bits.media_100BT4 = bmsr.bits.media_100BT4; + anar.bits.media_10BT_FD = bmsr.bits.media_10BT_FD; + anar.bits.media_10BT_HD = bmsr.bits.media_10BT_HD; + mii_write (dev, phy_addr, MII_ANAR, anar.image); + + /* Enable Auto crossover */ + pscr.image = mii_read (dev, phy_addr, MII_PHY_SCR); + pscr.bits.mdi_crossover_mode = 3; /* 11'b */ + mii_write (dev, phy_addr, MII_PHY_SCR, pscr.image); + /* Soft reset PHY */ + mii_write (dev, phy_addr, MII_BMCR, MII_BMCR_RESET); + bmcr.image = 0; + bmcr.bits.an_enable = 1; + bmcr.bits.reset = 1; + mii_write (dev, phy_addr, MII_BMCR, bmcr.image); + /* Wait for Link up, link up need a certain time */ + if (mii_wait_link (dev, 3200) != 0) { + printk (KERN_INFO "Link time out\n"); + } + mdelay (1); + mii_get_media (dev); + } else { + /* Force speed setting */ + /* 1) Disable Auto crossover */ + pscr.image = mii_read (dev, phy_addr, MII_PHY_SCR); + pscr.bits.mdi_crossover_mode = 0; + mii_write (dev, phy_addr, MII_PHY_SCR, pscr.image); + + /* 2) PHY Reset */ + bmcr.image = mii_read (dev, phy_addr, MII_BMCR); + bmcr.bits.reset = 1; + mii_write (dev, phy_addr, MII_BMCR, bmcr.image); + + /* 3) Power Down */ + bmcr.image = 0x1940; /* must be 0x1940 */ + mii_write (dev, phy_addr, MII_BMCR, bmcr.image); + mdelay (10); /* wait a certain time */ + + /* 4) Advertise nothing */ + mii_write (dev, phy_addr, MII_ANAR, 0); + + /* 5) Set media and Power Up */ + bmcr.image = 0; + bmcr.bits.power_down = 1; + if (np->speed == 100) { + bmcr.bits.speed100 = 1; + bmcr.bits.speed1000 = 0; + printk (KERN_INFO "Manual 100 Mbps, "); + } else if (np->speed == 10) { + bmcr.bits.speed100 = 0; + bmcr.bits.speed1000 = 0; + printk (KERN_INFO "Manual 10 Mbps, "); + } + if (np->full_duplex) { + bmcr.bits.duplex_mode = 1; + printk ("Full duplex. \n"); + } else { + bmcr.bits.duplex_mode = 0; + printk ("Half duplex.\n"); + } +#if 0 + /* Set 1000BaseT Master/Slave setting */ + mscr.image = mii_read (dev, phy_addr, MII_MSCR); + mscr.bits.cfg_enable = 1; + mscr.bits.cfg_value = 0; +#endif + mii_write (dev, phy_addr, MII_BMCR, bmcr.image); + + /* Wait for Link up, link up need a certain time */ + if (mii_wait_link (dev, 3200) != 0) { + printk (KERN_INFO "Link time out\n"); + } + mii_get_media (dev); + } + return 0; +} + +static int +rio_close (struct net_device *dev) +{ + long ioaddr = dev->base_addr; + struct netdev_private *np = dev->priv; + struct sk_buff *skb; + int i; + + netif_stop_queue (dev); + + /* Disable interrupts */ + writew (0, ioaddr + IntEnable); + + /* Stop Tx and Rx logics */ + writel (TxDisable | RxDisable | StatsDisable, ioaddr + MACCtrl); + synchronize_irq (); + free_irq (dev->irq, dev); + + /* Free all the skbuffs in the queue. */ + for (i = 0; i < RX_RING_SIZE; i++) { + np->rx_ring[i].status = 0; + np->rx_ring[i].fraginfo = 0; + skb = np->rx_skbuff[i]; + if (skb) { + pci_unmap_single(np->pdev, np->rx_ring[i].fraginfo, + skb->len, PCI_DMA_FROMDEVICE); + dev_kfree_skb (skb); + np->rx_skbuff[i] = 0; + } + } + for (i = 0; i < TX_RING_SIZE; i++) { + skb = np->tx_skbuff[i]; + if (skb) { + pci_unmap_single(np->pdev, np->tx_ring[i].fraginfo, + skb->len, PCI_DMA_TODEVICE); + dev_kfree_skb (skb); + np->tx_skbuff[i] = 0; + } + } + return 0; +} + +static void __devexit +rio_remove1 (struct pci_dev *pdev) +{ + struct net_device *dev = pci_get_drvdata (pdev); + + if (dev) { + struct netdev_private *np = dev->priv; + + unregister_netdev (dev); + pci_free_consistent(pdev, RX_TOTAL_SIZE, np->rx_ring, + np->rx_ring_dma); + pci_free_consistent(pdev, TX_TOTAL_SIZE, np->tx_ring, + np->tx_ring_dma); +#ifndef USE_IO_OPS + iounmap ((char *) (dev->base_addr)); +#endif + kfree (dev); + pci_release_regions (pdev); + pci_disable_device (pdev); + } + pci_set_drvdata (pdev, NULL); +} + +static struct pci_driver rio_driver = { + name: "dl2k", + id_table: rio_pci_tbl, + probe: rio_probe1, + remove: rio_remove1, +}; + +static int __init +rio_init (void) +{ +#ifdef MODULE + printk ("%s", version); +#endif + + return pci_module_init (&rio_driver); +} + +static void __exit +rio_exit (void) +{ + pci_unregister_driver (&rio_driver); +} + +module_init (rio_init); +module_exit (rio_exit); + +/* + +Compile command: + +gcc -D__KERNEL__ -DMODULE -I/usr/src/linux/include -Wall -Wstrict-prototypes -O2 -c dl2x.c + +*/ diff -u --recursive --new-file v2.4.6/linux/drivers/net/dl2k.h linux/drivers/net/dl2k.h --- v2.4.6/linux/drivers/net/dl2k.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/dl2k.h Tue Jul 17 18:53:55 2001 @@ -0,0 +1,733 @@ +/* D-Link DL2000-based Gigabit Ethernet Adapter Linux driver */ +/* + Copyright (c) 2001 by D-Link Corporation + Written by Edward Peng.<edward_peng@dlink.com.tw> + Created 03-May-2001, base on Linux' sundance.c. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. +*/ + +#ifndef __DL2K_H__ +#define __DL2K_H__ + +#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/slab.h> +#include <linux/interrupt.h> +#include <linux/pci.h> +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/skbuff.h> +#include <linux/init.h> +#include <asm/processor.h> /* Processor type for cache alignment. */ +#include <asm/bitops.h> +#include <asm/io.h> +#include <linux/delay.h> +#include <linux/spinlock.h> + +#define TX_RING_SIZE 16 +#define TX_QUEUE_LEN 10 /* Limit ring entries actually used. */ +#define RX_RING_SIZE 16 +#define TX_TOTAL_SIZE TX_RING_SIZE*sizeof(struct netdev_desc) +#define RX_TOTAL_SIZE RX_RING_SIZE*sizeof(struct netdev_desc) + +/* This driver was written to use PCI memory space, however x86-oriented + hardware often uses I/O space accesses. */ +#ifdef USE_IO_OPS +#undef readb +#undef readw +#undef readl +#undef writeb +#undef writew +#undef writel +#define readb inb +#define readw inw +#define readl inl +#define writeb outb +#define writew outw +#define writel outl +#endif + +/* Offsets to the device registers. + Unlike software-only systems, device drivers interact with complex hardware. + It's not useful to define symbolic names for every register bit in the + device. The name can only partially document the semantics and make + the driver longer and more difficult to read. + In general, only the important configuration values or bits changed + multiple times should be defined symbolically. +*/ +enum dl2x_offsets { + /* I/O register offsets */ + DMACtrl = 0x00, + RxDMAStatus = 0x08, + TFDListPtr0 = 0x10, + TFDListPtr1 = 0x14, + TxDMABurstThresh = 0x18, + TxDMAUrgentThresh = 0x19, + TxDMAPollPeriod = 0x1a, + RFDListPtr0 = 0x1c, + RFDListPtr1 = 0x20, + RxDMABurstThresh = 0x24, + RxDMAUrgentThresh = 0x25, + RxDMAPollPeriod = 0x26, + RxDMAIntCtrl = 0x28, + DebugCtrl = 0x2c, + ASICCtrl = 0x30, + FifoCtrl = 0x38, + RxEarlyThresh = 0x3a, + FlowOffThresh = 0x3c, + FlowOnThresh = 0x3e, + TxStartThresh = 0x44, + EepromData = 0x48, + EepromCtrl = 0x4a, + ExpromAddr = 0x4c, + Exprodata = 0x50, + WakeEvent0x51, + CountDown = 0x54, + IntStatusAck = 0x5a, + IntEnable = 0x5c, + IntStatus = 0x5e, + TxStatus = 0x60, + MACCtrl = 0x6c, + VLANTag = 0x70, + PhyCtrl = 0x76, + StationAddr0 = 0x78, + StationAddr1 = 0x7a, + StationAddr2 = 0x7c, + VLANId = 0x80, + MaxFrameSize = 0x86, + ReceiveMode = 0x88, + HashTable0 = 0x8c, + HashTable1 = 0x90, + RmonStatMask = 0x98, + StatMask = 0x9c, + RxJumboFrames = 0xbc, + TCPCheckSumErrors = 0xc0, + IPCheckSumErrors = 0xc2, + UDPCheckSumErrors = 0xc4, + TxJumboFrames = 0xf4, + /* Ethernet MIB statistic register offsets */ + OctetRcvOk = 0xa8, + McstOctetRcvOk = 0xac, + BcstOctetRcvOk = 0xb0, + FramesRcvOk = 0xb4, + McstFramesRcvOk = 0xb8, + BcstFramesRcvOk = 0xbe, + MacControlFramesRcvd = 0xc6, + FrameTooLongErrors = 0xc8, + InRangeLengthErrors = 0xca, + FrameCheckSeqError = 0xcc, + FrameLostRxError = 0xce, + OctetXmtOk = 0xd0, + McstOctetXmtOk = 0xd4, + BcstOctetXmtOk = 0xd8, + FramesXmtOk = 0xdc, + McstFramesXmtdOk = 0xe0, + FramesWDeferredXmt = 0xe4, + LateCollisions = 0xe8, + MultiColFrames = 0xec, + SingleColFrames = 0xf0, + BcstFramesXmtdOk = 0xf6, + CarrierSenseErrors = 0xf8, + MacControlFramesXmtd = 0xfa, + FramesAbortXSColls = 0xfc, + FramesWEXDeferal = 0xfe, + /* RMON statistic register offsets */ + EtherStatsCollisions = 0x100, + EtherStatsOctetsTransmit = 0x104, + EtherStatsPktsTransmit = 0x108, + EtherStatsPkts64OctetTransmit = 0x10c, + EtherStats65to127OctetsTransmit = 0x110, + EtherStatsPkts128to255OctetsTransmit = 0x114, + EtherStatsPkts256to511OctetsTransmit = 0x118, + EtherStatsPkts512to1023OctetsTransmit = 0x11c, + EtherStatsPkts1024to1518OctetsTransmit = 0x120, + EtherStatsCRCAlignErrors = 0x124, + EtherStatsUndersizePkts = 0x128, + EtherStatsFragments = 0x12c, + EtherStatsJabbers = 0x130, + EtherStatsOctets = 0x134, + EtherStatsPkts = 0x138, + EtherStats64Octets = 0x13c, + EtherStatsPkts65to127Octets = 0x140, + EtherStatsPkts128to255Octets = 0x144, + EtherStatsPkts256to511Octets = 0x148, + EtherStatsPkts512to1023Octets = 0x14c, + EtherStatsPkts1024to1518Octets = 0x150, +}; + +/* Bits in the interrupt status/mask registers. */ +enum IntStatus_bits { + InterruptStatus = 0x0001, + HostError = 0x0002, + MACCtrlFrame = 0x0008, + TxComplete = 0x0004, + RxComplete = 0x0010, + RxEarly = 0x0020, + IntRequested = 0x0040, + UpdateStats = 0x0080, + LinkEvent = 0x0100, + TxDMAComplete = 0x0200, + RxDMAComplete = 0x0400, + RFDListEnd = 0x0800, + RxDMAPriority = 0x1000, +}; + +/* Bits in the ReceiveMode register. */ +enum ReceiveMode_bits { + ReceiveIPMulticast = 0x0020, + ReceiveMulticastHash = 0x0010, + ReceiveAllFrames = 0x0008, + ReceiveBroadcast = 0x0004, + ReceiveMulticast = 0x0002, + ReceiveUnicast = 0x0001, + ReceiveVLANMatch = 0x0100, + ReceiveVLANHash = 0x0200, +}; +/* Bits in MACCtrl. */ +enum MACCtrl_bits { + DuplexSelect = 0x20, + RcvFCS = 0x200, + AutoVLANtagging = 0x1000, + AutoVLANuntagging = 0x2000, + StatsEnable = 0x00200000, + StatsDisable = 0x00400000, + StatsEnabled = 0x00800000, + TxEnable = 0x01000000, + TxDisable = 0x02000000, + TxEnabled = 0x04000000, + RxEnable = 0x08000000, + RxDisable = 0x10000000, + RxEnabled = 0x20000000, +}; +enum ASICCtrl_HiWord_bits { + GlobalReset = 0x0001, + RxReset = 0x0002, + TxReset = 0x0004, + DMAReset = 0x0008, + FIFOReset = 0x0010, + NetworkReset = 0x0020, + HostReset = 0x0040, + ResetBusy = 0x0400, +}; + +/* Transmit Frame Control bits */ +enum TFC_bits { + DwordAlign = 0x00000000, + WordAlignDisable = 0x00030000, + WordAlign = 0x00020000, + TCPChecksumEnable = 0x00040000, + UDPChecksumEnable = 0x00080000, + IPChecksumEnable = 0x00100000, + FCSAppendDisable = 0x00200000, + TxIndicate = 0x00400000, + TxDMAIndicate = 0x00800000, + FragCountShift = 24, + VLANTagInsert = 0x0000000010000000, + TFDDone = 0x80000000, + VIDShift = 32, + CFI = 0x0000100000000000, + UsePriorityShift = 48, +}; + +/* Receive Frames Status bits */ +enum RFS_bits { + RxFIFOOverrun = 0x00010000, + RxRuntFrame = 0x00020000, + RxAlignmentError = 0x00040000, + RxFCSError = 0x00080000, + RxOverSizedFrame = 0x00100000, + RxLengthError = 0x00200000, + VLANDetected = 0x00400000, + TCPDetected = 0x00800000, + TCPError = 0x01000000, + UDPDetected = 0x02000000, + UDPError = 0x04000000, + IPDetected = 0x08000000, + IPError = 0x10000000, + FrameStart = 0x20000000, + FrameEnd = 0x40000000, + RFDDone = 0x80000000, + TCIShift = 32, +}; + +#define MII_RESET_TIME_OUT 10000 +/* MII register */ +enum _mii_reg { + MII_BMCR = 0, + MII_BMSR = 1, + MII_PHY_ID1 = 2, + MII_PHY_ID2 = 3, + MII_ANAR = 4, + MII_ANLPAR = 5, + MII_ANER = 6, + MII_ANNPT = 7, + MII_ANLPRNP = 8, + MII_MSCR = 9, + MII_MSSR = 10, + MII_ESR = 15, + MII_PHY_SCR = 16, +}; + +/* Basic Mode Control Register */ +typedef union t_MII_BMCR { + u16 image; + struct { + u16 _bit_5_0:6; // bit 5:0 + u16 speed1000:1; // bit 6 + u16 col_test_enable:1; // bit 7 + u16 duplex_mode:1; // bit 8 + u16 restart_an:1; // bit 9 + u16 isolate:1; // bit 10 + u16 power_down:1; // bit 11 + u16 an_enable:1; // bit 12 + u16 speed100:1; // bit 13 + u16 loopback:1; // bit 14 + u16 reset:1; // bit 15 + } bits; +} BMCR_t, *PBMCR_t; + +enum _mii_bmcr { + MII_BMCR_RESET = 0x8000, + MII_BMCR_LOOP_BACK = 0x4000, + MII_BMCR_SPEED_LSB = 0x2000, + MII_BMCR_AN_ENABLE = 0x1000, + MII_BMCR_POWER_DOWN = 0x0800, + MII_BMCR_ISOLATE = 0x0400, + MII_BMCR_RESTART_AN = 0x0200, + MII_BMCR_DUPLEX_MODE = 0x0100, + MII_BMCR_COL_TEST = 0x0080, + MII_BMCR_SPEED_MSB = 0x0040, + MII_BMCR_SPEED_RESERVED = 0x003f, + MII_BMCR_SPEED_10 = 0, + MII_BMCR_SPEED_100 = MII_BMCR_SPEED_LSB, + MII_BMCR_SPEED_1000 = MII_BMCR_SPEED_MSB, +}; + +/* Basic Mode Status Register */ +typedef union t_MII_BMSR { + u16 image; + struct { + u16 ext_capability:1; // bit 0 + u16 japper_detect:1; // bit 1 + u16 link_status:1; // bit 2 + u16 an_ability:1; // bit 3 + u16 remote_fault:1; // bit 4 + u16 an_complete:1; // bit 5 + u16 preamble_supp:1; // bit 6 + u16 _bit_7:1; // bit 7 + u16 ext_status:1; // bit 8 + u16 media_100BT2_HD:1; // bit 9 + u16 media_100BT2_FD:1; // bit 10 + u16 media_10BT_HD:1; // bit 11 + u16 media_10BT_FD:1; // bit 12 + u16 media_100BX_HD:1; // bit 13 + u16 media_100BX_FD:1; // bit 14 + u16 media_100BT4:1; // bit 15 + } bits; +} BMSR_t, *PBMSR_t; + +enum _mii_bmsr { + MII_BMSR_100BT4 = 0x8000, + MII_BMSR_100BX_FD = 0x4000, + MII_BMSR_100BX_HD = 0x2000, + MII_BMSR_10BT_FD = 0x1000, + MII_BMSR_10BT_HD = 0x0800, + MII_BMSR_100BT2_FD = 0x0400, + MII_BMSR_100BT2_HD = 0x0200, + MII_BMSR_EXT_STATUS = 0x0100, + MII_BMSR_PREAMBLE_SUPP = 0x0040, + MII_BMSR_AN_COMPLETE = 0x0020, + MII_BMSR_REMOTE_FAULT = 0x0010, + MII_BMSR_AN_ABILITY = 0x0008, + MII_BMSR_LINK_STATUS = 0x0004, + MII_BMSR_JABBER_DETECT = 0x0002, + MII_BMSR_EXT_CAP = 0x0001, +}; + +/* ANAR */ +typedef union t_MII_ANAR { + u16 image; + struct { + u16 selector:5; // bit 4:0 + u16 media_10BT_HD:1; // bit 5 + u16 media_10BT_FD:1; // bit 6 + u16 media_100BX_HD:1; // bit 7 + u16 media_100BX_FD:1; // bit 8 + u16 media_100BT4:1; // bit 9 + u16 pause:1; // bit 10 + u16 asymmetric:1; // bit 11 + u16 _bit12:1; // bit 12 + u16 remote_fault:1; // bit 13 + u16 _bit14:1; // bit 14 + u16 next_page:1; // bit 15 + } bits; +} ANAR_t, *PANAR_t; + +enum _mii_anar { + MII_ANAR_NEXT_PAGE = 0x8000, + MII_ANAR_REMOTE_FAULT = 0x4000, + MII_ANAR_ASYMMETRIC = 0x0800, + MII_ANAR_PAUSE = 0x0400, + MII_ANAR_100BT4 = 0x0200, + MII_ANAR_100BX_FD = 0x0100, + MII_ANAR_100BX_HD = 0x0080, + MII_ANAR_10BT_FD = 0x0020, + MII_ANAR_10BT_HD = 0x0010, + MII_ANAR_SELECTOR = 0x001f, + MII_IEEE8023_CSMACD = 0x0001, +}; + +/* ANLPAR */ +typedef union t_MII_ANLPAR { + u16 image; + struct { + u16 selector:5; // bit 4:0 + u16 media_10BT_HD:1; // bit 5 + u16 media_10BT_FD:1; // bit 6 + u16 media_100BX_HD:1; // bit 7 + u16 media_100BX_FD:1; // bit 8 + u16 media_100BT4:1; // bit 9 + u16 pause:1; // bit 10 + u16 asymmetric:1; // bit 11 + u16 _bit12:1; // bit 12 + u16 remote_fault:1; // bit 13 + u16 _bit14:1; // bit 14 + u16 next_page:1; // bit 15 + } bits; +} ANLPAR_t, *PANLPAR_t; + +enum _mii_anlpar { + MII_ANLPAR_NEXT_PAGE = MII_ANAR_NEXT_PAGE, + MII_ANLPAR_REMOTE_FAULT = MII_ANAR_REMOTE_FAULT, + MII_ANLPAR_ASYMMETRIC = MII_ANAR_ASYMMETRIC, + MII_ANLPAR_PAUSE = MII_ANAR_PAUSE, + MII_ANLPAR_100BT4 = MII_ANAR_100BT4, + MII_ANLPAR_100BX_FD = MII_ANAR_100BX_FD, + MII_ANLPAR_100BX_HD = MII_ANAR_100BX_HD, + MII_ANLPAR_10BT_FD = MII_ANAR_10BT_FD, + MII_ANLPAR_10BT_HD = MII_ANAR_10BT_HD, + MII_ANLPAR_SELECTOR = MII_ANAR_SELECTOR, +}; + +/* Auto-Negotiation Expansion Register */ +typedef union t_MII_ANER { + u16 image; + struct { + u16 lp_negotiable:1; // bit 0 + u16 page_received:1; // bit 1 + u16 nextpagable:1; // bit 2 + u16 lp_nextpagable:1; // bit 3 + u16 pdetect_fault:1; // bit 4 + u16 _bit15_5:11; // bit 15:5 + } bits; +} ANER_t, *PANER_t; + +enum _mii_aner { + MII_ANER_PAR_DETECT_FAULT = 0x0010, + MII_ANER_LP_NEXTPAGABLE = 0x0008, + MII_ANER_NETXTPAGABLE = 0x0004, + MII_ANER_PAGE_RECEIVED = 0x0002, + MII_ANER_LP_NEGOTIABLE = 0x0001, +}; + +/* MASTER-SLAVE Control Register */ +typedef union t_MII_MSCR { + u16 image; + struct { + u16 _bit_7_0:8; // bit 7:0 + u16 media_1000BT_HD:1; // bit 8 + u16 media_1000BT_FD:1; // bit 9 + u16 port_type:1; // bit 10 + u16 cfg_value:1; // bit 11 + u16 cfg_enable:1; // bit 12 + u16 test_mode:3; // bit 15:13 + } bits; +} MSCR_t, *PMSCR_t; + +enum _mii_mscr { + MII_MSCR_TEST_MODE = 0xe000, + MII_MSCR_CFG_ENABLE = 0x1000, + MII_MSCR_CFG_VALUE = 0x0800, + MII_MSCR_PORT_VALUE = 0x0400, + MII_MSCR_1000BT_FD = 0x0200, + MII_MSCR_1000BT_HD = 0X0100, +}; + +/* MASTER-SLAVE Status Register */ +typedef union t_MII_MSSR { + u16 image; + struct { + u16 idle_err_count:8; // bit 7:0 + u16 _bit_9_8:2; // bit 9:8 + u16 lp_1000BT_HD:1; // bit 10 + u16 lp_1000BT_FD:1; // bit 11 + u16 remote_rcv_status:1; // bit 12 + u16 local_rcv_status:1; // bit 13 + u16 cfg_resolution:1; // bit 14 + u16 cfg_fault:1; // bit 15 + } bits; +} MSSR_t, *PMSSR_t; + +enum _mii_mssr { + MII_MSSR_CFG_FAULT = 0x8000, + MII_MSSR_CFG_RES = 0x4000, + MII_MSSR_LOCAL_RCV_STATUS = 0x2000, + MII_MSSR_REMOTE_RCVR = 0x1000, + MII_MSSR_LP_1000BT_HD = 0x0800, + MII_MSSR_LP_1000BT_FD = 0x0400, + MII_MSSR_IDLE_ERR_COUNT = 0x00ff, +}; + +/* IEEE Extened Status Register */ +typedef union t_MII_ESR { + u16 image; + struct { + u16 _bit_11_0:12; // bit 11:0 + u16 media_1000BT_HD:2; // bit 12 + u16 media_1000BT_FD:1; // bit 13 + u16 media_1000BX_HD:1; // bit 14 + u16 media_1000BX_FD:1; // bit 15 + } bits; +} ESR_t, *PESR_t; + +enum _mii_esr { + MII_ESR_1000BX_FD = 0x8000, + MII_ESR_1000BX_HD = 0x4000, + MII_ESR_1000BT_FD = 0x2000, + MII_ESR_1000BT_HD = 0x1000, +}; +/* PHY Specific Control Register */ +typedef union t_MII_PHY_SCR { + u16 image; + struct { + u16 disable_jabber:1; // bit 0 + u16 polarity_reversal:1; // bit 1 + u16 SEQ_test:1; // bit 2 + u16 _bit_3:1; // bit 3 + u16 disable_CLK125:1; // bit 4 + u16 mdi_crossover_mode:2; // bit 6:5 + u16 enable_ext_dist:1; // bit 7 + u16 _bit_8_9:2; // bit 9:8 + u16 force_link:1; // bit 10 + u16 assert_CRS:1; // bit 11 + u16 rcv_fifo_depth:2; // bit 13:12 + u16 xmit_fifo_depth:2; // bit 15:14 + } bits; +} PHY_SCR_t, *PPHY_SCR_t; + +typedef enum t_MII_ADMIN_STATUS { + adm_reset, + adm_operational, + adm_loopback, + adm_power_down, + adm_isolate +} MII_ADMIN_t, *PMII_ADMIN_t; + +typedef struct t_SROM { + u16 config_param; /* 0x00 */ + u16 asic_ctrl; /* 0x02 */ + u16 sub_vendor_id; /* 0x04 */ + u16 sub_system_id; /* 0x06 */ + u16 reserved1[12]; /* 0x08-0x1f */ + u8 mac_addr[6]; /* 0x20-0x25 */ + u8 reserved2[10]; /* 0x26-0x2f */ + u8 sib[204]; /* 0x30-0xfb */ + u32 crc; /* 0xfc-0xff */ +} SROM_t, *PSROM_t; + +/* Ioctl custom data */ +struct ioctl_data { + char signature[10]; + int cmd; + int len; + char *data; +}; + +struct mii_data { + __u16 reserved; + __u16 reg_num; + __u16 in_value; + __u16 out_value; +}; + +/* The Rx and Tx buffer descriptors. */ +struct netdev_desc { + u64 next_desc; + u64 status; + u64 fraginfo; +}; + +#define PRIV_ALIGN 15 /* Required alignment mask */ +/* Use __attribute__((aligned (L1_CACHE_BYTES))) to maintain alignment + within the structure. */ +struct netdev_private { + /* Descriptor rings first for alignment. */ + struct netdev_desc *rx_ring; + struct netdev_desc *tx_ring; + struct sk_buff *rx_skbuff[RX_RING_SIZE]; + struct sk_buff *tx_skbuff[TX_RING_SIZE]; + dma_addr_t tx_ring_dma; + dma_addr_t rx_ring_dma; + struct pci_dev * pdev; + spinlock_t lock; + struct net_device_stats stats; + unsigned int rx_buf_sz; /* Based on MTU+slack. */ + unsigned int tx_full:1; /* The Tx queue is full. */ + unsigned int full_duplex:1; /* Full-duplex operation requested. */ + unsigned int speed; /* Operating speed */ + unsigned int vlan; /* VLAN Id */ + unsigned int an_enable; /* Auto-Negotiated Enable */ + unsigned int chip_id; /* PCI table chip id */ + unsigned int jumbo; + 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; + int wake_polarity; + char name[256]; /* net device description */ + u8 duplex_polarity; + u16 mcast_filter[4]; + u16 advertising; /* NWay media advertisement */ + u16 negotiate; /* Negotiated media */ + int phy_addr; /* PHY addresses. */ + int tx_debug; + int rx_debug; +}; + +/* The station address location in the EEPROM. */ +#ifdef USE_IO_OPS +#define PCI_IOTYPE (PCI_USES_MASTER | PCI_USES_IO | PCI_ADDR0) +#else +#define PCI_IOTYPE (PCI_USES_MASTER | PCI_USES_MEM | PCI_ADDR1) +#endif +/* The struct pci_device_id consist of: + vendor, device Vendor and device ID to match (or PCI_ANY_ID) + subvendor, subdevice Subsystem vendor and device ID to match (or PCI_ANY_ID) + class Device class to match. The class_mask tells which bits + class_mask of the class are honored during the comparison. + driver_data Data private to the driver. +*/ +static struct pci_device_id rio_pci_tbl[] __devinitdata = { + {0x1186, 0x4000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {0,} +}; +MODULE_DEVICE_TABLE (pci, rio_pci_tbl); +#define TX_TIMEOUT (4*HZ) +#define PACKET_SIZE 1536 +#define RIO_IO_SIZE 340 +#ifdef RIO_DEBUG +#define DEBUG_TFD_DUMP(x) debug_tfd_dump(x) +#define DEBUG_RFD_DUMP(x,flag) debug_rfd_dump(x,flag) +#define DEBUG_PKT_DUMP(x,len) debug_pkt_dump(x,len) +#define DEBUG_PRINT printk + +static inline void +debug_tfd_dump (struct netdev_private *np) +{ + int i; + struct netdev_desc *desc; + + if (np->tx_debug == 6) { + printk ("TFDone Dump: "); + for (i = 0; i < TX_RING_SIZE; i++) { + desc = &np->tx_ring[i]; + if ((desc->fraginfo & 0xffffffffff) == 0) + printk ("X"); + else + printk ("%d", (desc->status & TFDDone) ? 1 : 0); + } + printk ("\n"); + } + if (np->tx_debug == 5) { + for (i = 0; i < TX_RING_SIZE; i++) { + desc = &np->tx_ring[i]; + printk + ("cur:%08x next:%08x status:%08x frag1:%08x frag0:%08x", + (u32) np->tx_ring_dma + i*sizeof(*desc), + (u32) desc->next_desc, (u32) desc->status, + (u32) (desc->fraginfo >> 32), + (u32) desc->fraginfo); + printk ("\n"); + } + printk ("\n"); + } +} +static inline void +debug_rfd_dump (struct netdev_private *np, int flag) +{ + int i; + struct netdev_desc *desc; + int entry = np->cur_rx % RX_RING_SIZE; + + if (np->rx_debug == 5) { + for (i = 0; i < RX_RING_SIZE; i++) { + desc = &np->rx_ring[i]; + printk + ("cur:%08x next:%08x status:%08x frag1:%08x frag0:%08x", + (u32) np->rx_ring_dma + i*sizeof(*desc), + (u32) desc->next_desc, (u32) desc->status, + (u32) (desc->fraginfo >> 32), + (u32) desc->fraginfo); + printk ("\n"); + } + printk ("\n"); + } + + if (np->rx_debug == 6) { + if (flag == 1) + printk ("RFDone Dump: "); + else if (flag == 2) + printk ("Re-Filling: "); + for (i = 0; i < RX_RING_SIZE; i++) { + desc = &np->rx_ring[i]; + printk ("%d", (desc->status & RFDDone) ? 1 : 0); + } + printk ("\n"); + } + if (np->rx_debug == 7) { + printk (" In rcv_pkt(), entry %d status %4.4x %4.4x.\n", + entry, (u32) (np->rx_ring[entry].status >> 32), + (u32) np->rx_ring[entry].status); + } + +} + +static inline void +debug_pkt_dump (struct netdev_private *np, int pkt_len) +{ + int entry = np->cur_rx % RX_RING_SIZE; + struct netdev_desc *desc = &np->rx_ring[entry]; + u64 frame_status = le64_to_cpu (desc->status); + unsigned char *pchar; + unsigned char *phead; + int i; + + if (np->rx_debug == 4) { + printk (" rcv_pkt: status was %4.4x %4.4x.\n", + (u32) (frame_status >> 32), (u32) frame_status); + } + if (np->rx_debug == 7) { + + phead = bus_to_virt(le64_to_cpu(desc->fraginfo & 0xffffffffff)); + for (pchar = phead, i = 0; i < pkt_len; i++, pchar++) { + printk ("%02x ", *pchar); + if ((i + 1) % 20 == 0) + printk ("\n"); + } + } +} +#else +#define DEBUG_TFD_DUMP(x) {} +#define DEBUG_RFD_DUMP(x,flag) {} +#define DEBUG_PKT_DUMP(x,len) {} +#define DEBUG_PRINT() {} +#endif + +#endif /* __DL2K_H__ */ diff -u --recursive --new-file v2.4.6/linux/drivers/net/dmfe.c linux/drivers/net/dmfe.c --- v2.4.6/linux/drivers/net/dmfe.c Tue Jul 3 17:08:20 2001 +++ linux/drivers/net/dmfe.c Wed Jul 4 14:41:33 2001 @@ -127,8 +127,8 @@ #define DMFE_TXTH_1K 0xC000 /* TX TH 1K byte */ #define DMFE_TIMER_WUT (jiffies + HZ * 1)/* timer wakeup time : 1 second */ -#define DMFE_TX_TIMEOUT (HZ * 1.5) /* tx packet time-out time 1.5 s" */ -#define DMFE_TX_KICK (HZ * 0.5) /* tx packet Kick-out time 0.5 s" */ +#define DMFE_TX_TIMEOUT ((3*HZ)/2) /* tx packet time-out time 1.5 s" */ +#define DMFE_TX_KICK (HZ/2) /* tx packet Kick-out time 0.5 s" */ #define DMFE_DBUG(dbug_now, msg, value) if (dmfe_debug || (dbug_now)) printk(KERN_ERR "<DMFE>: %s %lx\n", (msg), (long) (value)) diff -u --recursive --new-file v2.4.6/linux/drivers/net/e2100.c linux/drivers/net/e2100.c --- v2.4.6/linux/drivers/net/e2100.c Tue Jul 3 17:08:20 2001 +++ linux/drivers/net/e2100.c Tue Jul 17 18:53:55 2001 @@ -10,8 +10,10 @@ This is a driver for the Cabletron E2100 series ethercards. - The Author may be reached as becker@cesdis.gsfc.nasa.gov, or - C/O Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771 + The Author may be reached as becker@scyld.com, or C/O + Scyld Computing Corporation + 410 Severn Ave., Suite 210 + Annapolis MD 21403 The E2100 series ethercard is a fairly generic shared memory 8390 implementation. The only unusual aspect is the way the shared memory diff -u --recursive --new-file v2.4.6/linux/drivers/net/epic100.c linux/drivers/net/epic100.c --- v2.4.6/linux/drivers/net/epic100.c Tue Jul 3 17:08:20 2001 +++ linux/drivers/net/epic100.c Tue Jul 17 18:53:55 2001 @@ -48,13 +48,16 @@ * ethtool driver info support (jgarzik) LK1.1.9: - * MII ioctl support (jgarzik) + * ethtool media get/set support (jgarzik) + + LK1.1.10: + * revert MII transceiver init change (jgarzik) */ #define DRV_NAME "epic100" -#define DRV_VERSION "1.11+LK1.1.9" -#define DRV_RELDATE "July 2, 2001" +#define DRV_VERSION "1.11+LK1.1.10" +#define DRV_RELDATE "July 6, 2001" /* The user-configurable values. @@ -448,7 +451,7 @@ outl(0x0008, ioaddr + TEST1); /* Turn on the MII transceiver. */ - outl(dev->if_port == 1 ? 0x13 : 0x12, ioaddr + MIICfg); + outl(0x12, ioaddr + MIICfg); if (chip_idx == 1) outl((inl(ioaddr + NVCTL) & ~0x003C) | 0x4800, ioaddr + NVCTL); outl(0x0200, ioaddr + GENCTL); @@ -670,7 +673,9 @@ required by the details of which bits are reset and the transceiver wiring on the Ositech CardBus card. */ +#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); @@ -1174,8 +1179,6 @@ pci_dma_sync_single(ep->pci_dev, ep->rx_ring[entry].bufaddr, ep->rx_buf_sz, PCI_DMA_FROMDEVICE); - pci_unmap_single(ep->pci_dev, ep->rx_ring[entry].bufaddr, - ep->rx_buf_sz, PCI_DMA_FROMDEVICE); if (pkt_len > PKT_BUF_SZ - 4) { printk(KERN_ERR "%s: Oversized Ethernet frame, status %x " "%d bytes.\n", @@ -1196,6 +1199,9 @@ pkt_len); #endif } else { + pci_unmap_single(ep->pci_dev, + ep->rx_ring[entry].bufaddr, + ep->rx_buf_sz, PCI_DMA_FROMDEVICE); skb_put(skb = ep->rx_skbuff[entry], pkt_len); ep->rx_skbuff[entry] = NULL; } diff -u --recursive --new-file v2.4.6/linux/drivers/net/eql.c linux/drivers/net/eql.c --- v2.4.6/linux/drivers/net/eql.c Mon May 14 23:55:12 2001 +++ linux/drivers/net/eql.c Wed Jul 4 14:41:33 2001 @@ -16,9 +16,6 @@ * Phone: 1-703-847-0040 ext 103 */ -static const char *version = - "Equalizer1996: $Revision: 1.2.1 $ $Date: 1996/09/22 13:52:00 $ Simon Janes (simon@ncm.com)\n"; - /* * Sources: * skeleton.c by Donald Becker. @@ -124,6 +121,8 @@ #include <asm/uaccess.h> +static const char version[] __initdata = + "Equalizer1996: $Revision: 1.2.1 $ $Date: 1996/09/22 13:52:00 $ Simon Janes (simon@ncm.com)\n"; #ifndef EQL_DEBUG /* #undef EQL_DEBUG -* print nothing at all, not even a boot-banner */ @@ -360,9 +359,9 @@ #endif skb->dev = slave_dev; skb->priority = 1; + slave->bytes_queued += skb->len; dev_queue_xmit (skb); eql->stats->tx_packets++; - slave->bytes_queued += skb->len; } else { diff -u --recursive --new-file v2.4.6/linux/drivers/net/eth16i.c linux/drivers/net/eth16i.c --- v2.4.6/linux/drivers/net/eth16i.c Tue Jul 3 17:08:20 2001 +++ linux/drivers/net/eth16i.c Tue Jul 17 18:53:55 2001 @@ -28,7 +28,7 @@ Sources: - skeleton.c a sample network driver core for linux, - written by Donald Becker <becker@CESDIS.gsfc.nasa.gov> + written by Donald Becker <becker@scyld.com> - at1700.c a driver for Allied Telesis AT1700, written by Donald Becker. - e16iSRV.asm a Netware 3.X Server Driver for ICL EtherTeam16i @@ -354,21 +354,21 @@ #define RESET ID_ROM_0 /* This is the I/O address list to be probed when seeking the card */ -static unsigned int eth16i_portlist[] = { +static unsigned int eth16i_portlist[] __initdata = { 0x260, 0x280, 0x2A0, 0x240, 0x340, 0x320, 0x380, 0x300, 0 }; -static unsigned int eth32i_portlist[] = { +static unsigned int eth32i_portlist[] __initdata = { 0x1000, 0x2000, 0x3000, 0x4000, 0x5000, 0x6000, 0x7000, 0x8000, 0x9000, 0xA000, 0xB000, 0xC000, 0xD000, 0xE000, 0xF000, 0 }; /* This is the Interrupt lookup table for Eth16i card */ -static unsigned int eth16i_irqmap[] = { 9, 10, 5, 15, 0 }; +static unsigned int eth16i_irqmap[] __initdata = { 9, 10, 5, 15, 0 }; #define NUM_OF_ISA_IRQS 4 /* This is the Interrupt lookup table for Eth32i card */ -static unsigned int eth32i_irqmap[] = { 3, 5, 7, 9, 10, 11, 12, 15, 0 }; +static unsigned int eth32i_irqmap[] __initdata = { 3, 5, 7, 9, 10, 11, 12, 15, 0 }; #define EISA_IRQ_REG 0xc89 #define NUM_OF_EISA_IRQS 8 @@ -434,7 +434,7 @@ static struct net_device_stats *eth16i_get_stats(struct net_device *dev); -static char cardname[] = "ICL EtherTeam 16i/32"; +static char cardname[] __initdata = "ICL EtherTeam 16i/32"; int __init eth16i_probe(struct net_device *dev) { @@ -832,7 +832,7 @@ } #endif -static int eth16i_get_irq(int ioaddr) +static int __init eth16i_get_irq(int ioaddr) { unsigned char cbyte; @@ -850,7 +850,7 @@ } } -static int eth16i_check_signature(int ioaddr) +static int __init eth16i_check_signature(int ioaddr) { int i; unsigned char creg[4] = { 0 }; diff -u --recursive --new-file v2.4.6/linux/drivers/net/fmv18x.c linux/drivers/net/fmv18x.c --- v2.4.6/linux/drivers/net/fmv18x.c Tue Jul 3 17:08:20 2001 +++ linux/drivers/net/fmv18x.c Tue Jul 17 18:53:55 2001 @@ -3,9 +3,10 @@ Original: at1700.c (1993-94 by Donald Becker). Copyright 1993 United States Government as represented by the Director, National Security Agency. - The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O - Center of Excellence in Space Data and Information Sciences - Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771 + The author may be reached as becker@scyld.com, or C/O + Scyld Computing Corporation + 410 Severn Ave., Suite 210 + Annapolis MD 21403 Modified by Yutaka TAMIYA (tamy@flab.fujitsu.co.jp) Copyright 1994 Fujitsu Laboratories Ltd. diff -u --recursive --new-file v2.4.6/linux/drivers/net/hamachi.c linux/drivers/net/hamachi.c --- v2.4.6/linux/drivers/net/hamachi.c Tue Jul 3 17:08:20 2001 +++ linux/drivers/net/hamachi.c Tue Jul 17 18:53:55 2001 @@ -125,6 +125,8 @@ */ #define TX_RING_SIZE 64 #define RX_RING_SIZE 512 +#define TX_TOTAL_SIZE TX_RING_SIZE*sizeof(struct hamachi_desc) +#define RX_TOTAL_SIZE RX_RING_SIZE*sizeof(struct hamachi_desc) /* * Enable netdev_ioctl. Added interrupt coalescing parameter adjustment. @@ -207,10 +209,9 @@ /* Condensed bus+endian portability operations. */ #if ADDRLEN == 64 -#define virt_to_desc(addr) cpu_to_le64(virt_to_bus(addr)) +#define cpu_to_leXX(addr) cpu_to_le64(addr) #else -#define virt_to_desc(addr) cpu_to_le32(virt_to_bus(addr)) -#define le32desc_to_virt(addr) bus_to_virt(le32_to_cpu(addr)) +#define cpu_to_leXX(addr) cpu_to_le32(addr) #endif @@ -485,31 +486,30 @@ DescIntr=0x10000000, }; -#define PRIV_ALIGN 15 /* Required alignment mask */ +#define PRIV_ALIGN 15 /* Required alignment mask */ #define MII_CNT 4 struct hamachi_private { /* Descriptor rings first for alignment. Tx requires a second descriptor for status. */ - struct hamachi_desc rx_ring[RX_RING_SIZE]; - struct hamachi_desc tx_ring[TX_RING_SIZE]; - /* The addresses of receive-in-place skbuffs. */ + struct hamachi_desc *rx_ring; + struct hamachi_desc *tx_ring; struct sk_buff* rx_skbuff[RX_RING_SIZE]; - /* The saved address of a sent-in-place packet/buffer, for skfree(). */ struct sk_buff* tx_skbuff[TX_RING_SIZE]; + dma_addr_t tx_ring_dma; + dma_addr_t rx_ring_dma; struct net_device_stats stats; - struct timer_list timer; /* Media selection timer. */ + struct timer_list timer; /* Media selection timer. */ /* Frequently used and paired value: keep adjacent for cache effect. */ spinlock_t lock; int chip_id; - struct hamachi_desc *rx_head_desc; unsigned int cur_rx, dirty_rx; /* Producer/consumer ring indices */ unsigned int cur_tx, dirty_tx; - unsigned int rx_buf_sz; /* Based on MTU+slack. */ - unsigned int tx_full:1; /* The Tx queue is full. */ - unsigned int full_duplex:1; /* Full-duplex operation requested. */ + unsigned int rx_buf_sz; /* Based on MTU+slack. */ + unsigned int tx_full:1; /* The Tx queue is full. */ + unsigned int full_duplex:1; /* Full-duplex operation requested. */ unsigned int duplex_lock:1; - unsigned int medialock:1; /* Do not sense media. */ - unsigned int default_port:4; /* Last dev->if_port value. */ + unsigned int medialock:1; /* Do not sense media. */ + unsigned int default_port:4; /* Last dev->if_port value. */ /* MII transceiver section. */ int mii_cnt; /* MII device addresses. */ u16 advertising; /* NWay media advertisement */ @@ -580,6 +580,9 @@ long ioaddr; static int card_idx; struct net_device *dev; + void *ring_space; + dma_addr_t ring_dma; + int ret = -ENOMEM; /* when built into the kernel, we only print version if device is found */ #ifndef MODULE @@ -588,8 +591,10 @@ printk(version); #endif - if (pci_enable_device(pdev)) - return -EIO; + if (pci_enable_device(pdev)) { + ret = -EIO; + goto err_out; + } ioaddr = pci_resource_start(pdev, 0); #ifdef __alpha__ /* Really "64 bit addrs" */ @@ -603,17 +608,13 @@ irq = pdev->irq; ioaddr = (long) ioremap(ioaddr, 0x400); - if (!ioaddr) { - pci_release_regions(pdev); - return -ENOMEM; - } + if (!ioaddr) + goto err_out_release; dev = alloc_etherdev(sizeof(struct hamachi_private)); - if (!dev) { - pci_release_regions(pdev); - iounmap((char *)ioaddr); - return -ENOMEM; - } + if (!dev) + goto err_out_iounmap; + SET_MODULE_OWNER(dev); #ifdef TX_CHECKSUM @@ -635,6 +636,18 @@ hmp = dev->priv; spin_lock_init(&hmp->lock); + ring_space = pci_alloc_consistent(pdev, TX_TOTAL_SIZE, &ring_dma); + if (!ring_space) + goto err_out_cleardev; + hmp->tx_ring = (struct hamachi_desc *)ring_space; + hmp->tx_ring_dma = ring_dma; + + ring_space = pci_alloc_consistent(pdev, RX_TOTAL_SIZE, &ring_dma); + if (!ring_space) + goto err_out_unmap_tx; + hmp->rx_ring = (struct hamachi_desc *)ring_space; + hmp->rx_ring_dma = ring_dma; + /* Check for options being passed in */ option = card_idx < MAX_UNITS ? options[card_idx] : 0; if (dev->mem_start) @@ -715,11 +728,8 @@ i = register_netdev(dev); if (i) { - kfree(dev); - iounmap((char *)ioaddr); - pci_release_regions(pdev); - pci_set_drvdata(pdev, NULL); - return i; + ret = i; + goto err_out_unmap_rx; } printk(KERN_INFO "%s: %s type %x at 0x%lx, ", @@ -757,6 +767,21 @@ card_idx++; return 0; + +err_out_unmap_rx: + pci_free_consistent(pdev, RX_TOTAL_SIZE, hmp->rx_ring, + hmp->rx_ring_dma); +err_out_unmap_tx: + pci_free_consistent(pdev, TX_TOTAL_SIZE, hmp->tx_ring, + hmp->tx_ring_dma); +err_out_cleardev: + kfree (dev); +err_out_iounmap: + iounmap((char *)ioaddr); +err_out_release: + pci_release_regions(pdev); +err_out: + return ret; } static int read_eeprom(long ioaddr, int location) @@ -833,13 +858,14 @@ hamachi_init_ring(dev); #if ADDRLEN == 64 - writel(virt_to_bus(hmp->rx_ring), ioaddr + RxPtr); - writel(virt_to_bus(hmp->rx_ring) >> 32, ioaddr + RxPtr + 4); - writel(virt_to_bus(hmp->tx_ring), ioaddr + TxPtr); - writel(virt_to_bus(hmp->tx_ring) >> 32, ioaddr + TxPtr + 4); + /* writellll anyone ? */ + writel(cpu_to_le64(hmp->rx_ring_dma), ioaddr + RxPtr); + writel(cpu_to_le64(hmp->rx_ring_dma) >> 32, ioaddr + RxPtr + 4); + writel(cpu_to_le64(hmp->tx_ring_dma), ioaddr + TxPtr); + writel(cpu_to_le64(hmp->tx_ring_dma) >> 32, ioaddr + TxPtr + 4); #else - writel(virt_to_bus(hmp->rx_ring), ioaddr + RxPtr); - writel(virt_to_bus(hmp->tx_ring), ioaddr + TxPtr); + writel(cpu_to_le32(hmp->rx_ring_dma), ioaddr + RxPtr); + writel(cpu_to_le32(hmp->tx_ring_dma), ioaddr + TxPtr); #endif /* TODO: It would make sense to organize this as words since the card @@ -970,11 +996,17 @@ still owned by the card */ for (; hmp->cur_tx - hmp->dirty_tx > 0; hmp->dirty_tx++) { int entry = hmp->dirty_tx % TX_RING_SIZE; + struct sk_buff *skb; + if (hmp->tx_ring[entry].status_n_length & cpu_to_le32(DescOwn)) break; /* Free the original skb. */ - if (hmp->tx_skbuff[entry] != 0) { - dev_kfree_skb(hmp->tx_skbuff[entry]); + skb = hmp->tx_skbuff[entry]; + if (skb != 0) { + pci_unmap_single(hmp->pci_dev, + hmp->tx_ring[entry].addr, skb->len, + PCI_DMA_TODEVICE); + dev_kfree_skb(skb); hmp->tx_skbuff[entry] = 0; } hmp->tx_ring[entry].status_n_length = 0; @@ -1021,18 +1053,16 @@ printk(KERN_WARNING "%s: Hamachi transmit timed out, status %8.8x," " resetting...\n", dev->name, (int)readw(ioaddr + TxStatus)); -#ifndef __alpha__ { int i; - printk(KERN_DEBUG " Rx ring %8.8x: ", (int)hmp->rx_ring); + printk(KERN_DEBUG " Rx ring %p: ", hmp->rx_ring); for (i = 0; i < RX_RING_SIZE; i++) printk(" %8.8x", (unsigned int)hmp->rx_ring[i].status_n_length); - printk("\n"KERN_DEBUG" Tx ring %8.8x: ", (int)hmp->tx_ring); + printk("\n"KERN_DEBUG" Tx ring %p: ", hmp->tx_ring); for (i = 0; i < TX_RING_SIZE; i++) printk(" %4.4x", hmp->tx_ring[i].status_n_length); printk("\n"); } -#endif /* Reinit the hardware and make sure the Rx and Tx processes are up and running. @@ -1046,19 +1076,25 @@ */ for (i = 0; i < RX_RING_SIZE; i++) - hmp->rx_ring[i].status_n_length &= ~DescOwn; + hmp->rx_ring[i].status_n_length &= cpu_to_le32(~DescOwn); /* Presume that all packets in the Tx queue are gone if we have to * re-init the hardware. */ for (i = 0; i < TX_RING_SIZE; i++){ + struct sk_buff *skb; + if (i >= TX_RING_SIZE - 1) - hmp->tx_ring[i].status_n_length = DescEndRing | - (hmp->tx_ring[i].status_n_length & 0x0000FFFF); + hmp->tx_ring[i].status_n_length = cpu_to_le32( + DescEndRing | + (hmp->tx_ring[i].status_n_length & 0x0000FFFF)); else hmp->tx_ring[i].status_n_length &= 0x0000ffff; - if (hmp->tx_skbuff[i]){ - dev_kfree_skb(hmp->tx_skbuff[i]); + skb = hmp->tx_skbuff[i]; + if (skb){ + pci_unmap_single(hmp->pci_dev, hmp->tx_ring[i].addr, + skb->len, PCI_DMA_TODEVICE); + dev_kfree_skb(skb); hmp->tx_skbuff[i] = 0; } } @@ -1071,13 +1107,16 @@ hmp->tx_full = 0; hmp->cur_rx = hmp->cur_tx = 0; hmp->dirty_rx = hmp->dirty_tx = 0; - hmp->rx_head_desc = &hmp->rx_ring[0]; /* Rx packets are also presumed lost; however, we need to make sure a * ring of buffers is in tact. -KDU */ for (i = 0; i < RX_RING_SIZE; i++){ - if (hmp->rx_skbuff[i]){ - dev_kfree_skb(hmp->rx_skbuff[i]); + struct sk_buff *skb = hmp->rx_skbuff[i]; + + if (skb){ + pci_unmap_single(hmp->pci_dev, hmp->rx_ring[i].addr, + hmp->rx_buf_sz, PCI_DMA_FROMDEVICE); + dev_kfree_skb(skb); hmp->rx_skbuff[i] = 0; } } @@ -1089,9 +1128,10 @@ break; skb->dev = dev; /* Mark as being used by this device. */ skb_reserve(skb, 2); /* 16 byte align the IP header. */ - hmp->rx_ring[i].addr = virt_to_desc(skb->tail); - hmp->rx_ring[i].status_n_length = - cpu_to_le32(DescOwn | DescEndPacket | DescIntr | (hmp->rx_buf_sz - 2)); + hmp->rx_ring[i].addr = cpu_to_leXX(pci_map_single(hmp->pci_dev, + skb->tail, hmp->rx_buf_sz, PCI_DMA_FROMDEVICE)); + hmp->rx_ring[i].status_n_length = cpu_to_le32(DescOwn | + DescEndPacket | DescIntr | (hmp->rx_buf_sz - 2)); } hmp->dirty_rx = (unsigned int)(i - RX_RING_SIZE); /* Mark the last entry as wrapping the ring. */ @@ -1136,8 +1176,6 @@ hmp->rx_buf_sz = (dev->mtu <= 1492 ? PKT_BUF_SZ : (((dev->mtu+26+7) & ~7) + 2 + 16)); - hmp->rx_head_desc = &hmp->rx_ring[0]; - /* Initialize all Rx descriptors. */ for (i = 0; i < RX_RING_SIZE; i++) { hmp->rx_ring[i].status_n_length = 0; @@ -1151,24 +1189,20 @@ break; skb->dev = dev; /* Mark as being used by this device. */ skb_reserve(skb, 2); /* 16 byte align the IP header. */ - hmp->rx_ring[i].addr = virt_to_desc(skb->tail); + hmp->rx_ring[i].addr = cpu_to_leXX(pci_map_single(hmp->pci_dev, + skb->tail, hmp->rx_buf_sz, PCI_DMA_FROMDEVICE)); /* -2 because it doesn't REALLY have that first 2 bytes -KDU */ - hmp->rx_ring[i].status_n_length = - cpu_to_le32(DescOwn | DescEndPacket | DescIntr | (hmp->rx_buf_sz -2)); + hmp->rx_ring[i].status_n_length = cpu_to_le32(DescOwn | + DescEndPacket | DescIntr | (hmp->rx_buf_sz -2)); } hmp->dirty_rx = (unsigned int)(i - RX_RING_SIZE); - /* Mark the last entry as wrapping the ring. */ hmp->rx_ring[RX_RING_SIZE-1].status_n_length |= cpu_to_le32(DescEndRing); - - /* Mark the last entry as wrapping the ring. */ - hmp->rx_ring[RX_RING_SIZE-1].status_n_length |= DescEndRing; - for (i = 0; i < TX_RING_SIZE; i++) { hmp->tx_skbuff[i] = 0; hmp->tx_ring[i].status_n_length = 0; } - /* Mark the last entry as wrapping the ring. */ + /* Mark the last entry of the ring */ hmp->tx_ring[TX_RING_SIZE-1].status_n_length |= cpu_to_le32(DescEndRing); return; @@ -1270,7 +1304,8 @@ } #endif - hmp->tx_ring[entry].addr = virt_to_desc(skb->data); + hmp->tx_ring[entry].addr = cpu_to_leXX(pci_map_single(hmp->pci_dev, + skb->data, skb->len, PCI_DMA_TODEVICE)); /* Hmmmm, could probably put a DescIntr on these, but the way the driver is currently coded makes Tx interrupts unnecessary @@ -1282,11 +1317,11 @@ mitigating interrupt frequency with the tx_min_pkt parameter. -KDU */ if (entry >= TX_RING_SIZE-1) /* Wrap ring */ - hmp->tx_ring[entry].status_n_length = - cpu_to_le32(DescOwn|DescEndPacket|DescEndRing|DescIntr | skb->len); + hmp->tx_ring[entry].status_n_length = cpu_to_le32(DescOwn | + DescEndPacket | DescEndRing | DescIntr | skb->len); else - hmp->tx_ring[entry].status_n_length = - cpu_to_le32(DescOwn|DescEndPacket|DescIntr | skb->len); + hmp->tx_ring[entry].status_n_length = cpu_to_le32(DescOwn | + DescEndPacket | DescIntr | skb->len); hmp->cur_tx++; /* Non-x86 Todo: explicitly flush cache lines here. */ @@ -1361,11 +1396,18 @@ if (hmp->tx_full){ for (; hmp->cur_tx - hmp->dirty_tx > 0; hmp->dirty_tx++){ int entry = hmp->dirty_tx % TX_RING_SIZE; + struct sk_buff *skb; + if (hmp->tx_ring[entry].status_n_length & cpu_to_le32(DescOwn)) break; + skb = hmp->tx_skbuff[entry]; /* Free the original skb. */ - if (hmp->tx_skbuff[entry]){ - dev_kfree_skb_irq(hmp->tx_skbuff[entry]); + if (skb){ + pci_unmap_single(hmp->pci_dev, + hmp->tx_ring[entry].addr, + skb->len, + PCI_DMA_TODEVICE); + dev_kfree_skb_irq(skb); hmp->tx_skbuff[entry] = 0; } hmp->tx_ring[entry].status_n_length = 0; @@ -1489,14 +1531,19 @@ } /* If EOP is set on the next entry, it's a new packet. Send it up. */ - while ( ! (hmp->rx_head_desc->status_n_length & cpu_to_le32(DescOwn))) { - struct hamachi_desc *desc = hmp->rx_head_desc; + while (1) { + struct hamachi_desc *desc = &(hmp->rx_ring[entry]); u32 desc_status = le32_to_cpu(desc->status_n_length); - u16 data_size = desc_status; /* Implicit truncate */ - u8 *buf_addr = le32desc_to_virt(desc->addr); - s32 frame_status = - le32_to_cpu(get_unaligned((s32*)&(buf_addr[data_size - 12]))); + u16 data_size = desc_status; /* Implicit truncate */ + u8 *buf_addr; + s32 frame_status; + if (desc_status & DescOwn) + break; + pci_dma_sync_single(hmp->pci_dev, desc->addr, hmp->rx_buf_sz, + PCI_DMA_FROMDEVICE); + buf_addr = (u8 *)hmp->rx_ring + entry*sizeof(*desc); + frame_status = le32_to_cpu(get_unaligned((s32*)&(buf_addr[data_size - 12]))); if (hamachi_debug > 4) printk(KERN_DEBUG " hamachi_rx() status was %8.8x.\n", frame_status); @@ -1560,23 +1607,19 @@ skb_reserve(skb, 2); /* 16 byte align the IP header */ /* Call copy + cksum if available. */ #if 1 || USE_IP_COPYSUM - eth_copy_and_sum(skb, bus_to_virt(desc->addr), pkt_len, 0); + eth_copy_and_sum(skb, + hmp->rx_skbuff[entry]->data, pkt_len, 0); skb_put(skb, pkt_len); #else - memcpy(skb_put(skb, pkt_len), bus_to_virt(desc->addr),pkt_len); + memcpy(skb_put(skb, pkt_len), hmp->rx_ring_dma + + entry*sizeof(*desc), pkt_len); #endif } else { - char *temp = skb_put(skb = hmp->rx_skbuff[entry], pkt_len); + pci_unmap_single(hmp->pci_dev, + hmp->rx_ring[entry].addr, + hmp->rx_buf_sz, PCI_DMA_FROMDEVICE); + skb_put(skb = hmp->rx_skbuff[entry], pkt_len); hmp->rx_skbuff[entry] = NULL; -#ifndef final_version /* Remove after testing. */ - if (bus_to_virt(desc->addr) != temp) - printk(KERN_ERR "%s: Internal fault: The skbuff addresses " - "do not match in hamachi_rx: %p vs. %p / %p.\n", - dev->name, bus_to_virt(desc->addr), - skb->head, temp); -#else - (void) temp; -#endif } #ifdef TX_CHECKSUM /* account for extra TX hard_header bytes */ @@ -1609,18 +1652,18 @@ p_r1 = *(p-1); switch (inv) { case 0: - crc = (p_r & 0xffff) + (p_r >> 16); - break; + crc = (p_r & 0xffff) + (p_r >> 16); + break; case 1: - crc = (p_r >> 16) + (p_r & 0xffff) - + (p_r1 >> 16 & 0xff00); - break; + crc = (p_r >> 16) + (p_r & 0xffff) + + (p_r1 >> 16 & 0xff00); + break; case 2: - crc = p_r + (p_r1 >> 16); - break; + crc = p_r + (p_r1 >> 16); + break; case 3: - crc = p_r + (p_r1 & 0xff00) + (p_r1 >> 16); - break; + crc = p_r + (p_r1 & 0xff00) + (p_r1 >> 16); + break; default: /*NOTREACHED*/ crc = 0; } if (crc & 0xffff0000) { @@ -1648,29 +1691,32 @@ hmp->stats.rx_packets++; } entry = (++hmp->cur_rx) % RX_RING_SIZE; - hmp->rx_head_desc = &hmp->rx_ring[entry]; } /* Refill the Rx ring buffers. */ for (; hmp->cur_rx - hmp->dirty_rx > 0; hmp->dirty_rx++) { - struct sk_buff *skb; + struct hamachi_desc *desc; + entry = hmp->dirty_rx % RX_RING_SIZE; + desc = &(hmp->rx_ring[entry]); if (hmp->rx_skbuff[entry] == NULL) { - skb = dev_alloc_skb(hmp->rx_buf_sz); + struct sk_buff *skb = dev_alloc_skb(hmp->rx_buf_sz); + hmp->rx_skbuff[entry] = skb; if (skb == NULL) - break; /* Better luck next round. */ - skb->dev = dev; /* Mark as being used by this device. */ - skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ - hmp->rx_ring[entry].addr = virt_to_desc(skb->tail); + break; /* Better luck next round. */ + skb->dev = dev; /* Mark as being used by this device. */ + skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ + desc->addr = cpu_to_leXX(pci_map_single(hmp->pci_dev, + skb->tail, hmp->rx_buf_sz, PCI_DMA_FROMDEVICE)); } - hmp->rx_ring[entry].status_n_length = cpu_to_le32(hmp->rx_buf_sz); + desc->status_n_length = cpu_to_le32(hmp->rx_buf_sz); if (entry >= RX_RING_SIZE-1) - hmp->rx_ring[entry].status_n_length |= - cpu_to_le32(DescOwn | DescEndPacket | DescEndRing | DescIntr); + desc->status_n_length |= cpu_to_le32(DescOwn | + DescEndPacket | DescEndRing | DescIntr); else - hmp->rx_ring[entry].status_n_length |= - cpu_to_le32(DescOwn | DescEndPacket | DescIntr); + desc->status_n_length |= cpu_to_le32(DescOwn | + DescEndPacket | DescIntr); } /* Restart Rx engine if stopped. */ @@ -1721,6 +1767,7 @@ { long ioaddr = dev->base_addr; struct hamachi_private *hmp = dev->priv; + struct sk_buff *skb; int i; netif_stop_queue(dev); @@ -1743,22 +1790,25 @@ #ifdef __i386__ if (hamachi_debug > 2) { printk("\n"KERN_DEBUG" Tx ring at %8.8x:\n", - (int)virt_to_bus(hmp->tx_ring)); + (int)hmp->tx_ring_dma); for (i = 0; i < TX_RING_SIZE; i++) printk(" %c #%d desc. %8.8x %8.8x.\n", readl(ioaddr + TxCurPtr) == (long)&hmp->tx_ring[i] ? '>' : ' ', i, hmp->tx_ring[i].status_n_length, hmp->tx_ring[i].addr); printk("\n"KERN_DEBUG " Rx ring %8.8x:\n", - (int)virt_to_bus(hmp->rx_ring)); + (int)hmp->rx_ring_dma); for (i = 0; i < RX_RING_SIZE; i++) { printk(KERN_DEBUG " %c #%d desc. %4.4x %8.8x\n", readl(ioaddr + RxCurPtr) == (long)&hmp->rx_ring[i] ? '>' : ' ', i, hmp->rx_ring[i].status_n_length, hmp->rx_ring[i].addr); if (hamachi_debug > 6) { - if (*(u8*)bus_to_virt(hmp->rx_ring[i].addr) != 0x69) { + if (*(u8*)hmp->rx_skbuff[i]->tail != 0x69) { + u16 *addr = (u16 *) + hmp->rx_skbuff[i]->tail; int j; + for (j = 0; j < 0x50; j++) - printk(" %4.4x",((u16*)le32desc_to_virt(hmp->rx_ring[i].addr))[j]); + printk(" %4.4x", addr[j]); printk("\n"); } } @@ -1772,17 +1822,26 @@ /* Free all the skbuffs in the Rx queue. */ for (i = 0; i < RX_RING_SIZE; i++) { + skb = hmp->rx_skbuff[i]; hmp->rx_ring[i].status_n_length = 0; hmp->rx_ring[i].addr = 0xBADF00D0; /* An invalid address. */ - if (hmp->rx_skbuff[i]) { - dev_kfree_skb(hmp->rx_skbuff[i]); + if (skb) { + pci_unmap_single(hmp->pci_dev, + hmp->rx_ring[i].addr, hmp->rx_buf_sz, + PCI_DMA_FROMDEVICE); + dev_kfree_skb(skb); + hmp->rx_skbuff[i] = 0; } - hmp->rx_skbuff[i] = 0; } for (i = 0; i < TX_RING_SIZE; i++) { - if (hmp->tx_skbuff[i]) - dev_kfree_skb(hmp->tx_skbuff[i]); - hmp->tx_skbuff[i] = 0; + skb = hmp->tx_skbuff[i]; + if (skb) { + pci_unmap_single(hmp->pci_dev, + hmp->tx_ring[i].addr, skb->len, + PCI_DMA_TODEVICE); + dev_kfree_skb(skb); + hmp->tx_skbuff[i] = 0; + } } writeb(0x00, ioaddr + LEDCtrl); @@ -1849,7 +1908,7 @@ static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr) { - struct hamachi_private *np = dev->priv; + struct hamachi_private *hmp = dev->priv; u32 ethcmd; if (copy_from_user(ðcmd, useraddr, sizeof(ethcmd))) @@ -1860,7 +1919,7 @@ struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO}; strcpy(info.driver, DRV_NAME); strcpy(info.version, DRV_VERSION); - strcpy(info.bus_info, np->pci_dev->slot_name); + strcpy(info.bus_info, hmp->pci_dev->slot_name); if (copy_to_user(useraddr, &info, sizeof(info))) return -EFAULT; return 0; @@ -1926,6 +1985,12 @@ /* No need to check MOD_IN_USE, as sys_delete_module() checks. */ if (dev) { + struct hamachi_private *hmp = dev->priv; + + pci_free_consistent(pdev, RX_TOTAL_SIZE, hmp->rx_ring, + hmp->rx_ring_dma); + pci_free_consistent(pdev, TX_TOTAL_SIZE, hmp->tx_ring, + hmp->tx_ring_dma); unregister_netdev(dev); iounmap((char *)dev->base_addr); kfree(dev); diff -u --recursive --new-file v2.4.6/linux/drivers/net/hp-plus.c linux/drivers/net/hp-plus.c --- v2.4.6/linux/drivers/net/hp-plus.c Tue Jul 3 17:08:20 2001 +++ linux/drivers/net/hp-plus.c Tue Jul 17 18:53:55 2001 @@ -8,10 +8,10 @@ This software may be used and distributed according to the terms of the GNU General Public License, incorporated herein by reference. - The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O - - Center of Excellence in Space Data and Information Sciences - Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771 + The author may be reached as becker@scyld.com, or C/O + Scyld Computing Corporation + 410 Severn Ave., Suite 210 + Annapolis MD 21403 As is often the case, a great deal of credit is owed to Russ Nelson. The Crynwr packet driver was my primary source of HP-specific diff -u --recursive --new-file v2.4.6/linux/drivers/net/hp.c linux/drivers/net/hp.c --- v2.4.6/linux/drivers/net/hp.c Tue Jul 3 17:08:20 2001 +++ linux/drivers/net/hp.c Tue Jul 17 18:53:55 2001 @@ -8,9 +8,10 @@ This software may be used and distributed according to the terms of the GNU General Public License, incorporated herein by reference. - The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O - Center of Excellence in Space Data and Information Sciences - Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771 + The author may be reached as becker@scyld.com, or C/O + Scyld Computing Corporation + 410 Severn Ave., Suite 210 + Annapolis MD 21403 This is a driver for the HP PC-LAN adaptors. diff -u --recursive --new-file v2.4.6/linux/drivers/net/ioc3-eth.c linux/drivers/net/ioc3-eth.c --- v2.4.6/linux/drivers/net/ioc3-eth.c Wed May 16 10:25:38 2001 +++ linux/drivers/net/ioc3-eth.c Tue Jul 17 18:53:55 2001 @@ -5,43 +5,26 @@ * * Driver for SGI's IOC3 based Ethernet cards as found in the PCI card. * - * Copyright (C) 1999, 2000 Ralf Baechle - * Copyright (C) 1995, 1999, 2000 by Silicon Graphics, Inc. + * Copyright (C) 1999, 2000, 2001 Ralf Baechle + * Copyright (C) 1995, 1999, 2000, 2001 by Silicon Graphics, Inc. * - * Reporting bugs: - * - * If you find problems with this drivers, then if possible do the - * following. Hook up a terminal to the MSC port, send an NMI to the CPUs - * by typing ^Tnmi (where ^T stands for <CTRL>-T). You'll see something - * like: - * 1A 000: - * 1A 000: *** NMI while in Kernel and no NMI vector installed on node 0 - * 1A 000: *** Error EPC: 0xffffffff800265e4 (0xffffffff800265e4) - * 1A 000: *** Press ENTER to continue. - * - * Next enter the command ``lw i:0x86000f0 0x18'' and include this - * commands output which will look like below with your bugreport. - * - * 1A 000: POD MSC Dex> lw i:0x86000f0 0x18 - * 1A 000: 92000000086000f0: 0021f28c 00000000 00000000 00000000 - * 1A 000: 9200000008600100: a5000000 01cde000 00000000 000004e0 - * 1A 000: 9200000008600110: 00000650 00000000 00110b15 00000000 - * 1A 000: 9200000008600120: 006d0005 77bbca0a a5000000 01ce0000 - * 1A 000: 9200000008600130: 80000500 00000500 00002538 05690008 - * 1A 000: 9200000008600140: 00000000 00000000 000003e1 0000786d + * References: + * o IOC3 ASIC specification 4.51, 1996-04-18 + * o IEEE 802.3 specification, 2000 edition + * o DP38840A Specification, National Semiconductor, March 1997 * * To do: * - * - Handle allocation failures in ioc3_alloc_skb() more gracefully. - * - Handle allocation failures in ioc3_init_rings(). - * - Use prefetching for large packets. What is a good lower limit for + * o Handle allocation failures in ioc3_alloc_skb() more gracefully. + * o Handle allocation failures in ioc3_init_rings(). + * o Use prefetching for large packets. What is a good lower limit for * prefetching? - * - We're probably allocating a bit too much memory. - * - Workarounds for various PHYs. - * - Proper autonegotiation. - * - What exactly is net_device_stats.tx_dropped supposed to count? - * - Use hardware checksums. - * - Convert to using the PCI infrastructure / IOC3 meta driver. + * o We're probably allocating a bit too much memory. + * o Use hardware checksums. + * o Convert to using a IOC3 meta driver. + * o Which PHYs might possibly be attached to the IOC3 in real live, + * which workarounds are required for them? Do we ever have Lucent's? + * o For the 2.5 branch kill the mii-tool ioctls. */ #include <linux/init.h> #include <linux/delay.h> @@ -51,13 +34,23 @@ #include <linux/module.h> #include <linux/pci.h> +#ifdef CONFIG_SERIAL +#include <linux/serial.h> +#include <asm/serial.h> +#define IOC3_BAUD (22000000 / (3*16)) +#define IOC3_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST) +#endif + #include <linux/netdevice.h> #include <linux/etherdevice.h> +#include <linux/ethtool.h> #include <linux/skbuff.h> +#include <linux/mii.h> #include <asm/byteorder.h> #include <asm/io.h> #include <asm/pgtable.h> +#include <asm/uaccess.h> #include <asm/sn/types.h> #include <asm/sn/sn0/addrs.h> #include <asm/sn/sn0/hubni.h> @@ -68,22 +61,18 @@ #include <asm/pci/bridge.h> /* - * 32 RX buffers. This is tunable in the range of 16 <= x < 512. The + * 64 RX buffers. This is tunable in the range of 16 <= x < 512. The * value must be a power of two. */ #define RX_BUFFS 64 -/* - * Private ioctls that de facto are well known and used for examply - * by mii-tool. - */ -#define SIOCGMIIPHY (SIOCDEVPRIVATE) /* Read from current PHY */ -#define SIOCGMIIREG (SIOCDEVPRIVATE+1) /* Read any PHY register */ -#define SIOCSMIIREG (SIOCDEVPRIVATE+2) /* Write any PHY register */ - -/* These exist in other drivers; we don't use them at this time. */ -#define SIOCGPARAMS (SIOCDEVPRIVATE+3) /* Read operational parameters */ -#define SIOCSPARAMS (SIOCDEVPRIVATE+4) /* Set operational parameters */ +/* Timer state engine. */ +enum ioc3_timer_state { + arbwait = 0, /* Waiting for auto negotiation to complete. */ + lupwait = 1, /* Auto-neg complete, awaiting link-up status. */ + ltrywait = 2, /* Forcing try of all modes, from fastest to slowest. */ + asleep = 3, /* Time inactive. */ +}; /* Private per NIC data of the driver. */ struct ioc3_private { @@ -100,8 +89,20 @@ int tx_pi; /* TX producer index */ int txqlen; u32 emcr, ehar_h, ehar_l; - struct timer_list negtimer; spinlock_t ioc3_lock; + struct net_device *dev; + + /* Members used by autonegotiation */ + struct timer_list ioc3_timer; + enum ioc3_timer_state timer_state; /* State of auto-neg timer. */ + unsigned int timer_ticks; /* Number of clicks at each state */ + unsigned short sw_bmcr; /* sw copy of MII config register */ + unsigned short sw_bmsr; /* sw copy of MII status register */ + unsigned short sw_physid1; /* sw copy of PHYSID1 */ + unsigned short sw_physid2; /* sw copy of PHYSID2 */ + unsigned short sw_advertise; /* sw copy of ADVERTISE */ + unsigned short sw_lpa; /* sw copy of LPA */ + unsigned short sw_csconfig; /* sw copy of CSCONFIG */ }; static int ioc3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); @@ -109,8 +110,8 @@ static int ioc3_start_xmit(struct sk_buff *skb, struct net_device *dev); static void ioc3_timeout(struct net_device *dev); static inline unsigned int ioc3_hash(const unsigned char *addr); -static inline void ioc3_stop(struct net_device *dev); -static void ioc3_init(struct net_device *dev); +static inline void ioc3_stop(struct ioc3_private *ip); +static void ioc3_init(struct ioc3_private *ip); static const char ioc3_str[] = "IOC3 Ethernet"; @@ -341,8 +342,9 @@ /* * Read the NIC (Number-In-a-Can) device. */ -static void ioc3_get_eaddr(struct net_device *dev, struct ioc3 *ioc3) +static void ioc3_get_eaddr(struct ioc3_private *ip) { + struct ioc3 *ioc3 = ip->regs; u8 nic[14]; int i; int tries = 2; /* There may be some problem with the battery? */ @@ -370,7 +372,7 @@ printk("Ethernet address is "); for (i = 2; i < 8; i++) { - dev->dev_addr[i - 2] = nic[i]; + ip->dev->dev_addr[i - 2] = nic[i]; printk("%02x", nic[i]); if (i < 7) printk(":"); @@ -378,10 +380,15 @@ printk(".\n"); } -/* Caller must hold the ioc3_lock ever for MII readers. This is also - used to protect the transmitter side but it's low contention. */ -static u16 mii_read(struct ioc3 *ioc3, int phy, int reg) +/* + * Caller must hold the ioc3_lock ever for MII readers. This is also + * used to protect the transmitter side but it's low contention. + */ +static u16 mii_read(struct ioc3_private *ip, int reg) { + struct ioc3 *ioc3 = ip->regs; + int phy = ip->phy; + while (ioc3->micr & MICR_BUSY); ioc3->micr = (phy << MICR_PHYADDR_SHIFT) | reg | MICR_READTRIG; while (ioc3->micr & MICR_BUSY); @@ -389,16 +396,18 @@ return ioc3->midr_r & MIDR_DATA_MASK; } -static void mii_write(struct ioc3 *ioc3, int phy, int reg, u16 data) +static void mii_write(struct ioc3_private *ip, int reg, u16 data) { + struct ioc3 *ioc3 = ip->regs; + int phy = ip->phy; + while (ioc3->micr & MICR_BUSY); ioc3->midr_w = data; ioc3->micr = (phy << MICR_PHYADDR_SHIFT) | reg; while (ioc3->micr & MICR_BUSY); } -static int ioc3_mii_init(struct net_device *dev, struct ioc3_private *ip, - struct ioc3 *ioc3); +static int ioc3_mii_init(struct ioc3_private *ip); static struct net_device_stats *ioc3_get_stats(struct net_device *dev) { @@ -410,9 +419,10 @@ } static inline void -ioc3_rx(struct net_device *dev, struct ioc3_private *ip, struct ioc3 *ioc3) +ioc3_rx(struct ioc3_private *ip) { struct sk_buff *skb, *new_skb; + struct ioc3 *ioc3 = ip->regs; int rx_entry, n_entry, len; struct ioc3_erxbuf *rxb; unsigned long *rxr; @@ -429,12 +439,9 @@ while (w0 & ERXBUF_V) { err = rxb->err; /* It's valid ... */ if (err & ERXBUF_GOODPKT) { - len = (w0 >> ERXBUF_BYTECNT_SHIFT) & 0x7ff; + len = ((w0 >> ERXBUF_BYTECNT_SHIFT) & 0x7ff) - 4; skb_trim(skb, len); - skb->protocol = eth_type_trans(skb, dev); - netif_rx(skb); - - ip->rx_skbs[rx_entry] = NULL; /* Poison */ + skb->protocol = eth_type_trans(skb, ip->dev); new_skb = ioc3_alloc_skb(RX_BUF_ALLOC_SIZE, GFP_ATOMIC); if (!new_skb) { @@ -444,15 +451,18 @@ new_skb = skb; goto next; } + netif_rx(skb); + + ip->rx_skbs[rx_entry] = NULL; /* Poison */ - new_skb->dev = dev; + new_skb->dev = ip->dev; /* Because we reserve afterwards. */ skb_put(new_skb, (1664 + RX_OFFSET)); rxb = (struct ioc3_erxbuf *) new_skb->data; skb_reserve(new_skb, RX_OFFSET); - dev->last_rx = jiffies; + ip->dev->last_rx = jiffies; ip->stats.rx_packets++; /* Statistics */ ip->stats.rx_bytes += len; } else { @@ -485,9 +495,10 @@ } static inline void -ioc3_tx(struct net_device *dev, struct ioc3_private *ip, struct ioc3 *ioc3) +ioc3_tx(struct ioc3_private *ip) { unsigned long packets, bytes; + struct ioc3 *ioc3 = ip->regs; int tx_entry, o_entry; struct sk_buff *skb; u32 etcir; @@ -518,7 +529,7 @@ ip->txqlen -= packets; if (ip->txqlen < 128) - netif_wake_queue(dev); + netif_wake_queue(ip->dev); ip->tx_ci = o_entry; spin_unlock(&ip->ioc3_lock); @@ -532,31 +543,27 @@ * also consider to take the interface down. */ static void -ioc3_error(struct net_device *dev, struct ioc3_private *ip, - struct ioc3 *ioc3, u32 eisr) +ioc3_error(struct ioc3_private *ip, u32 eisr) { - if (eisr & EISR_RXOFLO) { - printk(KERN_ERR "%s: RX overflow.\n", dev->name); - } - if (eisr & EISR_RXBUFOFLO) { - printk(KERN_ERR "%s: RX buffer overflow.\n", dev->name); - } - if (eisr & EISR_RXMEMERR) { - printk(KERN_ERR "%s: RX PCI error.\n", dev->name); - } - if (eisr & EISR_RXPARERR) { - printk(KERN_ERR "%s: RX SSRAM parity error.\n", dev->name); - } - if (eisr & EISR_TXBUFUFLO) { - printk(KERN_ERR "%s: TX buffer underflow.\n", dev->name); - } - if (eisr & EISR_TXMEMERR) { - printk(KERN_ERR "%s: TX PCI error.\n", dev->name); - } + struct net_device *dev = ip->dev; + unsigned char *iface = dev->name; - ioc3_stop(dev); - ioc3_init(dev); - ioc3_mii_init(dev, ip, ioc3); + if (eisr & EISR_RXOFLO) + printk(KERN_ERR "%s: RX overflow.\n", iface); + if (eisr & EISR_RXBUFOFLO) + printk(KERN_ERR "%s: RX buffer overflow.\n", iface); + if (eisr & EISR_RXMEMERR) + printk(KERN_ERR "%s: RX PCI error.\n", iface); + if (eisr & EISR_RXPARERR) + printk(KERN_ERR "%s: RX SSRAM parity error.\n", iface); + if (eisr & EISR_TXBUFUFLO) + printk(KERN_ERR "%s: TX buffer underflow.\n", iface); + if (eisr & EISR_TXMEMERR) + printk(KERN_ERR "%s: TX PCI error.\n", iface); + + ioc3_stop(ip); + ioc3_init(ip); + ioc3_mii_init(ip); dev->trans_start = jiffies; netif_wake_queue(dev); @@ -566,7 +573,7 @@ after the Tx thread. */ static void ioc3_interrupt(int irq, void *_dev, struct pt_regs *regs) { - struct net_device *dev = _dev; + struct net_device *dev = (struct net_device *)_dev; struct ioc3_private *ip = dev->priv; struct ioc3 *ioc3 = ip->regs; const u32 enabled = EISR_RXTIMERINT | EISR_RXOFLO | EISR_RXBUFOFLO | @@ -582,53 +589,500 @@ if (eisr & (EISR_RXOFLO | EISR_RXBUFOFLO | EISR_RXMEMERR | EISR_RXPARERR | EISR_TXBUFUFLO | EISR_TXMEMERR)) - ioc3_error(dev, ip, ioc3, eisr); + ioc3_error(ip, eisr); if (eisr & EISR_RXTIMERINT) - ioc3_rx(dev, ip, ioc3); + ioc3_rx(ip); if (eisr & EISR_TXEXPLICIT) - ioc3_tx(dev, ip, ioc3); + ioc3_tx(ip); eisr = ioc3->eisr & enabled; } } -static void negotiate(unsigned long data) +/* + * Auto negotiation. The scheme is very simple. We have a timer routine that + * keeps watching the auto negotiation process as it progresses. The DP83840 + * is first told to start doing it's thing, we set up the time and place the + * timer state machine in it's initial state. + * + * Here the timer peeks at the DP83840 status registers at each click to see + * if the auto negotiation has completed, we assume here that the DP83840 PHY + * will time out at some point and just tell us what (didn't) happen. For + * complete coverage we only allow so many of the ticks at this level to run, + * when this has expired we print a warning message and try another strategy. + * This "other" strategy is to force the interface into various speed/duplex + * configurations and we stop when we see a link-up condition before the + * maximum number of "peek" ticks have occurred. + * + * Once a valid link status has been detected we configure the IOC3 to speak + * the most efficient protocol we could get a clean link for. The priority + * for link configurations, highest first is: + * + * 100 Base-T Full Duplex + * 100 Base-T Half Duplex + * 10 Base-T Full Duplex + * 10 Base-T Half Duplex + * + * We start a new timer now, after a successful auto negotiation status has + * been detected. This timer just waits for the link-up bit to get set in + * the BMCR of the DP83840. When this occurs we print a kernel log message + * describing the link type in use and the fact that it is up. + * + * If a fatal error of some sort is signalled and detected in the interrupt + * service routine, and the chip is reset, or the link is ifconfig'd down + * and then back up, this entire process repeats itself all over again. + */ +static int ioc3_try_next_permutation(struct ioc3_private *ip) +{ + ip->sw_bmcr = mii_read(ip, MII_BMCR); + + /* Downgrade from full to half duplex. Only possible via ethtool. */ + if (ip->sw_bmcr & BMCR_FULLDPLX) { + ip->sw_bmcr &= ~BMCR_FULLDPLX; + mii_write(ip, MII_BMCR, ip->sw_bmcr); + + return 0; + } + + /* Downgrade from 100 to 10. */ + if (ip->sw_bmcr & BMCR_SPEED100) { + ip->sw_bmcr &= ~BMCR_SPEED100; + mii_write(ip, MII_BMCR, ip->sw_bmcr); + + return 0; + } + + /* We've tried everything. */ + return -1; +} + +static void +ioc3_display_link_mode(struct ioc3_private *ip) +{ + char *tmode = ""; + + ip->sw_lpa = mii_read(ip, MII_LPA); + + if (ip->sw_lpa & (LPA_100HALF | LPA_100FULL)) { + if (ip->sw_lpa & LPA_100FULL) + tmode = "100Mb/s, Full Duplex"; + else + tmode = "100Mb/s, Half Duplex"; + } else { + if (ip->sw_lpa & LPA_10FULL) + tmode = "10Mb/s, Full Duplex"; + else + tmode = "10Mb/s, Half Duplex"; + } + + printk(KERN_INFO "%s: Link is up at %s.\n", ip->dev->name, tmode); +} + +static void +ioc3_display_forced_link_mode(struct ioc3_private *ip) +{ + char *speed = "", *duplex = ""; + + ip->sw_bmcr = mii_read(ip, MII_BMCR); + if (ip->sw_bmcr & BMCR_SPEED100) + speed = "100Mb/s, "; + else + speed = "10Mb/s, "; + if (ip->sw_bmcr & BMCR_FULLDPLX) + duplex = "Full Duplex.\n"; + else + duplex = "Half Duplex.\n"; + + printk(KERN_INFO "%s: Link has been forced up at %s%s", ip->dev->name, + speed, duplex); +} + +static int ioc3_set_link_modes(struct ioc3_private *ip) { - struct net_device *dev = (struct net_device *) data; - struct ioc3_private *ip = dev->priv; struct ioc3 *ioc3 = ip->regs; + int full; + + /* + * All we care about is making sure the bigmac tx_cfg has a + * proper duplex setting. + */ + if (ip->timer_state == arbwait) { + ip->sw_lpa = mii_read(ip, MII_LPA); + if (!(ip->sw_lpa & (LPA_10HALF | LPA_10FULL | + LPA_100HALF | LPA_100FULL))) + goto no_response; + if (ip->sw_lpa & LPA_100FULL) + full = 1; + else if (ip->sw_lpa & LPA_100HALF) + full = 0; + else if (ip->sw_lpa & LPA_10FULL) + full = 1; + else + full = 0; + } else { + /* Forcing a link mode. */ + ip->sw_bmcr = mii_read(ip, MII_BMCR); + if (ip->sw_bmcr & BMCR_FULLDPLX) + full = 1; + else + full = 0; + } + + if (full) + ip->emcr |= EMCR_DUPLEX; + else + ip->emcr &= ~EMCR_DUPLEX; + + ioc3->emcr = ip->emcr; + ioc3->emcr; + + return 0; + +no_response: + + return 1; +} + +static int is_lucent_phy(struct ioc3_private *ip) +{ + unsigned short mr2, mr3; + int ret = 0; + + mr2 = mii_read(ip, MII_PHYSID1); + mr3 = mii_read(ip, MII_PHYSID2); + if ((mr2 & 0xffff) == 0x0180 && ((mr3 & 0xffff) >> 10) == 0x1d) { + ret = 1; + } + + return ret; +} + +static void ioc3_timer(unsigned long data) +{ + struct ioc3_private *ip = (struct ioc3_private *) data; + int restart_timer = 0; + + ip->timer_ticks++; + switch (ip->timer_state) { + case arbwait: + /* + * Only allow for 5 ticks, thats 10 seconds and much too + * long to wait for arbitration to complete. + */ + if (ip->timer_ticks >= 10) { + /* Enter force mode. */ + do_force_mode: + ip->sw_bmcr = mii_read(ip, MII_BMCR); + printk(KERN_NOTICE "%s: Auto-Negotiation unsuccessful," + " trying force link mode\n", ip->dev->name); + ip->sw_bmcr = BMCR_SPEED100; + mii_write(ip, MII_BMCR, ip->sw_bmcr); + + if (!is_lucent_phy(ip)) { + /* + * OK, seems we need do disable the transceiver + * for the first tick to make sure we get an + * accurate link state at the second tick. + */ + ip->sw_csconfig = mii_read(ip, MII_CSCONFIG); + ip->sw_csconfig &= ~(CSCONFIG_TCVDISAB); + mii_write(ip, MII_CSCONFIG, ip->sw_csconfig); + } + ip->timer_state = ltrywait; + ip->timer_ticks = 0; + restart_timer = 1; + } else { + /* Anything interesting happen? */ + ip->sw_bmsr = mii_read(ip, MII_BMSR); + if (ip->sw_bmsr & BMSR_ANEGCOMPLETE) { + int ret; + + /* Just what we've been waiting for... */ + ret = ioc3_set_link_modes(ip); + if (ret) { + /* Ooops, something bad happened, go to + * force mode. + * + * XXX Broken hubs which don't support + * XXX 802.3u auto-negotiation make this + * XXX happen as well. + */ + goto do_force_mode; + } + + /* + * Success, at least so far, advance our state + * engine. + */ + ip->timer_state = lupwait; + restart_timer = 1; + } else { + restart_timer = 1; + } + } + break; + + case lupwait: + /* + * Auto negotiation was successful and we are awaiting a + * link up status. I have decided to let this timer run + * forever until some sort of error is signalled, reporting + * a message to the user at 10 second intervals. + */ + ip->sw_bmsr = mii_read(ip, MII_BMSR); + if (ip->sw_bmsr & BMSR_LSTATUS) { + /* + * Wheee, it's up, display the link mode in use and put + * the timer to sleep. + */ + ioc3_display_link_mode(ip); + ip->timer_state = asleep; + restart_timer = 0; + } else { + if (ip->timer_ticks >= 10) { + printk(KERN_NOTICE "%s: Auto negotiation successful, link still " + "not completely up.\n", ip->dev->name); + ip->timer_ticks = 0; + restart_timer = 1; + } else { + restart_timer = 1; + } + } + break; - mod_timer(&ip->negtimer, jiffies + 20 * HZ); + case ltrywait: + /* + * Making the timeout here too long can make it take + * annoyingly long to attempt all of the link mode + * permutations, but then again this is essentially + * error recovery code for the most part. + */ + ip->sw_bmsr = mii_read(ip, MII_BMSR); + ip->sw_csconfig = mii_read(ip, MII_CSCONFIG); + if (ip->timer_ticks == 1) { + if (!is_lucent_phy(ip)) { + /* + * Re-enable transceiver, we'll re-enable the + * transceiver next tick, then check link state + * on the following tick. + */ + ip->sw_csconfig |= CSCONFIG_TCVDISAB; + mii_write(ip, MII_CSCONFIG, ip->sw_csconfig); + } + restart_timer = 1; + break; + } + if (ip->timer_ticks == 2) { + if (!is_lucent_phy(ip)) { + ip->sw_csconfig &= ~(CSCONFIG_TCVDISAB); + mii_write(ip, MII_CSCONFIG, ip->sw_csconfig); + } + restart_timer = 1; + break; + } + if (ip->sw_bmsr & BMSR_LSTATUS) { + /* Force mode selection success. */ + ioc3_display_forced_link_mode(ip); + ioc3_set_link_modes(ip); /* XXX error? then what? */ + ip->timer_state = asleep; + restart_timer = 0; + } else { + if (ip->timer_ticks >= 4) { /* 6 seconds or so... */ + int ret; + + ret = ioc3_try_next_permutation(ip); + if (ret == -1) { + /* + * Aieee, tried them all, reset the + * chip and try all over again. + */ + printk(KERN_NOTICE "%s: Link down, " + "cable problem?\n", + ip->dev->name); + + ioc3_init(ip); + return; + } + if (!is_lucent_phy(ip)) { + ip->sw_csconfig = mii_read(ip, + MII_CSCONFIG); + ip->sw_csconfig |= CSCONFIG_TCVDISAB; + mii_write(ip, MII_CSCONFIG, + ip->sw_csconfig); + } + ip->timer_ticks = 0; + restart_timer = 1; + } else { + restart_timer = 1; + } + } + break; + + case asleep: + default: + /* Can't happens.... */ + printk(KERN_ERR "%s: Aieee, link timer is asleep but we got " + "one anyways!\n", ip->dev->name); + restart_timer = 0; + ip->timer_ticks = 0; + ip->timer_state = asleep; /* foo on you */ + break; + }; + + if (restart_timer) { + ip->ioc3_timer.expires = jiffies + ((12 * HZ)/10); /* 1.2s */ + add_timer(&ip->ioc3_timer); + } +} + +static void +ioc3_start_auto_negotiation(struct ioc3_private *ip, struct ethtool_cmd *ep) +{ + int timeout; + + /* Read all of the registers we are interested in now. */ + ip->sw_bmsr = mii_read(ip, MII_BMSR); + ip->sw_bmcr = mii_read(ip, MII_BMCR); + ip->sw_physid1 = mii_read(ip, MII_PHYSID1); + ip->sw_physid2 = mii_read(ip, MII_PHYSID2); + + /* XXX Check BMSR_ANEGCAPABLE, should not be necessary though. */ + + ip->sw_advertise = mii_read(ip, MII_ADVERTISE); + if (ep == NULL || ep->autoneg == AUTONEG_ENABLE) { + /* Advertise everything we can support. */ + if (ip->sw_bmsr & BMSR_10HALF) + ip->sw_advertise |= ADVERTISE_10HALF; + else + ip->sw_advertise &= ~ADVERTISE_10HALF; + + if (ip->sw_bmsr & BMSR_10FULL) + ip->sw_advertise |= ADVERTISE_10FULL; + else + ip->sw_advertise &= ~ADVERTISE_10FULL; + if (ip->sw_bmsr & BMSR_100HALF) + ip->sw_advertise |= ADVERTISE_100HALF; + else + ip->sw_advertise &= ~ADVERTISE_100HALF; + if (ip->sw_bmsr & BMSR_100FULL) + ip->sw_advertise |= ADVERTISE_100FULL; + else + ip->sw_advertise &= ~ADVERTISE_100FULL; + mii_write(ip, MII_ADVERTISE, ip->sw_advertise); + + /* + * XXX Currently no IOC3 card I know off supports 100BaseT4, + * XXX and this is because the DP83840 does not support it, + * XXX changes XXX would need to be made to the tx/rx logic in + * XXX the driver as well so I completely skip checking for it + * XXX in the BMSR for now. + */ + +#ifdef AUTO_SWITCH_DEBUG + ASD(("%s: Advertising [ ", ip->dev->name)); + if (ip->sw_advertise & ADVERTISE_10HALF) + ASD(("10H ")); + if (ip->sw_advertise & ADVERTISE_10FULL) + ASD(("10F ")); + if (ip->sw_advertise & ADVERTISE_100HALF) + ASD(("100H ")); + if (ip->sw_advertise & ADVERTISE_100FULL) + ASD(("100F ")); +#endif + + /* Enable Auto-Negotiation, this is usually on already... */ + ip->sw_bmcr |= BMCR_ANENABLE; + mii_write(ip, MII_BMCR, ip->sw_bmcr); + + /* Restart it to make sure it is going. */ + ip->sw_bmcr |= BMCR_ANRESTART; + mii_write(ip, MII_BMCR, ip->sw_bmcr); + + /* BMCR_ANRESTART self clears when the process has begun. */ + + timeout = 64; /* More than enough. */ + while (--timeout) { + ip->sw_bmcr = mii_read(ip, MII_BMCR); + if (!(ip->sw_bmcr & BMCR_ANRESTART)) + break; /* got it. */ + udelay(10); + } + if (!timeout) { + printk(KERN_ERR "%s: IOC3 would not start auto " + "negotiation BMCR=0x%04x\n", + ip->dev->name, ip->sw_bmcr); + printk(KERN_NOTICE "%s: Performing force link " + "detection.\n", ip->dev->name); + goto force_link; + } else { + ip->timer_state = arbwait; + } + } else { +force_link: + /* + * Force the link up, trying first a particular mode. Either + * we are here at the request of ethtool or because the IOC3 + * would not start to autoneg. + */ + + /* + * Disable auto-negotiation in BMCR, enable the duplex and + * speed setting, init the timer state machine, and fire it off. + */ + if (ep == NULL || ep->autoneg == AUTONEG_ENABLE) { + ip->sw_bmcr = BMCR_SPEED100; + } else { + if (ep->speed == SPEED_100) + ip->sw_bmcr = BMCR_SPEED100; + else + ip->sw_bmcr = 0; + if (ep->duplex == DUPLEX_FULL) + ip->sw_bmcr |= BMCR_FULLDPLX; + } + mii_write(ip, MII_BMCR, ip->sw_bmcr); + + if (!is_lucent_phy(ip)) { + /* + * OK, seems we need do disable the transceiver for the + * first tick to make sure we get an accurate link + * state at the second tick. + */ + ip->sw_csconfig = mii_read(ip, MII_CSCONFIG); + ip->sw_csconfig &= ~(CSCONFIG_TCVDISAB); + mii_write(ip, MII_CSCONFIG, ip->sw_csconfig); + } + ip->timer_state = ltrywait; + } + + del_timer(&ip->ioc3_timer); + ip->timer_ticks = 0; + ip->ioc3_timer.expires = jiffies + (12 * HZ)/10; /* 1.2 sec. */ + ip->ioc3_timer.data = (unsigned long) ip; + ip->ioc3_timer.function = &ioc3_timer; + add_timer(&ip->ioc3_timer); } -static int ioc3_mii_init(struct net_device *dev, struct ioc3_private *ip, - struct ioc3 *ioc3) +static int ioc3_mii_init(struct ioc3_private *ip) { - u16 word, mii0; - int i, phy; + int i, found; + u16 word; + found = 0; spin_lock_irq(&ip->ioc3_lock); - phy = -1; for (i = 0; i < 32; i++) { - word = mii_read(ioc3, i, 2); + ip->phy = i; + word = mii_read(ip, 2); if ((word != 0xffff) && (word != 0x0000)) { - phy = i; + found = 1; break; /* Found a PHY */ } } - if (phy == -1) { + if (!found) { spin_unlock_irq(&ip->ioc3_lock); return -ENODEV; } - ip->phy = phy; - /* Autonegotiate 100mbit and fullduplex. */ - mii0 = mii_read(ioc3, ip->phy, 0); - mii_write(ioc3, ip->phy, 0, mii0 | 0x3100); - - ip->negtimer.function = &negotiate; - ip->negtimer.data = (unsigned long) dev; - mod_timer(&ip->negtimer, jiffies); /* Run it now */ + ioc3_start_auto_negotiation(ip, NULL); // XXX ethtool spin_unlock_irq(&ip->ioc3_lock); @@ -808,13 +1262,15 @@ } } -static void ioc3_init(struct net_device *dev) +static void ioc3_init(struct ioc3_private *ip) { - struct ioc3_private *ip = dev->priv; + struct net_device *dev = ip->dev; struct ioc3 *ioc3 = ip->regs; + del_timer(&ip->ioc3_timer); /* Kill if running */ + ioc3->emcr = EMCR_RST; /* Reset */ - ioc3->emcr; /* flush WB */ + ioc3->emcr; /* Flush WB */ udelay(4); /* Give it time ... */ ioc3->emcr = 0; ioc3->emcr; @@ -832,7 +1288,7 @@ ioc3->ehar_l = ip->ehar_l; ioc3->ersr = 42; /* XXX should be random */ - ioc3_init_rings(dev, ip, ioc3); + ioc3_init_rings(ip->dev, ip, ioc3); ip->emcr |= ((RX_OFFSET / 2) << EMCR_RXOFF_SHIFT) | EMCR_TXDMAEN | EMCR_TXEN | EMCR_RXDMAEN | EMCR_RXEN; @@ -843,9 +1299,8 @@ ioc3->eier; } -static inline void ioc3_stop(struct net_device *dev) +static inline void ioc3_stop(struct ioc3_private *ip) { - struct ioc3_private *ip = dev->priv; struct ioc3 *ioc3 = ip->regs; ioc3->emcr = 0; /* Shutup */ @@ -856,19 +1311,17 @@ static int ioc3_open(struct net_device *dev) { - struct ioc3_private *ip; + struct ioc3_private *ip = dev->priv; - if (request_irq(dev->irq, ioc3_interrupt, 0, ioc3_str, dev)) { + if (request_irq(dev->irq, ioc3_interrupt, SA_SHIRQ, ioc3_str, dev)) { printk(KERN_ERR "%s: Can't get irq %d\n", dev->name, dev->irq); return -EAGAIN; } - ip = dev->priv; - ip->ehar_h = 0; ip->ehar_l = 0; - ioc3_init(dev); + ioc3_init(ip); netif_start_queue(dev); return 0; @@ -879,89 +1332,132 @@ { struct ioc3_private *ip = dev->priv; - del_timer(&ip->negtimer); + del_timer(&ip->ioc3_timer); + netif_stop_queue(dev); - ioc3_stop(dev); /* Flush */ + ioc3_stop(ip); free_irq(dev->irq, dev); ioc3_free_rings(ip); return 0; } +/* + * MENET cards have four IOC3 chips, which are attached to two sets of + * PCI slot resources each: the primary connections are on slots + * 0..3 and the secondaries are on 4..7 + * + * All four ethernets are brought out to connectors; six serial ports + * (a pair from each of the first three IOC3s) are brought out to + * MiniDINs; all other subdevices are left swinging in the wind, leave + * them disabled. + */ +static inline int ioc3_is_menet(struct pci_dev *pdev) +{ + struct pci_dev *dev; + + return pdev->bus->parent == NULL + && (dev = pci_find_slot(pdev->bus->number, PCI_DEVFN(0, 0))) + && dev->vendor == PCI_VENDOR_ID_SGI + && dev->device == PCI_DEVICE_ID_SGI_IOC3 + && (dev = pci_find_slot(pdev->bus->number, PCI_DEVFN(1, 0))) + && dev->vendor == PCI_VENDOR_ID_SGI + && dev->device == PCI_DEVICE_ID_SGI_IOC3 + && (dev = pci_find_slot(pdev->bus->number, PCI_DEVFN(2, 0))) + && dev->vendor == PCI_VENDOR_ID_SGI + && dev->device == PCI_DEVICE_ID_SGI_IOC3; +} + +static void inline ioc3_serial_probe(struct pci_dev *pdev, + struct ioc3 *ioc3) +{ + struct serial_struct req; + + /* + * We need to recognice and treat the fourth MENET serial as it + * does not have an SuperIO chip attached to it, therefore attempting + * to access it will result in bus errors. We call something an + * MENET if PCI slot 0, 1, 2 and 3 of a master PCI bus all have an IOC3 + * in it. This is paranoid but we want to avoid blowing up on a + * showhorn PCI box that happens to have 4 IOC3 cards in it so it's + * not paranoid enough ... + */ + if (ioc3_is_menet(pdev) && PCI_SLOT(pdev->devfn) == 3) + return; + + /* Register to interrupt zero because we share the interrupt with + the serial driver which we don't properly support yet. */ + memset(&req, 0, sizeof(req)); + req.irq = 0; + req.flags = IOC3_COM_FLAGS; + req.io_type = SERIAL_IO_MEM; + req.iomem_reg_shift = 0; + req.baud_base = IOC3_BAUD; + + req.iomem_base = (unsigned char *) &ioc3->sregs.uarta; + register_serial(&req); + + req.iomem_base = (unsigned char *) &ioc3->sregs.uartb; + register_serial(&req); +} + static int __devinit ioc3_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { - u16 mii0, mii_status, mii2, mii3, mii4; struct net_device *dev = NULL; struct ioc3_private *ip; struct ioc3 *ioc3; unsigned long ioc3_base, ioc3_size; u32 vendor, model, rev; - int phy, err; - - dev = init_etherdev(0, sizeof(struct ioc3_private)); + int err; + dev = alloc_etherdev(sizeof(struct ioc3_private)); if (!dev) return -ENOMEM; + err = pci_request_regions(pdev, "ioc3"); + if (err) + goto out_free; + SET_MODULE_OWNER(dev); ip = dev->priv; - memset(ip, 0, sizeof(*ip)); - - /* - * This probably needs to be register_netdevice, or call - * init_etherdev so that it calls register_netdevice. Quick - * hack for now. - */ - netif_device_attach(dev); + ip->dev = dev; dev->irq = pdev->irq; - ioc3_base = pdev->resource[0].start; - ioc3_size = pdev->resource[0].end - ioc3_base; + ioc3_base = pci_resource_start(pdev, 0); + ioc3_size = pci_resource_len(pdev, 0); ioc3 = (struct ioc3 *) ioremap(ioc3_base, ioc3_size); if (!ioc3) { - printk(KERN_CRIT"%s: Unable to map device I/O.\n", dev->name); + printk(KERN_CRIT "ioc3eth(%s): ioremap failed, goodbye.\n", + pdev->slot_name); err = -ENOMEM; - goto out_free; + goto out_res; } ip->regs = ioc3; +#ifdef CONFIG_SERIAL + ioc3_serial_probe(pdev, ioc3); +#endif + spin_lock_init(&ip->ioc3_lock); - ioc3_stop(dev); - ip->emcr = 0; - ioc3_init(dev); - - init_timer(&ip->negtimer); - ioc3_mii_init(dev, ip, ioc3); - - phy = ip->phy; - if (phy == -1) { - printk(KERN_CRIT"%s: Didn't find a PHY, goodbye.\n", dev->name); + ioc3_stop(ip); + ioc3_init(ip); + + init_timer(&ip->ioc3_timer); + ioc3_mii_init(ip); + + if (ip->phy == -1) { + printk(KERN_CRIT "ioc3-eth(%s): Didn't find a PHY, goodbye.\n", + pdev->slot_name); err = -ENODEV; goto out_stop; } - mii0 = mii_read(ioc3, phy, 0); - mii_status = mii_read(ioc3, phy, 1); - mii2 = mii_read(ioc3, phy, 2); - mii3 = mii_read(ioc3, phy, 3); - mii4 = mii_read(ioc3, phy, 4); - vendor = (mii2 << 12) | (mii3 >> 4); - model = (mii3 >> 4) & 0x3f; - rev = mii3 & 0xf; - printk(KERN_INFO"Using PHY %d, vendor 0x%x, model %d, rev %d.\n", - phy, vendor, model, rev); - printk(KERN_INFO "%s: MII transceiver found at MDIO address " - "%d, config %4.4x status %4.4x.\n", - dev->name, phy, mii0, mii_status); - ioc3_ssram_disc(ip); - printk("IOC3 SSRAM has %d kbyte.\n", ip->emcr & EMCR_BUFSIZ ? 128 : 64); - - ioc3_get_eaddr(dev, ioc3); + ioc3_get_eaddr(ip); /* The IOC3-specific entries in the device structure. */ dev->open = ioc3_open; @@ -973,20 +1469,40 @@ dev->do_ioctl = ioc3_ioctl; dev->set_multicast_list = ioc3_set_multicast_list; + err = register_netdev(dev); + if (err) + goto out_stop; + + vendor = (ip->sw_physid1 << 12) | (ip->sw_physid2 >> 4); + model = (ip->sw_physid2 >> 4) & 0x3f; + rev = ip->sw_physid2 & 0xf; + printk(KERN_INFO "%s: Using PHY %d, vendor 0x%x, model %d, " + "rev %d.\n", dev->name, ip->phy, vendor, model, rev); + printk(KERN_INFO "%s: IOC3 SSRAM has %d kbyte.\n", dev->name, + ip->emcr & EMCR_BUFSIZ ? 128 : 64); + return 0; out_stop: - ioc3_stop(dev); + ioc3_stop(ip); free_irq(dev->irq, dev); ioc3_free_rings(ip); +out_res: + pci_release_regions(pdev); out_free: kfree(dev); return err; } -static void __devexit eepro100_remove_one (struct pci_dev *pdev) +static void __devexit ioc3_remove_one (struct pci_dev *pdev) { - /* Later ... */ + struct net_device *dev = pci_get_drvdata(pdev); + struct ioc3_private *ip = dev->priv; + struct ioc3 *ioc3 = ip->regs; + + iounmap(ioc3); + pci_release_regions(pdev); + kfree(dev); } static struct pci_device_id ioc3_pci_tbl[] __devinitdata = { @@ -999,7 +1515,7 @@ name: "ioc3-eth", id_table: ioc3_pci_tbl, probe: ioc3_probe, - /* remove: ioc3_remove_one, */ + remove: ioc3_remove_one, }; static int __init ioc3_init_module(void) @@ -1080,13 +1596,12 @@ static void ioc3_timeout(struct net_device *dev) { struct ioc3_private *ip = dev->priv; - struct ioc3 *ioc3 = ip->regs; printk(KERN_ERR "%s: transmit timed out, resetting\n", dev->name); - ioc3_stop(dev); - ioc3_init(dev); - ioc3_mii_init(dev, ip, ioc3); + ioc3_stop(ip); + ioc3_init(ip); + ioc3_mii_init(ip); dev->trans_start = jiffies; netif_wake_queue(dev); @@ -1096,7 +1611,7 @@ * Given a multicast ethernet address, this routine calculates the * address's bit index in the logical address filter mask */ -#define CRC_MASK 0xEDB88320 +#define CRC_MASK 0xedb88320 static inline unsigned int ioc3_hash(const unsigned char *addr) @@ -1128,37 +1643,126 @@ return temp; } -/* Provide ioctl() calls to examine the MII xcvr state. */ + +/* We provide both the mii-tools and the ethtool ioctls. */ static int ioc3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { struct ioc3_private *ip = dev->priv; + struct ethtool_cmd *ep_user = (struct ethtool_cmd *) rq->ifr_data; u16 *data = (u16 *)&rq->ifr_data; struct ioc3 *ioc3 = ip->regs; - int phy = ip->phy; + struct ethtool_cmd ecmd; switch (cmd) { case SIOCGMIIPHY: /* Get the address of the PHY in use. */ - if (phy == -1) + if (ip->phy == -1) return -ENODEV; - data[0] = phy; + data[0] = ip->phy; return 0; - case SIOCGMIIREG: /* Read any PHY register. */ + case SIOCGMIIREG: { /* Read a PHY register. */ + unsigned int phy = data[0]; + unsigned int reg = data[1]; + + if (phy > 0x1f || reg > 0x1f) + return -EINVAL; + spin_lock_irq(&ip->ioc3_lock); - data[3] = mii_read(ioc3, data[0], data[1]); + while (ioc3->micr & MICR_BUSY); + ioc3->micr = (phy << MICR_PHYADDR_SHIFT) | reg | MICR_READTRIG; + while (ioc3->micr & MICR_BUSY); + data[3] = (ioc3->midr_r & MIDR_DATA_MASK); spin_unlock_irq(&ip->ioc3_lock); + return 0; - case SIOCSMIIREG: /* Write any PHY register. */ + case SIOCSMIIREG: /* Write a PHY register. */ + phy = data[0]; + reg = data[1]; + if (!capable(CAP_NET_ADMIN)) return -EPERM; + + if (phy > 0x1f || reg > 0x1f) + return -EINVAL; + spin_lock_irq(&ip->ioc3_lock); - mii_write(ioc3, data[0], data[1], data[2]); + while (ioc3->micr & MICR_BUSY); + ioc3->midr_w = data[2]; + ioc3->micr = (phy << MICR_PHYADDR_SHIFT) | reg; + while (ioc3->micr & MICR_BUSY); spin_unlock_irq(&ip->ioc3_lock); + return 0; + } + case SIOCETHTOOL: + if (copy_from_user(&ecmd, ep_user, sizeof(ecmd))) + return -EFAULT; + + if (ecmd.cmd == ETHTOOL_GSET) { + ecmd.supported = + (SUPPORTED_10baseT_Half | + SUPPORTED_10baseT_Full | + SUPPORTED_100baseT_Half | + SUPPORTED_100baseT_Full | SUPPORTED_Autoneg | + SUPPORTED_TP | SUPPORTED_MII); + + ecmd.port = PORT_TP; + ecmd.transceiver = XCVR_INTERNAL; + ecmd.phy_address = ip->phy; + + /* Record PHY settings. */ + spin_lock_irq(&ip->ioc3_lock); + ip->sw_bmcr = mii_read(ip, MII_BMCR); + ip->sw_lpa = mii_read(ip, MII_LPA); + spin_unlock_irq(&ip->ioc3_lock); + if (ip->sw_bmcr & BMCR_ANENABLE) { + ecmd.autoneg = AUTONEG_ENABLE; + ecmd.speed = (ip->sw_lpa & + (LPA_100HALF | LPA_100FULL)) ? + SPEED_100 : SPEED_10; + if (ecmd.speed == SPEED_100) + ecmd.duplex = (ip->sw_lpa & (LPA_100FULL)) ? + DUPLEX_FULL : DUPLEX_HALF; + else + ecmd.duplex = (ip->sw_lpa & (LPA_10FULL)) ? + DUPLEX_FULL : DUPLEX_HALF; + } else { + ecmd.autoneg = AUTONEG_DISABLE; + ecmd.speed = (ip->sw_bmcr & BMCR_SPEED100) ? + SPEED_100 : SPEED_10; + ecmd.duplex = (ip->sw_bmcr & BMCR_FULLDPLX) ? + DUPLEX_FULL : DUPLEX_HALF; + } + if (copy_to_user(ep_user, &ecmd, sizeof(ecmd))) + return -EFAULT; + return 0; + } else if (ecmd.cmd == ETHTOOL_SSET) { + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + + /* Verify the settings we care about. */ + if (ecmd.autoneg != AUTONEG_ENABLE && + ecmd.autoneg != AUTONEG_DISABLE) + return -EINVAL; + + if (ecmd.autoneg == AUTONEG_DISABLE && + ((ecmd.speed != SPEED_100 && + ecmd.speed != SPEED_10) || + (ecmd.duplex != DUPLEX_HALF && + ecmd.duplex != DUPLEX_FULL))) + return -EINVAL; + + /* Ok, do it to it. */ + del_timer(&ip->ioc3_timer); + spin_lock_irq(&ip->ioc3_lock); + ioc3_start_auto_negotiation(ip, &ecmd); + spin_unlock_irq(&ip->ioc3_lock); - default: - return -EOPNOTSUPP; + return 0; + } else + default: + return -EOPNOTSUPP; } return -EOPNOTSUPP; @@ -1169,10 +1773,11 @@ struct dev_mc_list *dmi = dev->mc_list; struct ioc3_private *ip = dev->priv; struct ioc3 *ioc3 = ip->regs; - char *addr = dmi->dmi_addr; u64 ehar = 0; int i; + netif_stop_queue(dev); /* Lock out others. */ + if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */ /* Unconditionally log net taps. */ printk(KERN_INFO "%s: Promiscuous mode enabled.\n", dev->name); @@ -1192,6 +1797,7 @@ ip->ehar_l = 0xffffffff; } else { for (i = 0; i < dev->mc_count; i++) { + char *addr = dmi->dmi_addr; dmi = dmi->next; if (!(*addr & 1)) @@ -1205,6 +1811,8 @@ ioc3->ehar_h = ip->ehar_h; ioc3->ehar_l = ip->ehar_l; } + + netif_wake_queue(dev); /* Let us get going again. */ } MODULE_AUTHOR("Ralf Baechle <ralf@oss.sgi.com>"); diff -u --recursive --new-file v2.4.6/linux/drivers/net/irda/Config.in linux/drivers/net/irda/Config.in --- v2.4.6/linux/drivers/net/irda/Config.in Tue May 1 16:05:00 2001 +++ linux/drivers/net/irda/Config.in Wed Jul 4 11:50:38 2001 @@ -23,6 +23,7 @@ dep_tristate 'Toshiba Type-O IR Port' CONFIG_TOSHIBA_FIR $CONFIG_IRDA if [ "$CONFIG_EXPERIMENTAL" != "n" ]; then dep_tristate 'SMC IrCC (Experimental)' CONFIG_SMC_IRCC_FIR $CONFIG_IRDA +dep_tristate 'ALi M5123 FIR (Experimental)' CONFIG_ALI_FIR $CONFIG_IRDA fi endmenu diff -u --recursive --new-file v2.4.6/linux/drivers/net/irda/Makefile linux/drivers/net/irda/Makefile --- v2.4.6/linux/drivers/net/irda/Makefile Tue May 1 16:05:00 2001 +++ linux/drivers/net/irda/Makefile Wed Jul 4 11:50:38 2001 @@ -17,6 +17,7 @@ obj-$(CONFIG_WINBOND_FIR) += w83977af_ir.o obj-$(CONFIG_TOSHIBA_FIR) += toshoboe.o obj-$(CONFIG_SMC_IRCC_FIR) += smc-ircc.o irport.o +obj-$(CONFIG_ALI_FIR) += ali-ircc.o obj-$(CONFIG_ESI_DONGLE) += esi.o obj-$(CONFIG_TEKRAM_DONGLE) += tekram.o obj-$(CONFIG_ACTISYS_DONGLE) += actisys.o diff -u --recursive --new-file v2.4.6/linux/drivers/net/irda/ali-ircc.c linux/drivers/net/irda/ali-ircc.c --- v2.4.6/linux/drivers/net/irda/ali-ircc.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/irda/ali-ircc.c Wed Jul 4 11:50:38 2001 @@ -0,0 +1,2306 @@ +/********************************************************************* + * + * Filename: ali-ircc.h + * Version: 0.5 + * Description: Driver for the ALI M1535D and M1543C FIR Controller + * Status: Experimental. + * Author: Benjamin Kong <benjamin_kong@ali.com.tw> + * Created at: 2000/10/16 03:46PM + * Modified at: 2001/1/3 02:55PM + * Modified by: Benjamin Kong <benjamin_kong@ali.com.tw> + * + * Copyright (c) 2000 Benjamin Kong <benjamin_kong@ali.com.tw> + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + ********************************************************************/ + +#include <linux/module.h> + +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/skbuff.h> +#include <linux/netdevice.h> +#include <linux/ioport.h> +#include <linux/delay.h> +#include <linux/malloc.h> +#include <linux/init.h> +#include <linux/rtnetlink.h> +#include <linux/serial_reg.h> + +#include <asm/io.h> +#include <asm/dma.h> +#include <asm/byteorder.h> + +#include <linux/pm.h> + +#include <net/irda/wrapper.h> +#include <net/irda/irda.h> +#include <net/irda/irmod.h> +#include <net/irda/irlap_frame.h> +#include <net/irda/irda_device.h> + +#include <net/irda/ali-ircc.h> + +#define CHIP_IO_EXTENT 8 +#define BROKEN_DONGLE_ID + +static char *driver_name = "ali-ircc"; + +/* Module parameters */ +static int qos_mtt_bits = 0x07; /* 1 ms or more */ + +/* Use BIOS settions by default, but user may supply module parameters */ +static unsigned int io[] = { ~0, ~0, ~0, ~0 }; +static unsigned int irq[] = { 0, 0, 0, 0 }; +static unsigned int dma[] = { 0, 0, 0, 0 }; + +static int ali_ircc_probe_43(ali_chip_t *chip, chipio_t *info); +static int ali_ircc_probe_53(ali_chip_t *chip, chipio_t *info); +static int ali_ircc_init_43(ali_chip_t *chip, chipio_t *info); +static int ali_ircc_init_53(ali_chip_t *chip, chipio_t *info); + +/* These are the currently known ALi sourth-bridge chipsets, the only one difference + * is that M1543C doesn't support HP HDSL-3600 + */ +static ali_chip_t chips[] = +{ + { "M1543", { 0x3f0, 0x370 }, 0x51, 0x23, 0x20, 0x43, ali_ircc_probe_53, ali_ircc_init_43 }, + { "M1535", { 0x3f0, 0x370 }, 0x51, 0x23, 0x20, 0x53, ali_ircc_probe_53, ali_ircc_init_53 }, + { NULL } +}; + +/* Max 4 instances for now */ +static struct ali_ircc_cb *dev_self[] = { NULL, NULL, NULL, NULL }; + +/* Dongle Types */ +static char *dongle_types[] = { + "TFDS6000", + "HP HSDL-3600", + "HP HSDL-1100", + "No dongle connected", +}; + +/* Some prototypes */ +static int ali_ircc_open(int i, chipio_t *info); + +#ifdef MODULE +static int ali_ircc_close(struct ali_ircc_cb *self); +#endif /* MODULE */ + +static int ali_ircc_setup(chipio_t *info); +static int ali_ircc_is_receiving(struct ali_ircc_cb *self); +static int ali_ircc_net_init(struct net_device *dev); +static int ali_ircc_net_open(struct net_device *dev); +static int ali_ircc_net_close(struct net_device *dev); +static int ali_ircc_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); +static int ali_ircc_pmproc(struct pm_dev *dev, pm_request_t rqst, void *data); +static void ali_ircc_change_speed(struct ali_ircc_cb *self, __u32 baud); +static void ali_ircc_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static void ali_ircc_suspend(struct ali_ircc_cb *self); +static void ali_ircc_wakeup(struct ali_ircc_cb *self); +static struct net_device_stats *ali_ircc_net_get_stats(struct net_device *dev); + +/* SIR function */ +static int ali_ircc_sir_hard_xmit(struct sk_buff *skb, struct net_device *dev); +static void ali_ircc_sir_interrupt(int irq, struct ali_ircc_cb *self, struct pt_regs *regs); +static void ali_ircc_sir_receive(struct ali_ircc_cb *self); +static void ali_ircc_sir_write_wakeup(struct ali_ircc_cb *self); +static int ali_ircc_sir_write(int iobase, int fifo_size, __u8 *buf, int len); +static void ali_ircc_sir_change_speed(struct ali_ircc_cb *priv, __u32 speed); + +/* FIR function */ +static int ali_ircc_fir_hard_xmit(struct sk_buff *skb, struct net_device *dev); +static void ali_ircc_fir_change_speed(struct ali_ircc_cb *priv, __u32 speed); +static void ali_ircc_fir_interrupt(int irq, struct ali_ircc_cb *self, struct pt_regs *regs); +static int ali_ircc_dma_receive(struct ali_ircc_cb *self); +static int ali_ircc_dma_receive_complete(struct ali_ircc_cb *self); +static int ali_ircc_dma_xmit_complete(struct ali_ircc_cb *self); +static void ali_ircc_dma_xmit(struct ali_ircc_cb *self); + +/* My Function */ +static int ali_ircc_read_dongle_id (int i, chipio_t *info); +static void ali_ircc_change_dongle_speed(struct ali_ircc_cb *priv, int speed); + +/* ALi chip function */ +static void SIR2FIR(int iobase); +static void FIR2SIR(int iobase); +static void SetCOMInterrupts(struct ali_ircc_cb *self , unsigned char enable); + +/* + * Function ali_ircc_init () + * + * Initialize chip. Find out whay kinds of chips we are dealing with + * and their configuation registers address + */ +int __init ali_ircc_init(void) +{ + ali_chip_t *chip; + chipio_t info; + int ret = -ENODEV; + int cfg, cfg_base; + int reg, revision; + int i = 0; + + IRDA_DEBUG(2, __FUNCTION__ "(), ---------------- Start ----------------\n"); + + /* Probe for all the ALi chipsets we know about */ + for (chip= chips; chip->name; chip++, i++) + { + IRDA_DEBUG(2, __FUNCTION__"(), Probing for %s ...\n", chip->name); + + /* Try all config registers for this chip */ + for (cfg=0; cfg<2; cfg++) + { + cfg_base = chip->cfg[cfg]; + if (!cfg_base) + continue; + + memset(&info, 0, sizeof(chipio_t)); + info.cfg_base = cfg_base; + info.fir_base = io[i]; + info.dma = dma[i]; + info.irq = irq[i]; + + + /* Enter Configuration */ + outb(chip->entr1, cfg_base); + outb(chip->entr2, cfg_base); + + /* Select Logical Device 5 Registers (UART2) */ + outb(0x07, cfg_base); + outb(0x05, cfg_base+1); + + /* Read Chip Identification Register */ + outb(chip->cid_index, cfg_base); + reg = inb(cfg_base+1); + + if (reg == chip->cid_value) + { + IRDA_DEBUG(2, __FUNCTION__ + "(), Chip found at 0x%03x\n", cfg_base); + + outb(0x1F, cfg_base); + revision = inb(cfg_base+1); + IRDA_DEBUG(2, __FUNCTION__ + "(), Found %s chip, revision=%d\n", + chip->name, revision); + + /* + * If the user supplies the base address, then + * we init the chip, if not we probe the values + * set by the BIOS + */ + if (io[i] < 2000) + { + chip->init(chip, &info); + } + else + { + chip->probe(chip, &info); + } + + if (ali_ircc_open(i, &info) == 0) + ret = 0; + i++; + } + else + { + IRDA_DEBUG(2, __FUNCTION__ + "(), No %s chip at 0x%03x\n", chip->name, cfg_base); + } + /* Exit configuration */ + outb(0xbb, cfg_base); + } + } + + IRDA_DEBUG(2, __FUNCTION__ "(), ----------------- End -----------------\n"); + return ret; +} + +/* + * Function ali_ircc_cleanup () + * + * Close all configured chips + * + */ +#ifdef MODULE +static void ali_ircc_cleanup(void) +{ + int i; + + IRDA_DEBUG(2, __FUNCTION__ "(), ---------------- Start ----------------\n"); + + pm_unregister_all(ali_ircc_pmproc); + + for (i=0; i < 4; i++) { + if (dev_self[i]) + ali_ircc_close(dev_self[i]); + } + + IRDA_DEBUG(2, __FUNCTION__ "(), ----------------- End -----------------\n"); +} +#endif /* MODULE */ + +/* + * Function ali_ircc_open (int i, chipio_t *inf) + * + * Open driver instance + * + */ +static int ali_ircc_open(int i, chipio_t *info) +{ + struct net_device *dev; + struct ali_ircc_cb *self; + struct pm_dev *pmdev; + int dongle_id; + int ret; + int err; + + IRDA_DEBUG(2, __FUNCTION__ "(), ---------------- Start ----------------\n"); + + /* Set FIR FIFO and DMA Threshold */ + if ((ali_ircc_setup(info)) == -1) + return -1; + + /* Allocate new instance of the driver */ + self = kmalloc(sizeof(struct ali_ircc_cb), GFP_KERNEL); + if (self == NULL) + { + ERROR(__FUNCTION__ "(), can't allocate memory for control block!\n"); + return -ENOMEM; + } + memset(self, 0, sizeof(struct ali_ircc_cb)); + spin_lock_init(&self->lock); + + /* Need to store self somewhere */ + dev_self[i] = self; + self->index = i; + + /* Initialize IO */ + self->io.cfg_base = info->cfg_base; /* In ali_ircc_probe_53 assign */ + self->io.fir_base = info->fir_base; /* info->sir_base = info->fir_base */ + self->io.sir_base = info->sir_base; /* ALi SIR and FIR use the same address */ + self->io.irq = info->irq; + self->io.fir_ext = CHIP_IO_EXTENT; + self->io.dma = info->dma; + self->io.fifo_size = 16; /* SIR: 16, FIR: 32 Benjamin 2000/11/1 */ + + /* Reserve the ioports that we need */ + ret = check_region(self->io.fir_base, self->io.fir_ext); + if (ret < 0) { + WARNING(__FUNCTION__ "(), can't get iobase of 0x%03x\n", + self->io.fir_base); + dev_self[i] = NULL; + kfree(self); + return -ENODEV; + } + request_region(self->io.fir_base, self->io.fir_ext, driver_name); + + /* Initialize QoS for this device */ + irda_init_max_qos_capabilies(&self->qos); + + /* The only value we must override it the baudrate */ + self->qos.baud_rate.bits = IR_9600|IR_19200|IR_38400|IR_57600| + IR_115200|IR_576000|IR_1152000|(IR_4000000 << 8); // benjamin 2000/11/8 05:27PM + + self->qos.min_turn_time.bits = qos_mtt_bits; + + irda_qos_bits_to_value(&self->qos); + + self->flags = IFF_FIR|IFF_MIR|IFF_SIR|IFF_DMA|IFF_PIO; // benjamin 2000/11/8 05:27PM + + /* Max DMA buffer size needed = (data_size + 6) * (window_size) + 6; */ + self->rx_buff.truesize = 14384; + self->tx_buff.truesize = 14384; + + /* Allocate memory if needed */ + self->rx_buff.head = (__u8 *) kmalloc(self->rx_buff.truesize, + GFP_KERNEL |GFP_DMA); + if (self->rx_buff.head == NULL) + { + kfree(self); + return -ENOMEM; + } + memset(self->rx_buff.head, 0, self->rx_buff.truesize); + + self->tx_buff.head = (__u8 *) kmalloc(self->tx_buff.truesize, + GFP_KERNEL|GFP_DMA); + if (self->tx_buff.head == NULL) { + kfree(self); + kfree(self->rx_buff.head); + return -ENOMEM; + } + memset(self->tx_buff.head, 0, self->tx_buff.truesize); + + self->rx_buff.in_frame = FALSE; + self->rx_buff.state = OUTSIDE_FRAME; + self->tx_buff.data = self->tx_buff.head; + self->rx_buff.data = self->rx_buff.head; + + /* Reset Tx queue info */ + self->tx_fifo.len = self->tx_fifo.ptr = self->tx_fifo.free = 0; + self->tx_fifo.tail = self->tx_buff.head; + + if (!(dev = dev_alloc("irda%d", &err))) { + ERROR(__FUNCTION__ "(), dev_alloc() failed!\n"); + return -ENOMEM; + } + + dev->priv = (void *) self; + self->netdev = dev; + + /* Override the network functions we need to use */ + dev->init = ali_ircc_net_init; + dev->hard_start_xmit = ali_ircc_sir_hard_xmit; + dev->open = ali_ircc_net_open; + dev->stop = ali_ircc_net_close; + dev->do_ioctl = ali_ircc_net_ioctl; + dev->get_stats = ali_ircc_net_get_stats; + + rtnl_lock(); + err = register_netdevice(dev); + rtnl_unlock(); + if (err) { + ERROR(__FUNCTION__ "(), register_netdev() failed!\n"); + return -1; + } + MESSAGE("IrDA: Registered device %s\n", dev->name); + + /* Check dongle id */ + dongle_id = ali_ircc_read_dongle_id(i, info); + MESSAGE(__FUNCTION__ "(), %s, Found dongle: %s\n", driver_name, dongle_types[dongle_id]); + + self->io.dongle_id = dongle_id; + + pmdev = pm_register(PM_SYS_DEV, PM_SYS_IRDA, ali_ircc_pmproc); + if (pmdev) + pmdev->data = self; + + IRDA_DEBUG(2, __FUNCTION__ "(), ----------------- End -----------------\n"); + + return 0; +} + + +#ifdef MODULE +/* + * Function ali_ircc_close (self) + * + * Close driver instance + * + */ +static int ali_ircc_close(struct ali_ircc_cb *self) +{ + int iobase; + + IRDA_DEBUG(4, __FUNCTION__ "(), ---------------- Start ----------------\n"); + + ASSERT(self != NULL, return -1;); + + iobase = self->io.fir_base; + + /* Remove netdevice */ + if (self->netdev) { + rtnl_lock(); + unregister_netdevice(self->netdev); + rtnl_unlock(); + } + + /* Release the PORT that this driver is using */ + IRDA_DEBUG(4, __FUNCTION__ "(), Releasing Region %03x\n", self->io.fir_base); + release_region(self->io.fir_base, self->io.fir_ext); + + if (self->tx_buff.head) + kfree(self->tx_buff.head); + + if (self->rx_buff.head) + kfree(self->rx_buff.head); + + dev_self[self->index] = NULL; + kfree(self); + + IRDA_DEBUG(2, __FUNCTION__ "(), ----------------- End -----------------\n"); + + return 0; +} +#endif /* MODULE */ + +/* + * Function ali_ircc_init_43 (chip, info) + * + * Initialize the ALi M1543 chip. + */ +static int ali_ircc_init_43(ali_chip_t *chip, chipio_t *info) +{ + /* All controller information like I/O address, DMA channel, IRQ + * are set by BIOS + */ + + return 0; +} + +/* + * Function ali_ircc_init_53 (chip, info) + * + * Initialize the ALi M1535 chip. + */ +static int ali_ircc_init_53(ali_chip_t *chip, chipio_t *info) +{ + /* All controller information like I/O address, DMA channel, IRQ + * are set by BIOS + */ + + return 0; +} + +/* + * Function ali_ircc_probe_43 (chip, info) + * + * Probes for the ALi M1543 + */ +static int ali_ircc_probe_43(ali_chip_t *chip, chipio_t *info) +{ + return 0; +} + +/* + * Function ali_ircc_probe_53 (chip, info) + * + * Probes for the ALi M1535D or M1535 + */ +static int ali_ircc_probe_53(ali_chip_t *chip, chipio_t *info) +{ + int cfg_base = info->cfg_base; + int hi, low, reg; + + IRDA_DEBUG(2, __FUNCTION__ "(), ---------------- Start ----------------\n"); + + /* Enter Configuration */ + outb(chip->entr1, cfg_base); + outb(chip->entr2, cfg_base); + + /* Select Logical Device 5 Registers (UART2) */ + outb(0x07, cfg_base); + outb(0x05, cfg_base+1); + + /* Read address control register */ + outb(0x60, cfg_base); + hi = inb(cfg_base+1); + outb(0x61, cfg_base); + low = inb(cfg_base+1); + info->fir_base = (hi<<8) + low; + + info->sir_base = info->fir_base; + + IRDA_DEBUG(2, __FUNCTION__ "(), probing fir_base=0x%03x\n", info->fir_base); + + /* Read IRQ control register */ + outb(0x70, cfg_base); + reg = inb(cfg_base+1); + info->irq = reg & 0x0f; + IRDA_DEBUG(2, __FUNCTION__ "(), probing irq=%d\n", info->irq); + + /* Read DMA channel */ + outb(0x74, cfg_base); + reg = inb(cfg_base+1); + info->dma = reg & 0x07; + + if(info->dma == 0x04) + WARNING(__FUNCTION__ "(), No DMA channel assigned !\n"); + else + IRDA_DEBUG(2, __FUNCTION__ "(), probing dma=%d\n", info->dma); + + /* Read Enabled Status */ + outb(0x30, cfg_base); + reg = inb(cfg_base+1); + info->enabled = (reg & 0x80) && (reg & 0x01); + IRDA_DEBUG(2, __FUNCTION__ "(), probing enabled=%d\n", info->enabled); + + /* Read Power Status */ + outb(0x22, cfg_base); + reg = inb(cfg_base+1); + info->suspended = (reg & 0x20); + IRDA_DEBUG(2, __FUNCTION__ "(), probing suspended=%d\n", info->suspended); + + /* Exit configuration */ + outb(0xbb, cfg_base); + + IRDA_DEBUG(2, __FUNCTION__ "(), ----------------- End -----------------\n"); + + return 0; +} + +/* + * Function ali_ircc_setup (info) + * + * Set FIR FIFO and DMA Threshold + * Returns non-negative on success. + * + */ +static int ali_ircc_setup(chipio_t *info) +{ + unsigned char tmp; + int version; + int iobase = info->fir_base; + + IRDA_DEBUG(2, __FUNCTION__ "(), ---------------- Start ----------------\n"); + + /* Switch to FIR space */ + SIR2FIR(iobase); + + /* Master Reset */ + outb(0x40, iobase+FIR_MCR); // benjamin 2000/11/30 11:45AM + + /* Read FIR ID Version Register */ + switch_bank(iobase, BANK3); + version = inb(iobase+FIR_ID_VR); + + /* Should be 0x00 in the M1535/M1535D */ + if(version != 0x00) + { + ERROR("%s, Wrong chip version %02x\n", driver_name, version); + return -1; + } + + // MESSAGE("%s, Found chip at base=0x%03x\n", driver_name, info->cfg_base); + + /* Set FIR FIFO Threshold Register */ + switch_bank(iobase, BANK1); + outb(RX_FIFO_Threshold, iobase+FIR_FIFO_TR); + + /* Set FIR DMA Threshold Register */ + outb(RX_DMA_Threshold, iobase+FIR_DMA_TR); + + /* CRC enable */ + switch_bank(iobase, BANK2); + outb(inb(iobase+FIR_IRDA_CR) | IRDA_CR_CRC, iobase+FIR_IRDA_CR); + + /* NDIS driver set TX Length here BANK2 Alias 3, Alias4*/ + + /* Switch to Bank 0 */ + switch_bank(iobase, BANK0); + + tmp = inb(iobase+FIR_LCR_B); + tmp &=~0x20; // disable SIP + tmp |= 0x80; // these two steps make RX mode + tmp &= 0xbf; + outb(tmp, iobase+FIR_LCR_B); + + /* Disable Interrupt */ + outb(0x00, iobase+FIR_IER); + + + /* Switch to SIR space */ + FIR2SIR(iobase); + + MESSAGE("%s, driver loaded (Benjamin Kong)\n", driver_name); + + /* Enable receive interrupts */ + // outb(UART_IER_RDI, iobase+UART_IER); //benjamin 2000/11/23 01:25PM + // Turn on the interrupts in ali_ircc_net_open + + IRDA_DEBUG(2, __FUNCTION__ "(), ----------------- End ------------------\n"); + + return 0; +} + +/* + * Function ali_ircc_read_dongle_id (int index, info) + * + * Try to read dongle indentification. This procedure needs to be executed + * once after power-on/reset. It also needs to be used whenever you suspect + * that the user may have plugged/unplugged the IrDA Dongle. + */ +static int ali_ircc_read_dongle_id (int i, chipio_t *info) +{ + int dongle_id, reg; + int cfg_base = info->cfg_base; + + IRDA_DEBUG(2, __FUNCTION__ "(), ---------------- Start ----------------\n"); + + /* Enter Configuration */ + outb(chips[i].entr1, cfg_base); + outb(chips[i].entr2, cfg_base); + + /* Select Logical Device 5 Registers (UART2) */ + outb(0x07, cfg_base); + outb(0x05, cfg_base+1); + + /* Read Dongle ID */ + outb(0xf0, cfg_base); + reg = inb(cfg_base+1); + dongle_id = ((reg>>6)&0x02) | ((reg>>5)&0x01); + IRDA_DEBUG(2, __FUNCTION__ "(), probing dongle_id=%d, dongle_types=%s\n", + dongle_id, dongle_types[dongle_id]); + + /* Exit configuration */ + outb(0xbb, cfg_base); + + IRDA_DEBUG(2, __FUNCTION__ "(), ----------------- End ------------------\n"); + + return dongle_id; +} + +/* + * Function ali_ircc_interrupt (irq, dev_id, regs) + * + * An interrupt from the chip has arrived. Time to do some work + * + */ +static void ali_ircc_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct net_device *dev = (struct net_device *) dev_id; + struct ali_ircc_cb *self; + + IRDA_DEBUG(2, __FUNCTION__ "(), ---------------- Start ----------------\n"); + + if (!dev) { + WARNING("%s: irq %d for unknown device.\n", driver_name, irq); + return; + } + + self = (struct ali_ircc_cb *) dev->priv; + + spin_lock(&self->lock); + + /* Dispatch interrupt handler for the current speed */ + if (self->io.speed > 115200) + ali_ircc_fir_interrupt(irq, self, regs); + else + ali_ircc_sir_interrupt(irq, self, regs); + + spin_unlock(&self->lock); + + IRDA_DEBUG(2, __FUNCTION__ "(), ----------------- End ------------------\n"); +} +/* + * Function ali_ircc_fir_interrupt(irq, struct ali_ircc_cb *self, regs) + * + * Handle MIR/FIR interrupt + * + */ +static void ali_ircc_fir_interrupt(int irq, struct ali_ircc_cb *self, struct pt_regs *regs) +{ + __u8 eir, OldMessageCount; + int iobase, tmp; + + IRDA_DEBUG(1, __FUNCTION__ "(), ---------------- Start ----------------\n"); + + iobase = self->io.fir_base; + + switch_bank(iobase, BANK0); + self->InterruptID = inb(iobase+FIR_IIR); + self->BusStatus = inb(iobase+FIR_BSR); + + OldMessageCount = (self->LineStatus + 1) & 0x07; + self->LineStatus = inb(iobase+FIR_LSR); + //self->ier = inb(iobase+FIR_IER); 2000/12/1 04:32PM + eir = self->InterruptID & self->ier; /* Mask out the interesting ones */ + + IRDA_DEBUG(1, __FUNCTION__ "(), self->InterruptID = %x\n",self->InterruptID); + IRDA_DEBUG(1, __FUNCTION__ "(), self->LineStatus = %x\n",self->LineStatus); + IRDA_DEBUG(1, __FUNCTION__ "(), self->ier = %x\n",self->ier); + IRDA_DEBUG(1, __FUNCTION__ "(), eir = %x\n",eir); + + /* Disable interrupts */ + SetCOMInterrupts(self, FALSE); + + /* Tx or Rx Interrupt */ + + if (eir & IIR_EOM) + { + if (self->io.direction == IO_XMIT) /* TX */ + { + IRDA_DEBUG(1, __FUNCTION__ "(), ******* IIR_EOM (Tx) *******\n"); + + if(ali_ircc_dma_xmit_complete(self)) + { + if (irda_device_txqueue_empty(self->netdev)) + { + /* Prepare for receive */ + ali_ircc_dma_receive(self); + self->ier = IER_EOM; + } + } + else + { + self->ier = IER_EOM; + } + + } + else /* RX */ + { + IRDA_DEBUG(1, __FUNCTION__ "(), ******* IIR_EOM (Rx) *******\n"); + + if(OldMessageCount > ((self->LineStatus+1) & 0x07)) + { + self->rcvFramesOverflow = TRUE; + IRDA_DEBUG(1, __FUNCTION__ "(), ******* self->rcvFramesOverflow = TRUE ******** \n"); + } + + if (ali_ircc_dma_receive_complete(self)) + { + IRDA_DEBUG(1, __FUNCTION__ "(), ******* receive complete ******** \n"); + + self->ier = IER_EOM; + } + else + { + IRDA_DEBUG(1, __FUNCTION__ "(), ******* Not receive complete ******** \n"); + + self->ier = IER_EOM | IER_TIMER; + } + + } + } + /* Timer Interrupt */ + else if (eir & IIR_TIMER) + { + if(OldMessageCount > ((self->LineStatus+1) & 0x07)) + { + self->rcvFramesOverflow = TRUE; + IRDA_DEBUG(1, __FUNCTION__ "(), ******* self->rcvFramesOverflow = TRUE ******* \n"); + } + /* Disable Timer */ + switch_bank(iobase, BANK1); + tmp = inb(iobase+FIR_CR); + outb( tmp& ~CR_TIMER_EN, iobase+FIR_CR); + + /* Check if this is a Tx timer interrupt */ + if (self->io.direction == IO_XMIT) + { + ali_ircc_dma_xmit(self); + + /* Interrupt on EOM */ + self->ier = IER_EOM; + + } + else /* Rx */ + { + if(ali_ircc_dma_receive_complete(self)) + { + self->ier = IER_EOM; + } + else + { + self->ier = IER_EOM | IER_TIMER; + } + } + } + + /* Restore Interrupt */ + SetCOMInterrupts(self, TRUE); + + IRDA_DEBUG(1, __FUNCTION__ "(), ----------------- End ---------------\n"); +} + +/* + * Function ali_ircc_sir_interrupt (irq, self, eir) + * + * Handle SIR interrupt + * + */ +static void ali_ircc_sir_interrupt(int irq, struct ali_ircc_cb *self, struct pt_regs *regs) +{ + int iobase; + int iir, lsr; + + IRDA_DEBUG(2, __FUNCTION__ "(), ---------------- Start ----------------\n"); + + iobase = self->io.sir_base; + + iir = inb(iobase+UART_IIR) & UART_IIR_ID; + if (iir) { + /* Clear interrupt */ + lsr = inb(iobase+UART_LSR); + + IRDA_DEBUG(4, __FUNCTION__ + "(), iir=%02x, lsr=%02x, iobase=%#x\n", + iir, lsr, iobase); + + switch (iir) + { + case UART_IIR_RLSI: + IRDA_DEBUG(2, __FUNCTION__ "(), RLSI\n"); + break; + case UART_IIR_RDI: + /* Receive interrupt */ + ali_ircc_sir_receive(self); + break; + case UART_IIR_THRI: + if (lsr & UART_LSR_THRE) + { + /* Transmitter ready for data */ + ali_ircc_sir_write_wakeup(self); + } + break; + default: + IRDA_DEBUG(0, __FUNCTION__ "(), unhandled IIR=%#x\n", iir); + break; + } + + } + + + IRDA_DEBUG(2, __FUNCTION__ "(), ----------------- End ------------------\n"); +} + + +/* + * Function ali_ircc_sir_receive (self) + * + * Receive one frame from the infrared port + * + */ +static void ali_ircc_sir_receive(struct ali_ircc_cb *self) +{ + int boguscount = 0; + int iobase; + + IRDA_DEBUG(2, __FUNCTION__ "(), ---------------- Start ----------------\n"); + ASSERT(self != NULL, return;); + + iobase = self->io.sir_base; + + /* + * Receive all characters in Rx FIFO, unwrap and unstuff them. + * async_unwrap_char will deliver all found frames + */ + do { + async_unwrap_char(self->netdev, &self->stats, &self->rx_buff, + inb(iobase+UART_RX)); + + /* Make sure we don't stay here to long */ + if (boguscount++ > 32) { + IRDA_DEBUG(2,__FUNCTION__ "(), breaking!\n"); + break; + } + } while (inb(iobase+UART_LSR) & UART_LSR_DR); + + IRDA_DEBUG(2, __FUNCTION__ "(), ----------------- End ------------------\n"); +} + +/* + * Function ali_ircc_sir_write_wakeup (tty) + * + * Called by the driver when there's room for more data. If we have + * more packets to send, we send them here. + * + */ +static void ali_ircc_sir_write_wakeup(struct ali_ircc_cb *self) +{ + int actual = 0; + int iobase; + + ASSERT(self != NULL, return;); + + IRDA_DEBUG(2, __FUNCTION__ "(), ---------------- Start ----------------\n"); + + iobase = self->io.sir_base; + + /* Finished with frame? */ + if (self->tx_buff.len > 0) + { + /* Write data left in transmit buffer */ + actual = ali_ircc_sir_write(iobase, self->io.fifo_size, + self->tx_buff.data, self->tx_buff.len); + self->tx_buff.data += actual; + self->tx_buff.len -= actual; + } + else + { + if (self->new_speed) + { + /* We must wait until all data are gone */ + while(!(inb(iobase+UART_LSR) & UART_LSR_TEMT)) + IRDA_DEBUG(1, __FUNCTION__ "(), UART_LSR_THRE\n"); + + IRDA_DEBUG(1, __FUNCTION__ "(), Changing speed! self->new_speed = %d\n", self->new_speed); + ali_ircc_change_speed(self, self->new_speed); + self->new_speed = 0; + + // benjamin 2000/11/10 06:32PM + if (self->io.speed > 115200) + { + IRDA_DEBUG(2, __FUNCTION__ "(), ali_ircc_change_speed from UART_LSR_TEMT \n"); + + self->ier = IER_EOM; + // SetCOMInterrupts(self, TRUE); + return; + } + } + else + { + netif_wake_queue(self->netdev); + } + + self->stats.tx_packets++; + + /* Turn on receive interrupts */ + outb(UART_IER_RDI, iobase+UART_IER); + } + + IRDA_DEBUG(2, __FUNCTION__ "(), ----------------- End ------------------\n"); +} + +static void ali_ircc_change_speed(struct ali_ircc_cb *self, __u32 baud) +{ + struct net_device *dev = self->netdev; + int iobase; + + IRDA_DEBUG(1, __FUNCTION__ "(), ---------------- Start ----------------\n"); + + IRDA_DEBUG(2, __FUNCTION__ "(), setting speed = %d \n", baud); + + iobase = self->io.fir_base; + + SetCOMInterrupts(self, FALSE); // 2000/11/24 11:43AM + + /* Go to MIR, FIR Speed */ + if (baud > 115200) + { + + + ali_ircc_fir_change_speed(self, baud); + + /* Install FIR xmit handler*/ + dev->hard_start_xmit = ali_ircc_fir_hard_xmit; + + /* Enable Interuupt */ + self->ier = IER_EOM; // benjamin 2000/11/20 07:24PM + + /* Be ready for incomming frames */ + ali_ircc_dma_receive(self); // benajmin 2000/11/8 07:46PM not complete + } + /* Go to SIR Speed */ + else + { + ali_ircc_sir_change_speed(self, baud); + + /* Install SIR xmit handler*/ + dev->hard_start_xmit = ali_ircc_sir_hard_xmit; + } + + + SetCOMInterrupts(self, TRUE); // 2000/11/24 11:43AM + + netif_wake_queue(self->netdev); + + IRDA_DEBUG(2, __FUNCTION__ "(), ----------------- End ------------------\n"); +} + +static void ali_ircc_fir_change_speed(struct ali_ircc_cb *priv, __u32 baud) +{ + + int iobase; + struct ali_ircc_cb *self = (struct ali_ircc_cb *) priv; + struct net_device *dev; + + IRDA_DEBUG(1, __FUNCTION__ "(), ---------------- Start ----------------\n"); + + ASSERT(self != NULL, return;); + + dev = self->netdev; + iobase = self->io.fir_base; + + IRDA_DEBUG(1, __FUNCTION__ "(), self->io.speed = %d, change to speed = %d\n",self->io.speed,baud); + + /* Come from SIR speed */ + if(self->io.speed <=115200) + { + SIR2FIR(iobase); + } + + /* Update accounting for new speed */ + self->io.speed = baud; + + // Set Dongle Speed mode + ali_ircc_change_dongle_speed(self, baud); + + IRDA_DEBUG(1, __FUNCTION__ "(), ----------------- End ------------------\n"); +} + +/* + * Function ali_sir_change_speed (self, speed) + * + * Set speed of IrDA port to specified baudrate + * + */ +static void ali_ircc_sir_change_speed(struct ali_ircc_cb *priv, __u32 speed) +{ + struct ali_ircc_cb *self = (struct ali_ircc_cb *) priv; + unsigned long flags; + int iobase; + int fcr; /* FIFO control reg */ + int lcr; /* Line control reg */ + int divisor; + + IRDA_DEBUG(1, __FUNCTION__ "(), ---------------- Start ----------------\n"); + + IRDA_DEBUG(1, __FUNCTION__ "(), Setting speed to: %d\n", speed); + + ASSERT(self != NULL, return;); + + iobase = self->io.sir_base; + + /* Come from MIR or FIR speed */ + if(self->io.speed >115200) + { + // Set Dongle Speed mode first + ali_ircc_change_dongle_speed(self, speed); + + FIR2SIR(iobase); + } + + // Clear Line and Auxiluary status registers 2000/11/24 11:47AM + + inb(iobase+UART_LSR); + inb(iobase+UART_SCR); + + /* Update accounting for new speed */ + self->io.speed = speed; + + spin_lock_irqsave(&self->lock, flags); + + divisor = 115200/speed; + + fcr = UART_FCR_ENABLE_FIFO; + + /* + * Use trigger level 1 to avoid 3 ms. timeout delay at 9600 bps, and + * almost 1,7 ms at 19200 bps. At speeds above that we can just forget + * about this timeout since it will always be fast enough. + */ + if (self->io.speed < 38400) + fcr |= UART_FCR_TRIGGER_1; + else + fcr |= UART_FCR_TRIGGER_14; + + /* IrDA ports use 8N1 */ + lcr = UART_LCR_WLEN8; + + outb(UART_LCR_DLAB | lcr, iobase+UART_LCR); /* Set DLAB */ + outb(divisor & 0xff, iobase+UART_DLL); /* Set speed */ + outb(divisor >> 8, iobase+UART_DLM); + outb(lcr, iobase+UART_LCR); /* Set 8N1 */ + outb(fcr, iobase+UART_FCR); /* Enable FIFO's */ + + /* without this, the conection will be broken after come back from FIR speed, + but with this, the SIR connection is harder to established */ + outb((UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2), iobase+UART_MCR); + + spin_unlock_irqrestore(&self->lock, flags); + + IRDA_DEBUG(1, __FUNCTION__ "(), ----------------- End ------------------\n"); +} + +static void ali_ircc_change_dongle_speed(struct ali_ircc_cb *priv, int speed) +{ + + struct ali_ircc_cb *self = (struct ali_ircc_cb *) priv; + int iobase,dongle_id; + unsigned long flags; + int tmp = 0; + + IRDA_DEBUG(1, __FUNCTION__ "(), ---------------- Start ----------------\n"); + + iobase = self->io.fir_base; /* or iobase = self->io.sir_base; */ + dongle_id = self->io.dongle_id; + + save_flags(flags); + cli(); + + IRDA_DEBUG(1, __FUNCTION__ "(), Set Speed for %s , Speed = %d\n", dongle_types[dongle_id], speed); + + switch_bank(iobase, BANK2); + tmp = inb(iobase+FIR_IRDA_CR); + + /* IBM type dongle */ + if(dongle_id == 0) + { + if(speed == 4000000) + { + // __ __ + // SD/MODE __| |__ __ + // __ __ + // IRTX __ __| |__ + // T1 T2 T3 T4 T5 + + tmp &= ~IRDA_CR_HDLC; // HDLC=0 + tmp |= IRDA_CR_CRC; // CRC=1 + + switch_bank(iobase, BANK2); + outb(tmp, iobase+FIR_IRDA_CR); + + // T1 -> SD/MODE:0 IRTX:0 + tmp &= ~0x09; + tmp |= 0x02; + outb(tmp, iobase+FIR_IRDA_CR); + udelay(2); + + // T2 -> SD/MODE:1 IRTX:0 + tmp &= ~0x01; + tmp |= 0x0a; + outb(tmp, iobase+FIR_IRDA_CR); + udelay(2); + + // T3 -> SD/MODE:1 IRTX:1 + tmp |= 0x0b; + outb(tmp, iobase+FIR_IRDA_CR); + udelay(2); + + // T4 -> SD/MODE:0 IRTX:1 + tmp &= ~0x08; + tmp |= 0x03; + outb(tmp, iobase+FIR_IRDA_CR); + udelay(2); + + // T5 -> SD/MODE:0 IRTX:0 + tmp &= ~0x09; + tmp |= 0x02; + outb(tmp, iobase+FIR_IRDA_CR); + udelay(2); + + // reset -> Normal TX output Signal + outb(tmp & ~0x02, iobase+FIR_IRDA_CR); + } + else /* speed <=1152000 */ + { + // __ + // SD/MODE __| |__ + // + // IRTX ________ + // T1 T2 T3 + + /* MIR 115200, 57600 */ + if (speed==1152000) + { + tmp |= 0xA0; //HDLC=1, 1.152Mbps=1 + } + else + { + tmp &=~0x80; //HDLC 0.576Mbps + tmp |= 0x20; //HDLC=1, + } + + tmp |= IRDA_CR_CRC; // CRC=1 + + switch_bank(iobase, BANK2); + outb(tmp, iobase+FIR_IRDA_CR); + + /* MIR 115200, 57600 */ + + //switch_bank(iobase, BANK2); + // T1 -> SD/MODE:0 IRTX:0 + tmp &= ~0x09; + tmp |= 0x02; + outb(tmp, iobase+FIR_IRDA_CR); + udelay(2); + + // T2 -> SD/MODE:1 IRTX:0 + tmp &= ~0x01; + tmp |= 0x0a; + outb(tmp, iobase+FIR_IRDA_CR); + + // T3 -> SD/MODE:0 IRTX:0 + tmp &= ~0x09; + tmp |= 0x02; + outb(tmp, iobase+FIR_IRDA_CR); + udelay(2); + + // reset -> Normal TX output Signal + outb(tmp & ~0x02, iobase+FIR_IRDA_CR); + } + } + else if (dongle_id == 1) /* HP HDSL-3600 */ + { + switch(speed) + { + case 4000000: + tmp &= ~IRDA_CR_HDLC; // HDLC=0 + break; + + case 1152000: + tmp |= 0xA0; // HDLC=1, 1.152Mbps=1 + break; + + case 576000: + tmp &=~0x80; // HDLC 0.576Mbps + tmp |= 0x20; // HDLC=1, + break; + } + + tmp |= IRDA_CR_CRC; // CRC=1 + + switch_bank(iobase, BANK2); + outb(tmp, iobase+FIR_IRDA_CR); + } + else /* HP HDSL-1100 */ + { + if(speed <= 115200) /* SIR */ + { + + tmp &= ~IRDA_CR_FIR_SIN; // HP sin select = 0 + + switch_bank(iobase, BANK2); + outb(tmp, iobase+FIR_IRDA_CR); + } + else /* MIR FIR */ + { + + switch(speed) + { + case 4000000: + tmp &= ~IRDA_CR_HDLC; // HDLC=0 + break; + + case 1152000: + tmp |= 0xA0; // HDLC=1, 1.152Mbps=1 + break; + + case 576000: + tmp &=~0x80; // HDLC 0.576Mbps + tmp |= 0x20; // HDLC=1, + break; + } + + tmp |= IRDA_CR_CRC; // CRC=1 + tmp |= IRDA_CR_FIR_SIN; // HP sin select = 1 + + switch_bank(iobase, BANK2); + outb(tmp, iobase+FIR_IRDA_CR); + } + } + + switch_bank(iobase, BANK0); + + restore_flags(flags); + + IRDA_DEBUG(1, __FUNCTION__ "(), ----------------- End ------------------\n"); +} + +/* + * Function ali_ircc_sir_write (driver) + * + * Fill Tx FIFO with transmit data + * + */ +static int ali_ircc_sir_write(int iobase, int fifo_size, __u8 *buf, int len) +{ + int actual = 0; + + IRDA_DEBUG(2, __FUNCTION__ "(), ---------------- Start ----------------\n"); + + /* Tx FIFO should be empty! */ + if (!(inb(iobase+UART_LSR) & UART_LSR_THRE)) { + IRDA_DEBUG(0, __FUNCTION__ "(), failed, fifo not empty!\n"); + return 0; + } + + /* Fill FIFO with current frame */ + while ((fifo_size-- > 0) && (actual < len)) { + /* Transmit next byte */ + outb(buf[actual], iobase+UART_TX); + + actual++; + } + + IRDA_DEBUG(2, __FUNCTION__ "(), ----------------- End ------------------\n"); + return actual; +} + +/* + * Function ali_ircc_net_init (dev) + * + * Initialize network device + * + */ +static int ali_ircc_net_init(struct net_device *dev) +{ + IRDA_DEBUG(2, __FUNCTION__ "(), ---------------- Start ----------------\n"); + + /* Setup to be a normal IrDA network device driver */ + irda_device_setup(dev); + + /* Insert overrides below this line! */ + + IRDA_DEBUG(2, __FUNCTION__ "(), ----------------- End ------------------\n"); + + return 0; +} + +/* + * Function ali_ircc_net_open (dev) + * + * Start the device + * + */ +static int ali_ircc_net_open(struct net_device *dev) +{ + struct ali_ircc_cb *self; + int iobase; + + IRDA_DEBUG(2, __FUNCTION__ "(), ---------------- Start ----------------\n"); + + ASSERT(dev != NULL, return -1;); + + self = (struct ali_ircc_cb *) dev->priv; + + ASSERT(self != NULL, return 0;); + + iobase = self->io.fir_base; + + /* Request IRQ and install Interrupt Handler */ + if (request_irq(self->io.irq, ali_ircc_interrupt, 0, dev->name, dev)) + { + WARNING("%s, unable to allocate irq=%d\n", driver_name, + self->io.irq); + return -EAGAIN; + } + + /* + * Always allocate the DMA channel after the IRQ, and clean up on + * failure. + */ + if (request_dma(self->io.dma, dev->name)) { + WARNING("%s, unable to allocate dma=%d\n", driver_name, + self->io.dma); + free_irq(self->io.irq, self); + return -EAGAIN; + } + + /* Turn on interrups */ + outb(UART_IER_RLSI | UART_IER_RDI |UART_IER_THRI, iobase+UART_IER); + + /* Ready to play! */ + netif_start_queue(dev); //benjamin by irport + + /* + * Open new IrLAP layer instance, now that everything should be + * initialized properly + */ + self->irlap = irlap_open(dev, &self->qos); + + MOD_INC_USE_COUNT; + + IRDA_DEBUG(2, __FUNCTION__ "(), ----------------- End ------------------\n"); + + return 0; +} + +/* + * Function ali_ircc_net_close (dev) + * + * Stop the device + * + */ +static int ali_ircc_net_close(struct net_device *dev) +{ + + struct ali_ircc_cb *self; + //int iobase; + + IRDA_DEBUG(4, __FUNCTION__ "(), ---------------- Start ----------------\n"); + + ASSERT(dev != NULL, return -1;); + + self = (struct ali_ircc_cb *) dev->priv; + ASSERT(self != NULL, return 0;); + + /* Stop device */ + netif_stop_queue(dev); + + /* Stop and remove instance of IrLAP */ + if (self->irlap) + irlap_close(self->irlap); + self->irlap = NULL; + + disable_dma(self->io.dma); + + /* Disable interrupts */ + SetCOMInterrupts(self, FALSE); + + free_irq(self->io.irq, dev); + free_dma(self->io.dma); + + MOD_DEC_USE_COUNT; + + IRDA_DEBUG(2, __FUNCTION__ "(), ----------------- End ------------------\n"); + + return 0; +} + +/* + * Function ali_ircc_fir_hard_xmit (skb, dev) + * + * Transmit the frame + * + */ +static int ali_ircc_fir_hard_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct ali_ircc_cb *self; + unsigned long flags; + int iobase; + __u32 speed; + int mtt, diff; + + IRDA_DEBUG(1, __FUNCTION__ "(), ---------------- Start -----------------\n"); + + self = (struct ali_ircc_cb *) dev->priv; + iobase = self->io.fir_base; + + netif_stop_queue(dev); + + /* Check if we need to change the speed */ + speed = irda_get_next_speed(skb); + if ((speed != self->io.speed) && (speed != -1)) { + /* Check for empty frame */ + if (!skb->len) { + ali_ircc_change_speed(self, speed); + dev_kfree_skb(skb); + return 0; + } else + self->new_speed = speed; + } + + spin_lock_irqsave(&self->lock, flags); + + /* Register and copy this frame to DMA memory */ + self->tx_fifo.queue[self->tx_fifo.free].start = self->tx_fifo.tail; + self->tx_fifo.queue[self->tx_fifo.free].len = skb->len; + self->tx_fifo.tail += skb->len; + + self->stats.tx_bytes += skb->len; + + memcpy(self->tx_fifo.queue[self->tx_fifo.free].start, skb->data, + skb->len); + + self->tx_fifo.len++; + self->tx_fifo.free++; + + /* Start transmit only if there is currently no transmit going on */ + if (self->tx_fifo.len == 1) + { + /* Check if we must wait the min turn time or not */ + mtt = irda_get_mtt(skb); + + if (mtt) + { + /* Check how much time we have used already */ + get_fast_time(&self->now); + + diff = self->now.tv_usec - self->stamp.tv_usec; + /* self->stamp is set from ali_ircc_dma_receive_complete() */ + + IRDA_DEBUG(1, __FUNCTION__ "(), ******* diff = %d ******* \n", diff); + + if (diff < 0) + diff += 1000000; + + /* Check if the mtt is larger than the time we have + * already used by all the protocol processing + */ + if (mtt > diff) + { + mtt -= diff; + + /* + * Use timer if delay larger than 1000 us, and + * use udelay for smaller values which should + * be acceptable + */ + if (mtt > 500) + { + /* Adjust for timer resolution */ + mtt = (mtt+250) / 500; /* 4 discard, 5 get advanced, Let's round off */ + + IRDA_DEBUG(1, __FUNCTION__ "(), ************** mtt = %d ***********\n", mtt); + + /* Setup timer */ + if (mtt == 1) /* 500 us */ + { + switch_bank(iobase, BANK1); + outb(TIMER_IIR_500, iobase+FIR_TIMER_IIR); + } + else if (mtt == 2) /* 1 ms */ + { + switch_bank(iobase, BANK1); + outb(TIMER_IIR_1ms, iobase+FIR_TIMER_IIR); + } + else /* > 2ms -> 4ms */ + { + switch_bank(iobase, BANK1); + outb(TIMER_IIR_2ms, iobase+FIR_TIMER_IIR); + } + + + /* Start timer */ + outb(inb(iobase+FIR_CR) | CR_TIMER_EN, iobase+FIR_CR); + self->io.direction = IO_XMIT; + + /* Enable timer interrupt */ + self->ier = IER_TIMER; + SetCOMInterrupts(self, TRUE); + + /* Timer will take care of the rest */ + goto out; + } + else + udelay(mtt); + } // if (if (mtt > diff) + }// if (mtt) + + /* Enable EOM interrupt */ + self->ier = IER_EOM; + SetCOMInterrupts(self, TRUE); + + /* Transmit frame */ + ali_ircc_dma_xmit(self); + } // if (self->tx_fifo.len == 1) + + out: + + /* Not busy transmitting anymore if window is not full */ + if (self->tx_fifo.free < MAX_TX_WINDOW) + netif_wake_queue(self->netdev); + + /* Restore bank register */ + switch_bank(iobase, BANK0); + + spin_unlock_irqrestore(&self->lock, flags); + dev_kfree_skb(skb); + + IRDA_DEBUG(1, __FUNCTION__ "(), ----------------- End ------------------\n"); + return 0; +} + + +static void ali_ircc_dma_xmit(struct ali_ircc_cb *self) +{ + int iobase, tmp; + unsigned char FIFO_OPTI, Hi, Lo; + + + IRDA_DEBUG(1, __FUNCTION__ "(), ---------------- Start -----------------\n"); + + iobase = self->io.fir_base; + + /* FIFO threshold , this method comes from NDIS5 code */ + + if(self->tx_fifo.queue[self->tx_fifo.ptr].len < TX_FIFO_Threshold) + FIFO_OPTI = self->tx_fifo.queue[self->tx_fifo.ptr].len-1; + else + FIFO_OPTI = TX_FIFO_Threshold; + + /* Disable DMA */ + switch_bank(iobase, BANK1); + outb(inb(iobase+FIR_CR) & ~CR_DMA_EN, iobase+FIR_CR); + + self->io.direction = IO_XMIT; + + setup_dma(self->io.dma, + self->tx_fifo.queue[self->tx_fifo.ptr].start, + self->tx_fifo.queue[self->tx_fifo.ptr].len, + DMA_TX_MODE); + + /* Reset Tx FIFO */ + switch_bank(iobase, BANK0); + outb(LCR_A_FIFO_RESET, iobase+FIR_LCR_A); + + /* Set Tx FIFO threshold */ + if (self->fifo_opti_buf!=FIFO_OPTI) + { + switch_bank(iobase, BANK1); + outb(FIFO_OPTI, iobase+FIR_FIFO_TR) ; + self->fifo_opti_buf=FIFO_OPTI; + } + + /* Set Tx DMA threshold */ + switch_bank(iobase, BANK1); + outb(TX_DMA_Threshold, iobase+FIR_DMA_TR); + + /* Set max Tx frame size */ + Hi = (self->tx_fifo.queue[self->tx_fifo.ptr].len >> 8) & 0x0f; + Lo = self->tx_fifo.queue[self->tx_fifo.ptr].len & 0xff; + switch_bank(iobase, BANK2); + outb(Hi, iobase+FIR_TX_DSR_HI); + outb(Lo, iobase+FIR_TX_DSR_LO); + + /* Disable SIP , Disable Brick Wall (we don't support in TX mode), Change to TX mode */ + switch_bank(iobase, BANK0); + tmp = inb(iobase+FIR_LCR_B); + tmp &= ~0x20; // Disable SIP + outb(((unsigned char)(tmp & 0x3f) | LCR_B_TX_MODE) & ~LCR_B_BW, iobase+FIR_LCR_B); + IRDA_DEBUG(1, __FUNCTION__ "(), ******* Change to TX mode: FIR_LCR_B = 0x%x ******* \n", inb(iobase+FIR_LCR_B)); + + outb(0, iobase+FIR_LSR); + + /* Enable DMA and Burst Mode */ + switch_bank(iobase, BANK1); + outb(inb(iobase+FIR_CR) | CR_DMA_EN | CR_DMA_BURST, iobase+FIR_CR); + + switch_bank(iobase, BANK0); + + IRDA_DEBUG(1, __FUNCTION__ "(), ----------------- End ------------------\n"); +} + +static int ali_ircc_dma_xmit_complete(struct ali_ircc_cb *self) +{ + int iobase; + int ret = TRUE; + + IRDA_DEBUG(1, __FUNCTION__ "(), ---------------- Start -----------------\n"); + + iobase = self->io.fir_base; + + /* Disable DMA */ + switch_bank(iobase, BANK1); + outb(inb(iobase+FIR_CR) & ~CR_DMA_EN, iobase+FIR_CR); + + /* Check for underrun! */ + switch_bank(iobase, BANK0); + if((inb(iobase+FIR_LSR) & LSR_FRAME_ABORT) == LSR_FRAME_ABORT) + + { + ERROR(__FUNCTION__ "(), ********* LSR_FRAME_ABORT *********\n"); + self->stats.tx_errors++; + self->stats.tx_fifo_errors++; + } + else + { + self->stats.tx_packets++; + } + + /* Check if we need to change the speed */ + if (self->new_speed) + { + ali_ircc_change_speed(self, self->new_speed); + self->new_speed = 0; + } + + /* Finished with this frame, so prepare for next */ + self->tx_fifo.ptr++; + self->tx_fifo.len--; + + /* Any frames to be sent back-to-back? */ + if (self->tx_fifo.len) + { + ali_ircc_dma_xmit(self); + + /* Not finished yet! */ + ret = FALSE; + } + else + { /* Reset Tx FIFO info */ + self->tx_fifo.len = self->tx_fifo.ptr = self->tx_fifo.free = 0; + self->tx_fifo.tail = self->tx_buff.head; + } + + /* Make sure we have room for more frames */ + if (self->tx_fifo.free < MAX_TX_WINDOW) { + /* Not busy transmitting anymore */ + /* Tell the network layer, that we can accept more frames */ + netif_wake_queue(self->netdev); + } + + switch_bank(iobase, BANK0); + + IRDA_DEBUG(1, __FUNCTION__ "(), ----------------- End ------------------\n"); + return ret; +} + +/* + * Function ali_ircc_dma_receive (self) + * + * Get ready for receiving a frame. The device will initiate a DMA + * if it starts to receive a frame. + * + */ +static int ali_ircc_dma_receive(struct ali_ircc_cb *self) +{ + int iobase, tmp; + + IRDA_DEBUG(1, __FUNCTION__ "(), ---------------- Start -----------------\n"); + + iobase = self->io.fir_base; + + /* Reset Tx FIFO info */ + self->tx_fifo.len = self->tx_fifo.ptr = self->tx_fifo.free = 0; + self->tx_fifo.tail = self->tx_buff.head; + + /* Disable DMA */ + switch_bank(iobase, BANK1); + outb(inb(iobase+FIR_CR) & ~CR_DMA_EN, iobase+FIR_CR); + + /* Reset Message Count */ + switch_bank(iobase, BANK0); + outb(0x07, iobase+FIR_LSR); + + self->rcvFramesOverflow = FALSE; + + self->LineStatus = inb(iobase+FIR_LSR) ; + + /* Reset Rx FIFO info */ + self->io.direction = IO_RECV; + self->rx_buff.data = self->rx_buff.head; + + /* Reset Rx FIFO */ + // switch_bank(iobase, BANK0); + outb(LCR_A_FIFO_RESET, iobase+FIR_LCR_A); + + self->st_fifo.len = self->st_fifo.pending_bytes = 0; + self->st_fifo.tail = self->st_fifo.head = 0; + + setup_dma(self->io.dma, self->rx_buff.data, self->rx_buff.truesize, + DMA_RX_MODE); + + /* Set Receive Mode,Brick Wall */ + //switch_bank(iobase, BANK0); + tmp = inb(iobase+FIR_LCR_B); + outb((unsigned char)(tmp &0x3f) | LCR_B_RX_MODE | LCR_B_BW , iobase + FIR_LCR_B); // 2000/12/1 05:16PM + IRDA_DEBUG(1, __FUNCTION__ "(), *** Change To RX mode: FIR_LCR_B = 0x%x *** \n", inb(iobase+FIR_LCR_B)); + + /* Set Rx Threshold */ + switch_bank(iobase, BANK1); + outb(RX_FIFO_Threshold, iobase+FIR_FIFO_TR); + outb(RX_DMA_Threshold, iobase+FIR_DMA_TR); + + /* Enable DMA and Burst Mode */ + // switch_bank(iobase, BANK1); + outb(CR_DMA_EN | CR_DMA_BURST, iobase+FIR_CR); + + switch_bank(iobase, BANK0); + IRDA_DEBUG(1, __FUNCTION__ "(), ----------------- End ------------------\n"); + return 0; +} + +static int ali_ircc_dma_receive_complete(struct ali_ircc_cb *self) +{ + struct st_fifo *st_fifo; + struct sk_buff *skb; + __u8 status, MessageCount; + int len, i, iobase, val; + + IRDA_DEBUG(1, __FUNCTION__ "(), ---------------- Start -----------------\n"); + + st_fifo = &self->st_fifo; + iobase = self->io.fir_base; + + switch_bank(iobase, BANK0); + MessageCount = inb(iobase+ FIR_LSR)&0x07; + + if (MessageCount > 0) + IRDA_DEBUG(0, __FUNCTION__ "(), Messsage count = %d,\n", MessageCount); + + for (i=0; i<=MessageCount; i++) + { + /* Bank 0 */ + switch_bank(iobase, BANK0); + status = inb(iobase+FIR_LSR); + + switch_bank(iobase, BANK2); + len = inb(iobase+FIR_RX_DSR_HI) & 0x0f; + len = len << 8; + len |= inb(iobase+FIR_RX_DSR_LO); + + IRDA_DEBUG(1, __FUNCTION__ "(), RX Length = 0x%.2x,\n", len); + IRDA_DEBUG(1, __FUNCTION__ "(), RX Status = 0x%.2x,\n", status); + + if (st_fifo->tail >= MAX_RX_WINDOW) { + IRDA_DEBUG(0, __FUNCTION__ "(), window is full!\n"); + continue; + } + + st_fifo->entries[st_fifo->tail].status = status; + st_fifo->entries[st_fifo->tail].len = len; + st_fifo->pending_bytes += len; + st_fifo->tail++; + st_fifo->len++; + } + + for (i=0; i<=MessageCount; i++) + { + /* Get first entry */ + status = st_fifo->entries[st_fifo->head].status; + len = st_fifo->entries[st_fifo->head].len; + st_fifo->pending_bytes -= len; + st_fifo->head++; + st_fifo->len--; + + /* Check for errors */ + if ((status & 0xd8) || self->rcvFramesOverflow || (len==0)) + { + IRDA_DEBUG(0,__FUNCTION__ "(), ************* RX Errors ************ \n"); + + /* Skip frame */ + self->stats.rx_errors++; + + self->rx_buff.data += len; + + if (status & LSR_FIFO_UR) + { + self->stats.rx_frame_errors++; + IRDA_DEBUG(0,__FUNCTION__ "(), ************* FIFO Errors ************ \n"); + } + if (status & LSR_FRAME_ERROR) + { + self->stats.rx_frame_errors++; + IRDA_DEBUG(0,__FUNCTION__ "(), ************* FRAME Errors ************ \n"); + } + + if (status & LSR_CRC_ERROR) + { + self->stats.rx_crc_errors++; + IRDA_DEBUG(0,__FUNCTION__ "(), ************* CRC Errors ************ \n"); + } + + if(self->rcvFramesOverflow) + { + self->stats.rx_frame_errors++; + IRDA_DEBUG(0,__FUNCTION__ "(), ************* Overran DMA buffer ************ \n"); + } + if(len == 0) + { + self->stats.rx_frame_errors++; + IRDA_DEBUG(0,__FUNCTION__ "(), ********** Receive Frame Size = 0 ********* \n"); + } + } + else + { + + if (st_fifo->pending_bytes < 32) + { + switch_bank(iobase, BANK0); + val = inb(iobase+FIR_BSR); + if ((val& BSR_FIFO_NOT_EMPTY)== 0x80) + { + IRDA_DEBUG(0, __FUNCTION__ "(), ************* BSR_FIFO_NOT_EMPTY ************ \n"); + + /* Put this entry back in fifo */ + st_fifo->head--; + st_fifo->len++; + st_fifo->pending_bytes += len; + st_fifo->entries[st_fifo->head].status = status; + st_fifo->entries[st_fifo->head].len = len; + + /* + * DMA not finished yet, so try again + * later, set timer value, resolution + * 500 us + */ + + switch_bank(iobase, BANK1); + outb(TIMER_IIR_500, iobase+FIR_TIMER_IIR); // 2001/1/2 05:07PM + + /* Enable Timer */ + outb(inb(iobase+FIR_CR) | CR_TIMER_EN, iobase+FIR_CR); + + return FALSE; /* I'll be back! */ + } + } + + /* + * Remember the time we received this frame, so we can + * reduce the min turn time a bit since we will know + * how much time we have used for protocol processing + */ + get_fast_time(&self->stamp); + + skb = dev_alloc_skb(len+1); + if (skb == NULL) + { + WARNING(__FUNCTION__ "(), memory squeeze, " + "dropping frame.\n"); + self->stats.rx_dropped++; + + return FALSE; + } + + /* Make sure IP header gets aligned */ + skb_reserve(skb, 1); + + /* Copy frame without CRC, CRC is removed by hardware*/ + skb_put(skb, len); + memcpy(skb->data, self->rx_buff.data, len); + + /* Move to next frame */ + self->rx_buff.data += len; + self->stats.rx_bytes += len; + self->stats.rx_packets++; + + skb->dev = self->netdev; + skb->mac.raw = skb->data; + skb->protocol = htons(ETH_P_IRDA); + netif_rx(skb); + } + } + + switch_bank(iobase, BANK0); + + IRDA_DEBUG(1, __FUNCTION__ "(), ----------------- End ------------------\n"); + return TRUE; +} + + + +/* + * Function ali_ircc_sir_hard_xmit (skb, dev) + * + * Transmit the frame! + * + */ +static int ali_ircc_sir_hard_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct ali_ircc_cb *self; + unsigned long flags; + int iobase; + __u32 speed; + + IRDA_DEBUG(2, __FUNCTION__ "(), ---------------- Start ----------------\n"); + + ASSERT(dev != NULL, return 0;); + + self = (struct ali_ircc_cb *) dev->priv; + ASSERT(self != NULL, return 0;); + + iobase = self->io.sir_base; + + netif_stop_queue(dev); + + /* Check if we need to change the speed */ + speed = irda_get_next_speed(skb); + if ((speed != self->io.speed) && (speed != -1)) { + /* Check for empty frame */ + if (!skb->len) { + ali_ircc_change_speed(self, speed); + dev_kfree_skb(skb); + return 0; + } else + self->new_speed = speed; + } + + spin_lock_irqsave(&self->lock, flags); + + /* Init tx buffer */ + self->tx_buff.data = self->tx_buff.head; + + /* Copy skb to tx_buff while wrapping, stuffing and making CRC */ + self->tx_buff.len = async_wrap_skb(skb, self->tx_buff.data, + self->tx_buff.truesize); + + self->stats.tx_bytes += self->tx_buff.len; + + /* Turn on transmit finished interrupt. Will fire immediately! */ + outb(UART_IER_THRI, iobase+UART_IER); + + spin_unlock_irqrestore(&self->lock, flags); + + dev_kfree_skb(skb); + + IRDA_DEBUG(2, __FUNCTION__ "(), ----------------- End ------------------\n"); + + return 0; +} + + +/* + * Function ali_ircc_net_ioctl (dev, rq, cmd) + * + * Process IOCTL commands for this device + * + */ +static int ali_ircc_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +{ + struct if_irda_req *irq = (struct if_irda_req *) rq; + struct ali_ircc_cb *self; + unsigned long flags; + int ret = 0; + + IRDA_DEBUG(2, __FUNCTION__ "(), ---------------- Start ----------------\n"); + + ASSERT(dev != NULL, return -1;); + + self = dev->priv; + + ASSERT(self != NULL, return -1;); + + IRDA_DEBUG(2, __FUNCTION__ "(), %s, (cmd=0x%X)\n", dev->name, cmd); + + /* Disable interrupts & save flags */ + save_flags(flags); + cli(); + + switch (cmd) { + case SIOCSBANDWIDTH: /* Set bandwidth */ + IRDA_DEBUG(1, __FUNCTION__ "(), SIOCSBANDWIDTH\n"); + /* + * This function will also be used by IrLAP to change the + * speed, so we still must allow for speed change within + * interrupt context. + */ + if (!in_interrupt() && !capable(CAP_NET_ADMIN)) + return -EPERM; + + ali_ircc_change_speed(self, irq->ifr_baudrate); + break; + case SIOCSMEDIABUSY: /* Set media busy */ + IRDA_DEBUG(1, __FUNCTION__ "(), SIOCSMEDIABUSY\n"); + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + irda_device_set_media_busy(self->netdev, TRUE); + break; + case SIOCGRECEIVING: /* Check if we are receiving right now */ + IRDA_DEBUG(2, __FUNCTION__ "(), SIOCGRECEIVING\n"); + irq->ifr_receiving = ali_ircc_is_receiving(self); + break; + default: + ret = -EOPNOTSUPP; + } + + restore_flags(flags); + + IRDA_DEBUG(2, __FUNCTION__ "(), ----------------- End ------------------\n"); + + return ret; +} + +/* + * Function ali_ircc_is_receiving (self) + * + * Return TRUE is we are currently receiving a frame + * + */ +static int ali_ircc_is_receiving(struct ali_ircc_cb *self) +{ + unsigned long flags; + int status = FALSE; + int iobase; + + IRDA_DEBUG(2, __FUNCTION__ "(), ---------------- Start -----------------\n"); + + ASSERT(self != NULL, return FALSE;); + + spin_lock_irqsave(&self->lock, flags); + + if (self->io.speed > 115200) + { + iobase = self->io.fir_base; + + switch_bank(iobase, BANK1); + if((inb(iobase+FIR_FIFO_FR) & 0x3f) != 0) + { + /* We are receiving something */ + IRDA_DEBUG(1, __FUNCTION__ "(), We are receiving something\n"); + status = TRUE; + } + switch_bank(iobase, BANK0); + } + else + { + status = (self->rx_buff.state != OUTSIDE_FRAME); + } + + spin_unlock_irqrestore(&self->lock, flags); + + IRDA_DEBUG(2, __FUNCTION__ "(), ----------------- End ------------------\n"); + + return status; +} + +static struct net_device_stats *ali_ircc_net_get_stats(struct net_device *dev) +{ + struct ali_ircc_cb *self = (struct ali_ircc_cb *) dev->priv; + + IRDA_DEBUG(2, __FUNCTION__ "(), ---------------- Start ----------------\n"); + + IRDA_DEBUG(2, __FUNCTION__ "(), ----------------- End ------------------\n"); + + return &self->stats; +} + +static void ali_ircc_suspend(struct ali_ircc_cb *self) +{ + IRDA_DEBUG(2, __FUNCTION__ "(), ---------------- Start ----------------\n"); + + MESSAGE("%s, Suspending\n", driver_name); + + if (self->io.suspended) + return; + + ali_ircc_net_close(self->netdev); + + self->io.suspended = 1; + + IRDA_DEBUG(2, __FUNCTION__ "(), ----------------- End ------------------\n"); +} + +static void ali_ircc_wakeup(struct ali_ircc_cb *self) +{ + IRDA_DEBUG(2, __FUNCTION__ "(), ---------------- Start ----------------\n"); + + if (!self->io.suspended) + return; + + ali_ircc_net_open(self->netdev); + + MESSAGE("%s, Waking up\n", driver_name); + + self->io.suspended = 0; + + IRDA_DEBUG(2, __FUNCTION__ "(), ----------------- End ------------------\n"); +} + +static int ali_ircc_pmproc(struct pm_dev *dev, pm_request_t rqst, void *data) +{ + struct ali_ircc_cb *self = (struct ali_ircc_cb*) dev->data; + + IRDA_DEBUG(2, __FUNCTION__ "(), ---------------- Start ----------------\n"); + + if (self) { + switch (rqst) { + case PM_SUSPEND: + ali_ircc_suspend(self); + break; + case PM_RESUME: + ali_ircc_wakeup(self); + break; + } + } + + IRDA_DEBUG(2, __FUNCTION__ "(), ----------------- End ------------------\n"); + + return 0; +} + + +/* ALi Chip Function */ + +static void SetCOMInterrupts(struct ali_ircc_cb *self , unsigned char enable) +{ + + unsigned char newMask; + + int iobase = self->io.fir_base; /* or sir_base */ + + IRDA_DEBUG(2, __FUNCTION__ "(), -------- Start -------- ( Enable = %d )\n", enable); + + /* Enable the interrupt which we wish to */ + if (enable){ + if (self->io.direction == IO_XMIT) + { + if (self->io.speed > 115200) /* FIR, MIR */ + { + newMask = self->ier; + } + else /* SIR */ + { + newMask = UART_IER_THRI | UART_IER_RDI; + } + } + else { + if (self->io.speed > 115200) /* FIR, MIR */ + { + newMask = self->ier; + } + else /* SIR */ + { + newMask = UART_IER_RDI; + } + } + } + else /* Disable all the interrupts */ + { + newMask = 0x00; + + } + + //SIR and FIR has different registers + if (self->io.speed > 115200) + { + switch_bank(iobase, BANK0); + outb(newMask, iobase+FIR_IER); + } + else + outb(newMask, iobase+UART_IER); + + IRDA_DEBUG(2, __FUNCTION__ "(), ----------------- End ------------------\n"); +} + +static void SIR2FIR(int iobase) +{ + //unsigned char tmp; + unsigned long flags; + + IRDA_DEBUG(1, __FUNCTION__ "(), ---------------- Start ----------------\n"); + + save_flags(flags); + cli(); + + outb(0x28, iobase+UART_MCR); + outb(0x68, iobase+UART_MCR); + outb(0x88, iobase+UART_MCR); + + restore_flags(flags); + + outb(0x60, iobase+FIR_MCR); /* Master Reset */ + outb(0x20, iobase+FIR_MCR); /* Master Interrupt Enable */ + + //tmp = inb(iobase+FIR_LCR_B); /* SIP enable */ + //tmp |= 0x20; + //outb(tmp, iobase+FIR_LCR_B); + + IRDA_DEBUG(1, __FUNCTION__ "(), ----------------- End ------------------\n"); +} + +static void FIR2SIR(int iobase) +{ + unsigned char val; + unsigned long flags; + + IRDA_DEBUG(1, __FUNCTION__ "(), ---------------- Start ----------------\n"); + + save_flags(flags); + cli(); + + outb(0x20, iobase+FIR_MCR); /* IRQ to low */ + outb(0x00, iobase+UART_IER); + + outb(0xA0, iobase+FIR_MCR); /* Don't set master reset */ + outb(0x00, iobase+UART_FCR); + outb(0x07, iobase+UART_FCR); + + val = inb(iobase+UART_RX); + val = inb(iobase+UART_LSR); + val = inb(iobase+UART_MSR); + + restore_flags(flags); + + IRDA_DEBUG(1, __FUNCTION__ "(), ----------------- End ------------------\n"); +} + +#ifdef MODULE +MODULE_AUTHOR("Benjamin Kong <benjamin_kong@ali.com.tw>"); +MODULE_DESCRIPTION("ALi FIR Controller Driver"); + +MODULE_PARM(io, "1-4i"); +MODULE_PARM_DESC(io, "Base I/O addresses"); +MODULE_PARM(irq, "1-4i"); +MODULE_PARM_DESC(irq, "IRQ lines"); +MODULE_PARM(dma, "1-4i"); +MODULE_PARM_DESC(dma, "DMA channels"); + +int init_module(void) +{ + return ali_ircc_init(); +} + +void cleanup_module(void) +{ + ali_ircc_cleanup(); +} +#endif /* MODULE */ diff -u --recursive --new-file v2.4.6/linux/drivers/net/irda/irport.c linux/drivers/net/irda/irport.c --- v2.4.6/linux/drivers/net/irda/irport.c Tue Mar 20 12:04:59 2001 +++ linux/drivers/net/irda/irport.c Wed Jul 4 11:50:38 2001 @@ -951,13 +951,17 @@ switch (cmd) { case SIOCSBANDWIDTH: /* Set bandwidth */ if (!capable(CAP_NET_ADMIN)) - return -EPERM; - irda_task_execute(self, __irport_change_speed, NULL, NULL, - (void *) irq->ifr_baudrate); + ret = -EPERM; + else + irda_task_execute(self, __irport_change_speed, NULL, + NULL, (void *) irq->ifr_baudrate); break; case SIOCSDONGLE: /* Set dongle */ - if (!capable(CAP_NET_ADMIN)) - return -EPERM; + if (!capable(CAP_NET_ADMIN)) { + ret = -EPERM; + break; + } + /* Initialize dongle */ dongle = irda_device_dongle_init(dev, irq->ifr_dongle); if (!dongle) @@ -978,16 +982,22 @@ NULL); break; case SIOCSMEDIABUSY: /* Set media busy */ - if (!capable(CAP_NET_ADMIN)) - return -EPERM; + if (!capable(CAP_NET_ADMIN)) { + ret = -EPERM; + break; + } + irda_device_set_media_busy(self->netdev, TRUE); break; case SIOCGRECEIVING: /* Check if we are receiving right now */ irq->ifr_receiving = irport_is_receiving(self); break; case SIOCSDTRRTS: - if (!capable(CAP_NET_ADMIN)) - return -EPERM; + if (!capable(CAP_NET_ADMIN)) { + ret = -EPERM; + break; + } + irport_set_dtr_rts(dev, irq->ifr_dtr, irq->ifr_rts); break; default: diff -u --recursive --new-file v2.4.6/linux/drivers/net/irda/irtty.c linux/drivers/net/irda/irtty.c --- v2.4.6/linux/drivers/net/irda/irtty.c Tue Mar 20 12:04:59 2001 +++ linux/drivers/net/irda/irtty.c Wed Jul 4 11:50:38 2001 @@ -971,13 +971,17 @@ switch (cmd) { case SIOCSBANDWIDTH: /* Set bandwidth */ if (!capable(CAP_NET_ADMIN)) - return -EPERM; - irda_task_execute(self, irtty_change_speed, NULL, NULL, - (void *) irq->ifr_baudrate); + ret = -EPERM; + else + irda_task_execute(self, irtty_change_speed, NULL, NULL, + (void *) irq->ifr_baudrate); break; case SIOCSDONGLE: /* Set dongle */ - if (!capable(CAP_NET_ADMIN)) - return -EPERM; + if (!capable(CAP_NET_ADMIN)) { + ret = -EPERM; + break; + } + /* Initialize dongle */ dongle = irda_device_dongle_init(dev, irq->ifr_dongle); if (!dongle) @@ -999,21 +1003,24 @@ break; case SIOCSMEDIABUSY: /* Set media busy */ if (!capable(CAP_NET_ADMIN)) - return -EPERM; - irda_device_set_media_busy(self->netdev, TRUE); + ret = -EPERM; + else + irda_device_set_media_busy(self->netdev, TRUE); break; case SIOCGRECEIVING: /* Check if we are receiving right now */ irq->ifr_receiving = irtty_is_receiving(self); break; case SIOCSDTRRTS: if (!capable(CAP_NET_ADMIN)) - return -EPERM; - irtty_set_dtr_rts(dev, irq->ifr_dtr, irq->ifr_rts); + ret = -EPERM; + else + irtty_set_dtr_rts(dev, irq->ifr_dtr, irq->ifr_rts); break; case SIOCSMODE: if (!capable(CAP_NET_ADMIN)) - return -EPERM; - irtty_set_mode(dev, irq->ifr_mode); + ret = -EPERM; + else + irtty_set_mode(dev, irq->ifr_mode); break; default: ret = -EOPNOTSUPP; diff -u --recursive --new-file v2.4.6/linux/drivers/net/irda/nsc-ircc.c linux/drivers/net/irda/nsc-ircc.c --- v2.4.6/linux/drivers/net/irda/nsc-ircc.c Tue May 1 16:05:00 2001 +++ linux/drivers/net/irda/nsc-ircc.c Wed Jul 4 11:50:38 2001 @@ -90,7 +90,7 @@ static nsc_chip_t chips[] = { { "PC87108", { 0x150, 0x398, 0xea }, 0x05, 0x10, 0xf0, nsc_ircc_probe_108, nsc_ircc_init_108 }, - { "PC87338", { 0x398, 0x15c, 0x2e }, 0x08, 0xb0, 0xf0, + { "PC87338", { 0x398, 0x15c, 0x2e }, 0x08, 0xb0, 0xf8, nsc_ircc_probe_338, nsc_ircc_init_338 }, { NULL } }; @@ -160,7 +160,7 @@ int i = 0; /* Probe for all the NSC chipsets we know about */ - for (chip=chips; chip->name ; chip++,i++) { + for (chip=chips; chip->name ; chip++) { IRDA_DEBUG(2, __FUNCTION__"(), Probing for %s ...\n", chip->name); @@ -196,7 +196,7 @@ * we init the chip, if not we probe the values * set by the BIOS */ - if (io[i] < 2000) { + if (io[i] < 0x2000) { chip->init(chip, &info); } else chip->probe(chip, &info); @@ -602,7 +602,7 @@ outb(CFG_PNP0, cfg_base); reg = inb(cfg_base+1); - pnp = (reg >> 4) & 0x01; + pnp = (reg >> 3) & 0x01; if (pnp) { IRDA_DEBUG(2, "(), Chip is in PnP mode\n"); outb(0x46, cfg_base); diff -u --recursive --new-file v2.4.6/linux/drivers/net/irda/smc-ircc.c linux/drivers/net/irda/smc-ircc.c --- v2.4.6/linux/drivers/net/irda/smc-ircc.c Tue Mar 20 12:04:59 2001 +++ linux/drivers/net/irda/smc-ircc.c Wed Jul 4 11:50:38 2001 @@ -98,6 +98,8 @@ { "FDC37N769", 0x55, 0x55, 0x0d, 0x28, ircc_probe_69 }, { "FDC37N869", 0x55, 0x00, 0x0d, 0x29, ircc_probe_69 }, { "FDC37N958", 0x55, 0x55, 0x20, 0x09, ircc_probe_58 }, + { "FDC37N971", 0x55, 0x55, 0x20, 0x0a, ircc_probe_58 }, + { "FDC37N972", 0x55, 0x55, 0x20, 0x0b, ircc_probe_58 }, { NULL } }; @@ -127,7 +129,7 @@ IRDA_DEBUG(0, __FUNCTION__ "\n"); /* Probe for all the NSC chipsets we know about */ - for (chip=chips; chip->name ; chip++,i++) { + for (chip=chips; chip->name ; chip++) { for (i=0; i<2; i++) { info.cfg_base = smcreg[i]; @@ -136,7 +138,7 @@ * parameters which we should use instead of probed * values */ - if (io[i] < 2000) { + if (io[i] < 0x2000) { info.fir_base = io[i]; info.sir_base = io2[i]; } else if (chip->probe(chip, &info) < 0) diff -u --recursive --new-file v2.4.6/linux/drivers/net/irda/toshoboe.c linux/drivers/net/irda/toshoboe.c --- v2.4.6/linux/drivers/net/irda/toshoboe.c Tue May 1 16:05:00 2001 +++ linux/drivers/net/irda/toshoboe.c Wed Jul 4 11:50:38 2001 @@ -43,9 +43,6 @@ /* Define this to enable FIR and MIR support */ #define ENABLE_FAST -/* Number of ports this driver can support, you also need to edit dev_self below */ -#define NSELFS 4 - /* Size of IO window */ #define CHIP_IO_EXTENT 0x1f @@ -77,7 +74,6 @@ #include <net/irda/irda_device.h> #include <linux/pm.h> -static int toshoboe_pmproc (struct pm_dev *dev, pm_request_t rqst, void *data); #include <net/irda/toshoboe.h> @@ -92,8 +88,6 @@ static const char *driver_name = "toshoboe"; -static struct toshoboe_cb *dev_self[NSELFS + 1]; - static int max_baud = 4000000; /* Shutdown the chip and point the taskfile reg somewhere else */ @@ -644,21 +638,20 @@ return ret; } -#ifdef MODULE - MODULE_DESCRIPTION("Toshiba OBOE IrDA Device Driver"); MODULE_AUTHOR("James McKenzie <james@fishsoup.dhs.org>"); MODULE_PARM (max_baud, "i"); MODULE_PARM_DESC(max_baus, "Maximum baud rate"); -static int -toshoboe_close (struct toshoboe_cb *self) +static void +toshoboe_remove (struct pci_dev *pci_dev) { int i; + struct toshoboe_cb *self = (struct toshoboe_cb*)pci_get_drvdata(pci_dev); IRDA_DEBUG (4, __FUNCTION__ "()\n"); - ASSERT (self != NULL, return -1; + ASSERT (self != NULL, return; ); if (!self->stopped) @@ -693,16 +686,12 @@ self->taskfilebuf = NULL; self->taskfile = NULL; - return (0); + return; } -#endif - - - static int -toshoboe_open (struct pci_dev *pci_dev) +toshoboe_probe (struct pci_dev *pci_dev, const struct pci_device_id *pdid) { struct toshoboe_cb *self; struct net_device *dev; @@ -713,15 +702,6 @@ IRDA_DEBUG (4, __FUNCTION__ "()\n"); - while (dev_self[i]) - i++; - - if (i == NSELFS) - { - printk (KERN_ERR "Oboe: No more instances available"); - return -ENOMEM; - } - if ((err=pci_enable_device(pci_dev))) return err; @@ -736,12 +716,10 @@ memset (self, 0, sizeof (struct toshoboe_cb)); - dev_self[i] = self; /*This needs moving if we ever get more than one chip */ - self->open = 0; self->stopped = 0; self->pdev = pci_dev; - self->base = pci_dev->resource[0].start; + self->base = pci_resource_start(pci_dev,0); self->io.sir_base = self->base; self->io.irq = pci_dev->irq; @@ -749,19 +727,15 @@ self->io.speed = 9600; /* Lock the port that we need */ - i = check_region (self->io.sir_base, self->io.sir_ext); - if (i < 0) + if (NULL==request_region (self->io.sir_base, self->io.sir_ext, driver_name)) { IRDA_DEBUG (0, __FUNCTION__ "(), can't get iobase of 0x%03x\n", self->io.sir_base); - dev_self[i] = NULL; - kfree (self); - - return -ENODEV; + err = -EBUSY; + goto freeself; } - irda_init_max_qos_capabilies (&self->qos); self->qos.baud_rate.bits = 0; @@ -804,8 +778,8 @@ if (!self->taskfilebuf) { printk (KERN_ERR "toshoboe: kmalloc for DMA failed()\n"); - kfree (self); - return -ENOMEM; + err = -ENOMEM; + goto freeregion; } @@ -839,25 +813,16 @@ if (ok != RX_SLOTS + TX_SLOTS) { printk (KERN_ERR "toshoboe: kmalloc for buffers failed()\n"); + err = -ENOMEM; + goto freebufs; + } - for (i = 0; i < TX_SLOTS; ++i) - if (self->xmit_bufs[i]) - kfree (self->xmit_bufs[i]); - for (i = 0; i < RX_SLOTS; ++i) - if (self->recv_bufs[i]) - kfree (self->recv_bufs[i]); - - kfree (self); - return -ENOMEM; - - } - - request_region (self->io.sir_base, self->io.sir_ext, driver_name); if (!(dev = dev_alloc("irda%d", &err))) { - ERROR(__FUNCTION__ "(), dev_alloc() failed!\n"); - return -ENOMEM; + ERROR(__FUNCTION__ "(), dev_alloc() failed!\n"); + err = -ENOMEM; + goto freebufs; } dev->priv = (void *) self; self->netdev = dev; @@ -875,12 +840,15 @@ rtnl_unlock(); if (err) { ERROR(__FUNCTION__ "(), register_netdev() failed!\n"); - return -1; + /* XXX there is not freeing for dev? */ + goto freebufs; } + pci_set_drvdata(pci_dev,self); - pmdev = pm_register (PM_PCI_DEV, PM_PCI_ID(pci_dev), toshoboe_pmproc); +/* pmdev = pm_register (PM_PCI_DEV, PM_PCI_ID(pci_dev), toshoboe_pmproc); if (pmdev) pmdev->data = self; + */ printk (KERN_WARNING "ToshOboe: Using "); #ifdef ONETASK @@ -891,22 +859,36 @@ printk (" tasks, version %s\n", rcsid); return (0); +freebufs: + for (i = 0; i < TX_SLOTS; ++i) + if (self->xmit_bufs[i]) + kfree (self->xmit_bufs[i]); + for (i = 0; i < RX_SLOTS; ++i) + if (self->recv_bufs[i]) + kfree (self->recv_bufs[i]); + kfree(self->taskfilebuf); +freeregion: + release_region (self->io.sir_base, self->io.sir_ext); +freeself: + kfree (self); + return err; } -static void -toshoboe_gotosleep (struct toshoboe_cb *self) +static int +toshoboe_suspend (struct pci_dev *pci_dev, u32 crap) { int i = 10; + struct toshoboe_cb *self = (struct toshoboe_cb*)pci_get_drvdata(pci_dev); printk (KERN_WARNING "ToshOboe: suspending\n"); - if (self->stopped) - return; + if (!self || self->stopped) + return 0; self->stopped = 1; if (!self->open) - return; + return 0; /*FIXME: can't sleep here wait one second */ @@ -917,22 +899,26 @@ toshoboe_disablebm (self); self->txpending = 0; - + return 0; } -static void -toshoboe_wakeup (struct toshoboe_cb *self) +static int +toshoboe_resume (struct pci_dev *pci_dev) { + struct toshoboe_cb *self = (struct toshoboe_cb*)pci_get_drvdata(pci_dev); unsigned long flags; + if (!self) + return 0; + if (!self->stopped) - return; + return 0; if (!self->open) { self->stopped = 0; - return; + return 0; } save_flags (flags); @@ -949,108 +935,29 @@ netif_wake_queue(self->netdev); restore_flags (flags); printk (KERN_WARNING "ToshOboe: waking up\n"); - -} - -static int -toshoboe_pmproc (struct pm_dev *dev, pm_request_t rqst, void *data) -{ - struct toshoboe_cb *self = (struct toshoboe_cb *) dev->data; - if (self) { - switch (rqst) { - case PM_SUSPEND: - toshoboe_gotosleep (self); - break; - case PM_RESUME: - toshoboe_wakeup (self); - break; - } - } return 0; } +static struct pci_driver toshoboe_pci_driver = { + name : "toshoboe", + id_table : toshoboe_pci_tbl, + probe : toshoboe_probe, + remove : toshoboe_remove, + suspend : toshoboe_suspend, + resume : toshoboe_resume +}; -int __init toshoboe_init (void) -{ - struct pci_dev *pci_dev = NULL; - int found = 0; - - do - { - pci_dev = pci_find_device (PCI_VENDOR_ID_TOSHIBA, - PCI_DEVICE_ID_FIR701, pci_dev); - if (pci_dev) - { - printk (KERN_WARNING "ToshOboe: Found 701 chip at 0x%0lx irq %d\n", - pci_dev->resource[0].start, - pci_dev->irq); - - if (!toshoboe_open (pci_dev)) - found++; - } - - } - while (pci_dev); - - if (!found) do - { - pci_dev = pci_find_device (PCI_VENDOR_ID_TOSHIBA, - PCI_DEVICE_ID_FIR701b, pci_dev); - if (pci_dev) - { - printk (KERN_WARNING "ToshOboe: Found 701b chip at 0x%0lx irq %d\n", - pci_dev->resource[0].start, - pci_dev->irq); - - if (!toshoboe_open (pci_dev)) - found++; - } - - } - while (pci_dev); - - - - if (found) - { - return 0; - } - - return -ENODEV; -} - -#ifdef MODULE - -static void -toshoboe_cleanup (void) -{ - int i; - - IRDA_DEBUG (4, __FUNCTION__ "()\n"); - - for (i = 0; i < 4; i++) - { - if (dev_self[i]) - toshoboe_close (dev_self[i]); - } - - pm_unregister_all (toshoboe_pmproc); -} - - - -int -init_module (void) -{ - return toshoboe_init (); +int __init +toshoboe_init (void) { + pci_module_init(&toshoboe_pci_driver); + return 0; } - void -cleanup_module (void) +toshoboe_cleanup (void) { - toshoboe_cleanup (); + pci_unregister_driver(&toshoboe_pci_driver); } - -#endif +module_init(toshoboe_init); +module_exit(toshoboe_cleanup); diff -u --recursive --new-file v2.4.6/linux/drivers/net/isa-skeleton.c linux/drivers/net/isa-skeleton.c --- v2.4.6/linux/drivers/net/isa-skeleton.c Thu Apr 12 12:15:25 2001 +++ linux/drivers/net/isa-skeleton.c Tue Jul 17 18:53:55 2001 @@ -8,9 +8,10 @@ * This software may be used and distributed according to the terms * of the GNU General Public License, incorporated herein by reference. * - * The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O - * Center of Excellence in Space Data and Information Sciences - * Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771 + * The author may be reached as becker@scyld.com, or C/O + * Scyld Computing Corporation + * 410 Severn Ave., Suite 210 + * Annapolis MD 21403 * * This file is an outline for writing a network device driver for the * the Linux operating system. diff -u --recursive --new-file v2.4.6/linux/drivers/net/lance.c linux/drivers/net/lance.c --- v2.4.6/linux/drivers/net/lance.c Tue Jul 3 17:08:20 2001 +++ linux/drivers/net/lance.c Tue Jul 17 18:53:55 2001 @@ -10,9 +10,10 @@ This driver is for the Allied Telesis AT1500 and HP J2405A, and should work with most other LANCE-based bus-master (NE2100/NE2500) ethercards. - The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O - Center of Excellence in Space Data and Information Sciences - Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771 + The author may be reached as becker@scyld.com, or C/O + Scyld Computing Corporation + 410 Severn Ave., Suite 210 + Annapolis MD 21403 Andrey V. Savochkin: - alignment problem with 1.3.* kernel and some minor changes. diff -u --recursive --new-file v2.4.6/linux/drivers/net/lasi_82596.c linux/drivers/net/lasi_82596.c --- v2.4.6/linux/drivers/net/lasi_82596.c Tue Jul 3 17:08:20 2001 +++ linux/drivers/net/lasi_82596.c Tue Jul 17 18:53:55 2001 @@ -63,8 +63,8 @@ according to the terms of the GNU General Public License as modified by SRC, incorporated herein by reference. - The author may be reached as becker@super.org or - C/O Supercomputing Research Ctr., 17100 Science Dr., Bowie MD 20715 + The author may be reached as becker@scyld.com, or C/O + Scyld Computing Corporation, 410 Severn Ave., Suite 210, Annapolis MD 21403 */ diff -u --recursive --new-file v2.4.6/linux/drivers/net/loopback.c linux/drivers/net/loopback.c --- v2.4.6/linux/drivers/net/loopback.c Wed Apr 18 14:40:06 2001 +++ linux/drivers/net/loopback.c Tue Jul 17 18:53:55 2001 @@ -9,7 +9,7 @@ * * Authors: Ross Biro, <bir7@leland.Stanford.Edu> * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> - * Donald Becker, <becker@cesdis.gsfc.nasa.gov> + * Donald Becker, <becker@scyld.com> * * Alan Cox : Fixed oddments for NET3.014 * Alan Cox : Rejig for NET3.029 snap #3 diff -u --recursive --new-file v2.4.6/linux/drivers/net/lp486e.c linux/drivers/net/lp486e.c --- v2.4.6/linux/drivers/net/lp486e.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/lp486e.c Tue Jul 17 18:53:55 2001 @@ -0,0 +1,1360 @@ +/* Intel Professional Workstation/panther ethernet driver */ +/* lp486e.c: A panther 82596 ethernet driver for linux. */ +/* + History and copyrights: + + Driver skeleton + Written 1993 by Donald Becker. + Copyright 1993 United States Government as represented by the Director, + National Security Agency. This software may only be used and + distributed according to the terms of the GNU Public License + as modified by SRC, incorporated herein by reference. + + The author may be reached as becker@scyld.com, or C/O + Scyld Computing Corporation + 410 Severn Ave., Suite 210 + Annapolis MD 21403 + + Apricot + Written 1994 by Mark Evans. + This driver is for the Apricot 82596 bus-master interface + + Modularised 12/94 Mark Evans + + Professional Workstation + Derived from apricot.c by Ard van Breemen + <ard@murphy.nl>|<ard@cstmel.hobby.nl>|<ard@cstmel.nl.eu.org> + + Credits: + Thanks to Murphy Software BV for letting me write this in their time. + Well, actually, I get payed doing this... + (Also: see http://www.murphy.nl for murphy, and my homepage ~ard for + more information on the Professional Workstation) + + Present version + aeb@cwi.nl +*/ +/* + There are currently two motherboards that I know of in the + professional workstation. The only one that I know is the + intel panther motherboard. -- ard +*/ +/* +The pws is equipped with an intel 82596. This is a very intelligent controller +which runs its own micro-code. Communication with the hostprocessor is done +through linked lists of commands and buffers in the hostprocessors memory. +A complete description of the 82596 is available from intel. Search for +a file called "29021806.pdf". It is a complete description of the chip itself. +To use it for the pws some additions are needed regarding generation of +the PORT and CA signal, and the interrupt glue needed for a pc. +I/O map: +PORT SIZE ACTION MEANING +0xCB0 2 WRITE Lower 16 bits for PORT command +0xCB2 2 WRITE Upper 16 bits for PORT command, and issue of PORT command +0xCB4 1 WRITE Generation of CA signal +0xCB8 1 WRITE Clear interrupt glue +All other communication is through memory! +*/ + +#define SLOW_DOWN_IO udelay(5); + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/string.h> +#include <linux/ptrace.h> +#include <linux/errno.h> +#include <linux/ioport.h> +#include <linux/malloc.h> +#include <linux/interrupt.h> +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/skbuff.h> + +#include <asm/bitops.h> +#include <asm/io.h> +#include <asm/dma.h> + +/* debug print flags */ +#define LOG_SRCDST 0x80000000 +#define LOG_STATINT 0x40000000 +#define LOG_STARTINT 0x20000000 + +#define i596_debug debug + +static int i596_debug = 0; + +static const char * const medianame[] = { + "10baseT", "AUI", + "10baseT-FD", "AUI-FD", +}; + +#define LP486E_TOTAL_SIZE 16 + +#define I596_NULL (0xffffffff) + +#define CMD_EOL 0x8000 /* The last command of the list, stop. */ +#define CMD_SUSP 0x4000 /* Suspend after doing cmd. */ +#define CMD_INTR 0x2000 /* Interrupt after doing cmd. */ + +#define CMD_FLEX 0x0008 /* Enable flexible memory model */ + +enum commands { + CmdNOP = 0, + CmdIASetup = 1, + CmdConfigure = 2, + CmdMulticastList = 3, + CmdTx = 4, + CmdTDR = 5, + CmdDump = 6, + CmdDiagnose = 7 +}; + +char *CUcmdnames[8] = { "NOP", "IASetup", "Configure", "MulticastList", + "Tx", "TDR", "Dump", "Diagnose" }; + +/* Status word bits */ +#define STAT_CX 0x8000 /* The CU finished executing a command + with the Interrupt bit set */ +#define STAT_FR 0x4000 /* The RU finished receiving a frame */ +#define STAT_CNA 0x2000 /* The CU left the active state */ +#define STAT_RNR 0x1000 /* The RU left the active state */ +#define STAT_ACK (STAT_CX | STAT_FR | STAT_CNA | STAT_RNR) +#define STAT_CUS 0x0700 /* Status of CU: 0: idle, 1: suspended, + 2: active, 3-7: unused */ +#define STAT_RUS 0x00f0 /* Status of RU: 0: idle, 1: suspended, + 2: no resources, 4: ready, + 10: no resources due to no more RBDs, + 12: no more RBDs, other: unused */ +#define STAT_T 0x0008 /* Bus throttle timers loaded */ +#define STAT_ZERO 0x0807 /* Always zero */ + +#if 0 +static char *CUstates[8] = { + "idle", "suspended", "active", 0, 0, 0, 0, 0 +}; +static char *RUstates[16] = { + "idle", "suspended", "no resources", 0, "ready", 0, 0, 0, + 0, 0, "no RBDs", 0, "out of RBDs", 0, 0, 0 +}; + +static void +i596_out_status(int status) { + int bad = 0; + char *s; + + printk("status %4.4x:", status); + if (status == 0xffff) + printk(" strange..\n"); + else { + if (status & STAT_CX) + printk(" CU done"); + if (status & STAT_CNA) + printk(" CU stopped"); + if (status & STAT_FR) + printk(" got a frame"); + if (status & STAT_RNR) + printk(" RU stopped"); + if (status & STAT_T) + printk(" throttled"); + if (status & STAT_ZERO) + bad = 1; + s = CUstates[(status & STAT_CUS) >> 8]; + if (!s) + bad = 1; + else + printk(" CU(%s)", s); + s = RUstates[(status & STAT_RUS) >> 4]; + if (!s) + bad = 1; + else + printk(" RU(%s)", s); + if (bad) + printk(" bad status"); + printk("\n"); + } +} +#endif + +/* Command word bits */ +#define ACK_CX 0x8000 +#define ACK_FR 0x4000 +#define ACK_CNA 0x2000 +#define ACK_RNR 0x1000 + +#define CUC_START 0x0100 +#define CUC_RESUME 0x0200 +#define CUC_SUSPEND 0x0300 +#define CUC_ABORT 0x0400 + +#define RX_START 0x0010 +#define RX_RESUME 0x0020 +#define RX_SUSPEND 0x0030 +#define RX_ABORT 0x0040 + +typedef u32 phys_addr; + +static inline phys_addr +va_to_pa(volatile void *x) { + return x ? virt_to_bus(x) : I596_NULL; +} + +static inline void * +pa_to_va(phys_addr x) { + return (x == I596_NULL) ? NULL : bus_to_virt(x); +} + +/* status bits for cmd */ +#define CMD_STAT_C 0x8000 /* CU command complete */ +#define CMD_STAT_B 0x4000 /* CU command in progress */ +#define CMD_STAT_OK 0x2000 /* CU command completed without errors */ +#define CMD_STAT_A 0x1000 /* CU command abnormally terminated */ + +struct i596_cmd { /* 8 bytes */ + unsigned short status; + unsigned short command; + phys_addr pa_next; /* va_to_pa(struct i596_cmd *next) */ +}; + +#define EOF 0x8000 +#define SIZE_MASK 0x3fff + +struct i596_tbd { + unsigned short size; + unsigned short pad; + phys_addr pa_next; /* va_to_pa(struct i596_tbd *next) */ + phys_addr pa_data; /* va_to_pa(char *data) */ + struct sk_buff *skb; +}; + +struct tx_cmd { + struct i596_cmd cmd; + phys_addr pa_tbd; /* va_to_pa(struct i596_tbd *tbd) */ + unsigned short size; + unsigned short pad; +}; + +/* status bits for rfd */ +#define RFD_STAT_C 0x8000 /* Frame reception complete */ +#define RFD_STAT_B 0x4000 /* Frame reception in progress */ +#define RFD_STAT_OK 0x2000 /* Frame received without errors */ +#define RFD_STATUS 0x1fff +#define RFD_LENGTH_ERR 0x1000 +#define RFD_CRC_ERR 0x0800 +#define RFD_ALIGN_ERR 0x0400 +#define RFD_NOBUFS_ERR 0x0200 +#define RFD_DMA_ERR 0x0100 /* DMA overrun failure to acquire system bus */ +#define RFD_SHORT_FRAME_ERR 0x0080 +#define RFD_NOEOP_ERR 0x0040 +#define RFD_TRUNC_ERR 0x0020 +#define RFD_MULTICAST 0x0002 /* 0: destination had our address + 1: destination was broadcast/multicast */ +#define RFD_COLLISION 0x0001 + +/* receive frame descriptor */ +struct i596_rfd { + unsigned short stat; + unsigned short cmd; + phys_addr pa_next; /* va_to_pa(struct i596_rfd *next) */ + phys_addr pa_rbd; /* va_to_pa(struct i596_rbd *rbd) */ + unsigned short count; + unsigned short size; + char data[1532]; +}; + +#define RBD_EL 0x8000 +#define RBD_P 0x4000 +#define RBD_SIZEMASK 0x3fff +#define RBD_EOF 0x8000 +#define RBD_F 0x4000 + +/* receive buffer descriptor */ +struct i596_rbd { + unsigned short size; + unsigned short pad; + phys_addr pa_next; /* va_to_pa(struct i596_tbd *next) */ + phys_addr pa_data; /* va_to_pa(char *data) */ + phys_addr pa_prev; /* va_to_pa(struct i596_tbd *prev) */ + + /* Driver private part */ + struct sk_buff *skb; +}; + +#define RX_RING_SIZE 64 +#define RX_SKBSIZE (ETH_FRAME_LEN+10) +#define RX_RBD_SIZE 32 + +/* System Control Block - 40 bytes */ +struct i596_scb { + u16 status; /* 0 */ + u16 command; /* 2 */ + phys_addr pa_cmd; /* 4 - va_to_pa(struct i596_cmd *cmd) */ + phys_addr pa_rfd; /* 8 - va_to_pa(struct i596_rfd *rfd) */ + u32 crc_err; /* 12 */ + u32 align_err; /* 16 */ + u32 resource_err; /* 20 */ + u32 over_err; /* 24 */ + u32 rcvdt_err; /* 28 */ + u32 short_err; /* 32 */ + u16 t_on; /* 36 */ + u16 t_off; /* 38 */ +}; + +/* Intermediate System Configuration Pointer - 8 bytes */ +struct i596_iscp { + u32 busy; /* 0 */ + phys_addr pa_scb; /* 4 - va_to_pa(struct i596_scb *scb) */ +}; + +/* System Configuration Pointer - 12 bytes */ +struct i596_scp { + u32 sysbus; /* 0 */ + u32 pad; /* 4 */ + phys_addr pa_iscp; /* 8 - va_to_pa(struct i596_iscp *iscp) */ +}; + +/* Selftest and dump results - needs 16-byte alignment */ +/* + * The size of the dump area is 304 bytes. When the dump is executed + * by the Port command an extra word will be appended to the dump area. + * The extra word is a copy of the Dump status word (containing the + * C, B, OK bits). [I find 0xa006, with a0 for C+OK and 6 for dump] + */ +struct i596_dump { + u16 dump[153]; /* (304 = 130h) + 2 bytes */ +}; + +struct i596_private { /* aligned to a 16-byte boundary */ + struct i596_scp scp; /* 0 - needs 16-byte alignment */ + struct i596_iscp iscp; /* 12 */ + struct i596_scb scb; /* 20 */ + u32 dummy; /* 60 */ + struct i596_dump dump; /* 64 - needs 16-byte alignment */ + + struct i596_cmd set_add; + char eth_addr[8]; /* directly follows set_add */ + + struct i596_cmd set_conf; + char i596_config[16]; /* directly follows set_conf */ + + struct i596_cmd tdr; + unsigned long tdr_stat; /* directly follows tdr */ + + int last_restart; + volatile struct i596_rbd *rbd_list; + volatile struct i596_rbd *rbd_tail; + volatile struct i596_rfd *rx_tail; + volatile struct i596_cmd *cmd_tail; + volatile struct i596_cmd *cmd_head; + int cmd_backlog; + unsigned long last_cmd; + struct net_device_stats stats; +}; + +static char init_setup[14] = { + 0x8E, /* length 14 bytes, prefetch on */ + 0xC8, /* default: fifo to 8, monitor off */ + 0x40, /* default: don't save bad frames (apricot.c had 0x80) */ + 0x2E, /* (default is 0x26) + No source address insertion, 8 byte preamble */ + 0x00, /* default priority and backoff */ + 0x60, /* default interframe spacing */ + 0x00, /* default slot time LSB */ + 0xf2, /* default slot time and nr of retries */ + 0x00, /* default various bits + (0: promiscuous mode, 1: broadcast disable, + 2: encoding mode, 3: transmit on no CRS, + 4: no CRC insertion, 5: CRC type, + 6: bit stuffing, 7: padding) */ + 0x00, /* default carrier sense and collision detect */ + 0x40, /* default minimum frame length */ + 0xff, /* (default is 0xff, and that is what apricot.c has; + elp486.c has 0xfb: Enable crc append in memory.) */ + 0x00, /* default: not full duplex */ + 0x7f /* (default is 0x3f) multi IA */ +}; + +static int i596_open(struct net_device *dev); +static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev); +static void i596_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static int i596_close(struct net_device *dev); +static struct net_device_stats *i596_get_stats(struct net_device *dev); +static void i596_add_cmd(struct net_device *dev, struct i596_cmd *cmd); +static void print_eth(char *); +static void set_multicast_list(struct net_device *dev); +static void i596_tx_timeout(struct net_device *dev); + +static int +i596_timeout(struct net_device *dev, char *msg, int ct) { + volatile struct i596_private *lp; + int boguscnt = ct; + + lp = (struct i596_private *) dev->priv; + while (lp->scb.command) { + if (--boguscnt == 0) { + printk("%s: %s timed out - stat %4.4x, cmd %4.4x\n", + dev->name, msg, + lp->scb.status, lp->scb.command); + return 1; + } + udelay(5); + } + return 0; +} + +static inline int +init_rx_bufs(struct net_device *dev, int num) { + volatile struct i596_private *lp; + struct i596_rfd *rfd; + int i; + // struct i596_rbd *rbd; + + lp = (struct i596_private *) dev->priv; + lp->scb.pa_rfd = I596_NULL; + + for (i = 0; i < num; i++) { + rfd = kmalloc(sizeof(struct i596_rfd), GFP_KERNEL); + if (rfd == NULL) + break; + + rfd->stat = 0; + rfd->pa_rbd = I596_NULL; + rfd->count = 0; + rfd->size = 1532; + if (i == 0) { + rfd->cmd = CMD_EOL; + lp->rx_tail = rfd; + } else { + rfd->cmd = 0; + } + rfd->pa_next = lp->scb.pa_rfd; + lp->scb.pa_rfd = va_to_pa(rfd); + lp->rx_tail->pa_next = lp->scb.pa_rfd; + } + +#if 0 + for (i = 0; i<RX_RBD_SIZE; i++) { + rbd = kmalloc(sizeof(struct i596_rbd), GFP_KERNEL); + if (rbd) { + rbd->pad = 0; + rbd->count = 0; + rbd->skb = dev_alloc_skb(RX_SKB_SIZE); + if (!rbd->skb) { + printk("dev_alloc_skb failed"); + } + rbd->next = rfd->rbd; + if (i) { + rfd->rbd->prev = rbd; + rbd->size = RX_SKB_SIZE; + } else { + rbd->size = (RX_SKB_SIZE | RBD_EL); + lp->rbd_tail = rbd; + } + + rfd->rbd = rbd; + } else { + printk("Could not kmalloc rbd\n"); + } + } + lp->rbd_tail->next = rfd->rbd; +#endif + return (i); +} + +static inline void +remove_rx_bufs(struct net_device *dev) { + struct i596_private *lp; + struct i596_rfd *rfd; + + lp = (struct i596_private *) dev->priv; + lp->rx_tail->pa_next = I596_NULL; + + do { + rfd = pa_to_va(lp->scb.pa_rfd); + lp->scb.pa_rfd = rfd->pa_next; + kfree(rfd); + } while (rfd != lp->rx_tail); + + lp->rx_tail = 0; + +#if 0 + for (lp->rbd_list) { + } +#endif +} + +#define PORT_RESET 0x00 /* reset 82596 */ +#define PORT_SELFTEST 0x01 /* selftest */ +#define PORT_ALTSCP 0x02 /* alternate SCB address */ +#define PORT_DUMP 0x03 /* dump */ + +#define IOADDR 0xcb0 /* real constant */ +#define IRQ 10 /* default IRQ - can be changed by ECU */ + +/* The 82596 requires two 16-bit write cycles for a port command */ +static inline void +PORT(phys_addr a, unsigned int cmd) { + if (a & 0xf) + printk("lp486e.c: PORT: address not aligned\n"); + outw(((a & 0xffff) | cmd), IOADDR); + outw(((a>>16) & 0xffff), IOADDR+2); +} + +static inline void +CA(void) { + outb(0, IOADDR+4); + udelay(8); +} + +static inline void +CLEAR_INT(void) { + outb(0, IOADDR+8); +} + +#define SIZE(x) (sizeof(x)/sizeof((x)[0])) + +#if 0 +/* selftest or dump */ +static void +i596_port_do(struct net_device *dev, int portcmd, char *cmdname) { + volatile struct i596_private *lp = dev->priv; + volatile u16 *outp; + int i, m; + + memset((void *)&(lp->dump), 0, sizeof(struct i596_dump)); + outp = &(lp->dump.dump[0]); + + PORT(va_to_pa(outp), portcmd); + mdelay(30); /* random, unmotivated */ + + printk("lp486e i82596 %s result:\n", cmdname); + for (m = SIZE(lp->dump.dump); m && lp->dump.dump[m-1] == 0; m--) + ; + for (i = 0; i < m; i++) { + printk(" %04x", lp->dump.dump[i]); + if (i%8 == 7) + printk("\n"); + } + printk("\n"); +} +#endif + +static int +i596_scp_setup(struct net_device *dev) { + volatile struct i596_private *lp = dev->priv; + int boguscnt; + + /* Setup SCP, ISCP, SCB */ + /* + * sysbus bits: + * only a single byte is significant - here 0x44 + * 0x80: big endian mode (details depend on stepping) + * 0x40: 1 + * 0x20: interrupt pin is active low + * 0x10: lock function disabled + * 0x08: external triggering of bus throttle timers + * 0x06: 00: 82586 compat mode, 01: segmented mode, 10: linear mode + * 0x01: unused + */ + lp->scp.sysbus = 0x00440000; /* linear mode */ + lp->scp.pad = 0; /* must be zero */ + lp->scp.pa_iscp = va_to_pa(&(lp->iscp)); + + /* + * The CPU sets the ISCP to 1 before it gives the first CA() + */ + lp->iscp.busy = 0x0001; + lp->iscp.pa_scb = va_to_pa(&(lp->scb)); + + lp->scb.command = 0; + lp->scb.status = 0; + lp->scb.pa_cmd = I596_NULL; + /* lp->scb.pa_rfd has been initialised already */ + + lp->last_cmd = jiffies; + lp->cmd_backlog = 0; + lp->cmd_head = NULL; + + /* + * Reset the 82596. + * We need to wait 10 systemclock cycles, and + * 5 serial clock cycles. + */ + PORT(0, PORT_RESET); /* address part ignored */ + udelay(100); + + /* + * Before the CA signal is asserted, the default SCP address + * (0x00fffff4) can be changed to a 16-byte aligned value + */ + PORT(va_to_pa(&lp->scp), PORT_ALTSCP); /* change the scp address */ + + /* + * The initialization procedure begins when a + * Channel Attention signal is asserted after a reset. + */ + + CA(); + + /* + * The ISCP busy is cleared by the 82596 after the SCB address is read. + */ + boguscnt = 100; + while (lp->iscp.busy) { + if (--boguscnt == 0) { + /* No i82596 present? */ + printk("%s: i82596 initialization timed out\n", + dev->name); + return 1; + } + udelay(5); + } + /* I find here boguscnt==100, so no delay was required. */ + + return 0; +} + +static int +init_i596(struct net_device *dev) { + volatile struct i596_private *lp; + + if (i596_scp_setup(dev)) + return 1; + + lp = (struct i596_private *) dev->priv; + lp->scb.command = 0; + + memcpy ((void *)lp->i596_config, init_setup, 14); + lp->set_conf.command = CmdConfigure; + i596_add_cmd(dev, (void *)&lp->set_conf); + + memcpy ((void *)lp->eth_addr, dev->dev_addr, 6); + lp->set_add.command = CmdIASetup; + i596_add_cmd(dev, (struct i596_cmd *)&lp->set_add); + + lp->tdr.command = CmdTDR; + i596_add_cmd(dev, (struct i596_cmd *)&lp->tdr); + + if (lp->scb.command && i596_timeout(dev, "i82596 init", 200)) + return 1; + + lp->scb.command = RX_START; + CA(); + + if (lp->scb.command && i596_timeout(dev, "Receive Unit start", 100)) + return 1; + + return 0; +} + +/* Receive a single frame */ +static inline int +i596_rx_one(struct net_device *dev, volatile struct i596_private *lp, + struct i596_rfd *rfd, int *frames) { + + if (rfd->stat & RFD_STAT_OK) { + /* a good frame */ + int pkt_len = (rfd->count & 0x3fff); + struct sk_buff *skb = dev_alloc_skb(pkt_len); + + (*frames)++; + + if (rfd->cmd & CMD_EOL) + printk("Received on EOL\n"); + + if (skb == NULL) { + printk ("%s: i596_rx Memory squeeze, " + "dropping packet.\n", dev->name); + lp->stats.rx_dropped++; + return 1; + } + + skb->dev = dev; + memcpy(skb_put(skb,pkt_len), rfd->data, pkt_len); + + skb->protocol = eth_type_trans(skb,dev); + netif_rx(skb); + lp->stats.rx_packets++; + } else { +#if 0 + printk("Frame reception error status %04x\n", + rfd->stat); +#endif + lp->stats.rx_errors++; + if (rfd->stat & RFD_COLLISION) + lp->stats.collisions++; + if (rfd->stat & RFD_SHORT_FRAME_ERR) + lp->stats.rx_length_errors++; + if (rfd->stat & RFD_DMA_ERR) + lp->stats.rx_over_errors++; + if (rfd->stat & RFD_NOBUFS_ERR) + lp->stats.rx_fifo_errors++; + if (rfd->stat & RFD_ALIGN_ERR) + lp->stats.rx_frame_errors++; + if (rfd->stat & RFD_CRC_ERR) + lp->stats.rx_crc_errors++; + if (rfd->stat & RFD_LENGTH_ERR) + lp->stats.rx_length_errors++; + } + rfd->stat = rfd->count = 0; + return 0; +} + +static int +i596_rx(struct net_device *dev) { + volatile struct i596_private *lp = (struct i596_private *) dev->priv; + struct i596_rfd *rfd; + int frames = 0; + + while (1) { + rfd = pa_to_va(lp->scb.pa_rfd); + if (!rfd) { + printk("i596_rx: NULL rfd?\n"); + return 0; + } +#if 1 + if (rfd->stat && !(rfd->stat & (RFD_STAT_C | RFD_STAT_B))) + printk("SF:%p-%04x\n", rfd, rfd->stat); +#endif + if (!(rfd->stat & RFD_STAT_C)) + break; /* next one not ready */ + if (i596_rx_one(dev, lp, rfd, &frames)) + break; /* out of memory */ + rfd->cmd = CMD_EOL; + lp->rx_tail->cmd = 0; + lp->rx_tail = rfd; + lp->scb.pa_rfd = rfd->pa_next; + } + + return frames; +} + +static void +i596_cleanup_cmd(struct net_device *dev) { + volatile struct i596_private *lp; + struct i596_cmd *cmd; + + lp = (struct i596_private *) dev->priv; + while (lp->cmd_head) { + cmd = (struct i596_cmd *)lp->cmd_head; + + lp->cmd_head = pa_to_va(lp->cmd_head->pa_next); + lp->cmd_backlog--; + + switch ((cmd->command) & 0x7) { + case CmdTx: { + struct tx_cmd *tx_cmd = (struct tx_cmd *) cmd; + struct i596_tbd * tx_cmd_tbd; + tx_cmd_tbd = pa_to_va(tx_cmd->pa_tbd); + + dev_kfree_skb_any(tx_cmd_tbd->skb); + + lp->stats.tx_errors++; + lp->stats.tx_aborted_errors++; + + cmd->pa_next = I596_NULL; + kfree((unsigned char *)tx_cmd); + netif_wake_queue(dev); + break; + } + case CmdMulticastList: { + // unsigned short count = *((unsigned short *) (ptr + 1)); + + cmd->pa_next = I596_NULL; + kfree((unsigned char *)cmd); + break; + } + default: { + cmd->pa_next = I596_NULL; + break; + } + } + } + + if (lp->scb.command && i596_timeout(dev, "i596_cleanup_cmd", 100)) + ; + + lp->scb.pa_cmd = va_to_pa(lp->cmd_head); +} + +static inline void +i596_reset(struct net_device *dev, + volatile struct i596_private *lp, int ioaddr) { + + if (lp->scb.command && i596_timeout(dev, "i596_reset", 100)) + ; + + netif_stop_queue(dev); + + lp->scb.command = CUC_ABORT | RX_ABORT; + CA(); + + /* wait for shutdown */ + if (lp->scb.command && i596_timeout(dev, "i596_reset(2)", 400)) + ; + + i596_cleanup_cmd(dev); + i596_rx(dev); + + netif_start_queue(dev); + /*dev_kfree_skb(skb, FREE_WRITE);*/ + init_i596(dev); +} + +static void i596_add_cmd(struct net_device *dev, struct i596_cmd *cmd) { + volatile struct i596_private *lp = dev->priv; + int ioaddr = dev->base_addr; + unsigned long flags; + + cmd->status = 0; + cmd->command |= (CMD_EOL | CMD_INTR); + cmd->pa_next = I596_NULL; + + save_flags(flags); + cli(); + if (lp->cmd_head) { + lp->cmd_tail->pa_next = va_to_pa(cmd); + } else { + lp->cmd_head = cmd; + if (lp->scb.command && i596_timeout(dev, "i596_add_cmd", 100)) + ; + lp->scb.pa_cmd = va_to_pa(cmd); + lp->scb.command = CUC_START; + CA(); + } + lp->cmd_tail = cmd; + lp->cmd_backlog++; + + lp->cmd_head = pa_to_va(lp->scb.pa_cmd); + restore_flags(flags); + + if (lp->cmd_backlog > 16) { + int tickssofar = jiffies - lp->last_cmd; + if (tickssofar < 25) return; + + printk("%s: command unit timed out, status resetting.\n", + dev->name); + i596_reset(dev, lp, ioaddr); + } +} + +static int +i596_open(struct net_device *dev) { + int i; + + i = request_irq(dev->irq, &i596_interrupt, SA_SHIRQ, dev->name, dev); + if (i) { + printk("%s: IRQ %d not free\n", dev->name, dev->irq); + return i; + } + + if ((i = init_rx_bufs(dev, RX_RING_SIZE)) < RX_RING_SIZE) + printk("%s: only able to allocate %d receive buffers\n", + dev->name, i); + + if (i < 4) { +// release buffers + free_irq(dev->irq, dev); + return -EAGAIN; + } + + netif_start_queue(dev); + + init_i596(dev); + + return 0; /* Always succeed */ +} + +static int +i596_start_xmit (struct sk_buff *skb, struct net_device *dev) { + volatile struct i596_private *lp = dev->priv; + struct tx_cmd *tx_cmd; + short length; + + /* If some higher level thinks we've missed a tx-done interrupt + we are passed NULL. n.b. dev_tint handles the cli()/sti() + itself. */ + if (skb == NULL) { + printk ("What about dev_tint\n"); + /* dev_tint(dev); */ + return 0; + } + + /* shouldn't happen */ + if (skb->len <= 0) + return 0; + + length = (ETH_ZLEN < skb->len) ? skb->len : ETH_ZLEN; + dev->trans_start = jiffies; + + tx_cmd = (struct tx_cmd *) + kmalloc ((sizeof (struct tx_cmd) + + sizeof (struct i596_tbd)), GFP_ATOMIC); + if (tx_cmd == NULL) { + printk ("%s: i596_xmit Memory squeeze, dropping packet.\n", + dev->name); + lp->stats.tx_dropped++; + + dev_kfree_skb (skb); + } else { + struct i596_tbd *tx_cmd_tbd; + tx_cmd_tbd = (struct i596_tbd *) (tx_cmd + 1); + tx_cmd->pa_tbd = va_to_pa (tx_cmd_tbd); + tx_cmd_tbd->pa_next = I596_NULL; + + tx_cmd->cmd.command = (CMD_FLEX | CmdTx); + + tx_cmd->pad = 0; + tx_cmd->size = 0; + tx_cmd_tbd->pad = 0; + tx_cmd_tbd->size = (EOF | length); + + tx_cmd_tbd->pa_data = va_to_pa (skb->data); + tx_cmd_tbd->skb = skb; + + if (i596_debug & LOG_SRCDST) + print_eth (skb->data); + + i596_add_cmd (dev, (struct i596_cmd *) tx_cmd); + + lp->stats.tx_packets++; + } + + return 0; +} + +static void +i596_tx_timeout (struct net_device *dev) { + volatile struct i596_private *lp = dev->priv; + int ioaddr = dev->base_addr; + + /* Transmitter timeout, serious problems. */ + printk ("%s: transmit timed out, status resetting.\n", dev->name); + lp->stats.tx_errors++; + + /* Try to restart the adaptor */ + if (lp->last_restart == lp->stats.tx_packets) { + printk ("Resetting board.\n"); + + /* Shutdown and restart */ + i596_reset (dev, lp, ioaddr); + } else { + /* Issue a channel attention signal */ + printk ("Kicking board.\n"); + lp->scb.command = (CUC_START | RX_START); + CA(); + lp->last_restart = lp->stats.tx_packets; + } + netif_wake_queue(dev); +} + +static void +print_eth(char *add) { + int i; + + printk ("Dest "); + for (i = 0; i < 6; i++) + printk(" %2.2X", (unsigned char) add[i]); + printk ("\n"); + + printk ("Source"); + for (i = 0; i < 6; i++) + printk(" %2.2X", (unsigned char) add[i+6]); + printk ("\n"); + + printk ("type %2.2X%2.2X\n", + (unsigned char) add[12], (unsigned char) add[13]); +} + +int __init +lp486e_probe(struct net_device *dev) { + volatile struct i596_private *lp; + unsigned char eth_addr[6] = { 0, 0xaa, 0, 0, 0, 0 }; + unsigned char *bios; + int i, j; + int ret = -ENOMEM; + static int probed; + + if (probed) + return -ENODEV; + probed++; + + if (!request_region(IOADDR, LP486E_TOTAL_SIZE, dev->name)) { + printk(KERN_ERR "lp486e: IO address 0x%x in use\n", IOADDR); + return -EBUSY; + } + + /* + * Allocate working memory, 16-byte aligned + */ + dev->mem_start = (unsigned long) + kmalloc(sizeof(struct i596_private) + 0x0f, GFP_KERNEL); + if (!dev->mem_start) + goto err_out; + dev->priv = (void *)((dev->mem_start + 0xf) & 0xfffffff0); + lp = (struct i596_private *) dev->priv; + memset((void *)lp, 0, sizeof(struct i596_private)); + + /* + * Do we really have this thing? + */ + if (i596_scp_setup(dev)) { + ret = -ENODEV; + goto err_out_kfree; + } + + dev->base_addr = IOADDR; + dev->irq = IRQ; + + ether_setup(dev); + + /* + * How do we find the ethernet address? I don't know. + * One possibility is to look at the EISA configuration area + * [0xe8000-0xe9fff]. This contains the ethernet address + * but not at a fixed address - things depend on setup options. + * + * If we find no address, or the wrong address, use + * ifconfig eth0 hw ether a1:a2:a3:a4:a5:a6 + * with the value found in the BIOS setup. + */ + bios = bus_to_virt(0xe8000); + for (j = 0; j < 0x2000; j++) { + if (bios[j] == 0 && bios[j+1] == 0xaa && bios[j+2] == 0) { + printk("%s: maybe address at BIOS 0x%x:", + dev->name, 0xe8000+j); + for (i = 0; i < 6; i++) { + eth_addr[i] = bios[i+j]; + printk(" %2.2X", eth_addr[i]); + } + printk("\n"); + } + } + + printk("%s: lp486e 82596 at %#3lx, IRQ %d,", + dev->name, dev->base_addr, dev->irq); + for (i = 0; i < 6; i++) + printk(" %2.2X", dev->dev_addr[i] = eth_addr[i]); + printk("\n"); + + /* The LP486E-specific entries in the device structure. */ + dev->open = &i596_open; + dev->stop = &i596_close; + dev->hard_start_xmit = &i596_start_xmit; + dev->get_stats = &i596_get_stats; + dev->set_multicast_list = &set_multicast_list; + dev->watchdog_timeo = 5*HZ; + dev->tx_timeout = i596_tx_timeout; + +#if 0 + /* selftest reports 0x320925ae - don't know what that means */ + i596_port_do(dev, PORT_SELFTEST, "selftest"); + i596_port_do(dev, PORT_DUMP, "dump"); +#endif + return 0; + +err_out_kfree: + kfree ((void *) dev->mem_start); +err_out: + release_region(IOADDR, LP486E_TOTAL_SIZE); + return ret; +} + +static void inline +i596_handle_CU_completion(struct net_device *dev, + volatile struct i596_private *lp, + unsigned short status, + unsigned short *ack_cmdp) { + volatile struct i596_cmd *cmd; + int frames_out = 0; + int commands_done = 0; + int cmd_val; + + cmd = lp->cmd_head; + + while (lp->cmd_head && (lp->cmd_head->status & CMD_STAT_C)) { + cmd = lp->cmd_head; + + lp->cmd_head = pa_to_va(lp->cmd_head->pa_next); + lp->cmd_backlog--; + + commands_done++; + cmd_val = cmd->command & 0x7; +#if 0 + printk("finished CU %s command (%d)\n", + CUcmdnames[cmd_val], cmd_val); +#endif + switch (cmd_val) { + case CmdTx: + { + struct tx_cmd *tx_cmd; + struct i596_tbd *tx_cmd_tbd; + + tx_cmd = (struct tx_cmd *) cmd; + tx_cmd_tbd = pa_to_va(tx_cmd->pa_tbd); + + frames_out++; + if (cmd->status & CMD_STAT_OK) { + if (i596_debug) + print_eth(pa_to_va(tx_cmd_tbd->pa_data)); + } else { + lp->stats.tx_errors++; + if (i596_debug) + printk("transmission failure:%04x\n", + cmd->status); + if (cmd->status & 0x0020) + lp->stats.collisions++; + if (!(cmd->status & 0x0040)) + lp->stats.tx_heartbeat_errors++; + if (cmd->status & 0x0400) + lp->stats.tx_carrier_errors++; + if (cmd->status & 0x0800) + lp->stats.collisions++; + if (cmd->status & 0x1000) + lp->stats.tx_aborted_errors++; + } + dev_kfree_skb_irq(tx_cmd_tbd->skb); + + cmd->pa_next = I596_NULL; + kfree((unsigned char *)tx_cmd); + netif_wake_queue(dev); + break; + } + + case CmdMulticastList: + cmd->pa_next = I596_NULL; + kfree((unsigned char *)cmd); + break; + + case CmdTDR: + { + unsigned long status = *((unsigned long *) (cmd + 1)); + if (status & 0x8000) { + if (i596_debug) + printk("%s: link ok.\n", dev->name); + } else { + if (status & 0x4000) + printk("%s: Transceiver problem.\n", + dev->name); + if (status & 0x2000) + printk("%s: Termination problem.\n", + dev->name); + if (status & 0x1000) + printk("%s: Short circuit.\n", + dev->name); + printk("%s: Time %ld.\n", + dev->name, status & 0x07ff); + } + } + default: + cmd->pa_next = I596_NULL; + lp->last_cmd = jiffies; + + } + } + + cmd = lp->cmd_head; + while (cmd && (cmd != lp->cmd_tail)) { + cmd->command &= 0x1fff; + cmd = pa_to_va(cmd->pa_next); + } + + if (lp->cmd_head) + *ack_cmdp |= CUC_START; + lp->scb.pa_cmd = va_to_pa(lp->cmd_head); +} + +static void +i596_interrupt (int irq, void *dev_instance, struct pt_regs *regs) { + struct net_device *dev = (struct net_device *) dev_instance; + volatile struct i596_private *lp; + unsigned short status, ack_cmd = 0; + int frames_in = 0; + + if (dev == NULL) { + printk ("i596_interrupt(): irq %d for unknown device.\n", irq); + return; + } + + lp = (struct i596_private *) dev->priv; + + /* + * The 82596 examines the command, performs the required action, + * and then clears the SCB command word. + */ + if (lp->scb.command && i596_timeout(dev, "interrupt", 40)) + ; + + /* + * The status word indicates the status of the 82596. + * It is modified only by the 82596. + * + * [So, we must not clear it. I find often status 0xffff, + * which is not one of the values allowed by the docs.] + */ + status = lp->scb.status; +#if 0 + if (i596_debug) { + printk("%s: i596 interrupt, ", dev->name); + i596_out_status(status); + } +#endif + /* Impossible, but it happens - perhaps when we get + a receive interrupt but scb.pa_rfd is I596_NULL. */ + if (status == 0xffff) { + printk("%s: i596_interrupt: got status 0xffff\n", dev->name); + goto out; + } + + ack_cmd = (status & STAT_ACK); + + if (status & (STAT_CX | STAT_CNA)) + i596_handle_CU_completion(dev, lp, status, &ack_cmd); + + if (status & (STAT_FR | STAT_RNR)) { + /* Restart the receive unit when it got inactive somehow */ + if ((status & STAT_RNR) && netif_running(dev)) + ack_cmd |= RX_START; + + if (status & STAT_FR) { + frames_in = i596_rx(dev); + if (!frames_in) + printk("receive frame reported, but no frames\n"); + } + } + + /* acknowledge the interrupt */ + /* + if ((lp->scb.pa_cmd != I596_NULL) && netif_running(dev)) + ack_cmd |= CUC_START; + */ + + if (lp->scb.command && i596_timeout(dev, "i596 interrupt", 100)) + ; + + lp->scb.command = ack_cmd; + + CLEAR_INT(); + CA(); + + out: + return; +} + +static int i596_close(struct net_device *dev) { + volatile struct i596_private *lp = dev->priv; + + netif_stop_queue(dev); + + if (i596_debug) + printk("%s: Shutting down ethercard, status was %4.4x.\n", + dev->name, lp->scb.status); + + lp->scb.command = (CUC_ABORT | RX_ABORT); + CA(); + + i596_cleanup_cmd(dev); + + if (lp->scb.command && i596_timeout(dev, "i596_close", 200)) + ; + + free_irq(dev->irq, dev); + remove_rx_bufs(dev); + + return 0; +} + +static struct net_device_stats * i596_get_stats(struct net_device *dev) { + struct i596_private *lp = dev->priv; + + return &lp->stats; +} + +/* +* Set or clear the multicast filter for this adaptor. +*/ + +static void set_multicast_list(struct net_device *dev) { + volatile struct i596_private *lp = dev->priv; + struct i596_cmd *cmd; + + if (i596_debug > 1) + printk ("%s: set multicast list %d\n", + dev->name, dev->mc_count); + + if (dev->mc_count > 0) { + struct dev_mc_list *dmi; + char *cp; + cmd = (struct i596_cmd *) + kmalloc(sizeof(struct i596_cmd)+2+dev->mc_count*6, + GFP_ATOMIC); + if (cmd == NULL) { + printk ("%s: set_multicast Memory squeeze.\n", + dev->name); + return; + } + cmd->command = CmdMulticastList; + *((unsigned short *) (cmd + 1)) = dev->mc_count * 6; + cp = ((char *)(cmd + 1))+2; + for (dmi = dev->mc_list; dmi != NULL; dmi = dmi->next) { + memcpy(cp, dmi,6); + cp += 6; + } + if (i596_debug & LOG_SRCDST) + print_eth (((char *)(cmd + 1)) + 2); + i596_add_cmd(dev, cmd); + } else { + if (lp->set_conf.pa_next != I596_NULL) { + return; + } + if (dev->mc_count == 0 && + !(dev->flags & (IFF_PROMISC | IFF_ALLMULTI))) { + if (dev->flags & IFF_ALLMULTI) + dev->flags |= IFF_PROMISC; + lp->i596_config[8] &= ~0x01; + } else { + lp->i596_config[8] |= 0x01; + } + + i596_add_cmd(dev, (struct i596_cmd *) &lp->set_conf); + } +} + +MODULE_AUTHOR("Ard van Breemen <ard@cstmel.nl.eu.org>"); +MODULE_DESCRIPTION("Intel Panther onboard i82596 driver"); +MODULE_PARM(debug, "i"); +//MODULE_PARM(max_interrupt_work, "i"); +//MODULE_PARM(reverse_probe, "i"); +//MODULE_PARM(rx_copybreak, "i"); +MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i"); +MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i"); + +static struct net_device dev_lp486e; +static int full_duplex; +static int options; +static int io = IOADDR; +static int irq = IRQ; + +static int __init lp486e_init_module(void) { + struct net_device *dev = &dev_lp486e; + dev->irq = irq; + dev->base_addr = io; + dev->init = lp486e_probe; + if (register_netdev(dev) != 0) + return -EIO; + full_duplex = 0; + options = 0; + return 0; +} + +static void __exit lp486e_cleanup_module(void) { + unregister_netdev(&dev_lp486e); + kfree((void *)dev_lp486e.mem_start); + dev_lp486e.priv = NULL; + release_region(dev_lp486e.base_addr, LP486E_TOTAL_SIZE); +} + +module_init(lp486e_init_module); +module_exit(lp486e_cleanup_module); diff -u --recursive --new-file v2.4.6/linux/drivers/net/natsemi.c linux/drivers/net/natsemi.c --- v2.4.6/linux/drivers/net/natsemi.c Tue Jul 3 17:08:20 2001 +++ linux/drivers/net/natsemi.c Tue Jul 17 18:53:55 2001 @@ -153,6 +153,7 @@ #include <linux/ethtool.h> #include <linux/delay.h> #include <linux/rtnetlink.h> +#include <linux/mii.h> #include <asm/processor.h> /* Processor type for cache alignment. */ #include <asm/bitops.h> #include <asm/io.h> @@ -737,11 +738,12 @@ of the 100Mbit autodetection circuitry. Also, we only want to do this for rev C of the chip. - There seems to be a typo on page 78: the fixup should be performed - for "DP83815CVNG (SRR = 203h)", but the description of the - SiliconRev regsiters says "DP83815CVNG: 00000302h" + There seems to be a typo on page 78, but there isn't. The fixup + should be performed for "DP83815CVNG (SRR = 203h)", which is a + pretty old rev. This is not to be confused with 302h, which is + current. Confirmed with engineers at NSC. */ - if (readl(ioaddr + SiliconRev) == 0x302) { + if (readl(ioaddr + SiliconRev) == 0x203) { writew(0x0001, ioaddr + PGSEL); writew(0x189C, ioaddr + PMDCSR); writew(0x0000, ioaddr + TSTDAT); @@ -1035,14 +1037,13 @@ /* The ring is no longer full, wake queue. */ netif_wake_queue(dev); } - spin_unlock(&np->lock); - } + /* The interrupt handler does all of the Rx thread work and cleans up after the Tx thread. */ static void intr_handler(int irq, void *dev_instance, struct pt_regs *rgs) { - struct net_device *dev = (struct net_device *)dev_instance; + struct net_device *dev = dev_instance; struct netdev_private *np; long ioaddr; int boguscnt = max_interrupt_work; @@ -1335,8 +1336,8 @@ } writel(rx_mode, ioaddr + RxFilterAddr); np->cur_rx_mode = rx_mode; - spin_unlock_irq(&np->lock); } + static void set_rx_mode(struct net_device *dev) { struct netdev_private *np = dev->priv; @@ -1372,23 +1373,28 @@ static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { struct netdev_private *np = dev->priv; - u16 *data = (u16 *)&rq->ifr_data; + struct mii_ioctl_data *data = (struct mii_ioctl_data *)&rq->ifr_data; switch(cmd) { case SIOCETHTOOL: return netdev_ethtool_ioctl(dev, (void *) rq->ifr_data); - case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */ - data[0] = 1; + case SIOCGMIIPHY: /* Get address of MII PHY in use. */ + case SIOCDEVPRIVATE: /* for binary compat, remove in 2.5 */ + data->phy_id = 1; /* Fall Through */ - case SIOCDEVPRIVATE+1: /* Read the specified MII register. */ - data[3] = mdio_read(dev, data[0] & 0x1f, data[1] & 0x1f); + + case SIOCGMIIREG: /* Read MII PHY register. */ + case SIOCDEVPRIVATE+1: /* for binary compat, remove in 2.5 */ + data->val_out = mdio_read(dev, data->phy_id & 0x1f, data->reg_num & 0x1f); return 0; - case SIOCDEVPRIVATE+2: /* Write the specified MII register */ + + case SIOCSMIIREG: /* Write MII PHY register. */ + case SIOCDEVPRIVATE+2: /* for binary compat, remove in 2.5 */ if (!capable(CAP_NET_ADMIN)) return -EPERM; - if (data[0] == 1) { - u16 miireg = data[1] & 0x1f; - u16 value = data[2]; + if (data->phy_id == 1) { + u16 miireg = data->reg_num & 0x1f; + u16 value = data->val_in; writew(value, dev->base_addr + 0x80 + (miireg << 2)); switch (miireg) { case 4: np->advertising = value; break; diff -u --recursive --new-file v2.4.6/linux/drivers/net/ne.c linux/drivers/net/ne.c --- v2.4.6/linux/drivers/net/ne.c Tue Jul 3 17:08:20 2001 +++ linux/drivers/net/ne.c Tue Jul 17 18:53:55 2001 @@ -8,9 +8,8 @@ This software may be used and distributed according to the terms of the GNU General Public License, incorporated herein by reference. - The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O - Center of Excellence in Space Data and Information Sciences - Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771 + The author may be reached as becker@scyld.com, or C/O + Scyld Computing Corporation, 410 Severn Ave., Suite 210, Annapolis MD 21403 This driver should work with many programmed-I/O 8390-based ethernet boards. Currently it supports the NE1000, NE2000, many clones, diff -u --recursive --new-file v2.4.6/linux/drivers/net/net_init.c linux/drivers/net/net_init.c --- v2.4.6/linux/drivers/net/net_init.c Wed May 16 10:25:39 2001 +++ linux/drivers/net/net_init.c Tue Jul 17 18:53:55 2001 @@ -2,9 +2,10 @@ /* Written 1993,1994,1995 by Donald Becker. - The author may be reached as becker@cesdis.gsfc.nasa.gov or - C/O Center of Excellence in Space Data and Information Sciences - Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771 + The author may be reached as becker@scyld.com, or C/O + Scyld Computing Corporation + 410 Severn Ave., Suite 210 + Annapolis MD 21403 This file contains the initialization for the "pl14+" style ethernet drivers. It should eventually replace most of drivers/net/Space.c. diff -u --recursive --new-file v2.4.6/linux/drivers/net/pcmcia/3c574_cs.c linux/drivers/net/pcmcia/3c574_cs.c --- v2.4.6/linux/drivers/net/pcmcia/3c574_cs.c Wed Apr 18 14:40:05 2001 +++ linux/drivers/net/pcmcia/3c574_cs.c Tue Jul 17 18:53:55 2001 @@ -1,7 +1,7 @@ /* 3c574.c: A PCMCIA ethernet driver for the 3com 3c574 "RoadRunner". Written 1993-1998 by - Donald Becker, becker@cesdis.gsfc.nasa.gov, (driver core) and + Donald Becker, becker@scyld.com, (driver core) and David Hinds, dahinds@users.sourceforge.net (from his PC card code). This software may be used and distributed according to the terms of @@ -16,7 +16,7 @@ /* Driver author info must always be in the binary. Version too.. */ static const char *tc574_version = -"3c574_cs.c v1.08 9/24/98 Donald Becker/David Hinds, becker@cesdis.gsfc.nasa.gov.\n"; +"3c574_cs.c v1.08 9/24/98 Donald Becker/David Hinds, becker@scyld.com.\n"; /* Theory of Operation @@ -217,7 +217,7 @@ MODULE_PARM(pc_debug, "i"); #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) static char *version = -"3c574_cs.c 1.000 1998/1/8 Donald Becker, becker@cesdis.gsfc.nasa.gov.\n"; +"3c574_cs.c 1.000 1998/1/8 Donald Becker, becker@scyld.com.\n"; #else #define DEBUG(n, args...) #endif diff -u --recursive --new-file v2.4.6/linux/drivers/net/pcmcia/3c589_cs.c linux/drivers/net/pcmcia/3c589_cs.c --- v2.4.6/linux/drivers/net/pcmcia/3c589_cs.c Wed Apr 18 14:40:05 2001 +++ linux/drivers/net/pcmcia/3c589_cs.c Tue Jul 17 18:53:55 2001 @@ -13,7 +13,7 @@ Director, National Security Agency. This software may be used and distributed according to the terms of the GNU General Public License, incorporated herein by reference. - Donald Becker may be reached at becker@cesdis1.gsfc.nasa.gov + Donald Becker may be reached at becker@scyld.com ======================================================================*/ diff -u --recursive --new-file v2.4.6/linux/drivers/net/pcmcia/fmvj18x_cs.c linux/drivers/net/pcmcia/fmvj18x_cs.c --- v2.4.6/linux/drivers/net/pcmcia/fmvj18x_cs.c Wed Apr 18 14:40:05 2001 +++ linux/drivers/net/pcmcia/fmvj18x_cs.c Tue Jul 17 18:53:55 2001 @@ -21,9 +21,9 @@ This software may be used and distributed according to the terms of the GNU General Public License, incorporated herein by reference. - The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O - Center of Excellence in Space Data and Information Sciences - Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771 + The author may be reached as becker@scyld.com, or C/O + Scyld Computing Corporation + 410 Severn Ave., Suite 210, Annapolis MD 21403 ======================================================================*/ diff -u --recursive --new-file v2.4.6/linux/drivers/net/pcmcia/ibmtr_cs.c linux/drivers/net/pcmcia/ibmtr_cs.c --- v2.4.6/linux/drivers/net/pcmcia/ibmtr_cs.c Tue Jul 3 17:08:20 2001 +++ linux/drivers/net/pcmcia/ibmtr_cs.c Wed Jul 4 11:50:39 2001 @@ -25,20 +25,9 @@ All we do here is set the card up enough so that the real ibmtr.c driver can find it and work with it properly. - i.e. We set up the io port, irq, mmio memory and shared ram memory. - This enables ibmtr_probe in ibmtr.c to find the card and configure it - as though it was a normal ISA and/or PnP card. - - There is some confusion with the difference between available shared - ram and the amount actually reserved from memory. ibmtr.c sets up - several offsets depending upon the actual on-board memory, not the - reserved memory. We need to get around this to allow the cards to - work with other cards in restricted memory space. Therefore the - pcmcia_reality_check function. - - TODO - - Write the suspend / resume functions. - - Fix Kernel Oops when removing card before ifconfig down + i.e. We set up the io port, irq, mmio memory and shared ram + memory. This enables ibmtr_probe in ibmtr.c to find the card and + configure it as though it was a normal ISA and/or PnP card. CHANGES @@ -49,16 +38,20 @@ Updated to version 2.2.7 to match the first version of the kernel that the modification to ibmtr.c were incorporated into. + v2.2.17 July 2000 Burt Silverman (burts@us.ibm.com) + Address translation feature of PCMCIA controller is usable so + memory windows can be placed in High memory (meaning above + 0xFFFFF.) + ======================================================================*/ #include <linux/kernel.h> #include <linux/init.h> #include <linux/sched.h> #include <linux/ptrace.h> -#include <linux/slab.h> +#include <linux/malloc.h> #include <linux/string.h> #include <linux/timer.h> -#include <linux/delay.h> #include <linux/module.h> #include <asm/io.h> #include <asm/system.h> @@ -81,8 +74,9 @@ MODULE_PARM(pc_debug, "i"); #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) static char *version = -"ibmtr_cs.c 1.10 1996/01/06 05:19:00 (Steve Kipisz)\n" -" 2.2.7 1999/05/03 12:00:00 (Mike Phillips)\n" ; +"ibmtr_cs.c 1.10 1996/01/06 05:19:00 (Steve Kipisz)\n" +" 2.2.7 1999/05/03 12:00:00 (Mike Phillips)\n" +" 2.4.2 2001/30/28 Midnight (Burt Silverman)\n"; #else #define DEBUG(n, args...) #endif @@ -96,13 +90,13 @@ static int irq_list[4] = { -1 }; /* MMIO base address */ -static u_long mmiobase; +static u_long mmiobase = 0xce000; /* SRAM base address */ -static u_long srambase; +static u_long srambase = 0xd0000; /* SRAM size 8,16,32,64 */ -static u_long sramsize = 16; +static u_long sramsize = 64; /* Ringspeed 4,16 */ static int ringspeed = 16; @@ -117,7 +111,7 @@ /*====================================================================*/ static void ibmtr_config(dev_link_t *link); -static void ibmtr_hw_setup(struct net_device *dev); +static void ibmtr_hw_setup(struct net_device *dev, u_int mmiobase); static void ibmtr_release(u_long arg); static int ibmtr_event(event_t event, int priority, event_callback_args_t *args); @@ -130,18 +124,14 @@ static dev_link_t *dev_list; extern int ibmtr_probe(struct net_device *dev); -unsigned char pcmcia_reality_check(unsigned char gss); - extern int trdev_init(struct net_device *dev); extern void tok_interrupt (int irq, void *dev_id, struct pt_regs *regs); -extern int tok_init_card(struct net_device *dev); -extern unsigned char get_sram_size(struct tok_info *ti); /*====================================================================*/ typedef struct ibmtr_dev_t { dev_link_t link; - struct net_device *dev; /* Changed for 2.2.0 */ + struct net_device *dev; dev_node_t node; window_handle_t sram_win_handle; struct tok_info ti; @@ -217,14 +207,13 @@ link->conf.Present = PRESENT_OPTION; dev = init_trdev(NULL,0); - dev->priv = &info->ti; - link->irq.Instance = info->dev = dev; - if (dev == NULL) { ibmtr_detach(link); return NULL; } - + dev->priv = &info->ti; + link->irq.Instance = info->dev = dev; + dev->init = &ibmtr_probe; /* Register with Card Services */ @@ -262,7 +251,7 @@ { struct ibmtr_dev_t *info = link->priv; dev_link_t **linkp; - struct net_device *dev; + struct net_device *dev; DEBUG(0, "ibmtr_detach(0x%p)\n", link); @@ -291,8 +280,10 @@ /* Unlink device structure, free bits */ *linkp = link->next; - if (link->dev) + if (info->dev) { unregister_trdev(info->dev); + kfree(info->dev); + } kfree(info); } /* ibmtr_detach */ @@ -320,7 +311,6 @@ memreq_t mem; int i, last_ret, last_fn; u_char buf[64]; - unsigned char Shared_Ram_Base; DEBUG(0, "ibmtr_config(0x%p)\n", link); @@ -361,41 +351,40 @@ /* Allocate the MMIO memory window */ req.Attributes = WIN_DATA_WIDTH_16|WIN_MEMORY_TYPE_CM|WIN_ENABLE; - req.Attributes |= WIN_USE_WAIT|WIN_STRICT_ALIGN; - req.Base = mmiobase; + req.Attributes |= WIN_USE_WAIT; + req.Base = 0; req.Size = 0x2000; req.AccessSpeed = 250; link->win = (window_handle_t)link->handle; CS_CHECK(RequestWindow, &link->win, &req); - mem.CardOffset = req.Base; + mem.CardOffset = mmiobase; mem.Page = 0; CS_CHECK(MapMemPage, link->win, &mem); ti->mmio = (u_long)ioremap(req.Base, req.Size); /* Allocate the SRAM memory window */ req.Attributes = WIN_DATA_WIDTH_16|WIN_MEMORY_TYPE_CM|WIN_ENABLE; - req.Attributes |= WIN_USE_WAIT|WIN_MAP_BELOW_1MB; - req.Base = srambase; + req.Attributes |= WIN_USE_WAIT; + req.Base = 0; req.Size = sramsize * 1024; req.AccessSpeed = 250; info->sram_win_handle = (window_handle_t)link->handle; CS_CHECK(RequestWindow, &info->sram_win_handle, &req); - mem.CardOffset = req.Base; + mem.CardOffset = srambase; mem.Page = 0; CS_CHECK(MapMemPage, info->sram_win_handle, &mem); - Shared_Ram_Base = req.Base >> 12; - - ti->sram = 0; - ti->sram_base = Shared_Ram_Base; - + + ti->sram_base = mem.CardOffset >> 12; + ti->sram_virt = (u_long)ioremap(req.Base, req.Size); + CS_CHECK(RequestConfiguration, link->handle, &link->conf); /* Set up the Token-Ring Controller Configuration Register and turn on the card. Check the "Local Area Network Credit Card Adapters Technical Reference" SC30-3585 for this info. */ - ibmtr_hw_setup(dev); + ibmtr_hw_setup(dev, mmiobase); i = register_trdev(dev); @@ -477,18 +466,20 @@ struct net_device *dev = info->dev; DEBUG(1, "ibmtr_event(0x%06x)\n", event); - + switch (event) { case CS_EVENT_CARD_REMOVAL: link->state &= ~DEV_PRESENT; if (link->state & DEV_CONFIG) { + /* set flag to bypass normal interrupt code */ + ((struct tok_info *)dev->priv)->sram_virt |= 1; netif_device_detach(dev); mod_timer(&link->release, jiffies + HZ/20); } break; case CS_EVENT_CARD_INSERTION: link->state |= DEV_PRESENT; - ibmtr_config(link); + ibmtr_config(link); break; case CS_EVENT_PM_SUSPEND: link->state |= DEV_SUSPEND; @@ -518,10 +509,9 @@ /*====================================================================*/ -static void ibmtr_hw_setup(struct net_device *dev) +static void ibmtr_hw_setup(struct net_device *dev, u_int mmiobase) { - struct tok_info *ti = dev->priv; - int i; + int i; /* Bizarre IBM behavior, there are 16 bits of information we need to set, but the card only allows us to send 4 bits at a @@ -530,11 +520,11 @@ the actual information */ /* First nibble provides 4 bits of mmio */ - i = ((int)ti->mmio >> 16) & 0x0F; + i = (mmiobase >> 16) & 0x0F; outb(i, dev->base_addr); /* Second nibble provides 3 bits of mmio */ - i = 0x10 | (((int)ti->mmio >> 12) & 0x0E); + i = 0x10 | ((mmiobase >> 12) & 0x0E); outb(i, dev->base_addr); /* Third nibble, hard-coded values */ @@ -544,8 +534,7 @@ /* Fourth nibble sets shared ram page size */ /* 8 = 00, 16 = 01, 32 = 10, 64 = 11 */ - - i = (sramsize >> 4) & 0x07; + i = (sramsize >> 4) & 0x07; i = ((i == 4) ? 3 : i) << 2; i |= 0x30; @@ -555,28 +544,10 @@ i |= 1; outb(i, dev->base_addr); - /* X40 will release the card for use */ - + /* 0x40 will release the card for use */ outb(0x40, dev->base_addr); - - return; -} -/*====================================================================== - - A sweet little function that circumvents the problem with - ibmtr.c trying to use more memory than we can allocate for - the PCMCIA card. ibmtr.c just assumes that if a card has - 64K of shared ram, the entire 64K must be mapped into memory, - whereas resources are sometimes a little tight in card services - so we fool ibmtr.c into thinking the card has less memory on - it than it has. - -======================================================================*/ - -unsigned char pcmcia_reality_check(unsigned char gss) -{ - return (gss < sramsize) ? sramsize : gss; + return; } /*====================================================================*/ @@ -584,7 +555,7 @@ static int __init init_ibmtr_cs(void) { servinfo_t serv; - DEBUG(0, "%s\n", version); + DEBUG(0, "%s", version); CardServices(GetCardServicesInfo, &serv); if (serv.Revision != CS_RELEASE_CODE) { printk(KERN_NOTICE "ibmtr_cs: Card Services release " diff -u --recursive --new-file v2.4.6/linux/drivers/net/pcmcia/nmclan_cs.c linux/drivers/net/pcmcia/nmclan_cs.c --- v2.4.6/linux/drivers/net/pcmcia/nmclan_cs.c Wed Apr 18 14:40:05 2001 +++ linux/drivers/net/pcmcia/nmclan_cs.c Tue Jul 17 18:53:55 2001 @@ -27,7 +27,7 @@ Tom Pollard, New Media Corporation Dean Siasoyco, New Media Corporation Ken Lesniak, Silicon Graphics, Inc. <lesniak@boston.sgi.com> - Donald Becker <becker@cesdis1.gsfc.nasa.gov> + Donald Becker <becker@scyld.com> David Hinds <dahinds@users.sourceforge.net> The Linux client driver is based on the 3c589_cs.c client driver by diff -u --recursive --new-file v2.4.6/linux/drivers/net/pcmcia/pcnet_cs.c linux/drivers/net/pcmcia/pcnet_cs.c --- v2.4.6/linux/drivers/net/pcmcia/pcnet_cs.c Fri Apr 20 11:54:22 2001 +++ linux/drivers/net/pcmcia/pcnet_cs.c Tue Jul 17 18:53:55 2001 @@ -20,7 +20,7 @@ Director, National Security Agency. This software may be used and distributed according to the terms of the GNU General Public License, incorporated herein by reference. - Donald Becker may be reached at becker@cesdis1.gsfc.nasa.gov + Donald Becker may be reached at becker@scyld.com. Based also on Keith Moore's changes to Don Becker's code, for IBM CCAE support. Drivers merged back together, and shared-memory diff -u --recursive --new-file v2.4.6/linux/drivers/net/pcmcia/smc91c92_cs.c linux/drivers/net/pcmcia/smc91c92_cs.c --- v2.4.6/linux/drivers/net/pcmcia/smc91c92_cs.c Wed Apr 18 14:40:05 2001 +++ linux/drivers/net/pcmcia/smc91c92_cs.c Tue Jul 17 18:53:55 2001 @@ -11,7 +11,7 @@ smc91c92_cs.c 1.106 2001/02/07 00:19:58 This driver contains code written by Donald Becker - (becker@cesdis.gsfc.nasa.gov), Rowan Hughes (x-csrdh@jcu.edu.au), + (becker@scyld.com), Rowan Hughes (x-csrdh@jcu.edu.au), David Hinds (dahinds@users.sourceforge.net), and Erik Stahlman (erik@vt.edu). Donald wrote the SMC 91c92 code using parts of Erik's SMC 91c94 driver. Rowan wrote a similar driver, and I've @@ -60,7 +60,7 @@ static int pc_debug = PCMCIA_DEBUG; MODULE_PARM(pc_debug, "i"); static const char *version = -"smc91c92_cs.c 0.09 1996/8/4 Donald Becker, becker@cesdis.gsfc.nasa.gov.\n"; +"smc91c92_cs.c 0.09 1996/8/4 Donald Becker, becker@scyld.com.\n"; #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) #else #define DEBUG(n, args...) diff -u --recursive --new-file v2.4.6/linux/drivers/net/pcmcia/xircom_tulip_cb.c linux/drivers/net/pcmcia/xircom_tulip_cb.c --- v2.4.6/linux/drivers/net/pcmcia/xircom_tulip_cb.c Tue Jul 3 17:08:20 2001 +++ linux/drivers/net/pcmcia/xircom_tulip_cb.c Tue Jul 17 18:53:55 2001 @@ -9,17 +9,17 @@ It should work with most DEC 21*4*-based chips/ethercards, as well as with work-alike chips from Lite-On (PNIC) and Macronix (MXIC) and ASIX. - The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O - Center of Excellence in Space Data and Information Sciences - Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771 + The author may be reached as becker@scyld.com, or C/O + Scyld Computing Corporation + 410 Severn Ave., Suite 210 + Annapolis MD 21403 Support and updates available at http://cesdis.gsfc.nasa.gov/linux/drivers/tulip.html */ -#define SMP_CHECK #define CARDBUS 1 -static const char version[] = "xircom_tulip_cb.c:v0.91 4/14/99 becker@cesdis.gsfc.nasa.gov (modified by danilo@cs.uni-magdeburg.de for XIRCOM CBE, fixed by Doug Ledford)\n"; +static const char version[] = "xircom_tulip_cb.c:v0.91 4/14/99 becker@scyld.com (modified by danilo@cs.uni-magdeburg.de for XIRCOM CBE, fixed by Doug Ledford)\n"; /* A few user-configurable values. */ @@ -84,11 +84,6 @@ /* Time in jiffies before concluding the transmitter is hung. */ #define TX_TIMEOUT (4*HZ) #define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer.*/ -/* This is a mysterious value that can be written to CSR11 in the 21040 (only) - to support a pre-NWay full-duplex signaling mechanism using short frames. - No one knows what it should be, but if left at its default value some - 10base2(!) packets trigger a full-duplex-request interrupt. */ -#define FULL_DUPLEX_MAGIC 0x6969 #if !defined(__OPTIMIZE__) || !defined(__KERNEL__) #warning You must compile this file with the correct options! @@ -99,32 +94,20 @@ #include <linux/version.h> #include <linux/module.h> #include <linux/kernel.h> -#include <linux/sched.h> -#include <linux/string.h> -#include <linux/timer.h> -#include <linux/errno.h> -#include <linux/ioport.h> -#include <linux/slab.h> -#include <linux/interrupt.h> #include <linux/pci.h> #include <linux/netdevice.h> #include <linux/etherdevice.h> -#include <linux/skbuff.h> #include <linux/delay.h> #include <linux/init.h> #include <asm/processor.h> /* Processor type for cache alignment. */ -#include <asm/bitops.h> -#include <asm/io.h> -#include <asm/unaligned.h> /* Kernel compatibility defines, some common to David Hinds' PCMCIA package. This is only in the support-all-kernels source code. */ -MODULE_AUTHOR("Donald Becker <becker@cesdis.gsfc.nasa.gov>"); +MODULE_AUTHOR("Donald Becker <becker@scyld.com>"); MODULE_DESCRIPTION("Digital 21*4* Tulip ethernet driver"); MODULE_PARM(debug, "i"); MODULE_PARM(max_interrupt_work, "i"); -MODULE_PARM(reverse_probe, "i"); MODULE_PARM(rx_copybreak, "i"); MODULE_PARM(csr0, "i"); MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i"); @@ -162,12 +145,6 @@ need to be set on the board. The system BIOS preferably should assign the PCI INTA signal to an otherwise unused system IRQ line. -Some boards have EEPROMs tables with default media entry. The factory default -is usually "autoselect". This should only be overridden when using -transceiver connections without link beat e.g. 10base2 or AUI, or (rarely!) -for forcing full-duplex when used with old link partners that do not do -autonegotiation. - III. Driver operation IIIa. Ring buffers @@ -214,42 +191,23 @@ IV. Notes -Thanks to Duke Kamstra of SMC for long ago providing an EtherPower board. -Greg LaPolla at Linksys provided PNIC and other Linksys boards. -Znyx provided a four-port card for testing. - IVb. References http://cesdis.gsfc.nasa.gov/linux/misc/NWay.html http://www.digital.com (search for current 21*4* datasheets and "21X4 SROM") http://www.national.com/pf/DP/DP83840A.html -http://www.asix.com.tw/pmac.htm -http://www.admtek.com.tw/ IVc. Errata -The old DEC databooks were light on details. -The 21040 databook claims that CSR13, CSR14, and CSR15 should each be the last -register of the set CSR12-15 written. Hmmm, now how is that possible? - -The DEC SROM format is very badly designed not precisely defined, leading to -part of the media selection junkheap below. Some boards do not have EEPROM -media tables and need to be patched up. Worse, other boards use the DEC -design kit media table when it isn't correct for their board. - We cannot use MII interrupts because there is no defined GPIO pin to attach them. The MII transceiver status is polled using an kernel timer. */ -/* This table use during operation for capabilities and media timer. */ - static void tulip_timer(unsigned long data); enum tbl_flag { - HAS_MII=1, HAS_MEDIA_TABLE=2, CSR12_IN_SROM=4, ALWAYS_CHECK_MII=8, - HAS_ACPI=0x10, MC_HASH_ONLY=0x20, /* Hash-only multicast filter. */ - HAS_NWAY143=0x40, /* Uses 21143-like internal NWay. */ + HAS_MII=1, HAS_ACPI=2, }; static struct tulip_chip_table { char *chip_name; @@ -262,11 +220,9 @@ HAS_MII | HAS_ACPI, tulip_timer }, {0}, }; -/* This matches the table above. Note 21142 == 21143. */ +/* This matches the table above. */ enum chips { X3201_3, - DC21040, DC21041, DC21140, DC21142=4, DC21143=4, - LC82C168, MX98713, MX98715, MX98725, AX88140, PNIC2, COMET, COMPEX9881, }; /* A full-duplex map for media types. */ @@ -275,13 +231,6 @@ MediaIs100=16}; static const char media_cap[] = {0,0,0,16, 3,19,16,24, 27,4,7,5, 0,20,23,20 }; -static u8 t21040_csr13[] = {2,0x0C,8,4, 4,0,0,0, 0,0,0,0, 4,0,0,0}; -/* 21041 transceiver register settings: 10-T, 10-2, AUI, 10-T, 10T-FD*/ -static u16 t21041_csr13[] = { 0xEF05, 0xEF09, 0xEF09, 0xEF01, 0xEF09, }; -static u16 t21041_csr14[] = { 0x7F3F, 0xF7FD, 0xF7FD, 0x7F3F, 0x7F3D, }; -static u16 t21041_csr15[] = { 0x0008, 0x0006, 0x000E, 0x0008, 0x0008, }; - -static u16 t21142_csr14[] = { 0xFFFF, 0x0705, 0x0705, 0x0000, 0x7F3D, }; /* Offsets to the Command and Status Registers, "CSRs". All accesses must be longword instructions and quadword aligned. */ @@ -325,34 +274,6 @@ */ #define DESC_RING_WRAP 0x02000000 -#ifdef CARDBUS -#define EEPROM_ADDRLEN (chip_rev == 65 ? 8 : 6) -#else -#define EEPROM_ADDRLEN 6 -#endif -#define EEPROM_SIZE 128 /* 2 << EEPROM_ADDRLEN */ - -struct medialeaf { - u8 type; - u8 media; - unsigned char *leafdata; -}; - -struct mediatable { - u16 defaultmedia; - u8 leafcount, csr12dir; /* General purpose pin directions. */ - unsigned has_mii:1, has_nonmii:1, has_reset:6; - u32 csr15dir, csr15val; /* 21143 NWay setting. */ - struct medialeaf mleaf[0]; -}; - -struct mediainfo { - struct mediainfo *next; - int info_type; - int index; - unsigned char *info; -}; - struct tulip_private { char devname[8]; /* Used only for kernel debugging. */ const char *product_name; @@ -379,38 +300,26 @@ unsigned int tx_full:1; /* The Tx queue is full. */ unsigned int full_duplex:1; /* Full-duplex operation requested. */ unsigned int full_duplex_lock:1; - unsigned int fake_addr:1; /* Multiport board faked address. */ unsigned int default_port:4; /* Last dev->if_port value. */ - unsigned int media2:4; /* Secondary monitored media port. */ unsigned int medialock:1; /* Don't sense media type. */ unsigned int mediasense:1; /* Media sensing in progress. */ - unsigned int nway:1, nwayset:1; /* 21143 internal NWay. */ unsigned int open:1; unsigned int csr0; /* CSR0 setting. */ unsigned int csr6; /* Current CSR6 control settings. */ - unsigned char eeprom[EEPROM_SIZE]; /* Serial EEPROM contents. */ u16 to_advertise; /* NWay capabilities advertised. */ - u16 lpar; /* 21143 Link partner ability. */ u16 advertising[4]; signed char phys[4], mii_cnt; /* MII device addresses. */ - struct mediatable *mtable; - int cur_index; /* Current media index. */ int saved_if_port; struct pci_dev *pdev; spinlock_t lock; - int pad0, pad1; /* Used for 8-byte alignment */ }; -static void parse_eeprom(struct net_device *dev); -static int read_eeprom(long ioaddr, int location, int addr_len); static int mdio_read(struct net_device *dev, int phy_id, int location); static void mdio_write(struct net_device *dev, int phy_id, int location, int value); -static void select_media(struct net_device *dev, int startup); static void tulip_up(struct net_device *dev); static void tulip_down(struct net_device *dev); static int tulip_open(struct net_device *dev); static void tulip_timer(unsigned long data); -static void t21142_start_nway(struct net_device *dev); static void tulip_tx_timeout(struct net_device *dev); static void tulip_init_ring(struct net_device *dev); static int tulip_start_xmit(struct sk_buff *skb, struct net_device *dev); @@ -433,11 +342,6 @@ long flags; save_flags(flags); cli(); - if (chip_idx != X3201_3) { - outl(newcsr6, ioaddr + CSR6); - restore_flags(flags); - return; - } newcsr6 &= 0x726cfecb; /* mask out the reserved CSR6 bits that always */ /* read 0 on the Xircom cards */ newcsr6 |= 0x320c0000; /* or in the reserved bits that always read 1 */ @@ -481,13 +385,8 @@ static int did_version; /* Already printed version info. */ struct net_device *dev; struct tulip_private *tp; - /* See note below on the multiport cards. */ - static unsigned char last_phys_addr[6] = {0x00, 'L', 'i', 'n', 'u', 'x'}; - static int last_irq; - static int multiport_cnt; /* For four-port boards w/one EEPROM */ u8 chip_rev; int i; - unsigned short sum; if (tulip_debug > 0 && did_version++ == 0) printk(KERN_INFO "%s", version); @@ -511,34 +410,7 @@ be polled, waiting for the value to be read bit serially from the EEPROM. */ - sum = 0; - if (chip_idx == DC21040) { - outl(0, ioaddr + CSR9); /* Reset the pointer with a dummy write. */ - for (i = 0; i < 6; i++) { - int value, boguscnt = 100000; - do - value = inl(ioaddr + CSR9); - while (value < 0 && --boguscnt > 0); - dev->dev_addr[i] = value; - sum += value & 0xff; - } - } else if (chip_idx == LC82C168) { - for (i = 0; i < 3; i++) { - int value, boguscnt = 100000; - outl(0x600 | i, ioaddr + 0x98); - do - value = inl(ioaddr + CSR9); - while (value < 0 && --boguscnt > 0); - put_unaligned(le16_to_cpu(value), ((u16*)dev->dev_addr) + i); - sum += value & 0xffff; - } - } else if (chip_idx == COMET) { - /* No need to read the EEPROM. */ - put_unaligned(inl(ioaddr + 0xA4), (u32 *)dev->dev_addr); - put_unaligned(inl(ioaddr + 0xA8), (u16 *)(dev->dev_addr + 4)); - for (i = 0; i < 6; i ++) - sum += dev->dev_addr[i]; - } else if (chip_idx == X3201_3) { + if (chip_idx == X3201_3) { /* Xircom has its address stored in the CIS * we access it through the boot rom interface for now * this might not work, as the CIS is not parsed but I @@ -574,58 +446,8 @@ break; } } - sum = 1; // to make check below fail! - } else { /* Must be a new chip, with a serial EEPROM interface. */ - /* We read the whole EEPROM, and sort it out later. DEC has a - specification _Digital Semiconductor 21X4 Serial ROM Format_ - but early vendor boards just put the address in the first six - EEPROM locations. */ - unsigned char ee_data[EEPROM_SIZE]; - int sa_offset = 0; - - for (i = 0; i < sizeof(ee_data)/2; i++) - ((u16 *)ee_data)[i] = - le16_to_cpu(read_eeprom(ioaddr, i, EEPROM_ADDRLEN)); - - /* Detect the simple EEPROM format by the duplicated station addr. */ - for (i = 0; i < 8; i ++) - if (ee_data[i] != ee_data[16+i]) - sa_offset = 20; - if (ee_data[0] == 0xff && ee_data[1] == 0xff && ee_data[2] == 0) { - sa_offset = 2; /* Grrr, damn Matrox boards. */ - multiport_cnt = 4; - } - for (i = 0; i < 6; i ++) { - dev->dev_addr[i] = ee_data[i + sa_offset]; - sum += ee_data[i + sa_offset]; - } - } - /* Lite-On boards have the address byte-swapped. */ - if ((dev->dev_addr[0] == 0xA0 || dev->dev_addr[0] == 0xC0) - && dev->dev_addr[1] == 0x00) - for (i = 0; i < 6; i+=2) { - char tmp = dev->dev_addr[i]; - dev->dev_addr[i] = dev->dev_addr[i+1]; - dev->dev_addr[i+1] = tmp; - } - /* On the Zynx 315 Etherarray and other multiport boards only the - first Tulip has an EEPROM. - The addresses of the subsequent ports are derived from the first. - Many PCI BIOSes also incorrectly report the IRQ line, so we correct - that here as well. */ - if (sum == 0 || sum == 6*0xff) { - printk(" EEPROM not present,"); - for (i = 0; i < 5; i++) - dev->dev_addr[i] = last_phys_addr[i]; - dev->dev_addr[i] = last_phys_addr[i] + 1; -#if defined(__i386__) /* Patch up x86 BIOS bug. */ - if (last_irq) - irq = last_irq; -#endif } - last_irq = irq; - /* We do a request_region() only to register /proc/ioports info. */ request_region(ioaddr, tulip_tbl[chip_idx].io_size, "xircom_tulip_cb"); @@ -646,11 +468,8 @@ /* BugFixes: The 21143-TD hangs with PCI Write-and-Invalidate cycles. And the ASIX must have a burst limit or horrible things happen. */ - if ( (chip_idx == DC21143 && chip_rev == 65) || - (chip_idx == X3201_3) ) + if (chip_idx == X3201_3) tp->csr0 &= ~0x01000000; - else if (chip_idx == AX88140) - tp->csr0 |= 0x2000; /* The lower four bits are the media type. */ if (board_idx >= 0 && board_idx < MAX_UNITS) { @@ -670,30 +489,14 @@ if (tp->full_duplex) tp->full_duplex_lock = 1; - /* This is logically part of probe1(), but too complex to write inline. */ - if (tulip_tbl[chip_idx].flags & HAS_MEDIA_TABLE) - parse_eeprom(dev); - if (media_cap[tp->default_port] & MediaIsMII) { u16 media2advert[] = { 0x20, 0x40, 0x03e0, 0x60, 0x80, 0x100, 0x200 }; tp->to_advertise = media2advert[tp->default_port - 9]; } else tp->to_advertise = 0x03e1; - if ((tulip_tbl[chip_idx].flags & ALWAYS_CHECK_MII) || - (tp->mtable && tp->mtable->has_mii) || - ( ! tp->mtable && (tulip_tbl[chip_idx].flags & HAS_MII))) { + if (tulip_tbl[chip_idx].flags & HAS_MII) { int phy, phy_idx; - if (tp->mtable && tp->mtable->has_mii) { - for (i = 0; i < tp->mtable->leafcount; i++) - if (tp->mtable->mleaf[i].media == 11) { - tp->cur_index = i; - tp->saved_if_port = dev->if_port; - select_media(dev, 1); - dev->if_port = tp->saved_if_port; - break; - } - } /* Find the connected MII xcvrs. Doing this in open() would allow detecting external xcvrs later, but takes much time. */ @@ -724,7 +527,7 @@ } } tp->mii_cnt = phy_idx; - if (tp->mtable && tp->mtable->has_mii && phy_idx == 0) { + if (phy_idx == 0) { printk(KERN_INFO "xircom(%s): ***WARNING***: No MII transceiver found!\n", pdev->slot_name); tp->phys[0] = 1; @@ -747,10 +550,6 @@ /* Reset the xcvr interface and turn on heartbeat. */ switch (chip_idx) { - case DC21140: default: - if (tp->mtable) - outl(tp->mtable->csr12dir | 0x100, ioaddr + CSR12); - break; case X3201_3: outl(0x0008, ioaddr + CSR15); udelay(5); /* The delays are Xircom recommended to give the @@ -767,8 +566,6 @@ if (register_netdev(dev)) { request_region(ioaddr, tulip_tbl[chip_idx].io_size, "xircom_tulip_cb"); - if (tp->mtable) - kfree(tp->mtable); kfree(dev->priv); kfree(dev); return NULL; @@ -777,282 +574,11 @@ printk(KERN_INFO "%s: %s rev %d at %#3lx,", dev->name, tulip_tbl[chip_idx].chip_name, chip_rev, ioaddr); for (i = 0; i < 6; i++) - printk("%c%2.2X", i ? ':' : ' ', - last_phys_addr[i] = dev->dev_addr[i]); + printk("%c%2.2X", i ? ':' : ' ', dev->dev_addr[i]); printk(", IRQ %d.\n", irq); return dev; } - -/* Serial EEPROM section. */ -/* The main routine to parse the very complicated SROM structure. - Search www.digital.com for "21X4 SROM" to get details. - This code is very complex, and will require changes to support - additional cards, so I'll be verbose about what is going on. - */ - -/* Known cards that have old-style EEPROMs. */ -static struct fixups { - char *name; - unsigned char addr0, addr1, addr2; - u16 newtable[32]; /* Max length below. */ -} eeprom_fixups[] = { - {"Asante", 0, 0, 0x94, {0x1e00, 0x0000, 0x0800, 0x0100, 0x018c, - 0x0000, 0x0000, 0xe078, 0x0001, 0x0050, 0x0018 }}, - {"SMC9332DST", 0, 0, 0xC0, { 0x1e00, 0x0000, 0x0800, 0x021f, - 0x0000, 0x009E, /* 10baseT */ - 0x0903, 0x006D, /* 100baseTx */ }}, - {"Cogent EM100", 0, 0, 0x92, { 0x1e00, 0x0000, 0x0800, 0x033f, - 0x0107, 0x8021, /* 100baseFx */ - 0x0108, 0x8021, /* 100baseFx-FD */ - 0x0103, 0x006D, /* 100baseTx */ }}, - {"Maxtech NX-110", 0, 0, 0xE8, { 0x1e00, 0x0000, 0x0800, 0x0313, - 0x1001, 0x009E, /* 10base2, CSR12 0x10*/ - 0x0000, 0x009E, /* 10baseT */ - 0x0303, 0x006D, /* 100baseTx, CSR12 0x03 */ }}, - {"Accton EN1207", 0, 0, 0xE8, { 0x1e00, 0x0000, 0x0800, 0x031F, - 0x1B01, 0x0000, /* 10base2, CSR12 0x1B */ - 0x1B03, 0x006D, /* 100baseTx, CSR12 0x1B */ - 0x0B00, 0x009E, /* 10baseT, CSR12 0x0B */ - }}, - {0, 0, 0, 0, {}}}; - -static const char * block_name[] = {"21140 non-MII", "21140 MII PHY", - "21142 Serial PHY", "21142 MII PHY", "21143 SYM PHY", "21143 reset method"}; - -#if defined(__i386__) /* AKA get_unaligned() */ -#define get_u16(ptr) (*(u16 *)(ptr)) -#else -#define get_u16(ptr) (((u8*)(ptr))[0] + (((u8*)(ptr))[1]<<8)) -#endif - -static void parse_eeprom(struct net_device *dev) -{ - /* The last media info list parsed, for multiport boards. */ - static struct mediatable *last_mediatable; - static unsigned char *last_ee_data; - static int controller_index; - struct tulip_private *tp = (struct tulip_private *)dev->priv; - long ioaddr = dev->base_addr; - unsigned char *ee_data = tp->eeprom; - int i; -#ifdef CARDBUS - int chip_rev = tp->revision; -#endif - - tp->mtable = 0; - for (i = 0; i < EEPROM_SIZE/2; i++) - ((u16 *)ee_data)[i] = - le16_to_cpu(read_eeprom(ioaddr, i, EEPROM_ADDRLEN)); - - /* Detect an old-style (SA only) EEPROM layout: - memcmp(eedata, eedata+16, 8). */ - for (i = 0; i < 8; i ++) - if (ee_data[i] != ee_data[16+i]) - break; - if (i >= 8) { - if (ee_data[0] == 0xff) { - if (last_mediatable) { - controller_index++; - printk(KERN_INFO "%s: Controller %d of multiport board.\n", - dev->name, controller_index); - tp->mtable = last_mediatable; - ee_data = last_ee_data; - goto subsequent_board; - } else - printk(KERN_INFO "%s: Missing EEPROM, this interface may " - "not work correctly!\n", - dev->name); - return; - } - /* Do a fix-up based on the vendor half of the station address prefix. */ - for (i = 0; eeprom_fixups[i].name; i++) { - if (dev->dev_addr[0] == eeprom_fixups[i].addr0 - && dev->dev_addr[1] == eeprom_fixups[i].addr1 - && dev->dev_addr[2] == eeprom_fixups[i].addr2) { - if (dev->dev_addr[2] == 0xE8 && ee_data[0x1a] == 0x55) - i++; /* An Accton EN1207, not an outlaw Maxtech. */ - memcpy(ee_data + 26, eeprom_fixups[i].newtable, - sizeof(eeprom_fixups[i].newtable)); - printk(KERN_INFO "%s: Old format EEPROM on '%s' board. Using" - " substitute media control info.\n", - dev->name, eeprom_fixups[i].name); - break; - } - } - if (eeprom_fixups[i].name == NULL) { /* No fixup found. */ - printk(KERN_INFO "%s: Old style EEPROM with no media selection " - "information.\n", - dev->name); - return; - } - } - - controller_index = 0; - if (ee_data[19] > 1) { /* Multiport board. */ - last_ee_data = ee_data; - } -subsequent_board: - - if (ee_data[27] == 0) { /* No valid media table. */ - } else if (tp->chip_id == DC21041) { - unsigned char *p = (void *)ee_data + ee_data[27 + controller_index*3]; - short media; - int count; - - media = get_u16(p); - p += 2; - count = *p++; - - printk(KERN_INFO "%s:21041 Media information at %d, default media " - "%4.4x (%s).\n", dev->name, ee_data[27], media, - media & 0x0800 ? "Autosense" : medianame[media & 15]); - for (i = 0; i < count; i++) { - unsigned char media_code = *p++; - u16 csrvals[3]; - int idx; - for (idx = 0; idx < 3; idx++) { - csrvals[idx] = get_u16(p); - p += 2; - } - if (media_code & 0x40) { - printk(KERN_INFO "%s: 21041 media %2.2x (%s)," - " csr13 %4.4x csr14 %4.4x csr15 %4.4x.\n", - dev->name, media_code & 15, medianame[media_code & 15], - csrvals[0], csrvals[1], csrvals[2]); - } else - printk(KERN_INFO "%s: 21041 media #%d, %s.\n", - dev->name, media_code & 15, medianame[media_code & 15]); - } - } else { - unsigned char *p = (void *)ee_data + ee_data[27]; - unsigned char csr12dir = 0; - int count; - struct mediatable *mtable; - u16 media = get_u16(p); - - p += 2; - if (tulip_tbl[tp->chip_id].flags & CSR12_IN_SROM) - csr12dir = *p++; - count = *p++; - mtable = (struct mediatable *) - kmalloc(sizeof(struct mediatable) + count*sizeof(struct medialeaf), - GFP_KERNEL); - if (mtable == NULL) - return; /* Horrible, impossible failure. */ - last_mediatable = tp->mtable = mtable; - mtable->defaultmedia = media; - mtable->leafcount = count; - mtable->csr12dir = csr12dir; - mtable->has_nonmii = mtable->has_mii = mtable->has_reset = 0; - mtable->csr15dir = mtable->csr15val = 0; - - printk(KERN_INFO "%s: EEPROM default media type %s.\n", dev->name, - media & 0x0800 ? "Autosense" : medianame[media & 15]); - for (i = 0; i < count; i++) { - struct medialeaf *leaf = &mtable->mleaf[i]; - - if ((p[0] & 0x80) == 0) { /* 21140 Compact block. */ - leaf->type = 0; - leaf->media = p[0] & 0x3f; - leaf->leafdata = p; - if ((p[2] & 0x61) == 0x01) /* Bogus, but Znyx boards do it. */ - mtable->has_mii = 1; - p += 4; - } else { - leaf->type = p[1]; - if (p[1] == 0x05) { - mtable->has_reset = i; - leaf->media = p[2] & 0x0f; - } else if (p[1] & 1) { - mtable->has_mii = 1; - leaf->media = 11; - } else { - mtable->has_nonmii = 1; - leaf->media = p[2] & 0x0f; - if (p[1] == 2) { - if (leaf->media == 0) { - mtable->csr15dir = get_unaligned((u16*)&p[3])<<16; - mtable->csr15val = get_unaligned((u16*)&p[5])<<16; - } else if (leaf->media == 0x40) { - u32 base15 = get_unaligned((u16*)&p[7]); - mtable->csr15dir = - (get_unaligned((u16*)&p[9])<<16) + base15; - mtable->csr15val = - (get_unaligned((u16*)&p[11])<<16) + base15; - } - } - } - leaf->leafdata = p + 2; - p += (p[0] & 0x3f) + 1; - } - if (tulip_debug > 1 && leaf->media == 11) { - unsigned char *bp = leaf->leafdata; - printk(KERN_INFO "%s: MII interface PHY %d, setup/reset " - "sequences %d/%d long, capabilities %2.2x %2.2x.\n", - dev->name, bp[0], bp[1], bp[1 + bp[1]*2], - bp[5 + bp[2 + bp[1]*2]*2], bp[4 + bp[2 + bp[1]*2]*2]); - } - printk(KERN_INFO "%s: Index #%d - Media %s (#%d) described " - "by a %s (%d) block.\n", - dev->name, i, medianame[leaf->media], leaf->media, - block_name[leaf->type], leaf->type); - } - } -} -/* Reading a serial EEPROM is a "bit" grungy, but we work our way through:->.*/ - -/* EEPROM_Ctrl bits. */ -#define EE_SHIFT_CLK 0x02 /* EEPROM shift clock. */ -#define EE_CS 0x01 /* EEPROM chip select. */ -#define EE_DATA_WRITE 0x04 /* EEPROM chip data in. */ -#define EE_WRITE_0 0x01 -#define EE_WRITE_1 0x05 -#define EE_DATA_READ 0x08 /* EEPROM chip data out. */ -#define EE_ENB (0x4800 | EE_CS) - -/* Delay between EEPROM clock transitions. - Even at 33Mhz current PCI implementations don't overrun the EEPROM clock. - We add a bus turn-around to insure that this remains true. */ -#define eeprom_delay() inl(ee_addr) - -/* The EEPROM commands include the alway-set leading bit. */ -#define EE_WRITE_CMD (5 << addr_len) -#define EE_READ_CMD (6 << addr_len) -#define EE_ERASE_CMD (7 << addr_len) - -static int read_eeprom(long ioaddr, int location, int addr_len) -{ - int i; - unsigned short retval = 0; - long ee_addr = ioaddr + CSR9; - int read_cmd = location | EE_READ_CMD; - - outl(EE_ENB & ~EE_CS, ee_addr); - outl(EE_ENB, ee_addr); - - /* Shift the read command bits out. */ - for (i = 4 + addr_len; i >= 0; i--) { - short dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0; - outl(EE_ENB | dataval, ee_addr); - eeprom_delay(); - outl(EE_ENB | dataval | EE_SHIFT_CLK, ee_addr); - eeprom_delay(); - } - outl(EE_ENB, ee_addr); - - for (i = 16; i > 0; i--) { - outl(EE_ENB | EE_SHIFT_CLK, ee_addr); - eeprom_delay(); - retval = (retval << 1) | ((inl(ee_addr) & EE_DATA_READ) ? 1 : 0); - outl(EE_ENB, ee_addr); - eeprom_delay(); - } - - /* Terminate the EEPROM access. */ - outl(EE_ENB & ~EE_CS, ee_addr); - return retval; -} /* MII transceiver control section. Read and write the MII registers using software-generated serial @@ -1076,36 +602,12 @@ static int mdio_read(struct net_device *dev, int phy_id, int location) { - struct tulip_private *tp = (struct tulip_private *)dev->priv; int i; int read_cmd = (0xf6 << 10) | (phy_id << 5) | location; int retval = 0; long ioaddr = dev->base_addr; long mdio_addr = ioaddr + CSR9; - if (tp->chip_id == LC82C168) { - int i = 1000; - outl(0x60020000 + (phy_id<<23) + (location<<18), ioaddr + 0xA0); - inl(ioaddr + 0xA0); - inl(ioaddr + 0xA0); - while (--i > 0) - if ( ! ((retval = inl(ioaddr + 0xA0)) & 0x80000000)) - return retval & 0xffff; - return 0xffff; - } - - if (tp->chip_id == COMET) { - if (phy_id == 1) { - if (location < 7) - return inl(ioaddr + 0xB4 + (location<<2)); - else if (location == 17) - return inl(ioaddr + 0xD0); - else if (location >= 29 && location <= 31) - return inl(ioaddr + 0xD4 + ((location-29)<<2)); - } - return 0xffff; - } - /* Establish sync by sending at least 32 logic ones. */ for (i = 32; i >= 0; i--) { outl(MDIO_ENB | MDIO_DATA_WRITE1, mdio_addr); @@ -1135,34 +637,11 @@ static void mdio_write(struct net_device *dev, int phy_id, int location, int value) { - struct tulip_private *tp = (struct tulip_private *)dev->priv; int i; int cmd = (0x5002 << 16) | (phy_id << 23) | (location<<18) | value; long ioaddr = dev->base_addr; long mdio_addr = ioaddr + CSR9; - if (tp->chip_id == LC82C168) { - int i = 1000; - outl(cmd, ioaddr + 0xA0); - do - if ( ! (inl(ioaddr + 0xA0) & 0x80000000)) - break; - while (--i > 0); - return; - } - - if (tp->chip_id == COMET) { - if (phy_id != 1) - return; - if (location < 7) - outl(value, ioaddr + 0xB4 + (location<<2)); - else if (location == 17) - outl(value, ioaddr + 0xD0); - else if (location >= 29 && location <= 31) - outl(value, ioaddr + 0xD4 + ((location-29)<<2)); - return; - } - /* Establish sync by sending 32 logic ones. */ for (i = 32; i >= 0; i--) { outl(MDIO_ENB | MDIO_DATA_WRITE1, mdio_addr); @@ -1196,7 +675,7 @@ int i; /* On some chip revs we must set the MII/SYM port before the reset!? */ - if (tp->mii_cnt || (tp->mtable && tp->mtable->has_mii)) + if (tp->mii_cnt) outl_CSR6(0x00040000, ioaddr, tp->chip_id); /* Reset the chip, holding bit 0 set at least 50 PCI cycles. */ @@ -1218,38 +697,7 @@ if (tulip_debug > 1) printk(KERN_DEBUG "%s: tulip_open() irq %d.\n", dev->name, dev->irq); - if (tulip_tbl[tp->chip_id].flags & MC_HASH_ONLY) { - u32 addr_low = cpu_to_le32(get_unaligned((u32 *)dev->dev_addr)); - u32 addr_high = cpu_to_le32(get_unaligned((u16 *)(dev->dev_addr+4))); - if (tp->chip_id == AX88140) { - outl(0, ioaddr + CSR13); - outl(addr_low, ioaddr + CSR14); - outl(1, ioaddr + CSR13); - outl(addr_high, ioaddr + CSR14); - } else if (tp->chip_id == COMET) { - outl(addr_low, ioaddr + 0xA4); - outl(addr_high, ioaddr + 0xA8); - outl(0, ioaddr + 0xAC); - outl(0, ioaddr + 0xB0); - } - } else if (tp->chip_id != X3201_3) { - /* This is set_rx_mode(), but without starting the transmitter. */ - u16 *eaddrs = (u16 *)dev->dev_addr; - u16 *setup_frm = &tp->setup_frame[15*6]; - - /* 21140 bug: you must add the broadcast address. */ - memset(tp->setup_frame, 0xff, 96*sizeof(u16)); - /* Fill the final entry of the table with our physical address. */ - *setup_frm++ = eaddrs[0]; *setup_frm++ = eaddrs[0]; - *setup_frm++ = eaddrs[1]; *setup_frm++ = eaddrs[1]; - *setup_frm++ = eaddrs[2]; *setup_frm++ = eaddrs[2]; - /* Put the setup frame on the Tx list. */ - tp->tx_ring[0].length = 0x68000000 | 192; - tp->tx_ring[0].buffer1 = virt_to_bus(tp->setup_frame); - tp->tx_ring[0].status = DescOwned; - - tp->cur_tx++; - } else { /* X3201_3 */ + { /* X3201_3 */ u16 *eaddrs = (u16 *)dev->dev_addr; u16 *setup_frm = &tp->setup_frame[0*6]; @@ -1277,78 +725,10 @@ tp->saved_if_port = dev->if_port; if (dev->if_port == 0) dev->if_port = tp->default_port; - if (tp->chip_id == DC21041 && dev->if_port > 4) - /* Invalid: Select initial TP, autosense, autonegotiate. */ - dev->if_port = 4; /* Allow selecting a default media. */ - i = 0; - if (tp->mtable == NULL) - goto media_picked; - if (dev->if_port) { - int looking_for = media_cap[dev->if_port] & MediaIsMII ? 11 : - (dev->if_port == 12 ? 0 : dev->if_port); - for (i = 0; i < tp->mtable->leafcount; i++) - if (tp->mtable->mleaf[i].media == looking_for) { - printk(KERN_INFO "%s: Using user-specified media %s.\n", - dev->name, medianame[dev->if_port]); - goto media_picked; - } - } - if ((tp->mtable->defaultmedia & 0x0800) == 0) { - int looking_for = tp->mtable->defaultmedia & 15; - for (i = 0; i < tp->mtable->leafcount; i++) - if (tp->mtable->mleaf[i].media == looking_for) { - printk(KERN_INFO "%s: Using EEPROM-set media %s.\n", - dev->name, medianame[looking_for]); - goto media_picked; - } - } - /* Start sensing first non-full-duplex media. */ - for (i = tp->mtable->leafcount - 1; - (media_cap[tp->mtable->mleaf[i].media] & MediaAlwaysFD) && i > 0; i--) - ; -media_picked: - tp->csr6 = 0; - tp->cur_index = i; - if (dev->if_port == 0 && tp->chip_id == DC21142) { - if (tp->mii_cnt) { - select_media(dev, 1); - if (tulip_debug > 1) - printk(KERN_INFO "%s: Using MII transceiver %d, status " - "%4.4x.\n", - dev->name, tp->phys[0], mdio_read(dev, tp->phys[0], 1)); - outl_CSR6(0x82020000, ioaddr, tp->chip_id); - tp->csr6 = 0x820E0000; - dev->if_port = 11; - outl(0x0000, ioaddr + CSR13); - outl(0x0000, ioaddr + CSR14); - } else - t21142_start_nway(dev); - } else if ((tp->chip_id == LC82C168 || tp->chip_id == PNIC2) - && tp->mii_cnt && ! tp->medialock) { - dev->if_port = 11; - tp->csr6 = 0x814C0000 | (tp->full_duplex ? 0x0200 : 0); - outl(0x0001, ioaddr + CSR15); - } else if ((tp->chip_id == MX98713 || tp->chip_id == COMPEX9881) - && ! tp->medialock) { - dev->if_port = 0; - tp->csr6 = 0x01880000 | (tp->full_duplex ? 0x0200 : 0); - outl(0x0f370000 | inw(ioaddr + 0x80), ioaddr + 0x80); - } else if (tp->chip_id == MX98715 || tp->chip_id == MX98725) { - /* Provided by BOLO, Macronix - 12/10/1998. */ - dev->if_port = 0; - tp->csr6 = 0x01880200; - outl(0x0f370000 | inw(ioaddr + 0x80), ioaddr + 0x80); - outl(0x11000 | inw(ioaddr + 0xa0), ioaddr + 0xa0); - } else if (tp->chip_id == DC21143 && - media_cap[dev->if_port] & MediaIsMII) { - /* We must reset the media CSRs when we force-select MII mode. */ - outl(0x0000, ioaddr + CSR13); - outl(0x0000, ioaddr + CSR14); - outl(0x0008, ioaddr + CSR15); - } else if (tp->chip_id == X3201_3) { + if (tp->chip_id == X3201_3) { outl(0x0008, ioaddr + CSR15); udelay(5); outl(0xa8050000, ioaddr + CSR15); @@ -1356,12 +736,7 @@ outl(0xa00f0000, ioaddr + CSR15); udelay(5); tp->csr6 = 0x32400000; - } else if (tp->chip_id == COMET) { - dev->if_port = 0; - tp->csr6 = 0x00040000; - } else - select_media(dev, 1); - + } /* Start the chip's Tx to process setup frame. */ outl_CSR6(tp->csr6, ioaddr, tp->chip_id); outl_CSR6(tp->csr6 | 0x2000, ioaddr, tp->chip_id); @@ -1405,238 +780,13 @@ return 0; } -/* Set up the transceiver control registers for the selected media type. */ -static void select_media(struct net_device *dev, int startup) -{ - long ioaddr = dev->base_addr; - struct tulip_private *tp = (struct tulip_private *)dev->priv; - struct mediatable *mtable = tp->mtable; - u32 new_csr6; - int i; - - if (mtable) { - struct medialeaf *mleaf = &mtable->mleaf[tp->cur_index]; - unsigned char *p = mleaf->leafdata; - switch (mleaf->type) { - case 0: /* 21140 non-MII xcvr. */ - if (tulip_debug > 1) - printk(KERN_DEBUG "%s: Using a 21140 non-MII transceiver" - " with control setting %2.2x.\n", - dev->name, p[1]); - dev->if_port = p[0]; - if (startup) - outl(mtable->csr12dir | 0x100, ioaddr + CSR12); - outl(p[1], ioaddr + CSR12); - new_csr6 = 0x02000000 | ((p[2] & 0x71) << 18); - break; - case 2: case 4: { - u16 setup[5]; - u32 csr13val, csr14val, csr15dir, csr15val; - for (i = 0; i < 5; i++) - setup[i] = get_u16(&p[i*2 + 1]); - - dev->if_port = p[0] & 15; - if (media_cap[dev->if_port] & MediaAlwaysFD) - tp->full_duplex = 1; - - if (startup && mtable->has_reset) { - struct medialeaf *rleaf = &mtable->mleaf[mtable->has_reset]; - unsigned char *rst = rleaf->leafdata; - if (tulip_debug > 1) - printk(KERN_DEBUG "%s: Resetting the transceiver.\n", - dev->name); - for (i = 0; i < rst[0]; i++) - outl(get_u16(rst + 1 + (i<<1)) << 16, ioaddr + CSR15); - } - if (tulip_debug > 1) - printk(KERN_DEBUG "%s: 21143 non-MII %s transceiver control " - "%4.4x/%4.4x.\n", - dev->name, medianame[dev->if_port], setup[0], setup[1]); - if (p[0] & 0x40) { /* SIA (CSR13-15) setup values are provided. */ - csr13val = setup[0]; - csr14val = setup[1]; - csr15dir = (setup[3]<<16) | setup[2]; - csr15val = (setup[4]<<16) | setup[2]; - outl(0, ioaddr + CSR13); - outl(csr14val, ioaddr + CSR14); - outl(csr15dir, ioaddr + CSR15); /* Direction */ - outl(csr15val, ioaddr + CSR15); /* Data */ - outl(csr13val, ioaddr + CSR13); - } else { - csr13val = 1; - csr14val = 0x0003FF7F; - csr15dir = (setup[0]<<16) | 0x0008; - csr15val = (setup[1]<<16) | 0x0008; - if (dev->if_port <= 4) - csr14val = t21142_csr14[dev->if_port]; - if (startup) { - outl(0, ioaddr + CSR13); - outl(csr14val, ioaddr + CSR14); - } - outl(csr15dir, ioaddr + CSR15); /* Direction */ - outl(csr15val, ioaddr + CSR15); /* Data */ - if (startup) outl(csr13val, ioaddr + CSR13); - } - if (tulip_debug > 1) - printk(KERN_DEBUG "%s: Setting CSR15 to %8.8x/%8.8x.\n", - dev->name, csr15dir, csr15val); - if (mleaf->type == 4) - new_csr6 = 0x82020000 | ((setup[2] & 0x71) << 18); - else - new_csr6 = 0x82420000; - break; - } - case 1: case 3: { - int phy_num = p[0]; - int init_length = p[1]; - u16 *misc_info; - u16 to_advertise; - - dev->if_port = 11; - new_csr6 = 0x020E0000; - if (mleaf->type == 3) { /* 21142 */ - u16 *init_sequence = (u16*)(p+2); - u16 *reset_sequence = &((u16*)(p+3))[init_length]; - int reset_length = p[2 + init_length*2]; - misc_info = reset_sequence + reset_length; - if (startup) - for (i = 0; i < reset_length; i++) - outl(get_u16(&reset_sequence[i]) << 16, ioaddr + CSR15); - for (i = 0; i < init_length; i++) - outl(get_u16(&init_sequence[i]) << 16, ioaddr + CSR15); - } else { - u8 *init_sequence = p + 2; - u8 *reset_sequence = p + 3 + init_length; - int reset_length = p[2 + init_length]; - misc_info = (u16*)(reset_sequence + reset_length); - if (startup) { - outl(mtable->csr12dir | 0x100, ioaddr + CSR12); - for (i = 0; i < reset_length; i++) - outl(reset_sequence[i], ioaddr + CSR12); - } - for (i = 0; i < init_length; i++) - outl(init_sequence[i], ioaddr + CSR12); - } - to_advertise = (get_u16(&misc_info[1]) & tp->to_advertise) | 1; - tp->advertising[phy_num] = to_advertise; - if (tulip_debug > 1) - printk(KERN_DEBUG "%s: Advertising %4.4x on PHY %d (%d).\n", - dev->name, to_advertise, phy_num, tp->phys[phy_num]); - /* Bogus: put in by a committee? */ - mdio_write(dev, tp->phys[phy_num], 4, to_advertise); - break; - } - default: - printk(KERN_DEBUG "%s: Invalid media table selection %d.\n", - dev->name, mleaf->type); - new_csr6 = 0x020E0000; - } - if (tulip_debug > 1) - printk(KERN_DEBUG "%s: Using media type %s, CSR12 is %2.2x.\n", - dev->name, medianame[dev->if_port], - inl(ioaddr + CSR12) & 0xff); - } else if (tp->chip_id == DC21041) { - if (tulip_debug > 1) - printk(KERN_DEBUG "%s: 21041 using media %s, CSR12 is %4.4x.\n", - dev->name, medianame[dev->if_port & 15], - inl(ioaddr + CSR12) & 0xffff); - outl(0x00000000, ioaddr + CSR13); /* Reset the serial interface */ - outl(t21041_csr14[dev->if_port], ioaddr + CSR14); - outl(t21041_csr15[dev->if_port], ioaddr + CSR15); - outl(t21041_csr13[dev->if_port], ioaddr + CSR13); - new_csr6 = 0x80020000; - } else if (tp->chip_id == LC82C168 || tp->chip_id == PNIC2) { - if (startup && ! tp->medialock) - dev->if_port = tp->mii_cnt ? 11 : 0; - if (tulip_debug > 1) - printk(KERN_DEBUG "%s: PNIC PHY status is %3.3x, CSR12 %4.4x," - " media %s.\n", - dev->name, inl(ioaddr + 0xB8), inl(ioaddr + CSR12), - medianame[dev->if_port]); - if (tp->mii_cnt) { - new_csr6 = 0x810C0000; - outl(0x0001, ioaddr + CSR15); - outl(0x0201B07A, ioaddr + 0xB8); - } else if (startup) { - /* Start with 10mbps to do autonegotiation. */ - outl(0x32, ioaddr + CSR12); - new_csr6 = 0x00420000; - outl(0x0001B078, ioaddr + 0xB8); - outl(0x0201B078, ioaddr + 0xB8); - } else if (dev->if_port == 3 || dev->if_port == 5) { - outl(0x33, ioaddr + CSR12); - new_csr6 = 0x01860000; - if (startup) - outl(0x0201F868, ioaddr + 0xB8); /* Trigger autonegotiation. */ - else - outl(0x1F868, ioaddr + 0xB8); - } else { - outl(0x32, ioaddr + CSR12); - new_csr6 = 0x00420000; - outl(0x1F078, ioaddr + 0xB8); - } - } else if (tp->chip_id == DC21040) { /* 21040 */ - /* Turn on the xcvr interface. */ - int csr12 = inl(ioaddr + CSR12); - if (tulip_debug > 1) - printk(KERN_DEBUG "%s: 21040 media type is %s, CSR12 is %2.2x.\n", - dev->name, medianame[dev->if_port], csr12); - if (media_cap[dev->if_port] & MediaAlwaysFD) - tp->full_duplex = 1; - new_csr6 = 0x20000; - /* Set the full duplux match frame. */ - outl(FULL_DUPLEX_MAGIC, ioaddr + CSR11); - outl(0x00000000, ioaddr + CSR13); /* Reset the serial interface */ - if (t21040_csr13[dev->if_port] & 8) { - outl(0x0705, ioaddr + CSR14); - outl(0x0006, ioaddr + CSR15); - } else { - outl(0xffff, ioaddr + CSR14); - outl(0x0000, ioaddr + CSR15); - } - outl(0x8f01 | t21040_csr13[dev->if_port], ioaddr + CSR13); - } else if (tp->chip_id == X3201_3) { /* Xircom */ - if (tp->default_port == 0) - dev->if_port = tp->mii_cnt ? 11 : 3; -/* Someone is on crack, the Xircom only does MII, no Fx */ -/* if (media_cap[dev->if_port] & MediaIsMII) { - new_csr6 = 0x020E0000; - } else if (media_cap[dev->if_port] & MediaIsFx) { - new_csr6 = 0x028600000; - } else - new_csr6 = 0x038600000;*/ - new_csr6 = 0x324c0000; - if (tulip_debug > 1) - printk(KERN_DEBUG "%s: Xircom CardBus Adapter: " - "%s transceiver, CSR12 %2.2x.\n", - dev->name, medianame[dev->if_port], - inl(ioaddr + CSR12)); - } else { /* Unknown chip type with no media table. */ - if (tp->default_port == 0) - dev->if_port = tp->mii_cnt ? 11 : 3; - if (media_cap[dev->if_port] & MediaIsMII) { - new_csr6 = 0x020E0000; - } else if (media_cap[dev->if_port] & MediaIsFx) { - new_csr6 = 0x028600000; - } else - new_csr6 = 0x038600000; - if (tulip_debug > 1) - printk(KERN_DEBUG "%s: No media description table, assuming " - "%s transceiver, CSR12 %2.2x.\n", - dev->name, medianame[dev->if_port], - inl(ioaddr + CSR12)); - } - - tp->csr6 = new_csr6 | (tp->csr6 & 0xfdff) | (tp->full_duplex ? 0x0200 : 0); - return; -} - /* Check the MII negotiated duplex, and change the CSR6 setting if required. Return 0 if everything is OK. Return < 0 if the transceiver is missing or has no link beat. */ +#if 0 static int check_duplex(struct net_device *dev) { long ioaddr = dev->base_addr; @@ -1679,6 +829,7 @@ } return 0; } +#endif static void tulip_timer(unsigned long data) { @@ -1695,273 +846,17 @@ csr12, inl(ioaddr + CSR13), inl(ioaddr + CSR14), inl(ioaddr + CSR15)); } - switch (tp->chip_id) { - case DC21040: - if (!tp->medialock && csr12 & 0x0002) { /* Network error */ - printk(KERN_INFO "%s: No link beat found.\n", - dev->name); - dev->if_port = (dev->if_port == 2 ? 0 : 2); - select_media(dev, 0); - dev->trans_start = jiffies; - } - break; - case DC21041: - if (tulip_debug > 2) - printk(KERN_DEBUG "%s: 21041 media tick CSR12 %8.8x.\n", - dev->name, csr12); - switch (dev->if_port) { - case 0: case 3: case 4: - if (csr12 & 0x0004) { /*LnkFail */ - /* 10baseT is dead. Check for activity on alternate port. */ - tp->mediasense = 1; - if (csr12 & 0x0200) - dev->if_port = 2; - else - dev->if_port = 1; - printk(KERN_INFO "%s: No 21041 10baseT link beat, Media switched to %s.\n", - dev->name, medianame[dev->if_port]); - outl(0, ioaddr + CSR13); /* Reset */ - outl(t21041_csr14[dev->if_port], ioaddr + CSR14); - outl(t21041_csr15[dev->if_port], ioaddr + CSR15); - outl(t21041_csr13[dev->if_port], ioaddr + CSR13); - next_tick = 10*HZ; /* 2.4 sec. */ - } else - next_tick = 30*HZ; - break; - case 1: /* 10base2 */ - case 2: /* AUI */ - if (csr12 & 0x0100) { - next_tick = (30*HZ); /* 30 sec. */ - tp->mediasense = 0; - } else if ((csr12 & 0x0004) == 0) { - printk(KERN_INFO "%s: 21041 media switched to 10baseT.\n", - dev->name); - dev->if_port = 0; - select_media(dev, 0); - next_tick = (24*HZ)/10; /* 2.4 sec. */ - } else if (tp->mediasense || (csr12 & 0x0002)) { - dev->if_port = 3 - dev->if_port; /* Swap ports. */ - select_media(dev, 0); - next_tick = 20*HZ; - } else { - next_tick = 20*HZ; - } - break; - } - break; - case DC21140: case DC21142: case MX98713: case COMPEX9881: default: { - struct medialeaf *mleaf; - unsigned char *p; - if (tp->mtable == NULL) { /* No EEPROM info, use generic code. */ - /* Not much that can be done. - Assume this a generic MII or SYM transceiver. */ - next_tick = 60*HZ; - if (tulip_debug > 2) - printk(KERN_DEBUG "%s: network media monitor CSR6 %8.8x " - "CSR12 0x%2.2x.\n", - dev->name, inl(ioaddr + CSR6), csr12 & 0xff); - break; - } - mleaf = &tp->mtable->mleaf[tp->cur_index]; - p = mleaf->leafdata; - switch (mleaf->type) { - case 0: case 4: { - /* Type 0 serial or 4 SYM transceiver. Check the link beat bit. */ - int offset = mleaf->type == 4 ? 5 : 2; - s8 bitnum = p[offset]; - if (p[offset+1] & 0x80) { - if (tulip_debug > 1) - printk(KERN_DEBUG"%s: Transceiver monitor tick " - "CSR12=%#2.2x, no media sense.\n", - dev->name, csr12); - if (mleaf->type == 4) { - if (mleaf->media == 3 && (csr12 & 0x02)) - goto select_next_media; - } - break; - } - if (tulip_debug > 2) - printk(KERN_DEBUG "%s: Transceiver monitor tick: CSR12=%#2.2x" - " bit %d is %d, expecting %d.\n", - dev->name, csr12, (bitnum >> 1) & 7, - (csr12 & (1 << ((bitnum >> 1) & 7))) != 0, - (bitnum >= 0)); - /* Check that the specified bit has the proper value. */ - if ((bitnum < 0) != - ((csr12 & (1 << ((bitnum >> 1) & 7))) != 0)) { - if (tulip_debug > 1) - printk(KERN_DEBUG "%s: Link beat detected for %s.\n", dev->name, - medianame[mleaf->media]); - if ((p[2] & 0x61) == 0x01) /* Bogus Znyx board. */ - goto actually_mii; - break; - } - if (tp->medialock) - break; - select_next_media: - if (--tp->cur_index < 0) { - /* We start again, but should instead look for default. */ - tp->cur_index = tp->mtable->leafcount - 1; - } - dev->if_port = tp->mtable->mleaf[tp->cur_index].media; - if (media_cap[dev->if_port] & MediaIsFD) - goto select_next_media; /* Skip FD entries. */ - if (tulip_debug > 1) - printk(KERN_DEBUG "%s: No link beat on media %s," - " trying transceiver type %s.\n", - dev->name, medianame[mleaf->media & 15], - medianame[tp->mtable->mleaf[tp->cur_index].media]); - select_media(dev, 0); - /* Restart the transmit process. */ - outl_CSR6(tp->csr6 | 0x0002, ioaddr, tp->chip_id); - outl_CSR6(tp->csr6 | 0x2002, ioaddr, tp->chip_id); - next_tick = (24*HZ)/10; - break; - } - case 1: case 3: /* 21140, 21142 MII */ - actually_mii: - check_duplex(dev); - next_tick = 60*HZ; - break; - case 2: /* 21142 serial block has no link beat. */ - default: - break; - } - } - break; - } - tp->timer.expires = RUN_AT(next_tick); - add_timer(&tp->timer); -} - -static void t21142_start_nway(struct net_device *dev) -{ - struct tulip_private *tp = (struct tulip_private *)dev->priv; - long ioaddr = dev->base_addr; - int csr14 = ((tp->to_advertise & 0x0180) << 9) | - ((tp->to_advertise&0x0020)<<1) | 0xffbf; - dev->if_port = 0; - tp->nway = tp->mediasense = 1; - tp->nwayset = tp->lpar = 0; - if (debug > 1) - printk(KERN_DEBUG "%s: Restarting 21143 autonegotiation, %8.8x.\n", - dev->name, csr14); - outl(0x0001, ioaddr + CSR13); - outl(csr14, ioaddr + CSR14); - tp->csr6 = 0x82420000 | (tp->to_advertise & 0x0040 ? 0x0200 : 0); - outl_CSR6(tp->csr6, ioaddr, tp->chip_id); - if (tp->mtable && tp->mtable->csr15dir) { - outl(tp->mtable->csr15dir, ioaddr + CSR15); - outl(tp->mtable->csr15val, ioaddr + CSR15); - } else - outw(0x0008, ioaddr + CSR15); - outl(0x1301, ioaddr + CSR12); /* Trigger NWAY. */ -} - -static void t21142_lnk_change(struct net_device *dev, int csr5) -{ - struct tulip_private *tp = (struct tulip_private *)dev->priv; - long ioaddr = dev->base_addr; - int csr12 = inl(ioaddr + CSR12); + /* Not much that can be done. + Assume this a generic MII or SYM transceiver. */ + next_tick = 60*HZ; + if (tulip_debug > 2) + printk(KERN_DEBUG "%s: network media monitor CSR6 %8.8x " + "CSR12 0x%2.2x.\n", + dev->name, inl(ioaddr + CSR6), csr12 & 0xff); - if (tulip_debug > 1) - printk(KERN_INFO"%s: 21143 link status interrupt %8.8x, CSR5 %x, " - "%8.8x.\n", dev->name, csr12, csr5, inl(ioaddr + CSR14)); - - /* If NWay finished and we have a negotiated partner capability. */ - if (tp->nway && !tp->nwayset && (csr12 & 0x7000) == 0x5000) { - int setup_done = 0; - tp->lpar = csr12 >> 16; - tp->nwayset = 1; - if (csr12 & 0x01000000) dev->if_port = 5; - else if (csr12 & 0x00800000) dev->if_port = 3; - else if (csr12 & 0x00400000) dev->if_port = 4; - else if (csr12 & 0x00200000) dev->if_port = 0; - else { - tp->nwayset = 0; - if ( ! (csr12 & 2)) dev->if_port = 3; - else if ( ! (csr12 & 4)) dev->if_port = 0; - } - tp->full_duplex = (media_cap[tp->default_port] & MediaAlwaysFD) ? 1:0; - - if (tulip_debug > 1) { - if (tp->nwayset) - printk(KERN_INFO "%s: Switching to %s based on link partner " - "advertisement %4.4x.\n", - dev->name, medianame[dev->if_port], tp->lpar); - else - printk(KERN_INFO "%s: Switching to %s based on link beat " - "status of %4.4x.\n", - dev->name, medianame[dev->if_port], csr12); - } - - if (tp->mtable) { - int i; - for (i = 0; i < tp->mtable->leafcount; i++) - if (tp->mtable->mleaf[i].media == dev->if_port) { - tp->cur_index = i; - select_media(dev, 0); - setup_done = 1; - break; - } - } - if ( ! setup_done) { - tp->csr6 = dev->if_port & 1 ? 0x83860000 : 0x82420000; - if (tp->full_duplex) - tp->csr6 |= 0x0200; - outw(0x0000, ioaddr + CSR13); - outw(0x0000, ioaddr + CSR14); - } - outl_CSR6(tp->csr6 | 0x0000, ioaddr, tp->chip_id); - if (debug > 2) - printk(KERN_DEBUG "%s: Restarting Tx and Rx, CSR5 is %8.8x.\n", - dev->name, inl(ioaddr + CSR5)); - outl_CSR6(tp->csr6 | 0x2002, ioaddr, tp->chip_id); - } else if ((tp->nwayset && (csr5 & 0x08000000) - && (dev->if_port == 3 || dev->if_port == 5) - && (csr12 & 2) == 2) || - (tp->nway && (csr5 & (TPLnkFail)))) { - /* Link blew? Maybe restart NWay. */ - del_timer(&tp->timer); - t21142_start_nway(dev); - tp->timer.expires = RUN_AT(3*HZ); - add_timer(&tp->timer); - } else if (dev->if_port == 3 || dev->if_port == 5) { - if (tulip_debug > 1) - printk(KERN_INFO"%s: 21143 %s link beat %s.\n", - dev->name, medianame[dev->if_port], - (csr12 & 2) ? "failed" : "good"); - if ((csr12 & 2) && ! tp->medialock) { - del_timer(&tp->timer); - t21142_start_nway(dev); - tp->timer.expires = RUN_AT(3*HZ); - add_timer(&tp->timer); - } - } else if (dev->if_port == 0 || dev->if_port == 4) { - if ((csr12 & 4) == 0) - printk(KERN_INFO"%s: 21143 10baseT link beat good.\n", - dev->name); - } else if (!(csr12 & 4)) { /* 10mbps link beat good. */ - if (tulip_debug) - printk(KERN_INFO"%s: 21143 10mbps sensed media.\n", - dev->name); - dev->if_port = 0; - } else if (tp->nwayset) { - if (tulip_debug) - printk(KERN_INFO"%s: 21143 using NWay-set %s, csr6 %8.8x.\n", - dev->name, medianame[dev->if_port], tp->csr6); - } else { /* 100mbps link beat good. */ - if (tulip_debug) - printk(KERN_INFO"%s: 21143 100baseTx sensed media.\n", - dev->name); - dev->if_port = 3; - tp->csr6 = 0x83860000; - outl(0x0003FF7F, ioaddr + CSR14); - outl(0x0301, ioaddr + CSR12); - outl_CSR6(tp->csr6 | 0x0002, ioaddr, tp->chip_id); - outl_CSR6(tp->csr6 | 0x2002, ioaddr, tp->chip_id); - } + tp->timer.expires = RUN_AT(next_tick); + add_timer(&tp->timer); } static void tulip_tx_timeout(struct net_device *dev) @@ -1974,59 +869,6 @@ if (tulip_debug > 1) printk(KERN_WARNING "%s: Transmit timeout using MII device.\n", dev->name); - } else if (tp->chip_id == DC21040) { - if ( !tp->medialock && inl(ioaddr + CSR12) & 0x0002) { - dev->if_port = (dev->if_port == 2 ? 0 : 2); - printk(KERN_INFO "%s: transmit timed out, switching to " - "%s.\n", - dev->name, medianame[dev->if_port]); - select_media(dev, 0); - } - dev->trans_start = jiffies; - return; - } else if (tp->chip_id == DC21041) { - int csr12 = inl(ioaddr + CSR12); - - printk(KERN_WARNING "%s: 21041 transmit timed out, status %8.8x, " - "CSR12 %8.8x, CSR13 %8.8x, CSR14 %8.8x, resetting...\n", - dev->name, inl(ioaddr + CSR5), csr12, - inl(ioaddr + CSR13), inl(ioaddr + CSR14)); - tp->mediasense = 1; - if ( ! tp->medialock) { - if (dev->if_port == 1 || dev->if_port == 2) - if (csr12 & 0x0004) { - dev->if_port = 2 - dev->if_port; - } else - dev->if_port = 0; - else - dev->if_port = 1; - select_media(dev, 0); - } - } else if (tp->chip_id == DC21140 || tp->chip_id == DC21142 - || tp->chip_id == MX98713 || tp->chip_id == COMPEX9881) { - printk(KERN_WARNING "%s: 21140 transmit timed out, status %8.8x, " - "SIA %8.8x %8.8x %8.8x %8.8x, resetting...\n", - dev->name, inl(ioaddr + CSR5), inl(ioaddr + CSR12), - inl(ioaddr + CSR13), inl(ioaddr + CSR14), inl(ioaddr + CSR15)); - if ( ! tp->medialock && tp->mtable) { - do - --tp->cur_index; - while (tp->cur_index >= 0 - && (media_cap[tp->mtable->mleaf[tp->cur_index].media] - & MediaIsFD)); - if (--tp->cur_index < 0) { - /* We start again, but should instead look for default. */ - tp->cur_index = tp->mtable->leafcount - 1; - } - select_media(dev, 0); - printk(KERN_WARNING "%s: transmit timed out, switching to %s " - "media.\n", dev->name, medianame[dev->if_port]); - } - } else { - printk(KERN_WARNING "%s: Transmit timed out, status %8.8x, CSR12 " - "%8.8x, resetting...\n", - dev->name, inl(ioaddr + CSR5), inl(ioaddr + CSR12)); - dev->if_port = 0; } #if defined(way_too_many_messages) @@ -2295,10 +1137,6 @@ dev->name, csr5); outl(tulip_tbl[tp->chip_id].valid_intrs, ioaddr + CSR7); } - if (csr5 & (TPLnkPass | TPLnkFail | 0x08000000)) { - if ( tp->chip_id == DC21142) - t21142_lnk_change(dev, csr5); - } /* Clear all error sources, included undocumented ones! */ outl(0x0800f7ba, ioaddr + CSR5); } @@ -2442,9 +1280,6 @@ outl(0x00000000, ioaddr + CSR7); /* Stop the chip's Tx and Rx processes. */ outl_CSR6(inl(ioaddr + CSR6) & ~0x2002, ioaddr, tp->chip_id); - /* 21040 -- Leave the card in 10baseT state. */ - if (tp->chip_id == DC21040) - outl(0x00000004, ioaddr + CSR13); if (inl(ioaddr + CSR6) != 0xffffffff) tp->stats.rx_missed_errors += inl(ioaddr + CSR8) & 0xffff; @@ -2510,7 +1345,6 @@ static int private_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { struct tulip_private *tp = (struct tulip_private *)dev->priv; - long ioaddr = dev->base_addr; u16 *data = (u16 *)&rq->ifr_data; int phy = tp->phys[0] & 0x1f; long flags; @@ -2523,27 +1357,7 @@ return -ENODEV; return 0; case SIOCDEVPRIVATE+1: /* Read the specified MII register. */ - if (data[0] == 32 && - (tp->chip_id == DC21142 || tp->chip_id == PNIC2)) { - int csr12 = inl(ioaddr + CSR12); - int csr14 = inl(ioaddr + CSR14); - switch (data[1]) { - case 0: { - data[3] = (csr14<<5) & 0x1000; - break; } - case 1: - data[3] = 0x7848 + ((csr12&0x7000) == 0x5000 ? 0x20 : 0) - + (csr12&0x06 ? 0x04 : 0); - break; - case 4: { - data[3] = ((csr14>>9)&0x0380) + - ((inl(ioaddr + CSR6)>>3)&0x0040) +((csr14>>1)&0x20) + 1; - break; - } - case 5: data[3] = csr12 >> 16; break; - default: data[3] = 0; break; - } - } else { + { save_flags(flags); cli(); data[3] = mdio_read(dev, data[0] & 0x1f, data[1] & 0x1f); @@ -2558,10 +1372,7 @@ if (!suser()) return -EPERM; #endif - if (data[0] == 32 && tp->chip_id == DC21142) { - if (data[1] == 5) - tp->to_advertise = data[2]; - } else { + { save_flags(flags); cli(); mdio_write(dev, data[0] & 0x1f, data[1] & 0x1f, data[2]); @@ -2632,21 +1443,6 @@ /* Too many to filter well -- accept all multicasts. */ tp->csr6 |= 0x0080; csr6 |= 0x0080; - } else if (tulip_tbl[tp->chip_id].flags & MC_HASH_ONLY) { - /* Some work-alikes have only a 64-entry hash filter table. */ - /* Should verify correctness on big-endian/__powerpc__ */ - struct dev_mc_list *mclist; - int i; - u32 mc_filter[2]; /* Multicast hash filter */ - if (dev->mc_count > 64) { /* Arbitrary non-effective limit. */ - tp->csr6 |= 0x0080; - csr6 |= 0x0080; - } else { - mc_filter[1] = mc_filter[0] = 0; - for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; - i++, mclist = mclist->next) - set_bit(ether_crc(ETH_ALEN, mclist->dmi_addr)>>26, mc_filter); - } } else { u16 *eaddrs, *setup_frm = tp->setup_frame; struct dev_mc_list *mclist; diff -u --recursive --new-file v2.4.6/linux/drivers/net/plip.c linux/drivers/net/plip.c --- v2.4.6/linux/drivers/net/plip.c Tue Jul 3 17:08:20 2001 +++ linux/drivers/net/plip.c Tue Jul 17 18:53:55 2001 @@ -2,7 +2,7 @@ /* PLIP: A parallel port "network" driver for Linux. */ /* This driver is for parallel port with 5-bit cable (LapLink (R) cable). */ /* - * Authors: Donald Becker <becker@super.org> + * Authors: Donald Becker <becker@scyld.com> * Tommy Thorn <thorn@daimi.aau.dk> * Tanabe Hiroyasu <hiro@sanpo.t.u-tokyo.ac.jp> * Alan Cox <gw4pts@gw4pts.ampr.org> @@ -37,7 +37,7 @@ */ /* - * Original version and the name 'PLIP' from Donald Becker <becker@super.org> + * Original version and the name 'PLIP' from Donald Becker <becker@scyld.com> * inspired by Russ Nelson's parallel port packet driver. * * NOTE: diff -u --recursive --new-file v2.4.6/linux/drivers/net/ppp_async.c linux/drivers/net/ppp_async.c --- v2.4.6/linux/drivers/net/ppp_async.c Tue Jul 3 17:08:20 2001 +++ linux/drivers/net/ppp_async.c Wed Jul 4 11:50:39 2001 @@ -96,7 +96,7 @@ static void async_lcp_peek(struct asyncppp *ap, unsigned char *data, int len, int inbound); -struct ppp_channel_ops async_ops = { +static struct ppp_channel_ops async_ops = { ppp_async_send, ppp_async_ioctl }; @@ -308,7 +308,7 @@ write_wakeup: ppp_asynctty_wakeup, }; -int +static int __init ppp_async_init(void) { int err; diff -u --recursive --new-file v2.4.6/linux/drivers/net/ppp_deflate.c linux/drivers/net/ppp_deflate.c --- v2.4.6/linux/drivers/net/ppp_deflate.c Tue Feb 13 13:15:05 2001 +++ linux/drivers/net/ppp_deflate.c Wed Jul 4 11:50:39 2001 @@ -598,7 +598,7 @@ * Module interface table *************************************************************/ -/* These are in ppp.c */ +/* These are in ppp_generic.c */ extern int ppp_register_compressor (struct compressor *cp); extern void ppp_unregister_compressor (struct compressor *cp); @@ -639,7 +639,7 @@ z_comp_stats, /* decomp_stat */ }; -int deflate_init(void) +int __init deflate_init(void) { int answer = ppp_register_compressor(&ppp_deflate); if (answer == 0) @@ -649,7 +649,7 @@ return answer; } -void deflate_cleanup(void) +void __exit deflate_cleanup(void) { ppp_unregister_compressor(&ppp_deflate); ppp_unregister_compressor(&ppp_deflate_draft); diff -u --recursive --new-file v2.4.6/linux/drivers/net/ppp_generic.c linux/drivers/net/ppp_generic.c --- v2.4.6/linux/drivers/net/ppp_generic.c Sun Apr 22 09:46:40 2001 +++ linux/drivers/net/ppp_generic.c Wed Jul 4 11:50:39 2001 @@ -878,7 +878,7 @@ return err; } -int +static int ppp_net_init(struct net_device *dev) { dev->hard_header_len = PPP_HDRLEN; diff -u --recursive --new-file v2.4.6/linux/drivers/net/ppp_synctty.c linux/drivers/net/ppp_synctty.c --- v2.4.6/linux/drivers/net/ppp_synctty.c Fri Apr 20 11:54:24 2001 +++ linux/drivers/net/ppp_synctty.c Wed Jul 4 11:50:39 2001 @@ -96,7 +96,7 @@ static void ppp_sync_input(struct syncppp *ap, const unsigned char *buf, char *flags, int count); -struct ppp_channel_ops sync_ops = { +static struct ppp_channel_ops sync_ops = { ppp_sync_send, ppp_sync_ioctl }; @@ -365,7 +365,7 @@ write_wakeup: ppp_sync_wakeup, }; -int +static int __init ppp_sync_init(void) { int err; diff -u --recursive --new-file v2.4.6/linux/drivers/net/pppoe.c linux/drivers/net/pppoe.c --- v2.4.6/linux/drivers/net/pppoe.c Wed May 16 10:31:27 2001 +++ linux/drivers/net/pppoe.c Thu Jul 19 17:55:06 2001 @@ -5,7 +5,7 @@ * PPPoE --- PPP over Ethernet (RFC 2516) * * - * Version: 0.6.6 + * Version: 0.6.8 * * 030700 : Fixed connect logic to allow for disconnect. * 270700 : Fixed potential SMP problems; we must protect against @@ -20,10 +20,20 @@ * 111100 : Fix recvmsg. * 050101 : Fix PADT procesing. * 140501 : Use pppoe_rcv_core to handle all backlog. (Alexey) + * 170701 : Do not lock_sock with rwlock held. (DaveM) + * Ignore discovery frames if user has socket + * locked. (DaveM) + * Ignore return value of dev_queue_xmit in __pppoe_xmit + * or else we may kfree an SKB twice. (DaveM) + * 190701 : When doing copies of skb's in __pppoe_xmit, always delete + * the original skb that was passed in on success, never on + * failure. Delete the copy of the skb on failure to avoid + * a memory leak. * - * Author: Michal Ostrowski <mostrows@styx.uwaterloo.ca> + * Author: Michal Ostrowski <mostrows@speakeasy.net> * Contributors: * Arnaldo Carvalho de Melo <acme@xconectiva.com.br> + * David S. Miller (davem@redhat.com) * * License: * This program is free software; you can redistribute it and/or @@ -100,10 +110,11 @@ static int hash_item(unsigned long sid, unsigned char *addr) { - char hash=0; - int i,j; - for (i = 0; i < ETH_ALEN ; ++i){ - for (j = 0; j < 8/PPPOE_HASH_BITS ; ++j){ + char hash = 0; + int i, j; + + for (i = 0; i < ETH_ALEN ; ++i) { + for (j = 0; j < 8/PPPOE_HASH_BITS ; ++j) { hash ^= addr[i] >> ( j * PPPOE_HASH_BITS ); } } @@ -188,7 +199,7 @@ read_lock_bh(&pppoe_hash_lock); po = __get_item(sid, addr); - if(po) + if (po) sock_hold(po->sk); read_unlock_bh(&pppoe_hash_lock); @@ -233,62 +244,83 @@ * Certain device events require that sockets be unconnected. * **************************************************************************/ + +static void pppoe_flush_dev(struct net_device *dev) +{ + int hash; + + if (dev == NULL) + BUG(); + + read_lock_bh(&pppoe_hash_lock); + for (hash = 0; hash < PPPOE_HASH_SIZE; hash++) { + struct pppox_opt *po = item_hash_table[hash]; + + while (po != NULL) { + if (po->pppoe_dev == dev) { + struct sock *sk = po->sk; + + sock_hold(sk); + po->pppoe_dev = NULL; + + /* We hold a reference to SK, now drop the + * hash table lock so that we may attempt + * to lock the socket (which can sleep). + */ + read_unlock_bh(&pppoe_hash_lock); + + lock_sock(sk); + + if (sk->state & (PPPOX_CONNECTED | PPPOX_BOUND)) { + pppox_unbind_sock(sk); + dev_put(dev); + sk->state = PPPOX_DEAD; + sk->state_change(sk); + } + + release_sock(sk); + + sock_put(sk); + + read_lock_bh(&pppoe_hash_lock); + + /* Now restart from the beginning of this + * hash chain. We always NULL out pppoe_dev + * so we are guarenteed to make forward + * progress. + */ + po = item_hash_table[hash]; + continue; + } + po = po->next; + } + } + read_unlock_bh(&pppoe_hash_lock); +} + static int pppoe_device_event(struct notifier_block *this, unsigned long event, void *ptr) { - int error = NOTIFY_DONE; struct net_device *dev = (struct net_device *) ptr; - struct pppox_opt *po = NULL; - int hash = 0; /* Only look at sockets that are using this specific device. */ switch (event) { case NETDEV_CHANGEMTU: - /* A change in mtu is a bad thing, requiring - * LCP re-negotiation. - */ + /* A change in mtu is a bad thing, requiring + * LCP re-negotiation. + */ + case NETDEV_GOING_DOWN: case NETDEV_DOWN: - /* Find every socket on this device and kill it. */ - read_lock_bh(&pppoe_hash_lock); - - while (!po && hash < PPPOE_HASH_SIZE){ - po = item_hash_table[hash]; - ++hash; - } - - while (po && hash < PPPOE_HASH_SIZE){ - if(po->pppoe_dev == dev){ - lock_sock(po->sk); - if (po->sk->state & (PPPOX_CONNECTED|PPPOX_BOUND)){ - pppox_unbind_sock(po->sk); - - dev_put(po->pppoe_dev); - po->pppoe_dev = NULL; - - po->sk->state = PPPOX_DEAD; - po->sk->state_change(po->sk); - } - release_sock(po->sk); - } - if (po->next) { - po = po->next; - } else { - po = NULL; - while (!po && hash < PPPOE_HASH_SIZE){ - po = item_hash_table[hash]; - ++hash; - } - } - } - read_unlock_bh(&pppoe_hash_lock); + pppoe_flush_dev(dev); break; + default: break; }; - return error; + return NOTIFY_DONE; } @@ -304,40 +336,39 @@ * Do the real work of receiving a PPPoE Session frame. * ***********************************************************************/ -int pppoe_rcv_core(struct sock *sk, struct sk_buff *skb){ - struct pppox_opt *po=sk->protinfo.pppox; +int pppoe_rcv_core(struct sock *sk, struct sk_buff *skb) +{ + struct pppox_opt *po = sk->protinfo.pppox; struct pppox_opt *relay_po = NULL; if (sk->state & PPPOX_BOUND) { skb_pull(skb, sizeof(struct pppoe_hdr)); - ppp_input(&po->chan, skb); - } else if( sk->state & PPPOX_RELAY ){ - - relay_po = get_item_by_addr( &po->pppoe_relay ); + } else if (sk->state & PPPOX_RELAY) { + relay_po = get_item_by_addr(&po->pppoe_relay); - if( relay_po == NULL || - !( relay_po->sk->state & PPPOX_CONNECTED ) ){ - goto abort; - } + if (relay_po == NULL) + goto abort_kfree; + + if ((relay_po->sk->state & PPPOX_CONNECTED) == 0) + goto abort_put; skb_pull(skb, sizeof(struct pppoe_hdr)); - if( !__pppoe_xmit( relay_po->sk , skb) ){ - goto abort; - } + if (!__pppoe_xmit( relay_po->sk , skb)) + goto abort_put; } else { sock_queue_rcv_skb(sk, skb); } - return 1; -abort: - if(relay_po) - sock_put(relay_po->sk); - return 0; - -} + return NET_RX_SUCCESS; +abort_put: + sock_put(relay_po->sk); +abort_kfree: + kfree_skb(skb); + return NET_RX_DROP; +} /************************************************************************ * @@ -356,24 +387,25 @@ po = get_item((unsigned long) ph->sid, skb->mac.ethernet->h_source); - if(!po){ + if (!po) { kfree_skb(skb); - return 0; + return NET_RX_DROP; } sk = po->sk; bh_lock_sock(sk); /* Socket state is unknown, must put skb into backlog. */ - if( sk->lock.users != 0 ){ - sk_add_backlog( sk, skb); - ret = 1; - }else{ + if (sk->lock.users != 0) { + sk_add_backlog(sk, skb); + ret = NET_RX_SUCCESS; + } else { ret = pppoe_rcv_core(sk, skb); } bh_unlock_sock(sk); sock_put(sk); + return ret; } @@ -390,43 +422,41 @@ { struct pppoe_hdr *ph = (struct pppoe_hdr *) skb->nh.raw; struct pppox_opt *po; - struct sock *sk = NULL; if (ph->code != PADT_CODE) goto abort; po = get_item((unsigned long) ph->sid, skb->mac.ethernet->h_source); + if (po) { + struct sock *sk = po->sk; - if (!po) - goto abort; + bh_lock_sock(sk); - sk = po->sk; + /* If the user has locked the socket, just ignore + * the packet. With the way two rcv protocols hook into + * one socket family type, we cannot (easily) distinguish + * what kind of SKB it is during backlog rcv. + */ + if (sk->lock.users == 0) + pppox_unbind_sock(sk); - pppox_unbind_sock(sk); + bh_unlock_sock(sk); + sock_put(sk); + } - sock_put(sk); - abort: +abort: kfree_skb(skb); - return 0; + return NET_RX_SUCCESS; /* Lies... :-) */ } - - - struct packet_type pppoes_ptype = { - __constant_htons(ETH_P_PPP_SES), - NULL, - pppoe_rcv, - NULL, - NULL + type: __constant_htons(ETH_P_PPP_SES), + func: pppoe_rcv, }; struct packet_type pppoed_ptype = { - __constant_htons(ETH_P_PPP_DISC), - NULL, - pppoe_disc_rcv, - NULL, - NULL + type: __constant_htons(ETH_P_PPP_DISC), + func: pppoe_disc_rcv, }; /*********************************************************************** @@ -533,7 +563,7 @@ struct sock *sk = sock->sk; struct net_device *dev = NULL; struct sockaddr_pppox *sp = (struct sockaddr_pppox *) uservaddr; - struct pppox_opt *po=sk->protinfo.pppox; + struct pppox_opt *po = sk->protinfo.pppox; int error; lock_sock(sk); @@ -576,17 +606,18 @@ if (!dev) goto end; - if( ! (dev->flags & IFF_UP) ) - goto end; + po->pppoe_dev = dev; + + if (!(dev->flags & IFF_UP)) + goto err_put; + memcpy(&po->pppoe_pa, &sp->sa_addr.pppoe, sizeof(struct pppoe_addr)); error = set_item(po); if (error < 0) - goto end; - - po->pppoe_dev = dev; + goto err_put; po->chan.hdrlen = (sizeof(struct pppoe_hdr) + dev->hard_header_len); @@ -595,6 +626,8 @@ po->chan.ops = &pppoe_chan_ops; error = ppp_register_channel(&po->chan); + if (error) + goto err_put; sk->state = PPPOX_CONNECTED; } @@ -604,6 +637,10 @@ end: release_sock(sk); return error; +err_put: + dev_put(po->pppoe_dev); + po->pppoe_dev = NULL; + goto end; } @@ -690,7 +727,7 @@ /* PPPoE address from the user specifies an outbound PPPoE address to which frames are forwarded to */ err = -EFAULT; - if( copy_from_user(&po->pppoe_relay, + if (copy_from_user(&po->pppoe_relay, (void*)arg, sizeof(struct sockaddr_pppox))) break; @@ -755,7 +792,7 @@ dev = sk->protinfo.pppox->pppoe_dev; error = -EMSGSIZE; - if(total_len > dev->mtu+dev->hard_header_len) + if (total_len > (dev->mtu + dev->hard_header_len)) goto end; @@ -778,7 +815,7 @@ ph = (struct pppoe_hdr *) skb_put(skb, total_len + sizeof(struct pppoe_hdr)); start = (char *) &ph->tag[0]; - error = memcpy_fromiovec( start, m->msg_iov, total_len); + error = memcpy_fromiovec(start, m->msg_iov, total_len); if (error < 0) { kfree_skb(skb); @@ -796,11 +833,12 @@ dev_queue_xmit(skb); - end: +end: release_sock(sk); return error; } + /************************************************************************ * * xmit function for internal use. @@ -813,10 +851,10 @@ struct pppoe_hdr *ph; int headroom = skb_headroom(skb); int data_len = skb->len; + struct sk_buff *skb2; - if (sk->dead || !(sk->state & PPPOX_CONNECTED)) { + if (sk->dead || !(sk->state & PPPOX_CONNECTED)) goto abort; - } hdr.ver = 1; hdr.type = 1; @@ -824,14 +862,11 @@ hdr.sid = sk->num; hdr.length = htons(skb->len); - if (!dev) { + if (!dev) goto abort; - } /* Copy the skb if there is no space for the header. */ if (headroom < (sizeof(struct pppoe_hdr) + dev->hard_header_len)) { - struct sk_buff *skb2; - skb2 = dev_alloc_skb(32+skb->len + sizeof(struct pppoe_hdr) + dev->hard_header_len); @@ -841,29 +876,38 @@ skb_reserve(skb2, dev->hard_header_len + sizeof(struct pppoe_hdr)); memcpy(skb_put(skb2, skb->len), skb->data, skb->len); - - skb_unlink(skb); - kfree_skb(skb); - skb = skb2; + } else { + /* Make a clone so as to not disturb the original skb, + * give dev_queue_xmit something it can free. + */ + skb2 = skb_clone(skb, GFP_ATOMIC); } - ph = (struct pppoe_hdr *) skb_push(skb, sizeof(struct pppoe_hdr)); + ph = (struct pppoe_hdr *) skb_push(skb2, sizeof(struct pppoe_hdr)); memcpy(ph, &hdr, sizeof(struct pppoe_hdr)); - skb->protocol = __constant_htons(ETH_P_PPP_SES); + skb2->protocol = __constant_htons(ETH_P_PPP_SES); - skb->nh.raw = skb->data; + skb2->nh.raw = skb2->data; - skb->dev = dev; + skb2->dev = dev; - dev->hard_header(skb, dev, ETH_P_PPP_SES, + dev->hard_header(skb2, dev, ETH_P_PPP_SES, sk->protinfo.pppox->pppoe_pa.remote, NULL, data_len); - if (dev_queue_xmit(skb) < 0) + /* We're transmitting skb2, and assuming that dev_queue_xmit + * will free it. The generic ppp layer however, is expecting + * that we give back 'skb' (not 'skb2') in case of failure, + * but free it in case of success. + */ + + if (dev_queue_xmit(skb2) < 0) goto abort; + kfree_skb(skb); return 1; - abort: + +abort: return 0; } @@ -1010,8 +1054,6 @@ int err = register_pppox_proto(PX_PROTO_OE, &pppoe_proto); if (err == 0) { - printk(KERN_INFO "Registered PPPoE v0.6.5\n"); - dev_add_pack(&pppoes_ptype); dev_add_pack(&pppoed_ptype); register_netdevice_notifier(&pppoe_notifier); diff -u --recursive --new-file v2.4.6/linux/drivers/net/pppox.c linux/drivers/net/pppox.c --- v2.4.6/linux/drivers/net/pppox.c Tue Feb 13 13:15:05 2001 +++ linux/drivers/net/pppox.c Thu Jul 19 17:55:06 2001 @@ -148,10 +148,6 @@ err = sock_register(&pppox_proto_family); - if (err == 0) { - printk(KERN_INFO "Registered PPPoX v0.5\n"); - } - return err; } diff -u --recursive --new-file v2.4.6/linux/drivers/net/rrunner.c linux/drivers/net/rrunner.c --- v2.4.6/linux/drivers/net/rrunner.c Wed Apr 18 14:40:04 2001 +++ linux/drivers/net/rrunner.c Wed Jul 4 11:50:39 2001 @@ -117,6 +117,14 @@ static int probed __initdata = 0; +#if LINUX_VERSION_CODE >= 0x20400 +static struct pci_device_id rrunner_pci_tbl[] __initdata = { + { PCI_VENDOR_ID_ESSENTIAL, PCI_DEVICE_ID_ESSENTIAL_ROADRUNNER, PCI_ANY_ID, PCI_ANY_ID, }, + { } /* Terminating entry */ +}; +MODULE_DEVICE_TABLE(pci, rrunner_pci_tbl); +#endif /* LINUX_VERSION_CODE >= 0x20400 */ + #ifdef NEW_NETINIT int __init rr_hippi_probe (void) #else @@ -137,9 +145,6 @@ return -ENODEV; probed++; - if (!pci_present()) /* is PCI BIOS even present? */ - return -ENODEV; - version_disp = 0; while((pdev = pci_find_device(PCI_VENDOR_ID_ESSENTIAL, @@ -176,6 +181,7 @@ sprintf(rrpriv->name, "RoadRunner serial HIPPI"); dev->irq = pdev->irq; + SET_MODULE_OWNER(dev); dev->open = &rr_open; dev->hard_start_xmit = &rr_start_xmit; dev->stop = &rr_close; @@ -1183,7 +1189,6 @@ netif_start_queue(dev); - MOD_INC_USE_COUNT; return ecode; error: @@ -1348,7 +1353,6 @@ free_irq(dev->irq, dev); spin_unlock(&rrpriv->lock); - MOD_DEC_USE_COUNT; return 0; } diff -u --recursive --new-file v2.4.6/linux/drivers/net/setup.c linux/drivers/net/setup.c --- v2.4.6/linux/drivers/net/setup.c Tue Feb 13 13:15:05 2001 +++ linux/drivers/net/setup.c Wed Jul 4 14:41:33 2001 @@ -10,7 +10,6 @@ #include <linux/netlink.h> extern int slip_init_ctrl_dev(void); -extern int strip_init_ctrl_dev(void); extern int x25_asy_init_ctrl_dev(void); extern int dmascc_init(void); @@ -23,13 +22,13 @@ extern int scc_enet_init(void); extern int fec_enet_init(void); extern int dlci_setup(void); -extern int lapbeth_init(void); extern int sdla_setup(void); extern int sdla_c_setup(void); extern int comx_init(void); extern int lmc_setup(void); extern int madgemc_probe(void); +extern int uml_net_probe(void); /* Pad device name to IFNAMSIZ=16. F.e. __PAD6 is string of 9 zeros. */ #define __PAD6 "\0\0\0\0\0\0\0\0\0" @@ -64,9 +63,6 @@ #if defined(CONFIG_SDLA) {sdla_c_setup, 0}, #endif -#if defined(CONFIG_LAPBETHER) - {lapbeth_init, 0}, -#endif #if defined(CONFIG_ARCNET) {arcnet_init, 0}, #endif @@ -107,6 +103,10 @@ #ifdef CONFIG_MADGEMC {madgemc_probe, 0}, #endif +#ifdef CONFIG_UML_NET + {uml_net_probe, 0}, +#endif + {NULL, 0}, }; @@ -139,9 +139,6 @@ #endif #if defined(CONFIG_X25_ASY) x25_asy_init_ctrl_dev(); -#endif -#if defined(CONFIG_STRIP) - strip_init_ctrl_dev(); #endif } diff -u --recursive --new-file v2.4.6/linux/drivers/net/sis900.c linux/drivers/net/sis900.c --- v2.4.6/linux/drivers/net/sis900.c Tue Jul 3 17:08:20 2001 +++ linux/drivers/net/sis900.c Tue Jul 17 18:53:55 2001 @@ -150,8 +150,11 @@ /* The saved address of a sent/receive-in-place packet buffer */ struct sk_buff *tx_skbuff[NUM_TX_DESC]; struct sk_buff *rx_skbuff[NUM_RX_DESC]; - BufferDesc tx_ring[NUM_TX_DESC]; - BufferDesc rx_ring[NUM_RX_DESC]; + BufferDesc *tx_ring; + BufferDesc *rx_ring; + + dma_addr_t tx_ring_dma; + dma_addr_t rx_ring_dma; unsigned int tx_full; /* The Tx queue is full. */ }; @@ -309,6 +312,8 @@ { struct sis900_private *sis_priv; struct net_device *net_dev; + dma_addr_t ring_dma; + void *ring_space; long ioaddr; int i, ret; u8 revision; @@ -353,6 +358,22 @@ pci_set_drvdata(pci_dev, net_dev); + ring_space = pci_alloc_consistent(pci_dev, TX_TOTAL_SIZE, &ring_dma); + if (!ring_space) { + ret = -ENOMEM; + goto err_out_cleardev; + } + sis_priv->tx_ring = (BufferDesc *)ring_space; + sis_priv->tx_ring_dma = ring_dma; + + ring_space = pci_alloc_consistent(pci_dev, RX_TOTAL_SIZE, &ring_dma); + if (!ring_space) { + ret = -ENOMEM; + goto err_unmap_tx; + } + sis_priv->rx_ring = (BufferDesc *)ring_space; + sis_priv->rx_ring_dma = ring_dma; + /* The SiS900-specific entries in the device structure. */ net_dev->open = &sis900_open; net_dev->hard_start_xmit = &sis900_start_xmit; @@ -366,7 +387,7 @@ ret = register_netdev(net_dev); if (ret) - goto err_out_cleardev; + goto err_unmap_rx; /* Get Mac address according to the chip revision */ pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &revision); @@ -401,6 +422,12 @@ err_out_unregister: unregister_netdev(net_dev); + err_unmap_rx: + pci_free_consistent(pci_dev, RX_TOTAL_SIZE, sis_priv->rx_ring, + sis_priv->rx_ring_dma); + err_unmap_tx: + pci_free_consistent(pci_dev, TX_TOTAL_SIZE, sis_priv->tx_ring, + sis_priv->tx_ring_dma); err_out_cleardev: pci_set_drvdata(pci_dev, NULL); pci_release_regions(pci_dev); @@ -808,7 +835,7 @@ { struct sis900_private *sis_priv = net_dev->priv; long ioaddr = net_dev->base_addr; - u8 revision; + u8 revision; int ret; /* Soft reset the chip. */ @@ -907,14 +934,14 @@ for (i = 0; i < NUM_TX_DESC; i++) { sis_priv->tx_skbuff[i] = NULL; - sis_priv->tx_ring[i].link = (u32) virt_to_bus(&sis_priv->tx_ring[i+1]); + sis_priv->tx_ring[i].link = sis_priv->tx_ring_dma + + ((i+1)%NUM_TX_DESC)*sizeof(BufferDesc); sis_priv->tx_ring[i].cmdsts = 0; sis_priv->tx_ring[i].bufptr = 0; } - sis_priv->tx_ring[i-1].link = (u32) virt_to_bus(&sis_priv->tx_ring[0]); /* load Transmit Descriptor Register */ - outl(virt_to_bus(&sis_priv->tx_ring[0]), ioaddr + txdp); + outl(sis_priv->tx_ring_dma, ioaddr + txdp); if (sis900_debug > 2) printk(KERN_INFO "%s: TX descriptor register loaded with: %8.8x\n", net_dev->name, inl(ioaddr + txdp)); @@ -942,11 +969,11 @@ for (i = 0; i < NUM_RX_DESC; i++) { sis_priv->rx_skbuff[i] = NULL; - sis_priv->rx_ring[i].link = (u32) virt_to_bus(&sis_priv->rx_ring[i+1]); + sis_priv->rx_ring[i].link = sis_priv->rx_ring_dma + + ((i+1)%NUM_RX_DESC)*sizeof(BufferDesc); sis_priv->rx_ring[i].cmdsts = 0; sis_priv->rx_ring[i].bufptr = 0; } - sis_priv->rx_ring[i-1].link = (u32) virt_to_bus(&sis_priv->rx_ring[0]); /* allocate sock buffers */ for (i = 0; i < NUM_RX_DESC; i++) { @@ -962,12 +989,13 @@ skb->dev = net_dev; sis_priv->rx_skbuff[i] = skb; sis_priv->rx_ring[i].cmdsts = RX_BUF_SIZE; - sis_priv->rx_ring[i].bufptr = virt_to_bus(skb->tail); + sis_priv->rx_ring[i].bufptr = pci_map_single(sis_priv->pci_dev, + skb->tail, RX_BUF_SIZE, PCI_DMA_FROMDEVICE); } sis_priv->dirty_rx = (unsigned int) (i - NUM_RX_DESC); /* load Receive Descriptor Register */ - outl(virt_to_bus(&sis_priv->rx_ring[0]), ioaddr + rxdp); + outl(sis_priv->rx_ring_dma, ioaddr + rxdp); if (sis900_debug > 2) printk(KERN_INFO "%s: RX descriptor register loaded with: %8.8x\n", net_dev->name, inl(ioaddr + rxdp)); @@ -1012,7 +1040,8 @@ revision == SIS630A_900_REV) ) return; - if ((dev = pci_find_device(SIS630_VENDOR_ID, SIS630_DEVICE_ID, dev))) + dev = pci_find_device(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_630, dev); + if (dev) pci_read_config_byte(dev, PCI_CLASS_REVISION, &host_bridge_rev); if (netif_carrier_ok(net_dev)) { @@ -1320,8 +1349,13 @@ /* discard unsent packets */ sis_priv->dirty_tx = sis_priv->cur_tx = 0; for (i = 0; i < NUM_TX_DESC; i++) { - if (sis_priv->tx_skbuff[i] != NULL) { - dev_kfree_skb(sis_priv->tx_skbuff[i]); + struct sk_buff *skb = sis_priv->tx_skbuff[i]; + + if (skb) { + pci_unmap_single(sis_priv->pci_dev, + sis_priv->tx_ring[i].bufptr, skb->len, + PCI_DMA_TODEVICE); + dev_kfree_skb(skb); sis_priv->tx_skbuff[i] = 0; sis_priv->tx_ring[i].cmdsts = 0; sis_priv->tx_ring[i].bufptr = 0; @@ -1368,7 +1402,8 @@ sis_priv->tx_skbuff[entry] = skb; /* set the transmit buffer descriptor and enable Transmit State Machine */ - sis_priv->tx_ring[entry].bufptr = virt_to_bus(skb->data); + sis_priv->tx_ring[entry].bufptr = pci_map_single(sis_priv->pci_dev, + skb->data, skb->len, PCI_DMA_TODEVICE); sis_priv->tx_ring[entry].cmdsts = (OWN | skb->len); outl(TxENA, ioaddr + cr); @@ -1509,7 +1544,13 @@ break; } - /* gvie the socket buffer to upper layers */ + pci_dma_sync_single(sis_priv->pci_dev, + sis_priv->rx_ring[entry].bufptr, RX_BUF_SIZE, + PCI_DMA_FROMDEVICE); + pci_unmap_single(sis_priv->pci_dev, + sis_priv->rx_ring[entry].bufptr, RX_BUF_SIZE, + PCI_DMA_FROMDEVICE); + /* give the socket buffer to upper layers */ skb = sis_priv->rx_skbuff[entry]; skb_put(skb, rx_size); skb->protocol = eth_type_trans(skb, net_dev); @@ -1542,7 +1583,9 @@ skb->dev = net_dev; sis_priv->rx_skbuff[entry] = skb; sis_priv->rx_ring[entry].cmdsts = RX_BUF_SIZE; - sis_priv->rx_ring[entry].bufptr = virt_to_bus(skb->tail); + sis_priv->rx_ring[entry].bufptr = + pci_map_single(sis_priv->pci_dev, skb->tail, + RX_BUF_SIZE, PCI_DMA_FROMDEVICE); sis_priv->dirty_rx++; } sis_priv->cur_rx++; @@ -1572,7 +1615,9 @@ skb->dev = net_dev; sis_priv->rx_skbuff[entry] = skb; sis_priv->rx_ring[entry].cmdsts = RX_BUF_SIZE; - sis_priv->rx_ring[entry].bufptr = virt_to_bus(skb->tail); + sis_priv->rx_ring[entry].bufptr = + pci_map_single(sis_priv->pci_dev, skb->tail, + RX_BUF_SIZE, PCI_DMA_FROMDEVICE); } } /* re-enable the potentially idle receive state matchine */ @@ -1596,6 +1641,7 @@ struct sis900_private *sis_priv = net_dev->priv; for (; sis_priv->dirty_tx < sis_priv->cur_tx; sis_priv->dirty_tx++) { + struct sk_buff *skb; unsigned int entry; u32 tx_status; @@ -1631,7 +1677,11 @@ sis_priv->stats.tx_packets++; } /* Free the original skb. */ - dev_kfree_skb_irq(sis_priv->tx_skbuff[entry]); + skb = sis_priv->tx_skbuff[entry]; + pci_unmap_single(sis_priv->pci_dev, + sis_priv->tx_ring[entry].bufptr, skb->len, + PCI_DMA_TODEVICE); + dev_kfree_skb_irq(skb); sis_priv->tx_skbuff[entry] = NULL; sis_priv->tx_ring[entry].bufptr = 0; sis_priv->tx_ring[entry].cmdsts = 0; @@ -1659,6 +1709,7 @@ { long ioaddr = net_dev->base_addr; struct sis900_private *sis_priv = net_dev->priv; + struct sk_buff *skb; int i; netif_stop_queue(net_dev); @@ -1676,14 +1727,24 @@ /* Free Tx and RX skbuff */ for (i = 0; i < NUM_RX_DESC; i++) { - if (sis_priv->rx_skbuff[i] != NULL) - dev_kfree_skb(sis_priv->rx_skbuff[i]); - sis_priv->rx_skbuff[i] = 0; + skb = sis_priv->rx_skbuff[i]; + if (skb) { + pci_unmap_single(sis_priv->pci_dev, + sis_priv->rx_ring[i].bufptr, + RX_BUF_SIZE, PCI_DMA_FROMDEVICE); + dev_kfree_skb(skb); + sis_priv->rx_skbuff[i] = 0; + } } for (i = 0; i < NUM_TX_DESC; i++) { - if (sis_priv->tx_skbuff[i] != NULL) - dev_kfree_skb(sis_priv->tx_skbuff[i]); - sis_priv->tx_skbuff[i] = 0; + skb = sis_priv->tx_skbuff[i]; + if (skb) { + pci_unmap_single(sis_priv->pci_dev, + sis_priv->tx_ring[i].bufptr, skb->len, + PCI_DMA_TODEVICE); + dev_kfree_skb(skb); + sis_priv->tx_skbuff[i] = 0; + } } /* Green! Put the chip in low-power mode. */ @@ -2007,6 +2068,10 @@ kfree(phy); } + pci_free_consistent(pci_dev, RX_TOTAL_SIZE, sis_priv->rx_ring, + sis_priv->rx_ring_dma); + pci_free_consistent(pci_dev, TX_TOTAL_SIZE, sis_priv->tx_ring, + sis_priv->tx_ring_dma); unregister_netdev(net_dev); kfree(net_dev); pci_release_regions(pci_dev); diff -u --recursive --new-file v2.4.6/linux/drivers/net/sis900.h linux/drivers/net/sis900.h --- v2.4.6/linux/drivers/net/sis900.h Tue Jul 3 17:08:20 2001 +++ linux/drivers/net/sis900.h Tue Jul 17 18:53:55 2001 @@ -265,6 +265,9 @@ #define NUM_TX_DESC 16 /* Number of Tx descriptor registers. */ #define NUM_RX_DESC 16 /* Number of Rx descriptor registers. */ +#define TX_TOTAL_SIZE NUM_TX_DESC*sizeof(BufferDesc) +#define RX_TOTAL_SIZE NUM_RX_DESC*sizeof(BufferDesc) +/* PCI stuff, should be move to pci.h */ #define SIS630_VENDOR_ID 0x1039 #define SIS630_DEVICE_ID 0x0630 diff -u --recursive --new-file v2.4.6/linux/drivers/net/sk98lin/Makefile linux/drivers/net/sk98lin/Makefile --- v2.4.6/linux/drivers/net/sk98lin/Makefile Fri Dec 29 14:07:22 2000 +++ linux/drivers/net/sk98lin/Makefile Wed Jul 4 11:50:39 2001 @@ -7,7 +7,7 @@ obj-y := skge.o skaddr.o skgehwt.o skgeinit.o skgepnmi.o skgesirq.o \ ski2c.o sklm80.o skqueue.o skrlmt.o sktimer.o skvpd.o \ - skxmac2.o skcsum.o + skxmac2.o skproc.o skcsum.o obj-m := $(O_TARGET) # DBGDEF = \ diff -u --recursive --new-file v2.4.6/linux/drivers/net/sk98lin/h/lm80.h linux/drivers/net/sk98lin/h/lm80.h --- v2.4.6/linux/drivers/net/sk98lin/h/lm80.h Tue Mar 20 12:04:59 2001 +++ linux/drivers/net/sk98lin/h/lm80.h Wed Jul 4 11:50:39 2001 @@ -126,7 +126,7 @@ #define LM80_IS_BTI (1<<1) /* state of BTI# pin */ #define LM80_IS_FAN1 (1<<2) /* count limit exceeded for Fan 1 */ #define LM80_IS_FAN2 (1<<3) /* count limit exceeded for Fan 2 */ -#define LM80_IS_CI (1<<4) /* Chassis Intrusion occurred */ +#define LM80_IS_CI (1<<4) /* Chassis Intrusion occured */ #define LM80_IS_OS (1<<5) /* OS temperature limit exceeded */ /* bit 6 and 7 are reserved in LM80_ISRC_2 */ #define LM80_IS_HT_IRQ_MD (1<<6) /* Hot temperature interrupt mode */ diff -u --recursive --new-file v2.4.6/linux/drivers/net/sk98lin/h/skaddr.h linux/drivers/net/sk98lin/h/skaddr.h --- v2.4.6/linux/drivers/net/sk98lin/h/skaddr.h Fri Sep 15 14:34:19 2000 +++ linux/drivers/net/sk98lin/h/skaddr.h Wed Jul 4 11:50:39 2001 @@ -2,16 +2,15 @@ * * Name: skaddr.h * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.23 $ - * Date: $Date: 2000/08/10 11:27:50 $ + * Version: $Revision: 1.24 $ + * Date: $Date: 2001/01/22 13:41:34 $ * Purpose: Header file for Address Management (MC, UC, Prom). * ******************************************************************************/ /****************************************************************************** * - * (C)Copyright 1998-2000 SysKonnect, - * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * (C)Copyright 1998-2001 SysKonnect GmbH. * * 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 @@ -27,6 +26,9 @@ * History: * * $Log: skaddr.h,v $ + * Revision 1.24 2001/01/22 13:41:34 rassmann + * Supporting two nets on dual-port adapters. + * * Revision 1.23 2000/08/10 11:27:50 rassmann * Editorial changes. * Preserving 32-bit alignment in structs for the adapter context. @@ -158,6 +160,8 @@ #define SK_ADDR_LOGICAL_ADDRESS 0 #define SK_ADDR_VIRTUAL_ADDRESS (SK_ADDR_LOGICAL_ADDRESS) /* old */ #define SK_ADDR_PHYSICAL_ADDRESS 1 +#define SK_ADDR_CLEAR_LOGICAL 2 +#define SK_ADDR_SET_LOGICAL 4 /* ----- Override return values ----- */ @@ -195,18 +199,22 @@ /* Macros */ #ifndef SK_ADDR_EQUAL +/* + * "&" instead of "&&" allows better optimization on IA-64. + * The replacement is safe here, as all bytes exist. + */ #ifndef SK_ADDR_DWORD_COMPARE #define SK_ADDR_EQUAL(A1,A2) ( \ - ((SK_U8 *)(A1))[5] == ((SK_U8 *)(A2))[5] && \ - ((SK_U8 *)(A1))[4] == ((SK_U8 *)(A2))[4] && \ - ((SK_U8 *)(A1))[3] == ((SK_U8 *)(A2))[3] && \ - ((SK_U8 *)(A1))[2] == ((SK_U8 *)(A2))[2] && \ - ((SK_U8 *)(A1))[1] == ((SK_U8 *)(A2))[1] && \ - ((SK_U8 *)(A1))[0] == ((SK_U8 *)(A2))[0]) + (((SK_U8 *)(A1))[5] == ((SK_U8 *)(A2))[5]) & \ + (((SK_U8 *)(A1))[4] == ((SK_U8 *)(A2))[4]) & \ + (((SK_U8 *)(A1))[3] == ((SK_U8 *)(A2))[3]) & \ + (((SK_U8 *)(A1))[2] == ((SK_U8 *)(A2))[2]) & \ + (((SK_U8 *)(A1))[1] == ((SK_U8 *)(A2))[1]) & \ + (((SK_U8 *)(A1))[0] == ((SK_U8 *)(A2))[0])) #else /* SK_ADDR_DWORD_COMPARE */ #define SK_ADDR_EQUAL(A1,A2) ( \ - *(SK_U32 *)&(((SK_U8 *)(A1))[2]) == *(SK_U32 *)&(((SK_U8 *)(A2))[2]) && \ - *(SK_U32 *)&(((SK_U8 *)(A1))[0]) == *(SK_U32 *)&(((SK_U8 *)(A2))[0])) + (*(SK_U32 *)&(((SK_U8 *)(A1))[2]) == *(SK_U32 *)&(((SK_U8 *)(A2))[2])) & \ + (*(SK_U32 *)&(((SK_U8 *)(A1))[0]) == *(SK_U32 *)&(((SK_U8 *)(A2))[0]))) #endif /* SK_ADDR_DWORD_COMPARE */ #endif /* SK_ADDR_EQUAL */ @@ -216,25 +224,31 @@ SK_U8 a[SK_MAC_ADDR_LEN]; } SK_MAC_ADDR; + /* SK_FILTER is used to ensure alignment of the filter. */ typedef union s_InexactFilter { SK_U8 Bytes[8]; SK_U64 Val; /* Dummy entry for alignment only. */ } SK_FILTER64; + +typedef struct s_AddrNet SK_ADDR_NET; + + typedef struct s_AddrPort { /* ----- Public part (read-only) ----- */ SK_MAC_ADDR CurrentMacAddress; /* Current physical MAC Address. */ SK_MAC_ADDR PermanentMacAddress; /* Permanent physical MAC Address. */ - int PromMode; /* Promiscuous Mode. */ + int PromMode; /* Promiscuous Mode. */ /* ----- Private part ----- */ SK_MAC_ADDR PreviousMacAddress; /* Prev. phys. MAC Address. */ SK_BOOL CurrentMacAddressSet; /* CurrentMacAddress is set. */ SK_U8 Align01; + SK_U32 FirstExactMatchRlmt; SK_U32 NextExactMatchRlmt; SK_U32 FirstExactMatchDrv; @@ -243,20 +257,30 @@ SK_FILTER64 InexactFilter; /* For 64-bit hash register. */ } SK_ADDR_PORT; + +struct s_AddrNet { +/* ----- Public part (read-only) ----- */ + + SK_MAC_ADDR CurrentMacAddress; /* Logical MAC Address. */ + SK_MAC_ADDR PermanentMacAddress; /* Logical MAC Address. */ + +/* ----- Private part ----- */ + + SK_U32 ActivePort; /* View of module ADDR. */ + SK_BOOL CurrentMacAddressSet; /* CurrentMacAddress is set. */ + SK_U8 Align01; + SK_U16 Align02; +}; + + typedef struct s_Addr { /* ----- Public part (read-only) ----- */ + SK_ADDR_NET Net[SK_MAX_NETS]; SK_ADDR_PORT Port[SK_MAX_MACS]; - SK_MAC_ADDR PermanentMacAddress; /* Logical MAC Address. */ - SK_MAC_ADDR CurrentMacAddress; /* Logical MAC Address. */ /* ----- Private part ----- */ - - SK_U32 ActivePort; /* View of module ADDR. */ - SK_BOOL CurrentMacAddressSet; /* CurrentMacAddress is set. */ - SK_U8 Align01; - SK_U16 Align02; } SK_ADDR; /* function prototypes ********************************************************/ @@ -270,44 +294,44 @@ extern int SkAddrInit( SK_AC *pAC, SK_IOC IoC, - int Level); + int Level); extern int SkAddrMcClear( SK_AC *pAC, SK_IOC IoC, - SK_U32 PortIdx, - int Flags); + SK_U32 PortNumber, + int Flags); extern int SkAddrMcAdd( SK_AC *pAC, SK_IOC IoC, - SK_U32 PortIdx, + SK_U32 PortNumber, SK_MAC_ADDR *pMc, - int Flags); + int Flags); extern int SkAddrMcUpdate( SK_AC *pAC, SK_IOC IoC, - SK_U32 PortIdx); + SK_U32 PortNumber); extern int SkAddrOverride( SK_AC *pAC, SK_IOC IoC, - SK_U32 PortIdx, + SK_U32 PortNumber, SK_MAC_ADDR *pNewAddr, - int Flags); + int Flags); extern int SkAddrPromiscuousChange( SK_AC *pAC, SK_IOC IoC, - SK_U32 PortIdx, - int NewPromMode); + SK_U32 PortNumber, + int NewPromMode); extern int SkAddrSwap( SK_AC *pAC, SK_IOC IoC, - SK_U32 FromPortIdx, - SK_U32 ToPortIdx); + SK_U32 FromPortNumber, + SK_U32 ToPortNumber); #else /* defined(SK_KR_PROTO)) */ diff -u --recursive --new-file v2.4.6/linux/drivers/net/sk98lin/h/skcsum.h linux/drivers/net/sk98lin/h/skcsum.h --- v2.4.6/linux/drivers/net/sk98lin/h/skcsum.h Fri Sep 15 14:34:19 2000 +++ linux/drivers/net/sk98lin/h/skcsum.h Wed Jul 4 11:50:39 2001 @@ -2,16 +2,15 @@ * * Name: skcsum.h * Project: GEnesis - SysKonnect SK-NET Gigabit Ethernet (SK-98xx) - * Version: $Revision: 1.7 $ - * Date: $Date: 2000/06/29 13:17:05 $ + * Version: $Revision: 1.9 $ + * Date: $Date: 2001/02/06 11:21:39 $ * Purpose: Store/verify Internet checksum in send/receive packets. * ******************************************************************************/ /****************************************************************************** * - * (C)Copyright 1998,1999 SysKonnect, - * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * (C)Copyright 1998-2001 SysKonnect GmbH. * * 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 @@ -27,6 +26,12 @@ * History: * * $Log: skcsum.h,v $ + * Revision 1.9 2001/02/06 11:21:39 rassmann + * Editorial changes. + * + * Revision 1.8 2001/02/06 11:15:36 rassmann + * Supporting two nets on dual-port adapters. + * * Revision 1.7 2000/06/29 13:17:05 rassmann * Corrected reception of a packet with UDP checksum == 0 (which means there * is no UDP checksum). @@ -193,13 +198,13 @@ */ typedef struct s_Csum { /* Enabled receive SK_PROTO_XXX bit flags. */ - unsigned ReceiveFlags; + unsigned ReceiveFlags[SK_MAX_NETS]; #ifdef TX_CSUM - unsigned TransmitFlags; + unsigned TransmitFlags[SK_MAX_NETS]; #endif /* TX_CSUM */ /* The protocol statistics structure; one per supported protocol. */ - SKCS_PROTO_STATS ProtoStats[SKCS_NUM_PROTOCOLS]; + SKCS_PROTO_STATS ProtoStats[SK_MAX_NETS][SKCS_NUM_PROTOCOLS]; } SK_CSUM; /* @@ -237,17 +242,20 @@ SK_AC *pAc, void *pIpHeader, unsigned Checksum1, - unsigned Checksum2); + unsigned Checksum2, + int NetNumber); extern void SkCsGetSendInfo( - SK_AC *pAc, - void *pIpHeader, - SKCS_PACKET_INFO *pPacketInfo); + SK_AC *pAc, + void *pIpHeader, + SKCS_PACKET_INFO *pPacketInfo, + int NetNumber); extern void SkCsSetReceiveFlags( SK_AC *pAc, unsigned ReceiveFlags, unsigned *pChecksum1Offset, - unsigned *pChecksum2Offset); + unsigned *pChecksum2Offset, + int NetNumber); #endif /* __INC_SKCSUM_H */ diff -u --recursive --new-file v2.4.6/linux/drivers/net/sk98lin/h/skdrv1st.h linux/drivers/net/sk98lin/h/skdrv1st.h --- v2.4.6/linux/drivers/net/sk98lin/h/skdrv1st.h Tue Feb 13 13:15:05 2001 +++ linux/drivers/net/sk98lin/h/skdrv1st.h Wed Jul 4 11:50:39 2001 @@ -2,15 +2,15 @@ * * Name: skdrv1st.h * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.8 $ - * Date: $Date: 2000/02/21 12:19:18 $ + * Version: $Revision: 1.9.2.1 $ + * Date: $Date: 2001/03/12 16:50:59 $ * Purpose: First header file for driver and all other modules * ******************************************************************************/ /****************************************************************************** * - * (C)Copyright 1998,1999 SysKonnect, + * (C)Copyright 1998-2001 SysKonnect, * a business unit of Schneider & Koch & Co. Datensysteme GmbH. * * This program is free software; you can redistribute it and/or modify @@ -27,6 +27,14 @@ * History: * * $Log: skdrv1st.h,v $ + * Revision 1.9.2.1 2001/03/12 16:50:59 mlindner + * chg: kernel 2.4 adaption + * + * Revision 1.9 2001/01/22 14:16:04 mlindner + * added ProcFs functionality + * Dual Net functionality integrated + * Rlmt networks added + * * Revision 1.8 2000/02/21 12:19:18 cgoos * Added default for SK_DEBUG_CHKMOD/_CHKCAT * @@ -105,7 +113,7 @@ #include <linux/string.h> #include <linux/errno.h> #include <linux/ioport.h> -#include <linux/slab.h> +#include <linux/malloc.h> #include <linux/interrupt.h> #include <linux/pci.h> #include <asm/byteorder.h> @@ -140,6 +148,7 @@ // #define SK_RLMT_SLOW_LOOKAHEAD #define SK_MAX_MACS 2 +#define SK_MAX_NETS 2 #define SK_IOC char* diff -u --recursive --new-file v2.4.6/linux/drivers/net/sk98lin/h/skdrv2nd.h linux/drivers/net/sk98lin/h/skdrv2nd.h --- v2.4.6/linux/drivers/net/sk98lin/h/skdrv2nd.h Tue Feb 8 18:58:25 2000 +++ linux/drivers/net/sk98lin/h/skdrv2nd.h Wed Jul 4 11:50:39 2001 @@ -2,15 +2,15 @@ * * Name: skdrv2nd.h * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.7 $ - * Date: $Date: 1999/09/28 12:38:21 $ + * Version: $Revision: 1.12.2.1 $ + * Date: $Date: 2001/03/12 16:50:59 $ * Purpose: Second header file for driver and all other modules * ******************************************************************************/ /****************************************************************************** * - * (C)Copyright 1998,1999 SysKonnect, + * (C)Copyright 1998-2001 SysKonnect, * a business unit of Schneider & Koch & Co. Datensysteme GmbH. * * This program is free software; you can redistribute it and/or modify @@ -27,6 +27,32 @@ * History: * * $Log: skdrv2nd.h,v $ + * Revision 1.12.2.1 2001/03/12 16:50:59 mlindner + * chg: kernel 2.4 adaption + * + * Revision 1.12 2001/03/01 12:52:15 mlindner + * Fixed ring size + * + * Revision 1.11 2001/02/19 13:28:02 mlindner + * Changed PNMI parameter values + * + * Revision 1.10 2001/01/22 14:16:04 mlindner + * added ProcFs functionality + * Dual Net functionality integrated + * Rlmt networks added + * + * Revision 1.1 2000/10/05 19:46:50 phargrov + * Add directory src/vipk_devs_nonlbl/vipk_sk98lin/ + * This is the SysKonnect SK-98xx Gigabit Ethernet driver, + * contributed by SysKonnect. + * + * Revision 1.9 2000/02/21 10:39:55 cgoos + * Added flag for jumbo support usage. + * + * Revision 1.8 1999/11/22 13:50:44 cgoos + * Changed license header to GPL. + * Fixed two comments. + * * Revision 1.7 1999/09/28 12:38:21 cgoos * Added CheckQueue to SK_AC. * @@ -160,6 +186,11 @@ #define SK_DRIVER_RESET(pAC, IoC) 0 #define SK_DRIVER_SENDEVENT(pAC, IoC) 0 #define SK_DRIVER_SELFTEST(pAC, IoC) 0 +/* For get mtu you must add an own function */ +#define SK_DRIVER_GET_MTU(pAc,IoC,i) 0 +#define SK_DRIVER_SET_MTU(pAc,IoC,i,v) 0 +#define SK_DRIVER_PRESET_MTU(pAc,IoC,i,v) 0 + /* TX and RX descriptors *****************************************************/ @@ -344,6 +375,16 @@ #define IRQ_HWE_MASK 0x00000FFF /* enable all HW irqs */ +typedef struct s_DevNet DEV_NET; + +struct s_DevNet { + int PortNr; + int NetNr; + int Mtu; + int Up; + SK_AC *pAC; +}; + typedef struct s_TxPort TX_PORT; struct s_TxPort { @@ -397,7 +438,8 @@ SK_RLMT Rlmt; /* for rlmt module */ spinlock_t SlowPathLock; /* Normal IRQ lock */ SK_PNMI_STRUCT_DATA PnmiStruct; /* structure to get all Pnmi-Data */ - int RlmtMode; /* link check mode to set */ + int RlmtMode; /* link check mode to set */ + int RlmtNets; /* Number of nets */ SK_IOC IoBase; /* register set of adapter */ int BoardLevel; /* level of active hw init (0-2) */ @@ -405,7 +447,7 @@ SK_U32 AllocFlag; /* flag allocation of resources */ struct pci_dev PciDev; /* for access to pci config space */ SK_U32 PciDevId; /* pci device id */ - struct net_device *dev; /* pointer to device struct */ + struct net_device *dev[2]; /* pointer to device struct */ char Name[30]; /* driver name */ struct net_device *Next; /* link all devices (for clearing) */ int RxBufSize; /* length of receive buffers */ @@ -424,6 +466,7 @@ /* (may be more than HW can)*/ int ActivePort; /* the active XMAC port */ + int MaxPorts; /* number of activated ports */ int TxDescrPerRing; /* # of descriptors per tx ring */ int RxDescrPerRing; /* # of descriptors per rx ring */ diff -u --recursive --new-file v2.4.6/linux/drivers/net/sk98lin/h/skgehw.h linux/drivers/net/sk98lin/h/skgehw.h --- v2.4.6/linux/drivers/net/sk98lin/h/skgehw.h Tue Mar 20 12:04:59 2001 +++ linux/drivers/net/sk98lin/h/skgehw.h Wed Jul 4 11:50:39 2001 @@ -2,8 +2,8 @@ * * Name: skgehw.h * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.35 $ - * Date: $Date: 2000/05/19 10:17:13 $ + * Version: $Revision: 1.36 $ + * Date: $Date: 2000/11/09 12:32:49 $ * Purpose: Defines and Macros for the Gigabit Ethernet Adapter Product * Family * @@ -11,8 +11,7 @@ /****************************************************************************** * - * (C)Copyright 1998,1999 SysKonnect, - * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * (C)Copyright 1998-2000 SysKonnect GmbH. * * 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 @@ -27,6 +26,9 @@ * * History: * $Log: skgehw.h,v $ + * Revision 1.36 2000/11/09 12:32:49 rassmann + * Renamed variables. + * * Revision 1.35 2000/05/19 10:17:13 cgoos * Added inactivity check in PHY_READ (in DEBUG mode only). * @@ -180,27 +182,27 @@ */ #define PCI_VENDOR_ID 0x00 /* 16 bit Vendor ID */ #define PCI_DEVICE_ID 0x02 /* 16 bit Device ID */ -#define PCI_COMMAND 0x04 /* 16 bit Command */ -#define PCI_STATUS 0x06 /* 16 bit Status */ -#define PCI_REV_ID 0x08 /* 8 bit Revision ID */ +#define PCI_COMMAND 0x04 /* 16 bit Command */ +#define PCI_STATUS 0x06 /* 16 bit Status */ +#define PCI_REV_ID 0x08 /* 8 bit Revision ID */ #define PCI_CLASS_CODE 0x09 /* 24 bit Class Code */ #define PCI_CACHE_LSZ 0x0c /* 8 bit Cache Line Size */ -#define PCI_LAT_TIM 0x0d /* 8 bit Latency Timer */ +#define PCI_LAT_TIM 0x0d /* 8 bit Latency Timer */ #define PCI_HEADER_T 0x0e /* 8 bit Header Type */ -#define PCI_BIST 0x0f /* 8 bit Built-in selftest */ +#define PCI_BIST 0x0f /* 8 bit Built-in selftest */ #define PCI_BASE_1ST 0x10 /* 32 bit 1st Base address */ #define PCI_BASE_2ND 0x14 /* 32 bit 2nd Base address */ /* Byte 18..2b: reserved */ -#define PCI_SUB_VID 0x2c /* 16 bit Subsystem Vendor ID */ -#define PCI_SUB_ID 0x2e /* 16 bit Subsystem ID */ +#define PCI_SUB_VID 0x2c /* 16 bit Subsystem Vendor ID */ +#define PCI_SUB_ID 0x2e /* 16 bit Subsystem ID */ #define PCI_BASE_ROM 0x30 /* 32 bit Expansion ROM Base Address */ /* Byte 34..33: reserved */ -#define PCI_CAP_PTR 0x34 /* 8 bit Capabilities Ptr */ +#define PCI_CAP_PTR 0x34 /* 8 bit Capabilities Ptr */ /* Byte 35..3b: reserved */ #define PCI_IRQ_LINE 0x3c /* 8 bit Interrupt Line */ -#define PCI_IRQ_PIN 0x3d /* 8 bit Interrupt Pin */ -#define PCI_MIN_GNT 0x3e /* 8 bit Min_Gnt */ -#define PCI_MAX_LAT 0x3f /* 8 bit Max_Lat */ +#define PCI_IRQ_PIN 0x3d /* 8 bit Interrupt Pin */ +#define PCI_MIN_GNT 0x3e /* 8 bit Min_Gnt */ +#define PCI_MAX_LAT 0x3f /* 8 bit Max_Lat */ /* Device Dependent Region */ #define PCI_OUR_REG_1 0x40 /* 32 bit Our Register 1 */ #define PCI_OUR_REG_2 0x44 /* 32 bit Our Register 2 */ @@ -233,34 +235,34 @@ /* PCI_DEVICE_ID 16 bit Device ID */ /* Values for Vendor ID and Device ID shall be patched into the code */ /* PCI_COMMAND 16 bit Command */ - /* Bit 15..10: reserved */ -#define PCI_FBTEN (1<<9) /* Bit 9: Fast Back-To-Back enable */ -#define PCI_SERREN (1<<8) /* Bit 8: SERR enable */ -#define PCI_ADSTEP (1<<7) /* Bit 7: Address Stepping */ -#define PCI_PERREN (1<<6) /* Bit 6: Parity Report Response enable */ + /* Bit 15..10: reserved */ +#define PCI_FBTEN (1<<9) /* Bit 9: Fast Back-To-Back enable */ +#define PCI_SERREN (1<<8) /* Bit 8: SERR enable */ +#define PCI_ADSTEP (1<<7) /* Bit 7: Address Stepping */ +#define PCI_PERREN (1<<6) /* Bit 6: Parity Report Response enable */ #define PCI_VGA_SNOOP (1<<5) /* Bit 5: VGA palette snoop */ -#define PCI_MWIEN (1<<4) /* Bit 4: Memory write an inv cycl ena */ -#define PCI_SCYCEN (1<<3) /* Bit 3: Special Cycle enable */ -#define PCI_BMEN (1<<2) /* Bit 2: Bus Master enable */ -#define PCI_MEMEN (1<<1) /* Bit 1: Memory Space Access enable */ -#define PCI_IOEN (1<<0) /* Bit 0: IO Space Access enable */ +#define PCI_MWIEN (1<<4) /* Bit 4: Memory write an inv cycl ena */ +#define PCI_SCYCEN (1<<3) /* Bit 3: Special Cycle enable */ +#define PCI_BMEN (1<<2) /* Bit 2: Bus Master enable */ +#define PCI_MEMEN (1<<1) /* Bit 1: Memory Space Access enable */ +#define PCI_IOEN (1<<0) /* Bit 0: IO Space Access enable */ /* PCI_STATUS 16 bit Status */ -#define PCI_PERR (1<<15) /* Bit 15: Parity Error */ -#define PCI_SERR (1<<14) /* Bit 14: Signaled SERR */ -#define PCI_RMABORT (1<<13) /* Bit 13: Received Master Abort */ -#define PCI_RTABORT (1<<12) /* Bit 12: Received Target Abort */ - /* Bit 11: reserved */ -#define PCI_DEVSEL (3<<9) /* Bit 10..9: DEVSEL Timing */ +#define PCI_PERR (1<<15) /* Bit 15: Parity Error */ +#define PCI_SERR (1<<14) /* Bit 14: Signaled SERR */ +#define PCI_RMABORT (1<<13) /* Bit 13: Received Master Abort */ +#define PCI_RTABORT (1<<12) /* Bit 12: Received Target Abort */ + /* Bit 11: reserved */ +#define PCI_DEVSEL (3<<9) /* Bit 10..9: DEVSEL Timing */ #define PCI_DEV_FAST (0<<9) /* fast */ #define PCI_DEV_MEDIUM (1<<9) /* medium */ #define PCI_DEV_SLOW (2<<9) /* slow */ #define PCI_DATAPERR (1<<8) /* Bit 8: DATA Parity error detected */ -#define PCI_FB2BCAP (1<<7) /* Bit 7: Fast Back-to-Back Capability */ -#define PCI_UDF (1<<6) /* Bit 6: User Defined Features */ +#define PCI_FB2BCAP (1<<7) /* Bit 7: Fast Back-to-Back Capability */ +#define PCI_UDF (1<<6) /* Bit 6: User Defined Features */ #define PCI_66MHZCAP (1<<5) /* Bit 5: 66 MHz PCI bus clock capable */ -#define PCI_NEWCAP (1<<4) /* Bit 4: New cap. list implemented */ - /* Bit 3..0: reserved */ +#define PCI_NEWCAP (1<<4) /* Bit 4: New cap. list implemented */ + /* Bit 3..0: reserved */ #define PCI_ERRBITS (PCI_PERR | PCI_SERR | PCI_RMABORT | PCI_RTABORT |\ PCI_DATAPERR) @@ -275,59 +277,59 @@ /* PCI_HEADER_T 8 bit Header Type */ #define PCI_HD_MF_DEV (1<<7) /* Bit 7: 0= single, 1= multi-func dev */ -#define PCI_HD_TYPE 0x7f /* Bit 6..0: Header Layout 0= normal */ +#define PCI_HD_TYPE 0x7f /* Bit 6..0: Header Layout 0= normal */ /* PCI_BIST 8 bit Built-in selftest */ /* Built-in Self test not supported (optional) */ /* PCI_BASE_1ST 32 bit 1st Base address */ -#define PCI_MEMSIZE 0x4000L /* use 16 kB Memory Base */ +#define PCI_MEMSIZE 0x4000L /* use 16 kB Memory Base */ #define PCI_MEMBASE_MSK 0xffffc000L /* Bit 31..14: Memory Base Address */ #define PCI_MEMSIZE_MSK 0x00003ff0L /* Bit 13.. 4: Memory Size Req. */ -#define PCI_PREFEN (1L<<3) /* Bit 3: Prefetchable */ -#define PCI_MEM_TYP (3L<<2) /* Bit 2.. 1: Memory Type */ +#define PCI_PREFEN (1L<<3) /* Bit 3: Prefetchable */ +#define PCI_MEM_TYP (3L<<2) /* Bit 2.. 1: Memory Type */ #define PCI_MEM32BIT (0L<<1) /* Base addr anywhere in 32 Bit range */ -#define PCI_MEM1M (1L<<1) /* Base addr below 1 MegaByte */ +#define PCI_MEM1M (1L<<1) /* Base addr below 1 MegaByte */ #define PCI_MEM64BIT (2L<<1) /* Base addr anywhere in 64 Bit range */ #define PCI_MEMSPACE (1L<<0) /* Bit 0: Memory Space Indic. */ /* PCI_BASE_2ND 32 bit 2nd Base address */ -#define PCI_IOBASE 0xffffff00L /* Bit 31..8: I/O Base address */ -#define PCI_IOSIZE 0x000000fcL /* Bit 7..2: I/O Size Requirements */ - /* Bit 1: reserved */ -#define PCI_IOSPACE (1L<<0) /* Bit 0: I/O Space Indicator */ +#define PCI_IOBASE 0xffffff00L /* Bit 31..8: I/O Base address */ +#define PCI_IOSIZE 0x000000fcL /* Bit 7..2: I/O Size Requirements */ + /* Bit 1: reserved */ +#define PCI_IOSPACE (1L<<0) /* Bit 0: I/O Space Indicator */ /* PCI_BASE_ROM 32 bit Expansion ROM Base Address */ -#define PCI_ROMBASE (0xfffeL<<17) /* Bit 31..17: ROM BASE address (1st)*/ -#define PCI_ROMBASZ (0x1cL<<14) /* Bit 16..14: Treat as BASE or SIZE */ -#define PCI_ROMSIZE (0x38L<<11) /* Bit 13..11: ROM Size Requirements */ - /* Bit 10.. 1: reserved */ -#define PCI_ROMEN (0x1L<<0) /* Bit 0: Address Decode enable */ +#define PCI_ROMBASE (0xfffeL<<17) /* Bit 31..17: ROM BASE address (1st)*/ +#define PCI_ROMBASZ (0x1cL<<14) /* Bit 16..14: Treat as BASE or SIZE */ +#define PCI_ROMSIZE (0x38L<<11) /* Bit 13..11: ROM Size Requirements */ + /* Bit 10.. 1: reserved */ +#define PCI_ROMEN (0x1L<<0) /* Bit 0: Address Decode enable */ /* Device Dependent Region */ /* PCI_OUR_REG_1 32 bit Our Register 1 */ - /* Bit 31..26: reserved */ -#define PCI_VIO (1L<<25) /* Bit 25: PCI IO Voltage, */ - /* 0 = 3.3V / 1 = 5V */ -#define PCI_EN_BOOT (1L<<24) /* Bit 24: Enable BOOT via ROM */ - /* 1 = Don't boot wth ROM*/ - /* 0 = Boot with ROM */ -#define PCI_EN_IO (1L<<23) /* Bit 23: Mapping to IO space */ + /* Bit 31..26: reserved */ +#define PCI_VIO (1L<<25) /* Bit 25: PCI IO Voltage, */ + /* 0 = 3.3V / 1 = 5V */ +#define PCI_EN_BOOT (1L<<24) /* Bit 24: Enable BOOT via ROM */ + /* 1 = Don't boot wth ROM*/ + /* 0 = Boot with ROM */ +#define PCI_EN_IO (1L<<23) /* Bit 23: Mapping to IO space */ #define PCI_EN_FPROM (1L<<22) /* Bit 22: FLASH mapped to mem? */ - /* 1 = Map Flash to Mem */ - /* 0 = Disable addr. dec*/ + /* 1 = Map Flash to Mem */ + /* 0 = Disable addr. dec*/ #define PCI_PAGESIZE (3L<<20) /* Bit 21..20: FLASH Page Size */ -#define PCI_PAGE_16 (0L<<20) /* 16 k pages */ +#define PCI_PAGE_16 (0L<<20) /* 16 k pages */ #define PCI_PAGE_32K (1L<<20) /* 32 k pages */ #define PCI_PAGE_64K (2L<<20) /* 64 k pages */ #define PCI_PAGE_128K (3L<<20) /* 128 k pages */ - /* Bit 19: reserved */ -#define PCI_PAGEREG (7L<<16) /* Bit 18..16: Page Register */ -#define PCI_NOTAR (1L<<15) /* Bit 15: No turnaround cycle */ + /* Bit 19: reserved */ +#define PCI_PAGEREG (7L<<16) /* Bit 18..16: Page Register */ +#define PCI_NOTAR (1L<<15) /* Bit 15: No turnaround cycle */ #define PCI_FORCE_BE (1L<<14) /* Bit 14: Assert all BEs on MR */ -#define PCI_DIS_MRL (1L<<13) /* Bit 13: Disable Mem R Line */ -#define PCI_DIS_MRM (1L<<12) /* Bit 12: Disable Mem R multip */ -#define PCI_DIS_MWI (1L<<11) /* Bit 11: Disable Mem W & inv */ +#define PCI_DIS_MRL (1L<<13) /* Bit 13: Disable Mem R Line */ +#define PCI_DIS_MRM (1L<<12) /* Bit 12: Disable Mem R multip */ +#define PCI_DIS_MWI (1L<<11) /* Bit 11: Disable Mem W & inv */ #define PCI_DISC_CLS (1L<<10) /* Bit 10: Disc: cacheLsz bound */ #define PCI_BURST_DIS (1L<<9) /* Bit 9: Burst Disable */ #define PCI_DIS_PCI_CLK (1L<<8) /* Bit 8: Disable PCI clock driv*/ @@ -337,9 +339,9 @@ /* PCI_OUR_REG_2 32 bit Our Register 2 */ #define PCI_VPD_WR_THR (0xffL<<24) /* Bit 31..24: VPD Write Threshold */ -#define PCI_DEV_SEL (0x7fL<<17) /* Bit 23..17: EEPROM Device Select */ +#define PCI_DEV_SEL (0x7fL<<17) /* Bit 23..17: EEPROM Device Select */ #define PCI_VPD_ROM_SZ (7L<<14) /* Bit 16..14: VPD ROM Size */ - /* Bit 13..12: reserved */ + /* Bit 13..12: reserved */ #define PCI_PATCH_DIR (0xfL<<8) /* Bit 11.. 8: Ext Patchs dir 3..0 */ #define PCI_PATCH_DIR_0 (1L<<8) #define PCI_PATCH_DIR_1 (1L<<9) @@ -352,27 +354,27 @@ #define PCI_EXT_PATCH_3 (1L<<7) #define PCI_EN_DUMMY_RD (1L<<3) /* Bit 3: Enable Dummy Read */ #define PCI_REV_DESC (1L<<2) /* Bit 2: Reverse Desc. Bytes */ - /* Bit 1: reserved */ + /* Bit 1: reserved */ #define PCI_USEDATA64 (1L<<0) /* Bit 0: Use 64Bit Data bus ext*/ /* Power Management Region */ /* PCI_PM_CAP_REG 16 bit Power Management Capabilities */ -#define PCI_PME_SUP (0x1f<<11) /* Bit 15..11: PM Manag. Event Sup */ +#define PCI_PME_SUP (0x1f<<11) /* Bit 15..11: PM Manag. Event Sup */ #define PCI_PM_D2_SUB (1<<10) /* Bit 10: D2 Support Bit */ #define PCI_PM_D1_SUB (1<<9) /* Bit 9: D1 Support Bit */ - /* Bit 8..6: reserved */ -#define PCI_PM_DSI (1<<5) /* Bit 5: Device Specific Init.*/ -#define PCI_PM_APS (1<<4) /* Bit 4: Auxialiary Power Src */ + /* Bit 8..6: reserved */ +#define PCI_PM_DSI (1<<5) /* Bit 5: Device Specific Init.*/ +#define PCI_PM_APS (1<<4) /* Bit 4: Auxialiary Power Src */ #define PCI_PME_CLOCK (1<<3) /* Bit 3: PM Event Clock */ -#define PCI_PM_VER (7<<0) /* Bit 2..0: PM PCI Spec. version */ +#define PCI_PM_VER (7<<0) /* Bit 2..0: PM PCI Spec. version */ /* PCI_PM_CTL_STS 16 bit Power Manag. Control/Status */ #define PCI_PME_STATUS (1<<15) /* Bit 15: PGA doesn't sup. PME# */ #define PCI_PM_DAT_SCL (3<<13) /* Bit 14..13: dat reg Scaling factor*/ #define PCI_PM_DAT_SEL (0xf<<9) /* Bit 12.. 9: PM data selector field*/ -#define PCI_PME_EN (1<<8) /* Bit 8: PGA doesn't sup. PME# */ - /* Bit 7.. 2: reserved */ +#define PCI_PME_EN (1<<8) /* Bit 8: PGA doesn't sup. PME# */ + /* Bit 7.. 2: reserved */ #define PCI_PM_STATE (3<<0) /* Bit 1.. 0: Power Management State*/ #define PCI_PM_STATE_D0 (0<<0) /* D0: Operational (default) */ #define PCI_PM_STATE_D1 (1<<0) /* D1: not supported */ @@ -388,22 +390,22 @@ * Control Register File: * Bank 0 */ -#define B0_RAP 0x0000 /* 8 bit Register Address Port */ +#define B0_RAP 0x0000 /* 8 bit Register Address Port */ /* 0x0001 - 0x0003: reserved */ -#define B0_CTST 0x0004 /* 16 bit Control/Status register */ -#define B0_LED 0x0006 /* 8 Bit LED register */ +#define B0_CTST 0x0004 /* 16 bit Control/Status register */ +#define B0_LED 0x0006 /* 8 Bit LED register */ /* 0x0007: reserved */ -#define B0_ISRC 0x0008 /* 32 bit Interrupt Source Register */ -#define B0_IMSK 0x000c /* 32 bit Interrupt Mask Register */ -#define B0_HWE_ISRC 0x0010 /* 32 bit HW Error Interrupt Src Reg */ -#define B0_HWE_IMSK 0x0014 /* 32 bit HW Error Interrupt Mask Reg */ -#define B0_SP_ISRC 0x0018 /* 32 bit Special Interrupt Source Reg */ +#define B0_ISRC 0x0008 /* 32 bit Interrupt Source Register */ +#define B0_IMSK 0x000c /* 32 bit Interrupt Mask Register */ +#define B0_HWE_ISRC 0x0010 /* 32 bit HW Error Interrupt Src Reg */ +#define B0_HWE_IMSK 0x0014 /* 32 bit HW Error Interrupt Mask Reg */ +#define B0_SP_ISRC 0x0018 /* 32 bit Special Interrupt Source Reg */ /* 0x001c: reserved */ /* B0 XMAC 1 registers */ -#define B0_XM1_IMSK 0x0020 /* 16 bit r/w XMAC 1 Interrupt Mask Register*/ +#define B0_XM1_IMSK 0x0020 /* 16 bit r/w XMAC 1 Interrupt Mask Register*/ /* 0x0022 - 0x0027 reserved */ -#define B0_XM1_ISRC 0x0028 /* 16 bit ro XMAC 1 Interrupt Status Reg */ +#define B0_XM1_ISRC 0x0028 /* 16 bit ro XMAC 1 Interrupt Status Reg */ /* 0x002a - 0x002f reserved */ #define B0_XM1_PHY_ADDR 0x0030 /* 16 bit r/w XMAC 1 PHY Address Register */ /* 0x0032 - 0x0033 reserved */ @@ -411,9 +413,9 @@ /* 0x0036 - 0x003f reserved */ /* B0 XMAC 2 registers */ -#define B0_XM2_IMSK 0x0040 /* 16 bit r/w XMAC 2 Interrupt Mask Register*/ +#define B0_XM2_IMSK 0x0040 /* 16 bit r/w XMAC 2 Interrupt Mask Register*/ /* 0x0042 - 0x0047 reserved */ -#define B0_XM2_ISRC 0x0048 /* 16 bit ro XMAC 2 Interrupt Status Reg */ +#define B0_XM2_ISRC 0x0048 /* 16 bit ro XMAC 2 Interrupt Status Reg */ /* 0x004a - 0x004f reserved */ #define B0_XM2_PHY_ADDR 0x0050 /* 16 bit r/w XMAC 2 PHY Address Register */ /* 0x0052 - 0x0053 reserved */ @@ -421,12 +423,12 @@ /* 0x0056 - 0x005f reserved */ /* BMU Control Status Registers */ -#define B0_R1_CSR 0x0060 /* 32 bit BMU Ctrl/Stat Rx Queue 1 */ -#define B0_R2_CSR 0x0064 /* 32 bit BMU Ctrl/Stat Rx Queue 2 */ -#define B0_XS1_CSR 0x0068 /* 32 bit BMU Ctrl/Stat Sync Tx Queue 1 */ -#define B0_XA1_CSR 0x006c /* 32 bit BMU Ctrl/Stat Async Tx Queue 1*/ -#define B0_XS2_CSR 0x0070 /* 32 bit BMU Ctrl/Stat Sync Tx Queue 2 */ -#define B0_XA2_CSR 0x0074 /* 32 bit BMU Ctrl/Stat Async Tx Queue 2*/ +#define B0_R1_CSR 0x0060 /* 32 bit BMU Ctrl/Stat Rx Queue 1 */ +#define B0_R2_CSR 0x0064 /* 32 bit BMU Ctrl/Stat Rx Queue 2 */ +#define B0_XS1_CSR 0x0068 /* 32 bit BMU Ctrl/Stat Sync Tx Queue 1 */ +#define B0_XA1_CSR 0x006c /* 32 bit BMU Ctrl/Stat Async Tx Queue 1*/ +#define B0_XS2_CSR 0x0070 /* 32 bit BMU Ctrl/Stat Sync Tx Queue 2 */ +#define B0_XA2_CSR 0x0074 /* 32 bit BMU Ctrl/Stat Async Tx Queue 2*/ /* x0078 - 0x007f reserved */ /* @@ -440,34 +442,34 @@ */ /* NA reg = 48 bit Network Address Register, 3x16 or 8x8 bit readable */ -#define B2_MAC_1 0x0100 /* NA reg MAC Address 1 */ +#define B2_MAC_1 0x0100 /* NA reg MAC Address 1 */ /* 0x0106 - 0x0107 reserved */ -#define B2_MAC_2 0x0108 /* NA reg MAC Address 2 */ +#define B2_MAC_2 0x0108 /* NA reg MAC Address 2 */ /* 0x010e - 0x010f reserved */ -#define B2_MAC_3 0x0110 /* NA reg MAC Address 3 */ +#define B2_MAC_3 0x0110 /* NA reg MAC Address 3 */ /* 0x0116 - 0x0117 reserved */ -#define B2_CONN_TYP 0x0118 /* 8 bit Connector type */ -#define B2_PMD_TYP 0x0119 /* 8 bit PMD type */ -#define B2_MAC_CFG 0x011a /* 8 bit MAC Configuration */ -#define B2_CHIP_REV 0x011b /* 8 bit Queen Chip Revision Number */ +#define B2_CONN_TYP 0x0118 /* 8 bit Connector type */ +#define B2_PMD_TYP 0x0119 /* 8 bit PMD type */ +#define B2_MAC_CFG 0x011a /* 8 bit MAC Configuration */ +#define B2_CHIP_REV 0x011b /* 8 bit Queen Chip Revision Number */ /* Eprom registers are currently of no use */ -#define B2_E_0 0x011c /* 8 bit EPROM Byte 0 */ -#define B2_E_1 0x011d /* 8 bit EPROM Byte 1 */ -#define B2_E_2 0x011e /* 8 bit EPROM Byte 2 */ -#define B2_E_3 0x011f /* 8 bit EPROM Byte 3 */ -#define B2_FAR 0x0120 /* 32 bit Flash-Prom Addr Reg/Cnt */ -#define B2_FDP 0x0124 /* 8 bit Flash-Prom Data Port */ +#define B2_E_0 0x011c /* 8 bit EPROM Byte 0 */ +#define B2_E_1 0x011d /* 8 bit EPROM Byte 1 */ +#define B2_E_2 0x011e /* 8 bit EPROM Byte 2 */ +#define B2_E_3 0x011f /* 8 bit EPROM Byte 3 */ +#define B2_FAR 0x0120 /* 32 bit Flash-Prom Addr Reg/Cnt */ +#define B2_FDP 0x0124 /* 8 bit Flash-Prom Data Port */ /* 0x0125 - 0x0127: reserved */ -#define B2_LD_CRTL 0x0128 /* 8 bit EPROM loader control register */ -#define B2_LD_TEST 0x0129 /* 8 bit EPROM loader test register */ +#define B2_LD_CRTL 0x0128 /* 8 bit EPROM loader control register */ +#define B2_LD_TEST 0x0129 /* 8 bit EPROM loader test register */ /* 0x012a - 0x012f: reserved */ -#define B2_TI_INI 0x0130 /* 32 bit Timer init value */ -#define B2_TI_VAL 0x0134 /* 32 bit Timer value */ -#define B2_TI_CRTL 0x0138 /* 8 bit Timer control */ -#define B2_TI_TEST 0x0139 /* 8 Bit Timer Test */ +#define B2_TI_INI 0x0130 /* 32 bit Timer init value */ +#define B2_TI_VAL 0x0134 /* 32 bit Timer value */ +#define B2_TI_CRTL 0x0138 /* 8 bit Timer control */ +#define B2_TI_TEST 0x0139 /* 8 Bit Timer Test */ /* 0x013a - 0x013f: reserved */ -#define B2_IRQM_INI 0x0140 /* 32 bit IRQ Moderation Timer Init Reg.*/ -#define B2_IRQM_VAL 0x0144 /* 32 bit IRQ Moderation Timer Value */ +#define B2_IRQM_INI 0x0140 /* 32 bit IRQ Moderation Timer Init Reg.*/ +#define B2_IRQM_VAL 0x0144 /* 32 bit IRQ Moderation Timer Value */ #define B2_IRQM_CTRL 0x0148 /* 8 bit IRQ Moderation Timer Control */ #define B2_IRQM_TEST 0x0149 /* 8 bit IRQ Moderation Timer Test */ #define B2_IRQM_MSK 0x014c /* 32 bit IRQ Moderation Mask */ @@ -476,22 +478,22 @@ #define B2_TST_CTRL1 0x0158 /* 8 bit Test Control Register 1 */ #define B2_TST_CTRL2 0x0159 /* 8 bit Test Control Register 2 */ /* 0x015a - 0x015b: reserved */ -#define B2_GP_IO 0x015c /* 32 bit General Purpose IO Register */ -#define B2_I2C_CTRL 0x0160 /* 32 bit I2C HW Control Register */ -#define B2_I2C_DATA 0x0164 /* 32 bit I2C HW Data Register */ -#define B2_I2C_IRQ 0x0168 /* 32 bit I2C HW IRQ Register */ -#define B2_I2C_SW 0x016c /* 32 bit I2C SW Port Register */ -#define B2_BSC_INI 0x0170 /* 32 bit Blink Source Counter Init Val */ -#define B2_BSC_VAL 0x0174 /* 32 bit Blink Source Counter Value */ -#define B2_BSC_CTRL 0x0178 /* 8 bit Blink Source Counter Control */ -#define B2_BSC_STAT 0x0179 /* 8 bit Blink Source Counter Status */ -#define B2_BSC_TST 0x017a /* 16 bit Blink Source Counter Test Reg */ +#define B2_GP_IO 0x015c /* 32 bit General Purpose IO Register */ +#define B2_I2C_CTRL 0x0160 /* 32 bit I2C HW Control Register */ +#define B2_I2C_DATA 0x0164 /* 32 bit I2C HW Data Register */ +#define B2_I2C_IRQ 0x0168 /* 32 bit I2C HW IRQ Register */ +#define B2_I2C_SW 0x016c /* 32 bit I2C SW Port Register */ +#define B2_BSC_INI 0x0170 /* 32 bit Blink Source Counter Init Val */ +#define B2_BSC_VAL 0x0174 /* 32 bit Blink Source Counter Value */ +#define B2_BSC_CTRL 0x0178 /* 8 bit Blink Source Counter Control */ +#define B2_BSC_STAT 0x0179 /* 8 bit Blink Source Counter Status */ +#define B2_BSC_TST 0x017a /* 16 bit Blink Source Counter Test Reg */ /* 0x017c - 0x017f: reserved */ /* * Bank 3 */ -#define B3_RAM_ADDR 0x0180 /* 32 bit RAM Address, to read or write */ +#define B3_RAM_ADDR 0x0180 /* 32 bit RAM Address, to read or write */ #define B3_RAM_DATA_LO 0x0184 /* 32 bit RAM Data Word (low dWord) */ #define B3_RAM_DATA_HI 0x0188 /* 32 bit RAM Data Word (high dWord) */ /* 0x018c - 0x018f: reserved */ @@ -499,7 +501,7 @@ /* * The HW-Spec. call this registers Timeout Value 0..11. But this names are * not usable in SW. Please notice these are NOT real timeouts, these are - * the number of qWords transferred continously. + * the number of qWords transfered continously. */ #define B3_RI_WTO_R1 0x0190 /* 8 bit RAM Iface WR Timeout Queue R1 (TO0) */ #define B3_RI_WTO_XA1 0x0191 /* 8 bit RAM Iface WR Timeout Queue XA1 (TO1) */ @@ -515,8 +517,8 @@ #define B3_RI_RTO_XS2 0x019b /* 8 bit RAM Iface RD Timeout Queue XS2 (TO11)*/ #define B3_RI_TO_VAL 0x019c /* 8 bit RAM Iface Current Timeout Count Val */ /* 0x019d - 0x019f reserved */ -#define B3_RI_CTRL 0x01a0 /* 16 bit RAM Iface Control Register */ -#define B3_RI_TEST 0x01a2 /* 8 bit RAM Iface Test Register */ +#define B3_RI_CTRL 0x01a0 /* 16 bit RAM Iface Control Register */ +#define B3_RI_TEST 0x01a2 /* 8 bit RAM Iface Test Register */ /* 0x01a3 - 0x01af reserved */ /* MAC Arbiter Registers */ /* Please notice these are the number of qWord tranfered continously and */ @@ -569,42 +571,42 @@ */ /* Transmit Arbiter Registers MAC 1 and 2, user MR_ADDR() to address */ -#define TXA_ITI_INI 0x0200 /* 32 bit Tx Arb Interval Timer Init Val*/ -#define TXA_ITI_VAL 0x0204 /* 32 bit Tx Arb Interval Timer Value */ -#define TXA_LIM_INI 0x0208 /* 32 bit Tx Arb Limit Counter Init Val */ -#define TXA_LIM_VAL 0x020c /* 32 bit Tx Arb Limit Counter Value */ -#define TXA_CTRL 0x0210 /* 8 bit Tx Arbiter Control Register */ -#define TXA_TEST 0x0211 /* 8 bit Tx Arbiter Test Register */ -#define TXA_STAT 0x0212 /* 8 bit Tx Arbiter Status Register */ +#define TXA_ITI_INI 0x0200 /* 32 bit Tx Arb Interval Timer Init Val*/ +#define TXA_ITI_VAL 0x0204 /* 32 bit Tx Arb Interval Timer Value */ +#define TXA_LIM_INI 0x0208 /* 32 bit Tx Arb Limit Counter Init Val */ +#define TXA_LIM_VAL 0x020c /* 32 bit Tx Arb Limit Counter Value */ +#define TXA_CTRL 0x0210 /* 8 bit Tx Arbiter Control Register */ +#define TXA_TEST 0x0211 /* 8 bit Tx Arbiter Test Register */ +#define TXA_STAT 0x0212 /* 8 bit Tx Arbiter Status Register */ /* 0x0213 - 0x027f: reserved */ /* * Bank 6 */ /* External registers */ -#define B6_EXT_REG 0x0300 +#define B6_EXT_REG 0x0300 /* * Bank 7 */ /* This is a copy of the Configuration register file (lower half) */ -#define B7_CFG_SPC 0x0380 +#define B7_CFG_SPC 0x0380 /* * Bank 8 - 15 */ /* Receive and Transmit Queue Registers, use Q_ADDR() to access */ -#define B8_Q_REGS 0x0400 +#define B8_Q_REGS 0x0400 /* Queue Register Offsets, use Q_ADDR() to access */ -#define Q_D 0x00 /* 8*32 bit Current Descriptor */ +#define Q_D 0x00 /* 8*32 bit Current Descriptor */ #define Q_DA_L 0x20 /* 32 bit Current Descriptor Address Low dWord */ #define Q_DA_H 0x24 /* 32 bit Current Descriptor Address High dWord */ #define Q_AC_L 0x28 /* 32 bit Current Address Counter Low dWord */ #define Q_AC_H 0x2c /* 32 bit Current Address Counter High dWord */ #define Q_BC 0x30 /* 32 bit Current Byte Counter */ #define Q_CSR 0x34 /* 32 bit BMU Control/Status Register */ -#define Q_F 0x38 /* 32 bit Flag Register */ +#define Q_F 0x38 /* 32 bit Flag Register */ #define Q_T1 0x3c /* 32 bit Test Register 1 */ #define Q_T1_TR 0x3c /* 8 bit Test Register 1 Transfer SM */ #define Q_T1_WR 0x3d /* 8 bit Test Register 1 Write Descriptor SM */ @@ -642,64 +644,64 @@ * Bank 24 - 25 */ /* Receive MAC FIFO, Receive LED, and Link Sync regs, use MR_ADDR() to address*/ -#define RX_MFF_EA 0x0c00 /* 32 bit Receive MAC FIFO End Address */ -#define RX_MFF_WP 0x0c04 /* 32 bit Receive MAC FIFO Write Pointer*/ +#define RX_MFF_EA 0x0c00 /* 32 bit Receive MAC FIFO End Address */ +#define RX_MFF_WP 0x0c04 /* 32 bit Receive MAC FIFO Write Pointer*/ /* 0x0c08 - 0x0c0b reserved */ -#define RX_MFF_RP 0x0c0c /* 32 bit Receive MAC FIFO Read Pointer */ -#define RX_MFF_PC 0x0c10 /* 32 bit Receive MAC FIFO Packet Cnt */ -#define RX_MFF_LEV 0x0c14 /* 32 bit Receive MAC FIFO Level */ +#define RX_MFF_RP 0x0c0c /* 32 bit Receive MAC FIFO Read Pointer */ +#define RX_MFF_PC 0x0c10 /* 32 bit Receive MAC FIFO Packet Cnt */ +#define RX_MFF_LEV 0x0c14 /* 32 bit Receive MAC FIFO Level */ #define RX_MFF_CTRL1 0x0c18 /* 16 bit Receive MAC FIFO Control Reg 1*/ #define RX_MFF_STAT_TO 0x0c1a /* 8 bit Receive MAC Status Timeout */ #define RX_MFF_TIST_TO 0x0c1b /* 8 bit Receive MAC Timestamp Timeout */ #define RX_MFF_CTRL2 0x0c1c /* 8 bit Receive MAC FIFO Control Reg 2*/ -#define RX_MFF_TST1 0x0c1d /* 8 bit Receive MAC FIFO Test Reg 1 */ -#define RX_MFF_TST2 0x0c1e /* 8 bit Receive MAC FIFO Test Reg 2 */ +#define RX_MFF_TST1 0x0c1d /* 8 bit Receive MAC FIFO Test Reg 1 */ +#define RX_MFF_TST2 0x0c1e /* 8 bit Receive MAC FIFO Test Reg 2 */ /* 0x0c1f reserved */ -#define RX_LED_INI 0x0c20 /* 32 bit Receive LED Cnt Init Value */ -#define RX_LED_VAL 0x0c24 /* 32 bit Receive LED Cnt Current Value */ -#define RX_LED_CTRL 0x0c28 /* 8 bit Receive LED Cnt Control Reg */ -#define RX_LED_TST 0x0c29 /* 8 bit Receive LED Cnt Test Register */ +#define RX_LED_INI 0x0c20 /* 32 bit Receive LED Cnt Init Value */ +#define RX_LED_VAL 0x0c24 /* 32 bit Receive LED Cnt Current Value */ +#define RX_LED_CTRL 0x0c28 /* 8 bit Receive LED Cnt Control Reg */ +#define RX_LED_TST 0x0c29 /* 8 bit Receive LED Cnt Test Register */ /* 0x0c2a - 0x0c2f reserved */ #define LNK_SYNC_INI 0x0c30 /* 32 bit Link Sync Cnt Init Value */ #define LNK_SYNC_VAL 0x0c34 /* 32 bit Link Sync Cnt Current Value */ #define LNK_SYNC_CTRL 0x0c38 /* 8 bit Link Sync Cnt Control Register*/ #define LNK_SYNC_TST 0x0c39 /* 8 bit Link Sync Cnt Test Register */ /* 0x0c3a - 0x0c3b reserved */ -#define LNK_LED_REG 0x0c3c /* 8 bit Link LED Register */ +#define LNK_LED_REG 0x0c3c /* 8 bit Link LED Register */ /* 0x0c3d - 0x0c7f reserved */ /* * Bank 26 - 27 */ /* Transmit MAC FIFO and Transmit LED Registers, use MR_ADDR() to address */ -#define TX_MFF_EA 0x0d00 /* 32 bit Transmit MAC FIFO End Address */ -#define TX_MFF_WP 0x0d04 /* 32 bit Transmit MAC FIFO WR Pointer */ -#define TX_MFF_WSP 0x0d08 /* 32 bit Transmit MAC FIFO WR Shadow Pt*/ -#define TX_MFF_RP 0x0d0c /* 32 bit Transmit MAC FIFO RD Pointer */ -#define TX_MFF_PC 0x0d10 /* 32 bit Transmit MAC FIFO Packet Cnt */ -#define TX_MFF_LEV 0x0d14 /* 32 bit Transmit MAC FIFO Level */ +#define TX_MFF_EA 0x0d00 /* 32 bit Transmit MAC FIFO End Address */ +#define TX_MFF_WP 0x0d04 /* 32 bit Transmit MAC FIFO WR Pointer */ +#define TX_MFF_WSP 0x0d08 /* 32 bit Transmit MAC FIFO WR Shadow Pt*/ +#define TX_MFF_RP 0x0d0c /* 32 bit Transmit MAC FIFO RD Pointer */ +#define TX_MFF_PC 0x0d10 /* 32 bit Transmit MAC FIFO Packet Cnt */ +#define TX_MFF_LEV 0x0d14 /* 32 bit Transmit MAC FIFO Level */ #define TX_MFF_CTRL1 0x0d18 /* 16 bit Transmit MAC FIFO Ctrl Reg 1 */ -#define TX_MFF_WAF 0x0d1a /* 8 bit Transmit MAC Wait after flush*/ +#define TX_MFF_WAF 0x0d1a /* 8 bit Transmit MAC Wait after flush*/ /* 0x0c1b reserved */ #define TX_MFF_CTRL2 0x0d1c /* 8 bit Transmit MAC FIFO Ctrl Reg 2 */ -#define TX_MFF_TST1 0x0d1d /* 8 bit Transmit MAC FIFO Test Reg 1 */ -#define TX_MFF_TST2 0x0d1e /* 8 bit Transmit MAC FIFO Test Reg 2 */ +#define TX_MFF_TST1 0x0d1d /* 8 bit Transmit MAC FIFO Test Reg 1 */ +#define TX_MFF_TST2 0x0d1e /* 8 bit Transmit MAC FIFO Test Reg 2 */ /* 0x0d1f reserved */ -#define TX_LED_INI 0x0d20 /* 32 bit Transmit LED Cnt Init Value */ -#define TX_LED_VAL 0x0d24 /* 32 bit Transmit LED Cnt Current Val */ -#define TX_LED_CTRL 0x0d28 /* 8 bit Transmit LED Cnt Control Reg */ -#define TX_LED_TST 0x0d29 /* 8 bit Transmit LED Cnt Test Register*/ +#define TX_LED_INI 0x0d20 /* 32 bit Transmit LED Cnt Init Value */ +#define TX_LED_VAL 0x0d24 /* 32 bit Transmit LED Cnt Current Val */ +#define TX_LED_CTRL 0x0d28 /* 8 bit Transmit LED Cnt Control Reg */ +#define TX_LED_TST 0x0d29 /* 8 bit Transmit LED Cnt Test Register*/ /* 0x0d2a - 0x0d7f reserved */ /* * Bank 28 */ /* Descriptor Poll Timer Registers */ -#define B28_DPT_INI 0x0e00 /* 32 bit Descriptor Poll Timer Init Val*/ -#define B28_DPT_VAL 0x0e04 /* 32 bit Descriptor Poll Timer Curr Val*/ +#define B28_DPT_INI 0x0e00 /* 32 bit Descriptor Poll Timer Init Val*/ +#define B28_DPT_VAL 0x0e04 /* 32 bit Descriptor Poll Timer Curr Val*/ #define B28_DPT_CTRL 0x0e08 /* 8 bit Descriptor Poll Timer Ctrl Reg*/ /* 0x0e09: reserved */ -#define B28_DPT_TST 0x0e0a /* 8 bit Descriptor Poll Timer Test Reg*/ +#define B28_DPT_TST 0x0e0a /* 8 bit Descriptor Poll Timer Test Reg*/ /* 0x0e0b - 0x0e8f: reserved */ /* @@ -739,7 +741,7 @@ */ /* B0_RAP 8 bit Register Address Port */ /* Bit 7: reserved */ -#define RAP_RAP 0x3f /* Bit 6..0: 0 = block 0, .., 6f = block 6f*/ +#define RAP_RAP 0x3f /* Bit 6..0: 0 = block 0, .., 6f = block 6f*/ /* B0_CTST 16 bit Control/Status register */ /* Bit 15..10: reserved */ @@ -749,70 +751,70 @@ #define CS_CL_SW_IRQ (1<<6) /* Bit 6: Clear IRQ SW Request */ #define CS_STOP_DONE (1<<5) /* Bit 5: Stop Master is finished */ #define CS_STOP_MAST (1<<4) /* Bit 4: Command Bit to stop the master*/ -#define CS_MRST_CLR (1<<3) /* Bit 3: Clear Master reset */ -#define CS_MRST_SET (1<<2) /* Bit 2: Set Master reset */ -#define CS_RST_CLR (1<<1) /* Bit 1: Clear Software reset */ -#define CS_RST_SET (1<<0) /* Bit 0: Set Software reset */ +#define CS_MRST_CLR (1<<3) /* Bit 3: Clear Master reset */ +#define CS_MRST_SET (1<<2) /* Bit 2: Set Master reset */ +#define CS_RST_CLR (1<<1) /* Bit 1: Clear Software reset */ +#define CS_RST_SET (1<<0) /* Bit 0: Set Software reset */ /* B0_LED 8 Bit LED register */ /* Bit 7..2: reserved */ -#define LED_STAT_ON (1<<1) /* Bit 1: Status LED on */ +#define LED_STAT_ON (1<<1) /* Bit 1: Status LED on */ #define LED_STAT_OFF (1<<0) /* Bit 0: Status LED off */ /* B0_ISRC 32 bit Interrupt Source Register */ /* B0_IMSK 32 bit Interrupt Mask Register */ /* B0_SP_ISRC 32 bit Special Interrupt Source Reg */ /* B2_IRQM_MSK 32 bit IRQ Moderation Mask */ -#define IS_ALL_MSK 0xbfffffffL /* All Interrupt bits */ -#define IS_HW_ERR (1UL<<31) /* Bit 31: Interrupt HW Error */ - /* Bit 30: reserved */ +#define IS_ALL_MSK 0xbfffffffL /* All Interrupt bits */ +#define IS_HW_ERR (1UL<<31) /* Bit 31: Interrupt HW Error */ + /* Bit 30: reserved */ #define IS_PA_TO_RX1 (1L<<29) /* Bit 29: Packet Arb Timeout Rx1*/ #define IS_PA_TO_RX2 (1L<<28) /* Bit 28: Packet Arb Timeout Rx2*/ #define IS_PA_TO_TX1 (1L<<27) /* Bit 27: Packet Arb Timeout Tx1*/ #define IS_PA_TO_TX2 (1L<<26) /* Bit 26: Packet Arb Timeout Tx2*/ #define IS_I2C_READY (1L<<25) /* Bit 25: IRQ on end of I2C tx */ -#define IS_IRQ_SW (1L<<24) /* Bit 24: SW forced IRQ */ -#define IS_EXT_REG (1L<<23) /* Bit 23: IRQ from external reg */ -#define IS_TIMINT (1L<<22) /* Bit 22: IRQ from Timer */ -#define IS_MAC1 (1L<<21) /* Bit 21: IRQ from MAC 1 */ +#define IS_IRQ_SW (1L<<24) /* Bit 24: SW forced IRQ */ +#define IS_EXT_REG (1L<<23) /* Bit 23: IRQ from external reg */ +#define IS_TIMINT (1L<<22) /* Bit 22: IRQ from Timer */ +#define IS_MAC1 (1L<<21) /* Bit 21: IRQ from MAC 1 */ #define IS_LNK_SYNC_M1 (1L<<20) /* Bit 20: Link Sync Cnt wrap M1 */ -#define IS_MAC2 (1L<<19) /* Bit 19: IRQ from MAC 2 */ +#define IS_MAC2 (1L<<19) /* Bit 19: IRQ from MAC 2 */ #define IS_LNK_SYNC_M2 (1L<<18) /* Bit 18: Link Sync Cnt wrap M2 */ /* Receive Queue 1 */ -#define IS_R1_B (1L<<17) /* Bit 17: Q_R1 End of Buffer */ -#define IS_R1_F (1L<<16) /* Bit 16: Q_R1 End of Frame */ -#define IS_R1_C (1L<<15) /* Bit 15: Q_R1 Encoding Error */ +#define IS_R1_B (1L<<17) /* Bit 17: Q_R1 End of Buffer */ +#define IS_R1_F (1L<<16) /* Bit 16: Q_R1 End of Frame */ +#define IS_R1_C (1L<<15) /* Bit 15: Q_R1 Encoding Error */ /* Receive Queue 2 */ -#define IS_R2_B (1L<<14) /* Bit 14: Q_R2 End of Buffer */ -#define IS_R2_F (1L<<13) /* Bit 13: Q_R2 End of Frame */ -#define IS_R2_C (1L<<12) /* Bit 12: Q_R2 Encoding Error */ +#define IS_R2_B (1L<<14) /* Bit 14: Q_R2 End of Buffer */ +#define IS_R2_F (1L<<13) /* Bit 13: Q_R2 End of Frame */ +#define IS_R2_C (1L<<12) /* Bit 12: Q_R2 Encoding Error */ /* Synchronous Transmit Queue 1 */ -#define IS_XS1_B (1L<<11) /* Bit 11: Q_XS1 End of Buffer */ -#define IS_XS1_F (1L<<10) /* Bit 10: Q_XS1 End of Frame */ -#define IS_XS1_C (1L<<9) /* Bit 9: Q_XS1 Encoding Error */ +#define IS_XS1_B (1L<<11) /* Bit 11: Q_XS1 End of Buffer */ +#define IS_XS1_F (1L<<10) /* Bit 10: Q_XS1 End of Frame */ +#define IS_XS1_C (1L<<9) /* Bit 9: Q_XS1 Encoding Error */ /* Asynchronous Transmit Queue 1 */ -#define IS_XA1_B (1L<<8) /* Bit 8: Q_XA1 End of Buffer */ -#define IS_XA1_F (1L<<7) /* Bit 7: Q_XA1 End of Frame */ -#define IS_XA1_C (1L<<6) /* Bit 6: Q_XA1 Encoding Error */ +#define IS_XA1_B (1L<<8) /* Bit 8: Q_XA1 End of Buffer */ +#define IS_XA1_F (1L<<7) /* Bit 7: Q_XA1 End of Frame */ +#define IS_XA1_C (1L<<6) /* Bit 6: Q_XA1 Encoding Error */ /* Synchronous Transmit Queue 2 */ -#define IS_XS2_B (1L<<5) /* Bit 5: Q_XS2 End of Buffer */ -#define IS_XS2_F (1L<<4) /* Bit 4: Q_XS2 End of Frame */ -#define IS_XS2_C (1L<<3) /* Bit 3: Q_XS2 Encoding Error */ +#define IS_XS2_B (1L<<5) /* Bit 5: Q_XS2 End of Buffer */ +#define IS_XS2_F (1L<<4) /* Bit 4: Q_XS2 End of Frame */ +#define IS_XS2_C (1L<<3) /* Bit 3: Q_XS2 Encoding Error */ /* Asynchronous Transmit Queue 2 */ -#define IS_XA2_B (1L<<2) /* Bit 2: Q_XA2 End of Buffer */ -#define IS_XA2_F (1L<<1) /* Bit 1: Q_XA2 End of Frame */ -#define IS_XA2_C (1L<<0) /* Bit 0: Q_XA2 Encoding Error */ +#define IS_XA2_B (1L<<2) /* Bit 2: Q_XA2 End of Buffer */ +#define IS_XA2_F (1L<<1) /* Bit 1: Q_XA2 End of Frame */ +#define IS_XA2_C (1L<<0) /* Bit 0: Q_XA2 Encoding Error */ /* B0_HWE_ISRC 32 bit HW Error Interrupt Src Reg */ /* B0_HWE_IMSK 32 bit HW Error Interrupt Mask Reg */ /* B2_IRQM_HWE_MSK 32 bit IRQ Moderation HW Error Mask */ -#define IS_ERR_MSK 0x00000fffL /* All Error bits */ - /* Bit 31..12: reserved */ +#define IS_ERR_MSK 0x00000fffL /* All Error bits */ + /* Bit 31..12: reserved */ #define IS_IRQ_MST_ERR (1L<<11) /* Bit 11: IRQ master error */ - /* PERR,RMABORT,RTABORT,DATAPERR */ -#define IS_IRQ_STAT (1L<<10) /* Bit 10: IRQ status execption */ - /* RMABORT, RTABORT, DATAPERR */ + /* PERR,RMABORT,RTABORT,DATAPERR */ +#define IS_IRQ_STAT (1L<<10) /* Bit 10: IRQ status execption */ + /* RMABORT, RTABORT, DATAPERR */ #define IS_NO_STAT_M1 (1L<<9) /* Bit 9: No Rx Status from MAC1*/ #define IS_NO_STAT_M2 (1L<<8) /* Bit 8: No Rx Status from MAC2*/ #define IS_NO_TIST_M1 (1L<<7) /* Bit 7: No Timestamp from MAC1*/ @@ -829,53 +831,53 @@ /* Values of connector and PMD type comply to SysKonnect internal std */ /* B2_MAC_CFG 8 bit MAC Configuration */ - /* Bit 7..2: reserved */ + /* Bit 7..2: reserved */ #define CFG_DIS_M2_CLK (1<<1) /* Bit 1: Disable Clock for 2nd MAC */ -#define CFG_SNG_MAC (1<<0) /* Bit 0: MAC Config: 1=2 MACs / 0=1 MAC*/ +#define CFG_SNG_MAC (1<<0) /* Bit 0: MAC Config: 1=2 MACs / 0=1 MAC*/ /* B2_CHIP_REV 8 bit Queen Chip Revision Number */ #define FIRST_CHIP_REV 0x0a /* Initial Revision Value */ /* B2_FAR 32 bit Flash-Prom Addr Reg/Cnt */ -#define FAR_ADDR 0x1ffffL /* Bit 16..0: FPROM Address mask */ +#define FAR_ADDR 0x1ffffL /* Bit 16..0: FPROM Address mask */ /* B2_LD_CRTL 8 bit EPROM loader control register */ /* Bits are currently reserved */ /* B2_LD_TEST 8 bit EPROM loader test register */ - /* Bit 7..4: reserved */ -#define LD_T_ON (1<<3) /* Bit 3: Loader Testmode on */ -#define LD_T_OFF (1<<2) /* Bit 2: Loader Testmode off */ -#define LD_T_STEP (1<<1) /* Bit 1: Decrement FPROM addr. Counter */ -#define LD_START (1<<0) /* Bit 0: Start loading FPROM */ + /* Bit 7..4: reserved */ +#define LD_T_ON (1<<3) /* Bit 3: Loader Testmode on */ +#define LD_T_OFF (1<<2) /* Bit 2: Loader Testmode off */ +#define LD_T_STEP (1<<1) /* Bit 1: Decrement FPROM addr. Counter */ +#define LD_START (1<<0) /* Bit 0: Start loading FPROM */ /* * Timer Section */ /* B2_TI_CRTL 8 bit Timer control */ /* B2_IRQM_CTRL 8 bit IRQ Moderation Timer Control */ - /* Bit 7..3: reserved */ -#define TIM_START (1<<2) /* Bit 2: Start Timer */ -#define TIM_STOP (1<<1) /* Bit 1: Stop Timer */ -#define TIM_CLR_IRQ (1<<0) /* Bit 0: Clear Timer IRQ, (!IRQM) */ + /* Bit 7..3: reserved */ +#define TIM_START (1<<2) /* Bit 2: Start Timer */ +#define TIM_STOP (1<<1) /* Bit 1: Stop Timer */ +#define TIM_CLR_IRQ (1<<0) /* Bit 0: Clear Timer IRQ, (!IRQM) */ /* B2_TI_TEST 8 Bit Timer Test */ /* B2_IRQM_TEST 8 bit IRQ Moderation Timer Test */ /* B28_DPT_TST 8 bit Descriptor Poll Timer Test Reg */ - /* Bit 7..3: reserved */ -#define TIM_T_ON (1<<2) /* Bit 2: Test mode on */ -#define TIM_T_OFF (1<<1) /* Bit 1: Test mode off */ -#define TIM_T_STEP (1<<0) /* Bit 0: Test step */ + /* Bit 7..3: reserved */ +#define TIM_T_ON (1<<2) /* Bit 2: Test mode on */ +#define TIM_T_OFF (1<<1) /* Bit 1: Test mode off */ +#define TIM_T_STEP (1<<0) /* Bit 0: Test step */ /* B28_DPT_INI 32 bit Descriptor Poll Timer Init Val */ /* B28_DPT_VAL 32 bit Descriptor Poll Timer Curr Val */ - /* Bit 31..24: reserved */ -#define DPT_MSK 0x00ffffffL /* Bit 23.. 0: Desc Poll Timer Bits */ + /* Bit 31..24: reserved */ +#define DPT_MSK 0x00ffffffL /* Bit 23.. 0: Desc Poll Timer Bits */ /* B28_DPT_CTRL 8 bit Descriptor Poll Timer Ctrl Reg */ - /* Bit 7..2: reserved */ -#define DPT_START (1<<1) /* Bit 1: Start Desciptor Poll Timer */ -#define DPT_STOP (1<<0) /* Bit 0: Stop Desciptor Poll Timer */ + /* Bit 7..2: reserved */ +#define DPT_START (1<<1) /* Bit 1: Start Desciptor Poll Timer */ +#define DPT_STOP (1<<0) /* Bit 0: Stop Desciptor Poll Timer */ /* B2_TST_CTRL1 8 bit Test Control Register 1 */ @@ -889,7 +891,7 @@ #define TST_CFG_WRITE_OFF (1<<0) /* Bit 0: Disable Config Reg WR */ /* B2_TST_CTRL2 8 bit Test Control Register 2 */ - /* Bit 7..4: reserved */ + /* Bit 7..4: reserved */ /* force the following error on */ /* the next master read/write */ #define TST_FRC_DPERR_MR64 (1<<3) /* Bit 3: DataPERR RD 64 */ @@ -898,7 +900,7 @@ #define TST_FRC_APERR_2M64 (1<<0) /* Bit 0: AddrPERR on 2. phase */ /* B2_GP_IO 32 bit General Purpose IO Register */ - /* Bit 31..26: reserved */ + /* Bit 31..26: reserved */ #define GP_DIR_9 (1L<<25) /* Bit 25: IO_9 direct, 0=I/1=O */ #define GP_DIR_8 (1L<<24) /* Bit 24: IO_8 direct, 0=I/1=O */ #define GP_DIR_7 (1L<<23) /* Bit 23: IO_7 direct, 0=I/1=O */ @@ -909,7 +911,7 @@ #define GP_DIR_2 (1L<<18) /* Bit 18: IO_2 direct, 0=I/1=O */ #define GP_DIR_1 (1L<<17) /* Bit 17: IO_1 direct, 0=I/1=O */ #define GP_DIR_0 (1L<<16) /* Bit 16: IO_0 direct, 0=I/1=O */ - /* Bit 15..10: reserved */ + /* Bit 15..10: reserved */ #define GP_IO_9 (1L<<9) /* Bit 9: IO_9 pin */ #define GP_IO_8 (1L<<8) /* Bit 8: IO_8 pin */ #define GP_IO_7 (1L<<7) /* Bit 7: IO_7 pin */ @@ -922,31 +924,31 @@ #define GP_IO_0 (1L<<0) /* Bit 0: IO_0 pin */ /* B2_I2C_CTRL 32 bit I2C HW Control Register */ -#define I2C_FLAG (1UL<<31) /* Bit 31: Start read/write if WR*/ +#define I2C_FLAG (1UL<<31) /* Bit 31: Start read/write if WR*/ #define I2C_ADDR (0x7fffL<<16) /* Bit 30..16: Addr to be RD/WR */ -#define I2C_DEV_SEL (0x7fL<<9) /* Bit 15.. 9: I2C Device Select */ - /* Bit 8.. 5: reserved */ +#define I2C_DEV_SEL (0x7fL<<9) /* Bit 15.. 9: I2C Device Select */ + /* Bit 8.. 5: reserved */ #define I2C_BURST_LEN (1L<<4) /* Bit 4: Burst Len, 1/4 bytes */ #define I2C_DEV_SIZE (7L<<1) /* Bit 3.. 1: I2C Device Size */ #define I2C_025K_DEV (0L<<1) /* 0: 256 Bytes or smal. */ -#define I2C_05K_DEV (1L<<1) /* 1: 512 Bytes */ -#define I2C_1K_DEV (2L<<1) /* 2: 1024 Bytes */ -#define I2C_2K_DEV (3L<<1) /* 3: 2048 Bytes */ -#define I2C_4K_DEV (4L<<1) /* 4: 4096 Bytes */ -#define I2C_8K_DEV (5L<<1) /* 5: 8192 Bytes */ -#define I2C_16K_DEV (6L<<1) /* 6: 16384 Bytes */ -#define I2C_32K_DEV (7L<<1) /* 7: 32768 Bytes */ -#define I2C_STOP (1L<<0) /* Bit 0: Interrupt I2C transfer*/ +#define I2C_05K_DEV (1L<<1) /* 1: 512 Bytes */ +#define I2C_1K_DEV (2L<<1) /* 2: 1024 Bytes */ +#define I2C_2K_DEV (3L<<1) /* 3: 2048 Bytes */ +#define I2C_4K_DEV (4L<<1) /* 4: 4096 Bytes */ +#define I2C_8K_DEV (5L<<1) /* 5: 8192 Bytes */ +#define I2C_16K_DEV (6L<<1) /* 6: 16384 Bytes */ +#define I2C_32K_DEV (7L<<1) /* 7: 32768 Bytes */ +#define I2C_STOP (1L<<0) /* Bit 0: Interrupt I2C transfer*/ /* B2_I2C_IRQ 32 bit I2C HW IRQ Register */ - /* Bit 31..1 reserved */ -#define I2C_CLR_IRQ (1<<0) /* Bit 0: Clear I2C IRQ */ + /* Bit 31..1 reserved */ +#define I2C_CLR_IRQ (1<<0) /* Bit 0: Clear I2C IRQ */ /* B2_I2C_SW 32 bit I2C HW SW Port Register */ - /* Bit 7..3: reserved */ + /* Bit 7..3: reserved */ #define I2C_DATA_DIR (1<<2) /* Bit 2: direction of I2C_DATA */ -#define I2C_DATA (1<<1) /* Bit 1: I2C Data Port */ -#define I2C_CLK (1<<0) /* Bit 0: I2C Clock Port */ +#define I2C_DATA (1<<1) /* Bit 1: I2C Data Port */ +#define I2C_CLK (1<<0) /* Bit 0: I2C Clock Port */ /* * I2C Address @@ -955,12 +957,12 @@ /* B2_BSC_CTRL 8 bit Blink Source Counter Control */ - /* Bit 7..2: reserved */ + /* Bit 7..2: reserved */ #define BSC_START (1<<1) /* Bit 1: Start Blink Source Counter */ #define BSC_STOP (1<<0) /* Bit 0: Stop Blink Source Counter */ /* B2_BSC_STAT 8 bit Blink Source Counter Status */ - /* Bit 7..1: reserved */ + /* Bit 7..1: reserved */ #define BSC_SRC (1<<0) /* Bit 0: Blink Source, 0=Off / 1=On */ /* B2_BSC_TST 16 bit Blink Source Counter Test Reg */ @@ -975,30 +977,30 @@ /* RAM Interface Registers */ /* B3_RI_CTRL 16 bit RAM Iface Control Register */ - /* Bit 15..10: reserved */ + /* Bit 15..10: reserved */ #define RI_CLR_RD_PERR (1<<9) /* Bit 9: Clear IRQ RAM Read Parity Err */ #define RI_CLR_WR_PERR (1<<8) /* Bit 8: Clear IRQ RAM Write Parity Err*/ - /* Bit 7..2: reserved */ -#define RI_RST_CLR (1<<1) /* Bit 1: Clear RAM Interface Reset */ -#define RI_RST_SET (1<<0) /* Bit 0: Set RAM Interface Reset */ + /* Bit 7..2: reserved */ +#define RI_RST_CLR (1<<1) /* Bit 1: Clear RAM Interface Reset */ +#define RI_RST_SET (1<<0) /* Bit 0: Set RAM Interface Reset */ /* B3_RI_TEST 8 bit RAM Iface Test Register */ - /* Bit 15..4: reserved */ -#define RI_T_EV (1<<3) /* Bit 3: Timeout Event occurred */ -#define RI_T_ON (1<<2) /* Bit 2: Timeout Timer Test On */ -#define RI_T_OFF (1<<1) /* Bit 1: Timeout Timer Test Off */ -#define RI_T_STEP (1<<0) /* Bit 0: Timeout Timer Step */ + /* Bit 15..4: reserved */ +#define RI_T_EV (1<<3) /* Bit 3: Timeout Event occured */ +#define RI_T_ON (1<<2) /* Bit 2: Timeout Timer Test On */ +#define RI_T_OFF (1<<1) /* Bit 1: Timeout Timer Test Off */ +#define RI_T_STEP (1<<0) /* Bit 0: Timeout Timer Step */ /* MAC Arbiter Registers */ /* B3_MA_TO_CTRL 16 bit MAC Arbiter Timeout Ctrl Reg */ - /* Bit 15..4: reserved */ -#define MA_FOE_ON (1<<3) /* Bit 3: XMAC Fast Output Enable ON */ -#define MA_FOE_OFF (1<<2) /* Bit 2: XMAC Fast Output Enable OFF */ -#define MA_RST_CLR (1<<1) /* Bit 1: Clear MAC Arbiter Reset */ -#define MA_RST_SET (1<<0) /* Bit 0: Set MAC Arbiter Reset */ + /* Bit 15..4: reserved */ +#define MA_FOE_ON (1<<3) /* Bit 3: XMAC Fast Output Enable ON */ +#define MA_FOE_OFF (1<<2) /* Bit 2: XMAC Fast Output Enable OFF */ +#define MA_RST_CLR (1<<1) /* Bit 1: Clear MAC Arbiter Reset */ +#define MA_RST_SET (1<<0) /* Bit 0: Set MAC Arbiter Reset */ /* B3_MA_RC_CTRL 16 bit MAC Arbiter Recovery Ctrl Reg */ - /* Bit 15..8: reserved */ + /* Bit 15..8: reserved */ #define MA_ENA_REC_TX2 (1<<7) /* Bit 7: Enable Recovery Timer TX2 */ #define MA_DIS_REC_TX2 (1<<6) /* Bit 6: Disable Recovery Timer TX2 */ #define MA_ENA_REC_TX1 (1<<5) /* Bit 5: Enable Recovery Timer TX1 */ @@ -1010,7 +1012,7 @@ /* Packet Arbiter Registers */ /* B3_PA_CTRL 16 bit Packet Arbiter Ctrl Register */ - /* Bit 15..14: reserved */ + /* Bit 15..14: reserved */ #define PA_CLR_TO_TX2 (1<<13) /* Bit 13: Clear IRQ Packet Timeout TX2 */ #define PA_CLR_TO_TX1 (1<<12) /* Bit 12: Clear IRQ Packet Timeout TX1 */ #define PA_CLR_TO_RX2 (1<<11) /* Bit 11: Clear IRQ Packet Timeout RX2 */ @@ -1023,30 +1025,30 @@ #define PA_DIS_TO_RX2 (1<<4) /* Bit 4: Disable Timeout Timer RX2 */ #define PA_ENA_TO_RX1 (1<<3) /* Bit 3: Enable Timeout Timer RX1 */ #define PA_DIS_TO_RX1 (1<<2) /* Bit 2: Disable Timeout Timer RX1 */ -#define PA_RST_CLR (1<<1) /* Bit 1: Clear MAC Arbiter Reset */ -#define PA_RST_SET (1<<0) /* Bit 0: Set MAC Arbiter Reset */ +#define PA_RST_CLR (1<<1) /* Bit 1: Clear MAC Arbiter Reset */ +#define PA_RST_SET (1<<0) /* Bit 0: Set MAC Arbiter Reset */ #define PA_ENA_TO_ALL (PA_ENA_TO_RX1 | PA_ENA_TO_RX2 |\ - PA_ENA_TO_TX1 | PA_ENA_TO_TX2) + PA_ENA_TO_TX1 | PA_ENA_TO_TX2) /* Rx/Tx Path related Arbiter Test Registers */ /* B3_MA_TO_TEST 16 bit MAC Arbiter Timeout Test Reg */ /* B3_MA_RC_TEST 16 bit MAC Arbiter Recovery Test Reg */ /* B3_PA_TEST 16 bit Packet Arbiter Test Register */ /* Bit 15, 11, 7, and 3 are reserved in B3_PA_TEST */ -#define TX2_T_EV (1<<15) /* Bit 15: TX2 Timeout/Recv Event occurred*/ +#define TX2_T_EV (1<<15) /* Bit 15: TX2 Timeout/Recv Event occured*/ #define TX2_T_ON (1<<14) /* Bit 14: TX2 Timeout/Recv Timer Test On*/ #define TX2_T_OFF (1<<13) /* Bit 13: TX2 Timeout/Recv Timer Tst Off*/ #define TX2_T_STEP (1<<12) /* Bit 12: TX2 Timeout/Recv Timer Step */ -#define TX1_T_EV (1<<11) /* Bit 11: TX1 Timeout/Recv Event occurred*/ +#define TX1_T_EV (1<<11) /* Bit 11: TX1 Timeout/Recv Event occured*/ #define TX1_T_ON (1<<10) /* Bit 10: TX1 Timeout/Recv Timer Test On*/ #define TX1_T_OFF (1<<9) /* Bit 9: TX1 Timeout/Recv Timer Tst Off*/ #define TX1_T_STEP (1<<8) /* Bit 8: TX1 Timeout/Recv Timer Step */ -#define RX2_T_EV (1<<7) /* Bit 7: RX2 Timeout/Recv Event occurred*/ +#define RX2_T_EV (1<<7) /* Bit 7: RX2 Timeout/Recv Event occured*/ #define RX2_T_ON (1<<6) /* Bit 6: RX2 Timeout/Recv Timer Test On*/ #define RX2_T_OFF (1<<5) /* Bit 5: RX2 Timeout/Recv Timer Tst Off*/ #define RX2_T_STEP (1<<4) /* Bit 4: RX2 Timeout/Recv Timer Step */ -#define RX1_T_EV (1<<3) /* Bit 3: RX1 Timeout/Recv Event occurred*/ +#define RX1_T_EV (1<<3) /* Bit 3: RX1 Timeout/Recv Event occured*/ #define RX1_T_ON (1<<2) /* Bit 2: RX1 Timeout/Recv Timer Test On*/ #define RX1_T_OFF (1<<1) /* Bit 1: RX1 Timeout/Recv Timer Tst Off*/ #define RX1_T_STEP (1<<0) /* Bit 0: RX1 Timeout/Recv Timer Step */ @@ -1057,7 +1059,7 @@ /* TXA_ITI_VAL 32 bit Tx Arb Interval Timer Value */ /* TXA_LIM_INI 32 bit Tx Arb Limit Counter Init Val */ /* TXA_LIM_VAL 32 bit Tx Arb Limit Counter Value */ - /* Bit 31..24: reserved */ + /* Bit 31..24: reserved */ #define TXA_MAX_VAL 0x00ffffffL /* Bit 23.. 0: Max TXA Timer/Cnt Val */ /* TXA_CTRL 8 bit Tx Arbiter Control Register */ @@ -1066,9 +1068,9 @@ #define TXA_ENA_ALLOC (1<<5) /* Bit 5: Enable alloc of free bandwidth*/ #define TXA_DIS_ALLOC (1<<4) /* Bit 4: Disabl alloc of free bandwidth*/ #define TXA_START_RC (1<<3) /* Bit 3: Start sync Rate Control */ -#define TXA_STOP_RC (1<<2) /* Bit 2: Stop sync Rate Control */ -#define TXA_ENA_ARB (1<<1) /* Bit 1: Enable Tx Arbiter */ -#define TXA_DIS_ARB (1<<0) /* Bit 0: Disable Tx Arbiter */ +#define TXA_STOP_RC (1<<2) /* Bit 2: Stop sync Rate Control */ +#define TXA_ENA_ARB (1<<1) /* Bit 1: Enable Tx Arbiter */ +#define TXA_DIS_ARB (1<<0) /* Bit 0: Disable Tx Arbiter */ /* TXA_TEST 8 bit Tx Arbiter Test Register */ /* Bit 7..6: reserved */ @@ -1080,12 +1082,12 @@ #define TXA_LIM_T_STEP (1<<0) /* Bit 0: Tx Arb Limit Timer Step */ /* TXA_STAT 8 bit Tx Arbiter Status Register */ - /* Bit 7..1: reserved */ -#define TXA_PRIO_XS (1<<0) /* Bit 0: sync queue has prio to send */ + /* Bit 7..1: reserved */ +#define TXA_PRIO_XS (1<<0) /* Bit 0: sync queue has prio to send */ /* Q_BC 32 bit Current Byte Counter */ /* Bit 31..16: reserved */ -#define BC_MAX 0xffff /* Bit 15.. 0: Byte counter */ +#define BC_MAX 0xffff /* Bit 15.. 0: Byte counter */ /* BMU Control Status Registers */ /* B0_R1_CSR 32 bit BMU Ctrl/Stat Rx Queue 1 */ @@ -1095,47 +1097,47 @@ /* B0_XA2_CSR 32 bit BMU Ctrl/Stat Sync Tx Queue 2 */ /* B0_XS2_CSR 32 bit BMU Ctrl/Stat Async Tx Queue 2 */ /* Q_CSR 32 bit BMU Control/Status Register */ - /* Bit 31..25: reserved */ -#define CSR_SV_IDLE (1L<<24) /* Bit 24: BMU SM Idle */ - /* Bit 23..22: reserved */ + /* Bit 31..25: reserved */ +#define CSR_SV_IDLE (1L<<24) /* Bit 24: BMU SM Idle */ + /* Bit 23..22: reserved */ #define CSR_DESC_CLR (1L<<21) /* Bit 21: Clear Reset for Descr */ #define CSR_DESC_SET (1L<<20) /* Bit 20: Set Reset for Descr */ #define CSR_FIFO_CLR (1L<<19) /* Bit 19: Clear Reset for FIFO */ #define CSR_FIFO_SET (1L<<18) /* Bit 18: Set Reset for FIFO */ -#define CSR_HPI_RUN (1L<<17) /* Bit 17: Release HPI SM */ -#define CSR_HPI_RST (1L<<16) /* Bit 16: Reset HPI SM to Idle */ -#define CSR_SV_RUN (1L<<15) /* Bit 15: Release Supervisor SM */ -#define CSR_SV_RST (1L<<14) /* Bit 14: Reset Supervisor SM */ +#define CSR_HPI_RUN (1L<<17) /* Bit 17: Release HPI SM */ +#define CSR_HPI_RST (1L<<16) /* Bit 16: Reset HPI SM to Idle */ +#define CSR_SV_RUN (1L<<15) /* Bit 15: Release Supervisor SM */ +#define CSR_SV_RST (1L<<14) /* Bit 14: Reset Supervisor SM */ #define CSR_DREAD_RUN (1L<<13) /* Bit 13: Release Descr Read SM */ #define CSR_DREAD_RST (1L<<12) /* Bit 12: Reset Descr Read SM */ #define CSR_DWRITE_RUN (1L<<11) /* Bit 11: Rel. Descr Write SM */ #define CSR_DWRITE_RST (1L<<10) /* Bit 10: Reset Descr Write SM */ #define CSR_TRANS_RUN (1L<<9) /* Bit 9: Release Transfer SM */ #define CSR_TRANS_RST (1L<<8) /* Bit 8: Reset Transfer SM */ -#define CSR_ENA_POL (1L<<7) /* Bit 7: Enable Descr Polling */ -#define CSR_DIS_POL (1L<<6) /* Bit 6: Disable Descr Polling */ -#define CSR_STOP (1L<<5) /* Bit 5: Stop Rx/Tx Queue */ -#define CSR_START (1L<<4) /* Bit 4: Start Rx/Tx Queue */ +#define CSR_ENA_POL (1L<<7) /* Bit 7: Enable Descr Polling */ +#define CSR_DIS_POL (1L<<6) /* Bit 6: Disable Descr Polling */ +#define CSR_STOP (1L<<5) /* Bit 5: Stop Rx/Tx Queue */ +#define CSR_START (1L<<4) /* Bit 4: Start Rx/Tx Queue */ #define CSR_IRQ_CL_P (1L<<3) /* Bit 3: (Rx) Clear Parity IRQ */ #define CSR_IRQ_CL_B (1L<<2) /* Bit 2: Clear EOB IRQ */ #define CSR_IRQ_CL_F (1L<<1) /* Bit 1: Clear EOF IRQ */ #define CSR_IRQ_CL_C (1L<<0) /* Bit 0: Clear ERR IRQ */ #define CSR_SET_RESET (CSR_DESC_SET|CSR_FIFO_SET|CSR_HPI_RST|CSR_SV_RST|\ - CSR_DREAD_RST|CSR_DWRITE_RST|CSR_TRANS_RST) + CSR_DREAD_RST|CSR_DWRITE_RST|CSR_TRANS_RST) #define CSR_CLR_RESET (CSR_DESC_CLR|CSR_FIFO_CLR|CSR_HPI_RUN|CSR_SV_RUN|\ - CSR_DREAD_RUN|CSR_DWRITE_RUN|CSR_TRANS_RUN) + CSR_DREAD_RUN|CSR_DWRITE_RUN|CSR_TRANS_RUN) /* Q_F 32 bit Flag Register */ /* Bit 28..31: reserved */ -#define F_ALM_FULL (1L<<27) (Rx) /* Bit 27: (Rx) FIFO almost full */ -#define F_EMPTY (1L<<27) (Tx) /* Bit 27: (Tx) FIFO empty flag */ -#define F_FIFO_EOF (1L<<26) /* Bit 26: Fag bit in FIFO */ +#define F_ALM_FULL (1L<<27) (Rx) /* Bit 27: (Rx) FIFO almost full */ +#define F_EMPTY (1L<<27) (Tx) /* Bit 27: (Tx) FIFO empty flag */ +#define F_FIFO_EOF (1L<<26) /* Bit 26: Fag bit in FIFO */ #define F_WM_REACHED (1L<<25) /* Bit 25: Watermark reached */ - /* Bit 24: reserved */ + /* Bit 24: reserved */ #define F_FIFO_LEVEL (0x1fL<<16) /* Bit 23..16: # of Qwords in FIFO */ - /* Bit 15..11: reserved */ + /* Bit 15..11: reserved */ #define F_WATER_MARK 0x0007ffL /* Bit 10.. 0: Watermark */ /* Q_T1 32 bit Test Register 1 */ @@ -1169,9 +1171,9 @@ #define T2_STEP01 (1<<0) /* Bit 0: Inc AC/Dec BC by 1 */ /* Q_T3 32 bit Test Register 3 */ - /* Bit 31..7: reserved */ + /* Bit 31..7: reserved */ #define T3_MUX (7<<4) /* Bit 6.. 4: Mux Position */ - /* Bit 3: reserved */ + /* Bit 3: reserved */ #define T3_VRAM (7<<0) /* Bit 2.. 0: Virtual RAM Buffer Address */ /* RAM Buffer Register Offsets */ @@ -1190,7 +1192,7 @@ #define RB_MSK 0x0007ffff /* Bit 18.. 0: RAM Buffer Pointer Bits */ /* RB_TST2 8 bit RAM Buffer Test Register 2 */ - /* Bit 4..7: reserved */ + /* Bit 4..7: reserved */ #define RB_PC_DEC (1<<3) /* Bit 3: Packet Counter Decrem */ #define RB_PC_T_ON (1<<2) /* Bit 2: Packet Counter Test On */ #define RB_PC_T_OFF (1<<1) /* Bit 1: Packet Counter Tst Off */ @@ -1201,19 +1203,19 @@ #define RB_WP_T_ON (1<<6) /* Bit 6: Write Pointer Test On */ #define RB_WP_T_OFF (1<<5) /* Bit 5: Write Pointer Test Off */ #define RB_WP_INC (1<<4) /* Bit 4: Write Pointer Increm */ - /* Bit 3: reserved */ + /* Bit 3: reserved */ #define RB_RP_T_ON (1<<2) /* Bit 2: Read Pointer Test On */ #define RB_RP_T_OFF (1<<1) /* Bit 1: Read Pointer Test Off */ #define RB_RP_DEC (1<<0) /* Bit 0: Read Pointer Decrement */ /* RB_CTRL 8 bit RAM Buffer Control Register */ - /* Bit 7..6: reserved */ + /* Bit 7..6: reserved */ #define RB_ENA_STFWD (1<<5) /* Bit 5: Enable Store & Forward */ #define RB_DIS_STFWD (1<<4) /* Bit 4: Disab. Store & Forward */ #define RB_ENA_OP_MD (1<<3) /* Bit 3: Enable Operation Mode */ #define RB_DIS_OP_MD (1<<2) /* Bit 2: Disab. Operation Mode */ -#define RB_RST_CLR (1<<1) /* Bit 1: Clr RAM Buf STM Reset */ -#define RB_RST_SET (1<<0) /* Bit 0: Set RAM Buf STM Reset */ +#define RB_RST_CLR (1<<1) /* Bit 1: Clr RAM Buf STM Reset */ +#define RB_RST_SET (1<<0) /* Bit 0: Set RAM Buf STM Reset */ /* Receive and Transmit MAC FIFO Registers, use MR_ADDR() to address */ @@ -1228,11 +1230,11 @@ /* TX_MFF_RP 32 bit Transmit MAC FIFO Read Pointer */ /* TX_MFF_PC 32 bit Transmit MAC FIFO Packet Cnt */ /* TX_MFF_LEV 32 bit Transmit MAC FIFO Level */ - /* Bit 31..6: reserved */ + /* Bit 31..6: reserved */ #define MFF_MSK 0x007fL /* Bit 5..0: MAC FIFO Address/Pointer Bits */ /* RX_MFF_CTRL1 16 bit Receive MAC FIFO Control Reg 1 */ - /* Bit 15..14: reserved */ + /* Bit 15..14: reserved */ #define MFF_ENA_RDY_PAT (1<<13) /* Bit 13: Enable Ready Patch */ #define MFF_DIS_RDY_PAT (1<<12) /* Bit 12: Disable Ready Patch */ #define MFF_ENA_TIM_PAT (1<<11) /* Bit 11: Enable Timing Patch */ @@ -1252,15 +1254,15 @@ /* TX_MFF_CTRL1 16 bit Transmit MAC FIFO Control Reg 1 */ #define MFF_CLR_PERR (1<<15) /* Bit 15: Clear Parity Error IRQ*/ - /* Bit 14: reserved */ + /* Bit 14: reserved */ #define MFF_ENA_PKT_REC (1<<13) /* Bit 13: Enable Packet Recovery*/ #define MFF_DIS_PKT_REC (1<<12) /* Bit 12: Disable Packet Recov. */ /* MFF_ENA_TIM_PAT (see RX_MFF_CTRL1)Bit 11: Enable Timing Patch */ /* MFF_DIS_TIM_PAT (see RX_MFF_CTRL1)Bit 10: Disable Timing Patch */ /* MFF_ENA_ALM_FUL (see RX_MFF_CTRL1)Bit 9: Enable AlmostFull Sign*/ /* MFF_DIS_ALM_FUL (see RX_MFF_CTRL1)Bit 8: Disab. AlmostFull Sign*/ -#define MFF_ENA_W4E (1<<7) /* Bit 7: Enable Wait for Empty */ -#define MFF_DIS_W4E (1<<6) /* Bit 6: Disab. Wait for Empty */ +#define MFF_ENA_W4E (1<<7) /* Bit 7: Enable Wait for Empty */ +#define MFF_DIS_W4E (1<<6) /* Bit 6: Disab. Wait for Empty */ /* MFF_ENA_FLUSH (see RX_MFF_CTRL1)Bit 5: Enable Frame Flushing */ /* MFF_DIS_FLUSH (see RX_MFF_CTRL1)Bit 4: Disab. Frame Flushing */ #define MFF_ENA_LOOPB (1<<3) /* Bit 3: Enable Loopback */ @@ -1272,61 +1274,61 @@ /* RX_MFF_TST2 8 bit Receive MAC FIFO Test Register 2 */ /* TX_MFF_TST2 8 bit Transmit MAC FIFO Test Register 2 */ - /* Bit 7: reserved */ + /* Bit 7: reserved */ #define MFF_WSP_T_ON (1<<6) /* Bit 6: (Tx) Write Shadow Pt TestOn */ #define MFF_WSP_T_OFF (1<<5) /* Bit 5: (Tx) Write Shadow Pt TstOff */ -#define MFF_WSP_INC (1<<4) /* Bit 4: (Tx) Write Shadow Pt Increm */ -#define MFF_PC_DEC (1<<3) /* Bit 3: Packet Counter Decrem */ -#define MFF_PC_T_ON (1<<2) /* Bit 2: Packet Counter Test On */ +#define MFF_WSP_INC (1<<4) /* Bit 4: (Tx) Write Shadow Pt Increm */ +#define MFF_PC_DEC (1<<3) /* Bit 3: Packet Counter Decrem */ +#define MFF_PC_T_ON (1<<2) /* Bit 2: Packet Counter Test On */ #define MFF_PC_T_OFF (1<<1) /* Bit 1: Packet Counter Tst Off */ -#define MFF_PC_INC (1<<0) /* Bit 0: Packet Counter Increm */ +#define MFF_PC_INC (1<<0) /* Bit 0: Packet Counter Increm */ /* RX_MFF_TST1 8 bit Receive MAC FIFO Test Register 1 */ /* TX_MFF_TST1 8 bit Transmit MAC FIFO Test Register 1 */ - /* Bit 7: reserved */ -#define MFF_WP_T_ON (1<<6) /* Bit 6: Write Pointer Test On */ + /* Bit 7: reserved */ +#define MFF_WP_T_ON (1<<6) /* Bit 6: Write Pointer Test On */ #define MFF_WP_T_OFF (1<<5) /* Bit 5: Write Pointer Test Off */ -#define MFF_WP_INC (1<<4) /* Bit 4: Write Pointer Increm */ - /* Bit 3: reserved */ -#define MFF_RP_T_ON (1<<2) /* Bit 2: Read Pointer Test On */ +#define MFF_WP_INC (1<<4) /* Bit 4: Write Pointer Increm */ + /* Bit 3: reserved */ +#define MFF_RP_T_ON (1<<2) /* Bit 2: Read Pointer Test On */ #define MFF_RP_T_OFF (1<<1) /* Bit 1: Read Pointer Test Off */ -#define MFF_RP_DEC (1<<0) /* Bit 0: Read Pointer Decrement */ +#define MFF_RP_DEC (1<<0) /* Bit 0: Read Pointer Decrement */ /* RX_MFF_CTRL2 8 bit Receive MAC FIFO Control Reg 2 */ /* TX_MFF_CTRL2 8 bit Transmit MAC FIFO Control Reg 2 */ - /* Bit 7..4: reserved */ + /* Bit 7..4: reserved */ #define MFF_ENA_OP_MD (1<<3) /* Bit 3: Enable Operation Mode */ #define MFF_DIS_OP_MD (1<<2) /* Bit 2: Disab. Operation Mode */ -#define MFF_RST_CLR (1<<1) /* Bit 1: Clear MAC FIFO Reset */ -#define MFF_RST_SET (1<<0) /* Bit 0: Set MAC FIFO Reset */ +#define MFF_RST_CLR (1<<1) /* Bit 1: Clear MAC FIFO Reset */ +#define MFF_RST_SET (1<<0) /* Bit 0: Set MAC FIFO Reset */ /* Receive, Transmit, and Link LED Counter Registers */ -/* RX_LED_CTRL 8 bit Receive LED Cnt Control Reg */ -/* TX_LED_CTRL 8 bit Transmit LED Cnt Control Reg */ -/* LNK_SYNC_CTRL 8 bit Link Sync Cnt Control Register */ - /* Bit 7..3: reserved */ +/* RX_LED_CTRL 8 bit Receive LED Cnt Control Reg */ +/* TX_LED_CTRL 8 bit Transmit LED Cnt Control Reg */ +/* LNK_SYNC_CTRL 8 bit Link Sync Cnt Control Register */ + /* Bit 7..3: reserved */ #define LED_START (1<<2) /* Bit 2: Start Timer */ #define LED_STOP (1<<1) /* Bit 1: Stop Timer */ #define LED_STATE (1<<0) /* Bit 0:(Rx/Tx)LED State, 1=LED on */ #define LED_CLR_IRQ (1<<0) /* Bit 0:(Lnk) Clear Link IRQ */ -/* RX_LED_TST 8 bit Receive LED Cnt Test Register */ -/* TX_LED_TST 8 bit Transmit LED Cnt Test Register */ -/* LNK_SYNC_TST 8 bit Link Sync Cnt Test Register */ - /* Bit 7..3: reserved */ +/* RX_LED_TST 8 bit Receive LED Cnt Test Register */ +/* TX_LED_TST 8 bit Transmit LED Cnt Test Register */ +/* LNK_SYNC_TST 8 bit Link Sync Cnt Test Register */ + /* Bit 7..3: reserved */ #define LED_T_ON (1<<2) /* Bit 2: LED Counter Testmode On */ #define LED_T_OFF (1<<1) /* Bit 1: LED Counter Testmode Off */ #define LED_T_STEP (1<<0) /* Bit 0: LED Counter Step */ /* LNK_LED_REG 8 bit Link LED Register */ - /* Bit 7..6: reserved */ -#define LED_BLK_ON (1<<5) /* Bit 5: Link LED Blinking On */ -#define LED_BLK_OFF (1<<4) /* Bit 4: Link LED Blinking Off */ -#define LED_SYNC_ON (1<<3) /* Bit 3: Use Sync Wire to switch LED */ + /* Bit 7..6: reserved */ +#define LED_BLK_ON (1<<5) /* Bit 5: Link LED Blinking On */ +#define LED_BLK_OFF (1<<4) /* Bit 4: Link LED Blinking Off */ +#define LED_SYNC_ON (1<<3) /* Bit 3: Use Sync Wire to switch LED */ #define LED_SYNC_OFF (1<<2) /* Bit 2: Disable Sync Wire Input */ -#define LED_ON (1<<1) /* Bit 1: switch LED on */ -#define LED_OFF (1<<0) /* Bit 0: switch LED off */ +#define LED_ON (1<<1) /* Bit 1: switch LED on */ +#define LED_OFF (1<<0) /* Bit 0: switch LED off */ /* Receive and Transmit Descriptors ******************************************/ @@ -1334,42 +1336,42 @@ /* Transmit Descriptor struct */ typedef struct s_HwTxd { SK_U32 volatile TxCtrl; /* Transmit Buffer Control Field */ - SK_U32 TxNext ; /* Physical Address Pointer to the next TxD */ - SK_U32 TxAdrLo ; /* Physical Tx Buffer Address lower dword */ - SK_U32 TxAdrHi ; /* Physical Tx Buffer Address upper dword */ - SK_U32 TxStat ; /* Transmit Frame Status Word */ + SK_U32 TxNext; /* Physical Address Pointer to the next TxD */ + SK_U32 TxAdrLo; /* Physical Tx Buffer Address lower dword */ + SK_U32 TxAdrHi; /* Physical Tx Buffer Address upper dword */ + SK_U32 TxStat; /* Transmit Frame Status Word */ #ifndef SK_USE_REV_DESC - SK_U16 TxTcpOffs ; /* TCP Checksum Calculation Start Value */ - SK_U16 TxRes1 ; /* 16 bit reserved field */ - SK_U16 TxTcpWp ; /* TCP Checksum Write Position */ - SK_U16 TxTcpSp ; /* TCP Checksum Calculation Start Position */ + SK_U16 TxTcpOffs; /* TCP Checksum Calculation Start Value */ + SK_U16 TxRes1; /* 16 bit reserved field */ + SK_U16 TxTcpWp; /* TCP Checksum Write Position */ + SK_U16 TxTcpSp; /* TCP Checksum Calculation Start Position */ #else /* SK_USE_REV_DESC */ - SK_U16 TxRes1 ; /* 16 bit reserved field */ - SK_U16 TxTcpOffs ; /* TCP Checksum Calculation Start Value */ - SK_U16 TxTcpSp ; /* TCP Checksum Calculation Start Position */ - SK_U16 TxTcpWp ; /* TCP Checksum Write Position */ + SK_U16 TxRes1; /* 16 bit reserved field */ + SK_U16 TxTcpOffs; /* TCP Checksum Calculation Start Value */ + SK_U16 TxTcpSp; /* TCP Checksum Calculation Start Position */ + SK_U16 TxTcpWp; /* TCP Checksum Write Position */ #endif /* SK_USE_REV_DESC */ - SK_U32 TxRes2; /* 32 bit reserved field */ + SK_U32 TxRes2; /* 32 bit reserved field */ } SK_HWTXD; /* Receive Descriptor struct */ typedef struct s_HwRxd { SK_U32 volatile RxCtrl; /* Receive Buffer Control Field */ - SK_U32 RxNext ; /* Physical Address Pointer to the next TxD */ - SK_U32 RxAdrLo ; /* Physical Receive Buffer Address lower dword*/ - SK_U32 RxAdrHi ; /* Physical Receive Buffer Address upper dword*/ - SK_U32 RxStat ; /* Receive Frame Status Word */ - SK_U32 RxTiSt ; /* Receive Timestamp provided by the XMAC */ + SK_U32 RxNext; /* Physical Address Pointer to the next TxD */ + SK_U32 RxAdrLo; /* Physical Receive Buffer Address lower dword*/ + SK_U32 RxAdrHi; /* Physical Receive Buffer Address upper dword*/ + SK_U32 RxStat; /* Receive Frame Status Word */ + SK_U32 RxTiSt; /* Receive Timestamp provided by the XMAC */ #ifndef SK_USE_REV_DESC - SK_U16 RxTcpSum1 ; /* TCP Checksum 1 */ - SK_U16 RxTcpSum2 ; /* TCP Checksum 2 */ - SK_U16 RxTcpSp1 ; /* TCP Checksum Calculation Start Position 1 */ - SK_U16 RxTcpSp2 ; /* TCP Checksum Calculation Start Position 2 */ + SK_U16 RxTcpSum1; /* TCP Checksum 1 */ + SK_U16 RxTcpSum2; /* TCP Checksum 2 */ + SK_U16 RxTcpSp1; /* TCP Checksum Calculation Start Position 1 */ + SK_U16 RxTcpSp2; /* TCP Checksum Calculation Start Position 2 */ #else /* SK_USE_REV_DESC */ - SK_U16 RxTcpSum2 ; /* TCP Checksum 2 */ - SK_U16 RxTcpSum1 ; /* TCP Checksum 1 */ - SK_U16 RxTcpSp2 ; /* TCP Checksum Calculation Start Position 2 */ - SK_U16 RxTcpSp1 ; /* TCP Checksum Calculation Start Position 1 */ + SK_U16 RxTcpSum2; /* TCP Checksum 2 */ + SK_U16 RxTcpSum1; /* TCP Checksum 1 */ + SK_U16 RxTcpSp2; /* TCP Checksum Calculation Start Position 2 */ + SK_U16 RxTcpSp1; /* TCP Checksum Calculation Start Position 1 */ #endif /* SK_USE_REV_DESC */ } SK_HWRXD; @@ -1387,23 +1389,23 @@ /* Descriptor Bit Definition */ /* TxCtrl Transmit Buffer Control Field */ /* RxCtrl Receive Buffer Control Field */ -#define BMU_OWN (1UL<<31) /* Bit 31: OWN bit: 0=host/1=BMU */ -#define BMU_STF (1L<<30) /* Bit 30: Start of Frame ? */ -#define BMU_EOF (1L<<29) /* Bit 29: End of Frame ? */ -#define BMU_IRQ_EOB (1L<<28) /* Bit 28: Req "End of Buff" IRQ */ -#define BMU_IRQ_EOF (1L<<27) /* Bit 27: Req "End of Frame" IRQ*/ +#define BMU_OWN (1UL<<31) /* Bit 31: OWN bit: 0=host/1=BMU */ +#define BMU_STF (1L<<30) /* Bit 30: Start of Frame ? */ +#define BMU_EOF (1L<<29) /* Bit 29: End of Frame ? */ +#define BMU_IRQ_EOB (1L<<28) /* Bit 28: Req "End of Buff" IRQ */ +#define BMU_IRQ_EOF (1L<<27) /* Bit 27: Req "End of Frame" IRQ*/ /* TxCtrl specific bits */ -#define BMU_STFWD (1L<<26) /* Bit 26: (Tx) Store&Forward Frame */ -#define BMU_NO_FCS (1L<<25) /* Bit 25: (Tx) disable XMAC FCS gener*/ -#define BMU_SW (1L<<24) /* Bit 24: (Tx) 1 bit res. for SW use */ +#define BMU_STFWD (1L<<26) /* Bit 26: (Tx) Store&Forward Frame */ +#define BMU_NO_FCS (1L<<25) /* Bit 25: (Tx) disable XMAC FCS gener*/ +#define BMU_SW (1L<<24) /* Bit 24: (Tx) 1 bit res. for SW use */ /* RxCtrl specific bits */ -#define BMU_DEV_0 (1L<<26) /* Bit 26: (Rx) transfer data to Dev0 */ +#define BMU_DEV_0 (1L<<26) /* Bit 26: (Rx) transfer data to Dev0 */ #define BMU_STAT_VAL (1L<<25) /* Bit 25: (Rx) RxStat Valid */ #define BMU_TIST_VAL (1L<<24) /* Bit 24: (Rx) RxTiSt Valid */ - /* Bit 23..16: BMU Check Opcodes */ -#define BMU_CHECK 0x00550000L /* Default BMU check */ + /* Bit 23..16: BMU Check Opcodes */ +#define BMU_CHECK 0x00550000L /* Default BMU check */ #define BMU_TCP_CHECK 0x00560000L /* Descr with TCP ext */ -#define BMU_BBC 0x0000FFFFL /* Bit 15..0: Buffer Byte Counter */ +#define BMU_BBC 0x0000FFFFL /* Bit 15..0: Buffer Byte Counter */ /* TxStat Transmit Frame Status Word */ /* RxStat Receive Frame Status Word */ @@ -1420,8 +1422,8 @@ * FlashProm specification */ #define MAX_PAGES 0x20000L /* Every byte has a single page */ -#define MAX_FADDR 1 /* 1 byte per page */ -#define SKFDDI_PSZ 8 /* address PROM size */ +#define MAX_FADDR 1 /* 1 byte per page */ +#define SKFDDI_PSZ 8 /* address PROM size */ /* macros ********************************************************************/ @@ -1507,7 +1509,7 @@ * (p)Val Value or pointer to the value which should be read or * written. * - * usage: XM_OUT16(IoC, MAC_1, XM_MMU_CMD, Value) ; + * usage: XM_OUT16(IoC, MAC_1, XM_MMU_CMD, Value); */ #ifdef SK_LITTLE_ENDIAN @@ -1520,19 +1522,19 @@ #define XMA(Mac,Reg) (((0x1000 << (Mac)) + 0x1000) | ((Reg) << 1)) -#define XM_IN16(IoC,Mac,Reg,pVal) SK_IN16((IoC),XMA((Mac),(Reg)),(pVal)) -#define XM_OUT16(IoC,Mac,Reg,Val) SK_OUT16((IoC),XMA((Mac),(Reg)),(Val)) +#define XM_IN16(IoC,Mac,Reg,pVal) SK_IN16((IoC), XMA((Mac), (Reg)), (pVal)) +#define XM_OUT16(IoC,Mac,Reg,Val) SK_OUT16((IoC), XMA((Mac), (Reg)), (Val)) -#define XM_IN32(IoC,Mac,Reg,pVal) { \ - SK_IN16((IoC),XMA((Mac),(Reg)), \ +#define XM_IN32(IoC,Mac,Reg,pVal) { \ + SK_IN16((IoC), XMA((Mac), (Reg)), \ (SK_U16 *)&((SK_U16 *)(pVal))[XM_WORD_LO]); \ - SK_IN16((IoC),XMA((Mac),(Reg+2)), \ + SK_IN16((IoC), XMA((Mac), (Reg+2)), \ (SK_U16 *)&((SK_U16 *)(pVal))[XM_WORD_HI]); \ } -#define XM_OUT32(IoC,Mac,Reg,Val) { \ - SK_OUT16((IoC),XMA((Mac),(Reg)), (SK_U16)((Val) & 0x0000ffffL));\ - SK_OUT16((IoC),XMA((Mac),(Reg+2)),(SK_U16)(((Val)>>16) & 0x0000ffffL));\ +#define XM_OUT32(IoC,Mac,Reg,Val) { \ + SK_OUT16((IoC), XMA((Mac), (Reg)), (SK_U16)((Val) & 0x0000ffffL)); \ + SK_OUT16((IoC), XMA((Mac), (Reg+2)),(SK_U16)(((Val)>>16) & 0x0000ffffL)); \ } /* @@ -1540,67 +1542,67 @@ */ #define XM_INADDR(IoC, Mac, Reg, pVal) { \ - SK_U16 Word; \ - SK_U8 *pByte; \ + SK_U16 Word; \ + SK_U8 *pByte; \ pByte = (SK_U8 *)&((SK_U8 *)(pVal))[0]; \ SK_IN16((IoC), XMA((Mac), (Reg)), &Word); \ - pByte[0] = (SK_U8) (Word & 0x00ff); \ - pByte[1] = (SK_U8) ((Word >> 8) & 0x00ff); \ + pByte[0] = (SK_U8)(Word & 0x00ff); \ + pByte[1] = (SK_U8)((Word >> 8) & 0x00ff); \ SK_IN16((IoC), XMA((Mac), (Reg+2)), &Word); \ - pByte[2] = (SK_U8) (Word & 0x00ff); \ - pByte[3] = (SK_U8) ((Word >> 8) & 0x00ff); \ + pByte[2] = (SK_U8)(Word & 0x00ff); \ + pByte[3] = (SK_U8)((Word >> 8) & 0x00ff); \ SK_IN16((IoC), XMA((Mac), (Reg+4)), &Word); \ - pByte[4] = (SK_U8) (Word & 0x00ff); \ - pByte[5] = (SK_U8) ((Word >> 8) & 0x00ff); \ + pByte[4] = (SK_U8)(Word & 0x00ff); \ + pByte[5] = (SK_U8)((Word >> 8) & 0x00ff); \ } #define XM_OUTADDR(IoC, Mac, Reg, pVal) { \ - SK_U8 *pByte; \ + SK_U8 *pByte; \ pByte = (SK_U8 *)&((SK_U8 *)(pVal))[0]; \ SK_OUT16((IoC), XMA((Mac), (Reg)), (SK_U16) \ - (((SK_U16)(pByte[0]) & 0x00ff)| \ - (((SK_U16)(pByte[1]) << 8) & 0xff00))); \ - SK_OUT16((IoC), XMA((Mac), (Reg+2)), (SK_U16) \ - (((SK_U16)(pByte[2]) & 0x00ff)| \ - (((SK_U16)(pByte[3]) << 8) & 0xff00))); \ - SK_OUT16((IoC), XMA((Mac), (Reg+4)), (SK_U16) \ - (((SK_U16)(pByte[4]) & 0x00ff)| \ - (((SK_U16)(pByte[5]) << 8) & 0xff00))); \ + (((SK_U16)(pByte[0]) & 0x00ff) | \ + (((SK_U16)(pByte[1]) << 8) & 0xff00))); \ + SK_OUT16((IoC), XMA((Mac), (Reg+2)), (SK_U16) \ + (((SK_U16)(pByte[2]) & 0x00ff) | \ + (((SK_U16)(pByte[3]) << 8) & 0xff00))); \ + SK_OUT16((IoC), XMA((Mac), (Reg+4)), (SK_U16) \ + (((SK_U16)(pByte[4]) & 0x00ff) | \ + (((SK_U16)(pByte[5]) << 8) & 0xff00))); \ } #define XM_INHASH(IoC, Mac, Reg, pVal) { \ - SK_U16 Word; \ - SK_U8 *pByte; \ + SK_U16 Word; \ + SK_U8 *pByte; \ pByte = (SK_U8 *)&((SK_U8 *)(pVal))[0]; \ SK_IN16((IoC), XMA((Mac), (Reg)), &Word); \ - pByte[0] = (SK_U8) (Word & 0x00ff); \ - pByte[1] = (SK_U8) ((Word >> 8) & 0x00ff); \ + pByte[0] = (SK_U8)(Word & 0x00ff); \ + pByte[1] = (SK_U8)((Word >> 8) & 0x00ff); \ SK_IN16((IoC), XMA((Mac), (Reg+2)), &Word); \ - pByte[2] = (SK_U8) (Word & 0x00ff); \ - pByte[3] = (SK_U8) ((Word >> 8) & 0x00ff); \ + pByte[2] = (SK_U8)(Word & 0x00ff); \ + pByte[3] = (SK_U8)((Word >> 8) & 0x00ff); \ SK_IN16((IoC), XMA((Mac), (Reg+4)), &Word); \ - pByte[4] = (SK_U8) (Word & 0x00ff); \ - pByte[5] = (SK_U8) ((Word >> 8) & 0x00ff); \ + pByte[4] = (SK_U8)(Word & 0x00ff); \ + pByte[5] = (SK_U8)((Word >> 8) & 0x00ff); \ SK_IN16((IoC), XMA((Mac), (Reg+6)), &Word); \ - pByte[6] = (SK_U8) (Word & 0x00ff); \ - pByte[7] = (SK_U8) ((Word >> 8) & 0x00ff); \ + pByte[6] = (SK_U8)(Word & 0x00ff); \ + pByte[7] = (SK_U8)((Word >> 8) & 0x00ff); \ } #define XM_OUTHASH(IoC, Mac, Reg, pVal) { \ - SK_U8 *pByte; \ + SK_U8 *pByte; \ pByte = (SK_U8 *)&((SK_U8 *)(pVal))[0]; \ SK_OUT16((IoC), XMA((Mac), (Reg)), (SK_U16) \ - (((SK_U16)(pByte[0]) & 0x00ff)| \ - (((SK_U16)(pByte[1]) << 8) & 0xff00))); \ - SK_OUT16((IoC), XMA((Mac), (Reg+2)), (SK_U16) \ - (((SK_U16)(pByte[2]) & 0x00ff)| \ - (((SK_U16)(pByte[3]) << 8) & 0xff00))); \ - SK_OUT16((IoC), XMA((Mac), (Reg+4)), (SK_U16) \ - (((SK_U16)(pByte[4]) & 0x00ff)| \ - (((SK_U16)(pByte[5]) << 8) & 0xff00))); \ - SK_OUT16((IoC), XMA((Mac), (Reg+6)), (SK_U16) \ - (((SK_U16)(pByte[6]) & 0x00ff)| \ - (((SK_U16)(pByte[7]) << 8) & 0xff00))); \ + (((SK_U16)(pByte[0]) & 0x00ff)| \ + (((SK_U16)(pByte[1]) << 8) & 0xff00))); \ + SK_OUT16((IoC), XMA((Mac), (Reg+2)), (SK_U16) \ + (((SK_U16)(pByte[2]) & 0x00ff)| \ + (((SK_U16)(pByte[3]) << 8) & 0xff00))); \ + SK_OUT16((IoC), XMA((Mac), (Reg+4)), (SK_U16) \ + (((SK_U16)(pByte[4]) & 0x00ff)| \ + (((SK_U16)(pByte[5]) << 8) & 0xff00))); \ + SK_OUT16((IoC), XMA((Mac), (Reg+6)), (SK_U16) \ + (((SK_U16)(pByte[6]) & 0x00ff)| \ + (((SK_U16)(pByte[7]) << 8) & 0xff00))); \ } /* @@ -1637,56 +1639,56 @@ * comes back. This is checked in DEBUG mode. */ #ifndef DEBUG -#define PHY_READ(IoC, pPort, Mac, PhyReg, pVal) { \ - SK_U16 Mmu; \ - \ - XM_OUT16((IoC),(Mac), XM_PHY_ADDR, (PhyReg)|(pPort)->PhyAddr); \ - XM_IN16((IoC), (Mac), XM_PHY_DATA, (pVal)); \ - if ((pPort)->PhyType != SK_PHY_XMAC) { \ - do { \ - XM_IN16((IoC), (Mac), XM_MMU_CMD, &Mmu); \ - } while ((Mmu & XM_MMU_PHY_RDY) == 0); \ - XM_IN16((IoC), (Mac), XM_PHY_DATA, (pVal)); \ - } \ +#define PHY_READ(IoC, pPort, Mac, PhyReg, pVal) { \ + SK_U16 Mmu; \ + \ + XM_OUT16((IoC), (Mac), XM_PHY_ADDR, (PhyReg) | (pPort)->PhyAddr); \ + XM_IN16((IoC), (Mac), XM_PHY_DATA, (pVal)); \ + if ((pPort)->PhyType != SK_PHY_XMAC) { \ + do { \ + XM_IN16((IoC), (Mac), XM_MMU_CMD, &Mmu); \ + } while ((Mmu & XM_MMU_PHY_RDY) == 0); \ + XM_IN16((IoC), (Mac), XM_PHY_DATA, (pVal)); \ + } \ } #else -#define PHY_READ(IoC, pPort, Mac, PhyReg, pVal) { \ - SK_U16 Mmu; \ - int __i = 0; \ - \ - XM_OUT16((IoC),(Mac), XM_PHY_ADDR, (PhyReg)|(pPort)->PhyAddr); \ - XM_IN16((IoC), (Mac), XM_PHY_DATA, (pVal)); \ - if ((pPort)->PhyType != SK_PHY_XMAC) { \ - do { \ - XM_IN16((IoC), (Mac), XM_MMU_CMD, &Mmu); \ - __i++; \ - if (__i > 10000) { \ - SK_DBG_PRINTF("*****************************\n"); \ - SK_DBG_PRINTF("PHY_READ on uninitialized PHY\n"); \ - SK_DBG_PRINTF("*****************************\n"); \ - break; \ - } \ - } while ((Mmu & XM_MMU_PHY_RDY) == 0); \ - XM_IN16((IoC), (Mac), XM_PHY_DATA, (pVal)); \ - } \ +#define PHY_READ(IoC, pPort, Mac, PhyReg, pVal) { \ + SK_U16 Mmu; \ + int __i = 0; \ + \ + XM_OUT16((IoC), (Mac), XM_PHY_ADDR, (PhyReg) | (pPort)->PhyAddr); \ + XM_IN16((IoC), (Mac), XM_PHY_DATA, (pVal)); \ + if ((pPort)->PhyType != SK_PHY_XMAC) { \ + do { \ + XM_IN16((IoC), (Mac), XM_MMU_CMD, &Mmu); \ + __i++; \ + if (__i > 100000) { \ + SK_DBG_PRINTF("*****************************\n"); \ + SK_DBG_PRINTF("PHY_READ on uninitialized PHY\n"); \ + SK_DBG_PRINTF("*****************************\n"); \ + break; \ + } \ + } while ((Mmu & XM_MMU_PHY_RDY) == 0); \ + XM_IN16((IoC), (Mac), XM_PHY_DATA, (pVal)); \ + } \ } #endif -#define PHY_WRITE(IoC, pPort, Mac, PhyReg, Val) { \ - SK_U16 Mmu; \ - \ - if ((pPort)->PhyType != SK_PHY_XMAC) { \ - do { \ - XM_IN16((IoC), (Mac), XM_MMU_CMD, &Mmu); \ - } while ((Mmu & XM_MMU_PHY_BUSY) != 0); \ - } \ - XM_OUT16((IoC), (Mac), XM_PHY_ADDR, (PhyReg)|(pPort)->PhyAddr); \ - XM_OUT16((IoC), (Mac), XM_PHY_DATA, (Val)); \ - if ((pPort)->PhyType != SK_PHY_XMAC) { \ - do { \ - XM_IN16((IoC), (Mac), XM_MMU_CMD, &Mmu); \ - } while ((Mmu & XM_MMU_PHY_BUSY) != 0); \ - } \ +#define PHY_WRITE(IoC, pPort, Mac, PhyReg, Val) { \ + SK_U16 Mmu; \ + \ + if ((pPort)->PhyType != SK_PHY_XMAC) { \ + do { \ + XM_IN16((IoC), (Mac), XM_MMU_CMD, &Mmu); \ + } while ((Mmu & XM_MMU_PHY_BUSY) != 0); \ + } \ + XM_OUT16((IoC), (Mac), XM_PHY_ADDR, (PhyReg) | (pPort)->PhyAddr); \ + XM_OUT16((IoC), (Mac), XM_PHY_DATA, (Val)); \ + if ((pPort)->PhyType != SK_PHY_XMAC) { \ + do { \ + XM_IN16((IoC), (Mac), XM_MMU_CMD, &Mmu); \ + } while ((Mmu & XM_MMU_PHY_BUSY) != 0); \ + } \ } /* @@ -1731,7 +1733,7 @@ * Mode Mode to set for this LED */ #define SK_HWAC_LINK_LED(pAC, IoC, Port, Mode) \ -SK_OUT8(IoC, MR_ADDR(Port,LNK_LED_REG), Mode); + SK_OUT8(IoC, MR_ADDR(Port,LNK_LED_REG), Mode); /* typedefs *******************************************************************/ diff -u --recursive --new-file v2.4.6/linux/drivers/net/sk98lin/h/skgehwt.h linux/drivers/net/sk98lin/h/skgehwt.h --- v2.4.6/linux/drivers/net/sk98lin/h/skgehwt.h Fri Sep 15 14:34:19 2000 +++ linux/drivers/net/sk98lin/h/skgehwt.h Wed Jul 4 11:50:39 2001 @@ -1,23 +1,32 @@ /****************************************************************************** * * Name: skhwt.h - * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.5 $ - * Date: $Date: 1999/11/22 13:54:24 $ + * Project: Genesis, PCI Gigabit Ethernet Adapter + * Version: $Revision: 1.4 $ + * Date: $Date: 1998/08/19 09:50:58 $ * Purpose: Defines for the hardware timer functions * ******************************************************************************/ /****************************************************************************** * - * (C)Copyright 1998,1999 SysKonnect, + * (C)Copyright 1989-1998 SysKonnect, * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * All Rights Reserved * - * 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 IS UNPUBLISHED PROPRIETARY SOURCE CODE OF SYSKONNECT + * The copyright notice above does not evidence any + * actual or intended publication of such source code. + * + * This Module contains Proprietary Information of SysKonnect + * and should be treated as Confidential. + * + * The information in this file is provided for the exclusive use of + * the licensees of SysKonnect. + * Such users have the right to use, modify, and incorporate this code + * into products for purposes authorized by the license agreement + * provided they include this notice and the associated copyright notice + * with any such product. * The information in this file is provided "AS IS" without warranty. * ******************************************************************************/ @@ -27,9 +36,6 @@ * History: * * $Log: skgehwt.h,v $ - * Revision 1.5 1999/11/22 13:54:24 cgoos - * Changed license header to GPL. - * * Revision 1.4 1998/08/19 09:50:58 gklug * fix: remove struct keyword from c-code (see CCC) add typedefs * diff -u --recursive --new-file v2.4.6/linux/drivers/net/sk98lin/h/skgeinit.h linux/drivers/net/sk98lin/h/skgeinit.h --- v2.4.6/linux/drivers/net/sk98lin/h/skgeinit.h Fri Sep 15 14:34:19 2000 +++ linux/drivers/net/sk98lin/h/skgeinit.h Wed Jul 4 11:50:39 2001 @@ -2,16 +2,15 @@ * * Name: skgeinit.h * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.46 $ - * Date: $Date: 2000/08/10 11:28:00 $ + * Version: $Revision: 1.51 $ + * Date: $Date: 2001/02/09 12:26:38 $ * Purpose: Structures and prototypes for the GE Init Module * ******************************************************************************/ /****************************************************************************** * - * (C)Copyright 1998-2000 SysKonnect, - * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * (C)Copyright 1998-2001 SysKonnect GmbH. * * 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 @@ -27,6 +26,22 @@ * History: * * $Log: skgeinit.h,v $ + * Revision 1.51 2001/02/09 12:26:38 cgoos + * Inserted #ifdef DIAG for half duplex workaround timer. + * + * Revision 1.50 2001/02/07 07:56:40 rassmann + * Corrected copyright. + * + * Revision 1.49 2001/01/31 15:32:18 gklug + * fix: problem with autosensing an SR8800 switch + * add: counter for autoneg timeouts + * + * Revision 1.48 2000/11/09 11:30:10 rassmann + * WA: Waiting after releasing reset until BCom chip is accessible. + * + * Revision 1.47 2000/10/18 12:22:40 cgoos + * Added workaround for half duplex hangup. + * * Revision 1.46 2000/08/10 11:28:00 rassmann * Editorial changes. * Preserving 32-bit alignment in structs for the adapter context. @@ -440,6 +455,12 @@ */ #define SK_MAX_LRESTART 3 /* Max. 3 times the link is restarted */ +/* + * define max. autonegotiation timeouts before link detection in sense mode is + * reset. + */ +#define SK_MAX_ANEG_TO 10 /* Max. 10 times the sense mode is reset */ + /* structures *****************************************************************/ /* @@ -453,8 +474,13 @@ SK_U64 PPrevRx; /* Previous RxOk Counter checking */ SK_U64 PPrevFcs; /* Previous FCS Error Counter checking */ SK_U64 PRxLim; /* Previous RxOk Counter checking */ + SK_U64 LastOctets; /* For half duplex hang check */ +#ifndef SK_DIAG + SK_TIMER HalfDupChkTimer; +#endif int PLinkResCt; /* Link Restart Counter */ int PAutoNegTimeOut;/* AutoNegotiation timeout current value */ + int PAutoNegTOCt; /* AutoNeg Timeout Counter */ int PRxQSize; /* Port Rx Queue Size in kB */ int PXSQSize; /* Port Synchronous Transmit Queue Size in kB */ int PXAQSize; /* Port Asynchronous Transmit Queue Size in kB*/ @@ -467,13 +493,17 @@ int PRxQOff; /* Rx Queue Address Offset */ int PXsQOff; /* Synchronous Tx Queue Address Offset */ int PXaQOff; /* Asynchronous Tx Queue Address Offset */ + int PhyType; /* PHY used on this port */ + SK_U16 PhyAddr; /* MDIO/MDC PHY address */ SK_U16 PRxCmd; /* Port Receive Command Configuration Value */ SK_U16 PIsave; /* Saved Interrupt status word */ SK_U16 PSsave; /* Saved PHY status word */ + SK_U16 Align01; SK_BOOL PHWLinkUp; /* The hardware Link is up (wireing) */ SK_BOOL PState; /* Is port initialized ? */ SK_BOOL PLinkBroken; /* Is Link broken ? */ SK_BOOL PCheckPar; /* Do we check for parity errors ? */ + SK_BOOL HalfDupTimerActive; SK_U8 PLinkCap; /* Link Capabilities */ SK_U8 PLinkModeConf; /* Link Mode configured */ SK_U8 PLinkMode; /* Link Mode currently used */ @@ -486,8 +516,7 @@ SK_U8 PMSStatus; /* Master/Slave Status */ SK_U8 PAutoNegFail; /* Autonegotiation fail flag */ SK_U8 PLipaAutoNeg; /* Autonegotiation possible with Link Partner */ - SK_U16 PhyAddr; /* MDIO/MDC PHY address */ - int PhyType; /* PHY used on this port */ + SK_U8 Align02; } SK_GEPORT; /* diff -u --recursive --new-file v2.4.6/linux/drivers/net/sk98lin/h/skgepnm2.h linux/drivers/net/sk98lin/h/skgepnm2.h --- v2.4.6/linux/drivers/net/sk98lin/h/skgepnm2.h Fri Sep 15 14:34:19 2000 +++ linux/drivers/net/sk98lin/h/skgepnm2.h Wed Jul 4 11:50:39 2001 @@ -2,16 +2,15 @@ * * Name: skgepnm2.h * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.28 $ - * Date: $Date: 2000/08/03 15:12:48 $ + * Version: $Revision: 1.30 $ + * Date: $Date: 2001/02/06 10:03:41 $ * Purpose: Defines for Private Network Management Interface * ****************************************************************************/ /****************************************************************************** * - * (C)Copyright 1998,1999 SysKonnect, - * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * (C)Copyright 1998-2001 SysKonnect GmbH. * * 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 @@ -27,6 +26,14 @@ * History: * * $Log: skgepnm2.h,v $ + * Revision 1.30 2001/02/06 10:03:41 mkunz + * - Pnmi V4 dual net support added. Interface functions and macros extended + * - Vpd bug fixed + * - OID_SKGE_MTU added + * + * Revision 1.29 2001/01/22 13:41:37 rassmann + * Supporting two nets on dual-port adapters. + * * Revision 1.28 2000/08/03 15:12:48 rwahl * - Additional comment for MAC statistic data structure. * @@ -159,8 +166,6 @@ /* * VPD releated defines */ -#define SK_PNMI_VPD_ARR_SIZE 40 -#define SK_PNMI_VPD_STR_SIZE 5 #define SK_PNMI_VPD_RW 1 #define SK_PNMI_VPD_RO 2 @@ -201,7 +206,8 @@ int Access; int (* Func)(SK_AC *pAc, SK_IOC pIo, int action, SK_U32 Id, char* pBuf, unsigned int* pLen, - SK_U32 Instance, unsigned int TableIndex); + SK_U32 Instance, unsigned int TableIndex, + SK_U32 NetNumber); SK_U16 Param; } SK_PNMI_TAB_ENTRY; diff -u --recursive --new-file v2.4.6/linux/drivers/net/sk98lin/h/skgepnmi.h linux/drivers/net/sk98lin/h/skgepnmi.h --- v2.4.6/linux/drivers/net/sk98lin/h/skgepnmi.h Fri Sep 15 14:34:19 2000 +++ linux/drivers/net/sk98lin/h/skgepnmi.h Wed Jul 4 11:50:39 2001 @@ -2,16 +2,15 @@ * * Name: skgepnmi.h * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.44 $ - * Date: $Date: 2000/09/07 07:35:27 $ + * Version: $Revision: 1.48 $ + * Date: $Date: 2001/02/23 14:34:24 $ * Purpose: Defines for Private Network Management Interface * ****************************************************************************/ /****************************************************************************** * - * (C)Copyright 1998,1999 SysKonnect, - * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * (C)Copyright 1998-2001 SysKonnect GmbH. * * 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 @@ -27,6 +26,25 @@ * History: * * $Log: skgepnmi.h,v $ + * Revision 1.48 2001/02/23 14:34:24 mkunz + * Changed macro PHYS2INST. Added pAC to Interface + * + * Revision 1.47 2001/02/07 08:28:23 mkunz + * - Added Oids: OID_SKGE_DIAG_ACTION + * OID_SKGE_DIAG_RESULT + * OID_SKGE_MULTICAST_LIST + * OID_SKGE_CURRENT_PACKET_FILTER + * OID_SKGE_INTERMEDIATE_SUPPORT + * - Changed value of OID_SKGE_MTU + * + * Revision 1.46 2001/02/06 10:01:41 mkunz + * - Pnmi V4 dual net support added. Interface functions and macros extended + * - Vpd bug fixed + * - OID_SKGE_MTU added + * + * Revision 1.45 2001/01/22 13:41:37 rassmann + * Supporting two nets on dual-port adapters. + * * Revision 1.44 2000/09/07 07:35:27 rwahl * - removed NDIS counter specific data type. * - fixed spelling for OID_SKGE_RLMT_PORT_PREFERRED. @@ -48,13 +66,13 @@ * Revision 1.40 2000/03/31 13:51:34 rwahl * Added SK_UPTR cast to offset calculation for PNMI struct fields; * missing cast caused compiler warnings by Win64 compiler. - * + * * Revision 1.39 1999/12/06 10:09:47 rwahl * Added new error log message. * * Revision 1.38 1999/11/22 13:57:55 cgoos * Changed license header to GPL. - * + * * Revision 1.37 1999/09/14 14:25:32 rwahl * Set MDB version for 1000Base-T (sensors, Master/Slave) changes. * @@ -112,7 +130,7 @@ * * Revision 1.22 1998/11/03 12:05:51 mhaveman * Added pAC parameter to counter macors. - * + * * Revision 1.21 1998/11/02 10:47:36 mhaveman * Added syslog messages for internal errors. * @@ -187,7 +205,7 @@ #include "h/ski2c.h" #include "h/skaddr.h" #include "h/skrlmt.h" - +#include "h/skvpd.h" /* * Management Database Version @@ -198,22 +216,23 @@ /* * Event definitions */ -#define SK_PNMI_EVT_SIRQ_OVERFLOW 1 /* Counter overflow */ -#define SK_PNMI_EVT_SEN_WAR_LOW 2 /* Lower war thres exceeded */ -#define SK_PNMI_EVT_SEN_WAR_UPP 3 /* Upper war thres exceeded */ -#define SK_PNMI_EVT_SEN_ERR_LOW 4 /* Lower err thres exceeded */ -#define SK_PNMI_EVT_SEN_ERR_UPP 5 /* Upper err thres exceeded */ -#define SK_PNMI_EVT_CHG_EST_TIMER 6 /* Timer event for RLMT Chg */ +#define SK_PNMI_EVT_SIRQ_OVERFLOW 1 /* Counter overflow */ +#define SK_PNMI_EVT_SEN_WAR_LOW 2 /* Lower war thres exceeded */ +#define SK_PNMI_EVT_SEN_WAR_UPP 3 /* Upper war thres exceeded */ +#define SK_PNMI_EVT_SEN_ERR_LOW 4 /* Lower err thres exceeded */ +#define SK_PNMI_EVT_SEN_ERR_UPP 5 /* Upper err thres exceeded */ +#define SK_PNMI_EVT_CHG_EST_TIMER 6 /* Timer event for RLMT Chg */ #define SK_PNMI_EVT_UTILIZATION_TIMER 7 /* Timer event for Utiliza. */ -#define SK_PNMI_EVT_CLEAR_COUNTER 8 /* Clear statistic counters */ -#define SK_PNMI_EVT_XMAC_RESET 9 /* XMAC will be reset */ +#define SK_PNMI_EVT_CLEAR_COUNTER 8 /* Clear statistic counters */ +#define SK_PNMI_EVT_XMAC_RESET 9 /* XMAC will be reset */ -#define SK_PNMI_EVT_RLMT_PORT_UP 10 /* Port came logically up */ -#define SK_PNMI_EVT_RLMT_PORT_DOWN 11 /* Port went logically down */ -#define SK_PNMI_EVT_RLMT_PORT_SWITCH 12 /* Switched active port */ +#define SK_PNMI_EVT_RLMT_PORT_UP 10 /* Port came logically up */ +#define SK_PNMI_EVT_RLMT_PORT_DOWN 11 /* Port went logically down */ #define SK_PNMI_EVT_RLMT_SEGMENTATION 13 /* Two SP root bridges found */ #define SK_PNMI_EVT_RLMT_ACTIVE_DOWN 14 /* Port went logically down */ -#define SK_PNMI_EVT_RLMT_ACTIVE_UP 15 /* Port came logically up */ +#define SK_PNMI_EVT_RLMT_ACTIVE_UP 15 /* Port came logically up */ +#define SK_PNMI_EVT_RLMT_SET_NETS 16 /* 1. Parameter is number of nets + 1 = single net; 2 = dual net */ /* * Return values @@ -225,6 +244,7 @@ #define SK_PNMI_ERR_READ_ONLY 4 #define SK_PNMI_ERR_UNKNOWN_OID 5 #define SK_PNMI_ERR_UNKNOWN_INST 6 +#define SK_PNMI_ERR_UNKNOWN_NET 7 /* @@ -355,7 +375,7 @@ #define OID_SKGE_CHKSM_RX_ERR_CTS 0xFF020113 #define OID_SKGE_CHKSM_TX_OK_CTS 0xFF020114 #define OID_SKGE_CHKSM_TX_UNABLE_CTS 0xFF020115 - + #define OID_SKGE_STAT_TX 0xFF020120 #define OID_SKGE_STAT_TX_OCTETS 0xFF020121 #define OID_SKGE_STAT_TX_BROADCAST 0xFF020122 @@ -412,7 +432,10 @@ #define OID_SKGE_STAT_RX_1023 0xFF020155 #define OID_SKGE_STAT_RX_MAX 0xFF020156 #define OID_SKGE_STAT_RX_LONGFRAMES 0xFF020157 - + +#define OID_SKGE_DIAG_ACTION 0xFF01011D +#define OID_SKGE_DIAG_RESULT 0xFF01011E +#define OID_SKGE_MTU 0xFF01011F #define OID_SKGE_PHYS_CUR_ADDR 0xFF010120 #define OID_SKGE_PHYS_FAC_ADDR 0xFF010121 #define OID_SKGE_PMD 0xFF010122 @@ -427,7 +450,9 @@ #define OID_SKGE_PHY_OPERATION_CAP 0xFF01012B #define OID_SKGE_PHY_OPERATION_MODE 0xFF01012C #define OID_SKGE_PHY_OPERATION_STATUS 0xFF01012D - +#define OID_SKGE_MULTICAST_LIST 0xFF01012E +#define OID_SKGE_CURRENT_PACKET_FILTER 0xFF01012F + #define OID_SKGE_TRAP 0xFF010130 #define OID_SKGE_TRAP_NUMBER 0xFF010131 @@ -435,11 +460,12 @@ #define OID_SKGE_RLMT_PORT_NUMBER 0xFF010141 #define OID_SKGE_RLMT_PORT_ACTIVE 0xFF010142 #define OID_SKGE_RLMT_PORT_PREFERRED 0xFF010143 +#define OID_SKGE_INTERMEDIATE_SUPPORT 0xFF010160 #define OID_SKGE_RLMT_CHANGE_CTS 0xFF020160 #define OID_SKGE_RLMT_CHANGE_TIME 0xFF020161 #define OID_SKGE_RLMT_CHANGE_ESTIM 0xFF020162 #define OID_SKGE_RLMT_CHANGE_THRES 0xFF020163 - + #define OID_SKGE_RLMT_PORT_INDEX 0xFF020164 #define OID_SKGE_RLMT_STATUS 0xFF020165 #define OID_SKGE_RLMT_TX_HELLO_CTS 0xFF020166 @@ -447,7 +473,7 @@ #define OID_SKGE_RLMT_TX_SP_REQ_CTS 0xFF020168 #define OID_SKGE_RLMT_RX_SP_CTS 0xFF020169 -#define OID_SKGE_RLMT_MONITOR_NUMBER 0xFF010150 +#define OID_SKGE_RLMT_MONITOR_NUMBER 0xFF010150 #define OID_SKGE_RLMT_MONITOR_INDEX 0xFF010151 #define OID_SKGE_RLMT_MONITOR_ADDR 0xFF010152 #define OID_SKGE_RLMT_MONITOR_ERRS 0xFF010153 @@ -471,7 +497,7 @@ #define OID_SKGE_ERR_RECOVERY_CTS 0xFF02017E #define OID_SKGE_SYSUPTIME 0xFF02017F -#define OID_SKGE_ALL_DATA 0xFF020190 +#define OID_SKGE_ALL_DATA 0xFF020190 #define OID_SKGE_TRAP_SEN_WAR_LOW 500 @@ -600,26 +626,27 @@ #define SK_PNMI_SET_DRIVER_VER(pAC,v) ((pAC)->Pnmi.pDriverVersion = \ (char *)(v)) -#define SK_PNMI_CNT_TX_QUEUE_LEN(pAC,v) \ + +#define SK_PNMI_CNT_TX_QUEUE_LEN(pAC,v,p) \ { \ - (pAC)->Pnmi.TxSwQueueLen = (SK_U64)(v); \ - if ((pAC)->Pnmi.TxSwQueueLen > (pAC)->Pnmi.TxSwQueueMax) { \ - (pAC)->Pnmi.TxSwQueueMax = (pAC)->Pnmi.TxSwQueueLen; \ + (pAC)->Pnmi.Port[p].TxSwQueueLen = (SK_U64)(v); \ + if ((pAC)->Pnmi.Port[p].TxSwQueueLen > (pAC)->Pnmi.Port[p].TxSwQueueMax) { \ + (pAC)->Pnmi.Port[p].TxSwQueueMax = (pAC)->Pnmi.Port[p].TxSwQueueLen; \ } \ } -#define SK_PNMI_CNT_TX_RETRY(pAC) (((pAC)->Pnmi.TxRetryCts)++) -#define SK_PNMI_CNT_RX_INTR(pAC) (((pAC)->Pnmi.RxIntrCts)++) -#define SK_PNMI_CNT_TX_INTR(pAC) (((pAC)->Pnmi.TxIntrCts)++) -#define SK_PNMI_CNT_NO_RX_BUF(pAC) (((pAC)->Pnmi.RxNoBufCts)++) -#define SK_PNMI_CNT_NO_TX_BUF(pAC) (((pAC)->Pnmi.TxNoBufCts)++) -#define SK_PNMI_CNT_USED_TX_DESCR(pAC,v) \ - ((pAC)->Pnmi.TxUsedDescrNo=(SK_U64)(v)); -#define SK_PNMI_CNT_RX_OCTETS_DELIVERED(pAC,v) \ +#define SK_PNMI_CNT_TX_RETRY(pAC,p) (((pAC)->Pnmi.Port[p].TxRetryCts)++) +#define SK_PNMI_CNT_RX_INTR(pAC,p) (((pAC)->Pnmi.Port[p].RxIntrCts)++) +#define SK_PNMI_CNT_TX_INTR(pAC,p) (((pAC)->Pnmi.Port[p].TxIntrCts)++) +#define SK_PNMI_CNT_NO_RX_BUF(pAC,p) (((pAC)->Pnmi.Port[p].RxNoBufCts)++) +#define SK_PNMI_CNT_NO_TX_BUF(pAC,p) (((pAC)->Pnmi.Port[p].TxNoBufCts)++) +#define SK_PNMI_CNT_USED_TX_DESCR(pAC,v,p) \ + ((pAC)->Pnmi.Port[p].TxUsedDescrNo=(SK_U64)(v)); +#define SK_PNMI_CNT_RX_OCTETS_DELIVERED(pAC,v,p) \ { \ - ((pAC)->Pnmi.RxDeliveredCts)++; \ - (pAC)->Pnmi.RxOctetsDeliveredCts += (SK_U64)(v); \ + ((pAC)->Pnmi.Port[p].RxDeliveredCts)++; \ + (pAC)->Pnmi.Port[p].RxOctetsDeliveredCts += (SK_U64)(v); \ } -#define SK_PNMI_CNT_ERR_RECOVERY(pAC) (((pAC)->Pnmi.ErrRecoveryCts)++); +#define SK_PNMI_CNT_ERR_RECOVERY(pAC,p) (((pAC)->Pnmi.Port[p].ErrRecoveryCts)++); #define SK_PNMI_CNT_SYNC_OCTETS(pAC,p,v) \ { \ @@ -643,14 +670,18 @@ #define SK_PNMI_PORT_LOG2INST(l) ((unsigned int)(l) + 1) #define SK_PNMI_PORT_PHYS2LOG(p) ((unsigned int)(p) + 1) #define SK_PNMI_PORT_LOG2PHYS(pAC,l) ((unsigned int)(l) - 1) -#define SK_PNMI_PORT_PHYS2INST(p) ((unsigned int)(p) + 2) +#define SK_PNMI_PORT_PHYS2INST(pAC,p) \ + (pAC->Pnmi.DualNetActiveFlag ? 2 : ((unsigned int)(p) + 2)) #define SK_PNMI_PORT_INST2PHYS(pAC,i) ((unsigned int)(i) - 2) /* * Structure definition for SkPnmiGetStruct and SkPnmiSetStruct */ -#define SK_PNMI_VPD_ENTRIES 20 -#define SK_PNMI_VPD_DATALEN 128 +#define SK_PNMI_VPD_KEY_SIZE 5 +#define SK_PNMI_VPD_BUFSIZE (VPD_SIZE) +#define SK_PNMI_VPD_ENTRIES (VPD_SIZE / 4) +#define SK_PNMI_VPD_DATALEN 128 /* Number of data bytes */ + #define SK_PNMI_MULTICAST_LISTLEN 64 #define SK_PNMI_SENSOR_ENTRIES (SK_MAX_SENSORS) #define SK_PNMI_CHECKSUM_ENTRIES 3 @@ -663,7 +694,7 @@ #define SK_PNMI_TRAP_QUEUE_LEN 512 typedef struct s_PnmiVpd { - char VpdKey[5]; + char VpdKey[SK_PNMI_VPD_KEY_SIZE]; char VpdValue[SK_PNMI_VPD_DATALEN]; SK_U8 VpdAccess; SK_U8 VpdAction; @@ -795,7 +826,7 @@ SK_U32 MgmtDBVersion; SK_PNMI_REQUEST_STATUS ReturnStatus; SK_U32 VpdFreeBytes; - char VpdEntriesList[SK_PNMI_VPD_DATALEN]; + char VpdEntriesList[SK_PNMI_VPD_ENTRIES * SK_PNMI_VPD_KEY_SIZE]; SK_U32 VpdEntriesNumber; SK_PNMI_VPD Vpd[SK_PNMI_VPD_ENTRIES]; SK_U32 PortNumber; @@ -805,6 +836,7 @@ char HwDescr[SK_PNMI_STRINGLEN1]; char HwVersion[SK_PNMI_STRINGLEN2]; SK_U16 Chipset; + SK_U32 MtuSize; SK_U32 Action; SK_U32 TestResult; SK_U8 BusType; @@ -885,8 +917,24 @@ SK_U64 StatSyncOctetsCts; SK_U64 StatRxLongFrameCts; SK_BOOL ActiveFlag; + SK_U64 TxSwQueueLen; + SK_U64 TxSwQueueMax; + SK_U64 TxRetryCts; + SK_U64 RxIntrCts; + SK_U64 TxIntrCts; + SK_U64 RxNoBufCts; + SK_U64 TxNoBufCts; + SK_U64 TxUsedDescrNo; + SK_U64 RxDeliveredCts; + SK_U64 RxOctetsDeliveredCts; + SK_U64 RxHwErrorsCts; + SK_U64 TxHwErrorsCts; + SK_U64 InErrorsCts; + SK_U64 OutErrorsCts; + SK_U64 ErrRecoveryCts; } SK_PNMI_PORT; + typedef struct s_PnmiData { SK_PNMI_PORT Port[SK_MAX_MACS]; SK_U64 VirtualCounterOffset[SK_PNMI_CNT_NO]; @@ -917,19 +965,8 @@ char PciBusWidth; char PMD; char Connector; - - SK_U64 TxSwQueueLen; - SK_U64 TxSwQueueMax; - SK_U64 TxRetryCts; - SK_U64 RxIntrCts; - SK_U64 TxIntrCts; - SK_U64 RxNoBufCts; - SK_U64 TxNoBufCts; - SK_U64 TxUsedDescrNo; - SK_U64 RxDeliveredCts; - SK_U64 RxOctetsDeliveredCts; - SK_U64 ErrRecoveryCts; SK_U64 StartUpTime; + SK_BOOL DualNetActiveFlag; } SK_PNMI; @@ -938,17 +975,17 @@ */ extern int SkPnmiInit(SK_AC *pAc, SK_IOC IoC, int level); extern int SkPnmiGetVar(SK_AC *pAc, SK_IOC IoC, SK_U32 Id, void* pBuf, - unsigned int* pLen, SK_U32 Instance); + unsigned int* pLen, SK_U32 Instance, SK_U32 NetIndex); extern int SkPnmiPreSetVar(SK_AC *pAc, SK_IOC IoC, SK_U32 Id, - void* pBuf, unsigned int *pLen, SK_U32 Instance); + void* pBuf, unsigned int *pLen, SK_U32 Instance, SK_U32 NetIndex); extern int SkPnmiSetVar(SK_AC *pAc, SK_IOC IoC, SK_U32 Id, void* pBuf, - unsigned int *pLen, SK_U32 Instance); + unsigned int *pLen, SK_U32 Instance, SK_U32 NetIndex); extern int SkPnmiGetStruct(SK_AC *pAc, SK_IOC IoC, void* pBuf, - unsigned int *pLen); + unsigned int *pLen, SK_U32 NetIndex); extern int SkPnmiPreSetStruct(SK_AC *pAc, SK_IOC IoC, void* pBuf, - unsigned int *pLen); + unsigned int *pLen, SK_U32 NetIndex); extern int SkPnmiSetStruct(SK_AC *pAc, SK_IOC IoC, void* pBuf, - unsigned int *pLen); + unsigned int *pLen, SK_U32 NetIndex); extern int SkPnmiEvent(SK_AC *pAc, SK_IOC IoC, SK_U32 Event, SK_EVPARA Param); diff -u --recursive --new-file v2.4.6/linux/drivers/net/sk98lin/h/skgesirq.h linux/drivers/net/sk98lin/h/skgesirq.h --- v2.4.6/linux/drivers/net/sk98lin/h/skgesirq.h Fri Sep 15 14:34:19 2000 +++ linux/drivers/net/sk98lin/h/skgesirq.h Wed Jul 4 11:50:39 2001 @@ -2,16 +2,15 @@ * * Name: skgesirq.h * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.20 $ - * Date: $Date: 1999/12/06 10:00:44 $ + * Version: $Revision: 1.22 $ + * Date: $Date: 2000/11/09 11:30:10 $ * Purpose: SK specific Gigabit Ethernet special IRQ functions * ******************************************************************************/ /****************************************************************************** * - * (C)Copyright 1998,1999 SysKonnect, - * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * (C)Copyright 1998-2000 SysKonnect GmbH. * * 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 @@ -26,6 +25,12 @@ * * History: * $Log: skgesirq.h,v $ + * Revision 1.22 2000/11/09 11:30:10 rassmann + * WA: Waiting after releasing reset until BCom chip is accessible. + * + * Revision 1.21 2000/10/18 12:22:40 cgoos + * Added workaround for half duplex hangup. + * * Revision 1.20 1999/12/06 10:00:44 cgoos * Added SET event for role. * @@ -106,9 +111,12 @@ #define SK_HWEV_SET_LMODE 6 /* Set Link Mode by PNMI */ #define SK_HWEV_SET_FLOWMODE 7 /* Set Flow Control Mode by PNMI */ #define SK_HWEV_SET_ROLE 8 /* Set Master/Slave (Role) by PNMI */ +#define SK_HWEV_HALFDUP_CHK 9 /* Set Master/Slave (Role) by PNMI */ #define SK_WA_ACT_TIME (5000000L) /* 5 sec */ #define SK_WA_INA_TIME (100000L) /* 100 msec */ + +#define SK_HALFDUP_CHK_TIME (10000L) /* 10 msec */ /* * Define the error numbers and messages diff -u --recursive --new-file v2.4.6/linux/drivers/net/sk98lin/h/ski2c.h linux/drivers/net/sk98lin/h/ski2c.h --- v2.4.6/linux/drivers/net/sk98lin/h/ski2c.h Fri Sep 15 14:34:19 2000 +++ linux/drivers/net/sk98lin/h/ski2c.h Wed Jul 4 11:50:39 2001 @@ -2,8 +2,8 @@ * * Name: ski2c.h * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.29 $ - * Date: $Date: 2000/08/03 14:28:17 $ + * Version: $Revision: 1.30 $ + * Date: $Date: 2001/04/05 11:38:09 $ * Purpose: Defines to access Voltage and Temperature Sensor * (taken from Monalisa (taken from Concentrator)) * @@ -28,6 +28,10 @@ * History: * * $Log: ski2c.h,v $ + * Revision 1.30 2001/04/05 11:38:09 rassmann + * Set SenState to idle in SkI2cWaitIrq(). + * Changed error message in SkI2cWaitIrq(). + * * Revision 1.29 2000/08/03 14:28:17 rassmann * - Added function to wait for I2C being ready before resetting the board. * - Replaced one duplicate "out of range" message with correct one. @@ -182,24 +186,26 @@ #define SKERR_I2C_E014MSG "WARNING: fan sensor out of range" #define SKERR_I2C_E015 (SKERR_I2C_E014+1) #define SKERR_I2C_E015MSG "ERROR: fan sensor out of range" +#define SKERR_I2C_E016 (SKERR_I2C_E015+1) +#define SKERR_I2C_E016MSG "I2C: active transfer does not complete.\n" /* * Define Timeout values */ -#define SK_I2C_TIM_LONG 2000000L /* 2 second */ -#define SK_I2C_TIM_SHORT 100000L /* 100 milli second */ +#define SK_I2C_TIM_LONG 2000000L /* 2 seconds */ +#define SK_I2C_TIM_SHORT 100000L /* 100 milliseconds */ /* * Define trap and error log hold times */ #ifndef SK_SEN_ERR_TR_HOLD -#define SK_SEN_ERR_TR_HOLD (4*SK_TICKS_PER_SEC) +#define SK_SEN_ERR_TR_HOLD (4*SK_TICKS_PER_SEC) #endif #ifndef SK_SEN_ERR_LOG_HOLD -#define SK_SEN_ERR_LOG_HOLD (60*SK_TICKS_PER_SEC) +#define SK_SEN_ERR_LOG_HOLD (60*SK_TICKS_PER_SEC) #endif #ifndef SK_SEN_WARN_TR_HOLD -#define SK_SEN_WARN_TR_HOLD (15*SK_TICKS_PER_SEC) +#define SK_SEN_WARN_TR_HOLD (15*SK_TICKS_PER_SEC) #endif #ifndef SK_SEN_WARN_LOG_HOLD #define SK_SEN_WARN_LOG_HOLD (15*60*SK_TICKS_PER_SEC) @@ -268,3 +274,4 @@ #endif #endif /* n_SKI2C_H */ + diff -u --recursive --new-file v2.4.6/linux/drivers/net/sk98lin/h/skqueue.h linux/drivers/net/sk98lin/h/skqueue.h --- v2.4.6/linux/drivers/net/sk98lin/h/skqueue.h Fri Sep 15 14:34:19 2000 +++ linux/drivers/net/sk98lin/h/skqueue.h Wed Jul 4 11:50:39 2001 @@ -1,23 +1,32 @@ /****************************************************************************** * * Name: skqueue.h - * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.13 $ - * Date: $Date: 1999/11/22 13:59:05 $ + * Project: Genesis, PCI Gigabit Ethernet Adapter + * Version: $Revision: 1.12 $ + * Date: $Date: 1998/09/08 08:48:01 $ * Purpose: Defines for the Event queue * ******************************************************************************/ /****************************************************************************** * - * (C)Copyright 1998,1999 SysKonnect, + * (C)Copyright 1989-1998 SysKonnect, * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * All Rights Reserved * - * 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 IS UNPUBLISHED PROPRIETARY SOURCE CODE OF SYSKONNECT + * The copyright notice above does not evidence any + * actual or intended publication of such source code. + * + * This Module contains Proprietary Information of SysKonnect + * and should be treated as Confidential. + * + * The information in this file is provided for the exclusive use of + * the licensees of SysKonnect. + * Such users have the right to use, modify, and incorporate this code + * into products for purposes authorized by the license agreement + * provided they include this notice and the associated copyright notice + * with any such product. * The information in this file is provided "AS IS" without warranty. * ******************************************************************************/ @@ -27,9 +36,6 @@ * History: * * $Log: skqueue.h,v $ - * Revision 1.13 1999/11/22 13:59:05 cgoos - * Changed license header to GPL. - * * Revision 1.12 1998/09/08 08:48:01 gklug * add: init level handling * diff -u --recursive --new-file v2.4.6/linux/drivers/net/sk98lin/h/skrlmt.h linux/drivers/net/sk98lin/h/skrlmt.h --- v2.4.6/linux/drivers/net/sk98lin/h/skrlmt.h Fri Sep 15 14:34:19 2000 +++ linux/drivers/net/sk98lin/h/skrlmt.h Wed Jul 4 11:50:39 2001 @@ -2,16 +2,15 @@ * * Name: skrlmt.h * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.27 $ - * Date: $Date: 1999/11/22 13:59:56 $ + * Version: $Revision: 1.32 $ + * Date: $Date: 2001/02/14 14:06:31 $ * Purpose: Header file for Redundant Link ManagemenT. * ******************************************************************************/ /****************************************************************************** * - * (C)Copyright 1998,1999 SysKonnect, - * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * (C)Copyright 1998-2001 SysKonnect GmbH. * * 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 @@ -27,14 +26,26 @@ * History: * * $Log: skrlmt.h,v $ + * Revision 1.32 2001/02/14 14:06:31 rassmann + * Editorial changes. + * + * Revision 1.31 2001/02/05 14:25:26 rassmann + * Prepared RLMT for transparent operation. + * + * Revision 1.30 2001/01/22 13:41:39 rassmann + * Supporting two nets on dual-port adapters. + * + * Revision 1.29 2000/11/17 08:58:00 rassmann + * Moved CheckSwitch from SK_RLMT_PACKET_RECEIVED to SK_RLMT_TIM event. + * + * Revision 1.28 2000/11/09 12:24:34 rassmann + * Editorial changes. + * * Revision 1.27 1999/11/22 13:59:56 cgoos * Changed license header to GPL. * * Revision 1.26 1999/10/04 14:01:19 rassmann - * Corrected reaction to reception of BPDU frames. - * Added parameter descriptions to "For Readme" section skrlmt.txt. - * Clarified usage of lookahead result *pForRlmt. - * Requested driver to present RLMT packets as soon as poosible. + * Corrected reaction to reception of BPDU frames (#10441). * * Revision 1.25 1999/07/20 12:53:39 rassmann * Fixed documentation errors for lookahead macros. @@ -149,7 +160,7 @@ #define __INC_SKRLMT_H #ifdef __cplusplus -xxxx /* not supported yet - force error */ +#error C++ is not yet supported. extern "C" { #endif /* cplusplus */ @@ -169,128 +180,140 @@ /* ----- PORT states ----- */ -#define SK_RLMT_PS_INIT 0 /* Port state: Init. */ +#define SK_RLMT_PS_INIT 0 /* Port state: Init. */ #define SK_RLMT_PS_LINK_DOWN 1 /* Port state: Link down. */ -#define SK_RLMT_PS_DOWN 2 /* Port state: Port down. */ -#define SK_RLMT_PS_GOING_UP 3 /* Port state: Going up. */ -#define SK_RLMT_PS_UP 4 /* Port state: Up. */ +#define SK_RLMT_PS_DOWN 2 /* Port state: Port down. */ +#define SK_RLMT_PS_GOING_UP 3 /* Port state: Going up. */ +#define SK_RLMT_PS_UP 4 /* Port state: Up. */ /* ----- RLMT states ----- */ -#define SK_RLMT_RS_INIT 0 /* RLMT state: Init. */ -#define SK_RLMT_RS_NET_DOWN 1 /* RLMT state: Net down. */ -#define SK_RLMT_RS_NET_UP 2 /* RLMT state: Net up. */ +#define SK_RLMT_RS_INIT 0 /* RLMT state: Init. */ +#define SK_RLMT_RS_NET_DOWN 1 /* RLMT state: Net down. */ +#define SK_RLMT_RS_NET_UP 2 /* RLMT state: Net up. */ /* ----- PORT events ----- */ -#define SK_RLMT_LINK_UP 1001 /* Link came up. */ -#define SK_RLMT_LINK_DOWN 1002 /* Link went down. */ -#define SK_RLMT_PORT_ADDR 1003 /* Port address changed. */ +#define SK_RLMT_LINK_UP 1001 /* Link came up. */ +#define SK_RLMT_LINK_DOWN 1002 /* Link went down. */ +#define SK_RLMT_PORT_ADDR 1003 /* Port address changed. */ /* ----- RLMT events ----- */ -#define SK_RLMT_START 2001 /* Start RLMT. */ -#define SK_RLMT_STOP 2002 /* Stop RLMT. */ +#define SK_RLMT_START 2001 /* Start RLMT. */ +#define SK_RLMT_STOP 2002 /* Stop RLMT. */ #define SK_RLMT_PACKET_RECEIVED 2003 /* Packet was received for RLMT. */ -#define SK_RLMT_STATS_CLEAR 2004 /* Clear statistics. */ +#define SK_RLMT_STATS_CLEAR 2004 /* Clear statistics. */ #define SK_RLMT_STATS_UPDATE 2005 /* Update statistics. */ #define SK_RLMT_PREFPORT_CHANGE 2006 /* Change preferred port. */ -#define SK_RLMT_MODE_CHANGE 2007 /* New RlmtMode. */ +#define SK_RLMT_MODE_CHANGE 2007 /* New RlmtMode. */ +#define SK_RLMT_SET_NETS 2008 /* Number of Nets (1 or 2). */ /* ----- RLMT mode bits ----- */ -#define SK_RLMT_CHECK_LINK 1 /* Check Link. */ -#define SK_RLMT_CHECK_LOC_LINK 2 /* Check other link on same adapter. */ -#define SK_RLMT_CHECK_SEG 4 /* Check segmentation. */ +/* + * CAUTION: These defines are private to RLMT. + * Please use the RLMT mode defines below. + */ + +#define SK_RLMT_CHECK_LINK 1 /* Check Link. */ +#define SK_RLMT_CHECK_LOC_LINK 2 /* Check other link on same adapter. */ +#define SK_RLMT_CHECK_SEG 4 /* Check segmentation. */ #ifndef RLMT_CHECK_REMOTE #define SK_RLMT_CHECK_OTHERS SK_RLMT_CHECK_LOC_LINK #else /* RLMT_CHECK_REMOTE */ -#define SK_RLMT_CHECK_REM_LINK 8 /* Check link(s) on other adapter(s). */ +#define SK_RLMT_CHECK_REM_LINK 8 /* Check link(s) on other adapter(s). */ #define SK_RLMT_MAX_REMOTE_PORTS_CHECKED 3 -#define SK_RLMT_CHECK_OTHERS (SK_RLMT_CHECK_LOC_LINK | \ - SK_RLMT_CHECK_REM_LINK) +#define SK_RLMT_CHECK_OTHERS \ + (SK_RLMT_CHECK_LOC_LINK | SK_RLMT_CHECK_REM_LINK) #endif /* RLMT_CHECK_REMOTE */ +#ifndef SK_RLMT_ENABLE_TRANSPARENT +#define SK_RLMT_TRANSPARENT 0 /* RLMT transparent - inactive. */ +#else /* SK_RLMT_ENABLE_TRANSPARENT */ +#define SK_RLMT_TRANSPARENT 128 /* RLMT transparent. */ +#endif /* SK_RLMT_ENABLE_TRANSPARENT */ + /* ----- RLMT modes ----- */ /* Check Link State. */ #define SK_RLMT_MODE_CLS (SK_RLMT_CHECK_LINK) /* Check Local Ports: check other links on the same adapter. */ -#define SK_RLMT_MODE_CLP (SK_RLMT_CHECK_LINK | \ - SK_RLMT_CHECK_LOC_LINK) +#define SK_RLMT_MODE_CLP (SK_RLMT_CHECK_LINK | SK_RLMT_CHECK_LOC_LINK) /* Check Local Ports and Segmentation Status. */ -#define SK_RLMT_MODE_CLPSS (SK_RLMT_CHECK_LINK | \ - SK_RLMT_CHECK_LOC_LINK | \ - SK_RLMT_CHECK_SEG) +#define SK_RLMT_MODE_CLPSS \ + (SK_RLMT_CHECK_LINK | SK_RLMT_CHECK_LOC_LINK | SK_RLMT_CHECK_SEG) #ifdef RLMT_CHECK_REMOTE /* Check Local and Remote Ports: check links (local or remote). */ Name of define TBD! -#define SK_RLMT_MODE_CRP (SK_RLMT_CHECK_LINK | \ - SK_RLMT_CHECK_LOC_LINK | \ - SK_RLMT_CHECK_REM_LINK) +#define SK_RLMT_MODE_CRP \ + (SK_RLMT_CHECK_LINK | SK_RLMT_CHECK_LOC_LINK | SK_RLMT_CHECK_REM_LINK) /* Check Local and Remote Ports and Segmentation Status. */ Name of define TBD! -#define SK_RLMT_MODE_CRPSS (SK_RLMT_CHECK_LINK | \ - SK_RLMT_CHECK_LOC_LINK | \ - SK_RLMT_CHECK_REM_LINK | \ - SK_RLMT_CHECK_SEG) +#define SK_RLMT_MODE_CRPSS \ + (SK_RLMT_CHECK_LINK | SK_RLMT_CHECK_LOC_LINK | \ + SK_RLMT_CHECK_REM_LINK | SK_RLMT_CHECK_SEG) #endif /* RLMT_CHECK_REMOTE */ /* ----- RLMT lookahead result bits ----- */ -#define SK_RLMT_RX_RLMT 1 /* Give packet to RLMT. */ -#define SK_RLMT_RX_PROTOCOL 2 /* Give packet to protocol. */ +#define SK_RLMT_RX_RLMT 1 /* Give packet to RLMT. */ +#define SK_RLMT_RX_PROTOCOL 2 /* Give packet to protocol. */ /* Macros */ #if 0 SK_AC *pAC /* adapter context */ -SK_U32 PortIdx /* receiving port */ -unsigned PacketLength /* received packet's length */ -SK_BOOL IsBc /* Flag: broadcast received */ -unsigned *pOffset /* Result: offset of bytes to present - to SK_RLMT_LOOKAHEAD */ -unsigned *pNumBytes /* Result: #Bytes to present - to SK_RLMT_LOOKAHEAD */ +SK_U32 PortNum /* receiving port */ +unsigned PktLen /* received packet's length */ +SK_BOOL IsBc /* Flag: packet is broadcast */ +unsigned *pOffset /* offs. of bytes to present to SK_RLMT_LOOKAHEAD */ +unsigned *pNumBytes /* #Bytes to present to SK_RLMT_LOOKAHEAD */ #endif /* 0 */ - -#define SK_RLMT_PRE_LOOKAHEAD(pAC,PortIdx,PacketLength,IsBc,pOffset,pNumBytes) { \ +#define SK_RLMT_PRE_LOOKAHEAD(pAC,PortNum,PktLen,IsBc,pOffset,pNumBytes) { \ SK_AC *_pAC; \ - SK_U32 _PortIdx; \ + SK_U32 _PortNum; \ _pAC = (pAC); \ - _PortIdx = (SK_U32)(PortIdx); \ - _pAC->Rlmt.Port[_PortIdx].PacketsRx++; \ - _pAC->Rlmt.Port[_PortIdx].PacketsPerTimeSlot++; \ - if ((IsBc) && _pAC->Rlmt.RlmtMode != SK_RLMT_MODE_CLS) { \ - *(pOffset) = 6; \ - *(pNumBytes) = 6; \ + _PortNum = (SK_U32)(PortNum); \ + /* _pAC->Rlmt.Port[_PortNum].PacketsRx++; */ \ + _pAC->Rlmt.Port[_PortNum].PacketsPerTimeSlot++; \ + if ((_pAC->Rlmt.Port[_PortNum].Net->RlmtMode & SK_RLMT_TRANSPARENT) != 0) { \ + *(pNumBytes) = 0; \ + } \ + else if (IsBc) { \ + if (_pAC->Rlmt.Port[_PortNum].Net->RlmtMode != SK_RLMT_MODE_CLS) { \ + *(pNumBytes) = 6; \ + *(pOffset) = 6; \ + } \ + else { \ + *(pNumBytes) = 0; \ + } \ } \ else { \ - *(pOffset) = 0; \ - if ((PacketLength) > SK_RLMT_MAX_TX_BUF_SIZE) { \ - _pAC->Rlmt.Port[_PortIdx].DataPacketsPerTimeSlot++; \ + if ((PktLen) > SK_RLMT_MAX_TX_BUF_SIZE) { \ + /* _pAC->Rlmt.Port[_PortNum].DataPacketsPerTimeSlot++; */ \ *(pNumBytes) = 0; \ } \ else { \ *(pNumBytes) = 6; \ + *(pOffset) = 0; \ } \ } \ } #if 0 SK_AC *pAC /* adapter context */ -SK_U32 PortIdx /* receiving port */ +SK_U32 PortNum /* receiving port */ SK_U8 *pLaPacket, /* received packet's data (points to pOffset) */ -SK_BOOL IsBc /* Flag: broadcast received */ -SK_BOOL IsMc /* Flag: multicast received */ -unsigned *pForRlmt /* Result: bits SK_RLMT_RX_RLMT, - SK_RLMT_RX_PROTOCOL */ +SK_BOOL IsBc /* Flag: packet is broadcast */ +SK_BOOL IsMc /* Flag: packet is multicast */ +unsigned *pForRlmt /* Result: bits SK_RLMT_RX_RLMT, SK_RLMT_RX_PROTOCOL */ SK_RLMT_LOOKAHEAD() expects *pNumBytes from packet offset *pOffset (s.a.) at *pLaPacket. @@ -298,29 +321,28 @@ BC, MC, or UC, you should use constants for IsBc and IsMc, so that your compiler can trash unneeded parts of the if construction. #endif /* 0 */ -#define SK_RLMT_LOOKAHEAD(pAC,PortIdx,pLaPacket,IsBc,IsMc,pForRlmt) { \ + +#define SK_RLMT_LOOKAHEAD(pAC,PortNum,pLaPacket,IsBc,IsMc,pForRlmt) { \ SK_AC *_pAC; \ - SK_U32 _PortIdx; \ + SK_U32 _PortNum; \ SK_U8 *_pLaPacket; \ _pAC = (pAC); \ - _PortIdx = (SK_U32)(PortIdx); \ + _PortNum = (SK_U32)(PortNum); \ _pLaPacket = (SK_U8 *)(pLaPacket); \ if (IsBc) {\ - if (!SK_ADDR_EQUAL( \ - _pLaPacket, \ - _pAC->Addr.CurrentMacAddress.a)) { \ - _pAC->Rlmt.Port[_PortIdx].BcTimeStamp = \ - SkOsGetTime(_pAC); \ + if (!SK_ADDR_EQUAL(_pLaPacket, _pAC->Addr.Net[_pAC->Rlmt.Port[ \ + _PortNum].Net->NetNumber].CurrentMacAddress.a)) { \ + _pAC->Rlmt.Port[_PortNum].BcTimeStamp = SkOsGetTime(_pAC); \ + _pAC->Rlmt.CheckSwitch = SK_TRUE; \ } \ - _pAC->Rlmt.Port[_PortIdx].DataPacketsPerTimeSlot++; \ + /* _pAC->Rlmt.Port[_PortNum].DataPacketsPerTimeSlot++; */ \ *(pForRlmt) = SK_RLMT_RX_PROTOCOL; \ } \ else if (IsMc) { \ if (SK_ADDR_EQUAL(_pLaPacket, BridgeMcAddr.a)) { \ - _pAC->Rlmt.Port[_PortIdx].BpduPacketsPerTimeSlot++; \ - if (_pAC->Rlmt.RlmtMode & SK_RLMT_CHECK_SEG) { \ - *(pForRlmt) = SK_RLMT_RX_RLMT | \ - SK_RLMT_RX_PROTOCOL; \ + _pAC->Rlmt.Port[_PortNum].BpduPacketsPerTimeSlot++; \ + if (_pAC->Rlmt.Port[_PortNum].Net->RlmtMode & SK_RLMT_CHECK_SEG) { \ + *(pForRlmt) = SK_RLMT_RX_RLMT | SK_RLMT_RX_PROTOCOL; \ } \ else { \ *(pForRlmt) = SK_RLMT_RX_PROTOCOL; \ @@ -330,18 +352,18 @@ *(pForRlmt) = SK_RLMT_RX_RLMT; \ } \ else { \ - _pAC->Rlmt.Port[_PortIdx].DataPacketsPerTimeSlot++; \ + /* _pAC->Rlmt.Port[_PortNum].DataPacketsPerTimeSlot++; */ \ *(pForRlmt) = SK_RLMT_RX_PROTOCOL; \ } \ } \ else { \ if (SK_ADDR_EQUAL( \ _pLaPacket, \ - _pAC->Addr.Port[_PortIdx].CurrentMacAddress.a)) { \ + _pAC->Addr.Port[_PortNum].CurrentMacAddress.a)) { \ *(pForRlmt) = SK_RLMT_RX_RLMT; \ } \ else { \ - _pAC->Rlmt.Port[_PortIdx].DataPacketsPerTimeSlot++; \ + /* _pAC->Rlmt.Port[_PortNum].DataPacketsPerTimeSlot++; */ \ *(pForRlmt) = SK_RLMT_RX_PROTOCOL; \ } \ } \ @@ -350,107 +372,143 @@ #ifdef SK_RLMT_FAST_LOOKAHEAD Error: SK_RLMT_FAST_LOOKAHEAD no longer used. Use new macros for lookahead. #endif /* SK_RLMT_FAST_LOOKAHEAD */ +#ifdef SK_RLMT_SLOW_LOOKAHEAD +Error: SK_RLMT_SLOW_LOOKAHEAD no longer used. Use new macros for lookahead. +#endif /* SK_RLMT_SLOW_LOOKAHEAD */ /* typedefs *******************************************************************/ +#ifdef SK_RLMT_MBUF_PRIVATE +typedef struct s_RlmtMbuf { + some content +} SK_RLMT_MBUF; +#endif /* SK_RLMT_MBUF_PRIVATE */ + + +#ifdef SK_LA_INFO +typedef struct s_Rlmt_PacketInfo { + unsigned PacketLength; /* Length of packet. */ + unsigned PacketType; /* Directed/Multicast/Broadcast. */ +} SK_RLMT_PINFO; +#endif /* SK_LA_INFO */ + + typedef struct s_RootId { - SK_U8 Id[8]; /* Root Bridge Id. */ + SK_U8 Id[8]; /* Root Bridge Id. */ } SK_RLMT_ROOT_ID; + typedef struct s_port { SK_MAC_ADDR CheckAddr; SK_BOOL SuspectTx; } SK_PORT_CHECK; + +typedef struct s_RlmtNet SK_RLMT_NET; + + typedef struct s_RlmtPort { /* ----- Public part (read-only) ----- */ - SK_U8 PortState; /* Current state of this port. */ + SK_U8 PortState; /* Current state of this port. */ /* For PNMI */ - - SK_BOOL LinkDown; - SK_BOOL PortDown; - - SK_U64 TxHelloCts; - SK_U64 RxHelloCts; - SK_U64 TxSpHelloReqCts; - SK_U64 RxSpHelloCts; + SK_BOOL LinkDown; + SK_BOOL PortDown; + SK_U8 Align01; + + SK_U32 PortNumber; /* Number of port on adapter. */ + SK_RLMT_NET * Net; /* Net port belongs to. */ + + SK_U64 TxHelloCts; + SK_U64 RxHelloCts; + SK_U64 TxSpHelloReqCts; + SK_U64 RxSpHelloCts; /* ----- Private part ----- */ - SK_BOOL PortStarted; /* Port is started. */ - SK_BOOL PortNoRx; /* NoRx for >= 1 time slot. */ - SK_U32 CheckingState; /* Checking State. */ - - SK_U64 PacketsRx; /* Total packets received. */ - SK_U32 PacketsPerTimeSlot; /* Packets rxed between TOs. */ - SK_U32 DataPacketsPerTimeSlot; /* Data packets ... */ -#if 0 - SK_U32 RlmtAcksPerTimeSlot; /* RLMT Acks rxed in TS. */ - SK_U32 RlmtChksPerTimeSlot; /* RLMT Chks rxed in TS. */ -#endif /* 0 */ - SK_U32 BpduPacketsPerTimeSlot; /* BPDU packets rxed in TS. */ - SK_U64 BcTimeStamp; /* Time of last BC receive. */ - SK_U64 GuTimeStamp; /* Time of entering GOING_UP. */ - - SK_TIMER UpTimer; /* Timer struct Link/Port up. */ - SK_TIMER DownRxTimer; /* Timer struct down rx. */ - SK_TIMER DownTxTimer; /* Timer struct down tx. */ - - SK_U8 Random[4]; /* Random value. */ - unsigned PortsChecked; /* #ports checked. */ - unsigned PortsSuspect; /* #ports checked that are s. */ +/* SK_U64 PacketsRx; */ /* Total packets received. */ + SK_U32 PacketsPerTimeSlot; /* Packets rxed between TOs. */ +/* SK_U32 DataPacketsPerTimeSlot; */ /* Data packets ... */ + SK_U32 BpduPacketsPerTimeSlot; /* BPDU packets rxed in TS. */ + SK_U64 BcTimeStamp; /* Time of last BC receive. */ + SK_U64 GuTimeStamp; /* Time of entering GOING_UP. */ + + SK_TIMER UpTimer; /* Timer struct Link/Port up. */ + SK_TIMER DownRxTimer; /* Timer struct down rx. */ + SK_TIMER DownTxTimer; /* Timer struct down tx. */ + + SK_U32 CheckingState; /* Checking State. */ + + SK_ADDR_PORT * AddrPort; + + SK_U8 Random[4]; /* Random value. */ + unsigned PortsChecked; /* #ports checked. */ + unsigned PortsSuspect; /* #ports checked that are s. */ SK_PORT_CHECK PortCheck[1]; /* SK_PORT_CHECK PortCheck[SK_MAX_MACS - 1]; */ - SK_BOOL RootIdSet; - SK_RLMT_ROOT_ID Root; /* Root Bridge Id. */ + SK_BOOL PortStarted; /* Port is started. */ + SK_BOOL PortNoRx; /* NoRx for >= 1 time slot. */ + SK_BOOL RootIdSet; + SK_RLMT_ROOT_ID Root; /* Root Bridge Id. */ } SK_RLMT_PORT; -#ifdef SK_RLMT_MBUF_PRIVATE -typedef struct s_RlmtMbuf { - some content -} SK_RLMT_MBUF; -#endif /* SK_RLMT_MBUF_PRIVATE */ -#ifdef SK_LA_INFO -typedef struct s_Rlmt_PacketInfo { - unsigned PacketLength; /* Length of packet. */ - unsigned PacketType; /* Directed/Multicast/Broadcast. */ -} SK_RLMT_PINFO; -#endif /* SK_LA_INFO */ - -typedef struct s_Rlmt { +struct s_RlmtNet { /* ----- Public part (read-only) ----- */ - SK_U8 RlmtState; /* Current RLMT state. */ - SK_RLMT_PORT Port[SK_MAX_MACS]; /* Array of available ports. */ - SK_U32 PrefPort; /* Preferred port. */ + SK_U32 NetNumber; /* Number of net. */ + + SK_RLMT_PORT * Port[SK_MAX_MACS]; /* Ports that belong to this net. */ + SK_U32 NumPorts; /* Number of ports. */ + SK_U32 PrefPort; /* Preferred port. */ /* For PNMI */ - SK_U32 RlmtMode; /* Check ... */ - SK_U32 MacActive; /* Active port. */ - SK_U32 MacPreferred; /* 0xFFFFFFFF: Automatic. */ + SK_U32 RlmtMode; /* Check ... */ + SK_U32 ActivePort; /* Active port. */ + SK_U32 Preference; /* 0xFFFFFFFF: Automatic. */ + + SK_U8 RlmtState; /* Current RLMT state. */ + +/* ----- Private part ----- */ + SK_BOOL RootIdSet; + SK_U16 Align01; + + int LinksUp; /* #Links up. */ + int PortsUp; /* #Ports up. */ + SK_U32 TimeoutValue; /* RLMT timeout value. */ + + SK_U32 CheckingState; /* Checking State. */ + SK_RLMT_ROOT_ID Root; /* Root Bridge Id. */ + + SK_TIMER LocTimer; /* Timer struct. */ + SK_TIMER SegTimer; /* Timer struct. */ +}; + + +typedef struct s_Rlmt { + +/* ----- Public part (read-only) ----- */ + + SK_U32 NumNets; /* Number of nets. */ + SK_U32 NetsStarted; /* Number of nets started. */ + SK_RLMT_NET Net[SK_MAX_NETS]; /* Array of available nets. */ + SK_RLMT_PORT Port[SK_MAX_MACS]; /* Array of available ports. */ /* ----- Private part ----- */ + SK_BOOL CheckSwitch; + SK_U8 Align01; + SK_U16 Align02; - int LinksUp; /* #Links up. */ - int PortsUp; /* #Ports up. */ - SK_U32 TimeoutValue; /* RLMT timeout value. */ - SK_TIMER LocTimer; /* Timer struct. */ - - SK_U32 CheckingState; /* Checking State. */ - SK_BOOL RootIdSet; - SK_RLMT_ROOT_ID Root; /* Root Bridge Id. */ - SK_TIMER SegTimer; /* Timer struct. */ } SK_RLMT; + extern SK_MAC_ADDR BridgeMcAddr; -extern SK_MAC_ADDR SkRlmtMcAddr; +extern SK_MAC_ADDR SkRlmtMcAddr; /* function prototypes ********************************************************/ @@ -464,16 +522,7 @@ extern void SkRlmtInit( SK_AC *pAC, SK_IOC IoC, - int Level); - -#ifdef SK_RLMT_SLOW_LOOKAHEAD -extern SK_BOOL SkRlmtLookaheadPacket( - SK_AC *pAC, - SK_U32 PortIdx, - SK_U8 *pLaPacket, - unsigned PacketLength, - unsigned LaLength); -#endif /* SK_RLMT_SLOW_LOOKAHEAD */ + int Level); extern int SkRlmtEvent( SK_AC *pAC, @@ -481,11 +530,11 @@ SK_U32 Event, SK_EVPARA Para); -#else /* defined(SK_KR_PROTO)) */ +#else /* defined(SK_KR_PROTO) */ /* Non-ANSI/C++ compliant function prototypes */ -xxxx /* not supported yet - force error */ +#error KR-style function prototypes are not yet provided. #endif /* defined(SK_KR_PROTO)) */ diff -u --recursive --new-file v2.4.6/linux/drivers/net/sk98lin/h/sktimer.h linux/drivers/net/sk98lin/h/sktimer.h --- v2.4.6/linux/drivers/net/sk98lin/h/sktimer.h Fri Sep 15 14:34:19 2000 +++ linux/drivers/net/sk98lin/h/sktimer.h Wed Jul 4 11:50:39 2001 @@ -1,23 +1,32 @@ /****************************************************************************** * * Name: sktimer.h - * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.9 $ - * Date: $Date: 1999/11/22 14:00:29 $ + * Project: Genesis, PCI Gigabit Ethernet Adapter + * Version: $Revision: 1.8 $ + * Date: $Date: 1998/09/08 08:48:02 $ * Purpose: Defines for the timer functions * ******************************************************************************/ /****************************************************************************** * - * (C)Copyright 1998,1999 SysKonnect, + * (C)Copyright 1989-1998 SysKonnect, * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * All Rights Reserved * - * 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 IS UNPUBLISHED PROPRIETARY SOURCE CODE OF SYSKONNECT + * The copyright notice above does not evidence any + * actual or intended publication of such source code. + * + * This Module contains Proprietary Information of SysKonnect + * and should be treated as Confidential. + * + * The information in this file is provided for the exclusive use of + * the licensees of SysKonnect. + * Such users have the right to use, modify, and incorporate this code + * into products for purposes authorized by the license agreement + * provided they include this notice and the associated copyright notice + * with any such product. * The information in this file is provided "AS IS" without warranty. * ******************************************************************************/ @@ -27,9 +36,6 @@ * History: * * $Log: sktimer.h,v $ - * Revision 1.9 1999/11/22 14:00:29 cgoos - * Changed license header to GPL. - * * Revision 1.8 1998/09/08 08:48:02 gklug * add: init level handling * diff -u --recursive --new-file v2.4.6/linux/drivers/net/sk98lin/h/skversion.h linux/drivers/net/sk98lin/h/skversion.h --- v2.4.6/linux/drivers/net/sk98lin/h/skversion.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/sk98lin/h/skversion.h Wed Jul 4 11:50:39 2001 @@ -0,0 +1,46 @@ +/****************************************************************************** + * + * Name: version.h + * Project: GEnesis, PCI Gigabit Ethernet Adapter + * Version: $Revision: 1.1 $ + * Date: $Date: 2001/03/06 09:25:00 $ + * Purpose: SK specific Error log support + * + ******************************************************************************/ + +/****************************************************************************** + * + * (C)Copyright 1998,1999 SysKonnect, + * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * + * 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. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + +/****************************************************************************** + * + * History: + * $Log: skversion.h,v $ + * Revision 1.1 2001/03/06 09:25:00 mlindner + * first version + * + * + * + ******************************************************************************/ + + +static const char SysKonnectFileId[] = "@(#)" __FILE__ " (C) SysKonnect GmbH."; +static const char SysKonnectBuildNumber[] = + "@(#)SK-BUILD: 4.06 PL: 01"; + +#define BOOT_STRING "sk98lin: Network Device Driver v4.06\n" \ + "Copyright (C) 2000-2001 SysKonnect GmbH." + +#define VER_STRING "4.06" + + diff -u --recursive --new-file v2.4.6/linux/drivers/net/sk98lin/h/skvpd.h linux/drivers/net/sk98lin/h/skvpd.h --- v2.4.6/linux/drivers/net/sk98lin/h/skvpd.h Fri Sep 15 14:34:19 2000 +++ linux/drivers/net/sk98lin/h/skvpd.h Wed Jul 4 11:50:39 2001 @@ -2,15 +2,15 @@ * * Name: skvpd.h * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.10 $ - * Date: $Date: 2000/08/10 11:29:07 $ + * Version: $Revision: 1.9 $ + * Date: $Date: 1999/11/22 14:02:27 $ * Purpose: Defines and Macros for VPD handling * ******************************************************************************/ /****************************************************************************** * - * (C)Copyright 1998-2000 SysKonnect, + * (C)Copyright 1998,1999 SysKonnect, * a business unit of Schneider & Koch & Co. Datensysteme GmbH. * * This program is free software; you can redistribute it and/or modify @@ -27,12 +27,6 @@ * History: * * $Log: skvpd.h,v $ - * Revision 1.10 2000/08/10 11:29:07 rassmann - * Editorial changes. - * Preserving 32-bit alignment in structs for the adapter context. - * Removed unused function VpdWriteDword() (#if 0). - * Made VpdReadKeyword() available for SKDIAG only. - * * Revision 1.9 1999/11/22 14:02:27 cgoos * Changed license header to GPL. * @@ -121,42 +115,40 @@ /* VPD status */ /* bit 7..1 reserved */ -#define VPD_VALID (1<<0) /* VPD data buffer, vpd_free_ro, */ - /* and vpd_free_rw valid */ +#define VPD_VALID (1<<0) /* VPD data buffer, vpd_free_ro, */ + /* and vpd_free_rw valid */ /* * VPD structs */ typedef struct s_vpd_status { - unsigned short Align01; /* Alignment */ - unsigned short vpd_status; /* VPD status, description see above */ - int vpd_free_ro; /* unused bytes in read only area */ - int vpd_free_rw; /* bytes available in read/write area */ + unsigned short vpd_status ; /* VPD status, description see above */ + int vpd_free_ro ; /* unused bytes in read only area */ + int vpd_free_rw ; /* bytes available in read/write area */ } SK_VPD_STATUS; typedef struct s_vpd { - SK_VPD_STATUS v; /* VPD status structure */ - char vpd_buf[VPD_SIZE]; /* VPD buffer */ + SK_VPD_STATUS v ; /* VPD status structure */ + char vpd_buf[VPD_SIZE] ; /* VPD buffer */ } SK_VPD; typedef struct s_vpd_para { - unsigned int p_len; /* parameter length */ - char *p_val; /* points to the value */ + unsigned int p_len ; /* parameter length */ + char *p_val ; /* points to the value */ } SK_VPD_PARA; /* * structure of Large Resource Type Identifiers */ - -/* was removed because of alignment problems */ +/* was removed, because of alignment problems */ /* * sturcture of VPD keywords */ typedef struct s_vpd_key { - char p_key[2]; /* 2 bytes ID string */ - unsigned char p_len; /* 1 byte length */ - char p_val; /* start of the value string */ + char p_key[2] ; /* 2 bytes ID string */ + unsigned char p_len ; /* 1 byte length */ + char p_val ; /* start of the value string */ } SK_VPD_KEY; @@ -180,39 +172,39 @@ #define VPD_IN32(pAC,IoC,Addr,pVal) SK_IN32(IoC,PCI_C(Addr),pVal) #endif /* VPD_DO_IO */ #else /* SKDIAG */ -#define VPD_OUT8(pAC,Ioc,Addr,Val) { \ +#define VPD_OUT8(pAC,Ioc,Addr,Val) { \ if ((pAC)->DgT.DgUseCfgCycle) \ - SkPciWriteCfgByte(pAC,Addr,Val); \ - else \ + SkPciWriteCfgByte(pAC,Addr,Val) ; \ + else \ SK_OUT8(pAC,PCI_C(Addr),Val); \ } -#define VPD_OUT16(pAC,Ioc,Addr,Val) { \ +#define VPD_OUT16(pAC,Ioc,Addr,Val) { \ if ((pAC)->DgT.DgUseCfgCycle) \ - SkPciWriteCfgWord(pAC,Addr,Val); \ + SkPciWriteCfgWord(pAC,Addr,Val) ; \ else \ SK_OUT16(pAC,PCI_C(Addr),Val); \ } -#define VPD_OUT32(pAC,Ioc,Addr,Val) { \ +#define VPD_OUT32(pAC,Ioc,Addr,Val) { \ if ((pAC)->DgT.DgUseCfgCycle) \ - SkPciWriteCfgDWord(pAC,Addr,Val); \ + SkPciWriteCfgDWord(pAC,Addr,Val) ; \ else \ SK_OUT32(pAC,PCI_C(Addr),Val); \ } -#define VPD_IN8(pAC,Ioc,Addr,pVal) { \ +#define VPD_IN8(pAC,Ioc,Addr,pVal) { \ if ((pAC)->DgT.DgUseCfgCycle) \ - SkPciReadCfgByte(pAC,Addr,pVal); \ + SkPciReadCfgByte(pAC,Addr,pVal) ; \ else \ SK_IN8(pAC,PCI_C(Addr),pVal); \ } -#define VPD_IN16(pAC,Ioc,Addr,pVal) { \ +#define VPD_IN16(pAC,Ioc,Addr,pVal) { \ if ((pAC)->DgT.DgUseCfgCycle) \ - SkPciReadCfgWord(pAC,Addr,pVal); \ + SkPciReadCfgWord(pAC,Addr,pVal) ; \ else \ SK_IN16(pAC,PCI_C(Addr),pVal); \ } -#define VPD_IN32(pAC,Ioc,Addr,pVal) { \ +#define VPD_IN32(pAC,Ioc,Addr,pVal) { \ if ((pAC)->DgT.DgUseCfgCycle) \ - SkPciReadCfgDWord(pAC,Addr,pVal); \ + SkPciReadCfgDWord(pAC,Addr,pVal) ; \ else \ SK_IN32(pAC,PCI_C(Addr),pVal); \ } @@ -221,52 +213,50 @@ /* function prototypes ********************************************************/ #ifndef SK_KR_PROTO -#ifdef SKDIAG extern SK_U32 VpdReadDWord( SK_AC *pAC, SK_IOC IoC, - int addr); -#endif /* SKDIAG */ + int addr) ; extern int VpdSetupPara( SK_AC *pAC, char *key, char *buf, - int len, - int type, - int op); + int len, + int type, + int op) ; extern SK_VPD_STATUS *VpdStat( SK_AC *pAC, - SK_IOC IoC); + SK_IOC IoC) ; extern int VpdKeys( SK_AC *pAC, SK_IOC IoC, char *buf, - int *len, - int *elements); + int *len, + int *elements) ; extern int VpdRead( SK_AC *pAC, SK_IOC IoC, char *key, char *buf, - int *len); + int *len) ; extern SK_BOOL VpdMayWrite( - char *key); + char *key) ; extern int VpdWrite( SK_AC *pAC, SK_IOC IoC, char *key, - char *buf); + char *buf) ; extern int VpdDelete( SK_AC *pAC, SK_IOC IoC, - char *key); + char *key) ; extern int VpdUpdate( SK_AC *pAC, @@ -275,34 +265,34 @@ extern void VpdErrLog( SK_AC *pAC, SK_IOC IoC, - char *msg); + char *msg) ; #ifdef SKDIAG extern int VpdReadBlock( SK_AC *pAC, SK_IOC IoC, char *buf, - int addr, - int len); + int addr, + int len) ; extern int VpdWriteBlock( SK_AC *pAC, SK_IOC IoC, char *buf, - int addr, - int len); + int addr, + int len) ; #endif /* SKDIAG */ #else /* SK_KR_PROTO */ -extern SK_U32 VpdReadDWord(); -extern int VpdSetupPara(); -extern SK_VPD_STATUS *VpdStat(); -extern int VpdKeys(); -extern int VpdRead(); -extern SK_BOOL VpdMayWrite(); -extern int VpdWrite(); -extern int VpdDelete(); -extern int VpdUpdate(); -extern void VpdErrLog(); +extern SK_U32 VpdReadDWord() ; +extern int VpdSetupPara() ; +extern SK_VPD_STATUS *VpdStat() ; +extern int VpdKeys() ; +extern int VpdRead() ; +extern SK_BOOL VpdMayWrite() ; +extern int VpdWrite() ; +extern int VpdDelete() ; +extern int VpdUpdate() ; +extern void VpdErrLog() ; #endif /* SK_KR_PROTO */ #endif /* __INC_SKVPD_H_ */ diff -u --recursive --new-file v2.4.6/linux/drivers/net/sk98lin/h/xmac_ii.h linux/drivers/net/sk98lin/h/xmac_ii.h --- v2.4.6/linux/drivers/net/sk98lin/h/xmac_ii.h Tue Mar 20 12:04:59 2001 +++ linux/drivers/net/sk98lin/h/xmac_ii.h Wed Jul 4 11:50:39 2001 @@ -2,16 +2,15 @@ * * Name: xmac_ii.h * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.27 $ - * Date: $Date: 2000/05/17 11:00:46 $ + * Version: $Revision: 1.28 $ + * Date: $Date: 2000/11/09 12:32:49 $ * Purpose: Defines and Macros for XaQti's Gigabit Ethernet Controller * ******************************************************************************/ /****************************************************************************** * - * (C)Copyright 1998,1999 SysKonnect, - * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * (C)Copyright 1998-2000 SysKonnect GmbH. * * 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 @@ -27,6 +26,9 @@ * History: * * $Log: xmac_ii.h,v $ + * Revision 1.28 2000/11/09 12:32:49 rassmann + * Renamed variables. + * * Revision 1.27 2000/05/17 11:00:46 malthoff * Add bit for enable/disable power management in BCOM chip. * @@ -145,40 +147,40 @@ * Note: NA reg = Network Address e.g DA, SA etc. * */ -#define XM_MMU_CMD 0x0000 /* 16 bit r/w MMU Command Register */ +#define XM_MMU_CMD 0x0000 /* 16 bit r/w MMU Command Register */ /* 0x0004: reserved */ -#define XM_POFF 0x0008 /* 32 bit r/w Packet Offset Register */ -#define XM_BURST 0x000c /* 32 bit r/w Burst Register for half duplex*/ +#define XM_POFF 0x0008 /* 32 bit r/w Packet Offset Register */ +#define XM_BURST 0x000c /* 32 bit r/w Burst Register for half duplex*/ #define XM_1L_VLAN_TAG 0x0010 /* 16 bit r/w One Level VLAN Tag ID */ #define XM_2L_VLAN_TAG 0x0014 /* 16 bit r/w Two Level VLAN Tag ID */ /* 0x0018 - 0x001e: reserved */ -#define XM_TX_CMD 0x0020 /* 16 bit r/w Transmit Command Register */ +#define XM_TX_CMD 0x0020 /* 16 bit r/w Transmit Command Register */ #define XM_TX_RT_LIM 0x0024 /* 16 bit r/w Transmit Retry Limit Register */ -#define XM_TX_STIME 0x0028 /* 16 bit r/w Transmit Slottime Register */ -#define XM_TX_IPG 0x002c /* 16 bit r/w Transmit Inter Packet Gap */ -#define XM_RX_CMD 0x0030 /* 16 bit r/w Receive Command Register */ -#define XM_PHY_ADDR 0x0034 /* 16 bit r/w PHY Address Register */ -#define XM_PHY_DATA 0x0038 /* 16 bit r/w PHY Data Register */ +#define XM_TX_STIME 0x0028 /* 16 bit r/w Transmit Slottime Register */ +#define XM_TX_IPG 0x002c /* 16 bit r/w Transmit Inter Packet Gap */ +#define XM_RX_CMD 0x0030 /* 16 bit r/w Receive Command Register */ +#define XM_PHY_ADDR 0x0034 /* 16 bit r/w PHY Address Register */ +#define XM_PHY_DATA 0x0038 /* 16 bit r/w PHY Data Register */ /* 0x003c: reserved */ -#define XM_GP_PORT 0x0040 /* 32 bit r/w General Purpose Port Register */ -#define XM_IMSK 0x0044 /* 16 bit r/w Interrupt Mask Register */ -#define XM_ISRC 0x0048 /* 16 bit ro Interrupt Status Register */ -#define XM_HW_CFG 0x004c /* 16 bit r/w Hardware Config Register */ +#define XM_GP_PORT 0x0040 /* 32 bit r/w General Purpose Port Register */ +#define XM_IMSK 0x0044 /* 16 bit r/w Interrupt Mask Register */ +#define XM_ISRC 0x0048 /* 16 bit ro Interrupt Status Register */ +#define XM_HW_CFG 0x004c /* 16 bit r/w Hardware Config Register */ /* 0x0050 - 0x005e: reserved */ -#define XM_TX_LO_WM 0x0060 /* 16 bit r/w Tx FIFO Low Water Mark */ -#define XM_TX_HI_WM 0x0062 /* 16 bit r/w Tx FIFO High Water Mark */ -#define XM_TX_THR 0x0064 /* 16 bit r/w Tx Request Threshold */ -#define XM_HT_THR 0x0066 /* 16 bit r/w Host Request Threshold */ -#define XM_PAUSE_DA 0x0068 /* NA reg r/w Pause Destination Address */ +#define XM_TX_LO_WM 0x0060 /* 16 bit r/w Tx FIFO Low Water Mark */ +#define XM_TX_HI_WM 0x0062 /* 16 bit r/w Tx FIFO High Water Mark */ +#define XM_TX_THR 0x0064 /* 16 bit r/w Tx Request Threshold */ +#define XM_HT_THR 0x0066 /* 16 bit r/w Host Request Threshold */ +#define XM_PAUSE_DA 0x0068 /* NA reg r/w Pause Destination Address */ /* 0x006e: reserved */ -#define XM_CTL_PARA 0x0070 /* 32 bit r/w Control Parameter Register */ +#define XM_CTL_PARA 0x0070 /* 32 bit r/w Control Parameter Register */ #define XM_MAC_OPCODE 0x0074 /* 16 bit r/w Opcode for MAC control frames */ #define XM_MAC_PTIME 0x0076 /* 16 bit r/w Pause time for MAC ctrl frames*/ -#define XM_TX_STAT 0x0078 /* 32 bit ro Tx Status LIFO Register */ +#define XM_TX_STAT 0x0078 /* 32 bit ro Tx Status LIFO Register */ /* 0x0080 - 0x00fc: 16 NA reg r/w Exakt Match Address Registers */ /* use the XM_EMX() macro to address */ -#define XM_EXM_START 0x0080 /* r/w Start Address of the EXM Regs */ +#define XM_EXM_START 0x0080 /* r/w Start Address of the EXM Regs */ /* * XM_EXM(Reg) @@ -191,18 +193,18 @@ */ #define XM_EXM(Reg) (XM_EXM_START + ((Reg) << 3)) -#define XM_SRC_CHK 0x0100 /* NA reg r/w Source Check Address Register */ -#define XM_SA 0x0108 /* NA reg r/w Station Address Register */ -#define XM_HSM 0x0110 /* 64 bit r/w Hash Match Address Registers */ -#define XM_RX_LO_WM 0x0118 /* 16 bit r/w Receive Low Water Mark */ -#define XM_RX_HI_WM 0x011a /* 16 bit r/w Receive High Water Mark */ -#define XM_RX_THR 0x011c /* 32 bit r/w Receive Request Threshold */ -#define XM_DEV_ID 0x0120 /* 32 bit ro Device ID Register */ -#define XM_MODE 0x0124 /* 32 bit r/w Mode Register */ -#define XM_LSA 0x0128 /* NA reg ro Last Source Register */ +#define XM_SRC_CHK 0x0100 /* NA reg r/w Source Check Address Register */ +#define XM_SA 0x0108 /* NA reg r/w Station Address Register */ +#define XM_HSM 0x0110 /* 64 bit r/w Hash Match Address Registers */ +#define XM_RX_LO_WM 0x0118 /* 16 bit r/w Receive Low Water Mark */ +#define XM_RX_HI_WM 0x011a /* 16 bit r/w Receive High Water Mark */ +#define XM_RX_THR 0x011c /* 32 bit r/w Receive Request Threshold */ +#define XM_DEV_ID 0x0120 /* 32 bit ro Device ID Register */ +#define XM_MODE 0x0124 /* 32 bit r/w Mode Register */ +#define XM_LSA 0x0128 /* NA reg ro Last Source Register */ /* 0x012e: reserved */ -#define XM_TS_READ 0x0130 /* 32 bit ro TimeStamp Read Regeister */ -#define XM_TS_LOAD 0x0134 /* 32 bit ro TimeStamp Load Value */ +#define XM_TS_READ 0x0130 /* 32 bit ro TimeStamp Read Regeister */ +#define XM_TS_LOAD 0x0134 /* 32 bit ro TimeStamp Load Value */ /* 0x0138 - 0x01fe: reserved */ #define XM_STAT_CMD 0x0200 /* 16 bit r/w Statistics Command Register */ #define XM_RX_CNT_EV 0x0204 /* 32 bit ro Rx Counter Event Register */ @@ -210,13 +212,13 @@ #define XM_RX_EV_MSK 0x020c /* 32 bit r/w Rx Counter Event Mask */ #define XM_TX_EV_MSK 0x0210 /* 32 bit r/w Tx Counter Event Mask */ /* 0x0204 - 0x027e: reserved */ -#define XM_TXF_OK 0x0280 /* 32 bit ro Frames Transmitted OK Conuter */ +#define XM_TXF_OK 0x0280 /* 32 bit ro Frames Transmitted OK Conuter */ #define XM_TXO_OK_HI 0x0284 /* 32 bit ro Octets Transmitted OK High Cnt*/ #define XM_TXO_OK_LO 0x0288 /* 32 bit ro Octets Transmitted OK Low Cnt */ #define XM_TXF_BC_OK 0x028c /* 32 bit ro Broadcast Frames Xmitted OK */ #define XM_TXF_MC_OK 0x0290 /* 32 bit ro Multicast Frames Xmitted OK */ #define XM_TXF_UC_OK 0x0294 /* 32 bit ro Unicast Frames Xmitted OK */ -#define XM_TXF_LONG 0x0298 /* 32 bit ro Tx Long Frame Counter */ +#define XM_TXF_LONG 0x0298 /* 32 bit ro Tx Long Frame Counter */ #define XM_TXE_BURST 0x029c /* 32 bit ro Tx Burst Event Counter */ #define XM_TXF_MPAUSE 0x02a0 /* 32 bit ro Tx Pause MAC Ctrl Frame Cnt */ #define XM_TXF_MCTRL 0x02a4 /* 32 bit ro Tx MAC Ctrl Frame Counter */ @@ -224,20 +226,20 @@ #define XM_TXF_MUL_COL 0x02ac /* 32 bit ro Tx Multiple Collision Counter */ #define XM_TXF_ABO_COL 0x02b0 /* 32 bit ro Tx aborted due to Exessive Col*/ #define XM_TXF_LAT_COL 0x02b4 /* 32 bit ro Tx Late Collision Counter */ -#define XM_TXF_DEF 0x02b8 /* 32 bit ro Tx Deferred Frame Counter */ +#define XM_TXF_DEF 0x02b8 /* 32 bit ro Tx Deferred Frame Counter */ #define XM_TXF_EX_DEF 0x02bc /* 32 bit ro Tx Excessive Deferall Counter */ #define XM_TXE_FIFO_UR 0x02c0 /* 32 bit ro Tx FIFO Underrun Event Cnt */ #define XM_TXE_CS_ERR 0x02c4 /* 32 bit ro Tx Carrier Sence Error Cnt */ -#define XM_TXP_UTIL 0x02c8 /* 32 bit ro Tx Utilization in % */ +#define XM_TXP_UTIL 0x02c8 /* 32 bit ro Tx Utilization in % */ /* 0x02cc - 0x02ce: reserved */ -#define XM_TXF_64B 0x02d0 /* 32 bit ro 64 Byte Tx Frame Counter */ -#define XM_TXF_127B 0x02d4 /* 32 bit ro 65-127 Byte Tx Frame Counter */ -#define XM_TXF_255B 0x02d8 /* 32 bit ro 128-255 Byte Tx Frame Counter */ -#define XM_TXF_511B 0x02dc /* 32 bit ro 256-511 Byte Tx Frame Counter */ +#define XM_TXF_64B 0x02d0 /* 32 bit ro 64 Byte Tx Frame Counter */ +#define XM_TXF_127B 0x02d4 /* 32 bit ro 65-127 Byte Tx Frame Counter */ +#define XM_TXF_255B 0x02d8 /* 32 bit ro 128-255 Byte Tx Frame Counter */ +#define XM_TXF_511B 0x02dc /* 32 bit ro 256-511 Byte Tx Frame Counter */ #define XM_TXF_1023B 0x02e0 /* 32 bit ro 512-1023 Byte Tx Frame Counter*/ #define XM_TXF_MAX_SZ 0x02e4 /* 32 bit ro 1024-MaxSize Byte Tx Frame Cnt*/ /* 0x02e8 - 0x02fe: reserved */ -#define XM_RXF_OK 0x0300 /* 32 bit ro Frames Received OK */ +#define XM_RXF_OK 0x0300 /* 32 bit ro Frames Received OK */ #define XM_RXO_OK_HI 0x0304 /* 32 bit ro Octets Received OK High Cnt */ #define XM_RXO_OK_LO 0x0308 /* 32 bit ro Octets Received OK Low Counter*/ #define XM_RXF_BC_OK 0x030c /* 32 bit ro Broadcast Frames Received OK */ @@ -256,17 +258,17 @@ #define XM_RXF_LEN_ERR 0x0340 /* 32 bit ro Rx in Range Length Error */ #define XM_RXE_SYM_ERR 0x0344 /* 32 bit ro Rx Symbol Error Counter */ #define XM_RXE_SHT_ERR 0x0348 /* 32 bit ro Rx Short Event Error Cnt */ -#define XM_RXE_RUNT 0x034c /* 32 bit ro Rx Runt Event Counter */ +#define XM_RXE_RUNT 0x034c /* 32 bit ro Rx Runt Event Counter */ #define XM_RXF_LNG_ERR 0x0350 /* 32 bit ro Rx Frame too Long Error Cnt */ #define XM_RXF_FCS_ERR 0x0354 /* 32 bit ro Rx Frame Check Seq. Error Cnt */ /* 0x0358 - 0x035a: reserved */ #define XM_RXF_CEX_ERR 0x035c /* 32 bit ro Rx Carrier Ext Error Frame Cnt*/ -#define XM_RXP_UTIL 0x0360 /* 32 bit ro Rx Utilization in % */ +#define XM_RXP_UTIL 0x0360 /* 32 bit ro Rx Utilization in % */ /* 0x0364 - 0x0366: reserved */ -#define XM_RXF_64B 0x0368 /* 32 bit ro 64 Byte Rx Frame Counter */ -#define XM_RXF_127B 0x036c /* 32 bit ro 65-127 Byte Rx Frame Counter */ -#define XM_RXF_255B 0x0370 /* 32 bit ro 128-255 Byte Rx Frame Counter */ -#define XM_RXF_511B 0x0374 /* 32 bit ro 256-511 Byte Rx Frame Counter */ +#define XM_RXF_64B 0x0368 /* 32 bit ro 64 Byte Rx Frame Counter */ +#define XM_RXF_127B 0x036c /* 32 bit ro 65-127 Byte Rx Frame Counter */ +#define XM_RXF_255B 0x0370 /* 32 bit ro 128-255 Byte Rx Frame Counter */ +#define XM_RXF_511B 0x0374 /* 32 bit ro 256-511 Byte Rx Frame Counter */ #define XM_RXF_1023B 0x0378 /* 32 bit ro 512-1023 Byte Rx Frame Counter*/ #define XM_RXF_MAX_SZ 0x037c /* 32 bit ro 1024-MaxSize Byte Rx Frame Cnt*/ /* 0x02e8 - 0x02fe: reserved */ @@ -277,19 +279,19 @@ * XMAC Bit Definitions * * If the bit access behaviour differs from the register access behaviour - * (r/w, ro) this is documented after the bit number. The following bit + * (r/w, ro) this is docomented after the bit number. The following bit * access behaviours are used: * (sc) self clearing * (ro) read only */ /* XM_MMU_CMD 16 bit r/w MMU Comamnd Register */ - /* Bit 15..13: reserved */ + /* Bit 15..13: reserved */ #define XM_MMU_PHY_RDY (1<<12) /* Bit 12: PHY Read Ready */ #define XM_MMU_PHY_BUSY (1<<11) /* Bit 11: PHY Busy */ #define XM_MMU_IGN_PF (1<<10) /* Bit 10: Ignore Pause Frame */ #define XM_MMU_MAC_LB (1<<9) /* Bit 9: Enable MAC Loopback */ - /* Bit 8: reserved */ + /* Bit 8: reserved */ #define XM_MMU_FRC_COL (1<<7) /* Bit 7: Force Collision */ #define XM_MMU_SIM_COL (1<<6) /* Bit 6: Simulate Collision */ #define XM_MMU_NO_PRE (1<<5) /* Bit 5: No MDIO Preamble */ @@ -301,8 +303,8 @@ /* XM_TX_CMD 16 bit r/w Transmit Command Register */ - /* Bit 15..7: reserved */ -#define XM_TX_BK2BK (1<<6) /* Bit 6: Ignor Carrier Sense (tx Bk2Bk)*/ + /* Bit 15..7: reserved */ +#define XM_TX_BK2BK (1<<6) /* Bit 6: Ignor Carrier Sense (tx Bk2Bk)*/ #define XM_TX_ENC_BYP (1<<5) /* Bit 5: Set Encoder in Bypass Mode */ #define XM_TX_SAM_LINE (1<<4) /* Bit 4: (sc) Start utilization calculation */ #define XM_TX_NO_GIG_MD (1<<3) /* Bit 3: Disable Carrier Extension */ @@ -312,28 +314,28 @@ /* XM_TX_RT_LIM 16 bit r/w Transmit Retry Limit Register */ - /* Bit 15..5: reserved */ + /* Bit 15..5: reserved */ #define XM_RT_LIM_MSK 0x1f /* Bit 4..0: Tx Retry Limit */ /* XM_TX_STIME 16 bit r/w Transmit Slottime Register */ - /* Bit 15..7: reserved */ + /* Bit 15..7: reserved */ #define XM_STIME_MSK 0x7f /* Bit 6..0: Tx Slottime bits */ /* XM_TX_IPG 16 bit r/w Transmit Inter Packet Gap */ - /* Bit 15..8: reserved */ -#define XM_IPG_MSK 0xff /* Bit 7..0: IPG value bits */ + /* Bit 15..8: reserved */ +#define XM_IPG_MSK 0xff /* Bit 7..0: IPG value bits */ /* XM_RX_CMD 16 bit r/w Receive Command Register */ - /* Bit 15..9: reserved */ + /* Bit 15..9: reserved */ #define XM_RX_LENERR_OK (1<<8) /* Bit 8 don't set Rx Err bit for */ - /* inrange error packets */ + /* inrange error packets */ #define XM_RX_BIG_PK_OK (1<<7) /* Bit 7 don't set Rx Err bit for */ - /* jumbo packets */ + /* jumbo packets */ #define XM_RX_IPG_CAP (1<<6) /* Bit 6 repl. type field with IPG */ -#define XM_RX_TP_MD (1<<5) /* Bit 5: Enable transparent Mode */ +#define XM_RX_TP_MD (1<<5) /* Bit 5: Enable transparent Mode */ #define XM_RX_STRIP_FCS (1<<4) /* Bit 4: Enable FCS Stripping */ #define XM_RX_SELF_RX (1<<3) /* Bit 3: Enable Rx of own packets */ #define XM_RX_SAM_LINE (1<<2) /* Bit 2: (sc) Start utilization calculation */ @@ -342,24 +344,24 @@ /* XM_PHY_ADDR 16 bit r/w PHY Address Register */ - /* Bit 15..5: reserved */ + /* Bit 15..5: reserved */ #define XM_PHY_ADDR_SZ 0x1f /* Bit 4..0: PHY Address bits */ /* XM_GP_PORT 32 bit r/w General Purpose Port Register */ - /* Bit 31..7: reserved */ -#define XM_GP_ANIP (1L<<6) /* Bit 6: (ro) Auto Negotiation in Progress */ + /* Bit 31..7: reserved */ +#define XM_GP_ANIP (1L<<6) /* Bit 6: (ro) Auto Negotiation in Progress */ #define XM_GP_FRC_INT (1L<<5) /* Bit 5: (sc) Force Interrupt */ - /* Bit 4: reserved */ + /* Bit 4: reserved */ #define XM_GP_RES_MAC (1L<<3) /* Bit 3: (sc) Reset MAC and FIFOs */ #define XM_GP_RES_STAT (1L<<2) /* Bit 2: (sc) Reset the statistics module */ - /* Bit 1: reserved */ + /* Bit 1: reserved */ #define XM_GP_INP_ASS (1L<<0) /* Bit 0: (ro) GP Input Pin asserted */ /* XM_IMSK 16 bit r/w Interrupt Mask Register */ /* XM_ISRC 16 bit ro Interrupt Status Register */ - /* Bit 15: reserved */ + /* Bit 15: reserved */ #define XM_IS_LNK_AE (1<<14) /* Bit 14: Link Asynchronous Event */ #define XM_IS_TX_ABORT (1<<13) /* Bit 13: Transmit Abort, late Col. etc */ #define XM_IS_FRC_INT (1<<12) /* Bit 12: Force INT bit set in GP */ @@ -367,7 +369,7 @@ #define XM_IS_LIPA_RC (1<<10) /* Bit 10: Link Partner requests config */ #define XM_IS_RX_PAGE (1<<9) /* Bit 9: Page Received */ #define XM_IS_TX_PAGE (1<<8) /* Bit 8: Next Page Loaded for Transmit */ -#define XM_IS_AND (1<<7) /* Bit 7: Auto Negotiation Done */ +#define XM_IS_AND (1<<7) /* Bit 7: Auto Negotiation Done */ #define XM_IS_TSC_OV (1<<6) /* Bit 6: Time Stamp Counter Overflow */ #define XM_IS_RXC_OV (1<<5) /* Bit 5: Rx Counter Event Overflow */ #define XM_IS_TXC_OV (1<<4) /* Bit 4: Tx Counter Event Overflow */ @@ -377,42 +379,41 @@ #define XM_IS_RX_COMP (1<<0) /* Bit 0: Frame Rx Complete */ #define XM_DEF_MSK (~(XM_IS_INP_ASS | XM_IS_LIPA_RC | XM_IS_RX_PAGE |\ - XM_IS_AND | XM_IS_RXC_OV | XM_IS_TXC_OV |\ - XM_IS_TXF_UR)) + XM_IS_AND | XM_IS_RXC_OV | XM_IS_TXC_OV | XM_IS_TXF_UR)) /* XM_HW_CFG 16 bit r/w Hardware Config Register */ - /* Bit 15.. 4: reserved */ + /* Bit 15.. 4: reserved */ #define XM_HW_GEN_EOP (1<<3) /* Bit 3: generate End of Packet pulse */ #define XM_HW_COM4SIG (1<<2) /* Bit 2: use Comma Detect for Sig. Det.*/ - /* Bit 1: reserved */ + /* Bit 1: reserved */ #define XM_HW_GMII_MD (1<<0) /* Bit 0: GMII Interface selected */ /* XM_TX_LO_WM 16 bit r/w Tx FIFO Low Water Mark */ /* XM_TX_HI_WM 16 bit r/w Tx FIFO High Water Mark */ - /* Bit 15..10 reserved */ + /* Bit 15..10 reserved */ #define XM_TX_WM_MSK 0x01ff /* Bit 9.. 0 Tx FIFO Watermark bits */ /* XM_TX_THR 16 bit r/w Tx Request Threshold */ /* XM_HT_THR 16 bit r/w Host Request Threshold */ /* XM_RX_THR 16 bit r/w Receive Request Threshold */ - /* Bit 15..11 reserved */ -#define XM_THR_MSK 0x03ff /* Bit 10.. 0 Tx FIFO Watermark bits */ + /* Bit 15..11 reserved */ +#define XM_THR_MSK 0x03ff /* Bit 10.. 0 Tx FIFO Watermark bits */ /* XM_TX_STAT 32 bit ro Tx Status LIFO Register */ -#define XM_ST_VALID (1UL<<31) /* Bit 31: Status Valid */ +#define XM_ST_VALID (1UL<<31) /* Bit 31: Status Valid */ #define XM_ST_BYTE_CNT (0x3fffL<<17) /* Bit 30..17: Tx frame Length */ #define XM_ST_RETRY_CNT (0x1fL<<12) /* Bit 16..12: Retry Count */ #define XM_ST_EX_COL (1L<<11) /* Bit 11: Excessive Collisions */ #define XM_ST_EX_DEF (1L<<10) /* Bit 10: Excessive Deferral */ -#define XM_ST_BURST (1L<<9) /* Bit 9: p. xmitted in burst md*/ -#define XM_ST_DEFER (1L<<8) /* Bit 8: packet was defered */ -#define XM_ST_BC (1L<<7) /* Bit 7: Broadcast packet */ -#define XM_ST_MC (1L<<6) /* Bit 6: Multicast packet */ -#define XM_ST_UC (1L<<5) /* Bit 5: Unicast packet */ -#define XM_ST_TX_UR (1L<<4) /* Bit 4: FIFO Underrun occurred */ +#define XM_ST_BURST (1L<<9) /* Bit 9: p. xmitted in burst md*/ +#define XM_ST_DEFER (1L<<8) /* Bit 8: packet was defered */ +#define XM_ST_BC (1L<<7) /* Bit 7: Broadcast packet */ +#define XM_ST_MC (1L<<6) /* Bit 6: Multicast packet */ +#define XM_ST_UC (1L<<5) /* Bit 5: Unicast packet */ +#define XM_ST_TX_UR (1L<<4) /* Bit 4: FIFO Underrun occured */ #define XM_ST_CS_ERR (1L<<3) /* Bit 3: Carrier Sense Error */ #define XM_ST_LAT_COL (1L<<2) /* Bit 2: Late Collision Error */ #define XM_ST_MUL_COL (1L<<1) /* Bit 1: Multiple Collisions */ @@ -420,8 +421,8 @@ /* XM_RX_LO_WM 16 bit r/w Receive Low Water Mark */ /* XM_RX_HI_WM 16 bit r/w Receive High Water Mark */ - /* Bit 15..11: reserved */ -#define XM_RX_WM_MSK 0x03ff /* Bit 11.. 0: Rx FIFO Watermark bits */ + /* Bit 15..11: reserved */ +#define XM_RX_WM_MSK 0x03ff /* Bit 11.. 0: Rx FIFO Watermark bits */ /* XM_DEV_ID 32 bit ro Device ID Register */ @@ -430,25 +431,25 @@ /* XM_MODE 32 bit r/w Mode Register */ - /* Bit 31..27: reserved */ + /* Bit 31..27: reserved */ #define XM_MD_ENA_REJ (1L<<26) /* Bit 26: Enable Frame Reject */ #define XM_MD_SPOE_E (1L<<25) /* Bit 25: Send Pause on Edge */ - /* extern generated */ + /* extern generated */ #define XM_MD_TX_REP (1L<<24) /* Bit 24: Transmit Repeater Mode*/ #define XM_MD_SPOFF_I (1L<<23) /* Bit 23: Send Pause on FIFOfull*/ - /* intern generated */ + /* intern generated */ #define XM_MD_LE_STW (1L<<22) /* Bit 22: Rx Stat Word in Lit En*/ #define XM_MD_TX_CONT (1L<<21) /* Bit 21: Send Continuous */ #define XM_MD_TX_PAUSE (1L<<20) /* Bit 20: (sc) Send Pause Frame */ -#define XM_MD_ATS (1L<<19) /* Bit 19: Append Time Stamp */ +#define XM_MD_ATS (1L<<19) /* Bit 19: Append Time Stamp */ #define XM_MD_SPOL_I (1L<<18) /* Bit 18: Send Pause on Low */ - /* intern generated */ + /* intern generated */ #define XM_MD_SPOH_I (1L<<17) /* Bit 17: Send Pause on High */ - /* intern generated */ -#define XM_MD_CAP (1L<<16) /* Bit 16: Check Address Pair */ + /* intern generated */ +#define XM_MD_CAP (1L<<16) /* Bit 16: Check Address Pair */ #define XM_MD_ENA_HSH (1L<<15) /* Bit 15: Enable Hashing */ -#define XM_MD_CSA (1L<<14) /* Bit 14: Check Station Address */ -#define XM_MD_CAA (1L<<13) /* Bit 13: Check Address Array */ +#define XM_MD_CSA (1L<<14) /* Bit 14: Check Station Address */ +#define XM_MD_CAA (1L<<13) /* Bit 13: Check Address Array */ #define XM_MD_RX_MCTRL (1L<<12) /* Bit 12: Rx MAC Control Frames */ #define XM_MD_RX_RUNT (1L<<11) /* Bit 11: Rx Runt Frames */ #define XM_MD_RX_IRLE (1L<<10) /* Bit 10: Rx in Range Len Err F */ @@ -460,16 +461,15 @@ #define XM_MD_DIS_BC (1L<<4) /* Bit 4: Disable Rx Boradcast */ #define XM_MD_ENA_PROM (1L<<3) /* Bit 3: Enable Promiscuous */ #define XM_MD_ENA_BE (1L<<2) /* Bit 2: Enable Big Endian */ -#define XM_MD_FTF (1L<<1) /* Bit 1: (sc) Flush Tx FIFO */ -#define XM_MD_FRF (1L<<0) /* Bit 0: (sc) Flush Rx FIFO */ +#define XM_MD_FTF (1L<<1) /* Bit 1: (sc) Flush Tx FIFO */ +#define XM_MD_FRF (1L<<0) /* Bit 0: (sc) Flush Rx FIFO */ #define XM_PAUSE_MODE (XM_MD_SPOE_E | XM_MD_SPOL_I | XM_MD_SPOH_I) #define XM_DEF_MODE (XM_MD_RX_RUNT | XM_MD_RX_IRLE | XM_MD_RX_LONG |\ - XM_MD_RX_CRCE | XM_MD_RX_ERR | XM_MD_CSA |\ - XM_MD_CAA) + XM_MD_RX_CRCE | XM_MD_RX_ERR | XM_MD_CSA | XM_MD_CAA) /* XM_STAT_CMD 16 bit r/w Statistics Command Register */ - /* Bit 16..6: reserved */ + /* Bit 16..6: reserved */ #define XM_SC_SNP_RXC (1<<5) /* Bit 5: (sc) Snap Rx Counters */ #define XM_SC_SNP_TXC (1<<4) /* Bit 4: (sc) Snap Tx Counters */ #define XM_SC_CP_RXC (1<<3) /* Bit 3: Copy Rx Counters Continuously */ @@ -482,28 +482,28 @@ /* XM_RX_EV_MSK 32 bit r/w Rx Counter Event Mask */ #define XMR_MAX_SZ_OV (1UL<<31) /* Bit 31: 1024-MaxSize Rx Cnt Ov*/ #define XMR_1023B_OV (1L<<30) /* Bit 30: 512-1023Byte Rx Cnt Ov*/ -#define XMR_511B_OV (1L<<29) /* Bit 29: 256-511 Byte Rx Cnt Ov*/ -#define XMR_255B_OV (1L<<28) /* Bit 28: 128-255 Byte Rx Cnt Ov*/ -#define XMR_127B_OV (1L<<27) /* Bit 27: 65-127 Byte Rx Cnt Ov */ -#define XMR_64B_OV (1L<<26) /* Bit 26: 64 Byte Rx Cnt Ov */ -#define XMR_UTIL_OV (1L<<25) /* Bit 25: Rx Util Cnt Overflow */ -#define XMR_UTIL_UR (1L<<24) /* Bit 24: Rx Util Cnt Underrun */ +#define XMR_511B_OV (1L<<29) /* Bit 29: 256-511 Byte Rx Cnt Ov*/ +#define XMR_255B_OV (1L<<28) /* Bit 28: 128-255 Byte Rx Cnt Ov*/ +#define XMR_127B_OV (1L<<27) /* Bit 27: 65-127 Byte Rx Cnt Ov */ +#define XMR_64B_OV (1L<<26) /* Bit 26: 64 Byte Rx Cnt Ov */ +#define XMR_UTIL_OV (1L<<25) /* Bit 25: Rx Util Cnt Overflow */ +#define XMR_UTIL_UR (1L<<24) /* Bit 24: Rx Util Cnt Underrun */ #define XMR_CEX_ERR_OV (1L<<23) /* Bit 23: CEXT Err Cnt Ov */ - /* Bit 22: reserved */ + /* Bit 22: reserved */ #define XMR_FCS_ERR_OV (1L<<21) /* Bit 21: Rx FCS Error Cnt Ov */ #define XMR_LNG_ERR_OV (1L<<20) /* Bit 20: Rx too Long Err Cnt Ov*/ -#define XMR_RUNT_OV (1L<<19) /* Bit 19: Runt Event Cnt Ov */ +#define XMR_RUNT_OV (1L<<19) /* Bit 19: Runt Event Cnt Ov */ #define XMR_SHT_ERR_OV (1L<<18) /* Bit 18: Rx Short Ev Err Cnt Ov*/ #define XMR_SYM_ERR_OV (1L<<17) /* Bit 17: Rx Sym Err Cnt Ov */ - /* Bit 16: reserved */ + /* Bit 16: reserved */ #define XMR_CAR_ERR_OV (1L<<15) /* Bit 15: Rx Carr Ev Err Cnt Ov */ #define XMR_JAB_PKT_OV (1L<<14) /* Bit 14: Rx Jabb Packet Cnt Ov */ -#define XMR_FIFO_OV (1L<<13) /* Bit 13: Rx FIFO Ov Ev Cnt Ov */ +#define XMR_FIFO_OV (1L<<13) /* Bit 13: Rx FIFO Ov Ev Cnt Ov */ #define XMR_FRA_ERR_OV (1L<<12) /* Bit 12: Rx Framing Err Cnt Ov */ #define XMR_FMISS_OV (1L<<11) /* Bit 11: Rx Missed Ev Cnt Ov */ -#define XMR_BURST (1L<<10) /* Bit 10: Rx Burst Event Cnt Ov */ -#define XMR_INV_MOC (1L<<9) /* Bit 9: Rx with inv. MAC OC Ov*/ -#define XMR_INV_MP (1L<<8) /* Bit 8: Rx inv Pause Frame Ov */ +#define XMR_BURST (1L<<10) /* Bit 10: Rx Burst Event Cnt Ov */ +#define XMR_INV_MOC (1L<<9) /* Bit 9: Rx with inv. MAC OC Ov*/ +#define XMR_INV_MP (1L<<8) /* Bit 8: Rx inv Pause Frame Ov */ #define XMR_MCTRL_OV (1L<<7) /* Bit 7: Rx MAC Ctrl-F Cnt Ov */ #define XMR_MPAUSE_OV (1L<<6) /* Bit 6: Rx Pause MAC Ctrl-F Ov*/ #define XMR_UC_OK_OV (1L<<5) /* Bit 5: Rx Unicast Frame CntOv*/ @@ -511,39 +511,39 @@ #define XMR_BC_OK_OV (1L<<3) /* Bit 3: Rx Broadcast Cnt Ov */ #define XMR_OK_LO_OV (1L<<2) /* Bit 2: Octets Rx OK Low CntOv*/ #define XMR_OK_HI_OV (1L<<1) /* Bit 1: Octets Rx OK Hi Cnt Ov*/ -#define XMR_OK_OV (1L<<0) /* Bit 0: Frames Received Ok Ov */ +#define XMR_OK_OV (1L<<0) /* Bit 0: Frames Received Ok Ov */ #define XMR_DEF_MSK 0x00000006L /* all bits excepting 1 and 2 */ /* XM_TX_CNT_EV 32 bit ro Tx Counter Event Register */ /* XM_TX_EV_MSK 32 bit r/w Tx Counter Event Mask */ - /* Bit 31..26: reserved */ + /* Bit 31..26: reserved */ #define XMT_MAX_SZ_OV (1L<<25) /* Bit 25: 1024-MaxSize Tx Cnt Ov*/ #define XMT_1023B_OV (1L<<24) /* Bit 24: 512-1023Byte Tx Cnt Ov*/ -#define XMT_511B_OV (1L<<23) /* Bit 23: 256-511 Byte Tx Cnt Ov*/ -#define XMT_255B_OV (1L<<22) /* Bit 22: 128-255 Byte Tx Cnt Ov*/ -#define XMT_127B_OV (1L<<21) /* Bit 21: 65-127 Byte Tx Cnt Ov */ -#define XMT_64B_OV (1L<<20) /* Bit 20: 64 Byte Tx Cnt Ov */ -#define XMT_UTIL_OV (1L<<19) /* Bit 19: Tx Util Cnt Overflow */ -#define XMT_UTIL_UR (1L<<18) /* Bit 18: Tx Util Cnt Underrun */ +#define XMT_511B_OV (1L<<23) /* Bit 23: 256-511 Byte Tx Cnt Ov*/ +#define XMT_255B_OV (1L<<22) /* Bit 22: 128-255 Byte Tx Cnt Ov*/ +#define XMT_127B_OV (1L<<21) /* Bit 21: 65-127 Byte Tx Cnt Ov */ +#define XMT_64B_OV (1L<<20) /* Bit 20: 64 Byte Tx Cnt Ov */ +#define XMT_UTIL_OV (1L<<19) /* Bit 19: Tx Util Cnt Overflow */ +#define XMT_UTIL_UR (1L<<18) /* Bit 18: Tx Util Cnt Underrun */ #define XMT_CS_ERR_OV (1L<<17) /* Bit 17: Tx Carr Sen Err Cnt Ov*/ #define XMT_FIFO_UR_OV (1L<<16) /* Bit 16: Tx FIFO Ur Ev Cnt Ov */ #define XMT_EX_DEF_OV (1L<<15) /* Bit 15: Tx Ex Deferall Cnt Ov */ -#define XMT_DEF (1L<<14) /* Bit 14: Tx Deferred Cnt Ov */ +#define XMT_DEF (1L<<14) /* Bit 14: Tx Deferred Cnt Ov */ #define XMT_LAT_COL_OV (1L<<13) /* Bit 13: Tx Late Col Cnt Ov */ #define XMT_ABO_COL_OV (1L<<12) /* Bit 12: Tx abo dueto Ex Col Ov*/ #define XMT_MUL_COL_OV (1L<<11) /* Bit 11: Tx Mult Col Cnt Ov */ -#define XMT_SNG_COL (1L<<10) /* Bit 10: Tx Single Col Cnt Ov */ +#define XMT_SNG_COL (1L<<10) /* Bit 10: Tx Single Col Cnt Ov */ #define XMT_MCTRL_OV (1L<<9) /* Bit 9: Tx MAC Ctrl Counter Ov*/ -#define XMT_MPAUSE (1L<<8) /* Bit 8: Tx Pause MAC Ctrl-F Ov*/ -#define XMT_BURST (1L<<7) /* Bit 7: Tx Burst Event Cnt Ov */ -#define XMT_LONG (1L<<6) /* Bit 6: Tx Long Frame Cnt Ov */ +#define XMT_MPAUSE (1L<<8) /* Bit 8: Tx Pause MAC Ctrl-F Ov*/ +#define XMT_BURST (1L<<7) /* Bit 7: Tx Burst Event Cnt Ov */ +#define XMT_LONG (1L<<6) /* Bit 6: Tx Long Frame Cnt Ov */ #define XMT_UC_OK_OV (1L<<5) /* Bit 5: Tx Unicast Cnt Ov */ #define XMT_MC_OK_OV (1L<<4) /* Bit 4: Tx Multicast Cnt Ov */ #define XMT_BC_OK_OV (1L<<3) /* Bit 3: Tx Broadcast Cnt Ov */ #define XMT_OK_LO_OV (1L<<2) /* Bit 2: Octets Tx OK Low CntOv*/ #define XMT_OK_HI_OV (1L<<1) /* Bit 1: Octets Tx OK Hi Cnt Ov*/ -#define XMT_OK_OV (1L<<0) /* Bit 0: Frames Tx Ok Ov */ +#define XMT_OK_OV (1L<<0) /* Bit 0: Frames Tx Ok Ov */ #define XMT_DEF_MSK 0x00000006L /* all bits excepting 1 and 2 */ @@ -553,10 +553,10 @@ #define XMR_FS_LEN (0x3fffUL<<18) /* Bit 31..18: Rx Frame Length */ #define XMR_FS_2L_VLAN (1L<<17) /* Bit 17: tagged wh 2Lev VLAN ID*/ #define XMR_FS_1L_VLAN (1L<<16) /* Bit 16: tagged wh 1Lev VLAN ID*/ -#define XMR_FS_BC (1L<<15) /* Bit 15: Broadcast Frame */ -#define XMR_FS_MC (1L<<14) /* Bit 14: Multicast Frame */ -#define XMR_FS_UC (1L<<13) /* Bit 13: Unicast Frame */ - /* Bit 12: reserved */ +#define XMR_FS_BC (1L<<15) /* Bit 15: Broadcast Frame */ +#define XMR_FS_MC (1L<<14) /* Bit 14: Multicast Frame */ +#define XMR_FS_UC (1L<<13) /* Bit 13: Unicast Frame */ + /* Bit 12: reserved */ #define XMR_FS_BURST (1L<<11) /* Bit 11: Burst Mode */ #define XMR_FS_CEX_ERR (1L<<10) /* Bit 10: Carrier Ext. Error */ #define XMR_FS_802_3 (1L<<9) /* Bit 9: 802.3 Frame */ @@ -564,10 +564,10 @@ #define XMR_FS_CAR_ERR (1L<<7) /* Bit 7: Carrier Event Error */ #define XMR_FS_LEN_ERR (1L<<6) /* Bit 6: In-Range Length Error */ #define XMR_FS_FRA_ERR (1L<<5) /* Bit 5: Framing Error */ -#define XMR_FS_RUNT (1L<<4) /* Bit 4: Runt Error */ +#define XMR_FS_RUNT (1L<<4) /* Bit 4: Runt Error */ #define XMR_FS_LNG_ERR (1L<<3) /* Bit 3: Gaint Error */ #define XMR_FS_FCS_ERR (1L<<2) /* Bit 2: Frame Check Sequ Err */ -#define XMR_FS_ERR (1L<<1) /* Bit 1: Frame Error */ +#define XMR_FS_ERR (1L<<1) /* Bit 1: Frame Error */ #define XMR_FS_MCTRL (1L<<0) /* Bit 0: MAC Control Packet */ /* @@ -661,8 +661,8 @@ */ #define PHY_NAT_CTRL 0x00 /* 16 bit r/w PHY Control Register */ #define PHY_NAT_STAT 0x01 /* 16 bit r/w PHY Status Register */ -#define PHY_NAT_ID0 0x02 /* 16 bit ro PHY ID0 Register */ -#define PHY_NAT_ID1 0x03 /* 16 bit ro PHY ID1 Register */ +#define PHY_NAT_ID0 0x02 /* 16 bit ro PHY ID0 Register */ +#define PHY_NAT_ID1 0x03 /* 16 bit ro PHY ID1 Register */ #define PHY_NAT_AUNE_ADV 0x04 /* 16 bit r/w Autonegotiation Advertisement */ #define PHY_NAT_AUNE_LP 0x05 /* 16 bit ro Link Partner Ability Reg */ #define PHY_NAT_AUNE_EXP 0x06 /* 16 bit ro Autonegotiation Expansion Reg */ @@ -695,16 +695,16 @@ /***** PHY_BCOM_CTRL 16 bit r/w PHY Control Register *****/ /***** PHY_LONE_CTRL 16 bit r/w PHY Control Register *****/ #define PHY_CT_RESET (1<<15) /* Bit 15: (sc) clear all PHY releated regs */ -#define PHY_CT_LOOP (1<<14) /* Bit 14: enable Loopback over PHY */ +#define PHY_CT_LOOP (1<<14) /* Bit 14: enable Loopback over PHY */ #define PHY_CT_SPS_LSB (1<<13) /* Bit 13: (BC,L1) Speed select, lower bit */ -#define PHY_CT_ANE (1<<12) /* Bit 12: Autonegotiation Enabled */ +#define PHY_CT_ANE (1<<12) /* Bit 12: Autonegotiation Enabled */ #define PHY_CT_PDOWN (1<<11) /* Bit 11: (BC,L1) Power Down Mode */ -#define PHY_CT_ISOL (1<<10) /* Bit 10: (BC,L1) Isolate Mode */ +#define PHY_CT_ISOL (1<<10) /* Bit 10: (BC,L1) Isolate Mode */ #define PHY_CT_RE_CFG (1<<9) /* Bit 9: (sc) Restart Autonegotiation */ #define PHY_CT_DUP_MD (1<<8) /* Bit 8: Duplex Mode */ #define PHY_CT_COL_TST (1<<7) /* Bit 7: (BC,L1) Collsion Test enabled */ #define PHY_CT_SPS_MSB (1<<6) /* Bit 6: (BC,L1) Speed select, upper bit */ - /* Bit 5..0: reserved */ + /* Bit 5..0: reserved */ #define PHY_B_CT_SP1000 (1<<6) /* Bit 6: enable speed of 1000 MBit/s */ #define PHY_B_CT_SP100 (1<<13) /* Bit 13: enable speed of 100 MBit/s */ @@ -718,10 +718,10 @@ /***** PHY_XMAC_STAT 16 bit r/w PHY Status Register *****/ /***** PHY_BCOM_STAT 16 bit r/w PHY Status Register *****/ /***** PHY_LONE_STAT 16 bit r/w PHY Status Register *****/ - /* Bit 15..9: reserved */ + /* Bit 15..9: reserved */ /* (BC/L1) 100/10 MBit/s cap bits ignored*/ #define PHY_ST_EXT_ST (1<<8) /* Bit 8: Extended Status Present */ - /* Bit 7: reserved */ + /* Bit 7: reserved */ #define PHY_ST_PRE_SUB (1<<6) /* Bit 6: (BC/L1) preamble suppression */ #define PHY_ST_AN_OVER (1<<5) /* Bit 5: Autonegotiation Over */ #define PHY_ST_REM_FLT (1<<4) /* Bit 4: Remode Fault Condition Occured*/ @@ -734,9 +734,9 @@ /* PHY_XMAC_ID1 16 bit ro PHY ID1 Register */ /* PHY_BCOM_ID1 16 bit ro PHY ID1 Register */ /* PHY_LONE_ID1 16 bit ro PHY ID1 Register */ -#define PHY_I1_OUI (0x3f<<10) /* Bit 15..10: Organiz. Unique ID */ +#define PHY_I1_OUI (0x3f<<10) /* Bit 15..10: Organiz. Unique ID */ #define PHY_I1_MOD_NUM (0x3f<<4) /* Bit 9.. 4: Model Number */ -#define PHY_I1_REV (0x0f<<0) /* Bit 3.. 0: Revision Number */ +#define PHY_I1_REV (0x0f<<0) /* Bit 3.. 0: Revision Number */ /***** PHY_XMAC_AUNE_ADV 16 bit r/w Autoneg Advertisement *****/ @@ -744,43 +744,43 @@ #define PHY_AN_NXT_PG (1<<15) /* Bit 15: Request Next Page */ #define PHY_X_AN_ACK (1<<14) /* Bit 14: (ro) Acknowledge Received */ #define PHY_X_AN_RFB (3<<12) /* Bit 13..12: Remode Fault Bits */ - /* Bit 11.. 9: reserved */ + /* Bit 11.. 9: reserved */ #define PHY_X_AN_PAUSE (3<<7) /* Bit 8.. 7: Pause Bits */ -#define PHY_X_AN_HD (1<<6) /* Bit 6: Half Duplex */ -#define PHY_X_AN_FD (1<<5) /* Bit 5: Full Duplex */ - /* Bit 4.. 0: reserved */ +#define PHY_X_AN_HD (1<<6) /* Bit 6: Half Duplex */ +#define PHY_X_AN_FD (1<<5) /* Bit 5: Full Duplex */ + /* Bit 4.. 0: reserved */ /***** PHY_BCOM_AUNE_ADV 16 bit r/w Autoneg Advertisement *****/ /***** PHY_BCOM_AUNE_LP 16 bit ro Link Partner Ability Reg *****/ -/* PHY_AN_NXT_PG (see XMAC) Bit 15: Request Next Page */ - /* Bit 14: reserved */ -#define PHY_B_AN_RF (1<<13) /* Bit 13: Remote Fault */ - /* Bit 12: reserved */ +/* PHY_AN_NXT_PG (see XMAC) Bit 15: Request Next Page */ + /* Bit 14: reserved */ +#define PHY_B_AN_RF (1<<13) /* Bit 13: Remote Fault */ + /* Bit 12: reserved */ #define PHY_B_AN_ASP (1<<11) /* Bit 11: Asymetric Pause */ -#define PHY_B_AN_PC (1<<10) /* Bit 10: Pause Capable */ - /* Bit 9..5: 100/10 BT cap bits ingnored */ +#define PHY_B_AN_PC (1<<10) /* Bit 10: Pause Capable */ + /* Bit 9..5: 100/10 BT cap bits ingnored */ #define PHY_B_AN_SEL (0x1f<<0)/* Bit 4..0: Selector Field, 00001=Ethernet*/ /***** PHY_LONE_AUNE_ADV 16 bit r/w Autoneg Advertisement *****/ /***** PHY_LONE_AUNE_LP 16 bit ro Link Partner Ability Reg *****/ -/* PHY_AN_NXT_PG (see XMAC) Bit 15: Request Next Page */ - /* Bit 14: reserved */ -#define PHY_L_AN_RF (1<<13) /* Bit 13: Remote Fault */ - /* Bit 12: reserved */ +/* PHY_AN_NXT_PG (see XMAC) Bit 15: Request Next Page */ + /* Bit 14: reserved */ +#define PHY_L_AN_RF (1<<13) /* Bit 13: Remote Fault */ + /* Bit 12: reserved */ #define PHY_L_AN_ASP (1<<11) /* Bit 11: Asymetric Pause */ -#define PHY_L_AN_PC (1<<10) /* Bit 10: Pause Capable */ - /* Bit 9..5: 100/10 BT cap bits ingnored */ +#define PHY_L_AN_PC (1<<10) /* Bit 10: Pause Capable */ + /* Bit 9..5: 100/10 BT cap bits ingnored */ #define PHY_L_AN_SEL (0x1f<<0)/* Bit 4..0: Selector Field, 00001=Ethernet*/ /***** PHY_NAT_AUNE_ADV 16 bit r/w Autoneg Advertisement *****/ /***** PHY_NAT_AUNE_LP 16 bit ro Link Partner Ability Reg *****/ -/* PHY_AN_NXT_PG (see XMAC) Bit 15: Request Next Page */ - /* Bit 14: reserved */ -#define PHY_N_AN_RF (1<<13) /* Bit 13: Remote Fault */ - /* Bit 12: reserved */ +/* PHY_AN_NXT_PG (see XMAC) Bit 15: Request Next Page */ + /* Bit 14: reserved */ +#define PHY_N_AN_RF (1<<13) /* Bit 13: Remote Fault */ + /* Bit 12: reserved */ #define PHY_N_AN_100F (1<<11) /* Bit 11: 100Base-T2 FD Support */ #define PHY_N_AN_100H (1<<10) /* Bit 10: 100Base-T2 HD Support */ - /* Bit 9..5: 100/10 BT cap bits ingnored */ + /* Bit 9..5: 100/10 BT cap bits ingnored */ #define PHY_N_AN_SEL (0x1f<<0)/* Bit 4..0: Selector Field, 00001=Ethernet*/ /* field type definition for PHY_x_AN_SEL */ @@ -791,22 +791,22 @@ #define PHY_AN_LP_NP (1<<3) /* Bit 3: Link Partner can Next Page */ #define PHY_AN_LOC_NP (1<<2) /* Bit 2: Local PHY can Next Page */ #define PHY_AN_RX_PG (1<<1) /* Bit 1: Page Received */ - /* Bit 0: reserved */ + /* Bit 0: reserved */ /***** PHY_BCOM_AUNE_EXP 16 bit ro Autoneg Expansion Reg *****/ - /* Bit 15..5: reserved */ + /* Bit 15..5: reserved */ #define PHY_B_AN_PDF (1<<4) /* Bit 4: Parallel Detection Fault */ -/* PHY_AN_LP_NP (see XMAC) Bit 3: Link Partner can Next Page */ -/* PHY_AN_LOC_NP (see XMAC) Bit 2: Local PHY can Next Page */ -/* PHY_AN_RX_PG (see XMAC) Bit 1: Page Received */ +/* PHY_AN_LP_NP (see XMAC) Bit 3: Link Partner can Next Page */ +/* PHY_AN_LOC_NP (see XMAC) Bit 2: Local PHY can Next Page */ +/* PHY_AN_RX_PG (see XMAC) Bit 1: Page Received */ #define PHY_B_AN_LP_CAP (1<<0) /* Bit 0: Link Partner Autoneg Cap. */ /***** PHY_LONE_AUNE_EXP 16 bit ro Autoneg Expansion Reg *****/ -#define PHY_L_AN_BP (1<<5) /* Bit 5: Base Page Indication */ +#define PHY_L_AN_BP (1<<5) /* Bit 5: Base Page Indication */ #define PHY_L_AN_PDF (1<<4) /* Bit 4: Parallel Detection Fault */ -/* PHY_AN_LP_NP (see XMAC) Bit 3: Link Partner can Next Page */ -/* PHY_AN_LOC_NP (see XMAC) Bit 2: Local PHY can Next Page */ -/* PHY_AN_RX_PG (see XMAC) Bit 1: Page Received */ +/* PHY_AN_LP_NP (see XMAC) Bit 3: Link Partner can Next Page */ +/* PHY_AN_LOC_NP (see XMAC) Bit 2: Local PHY can Next Page */ +/* PHY_AN_RX_PG (see XMAC) Bit 1: Page Received */ #define PHY_B_AN_LP_CAP (1<<0) /* Bit 0: Link Partner Autoneg Cap. */ @@ -816,35 +816,35 @@ /***** PHY_XMAC_NEPG_LP 16 bit ro Next Page Link Partner *****/ /***** PHY_BCOM_NEPG_LP 16 bit ro Next Page Link Partner *****/ /***** PHY_LONE_NEPG_LP 16 bit ro Next Page Link Partner *****/ -#define PHY_NP_MORE (1<<15) /* Bit 15: More, Next Pages to follow */ -#define PHY_NP_ACK1 (1<<14) /* Bit 14: (ro) Ack 1, for receiving a message*/ +#define PHY_NP_MORE (1<<15) /* Bit 15: More, Next Pages to follow */ +#define PHY_NP_ACK1 (1<<14) /* Bit 14: (ro) Ack 1, for receiving a message*/ #define PHY_NP_MSG_VAL (1<<13) /* Bit 13: Message Page valid */ -#define PHY_NP_ACK2 (1<<12) /* Bit 12: Ack 2, comply with msg content*/ -#define PHY_NP_TOG (1<<11) /* Bit 11: Toggle Bit, ensure sync */ -#define PHY_NP_MSG 0x07ff /* Bit 10..0: Message from/to Link Partner */ +#define PHY_NP_ACK2 (1<<12) /* Bit 12: Ack 2, comply with msg content*/ +#define PHY_NP_TOG (1<<11) /* Bit 11: Toggle Bit, ensure sync */ +#define PHY_NP_MSG 0x07ff /* Bit 10..0: Message from/to Link Partner */ /* * XMAC-Specific */ /***** PHY_XMAC_EXT_STAT 16 bit r/w Extended Status Register *****/ -#define PHY_X_EX_FD (1<<15) /* Bit 15: Device Supports Full Duplex */ -#define PHY_X_EX_HD (1<<14) /* Bit 14: Device Supports Half Duplex */ - /* Bit 13..0: reserved */ +#define PHY_X_EX_FD (1<<15) /* Bit 15: Device Supports Full Duplex */ +#define PHY_X_EX_HD (1<<14) /* Bit 14: Device Supports Half Duplex */ + /* Bit 13..0: reserved */ /***** PHY_XMAC_RES_ABI 16 bit ro PHY Resolved Ability *****/ - /* Bit 15..9: reserved */ + /* Bit 15..9: reserved */ #define PHY_X_RS_PAUSE (3<<7) /* Bit 8..7: selected Pause Mode */ -#define PHY_X_RS_HD (1<<6) /* Bit 6: Half Duplex Mode selected */ -#define PHY_X_RS_FD (1<<5) /* Bit 5: Full Duplex Mode selected */ +#define PHY_X_RS_HD (1<<6) /* Bit 6: Half Duplex Mode selected */ +#define PHY_X_RS_FD (1<<5) /* Bit 5: Full Duplex Mode selected */ #define PHY_X_RS_ABLMIS (1<<4) /* Bit 4: duplex or pause cap mismatch */ #define PHY_X_RS_PAUMIS (1<<3) /* Bit 3: pause capability missmatch */ - /* Bit 2..0: reserved */ + /* Bit 2..0: reserved */ /* * Remote Fault Bits (PHY_X_AN_RFB) encoding */ -#define X_RFB_OK (0<<12) /* Bit 12..13 No errors, Link OK */ -#define X_RFB_LF (1<<12) /* Bit 12..13 Link Failure */ -#define X_RFB_OFF (2<<12) /* Bit 12..13 Offline */ +#define X_RFB_OK (0<<12) /* Bit 12..13 No errors, Link OK */ +#define X_RFB_LF (1<<12) /* Bit 12..13 Link Failure */ +#define X_RFB_OFF (2<<12) /* Bit 12..13 Offline */ #define X_RFB_AN_ERR (3<<12) /* Bit 12..13 Autonegotiation Error */ /* @@ -866,7 +866,7 @@ #define PHY_B_1000C_RD (1<<10) /* Bit 10: Repeater/DTE */ #define PHY_B_1000C_AFD (1<<9) /* Bit 9: Advertise Full Duplex */ #define PHY_B_1000C_AHD (1<<8) /* Bit 8: Advertise Half Duplex */ - /* Bit 7..0: reserved */ + /* Bit 7..0: reserved */ /***** PHY_BCOM_1000T_STAT 16 bit ro 1000Base-T Status Reg *****/ #define PHY_B_1000S_MSF (1<<15) /* Bit 15: Master/Slave Fault */ @@ -875,7 +875,7 @@ #define PHY_B_1000S_RRS (1<<12) /* Bit 12: Remote Receiver Status */ #define PHY_B_1000S_LP_FD (1<<11) /* Bit 11: Link Partner can FD */ #define PHY_B_1000S_LP_HD (1<<10) /* Bit 10: Link Partner can HD */ - /* Bit 9..8: reserved */ + /* Bit 9..8: reserved */ #define PHY_B_1000S_IEC (255<<0)/* Bit 7..0: Idle Error Count */ /***** PHY_BCOM_EXT_STAT 16 bit ro Extended Status Register *****/ @@ -883,7 +883,7 @@ #define PHY_B_ES_X_HD_CAP (1<<14) /* Bit 14: 1000Base-X HD capable */ #define PHY_B_ES_T_FD_CAP (1<<13) /* Bit 13: 1000Base-T FD capable */ #define PHY_B_ES_T_HD_CAP (1<<12) /* Bit 12: 1000Base-T HD capable */ - /* Bit 11..0: reserved */ + /* Bit 11..0: reserved */ /***** PHY_BCOM_P_EXT_CTRL 16 bit r/w PHY Extended Control Reg *****/ #define PHY_B_PEC_MAC_PHY (1<<15) /* Bit 15: 10BIT/GMI-Interface */ @@ -892,36 +892,36 @@ #define PHY_B_PEC_INT_DIS (1<<12) /* Bit 12: Interrupts Disabled */ #define PHY_B_PEC_F_INT (1<<11) /* Bit 11: Force Interrupt */ #define PHY_B_PEC_BY_45 (1<<10) /* Bit 10: Bypass 4B5B-Decoder */ -#define PHY_B_PEC_BY_SCR (1<<9) /* Bit 9: Bypass Scrambler */ -#define PHY_B_PEC_BY_MLT3 (1<<8) /* Bit 8: Bypass MLT3 Encoder */ -#define PHY_B_PEC_BY_RXA (1<<7) /* Bit 7: Bypass Rx Alignm. */ -#define PHY_B_PEC_RES_SCR (1<<6) /* Bit 6: Reset Scrambler */ -#define PHY_B_PEC_EN_LTR (1<<5) /* Bit 5: Ena LED Traffic Mode */ -#define PHY_B_PEC_LED_ON (1<<4) /* Bit 4: Force LED's on */ -#define PHY_B_PEC_LED_OFF (1<<3) /* Bit 3: Force LED's off */ -#define PHY_B_PEC_EX_IPG (1<<2) /* Bit 2: Extend Tx IPG Mode */ -#define PHY_B_PEC_3_LED (1<<1) /* Bit 1: Three Link LED mode */ -#define PHY_B_PEC_HIGH_LA (1<<0) /* Bit 0: GMII Fifo Elasticy */ +#define PHY_B_PEC_BY_SCR (1<<9) /* Bit 9: Bypass Scrambler */ +#define PHY_B_PEC_BY_MLT3 (1<<8) /* Bit 8: Bypass MLT3 Encoder */ +#define PHY_B_PEC_BY_RXA (1<<7) /* Bit 7: Bypass Rx Alignm. */ +#define PHY_B_PEC_RES_SCR (1<<6) /* Bit 6: Reset Scrambler */ +#define PHY_B_PEC_EN_LTR (1<<5) /* Bit 5: Ena LED Traffic Mode */ +#define PHY_B_PEC_LED_ON (1<<4) /* Bit 4: Force LED's on */ +#define PHY_B_PEC_LED_OFF (1<<3) /* Bit 3: Force LED's off */ +#define PHY_B_PEC_EX_IPG (1<<2) /* Bit 2: Extend Tx IPG Mode */ +#define PHY_B_PEC_3_LED (1<<1) /* Bit 1: Three Link LED mode */ +#define PHY_B_PEC_HIGH_LA (1<<0) /* Bit 0: GMII Fifo Elasticy */ /***** PHY_BCOM_P_EXT_STAT 16 bit ro PHY Extended Status Reg *****/ - /* Bit 15..14: reserved */ + /* Bit 15..14: reserved */ #define PHY_B_PES_CROSS_STAT (1<<13) /* Bit 13: MDI Crossover Status */ #define PHY_B_PES_INT_STAT (1<<12) /* Bit 12: Interrupt Status */ #define PHY_B_PES_RRS (1<<11) /* Bit 11: Remote Receiver Stat. */ #define PHY_B_PES_LRS (1<<10) /* Bit 10: Local Receiver Stat. */ -#define PHY_B_PES_LOCKED (1<<9) /* Bit 9: Locked */ -#define PHY_B_PES_LS (1<<8) /* Bit 8: Link Status */ -#define PHY_B_PES_RF (1<<7) /* Bit 7: Remote Fault */ -#define PHY_B_PES_CE_ER (1<<6) /* Bit 6: Carrier Ext Error */ -#define PHY_B_PES_BAD_SSD (1<<5) /* Bit 5: Bad SSD */ -#define PHY_B_PES_BAD_ESD (1<<4) /* Bit 4: Bad ESD */ -#define PHY_B_PES_RX_ER (1<<3) /* Bit 3: Receive Error */ -#define PHY_B_PES_TX_ER (1<<2) /* Bit 2: Transmit Error */ -#define PHY_B_PES_LOCK_ER (1<<1) /* Bit 1: Lock Error */ -#define PHY_B_PES_MLT3_ER (1<<0) /* Bit 0: MLT3 code Error */ +#define PHY_B_PES_LOCKED (1<<9) /* Bit 9: Locked */ +#define PHY_B_PES_LS (1<<8) /* Bit 8: Link Status */ +#define PHY_B_PES_RF (1<<7) /* Bit 7: Remote Fault */ +#define PHY_B_PES_CE_ER (1<<6) /* Bit 6: Carrier Ext Error */ +#define PHY_B_PES_BAD_SSD (1<<5) /* Bit 5: Bad SSD */ +#define PHY_B_PES_BAD_ESD (1<<4) /* Bit 4: Bad ESD */ +#define PHY_B_PES_RX_ER (1<<3) /* Bit 3: Receive Error */ +#define PHY_B_PES_TX_ER (1<<2) /* Bit 2: Transmit Error */ +#define PHY_B_PES_LOCK_ER (1<<1) /* Bit 1: Lock Error */ +#define PHY_B_PES_MLT3_ER (1<<0) /* Bit 0: MLT3 code Error */ /***** PHY_BCOM_FC_CTR 16 bit r/w False Carrier Counter *****/ - /* Bit 15..8: reserved */ + /* Bit 15..8: reserved */ #define PHY_B_FC_CTR (255<<0)/* Bit 7..0: False Carrier Counter */ /***** PHY_BCOM_RNO_CTR 16 bit r/w Receive NOT_OK Counter *****/ @@ -932,15 +932,15 @@ #define PHY_B_AC_L_SQE (1<<15) /* Bit 15: Low Squelch */ #define PHY_B_AC_LONG_PACK (1<<14) /* Bit 14: Rx Long Packets */ #define PHY_B_AC_ER_CTRL (3<<12) /* Bit 13..12: Edgerate Control */ - /* Bit 11: reserved */ + /* Bit 11: reserved */ #define PHY_B_AC_TX_TST (1<<10) /* Bit 10: tx test bit, always 1 */ - /* Bit 9.. 8: reserved */ + /* Bit 9.. 8: reserved */ #define PHY_B_AC_DIS_PRF (1<<7) /* Bit 7: dis part resp filter */ - /* Bit 6: reserved */ + /* Bit 6: reserved */ #define PHY_B_AC_DIS_PM (1<<5) /* Bit 5: dis power management */ - /* Bit 4: reserved */ + /* Bit 4: reserved */ #define PHY_B_AC_DIAG (1<<3) /* Bit 3: Diagnostic Mode */ - /* Bit 2.. 0: reserved */ + /* Bit 2.. 0: reserved */ /***** PHY_BCOM_AUX_STAT 16 bit ro Auxiliary Status Reg *****/ #define PHY_B_AS_AN_C (1<<15) /* Bit 15: AutoNeg complete */ @@ -949,37 +949,36 @@ #define PHY_B_AS_ANAB_D (1<<12) /* Bit 12: AN Ability Detect */ #define PHY_B_AS_NPW (1<<11) /* Bit 11: AN Next Page Wait */ #define PHY_B_AS_AN_RES (7<<8) /* Bit 10..8: AN HDC */ -#define PHY_B_AS_PDF (1<<7) /* Bit 7: Parallel Detect. Fault*/ -#define PHY_B_AS_RF (1<<6) /* Bit 6: Remote Fault */ -#define PHY_B_AS_ANP_R (1<<5) /* Bit 5: AN Page Received */ -#define PHY_B_AS_LP_ANAB (1<<4) /* Bit 4: LP AN Ability */ -#define PHY_B_AS_LP_NPAB (1<<3) /* Bit 3: LP Next Page Ability */ -#define PHY_B_AS_LS (1<<2) /* Bit 2: Link Status */ -#define PHY_B_AS_PRR (1<<1) /* Bit 1: Pause Resolution-Rx */ -#define PHY_B_AS_PRT (1<<0) /* Bit 0: Pause Resolution-Tx */ +#define PHY_B_AS_PDF (1<<7) /* Bit 7: Parallel Detect. Fault*/ +#define PHY_B_AS_RF (1<<6) /* Bit 6: Remote Fault */ +#define PHY_B_AS_ANP_R (1<<5) /* Bit 5: AN Page Received */ +#define PHY_B_AS_LP_ANAB (1<<4) /* Bit 4: LP AN Ability */ +#define PHY_B_AS_LP_NPAB (1<<3) /* Bit 3: LP Next Page Ability */ +#define PHY_B_AS_LS (1<<2) /* Bit 2: Link Status */ +#define PHY_B_AS_PRR (1<<1) /* Bit 1: Pause Resolution-Rx */ +#define PHY_B_AS_PRT (1<<0) /* Bit 0: Pause Resolution-Tx */ /***** PHY_BCOM_INT_STAT 16 bit ro Interrupt Status Reg *****/ /***** PHY_BCOM_INT_MASK 16 bit r/w Interrupt Mask Reg *****/ - /* Bit 15: reserved */ + /* Bit 15: reserved */ #define PHY_B_IS_PSE (1<<14) /* Bit 14: Pair Swap Error */ #define PHY_B_IS_MDXI_SC (1<<13) /* Bit 13: MDIX Status Change */ #define PHY_B_IS_HCT (1<<12) /* Bit 12: counter above 32k */ -#define PHY_B_IS_LCT (1<<11) /* Bit 11: all counter below 128 */ +#define PHY_B_IS_LCT (1<<11) /* Bit 11: counter above 128 */ #define PHY_B_IS_AN_PR (1<<10) /* Bit 10: Page Received */ -#define PHY_B_IS_NO_HDCL (1<<9) /* Bit 9: No HCD Link */ -#define PHY_B_IS_NO_HDC (1<<8) /* Bit 8: No HCD */ -#define PHY_B_IS_NEG_USHDC (1<<7) /* Bit 7: Negotiated Unsup. HCD */ -#define PHY_B_IS_SCR_S_ER (1<<6) /* Bit 6: Scrambler Sync Error */ -#define PHY_B_IS_RRS_CHANGE (1<<5) /* Bit 5: Remote Rx Stat Change */ -#define PHY_B_IS_LRS_CHANGE (1<<4) /* Bit 4: Local Rx Stat Change */ -#define PHY_B_IS_DUP_CHANGE (1<<3) /* Bit 3: Duplex Mode Change */ -#define PHY_B_IS_LSP_CHANGE (1<<2) /* Bit 2: Link Speed Change */ -#define PHY_B_IS_LST_CHANGE (1<<1) /* Bit 1: Link Status Changed */ -#define PHY_B_IS_CRC_ER (1<<0) /* Bit 0: CRC Error */ +#define PHY_B_IS_NO_HDCL (1<<9) /* Bit 9: No HCD Link */ +#define PHY_B_IS_NO_HDC (1<<8) /* Bit 8: No HCD */ +#define PHY_B_IS_NEG_USHDC (1<<7) /* Bit 7: Negotiated Unsup. HCD */ +#define PHY_B_IS_SCR_S_ER (1<<6) /* Bit 6: Scrambler Sync Error */ +#define PHY_B_IS_RRS_CHANGE (1<<5) /* Bit 5: Remote Rx Stat Change */ +#define PHY_B_IS_LRS_CHANGE (1<<4) /* Bit 4: Local Rx Stat Change */ +#define PHY_B_IS_DUP_CHANGE (1<<3) /* Bit 3: Duplex Mode Change */ +#define PHY_B_IS_LSP_CHANGE (1<<2) /* Bit 2: Link Speed Change */ +#define PHY_B_IS_LST_CHANGE (1<<1) /* Bit 1: Link Status Changed */ +#define PHY_B_IS_CRC_ER (1<<0) /* Bit 0: CRC Error */ #define PHY_B_DEF_MSK (~(PHY_B_IS_AN_PR | PHY_B_IS_LST_CHANGE)) - /* * Pause Bits (PHY_B_AN_ASP and PHY_B_AN_PC) encoding */ @@ -1005,7 +1004,7 @@ #define PHY_L_1000C_RD (1<<10) /* Bit 10: Repeater/DTE */ #define PHY_L_1000C_AFD (1<<9) /* Bit 9: Advertise Full Duplex */ #define PHY_L_1000C_AHD (1<<8) /* Bit 8: Advertise Half Duplex */ - /* Bit 7..0: reserved */ + /* Bit 7..0: reserved */ /***** PHY_LONE_1000T_STAT 16 bit ro 1000Base-T Status Reg *****/ #define PHY_L_1000S_MSF (1<<15) /* Bit 15: Master/Slave Fault */ @@ -1014,7 +1013,7 @@ #define PHY_L_1000S_RRS (1<<12) /* Bit 12: Remote Receiver Status*/ #define PHY_L_1000S_LP_FD (1<<11) /* Bit 11: Link Partner can FD */ #define PHY_L_1000S_LP_HD (1<<10) /* Bit 10: Link Partner can HD */ - /* Bit 9..8: reserved */ + /* Bit 9..8: reserved */ #define PHY_B_1000S_IEC (255<<0)/* Bit 7..0: Idle Error Count */ /***** PHY_LONE_EXT_STAT 16 bit ro Extended Status Register *****/ @@ -1022,11 +1021,11 @@ #define PHY_L_ES_X_HD_CAP (1<<14) /* Bit 14: 1000Base-X HD capable */ #define PHY_L_ES_T_FD_CAP (1<<13) /* Bit 13: 1000Base-T FD capable */ #define PHY_L_ES_T_HD_CAP (1<<12) /* Bit 12: 1000Base-T HD capable */ - /* Bit 11..0: reserved */ + /* Bit 11..0: reserved */ /***** PHY_LONE_PORT_CFG 16 bit r/w Port Configuration Reg *****/ #define PHY_L_PC_REP_MODE (1<<15) /* Bit 15: Repeater Mode */ - /* Bit 14: reserved */ + /* Bit 14: reserved */ #define PHY_L_PC_TX_DIS (1<<13) /* Bit 13: Tx output Disabled */ #define PHY_L_PC_BY_SCR (1<<12) /* Bit 12: Bypass Scrambler */ #define PHY_L_PC_BY_45 (1<<11) /* Bit 11: Bypass 4B5B-Decoder */ @@ -1049,7 +1048,7 @@ #define PHY_L_QS_COL_STAT (1<<11) /* Bit 11: Collision */ #define PHY_L_QS_L_STAT (1<<10) /* Bit 10: Link is up */ #define PHY_L_QS_DUP_MOD (1<<9) /* Bit 9: Full/Half Duplex */ -#define PHY_L_QS_AN (1<<8) /* Bit 8: AutoNeg is On */ +#define PHY_L_QS_AN (1<<8) /* Bit 8: AutoNeg is On */ #define PHY_L_QS_AN_C (1<<7) /* Bit 7: AN is Complete */ #define PHY_L_QS_LLE (7<<4) /* Bit 6: Line Length Estim. */ #define PHY_L_QS_PAUSE (1<<3) /* Bit 3: LP advertised Pause */ @@ -1059,24 +1058,24 @@ /***** PHY_LONE_INT_ENAB 16 bit r/w Interrupt Enable Reg *****/ /***** PHY_LONE_INT_STAT 16 bit ro Interrupt Status Reg *****/ - /* Bit 15..14: reserved */ + /* Bit 15..14: reserved */ #define PHY_L_IS_AN_F (1<<13) /* Bit 13: Autoneg fault */ - /* Bit 12: not described */ + /* Bit 12: not described */ #define PHY_L_IS_CROSS (1<<11) /* Bit 11: Crossover used */ #define PHY_L_IS_POL (1<<10) /* Bit 10: Polarity correct. used*/ -#define PHY_L_IS_SS (1<<9) /* Bit 9: Smart Speed Downgrade*/ +#define PHY_L_IS_SS (1<<9) /* Bit 9: Smart Speed Downgrade*/ #define PHY_L_IS_CFULL (1<<8) /* Bit 8: Counter Full */ #define PHY_L_IS_AN_C (1<<7) /* Bit 7: AutoNeg Complete */ #define PHY_L_IS_SPEED (1<<6) /* Bit 6: Speed Changed */ #define PHY_L_IS_DUP (1<<5) /* Bit 5: Duplex Changed */ -#define PHY_L_IS_LS (1<<4) /* Bit 4: Link Status Changed */ +#define PHY_L_IS_LS (1<<4) /* Bit 4: Link Status Changed */ #define PHY_L_IS_ISOL (1<<3) /* Bit 3: Isolate Occured */ #define PHY_L_IS_MDINT (1<<2) /* Bit 2: (ro) STAT: MII Int Pending */ #define PHY_L_IS_INTEN (1<<1) /* Bit 1: ENAB: Enable IRQs */ #define PHY_L_IS_FORCE (1<<0) /* Bit 0: ENAB: Force Interrupt */ -#define PHY_L_DEF_MSK (PHY_L_IS_LS | PHY_L_IS_ISOL | \ - PHY_L_IS_INTEN) /* int. mask */ +/* int. mask */ +#define PHY_L_DEF_MSK (PHY_L_IS_LS | PHY_L_IS_ISOL | PHY_L_IS_INTEN) /***** PHY_LONE_LED_CFG 16 bit r/w LED Configuration Reg *****/ #define PHY_L_LC_LEDC (3<<14) /* Bit 15..14: Col/Blink/On/Off */ @@ -1091,12 +1090,12 @@ /***** PHY_LONE_PORT_CTRL 16 bit r/w Port Control Reg *****/ #define PHY_L_PC_TX_TCLK (1<<15) /* Bit 15: Enable TX_TCLK */ - /* Bit 14: reserved */ + /* Bit 14: reserved */ #define PHY_L_PC_ALT_NP (1<<13) /* Bit 14: Alternate Next Page */ #define PHY_L_PC_GMII_ALT (1<<12) /* Bit 13: Alternate GMII driver */ - /* Bit 11: reserved */ + /* Bit 11: reserved */ #define PHY_L_PC_TEN_CRS (1<<10) /* Bit 10: Extend CRS*/ - /* Bit 9..0: not described */ + /* Bit 9..0: not described */ /***** PHY_LONE_CIM 16 bit ro CIM Reg *****/ #define PHY_L_CIM_ISOL (255<<8)/* Bit 15..8: Isolate Count */ @@ -1123,7 +1122,7 @@ #define PHY_N_1000C_AFD (1<<9) /* Bit 9: Advertise Full Duplex */ #define PHY_N_1000C_AHD (1<<8) /* Bit 8: Advertise Half Duplex */ #define PHY_N_1000C_APC (1<<7) /* Bit 7: Asymetric Pause Cap. */ - /* Bit 6..0: reserved */ + /* Bit 6..0: reserved */ /***** PHY_NAT_1000T_STAT 16 bit ro 1000Base-T Status Reg *****/ #define PHY_N_1000S_MSF (1<<15) /* Bit 15: Master/Slave Fault */ @@ -1133,7 +1132,7 @@ #define PHY_N_1000S_LP_FD (1<<11) /* Bit 11: Link Partner can FD */ #define PHY_N_1000S_LP_HD (1<<10) /* Bit 10: Link Partner can HD */ #define PHY_N_1000C_LP_APC (1<<9) /* Bit 9: LP Asym. Pause Cap. */ - /* Bit 8: reserved */ + /* Bit 8: reserved */ #define PHY_N_1000S_IEC (255<<0)/* Bit 7..0: Idle Error Count */ /***** PHY_NAT_EXT_STAT 16 bit ro Extended Status Register *****/ @@ -1141,7 +1140,7 @@ #define PHY_N_ES_X_HD_CAP (1<<14) /* Bit 14: 1000Base-X HD capable */ #define PHY_N_ES_T_FD_CAP (1<<13) /* Bit 13: 1000Base-T FD capable */ #define PHY_N_ES_T_HD_CAP (1<<12) /* Bit 12: 1000Base-T HD capable */ - /* Bit 11..0: reserved */ + /* Bit 11..0: reserved */ /* todo: those are still missing */ /***** PHY_NAT_EXT_CTRL1 16 bit ro Extended Control Reg1 *****/ diff -u --recursive --new-file v2.4.6/linux/drivers/net/sk98lin/skaddr.c linux/drivers/net/sk98lin/skaddr.c --- v2.4.6/linux/drivers/net/sk98lin/skaddr.c Fri Sep 15 14:34:19 2000 +++ linux/drivers/net/sk98lin/skaddr.c Wed Jul 4 11:50:39 2001 @@ -2,16 +2,15 @@ * * Name: skaddr.c * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.36 $ - * Date: $Date: 2000/08/07 11:10:39 $ + * Version: $Revision: 1.40 $ + * Date: $Date: 2001/02/14 14:04:59 $ * Purpose: Manage Addresses (Multicast and Unicast) and Promiscuous Mode. * ******************************************************************************/ /****************************************************************************** * - * (C)Copyright 1998-2000 SysKonnect, - * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * (C)Copyright 1998-2001 SysKonnect GmbH. * * 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 @@ -27,6 +26,18 @@ * History: * * $Log: skaddr.c,v $ + * Revision 1.40 2001/02/14 14:04:59 rassmann + * Editorial changes. + * + * Revision 1.39 2001/01/30 10:30:04 rassmann + * Editorial changes. + * + * Revision 1.38 2001/01/25 16:26:52 rassmann + * Ensured that logical address overrides are done on net's active port. + * + * Revision 1.37 2001/01/22 13:41:34 rassmann + * Supporting two nets on dual-port adapters. + * * Revision 1.36 2000/08/07 11:10:39 rassmann * Editorial changes. * @@ -172,7 +183,7 @@ #ifndef lint static const char SysKonnectFileId[] = - "@(#) $Id: skaddr.c,v 1.36 2000/08/07 11:10:39 rassmann Exp $ (C) SysKonnect."; + "@(#) $Id: skaddr.c,v 1.40 2001/02/14 14:04:59 rassmann Exp $ (C) SysKonnect."; #endif /* !defined(lint) */ #define __SKADDR_C @@ -300,7 +311,9 @@ break; case SK_INIT_IO: - pAC->Addr.ActivePort = pAC->Rlmt.MacActive; + for (i = 0; i < SK_MAX_NETS; i++) { + pAC->Addr.Net[i].ActivePort = pAC->Rlmt.Net[i].ActivePort; + } #ifdef DEBUG for (i = 0; i < SK_MAX_MACS; i++) { @@ -313,23 +326,33 @@ /* Read permanent logical MAC address from Control Register File. */ for (j = 0; j < SK_MAC_ADDR_LEN; j++) { - InAddr = (SK_U8 *)&pAC->Addr.PermanentMacAddress.a[j]; + InAddr = (SK_U8 *)&pAC->Addr.Net[0].PermanentMacAddress.a[j]; SK_IN8(IoC, B2_MAC_1 + j, InAddr); } - if (!pAC->Addr.CurrentMacAddressSet) { - /* - * Set the current logical MAC address - * to the permanent one. - */ - pAC->Addr.CurrentMacAddress = - pAC->Addr.PermanentMacAddress; - pAC->Addr.CurrentMacAddressSet = SK_TRUE; + if (!pAC->Addr.Net[0].CurrentMacAddressSet) { + /* Set the current logical MAC address to the permanent one. */ + pAC->Addr.Net[0].CurrentMacAddress = + pAC->Addr.Net[0].PermanentMacAddress; + pAC->Addr.Net[0].CurrentMacAddressSet = SK_TRUE; } /* Set the current logical MAC address. */ - pAC->Addr.Port[pAC->Addr.ActivePort].Exact[0] = - pAC->Addr.CurrentMacAddress; + pAC->Addr.Port[pAC->Addr.Net[0].ActivePort].Exact[0] = + pAC->Addr.Net[0].CurrentMacAddress; + +#if SK_MAX_NETS > 1 + /* Set logical MAC address for net 2 to (log | 3). */ + if (!pAC->Addr.Net[1].CurrentMacAddressSet) { + pAC->Addr.Net[1].PermanentMacAddress = + pAC->Addr.Net[0].PermanentMacAddress; + pAC->Addr.Net[1].PermanentMacAddress.a[5] |= 3; + /* Set the current logical MAC address to the permanent one. */ + pAC->Addr.Net[1].CurrentMacAddress = + pAC->Addr.Net[1].PermanentMacAddress; + pAC->Addr.Net[1].CurrentMacAddressSet = SK_TRUE; + } +#endif /* SK_MAX_NETS > 1 */ #ifdef xDEBUG SK_DBG_MSG( @@ -365,10 +388,7 @@ for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) { pAPort = &pAC->Addr.Port[i]; - /* - * Read permanent port addresses from - * Control Register File. - */ + /* Read permanent port addresses from Control Register File. */ for (j = 0; j < SK_MAC_ADDR_LEN; j++) { InAddr = (SK_U8 *)&pAPort->PermanentMacAddress.a[j]; SK_IN8(IoC, B2_MAC_2 + 8 * i + j, InAddr); @@ -376,9 +396,8 @@ if (!pAPort->CurrentMacAddressSet) { /* - * Set the current and previous physical - * MAC address of this port to its permanent - * MAC address. + * Set the current and previous physical MAC address + * of this port to its permanent MAC address. */ pAPort->CurrentMacAddress = pAPort->PermanentMacAddress; pAPort->PreviousMacAddress = pAPort->PermanentMacAddress; @@ -460,35 +479,35 @@ int SkAddrMcClear( SK_AC *pAC, /* adapter context */ SK_IOC IoC, /* I/O context */ -SK_U32 PortIdx, /* Index of affected port */ +SK_U32 PortNumber, /* Index of affected port */ int Flags) /* permanent/non-perm, sw-only */ { int i; - if (PortIdx >= (SK_U32)pAC->GIni.GIMacsFound) { + if (PortNumber >= (SK_U32)pAC->GIni.GIMacsFound) { return (SK_ADDR_ILLEGAL_PORT); } if (Flags & SK_ADDR_PERMANENT) { /* Clear RLMT multicast addresses. */ - pAC->Addr.Port[PortIdx].NextExactMatchRlmt = SK_ADDR_FIRST_MATCH_RLMT; + pAC->Addr.Port[PortNumber].NextExactMatchRlmt = SK_ADDR_FIRST_MATCH_RLMT; } else { /* not permanent => DRV */ /* Clear InexactFilter. */ for (i = 0; i < 8; i++) { - pAC->Addr.Port[PortIdx].InexactFilter.Bytes[i] = 0; + pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i] = 0; } /* Clear DRV multicast addresses. */ - pAC->Addr.Port[PortIdx].NextExactMatchDrv = SK_ADDR_FIRST_MATCH_DRV; + pAC->Addr.Port[PortNumber].NextExactMatchDrv = SK_ADDR_FIRST_MATCH_DRV; } if (!(Flags & SK_MC_SW_ONLY)) { - (void)SkAddrMcUpdate(pAC, IoC, PortIdx); + (void)SkAddrMcUpdate(pAC, IoC, PortNumber); } return (SK_ADDR_SUCCESS); @@ -563,7 +582,7 @@ int SkAddrMcAdd( SK_AC *pAC, /* adapter context */ SK_IOC IoC, /* I/O context */ -SK_U32 PortIdx, /* Port Index */ +SK_U32 PortNumber, /* Port Number */ SK_MAC_ADDR *pMc, /* multicast address to be added */ int Flags) /* permanent/non-permanent */ { @@ -573,56 +592,57 @@ unsigned HashBit; #endif /* !defined(SK_ADDR_CHEAT) */ - if (PortIdx >= (SK_U32)pAC->GIni.GIMacsFound) { + if (PortNumber >= (SK_U32)pAC->GIni.GIMacsFound) { return (SK_ADDR_ILLEGAL_PORT); } if (Flags & SK_ADDR_PERMANENT) { #ifdef DEBUG - if (pAC->Addr.Port[PortIdx].NextExactMatchRlmt < + if (pAC->Addr.Port[PortNumber].NextExactMatchRlmt < SK_ADDR_FIRST_MATCH_RLMT) { - Next0[PortIdx] |= 1; + Next0[PortNumber] |= 1; return (SK_MC_RLMT_OVERFLOW); } #endif /* DEBUG */ - if (pAC->Addr.Port[PortIdx].NextExactMatchRlmt > + if (pAC->Addr.Port[PortNumber].NextExactMatchRlmt > SK_ADDR_LAST_MATCH_RLMT) { return (SK_MC_RLMT_OVERFLOW); } /* Set an RLMT multicast address. */ - pAC->Addr.Port[PortIdx].Exact[ - pAC->Addr.Port[PortIdx].NextExactMatchRlmt++] = *pMc; + pAC->Addr.Port[PortNumber].Exact[ + pAC->Addr.Port[PortNumber].NextExactMatchRlmt++] = *pMc; return (SK_MC_FILTERING_EXACT); } +#if 0 /* Not PERMANENT => DRV */ - if (PortIdx != pAC->Addr.ActivePort) { - + if (PortNumber != pAC->Addr.ActivePort) { /* Only RLMT is allowed to do this. */ return (SK_MC_ILLEGAL_PORT); } +#endif /* 0 */ #ifdef DEBUG - if (pAC->Addr.Port[PortIdx].NextExactMatchDrv < + if (pAC->Addr.Port[PortNumber].NextExactMatchDrv < SK_ADDR_FIRST_MATCH_DRV) { - Next0[PortIdx] |= 2; + Next0[PortNumber] |= 2; return (SK_MC_RLMT_OVERFLOW); } #endif /* DEBUG */ - if (pAC->Addr.Port[PortIdx].NextExactMatchDrv <= SK_ADDR_LAST_MATCH_DRV) { + if (pAC->Addr.Port[PortNumber].NextExactMatchDrv <= SK_ADDR_LAST_MATCH_DRV) { /* Set exact match entry. */ - pAC->Addr.Port[PortIdx].Exact[ - pAC->Addr.Port[PortIdx].NextExactMatchDrv++] = *pMc; + pAC->Addr.Port[PortNumber].Exact[ + pAC->Addr.Port[PortNumber].NextExactMatchDrv++] = *pMc; /* Clear InexactFilter. */ for (i = 0; i < 8; i++) { - pAC->Addr.Port[PortIdx].InexactFilter.Bytes[i] = 0; + pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i] = 0; } } else { @@ -638,21 +658,21 @@ HashBit = 63 - SkCrc32McHash(&pMc->a[0]); /* Add bit to InexactFilter. */ - pAC->Addr.Port[PortIdx].InexactFilter.Bytes[HashBit / 8] |= + pAC->Addr.Port[PortNumber].InexactFilter.Bytes[HashBit / 8] |= 1 << (HashBit % 8); #else /* SK_ADDR_CHEAT */ /* Set all bits in InexactFilter. */ for (i = 0; i < 8; i++) { - pAC->Addr.Port[PortIdx].InexactFilter.Bytes[i] = 0xFF; + pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i] = 0xFF; } #endif /* SK_ADDR_CHEAT */ } for (Inexact = 0, i = 0; i < 8; i++) { - Inexact |= pAC->Addr.Port[PortIdx].InexactFilter.Bytes[i]; + Inexact |= pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i]; } - if (Inexact == 0 && pAC->Addr.Port[PortIdx].PromMode == 0) { + if (Inexact == 0 && pAC->Addr.Port[PortNumber].PromMode == 0) { return (SK_MC_FILTERING_EXACT); } else { @@ -685,7 +705,7 @@ int SkAddrMcUpdate( SK_AC *pAC, /* adapter context */ SK_IOC IoC, /* I/O context */ -SK_U32 PortIdx) /* Port Index */ +SK_U32 PortNumber) /* Port Number */ { SK_U32 i; SK_U8 Inexact; @@ -693,7 +713,7 @@ SK_U16 LoMode; /* Lower 16 bits of XMAC Mode Reg. */ SK_ADDR_PORT *pAPort; - if (PortIdx >= (SK_U32)pAC->GIni.GIMacsFound) { + if (PortNumber >= (SK_U32)pAC->GIni.GIMacsFound) { return (SK_ADDR_ILLEGAL_PORT); } @@ -701,25 +721,23 @@ pAC, SK_DBGMOD_ADDR, SK_DBGCAT_CTRL, - ("SkAddrMcUpdate on Port %u.\n", PortIdx)) + ("SkAddrMcUpdate on Port %u.\n", PortNumber)) - pAPort = &pAC->Addr.Port[PortIdx]; + pAPort = &pAC->Addr.Port[PortNumber]; #ifdef DEBUG SK_DBG_MSG( pAC, SK_DBGMOD_ADDR, SK_DBGCAT_CTRL, - ("Next0 on Port %d: %d\n", PortIdx, Next0[PortIdx])) + ("Next0 on Port %d: %d\n", PortNumber, Next0[PortNumber])) #endif /* DEBUG */ - for (i = 0; /* Also program the logical MAC address. */ - i < pAPort->NextExactMatchRlmt; - i++) { - + /* Start with 0 to also program the logical MAC address. */ + for (i = 0; i < pAPort->NextExactMatchRlmt; i++) { /* Set exact match address i on HW. */ OutAddr = (SK_U16 *)&pAPort->Exact[i].a[0]; - XM_OUTADDR(IoC, PortIdx, XM_EXM(i), OutAddr); + XM_OUTADDR(IoC, PortNumber, XM_EXM(i), OutAddr); } /* Clear other permanent exact match addresses on HW. */ @@ -727,14 +745,14 @@ SkXmClrExactAddr( pAC, IoC, - PortIdx, + PortNumber, pAPort->NextExactMatchRlmt, SK_ADDR_LAST_MATCH_RLMT); } for (i = pAPort->FirstExactMatchDrv; i < pAPort->NextExactMatchDrv; i++) { OutAddr = (SK_U16 *)&pAPort->Exact[i].a[0]; - XM_OUTADDR(IoC, PortIdx, XM_EXM(i), OutAddr); + XM_OUTADDR(IoC, PortNumber, XM_EXM(i), OutAddr); } /* Clear other non-permanent exact match addresses on HW. */ @@ -742,7 +760,7 @@ SkXmClrExactAddr( pAC, IoC, - PortIdx, + PortNumber, pAPort->NextExactMatchDrv, SK_ADDR_LAST_MATCH_DRV); } @@ -753,54 +771,52 @@ if (pAPort->PromMode & SK_PROM_MODE_ALL_MC) { /* Set all bits in 64-bit hash register. */ - XM_OUTHASH(IoC, PortIdx, XM_HSM, &OnesHash); + XM_OUTHASH(IoC, PortNumber, XM_HSM, &OnesHash); /* Set bit 15 in mode register. */ - XM_IN16(IoC, PortIdx, XM_MODE, &LoMode); + XM_IN16(IoC, PortNumber, XM_MODE, &LoMode); LoMode |= XM_MD_ENA_HSH; - XM_OUT16(IoC, PortIdx, XM_MODE, LoMode); + XM_OUT16(IoC, PortNumber, XM_MODE, LoMode); } else if (Inexact != 0) { /* Set 64-bit hash register to InexactFilter. */ - XM_OUTHASH(IoC, PortIdx, XM_HSM, &pAPort->InexactFilter.Bytes[0]); + XM_OUTHASH(IoC, PortNumber, XM_HSM, &pAPort->InexactFilter.Bytes[0]); /* Set bit 15 in mode register. */ - XM_IN16(IoC, PortIdx, XM_MODE, &LoMode); + XM_IN16(IoC, PortNumber, XM_MODE, &LoMode); LoMode |= XM_MD_ENA_HSH; - XM_OUT16(IoC, PortIdx, XM_MODE, LoMode); + XM_OUT16(IoC, PortNumber, XM_MODE, LoMode); } else { /* Clear bit 15 in mode register. */ - XM_IN16(IoC, PortIdx, XM_MODE, &LoMode); + XM_IN16(IoC, PortNumber, XM_MODE, &LoMode); LoMode &= ~XM_MD_ENA_HSH; - XM_OUT16(IoC, PortIdx, XM_MODE, LoMode); + XM_OUT16(IoC, PortNumber, XM_MODE, LoMode); } if (pAPort->PromMode != SK_PROM_MODE_NONE) { - (void)SkAddrPromiscuousChange(pAC, IoC, PortIdx, pAPort->PromMode); + (void)SkAddrPromiscuousChange(pAC, IoC, PortNumber, pAPort->PromMode); } /* Set port's current MAC address. */ OutAddr = (SK_U16 *)&pAPort->CurrentMacAddress.a[0]; - XM_OUTADDR(IoC, PortIdx, XM_SA, OutAddr); + XM_OUTADDR(IoC, PortNumber, XM_SA, OutAddr); -#ifdef DEBUG - for (i = 0; /* Also program the logical MAC address. */ - i < pAPort->NextExactMatchRlmt; - i++) { +#ifdef xDEBUG + for (i = 0; i < pAPort->NextExactMatchRlmt; i++) { SK_U8 InAddr8[6]; SK_U16 *InAddr; - /* Get exact match address i from port PortIdx. */ + /* Get exact match address i from port PortNumber. */ InAddr = (SK_U16 *)&InAddr8[0]; - XM_INADDR(IoC, PortIdx, XM_EXM(i), InAddr); + XM_INADDR(IoC, PortNumber, XM_EXM(i), InAddr); SK_DBG_MSG( pAC, - SK_DBGMOD_RLMT, + SK_DBGMOD_ADDR, SK_DBGCAT_CTRL, ("MC address %d on Port %u: %02x %02x %02x %02x %02x %02x -- %02x %02x %02x %02x %02x %02x.\n", i, - PortIdx, + PortNumber, InAddr8[0], InAddr8[1], InAddr8[2], @@ -846,52 +862,70 @@ int SkAddrOverride( SK_AC *pAC, /* adapter context */ SK_IOC IoC, /* I/O context */ -SK_U32 PortIdx, /* Port Index */ +SK_U32 PortNumber, /* Port Number */ SK_MAC_ADDR *pNewAddr, /* new MAC address */ int Flags) /* logical/physical MAC address */ { + SK_EVPARA Para; + SK_U32 NetNumber; SK_U32 i; SK_U16 *OutAddr; - SK_EVPARA Para; -#if 0 - SK_MAC_ADDR NewAddr; /* new MAC address */ - SK_U8 AddrBits; -#endif /* 0 */ - if (PortIdx >= (SK_U32)pAC->GIni.GIMacsFound) { + NetNumber = pAC->Rlmt.Port[PortNumber].Net->NetNumber; + + if (PortNumber >= (SK_U32)pAC->GIni.GIMacsFound) { return (SK_ADDR_ILLEGAL_PORT); } - if (pNewAddr->a[0] & SK_MC_BIT) { + if (pNewAddr != NULL && (pNewAddr->a[0] & SK_MC_BIT) != 0) { return (SK_ADDR_MULTICAST_ADDRESS); } -#if 0 -DANGEROUS! - if (Flags & SK_ADDR_PHYSICAL_ADDRESS) { /* Physical address. */ - if (!pAC->Addr.Port[PortIdx].CurrentMacAddressSet) { - pAC->Addr.Port[PortIdx].PreviousMacAddress = *pNewAddr; - pAC->Addr.Port[PortIdx].CurrentMacAddress = *pNewAddr; - pAC->Addr.Port[PortIdx].CurrentMacAddressSet = SK_TRUE; - return (SK_ADDR_SUCCESS); - } + if (!pAC->Addr.Net[NetNumber].CurrentMacAddressSet) { + return (SK_ADDR_TOO_EARLY); } - else { - if (!pAC->Addr.CurrentMacAddressSet) { - pAC->Addr.CurrentMacAddress = *pNewAddr; - pAC->Addr.CurrentMacAddressSet = SK_TRUE; - return (SK_ADDR_SUCCESS); + + if (Flags & SK_ADDR_SET_LOGICAL) { /* Activate logical MAC address. */ + /* Parameter *pNewAddr is ignored. */ + for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) { + if (!pAC->Addr.Port[i].CurrentMacAddressSet) { + return (SK_ADDR_TOO_EARLY); + } } - } -DANGEROUS! -#endif /* 0 */ - if (!pAC->Addr.CurrentMacAddressSet) { - return (SK_ADDR_TOO_EARLY); + /* Set PortNumber to number of net's active port. */ + PortNumber = pAC->Rlmt.Net[NetNumber]. + Port[pAC->Addr.Net[NetNumber].ActivePort]->PortNumber; + + pAC->Addr.Port[PortNumber].Exact[0] = + pAC->Addr.Net[NetNumber].CurrentMacAddress; + + /* Write address to first exact match entry of active port. */ + (void)SkAddrMcUpdate(pAC, IoC, PortNumber); } + else if (Flags & SK_ADDR_CLEAR_LOGICAL) { + /* Deactivate logical MAC address. */ + /* Parameter *pNewAddr is ignored. */ + for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) { + if (!pAC->Addr.Port[i].CurrentMacAddressSet) { + return (SK_ADDR_TOO_EARLY); + } + } + + /* Set PortNumber to number of net's active port. */ + PortNumber = pAC->Rlmt.Net[NetNumber]. + Port[pAC->Addr.Net[NetNumber].ActivePort]->PortNumber; + + for (i = 0; i < SK_MAC_ADDR_LEN; i++ ) { + pAC->Addr.Port[PortNumber].Exact[0].a[i] = 0; + } - if (Flags & SK_ADDR_PHYSICAL_ADDRESS) { /* Physical MAC address. */ - if (SK_ADDR_EQUAL(pNewAddr->a, pAC->Addr.CurrentMacAddress.a)) { + /* Write address to first exact match entry of active port. */ + (void)SkAddrMcUpdate(pAC, IoC, PortNumber); + } + else if (Flags & SK_ADDR_PHYSICAL_ADDRESS) { /* Physical MAC address. */ + if (SK_ADDR_EQUAL(pNewAddr->a, + pAC->Addr.Net[NetNumber].CurrentMacAddress.a)) { return (SK_ADDR_DUPLICATE_ADDRESS); } @@ -900,10 +934,9 @@ return (SK_ADDR_TOO_EARLY); } - if (SK_ADDR_EQUAL( - pNewAddr->a, + if (SK_ADDR_EQUAL(pNewAddr->a, pAC->Addr.Port[i].CurrentMacAddress.a)) { - if (i == PortIdx) { + if (i == PortNumber) { return (SK_ADDR_SUCCESS); } else { @@ -912,20 +945,22 @@ } } - pAC->Addr.Port[PortIdx].PreviousMacAddress = - pAC->Addr.Port[PortIdx].CurrentMacAddress; - pAC->Addr.Port[PortIdx].CurrentMacAddress = *pNewAddr; + pAC->Addr.Port[PortNumber].PreviousMacAddress = + pAC->Addr.Port[PortNumber].CurrentMacAddress; + pAC->Addr.Port[PortNumber].CurrentMacAddress = *pNewAddr; /* Change port's address. */ OutAddr = (SK_U16 *)pNewAddr; - XM_OUTADDR(IoC, PortIdx, XM_SA, OutAddr); + XM_OUTADDR(IoC, PortNumber, XM_SA, OutAddr); /* Report address change to RLMT. */ - Para.Para32[0] = PortIdx; + Para.Para32[0] = PortNumber; + Para.Para32[0] = -1; SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_PORT_ADDR, Para); } else { /* Logical MAC address. */ - if (SK_ADDR_EQUAL(pNewAddr->a, pAC->Addr.CurrentMacAddress.a)) { + if (SK_ADDR_EQUAL(pNewAddr->a, + pAC->Addr.Net[NetNumber].CurrentMacAddress.a)) { return (SK_ADDR_SUCCESS); } @@ -934,15 +969,18 @@ return (SK_ADDR_TOO_EARLY); } - if (SK_ADDR_EQUAL( - pNewAddr->a, + if (SK_ADDR_EQUAL(pNewAddr->a, pAC->Addr.Port[i].CurrentMacAddress.a)) { return (SK_ADDR_DUPLICATE_ADDRESS); } } - pAC->Addr.CurrentMacAddress = *pNewAddr; - pAC->Addr.Port[PortIdx].Exact[0] = *pNewAddr; + /* Set PortNumber to number of net's active port. */ + PortNumber = pAC->Rlmt.Net[NetNumber]. + Port[pAC->Addr.Net[NetNumber].ActivePort]->PortNumber; + + pAC->Addr.Net[NetNumber].CurrentMacAddress = *pNewAddr; + pAC->Addr.Port[PortNumber].Exact[0] = *pNewAddr; #ifdef DEBUG SK_DBG_MSG( @@ -950,27 +988,27 @@ SK_DBGMOD_ADDR, SK_DBGCAT_CTRL, ("Permanent MAC Address: %02X %02X %02X %02X %02X %02X\n", - pAC->Addr.PermanentMacAddress.a[0], - pAC->Addr.PermanentMacAddress.a[1], - pAC->Addr.PermanentMacAddress.a[2], - pAC->Addr.PermanentMacAddress.a[3], - pAC->Addr.PermanentMacAddress.a[4], - pAC->Addr.PermanentMacAddress.a[5])) + pAC->Addr.Net[NetNumber].PermanentMacAddress.a[0], + pAC->Addr.Net[NetNumber].PermanentMacAddress.a[1], + pAC->Addr.Net[NetNumber].PermanentMacAddress.a[2], + pAC->Addr.Net[NetNumber].PermanentMacAddress.a[3], + pAC->Addr.Net[NetNumber].PermanentMacAddress.a[4], + pAC->Addr.Net[NetNumber].PermanentMacAddress.a[5])) SK_DBG_MSG( pAC, SK_DBGMOD_ADDR, SK_DBGCAT_CTRL, ("New logical MAC Address: %02X %02X %02X %02X %02X %02X\n", - pAC->Addr.CurrentMacAddress.a[0], - pAC->Addr.CurrentMacAddress.a[1], - pAC->Addr.CurrentMacAddress.a[2], - pAC->Addr.CurrentMacAddress.a[3], - pAC->Addr.CurrentMacAddress.a[4], - pAC->Addr.CurrentMacAddress.a[5])) + pAC->Addr.Net[NetNumber].CurrentMacAddress.a[0], + pAC->Addr.Net[NetNumber].CurrentMacAddress.a[1], + pAC->Addr.Net[NetNumber].CurrentMacAddress.a[2], + pAC->Addr.Net[NetNumber].CurrentMacAddress.a[3], + pAC->Addr.Net[NetNumber].CurrentMacAddress.a[4], + pAC->Addr.Net[NetNumber].CurrentMacAddress.a[5])) #endif /* DEBUG */ /* Write address to first exact match entry of active port. */ - (void)SkAddrMcUpdate(pAC, IoC, PortIdx); + (void)SkAddrMcUpdate(pAC, IoC, PortNumber); } return (SK_ADDR_SUCCESS); @@ -998,7 +1036,7 @@ int SkAddrPromiscuousChange( SK_AC *pAC, /* adapter context */ SK_IOC IoC, /* I/O context */ -SK_U32 PortIdx, /* port whose promiscuous mode changes */ +SK_U32 PortNumber, /* port whose promiscuous mode changes */ int NewPromMode) /* new promiscuous mode */ { int i; @@ -1009,31 +1047,31 @@ SK_U16 LoMode; /* Lower 16 bits of XMAC Mode Register. */ int CurPromMode = SK_PROM_MODE_NONE; - if (PortIdx >= (SK_U32)pAC->GIni.GIMacsFound) { + if (PortNumber >= (SK_U32)pAC->GIni.GIMacsFound) { return (SK_ADDR_ILLEGAL_PORT); } /* Read CurPromMode from Hardware. */ - XM_IN16(IoC, PortIdx, XM_MODE, &LoMode); + XM_IN16(IoC, PortNumber, XM_MODE, &LoMode); if (LoMode & XM_MD_ENA_PROM) { CurPromMode |= SK_PROM_MODE_LLC; } for (Inexact = 0xFF, i = 0; i < 8; i++) { - Inexact &= pAC->Addr.Port[PortIdx].InexactFilter.Bytes[i]; + Inexact &= pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i]; } if (Inexact == 0xFF) { - CurPromMode |= (pAC->Addr.Port[PortIdx].PromMode & SK_PROM_MODE_ALL_MC); + CurPromMode |= (pAC->Addr.Port[PortNumber].PromMode & SK_PROM_MODE_ALL_MC); } else { /* Read InexactModeBit (bit 15 in mode register). */ - XM_IN16(IoC, PortIdx, XM_MODE, &LoMode); + XM_IN16(IoC, PortNumber, XM_MODE, &LoMode); InexactModeBit = (LoMode & XM_MD_ENA_HSH) != 0; /* Read 64-bit hash register from HW. */ - XM_INHASH(IoC, PortIdx, XM_HSM, &HwInexactFilter.Bytes[0]); + XM_INHASH(IoC, PortNumber, XM_HSM, &HwInexactFilter.Bytes[0]); for (HwInexact = 0xFF, i = 0; i < 8; i++) { HwInexact &= HwInexactFilter.Bytes[i]; @@ -1044,7 +1082,7 @@ } } - pAC->Addr.Port[PortIdx].PromMode = NewPromMode; + pAC->Addr.Port[PortNumber].PromMode = NewPromMode; if (NewPromMode == CurPromMode) { return (SK_ADDR_SUCCESS); @@ -1053,43 +1091,43 @@ if ((NewPromMode & SK_PROM_MODE_ALL_MC) && !(CurPromMode & SK_PROM_MODE_ALL_MC)) { /* All MC. */ /* Set all bits in 64-bit hash register. */ - XM_OUTHASH(IoC, PortIdx, XM_HSM, &OnesHash); + XM_OUTHASH(IoC, PortNumber, XM_HSM, &OnesHash); /* Set bit 15 in mode register. */ - XM_IN16(IoC, PortIdx, XM_MODE, &LoMode); + XM_IN16(IoC, PortNumber, XM_MODE, &LoMode); LoMode |= XM_MD_ENA_HSH; - XM_OUT16(IoC, PortIdx, XM_MODE, LoMode); + XM_OUT16(IoC, PortNumber, XM_MODE, LoMode); } else if ((CurPromMode & SK_PROM_MODE_ALL_MC) && !(NewPromMode & SK_PROM_MODE_ALL_MC)) { /* Norm MC. */ for (Inexact = 0, i = 0; i < 8; i++) { - Inexact |= pAC->Addr.Port[PortIdx].InexactFilter.Bytes[i]; + Inexact |= pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i]; } if (Inexact == 0) { /* Clear bit 15 in mode register. */ - XM_IN16(IoC, PortIdx, XM_MODE, &LoMode); + XM_IN16(IoC, PortNumber, XM_MODE, &LoMode); LoMode &= ~XM_MD_ENA_HSH; - XM_OUT16(IoC, PortIdx, XM_MODE, LoMode); + XM_OUT16(IoC, PortNumber, XM_MODE, LoMode); } else { /* Set 64-bit hash register to InexactFilter. */ XM_OUTHASH( IoC, - PortIdx, + PortNumber, XM_HSM, - &pAC->Addr.Port[PortIdx].InexactFilter.Bytes[0]); + &pAC->Addr.Port[PortNumber].InexactFilter.Bytes[0]); /* Set bit 15 in mode register. */ - XM_IN16(IoC, PortIdx, XM_MODE, &LoMode); + XM_IN16(IoC, PortNumber, XM_MODE, &LoMode); LoMode |= XM_MD_ENA_HSH; - XM_OUT16(IoC, PortIdx, XM_MODE, LoMode); + XM_OUT16(IoC, PortNumber, XM_MODE, LoMode); } } if ((NewPromMode & SK_PROM_MODE_LLC) && !(CurPromMode & SK_PROM_MODE_LLC)) { /* Prom. LLC */ /* Set promiscuous bit in mode register. */ - XM_IN16(IoC, PortIdx, XM_MODE, &LoMode); + XM_IN16(IoC, PortNumber, XM_MODE, &LoMode); #if 0 /* Receive MAC frames. */ @@ -1097,12 +1135,12 @@ #endif /* 0 */ LoMode |= XM_MD_ENA_PROM; - XM_OUT16(IoC, PortIdx, XM_MODE, LoMode); + XM_OUT16(IoC, PortNumber, XM_MODE, LoMode); } else if ((CurPromMode & SK_PROM_MODE_LLC) && !(NewPromMode & SK_PROM_MODE_LLC)) { /* Norm. LLC. */ /* Clear promiscuous bit in mode register. */ - XM_IN16(IoC, PortIdx, XM_MODE, &LoMode); + XM_IN16(IoC, PortNumber, XM_MODE, &LoMode); #if 0 /* Don't receive MAC frames. */ @@ -1110,7 +1148,7 @@ #endif /* 0 */ LoMode &= ~XM_MD_ENA_PROM; - XM_OUT16(IoC, PortIdx, XM_MODE, LoMode); + XM_OUT16(IoC, PortNumber, XM_MODE, LoMode); } return (SK_ADDR_SUCCESS); @@ -1135,19 +1173,23 @@ int SkAddrSwap( SK_AC *pAC, /* adapter context */ SK_IOC IoC, /* I/O context */ -SK_U32 FromPortIdx, /* Port1 Index */ -SK_U32 ToPortIdx) /* Port2 Index */ +SK_U32 FromPortNumber, /* Port1 Index */ +SK_U32 ToPortNumber) /* Port2 Index */ { int i; SK_U8 Byte; SK_MAC_ADDR MacAddr; SK_U32 DWord; - if (FromPortIdx >= (SK_U32)pAC->GIni.GIMacsFound) { + if (FromPortNumber >= (SK_U32)pAC->GIni.GIMacsFound) { + return (SK_ADDR_ILLEGAL_PORT); + } + + if (ToPortNumber >= (SK_U32)pAC->GIni.GIMacsFound) { return (SK_ADDR_ILLEGAL_PORT); } - if (ToPortIdx >= (SK_U32)pAC->GIni.GIMacsFound) { + if (pAC->Rlmt.Port[FromPortNumber].Net != pAC->Rlmt.Port[ToPortNumber].Net) { return (SK_ADDR_ILLEGAL_PORT); } @@ -1164,47 +1206,56 @@ */ for (i = 0; i < SK_ADDR_EXACT_MATCHES; i++) { - MacAddr = pAC->Addr.Port[FromPortIdx].Exact[i]; - pAC->Addr.Port[FromPortIdx].Exact[i] = - pAC->Addr.Port[ToPortIdx].Exact[i]; - pAC->Addr.Port[ToPortIdx].Exact[i] = MacAddr; + MacAddr = pAC->Addr.Port[FromPortNumber].Exact[i]; + pAC->Addr.Port[FromPortNumber].Exact[i] = + pAC->Addr.Port[ToPortNumber].Exact[i]; + pAC->Addr.Port[ToPortNumber].Exact[i] = MacAddr; } for (i = 0; i < 8; i++) { - Byte = pAC->Addr.Port[FromPortIdx].InexactFilter.Bytes[i]; - pAC->Addr.Port[FromPortIdx].InexactFilter.Bytes[i] = - pAC->Addr.Port[ToPortIdx].InexactFilter.Bytes[i]; - pAC->Addr.Port[ToPortIdx].InexactFilter.Bytes[i] = Byte; - } - - i = pAC->Addr.Port[FromPortIdx].PromMode; - pAC->Addr.Port[FromPortIdx].PromMode = pAC->Addr.Port[ToPortIdx].PromMode; - pAC->Addr.Port[ToPortIdx].PromMode = i; - - DWord = pAC->Addr.Port[FromPortIdx].FirstExactMatchRlmt; - pAC->Addr.Port[FromPortIdx].FirstExactMatchRlmt = - pAC->Addr.Port[ToPortIdx].FirstExactMatchRlmt; - pAC->Addr.Port[ToPortIdx].FirstExactMatchRlmt = DWord; - - DWord = pAC->Addr.Port[FromPortIdx].NextExactMatchRlmt; - pAC->Addr.Port[FromPortIdx].NextExactMatchRlmt = - pAC->Addr.Port[ToPortIdx].NextExactMatchRlmt; - pAC->Addr.Port[ToPortIdx].NextExactMatchRlmt = DWord; - - DWord = pAC->Addr.Port[FromPortIdx].FirstExactMatchDrv; - pAC->Addr.Port[FromPortIdx].FirstExactMatchDrv = - pAC->Addr.Port[ToPortIdx].FirstExactMatchDrv; - pAC->Addr.Port[ToPortIdx].FirstExactMatchDrv = DWord; - - DWord = pAC->Addr.Port[FromPortIdx].NextExactMatchDrv; - pAC->Addr.Port[FromPortIdx].NextExactMatchDrv = - pAC->Addr.Port[ToPortIdx].NextExactMatchDrv; - pAC->Addr.Port[ToPortIdx].NextExactMatchDrv = DWord; - - pAC->Addr.ActivePort = ToPortIdx; + Byte = pAC->Addr.Port[FromPortNumber].InexactFilter.Bytes[i]; + pAC->Addr.Port[FromPortNumber].InexactFilter.Bytes[i] = + pAC->Addr.Port[ToPortNumber].InexactFilter.Bytes[i]; + pAC->Addr.Port[ToPortNumber].InexactFilter.Bytes[i] = Byte; + } + + i = pAC->Addr.Port[FromPortNumber].PromMode; + pAC->Addr.Port[FromPortNumber].PromMode = pAC->Addr.Port[ToPortNumber].PromMode; + pAC->Addr.Port[ToPortNumber].PromMode = i; + + DWord = pAC->Addr.Port[FromPortNumber].FirstExactMatchRlmt; + pAC->Addr.Port[FromPortNumber].FirstExactMatchRlmt = + pAC->Addr.Port[ToPortNumber].FirstExactMatchRlmt; + pAC->Addr.Port[ToPortNumber].FirstExactMatchRlmt = DWord; + + DWord = pAC->Addr.Port[FromPortNumber].NextExactMatchRlmt; + pAC->Addr.Port[FromPortNumber].NextExactMatchRlmt = + pAC->Addr.Port[ToPortNumber].NextExactMatchRlmt; + pAC->Addr.Port[ToPortNumber].NextExactMatchRlmt = DWord; + + DWord = pAC->Addr.Port[FromPortNumber].FirstExactMatchDrv; + pAC->Addr.Port[FromPortNumber].FirstExactMatchDrv = + pAC->Addr.Port[ToPortNumber].FirstExactMatchDrv; + pAC->Addr.Port[ToPortNumber].FirstExactMatchDrv = DWord; + + DWord = pAC->Addr.Port[FromPortNumber].NextExactMatchDrv; + pAC->Addr.Port[FromPortNumber].NextExactMatchDrv = + pAC->Addr.Port[ToPortNumber].NextExactMatchDrv; + pAC->Addr.Port[ToPortNumber].NextExactMatchDrv = DWord; + + /* CAUTION: Solution works if only ports of one adapter are in use. */ + for (i = 0; (SK_U32)i < pAC->Rlmt.Net[pAC->Rlmt.Port[ToPortNumber]. + Net->NetNumber].NumPorts; i++) { + if (pAC->Rlmt.Net[pAC->Rlmt.Port[ToPortNumber].Net->NetNumber]. + Port[i]->PortNumber == ToPortNumber) { + pAC->Addr.Net[pAC->Rlmt.Port[ToPortNumber].Net->NetNumber]. + ActivePort = i; + /* 20001207 RA: Was "ToPortNumber;". */ - (void)SkAddrMcUpdate(pAC, IoC, FromPortIdx); - (void)SkAddrMcUpdate(pAC, IoC, ToPortIdx); + } + } + (void)SkAddrMcUpdate(pAC, IoC, FromPortNumber); + (void)SkAddrMcUpdate(pAC, IoC, ToPortNumber); return (SK_ADDR_SUCCESS); } /* SkAddrSwap */ diff -u --recursive --new-file v2.4.6/linux/drivers/net/sk98lin/skcsum.c linux/drivers/net/sk98lin/skcsum.c --- v2.4.6/linux/drivers/net/sk98lin/skcsum.c Fri Sep 15 14:34:19 2000 +++ linux/drivers/net/sk98lin/skcsum.c Wed Jul 4 11:50:39 2001 @@ -2,16 +2,15 @@ * * Name: skcsum.c * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.7 $ - * Date: $Date: 2000/06/29 13:17:05 $ + * Version: $Revision: 1.8 $ + * Date: $Date: 2001/02/06 11:15:36 $ * Purpose: Store/verify Internet checksum in send/receive packets. * ******************************************************************************/ /****************************************************************************** * - * (C)Copyright 1998-2000 SysKonnect, - * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * (C)Copyright 1998-2001 SysKonnect GmbH. * * 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 @@ -27,6 +26,9 @@ * History: * * $Log: skcsum.c,v $ + * Revision 1.8 2001/02/06 11:15:36 rassmann + * Supporting two nets on dual-port adapters. + * * Revision 1.7 2000/06/29 13:17:05 rassmann * Corrected reception of a packet with UDP checksum == 0 (which means there * is no UDP checksum). @@ -63,7 +65,7 @@ #ifndef lint static const char SysKonnectFileId[] = "@(#)" - "$Id: skcsum.c,v 1.7 2000/06/29 13:17:05 rassmann Exp $" + "$Id: skcsum.c,v 1.8 2001/02/06 11:15:36 rassmann Exp $" " (C) SysKonnect."; #endif /* !lint */ @@ -249,7 +251,8 @@ void SkCsGetSendInfo( SK_AC *pAc, /* Adapter context struct. */ void *pIpHeader, /* IP header. */ -SKCS_PACKET_INFO *pPacketInfo) /* Packet information struct. */ +SKCS_PACKET_INFO *pPacketInfo, /* Packet information struct. */ +int NetNumber) /* Net number */ { /* Internet Header Version found in IP header. */ unsigned InternetHeaderVersion; @@ -291,7 +294,7 @@ ("Tx: Unknown Internet Header Version %u.\n", InternetHeaderVersion)); pPacketInfo->ProtocolFlags = 0; - pAc->Csum.ProtoStats[SKCS_PROTO_STATS_IP].TxUnableCts++; + pAc->Csum.ProtoStats[NetNumber][SKCS_PROTO_STATS_IP].TxUnableCts++; return; } @@ -312,13 +315,13 @@ SK_DBG_MSG(pAc, SK_DBGMOD_CSUM, SK_DBGCAT_ERR | SK_DBGCAT_TX, ("Tx: Invalid IP Header Length %u.\n", IpHeaderLength)); pPacketInfo->ProtocolFlags = 0; - pAc->Csum.ProtoStats[SKCS_PROTO_STATS_IP].TxUnableCts++; + pAc->Csum.ProtoStats[NetNumber][SKCS_PROTO_STATS_IP].TxUnableCts++; return; } /* This is an IPv4 frame with a header of valid length. */ - pAc->Csum.ProtoStats[SKCS_PROTO_STATS_IP].TxOkCts++; + pAc->Csum.ProtoStats[NetNumber][SKCS_PROTO_STATS_IP].TxOkCts++; /* Check if we should calculate the IP header checksum. */ @@ -347,14 +350,14 @@ /* TCP/IP frame. */ ProtocolFlags &= SKCS_PROTO_TCP | SKCS_PROTO_IP; NextLevelProtoStats = - &pAc->Csum.ProtoStats[SKCS_PROTO_STATS_TCP]; + &pAc->Csum.ProtoStats[NetNumber][SKCS_PROTO_STATS_TCP]; } else if ((ProtocolFlags & SKCS_PROTO_UDP) != 0 && NextLevelProtocol == SKCS_PROTO_ID_UDP) { /* UDP/IP frame. */ ProtocolFlags &= SKCS_PROTO_UDP | SKCS_PROTO_IP; NextLevelProtoStats = - &pAc->Csum.ProtoStats[SKCS_PROTO_STATS_UDP]; + &pAc->Csum.ProtoStats[NetNumber][SKCS_PROTO_STATS_UDP]; } else { /* @@ -475,7 +478,8 @@ SK_AC *pAc, /* Adapter context struct. */ void *pIpHeader, /* IP header. */ unsigned Checksum1, /* Hardware checksum 1. */ -unsigned Checksum2) /* Hardware checksum 2. */ +unsigned Checksum2, /* Hardware checksum 2. */ +int NetNumber) /* Net number */ { /* Internet Header Version found in IP header. */ unsigned InternetHeaderVersion; @@ -522,7 +526,7 @@ SK_DBG_MSG(pAc, SK_DBGMOD_CSUM, SK_DBGCAT_ERR | SK_DBGCAT_RX, ("Rx: Unknown Internet Header Version %u.\n", InternetHeaderVersion)); - pAc->Csum.ProtoStats[SKCS_PROTO_STATS_IP].RxUnableCts++; + pAc->Csum.ProtoStats[NetNumber][SKCS_PROTO_STATS_IP].RxUnableCts++; return (SKCS_STATUS_UNKNOWN_IP_VERSION); } @@ -541,7 +545,7 @@ if (IpHeaderLength < 5*4) { SK_DBG_MSG(pAc, SK_DBGMOD_CSUM, SK_DBGCAT_ERR | SK_DBGCAT_RX, ("Rx: Invalid IP Header Length %u.\n", IpHeaderLength)); - pAc->Csum.ProtoStats[SKCS_PROTO_STATS_IP].RxErrCts++; + pAc->Csum.ProtoStats[NetNumber][SKCS_PROTO_STATS_IP].RxErrCts++; return (SKCS_STATUS_IP_CSUM_ERROR); } @@ -590,7 +594,7 @@ SKCS_IDX(pIpHeader, SKCS_OFS_IP_NEXT_LEVEL_PROTOCOL); if (IpHeaderChecksum != 0xFFFF) { - pAc->Csum.ProtoStats[SKCS_PROTO_STATS_IP].RxErrCts++; + pAc->Csum.ProtoStats[NetNumber][SKCS_PROTO_STATS_IP].RxErrCts++; /* the NDIS tester wants to know the upper level protocol too */ if (NextLevelProtocol == SKCS_PROTO_ID_TCP) { return(SKCS_STATUS_IP_CSUM_ERROR_TCP); @@ -609,15 +613,17 @@ * frame. */ - if ((pAc->Csum.ReceiveFlags & SKCS_PROTO_TCP) != 0 && + if ((pAc->Csum.ReceiveFlags[NetNumber] & SKCS_PROTO_TCP) != 0 && NextLevelProtocol == SKCS_PROTO_ID_TCP) { /* TCP/IP frame. */ - NextLevelProtoStats = &pAc->Csum.ProtoStats[SKCS_PROTO_STATS_TCP]; + NextLevelProtoStats = + &pAc->Csum.ProtoStats[NetNumber][SKCS_PROTO_STATS_TCP]; } - else if ((pAc->Csum.ReceiveFlags & SKCS_PROTO_UDP) != 0 && + else if ((pAc->Csum.ReceiveFlags[NetNumber] & SKCS_PROTO_UDP) != 0 && NextLevelProtocol == SKCS_PROTO_ID_UDP) { /* UDP/IP frame. */ - NextLevelProtoStats = &pAc->Csum.ProtoStats[SKCS_PROTO_STATS_UDP]; + NextLevelProtoStats = + &pAc->Csum.ProtoStats[NetNumber][SKCS_PROTO_STATS_UDP]; } else { /* @@ -755,11 +761,12 @@ SK_AC *pAc, /* Adapter context struct. */ unsigned ReceiveFlags, /* New receive flags. */ unsigned *pChecksum1Offset, /* Offset for hardware checksum 1. */ -unsigned *pChecksum2Offset) /* Offset for hardware checksum 2. */ +unsigned *pChecksum2Offset, /* Offset for hardware checksum 2. */ +int NetNumber) { /* Save the receive flags. */ - pAc->Csum.ReceiveFlags = ReceiveFlags; + pAc->Csum.ReceiveFlags[NetNumber] = ReceiveFlags; /* First checksum start offset is the IP header. */ *pChecksum1Offset = SKCS_MAC_HEADER_SIZE; @@ -871,23 +878,26 @@ SK_EVPARA Param) /* Event dependent parameter. */ { int ProtoIndex; + int NetNumber; switch (Event) { /* * Clear protocol statistics. * * Param - Protocol index, or -1 for all protocols. + * - Net number. */ case SK_CSUM_EVENT_CLEAR_PROTO_STATS: - ProtoIndex = (int) Param.Para32[0]; + ProtoIndex = (int)Param.Para32[0]; + NetNumber = (int)Param.Para32[1]; if (ProtoIndex < 0) { /* Clear for all protocols. */ - memset(&pAc->Csum.ProtoStats[0], 0, - sizeof(pAc->Csum.ProtoStats)); + memset(&pAc->Csum.ProtoStats[NetNumber][0], 0, + sizeof(pAc->Csum.ProtoStats[NetNumber])); } else { /* Clear for individual protocol. */ - memset(&pAc->Csum.ProtoStats[ProtoIndex], 0, - sizeof(pAc->Csum.ProtoStats[ProtoIndex])); + memset(&pAc->Csum.ProtoStats[NetNumber][ProtoIndex], 0, + sizeof(pAc->Csum.ProtoStats[NetNumber][ProtoIndex])); } break; default: diff -u --recursive --new-file v2.4.6/linux/drivers/net/sk98lin/skge.c linux/drivers/net/sk98lin/skge.c --- v2.4.6/linux/drivers/net/sk98lin/skge.c Wed Apr 18 14:40:05 2001 +++ linux/drivers/net/sk98lin/skge.c Wed Jul 4 11:50:39 2001 @@ -1,20 +1,21 @@ -;/****************************************************************************** +/****************************************************************************** * - * Name: skge.c + * Name: skge.c * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.29 $ - * Date: $Date: 2000/02/21 13:31:56 $ + * Version: $Revision: 1.29.2.6 $ + * Date: $Date: 2001/05/21 07:59:29 $ * Purpose: The main driver source module * ******************************************************************************/ /****************************************************************************** * - * (C)Copyright 1998,1999 SysKonnect, - * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * (C)Copyright 1998-2001 SysKonnect GmbH. * * Driver for SysKonnect Gigabit Ethernet Server Adapters: * + * SK-9861 (single link 1000Base-SX, VF45 Volition Plug) + * SK-9862 (dual link 1000Base-SX, VF45 Volition Plug) * SK-9841 (single link 1000Base-LX) * SK-9842 (dual link 1000Base-LX) * SK-9843 (single link 1000Base-SX) @@ -25,6 +26,7 @@ * Created 10-Feb-1999, based on Linux' acenic.c, 3c59x.c and * SysKonnects GEnesis Solaris driver * Author: Christoph Goos (cgoos@syskonnect.de) + * Mirko Lindner (mlindner@syskonnect.de) * * Address all question to: linux@syskonnect.de * @@ -46,6 +48,27 @@ * History: * * $Log: skge.c,v $ + * Revision 1.29.2.6 2001/05/21 07:59:29 mlindner + * fix: MTU init problems + * + * Revision 1.29.2.5 2001/05/08 11:25:08 mlindner + * fix: removed VLAN error message + * + * Revision 1.29.2.4 2001/05/04 13:31:43 gklug + * fix: do not handle eth_copy on bad fragments received. + * + * Revision 1.29.2.3 2001/04/23 08:06:43 mlindner + * Fix: error handling + * + * Revision 1.29.2.2 2001/03/15 12:04:54 mlindner + * Fixed memory problem + * + * Revision 1.29.2.1 2001/03/12 16:41:44 mlindner + * add: procfs function + * add: dual-net function + * add: RLMT networks + * add: extended PNMI features + * * Kernel 2.4.x specific: * Revision 1.xx 2000/09/12 13:31:56 cgoos * Fixed missign "dev=NULL in skge_probe. @@ -109,7 +132,7 @@ * Transmit descriptor polling was not reenabled after SkGePortInit. * * Revision 1.16 1999/07/27 15:17:29 cgoos - * Added some "\n" in output strings (removed while debugging...). + * Added some "\n" in output strings (removed while debuging...). * * Revision 1.15 1999/07/23 12:09:30 cgoos * Performance optimization, rx checksumming, large frame support. @@ -242,25 +265,17 @@ * ******************************************************************************/ -static const char SysKonnectFileId[] = "@(#)" __FILE__ " (C) SysKonnect."; -static const char SysKonnectBuildNumber[] = - "@(#)SK-BUILD: 3.05 (20000907) PL: 01"; +#include "h/skversion.h" #include <linux/module.h> #include <linux/init.h> +#include <linux/proc_fs.h> #include "h/skdrv1st.h" #include "h/skdrv2nd.h" /* defines ******************************************************************/ - -#define BOOT_STRING "sk98lin: Network Device Driver v3.05\n" \ - "Copyright (C) 1999-2000 SysKonnect" - -#define VER_STRING "3.05" - - -/* for debugging on x86 only */ +/* for debuging on x86 only */ /* #define BREAKPOINT() asm(" int $3"); */ /* use of a transmit complete interrupt */ @@ -292,8 +307,7 @@ // #define ROLE_A {"Auto", } // #define ROLE_B {"Auto", } // #define PREF_PORT {"A", } -// #define RLMT_MODE {"CheckLink", } - +// #define RLMT_MODE {"CheckLinkState", } #define DEV_KFREE_SKB(skb) dev_kfree_skb(skb) #define DEV_KFREE_SKB_IRQ(skb) dev_kfree_skb_irq(skb) @@ -333,7 +347,18 @@ static void SetQueueSizes(SK_AC *pAC); static int SkGeChangeMtu(struct net_device *dev, int new_mtu); static void PortReInitBmu(SK_AC*, int); -static int SkGeIocMib(SK_AC*, unsigned int, int); +static int SkGeIocMib(DEV_NET*, unsigned int, int); + + +/*Extern */ + +extern struct proc_dir_entry *pSkRootDir; + +//extern struct proc_dir_entry Our_Proc_Dir; +extern int proc_read(char *buffer, char **buffer_location, + off_t offset, int buffer_length, int *eof, void *data); + + #ifdef DEBUG static void DumpMsg(struct sk_buff*, char*); static void DumpData(char*, int); @@ -343,13 +368,27 @@ /* global variables *********************************************************/ static const char *BootString = BOOT_STRING; -static struct net_device *root_dev; +static struct net_device *root_dev = NULL; static int probed __initdata = 0; +struct inode_operations SkInodeOps; +//static struct file_operations SkFileOps; /* with open/relase */ /* local variables **********************************************************/ static uintptr_t TxQueueAddr[SK_MAX_MACS][2] = {{0x680, 0x600},{0x780, 0x700}}; static uintptr_t RxQueueAddr[SK_MAX_MACS] = {0x400, 0x480}; + + +void proc_fill_inode(struct inode *inode, int fill) +{ + if (fill) + MOD_INC_USE_COUNT; + else + MOD_DEC_USE_COUNT; +} + + + /***************************************************************************** * * skge_probe - find all SK-98xx adapters @@ -365,12 +404,14 @@ */ static int __init skge_probe (void) { - int boards_found = 0; - int version_disp = 0; + int boards_found = 0; + int version_disp = 0; SK_AC *pAC; - struct pci_dev *pdev = NULL; - unsigned long base_address; + DEV_NET *pNet = NULL; + struct pci_dev *pdev = NULL; + unsigned long base_address; struct net_device *dev = NULL; + struct proc_dir_entry *pProcFile; if (probed) return -ENODEV; @@ -388,27 +429,46 @@ if (!pci_present()) /* is PCI support present? */ return -ENODEV; + pSkRootDir = create_proc_entry("sk98lin", + S_IFDIR | S_IWUSR | S_IRUGO | S_IXUGO, proc_net); + + pSkRootDir->owner = THIS_MODULE; + while((pdev = pci_find_device(PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_GE, pdev)) != NULL) { - if (pci_enable_device(pdev)) - continue; dev = NULL; - dev = init_etherdev(dev, sizeof(SK_AC)); + pNet = NULL; + + if (pci_enable_device(pdev)) + continue; - if (dev == NULL) { + if ((dev = init_etherdev(dev, sizeof(DEV_NET))) == 0) { printk(KERN_ERR "Unable to allocate etherdev " "structure!\n"); break; } - pAC = dev->priv; + pNet = dev->priv; + pNet->pAC = kmalloc(sizeof(SK_AC), GFP_KERNEL); + if (pNet->pAC == NULL){ + kfree(dev->priv); + printk(KERN_ERR "Unable to allocate adapter " + "structure!\n"); + break; + } + + memset(pNet->pAC, 0, sizeof(SK_AC)); + pAC = pNet->pAC; pAC->PciDev = *pdev; pAC->PciDevId = pdev->device; - pAC->dev = dev; + pAC->dev[0] = dev; + pAC->dev[1] = dev; sprintf(pAC->Name, "SysKonnect SK-98xx"); pAC->CheckQueue = SK_FALSE; - + + pNet->Mtu = 1500; + pNet->Up = 0; dev->irq = pdev->irq; dev->open = &SkGeOpen; @@ -419,14 +479,20 @@ dev->set_mac_address = &SkGeSetMacAddr; dev->do_ioctl = &SkGeIoctl; dev->change_mtu = &SkGeChangeMtu; - + + pProcFile = create_proc_entry(dev->name, + S_IFREG | 0444, pSkRootDir); + pProcFile->read_proc = proc_read; + pProcFile->write_proc = NULL; + pProcFile->nlink = 1; + pProcFile->size = sizeof(dev->name+1); + pProcFile->data = (void*)pProcFile; + /* * Dummy value. */ dev->base_addr = 42; - pci_set_master(pdev); - base_address = pci_resource_start (pdev, 0); #ifdef SK_BIG_ENDIAN @@ -446,24 +512,28 @@ * Remap the regs into kernel space. */ - pAC->IoBase = (char*)ioremap(base_address, 0x4000); if (!pAC->IoBase){ printk(KERN_ERR "%s: Unable to map I/O register, " "SK 98xx No. %i will be disabled.\n", dev->name, boards_found); + kfree(dev); break; } pAC->Index = boards_found; if (SkGeBoardInit(dev, pAC)) { FreeResources(dev); + kfree(dev); continue; } - memcpy((caddr_t) &dev->dev_addr, - (caddr_t) &pAC->Addr.CurrentMacAddress, 6); - + memcpy((caddr_t) &dev->dev_addr, + (caddr_t) &pAC->Addr.Net[0].CurrentMacAddress, 6); + + pNet->PortNr = 0; + pNet->NetNr = 0; + boards_found++; /* @@ -499,10 +569,12 @@ static void FreeResources(struct net_device *dev) { SK_U32 AllocFlag; -SK_AC *pAC; +DEV_NET *pNet; +SK_AC *pAC; if (dev->priv) { - pAC = (SK_AC*) dev->priv; + pNet = (DEV_NET*) dev->priv; + pAC = pNet->pAC; AllocFlag = pAC->AllocFlag; if (AllocFlag & SK_ALLOC_IRQ) { free_irq(dev->irq, dev); @@ -517,13 +589,6 @@ } /* FreeResources */ - -static struct pci_device_id skge_pci_tbl[] __initdata = { - { PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_GE, PCI_ANY_ID, PCI_ANY_ID, }, - { } /* Terminating entry */ -}; -MODULE_DEVICE_TABLE(pci, skge_pci_tbl); - MODULE_AUTHOR("Christoph Goos <cgoos@syskonnect.de>"); MODULE_DESCRIPTION("SysKonnect SK-NET Gigabit Ethernet SK-98xx driver"); MODULE_PARM(AutoNeg_A, "1-" __MODULE_STRING(SK_MAX_CARD_PARAM) "s"); @@ -602,8 +667,8 @@ #endif -static int debug; /* not used */ -static int options[SK_MAX_CARD_PARAM]; /* not used */ +static int debug = 0; /* not used */ +static int options[SK_MAX_CARD_PARAM] = {0, }; /* not used */ /***************************************************************************** @@ -620,7 +685,6 @@ static int __init skge_init_module(void) { int cards; - root_dev = NULL; /* just to avoid warnings ... */ @@ -647,21 +711,28 @@ */ static void __exit skge_cleanup_module(void) { -SK_AC *pAC; +DEV_NET *pNet; +SK_AC *pAC; struct net_device *next; unsigned long Flags; SK_EVPARA EvPara; while (root_dev) { - pAC = (SK_AC*)root_dev->priv; + pNet = (DEV_NET*) root_dev->priv; + pAC = pNet->pAC; next = pAC->Next; netif_stop_queue(root_dev); SkGeYellowLED(pAC, pAC->IoBase, 0); - + if(pAC->BoardLevel == 2) { /* board is still alive */ spin_lock_irqsave(&pAC->SlowPathLock, Flags); + EvPara.Para32[0] = 0; + EvPara.Para32[1] = -1; + SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_STOP, EvPara); + EvPara.Para32[0] = 1; + EvPara.Para32[1] = -1; SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_STOP, EvPara); SkEventDispatcher(pAC, pAC->IoBase); /* disable interrupts */ @@ -671,15 +742,20 @@ pAC->BoardLevel = 0; /* We do NOT check here, if IRQ was pending, of course*/ } - + if(pAC->BoardLevel == 1) { /* board is still alive */ SkGeDeInit(pAC, pAC->IoBase); pAC->BoardLevel = 0; } - + + if ((pAC->GIni.GIMacsFound == 2) && pAC->RlmtNets == 2){ + unregister_netdev(pAC->dev[1]); + kfree(pAC->dev[1]); + } + FreeResources(root_dev); - + root_dev->get_stats = NULL; /* * otherwise unregister_netdev calls get_stats with @@ -687,9 +763,13 @@ */ unregister_netdev(root_dev); kfree(root_dev); - + kfree(pAC); root_dev = next; } + + /* clear proc-dir */ + remove_proc_entry(pSkRootDir->name, proc_net); + } /* skge_cleanup_module */ module_init(skge_init_module); @@ -757,8 +837,6 @@ spin_unlock_irqrestore(&pAC->SlowPathLock, Flags); - GetConfiguration(pAC); - /* level 1 init common modules here (HW init) */ spin_lock_irqsave(&pAC->SlowPathLock, Flags); if (SkGeInit(pAC, pAC->IoBase, 1) != 0) { @@ -773,6 +851,12 @@ SkRlmtInit( pAC, pAC->IoBase, 1); SkTimerInit(pAC, pAC->IoBase, 1); + GetConfiguration(pAC); + if (pAC->RlmtNets == 2) { + pAC->GIni.GIPortUsage = SK_MUL_LINK; + } + + pAC->BoardLevel = 1; spin_unlock_irqrestore(&pAC->SlowPathLock, Flags); @@ -801,7 +885,7 @@ SkCsSetReceiveFlags(pAC, SKCS_PROTO_IP | SKCS_PROTO_TCP | SKCS_PROTO_UDP, - &pAC->CsOfs1, &pAC->CsOfs2); + &pAC->CsOfs1, &pAC->CsOfs2, 0); pAC->CsOfs = (pAC->CsOfs2 << 16) | pAC->CsOfs1; BoardInitMem(pAC); @@ -814,11 +898,13 @@ /* Print configuration settings */ printk(" PrefPort:%c RlmtMode:%s\n", - 'A' + pAC->Rlmt.PrefPort, - (pAC->RlmtMode==0) ? "ChkLink" : - ((pAC->RlmtMode==1) ? "ChkLink" : - ((pAC->RlmtMode==3) ? "ChkOth" : - ((pAC->RlmtMode==7) ? "ChkSeg" : "Error")))); + 'A' + pAC->Rlmt.Net[0].Port[pAC->Rlmt.Net[0].PrefPort]->PortNumber, + (pAC->RlmtMode==0) ? "Check Link State" : + ((pAC->RlmtMode==1) ? "Check Link State" : + ((pAC->RlmtMode==3) ? "Check Local Port" : + ((pAC->RlmtMode==7) ? "Check Segmentation" : + ((pAC->RlmtMode==17) ? "Dual Check Link State" :"Error"))))); + SkGeYellowLED(pAC, pAC->IoBase, 1); @@ -1103,10 +1189,13 @@ static void SkGeIsr(int irq, void *dev_id, struct pt_regs *ptregs) { struct net_device *dev = (struct net_device *)dev_id; + +DEV_NET *pNet; SK_AC *pAC; SK_U32 IntSrc; /* interrupts source register contents */ - pAC = (SK_AC*) dev->priv; + pNet = (DEV_NET*) dev->priv; + pAC = pNet->pAC; /* * Check and process if its our interrupt @@ -1129,21 +1218,21 @@ SK_DBGCAT_DRV_INT_SRC, ("EOF RX1 IRQ\n")); ReceiveIrq(pAC, &pAC->RxPort[0]); - SK_PNMI_CNT_RX_INTR(pAC); + SK_PNMI_CNT_RX_INTR(pAC,0); } if (IntSrc & IRQ_EOF_RX2) { SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_INT_SRC, ("EOF RX2 IRQ\n")); ReceiveIrq(pAC, &pAC->RxPort[1]); - SK_PNMI_CNT_RX_INTR(pAC); + SK_PNMI_CNT_RX_INTR(pAC,1); } #ifdef USE_TX_COMPLETE /* only if tx complete interrupt used */ if (IntSrc & IRQ_EOF_AS_TX1) { SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_INT_SRC, ("EOF AS TX1 IRQ\n")); - SK_PNMI_CNT_TX_INTR(pAC); + SK_PNMI_CNT_TX_INTR(pAC,0); spin_lock(&pAC->TxPort[0][TX_PRIO_LOW].TxDesRingLock); FreeTxDescriptors(pAC, &pAC->TxPort[0][TX_PRIO_LOW]); spin_unlock(&pAC->TxPort[0][TX_PRIO_LOW].TxDesRingLock); @@ -1152,7 +1241,7 @@ SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_INT_SRC, ("EOF AS TX2 IRQ\n")); - SK_PNMI_CNT_TX_INTR(pAC); + SK_PNMI_CNT_TX_INTR(pAC,1); spin_lock(&pAC->TxPort[1][TX_PRIO_LOW].TxDesRingLock); FreeTxDescriptors(pAC, &pAC->TxPort[1][TX_PRIO_LOW]); spin_unlock(&pAC->TxPort[1][TX_PRIO_LOW].TxDesRingLock); @@ -1162,7 +1251,7 @@ SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_INT_SRC, ("EOF SY TX1 IRQ\n")); - SK_PNMI_CNT_TX_INTR(pAC); + SK_PNMI_CNT_TX_INTR(pAC,0); spin_lock(&pAC->TxPort[0][TX_PRIO_HIGH].TxDesRingLock); FreeTxDescriptors(pAC, 0, TX_PRIO_HIGH); spin_unlock(&pAC->TxPort[0][TX_PRIO_HIGH].TxDesRingLock); @@ -1172,7 +1261,7 @@ SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_INT_SRC, ("EOF SY TX2 IRQ\n")); - SK_PNMI_CNT_TX_INTR(pAC); + SK_PNMI_CNT_TX_INTR(pAC,1); spin_lock(&pAC->TxPort[1][TX_PRIO_HIGH].TxDesRingLock); FreeTxDescriptors(pAC, 1, TX_PRIO_HIGH); spin_unlock(&pAC->TxPort[1][TX_PRIO_HIGH].TxDesRingLock); @@ -1210,8 +1299,12 @@ * came in after handling the ring (OUTs may be delayed * in hardware buffers, but are through after IN) */ - ReceiveIrq(pAC, &pAC->RxPort[pAC->ActivePort]); -// ReceiveIrq(pAC, &pAC->RxPort[1]); + // ReceiveIrq(pAC, &pAC->RxPort[pAC->ActivePort]); + ReceiveIrq(pAC, &pAC->RxPort[0]); + ReceiveIrq(pAC, &pAC->RxPort[1]); + + + #if 0 // #ifdef USE_TX_COMPLETE /* only if tx complete interrupt used */ @@ -1257,10 +1350,12 @@ static void SkGeIsrOnePort(int irq, void *dev_id, struct pt_regs *ptregs) { struct net_device *dev = (struct net_device *)dev_id; +DEV_NET *pNet; SK_AC *pAC; SK_U32 IntSrc; /* interrupts source register contents */ - pAC = (SK_AC*) dev->priv; + pNet = (DEV_NET*) dev->priv; + pAC = pNet->pAC; /* * Check and process if its our interrupt @@ -1283,14 +1378,14 @@ SK_DBGCAT_DRV_INT_SRC, ("EOF RX1 IRQ\n")); ReceiveIrq(pAC, &pAC->RxPort[0]); - SK_PNMI_CNT_RX_INTR(pAC); + SK_PNMI_CNT_RX_INTR(pAC,0); } #ifdef USE_TX_COMPLETE /* only if tx complete interrupt used */ if (IntSrc & IRQ_EOF_AS_TX1) { SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_INT_SRC, ("EOF AS TX1 IRQ\n")); - SK_PNMI_CNT_TX_INTR(pAC); + SK_PNMI_CNT_TX_INTR(pAC,0); spin_lock(&pAC->TxPort[0][TX_PRIO_LOW].TxDesRingLock); FreeTxDescriptors(pAC, &pAC->TxPort[0][TX_PRIO_LOW]); spin_unlock(&pAC->TxPort[0][TX_PRIO_LOW].TxDesRingLock); @@ -1300,7 +1395,7 @@ SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_INT_SRC, ("EOF SY TX1 IRQ\n")); - SK_PNMI_CNT_TX_INTR(pAC); + SK_PNMI_CNT_TX_INTR(pAC,1); spin_lock(&pAC->TxPort[0][TX_PRIO_HIGH].TxDesRingLock); FreeTxDescriptors(pAC, 0, TX_PRIO_HIGH); spin_unlock(&pAC->TxPort[0][TX_PRIO_HIGH].TxDesRingLock); @@ -1376,12 +1471,14 @@ static int SkGeOpen( struct net_device *dev) { -SK_AC *pAC; /* pointer to adapter context struct */ +DEV_NET *pNet; +SK_AC *pAC; unsigned int Flags; /* for spin lock */ int i; -SK_EVPARA EvPara; /* an event parameter union */ +SK_EVPARA EvPara; /* an event parameter union */ - pAC = (SK_AC*) dev->priv; + pNet = (DEV_NET*) dev->priv; + pAC = pNet->pAC; SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY, ("SkGeOpen: pAC=0x%lX:\n", (unsigned long)pAC)); @@ -1389,7 +1486,7 @@ if (pAC->BoardLevel == 0) { /* level 1 init common modules here */ if (SkGeInit(pAC, pAC->IoBase, 1) != 0) { - printk("%s: HWInit(1) failed\n", pAC->dev->name); + printk("%s: HWInit(1) failed\n", pAC->dev[pNet->PortNr]->name); return (-1); } SkI2cInit (pAC, pAC->IoBase, 1); @@ -1400,26 +1497,27 @@ SkTimerInit (pAC, pAC->IoBase, 1); pAC->BoardLevel = 1; } - - /* level 2 init modules here */ - SkGeInit (pAC, pAC->IoBase, 2); - SkI2cInit (pAC, pAC->IoBase, 2); - SkEventInit (pAC, pAC->IoBase, 2); - SkPnmiInit (pAC, pAC->IoBase, 2); - SkAddrInit (pAC, pAC->IoBase, 2); - SkRlmtInit (pAC, pAC->IoBase, 2); - SkTimerInit (pAC, pAC->IoBase, 2); - pAC->BoardLevel = 2; - + + if (pAC->BoardLevel != 2) { + /* level 2 init modules here */ + SkGeInit (pAC, pAC->IoBase, 2); + SkI2cInit (pAC, pAC->IoBase, 2); + SkEventInit (pAC, pAC->IoBase, 2); + SkPnmiInit (pAC, pAC->IoBase, 2); + SkAddrInit (pAC, pAC->IoBase, 2); + SkRlmtInit (pAC, pAC->IoBase, 2); + SkTimerInit (pAC, pAC->IoBase, 2); + pAC->BoardLevel = 2; + } for (i=0; i<pAC->GIni.GIMacsFound; i++) { - // Enable transmit descriptor polling. + /* Enable transmit descriptor polling. */ SkGePollTxD(pAC, pAC->IoBase, i, SK_TRUE); FillRxRing(pAC, &pAC->RxPort[i]); } SkGeYellowLED(pAC, pAC->IoBase, 1); #ifdef USE_INT_MOD -// moderate only TX complete interrupts (these are not time critical) +/* moderate only TX complete interrupts (these are not time critical) */ #define IRQ_MOD_MASK (IRQ_EOF_AS_TX1 | IRQ_EOF_AS_TX2) { unsigned long ModBase; @@ -1435,17 +1533,29 @@ SK_OUT32(pAC->IoBase, B0_HWE_IMSK, IRQ_HWE_MASK); spin_lock_irqsave(&pAC->SlowPathLock, Flags); - SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_START, EvPara); - if (pAC->RlmtMode != 0) { + + if ((pAC->RlmtMode != 0) && (pAC->MaxPorts == 0)) { + EvPara.Para32[0] = pAC->RlmtNets; + EvPara.Para32[1] = -1; + SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_SET_NETS, + EvPara); EvPara.Para32[0] = pAC->RlmtMode; + EvPara.Para32[1] = 0; SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_MODE_CHANGE, EvPara); } + + EvPara.Para32[0] = pNet->NetNr; + EvPara.Para32[1] = -1; + SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_START, EvPara); SkEventDispatcher(pAC, pAC->IoBase); spin_unlock_irqrestore(&pAC->SlowPathLock, Flags); - + + pAC->MaxPorts++; + pNet->Up = 1; + MOD_INC_USE_COUNT; - + SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY, ("SkGeOpen suceeded\n")); @@ -1467,48 +1577,84 @@ static int SkGeClose( struct net_device *dev) { +DEV_NET *pNet; SK_AC *pAC; + unsigned int Flags; /* for spin lock */ -int i; -SK_EVPARA EvPara; +int i; +int PortIdx; +SK_EVPARA EvPara; netif_stop_queue(dev); - pAC = (SK_AC*) dev->priv; - + pNet = (DEV_NET*) dev->priv; + pAC = pNet->pAC; + + if (pAC->RlmtNets == 1) + PortIdx = pAC->ActivePort; + else + PortIdx = pNet->NetNr; + SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY, ("SkGeClose: pAC=0x%lX ", (unsigned long)pAC)); /* * Clear multicast table, promiscuous mode .... */ - SkAddrMcClear(pAC, pAC->IoBase, pAC->ActivePort, 0); - SkAddrPromiscuousChange(pAC, pAC->IoBase, pAC->ActivePort, + + SkAddrMcClear(pAC, pAC->IoBase, PortIdx, 0); + SkAddrPromiscuousChange(pAC, pAC->IoBase, PortIdx, SK_PROM_MODE_NONE); + if (pAC->MaxPorts == 1) { + spin_lock_irqsave(&pAC->SlowPathLock, Flags); + /* disable interrupts */ + SK_OUT32(pAC->IoBase, B0_IMSK, 0); + EvPara.Para32[0] = pNet->NetNr; + EvPara.Para32[1] = -1; + SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_STOP, EvPara); + SkEventDispatcher(pAC, pAC->IoBase); + SK_OUT32(pAC->IoBase, B0_IMSK, 0); + /* stop the hardware */ + SkGeDeInit(pAC, pAC->IoBase); + pAC->BoardLevel = 0; + spin_unlock_irqrestore(&pAC->SlowPathLock, Flags); + } else { - spin_lock_irqsave(&pAC->SlowPathLock, Flags); - /* disable interrupts */ - SK_OUT32(pAC->IoBase, B0_IMSK, 0); - SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_STOP, EvPara); - SkEventDispatcher(pAC, pAC->IoBase); - SK_OUT32(pAC->IoBase, B0_IMSK, 0); - /* stop the hardware */ - SkGeDeInit(pAC, pAC->IoBase); - pAC->BoardLevel = 0; - - spin_unlock_irqrestore(&pAC->SlowPathLock, Flags); - - for (i=0; i<pAC->GIni.GIMacsFound; i++) { + spin_lock_irqsave(&pAC->SlowPathLock, Flags); + EvPara.Para32[0] = pNet->NetNr; + EvPara.Para32[1] = -1; + SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_STOP, EvPara); + SkEventDispatcher(pAC, pAC->IoBase); + spin_unlock_irqrestore(&pAC->SlowPathLock, Flags); + + /* Stop port */ + spin_lock_irqsave(&pAC->TxPort[pNet->PortNr] + [TX_PRIO_LOW].TxDesRingLock, Flags); + SkGeStopPort(pAC, pAC->IoBase, pNet->PortNr, + SK_STOP_ALL, SK_HARD_RST); + spin_unlock_irqrestore(&pAC->TxPort[pNet->PortNr] + [TX_PRIO_LOW].TxDesRingLock, Flags); + } + if (pAC->RlmtNets == 1) { /* clear all descriptor rings */ - ReceiveIrq(pAC, &pAC->RxPort[i]); - ClearRxRing(pAC, &pAC->RxPort[i]); - ClearTxRing(pAC, &pAC->TxPort[i][TX_PRIO_LOW]); + for (i=0; i<pAC->GIni.GIMacsFound; i++) { + ReceiveIrq(pAC, &pAC->RxPort[i]); + ClearRxRing(pAC, &pAC->RxPort[i]); + ClearTxRing(pAC, &pAC->TxPort[i][TX_PRIO_LOW]); + } + } else { + /* clear port descriptor rings */ + ReceiveIrq(pAC, &pAC->RxPort[pNet->PortNr]); + ClearRxRing(pAC, &pAC->RxPort[pNet->PortNr]); + ClearTxRing(pAC, &pAC->TxPort[pNet->PortNr][TX_PRIO_LOW]); } SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY, ("SkGeClose: done ")); + pAC->MaxPorts--; + pNet->Up = 0; MOD_DEC_USE_COUNT; return (0); @@ -1531,12 +1677,17 @@ */ static int SkGeXmit(struct sk_buff *skb, struct net_device *dev) { +DEV_NET *pNet; SK_AC *pAC; -int Rc; /* return code of XmitFrame */ +int Rc; /* return code of XmitFrame */ - pAC = (SK_AC*) dev->priv; + pNet = (DEV_NET*) dev->priv; + pAC = pNet->pAC; - Rc = XmitFrame(pAC, &pAC->TxPort[pAC->ActivePort][TX_PRIO_LOW], skb); + if (pAC->RlmtNets == 2) + Rc = XmitFrame(pAC, &pAC->TxPort[pNet->PortNr][TX_PRIO_LOW], skb); + else + Rc = XmitFrame(pAC, &pAC->TxPort[pAC->ActivePort][TX_PRIO_LOW], skb); /* Transmitter out of resources? */ if (Rc <= 0) @@ -1551,7 +1702,7 @@ dev->trans_start = jiffies; return (0); } /* SkGeXmit */ - + /***************************************************************************** * @@ -1570,10 +1721,10 @@ * if necessary. * * Returns: - * > 0 - on succes: the number of bytes in the message - * = 0 - on resource shortage: this frame sent or dropped, now + * > 0 - on succes: the number of bytes in the message + * = 0 - on resource shortage: this frame sent or dropped, now * the ring is full ( -> set tbusy) - * < 0 - on failure: other problems ( -> return failure to upper layers) + * < 0 - on failure: other problems ( -> return failure to upper layers) */ static int XmitFrame( SK_AC *pAC, /* pointer to adapter context */ @@ -1595,7 +1746,7 @@ FreeTxDescriptors(pAC, pTxPort); if (pTxPort->TxdRingFree == 0) { spin_unlock_irqrestore(&pTxPort->TxDesRingLock, Flags); - SK_PNMI_CNT_NO_TX_BUF(pAC); + SK_PNMI_CNT_NO_TX_BUF(pAC, pTxPort->PortIndex); SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_TX_PROGRESS, ("XmitFrame failed\n")); @@ -1699,13 +1850,13 @@ * freed ( -> ring completely free now). */ pTxPort->pTxdRingTail = pTxd; - netif_start_queue(pAC->dev); + netif_start_queue(pAC->dev[pTxPort->PortIndex]); return; } if (Control & TX_CTRL_OWN_BMU) { pTxPort->pTxdRingTail = pTxd; if (pTxPort->TxdRingFree > 0) { - netif_start_queue(pAC->dev); + netif_start_queue(pAC->dev[pTxPort->PortIndex]); } return; } @@ -1784,8 +1935,8 @@ SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY, ("%s: Allocation of rx buffer failed !\n", - pAC->dev->name)); - SK_PNMI_CNT_NO_RX_BUF(pAC); + pAC->dev[pRxPort->PortIndex]->name)); + SK_PNMI_CNT_NO_RX_BUF(pAC, pRxPort->PortIndex); return(SK_FALSE); } skb_reserve(pMsgBlock, 2); /* to align IP frames */ @@ -1877,64 +2028,110 @@ int Result; SK_U64 PhysAddr; - rx_start: /* do forever; exit if RX_CTRL_OWN_BMU found */ - while (pRxPort->RxdRingFree < pAC->RxDescrPerRing) { - pRxd = pRxPort->pRxdRingHead; - + for ( pRxd = pRxPort->pRxdRingHead ; + pRxPort->RxdRingFree < pAC->RxDescrPerRing ; + pRxd = pRxd->pNextRxd, + pRxPort->pRxdRingHead = pRxd, + pRxPort->RxdRingFree ++) { + + /* + * For a better understanding of this loop + * Go through every descriptor beginning at the head + * Please note: the ring might be completely received so the OWN bit + * set is not a good crirteria to leave that loop. + * Therefore the RingFree counter is used. + * On entry of this loop pRxd is a pointer to the Rxd that needs + * to be checked next. + */ + Control = pRxd->RBControl; - + /* check if this descriptor is ready */ if ((Control & RX_CTRL_OWN_BMU) != 0) { /* this descriptor is not yet ready */ + /* This is the usual end of the loop */ + /* We don't need to start the ring again */ FillRxRing(pAC, pRxPort); return; } - + /* get length of frame and check it */ FrameLength = Control & RX_CTRL_LEN_MASK; - if (FrameLength > pAC->RxBufSize) + if (FrameLength > pAC->RxBufSize) { goto rx_failed; + } /* check for STF and EOF */ if ((Control & (RX_CTRL_STF | RX_CTRL_EOF)) != - (RX_CTRL_STF | RX_CTRL_EOF)) + (RX_CTRL_STF | RX_CTRL_EOF)) { goto rx_failed; + } /* here we have a complete frame in the ring */ pMsg = pRxd->pMBuf; + + FrameStat = pRxd->FrameStat; + SK_DBG_MSG(NULL, SK_DBGMOD_DRV, 0, + ("Received frame of length %d on port %d\n", + FrameLength, PortIndex)); + SK_DBG_MSG(NULL, SK_DBGMOD_DRV, 0, + ("Number of free rx descriptors: %d\n", + pRxPort->RxdRingFree)); + /*DumpMsg(pMsg, "Rx"); */ + if ((Control & RX_CTRL_STAT_VALID) != RX_CTRL_STAT_VALID || + (FrameStat & (XMR_FS_ANY_ERR | XMR_FS_2L_VLAN)) != 0) { + /* there is a receive error in this frame */ + SK_DBG_MSG(NULL, SK_DBGMOD_DRV, + SK_DBGCAT_DRV_RX_PROGRESS, + ("skge: Error in received frame, dropped!\n" + "Control: %x\nRxStat: %x\n", + Control, FrameStat)); + PhysAddr = ((SK_U64) pRxd->VDataHigh) << (SK_U64)32; + PhysAddr |= (SK_U64) pRxd->VDataLow; + pci_dma_sync_single(&pAC->PciDev, + (dma_addr_t) PhysAddr, + FrameLength, + PCI_DMA_FROMDEVICE); + ReQueueRxBuffer(pAC, pRxPort, pMsg, + pRxd->VDataHigh, pRxd->VDataLow); + + continue; + } + /* * if short frame then copy data to reduce memory waste */ - pNewMsg = NULL; - if (FrameLength < SK_COPY_THRESHOLD) { - pNewMsg = alloc_skb(FrameLength+2, GFP_ATOMIC); - if (pNewMsg != NULL) { - PhysAddr = ((SK_U64) pRxd->VDataHigh) << (SK_U64)32; - PhysAddr |= (SK_U64) pRxd->VDataLow; - - /* use new skb and copy data */ - skb_reserve(pNewMsg, 2); - skb_put(pNewMsg, FrameLength); - pci_dma_sync_single(&pAC->PciDev, - (dma_addr_t) PhysAddr, - FrameLength, - PCI_DMA_FROMDEVICE); - eth_copy_and_sum(pNewMsg, pMsg->data, - FrameLength, 0); - ReQueueRxBuffer(pAC, pRxPort, pMsg, - pRxd->VDataHigh, pRxd->VDataLow); - pMsg = pNewMsg; - } + if ((FrameLength < SK_COPY_THRESHOLD) && + ((pNewMsg = alloc_skb(FrameLength+2, GFP_ATOMIC)) != NULL)) { + /* + * Short frame detected and allocation successfull + */ + PhysAddr = ((SK_U64) pRxd->VDataHigh) << (SK_U64)32; + PhysAddr |= (SK_U64) pRxd->VDataLow; + + /* use new skb and copy data */ + skb_reserve(pNewMsg, 2); + skb_put(pNewMsg, FrameLength); + pci_dma_sync_single(&pAC->PciDev, + (dma_addr_t) PhysAddr, + FrameLength, + PCI_DMA_FROMDEVICE); + eth_copy_and_sum(pNewMsg, pMsg->data, + FrameLength, 0); + ReQueueRxBuffer(pAC, pRxPort, pMsg, + pRxd->VDataHigh, pRxd->VDataLow); + pMsg = pNewMsg; + } + else { + /* + * if large frame, or SKB allocation failed, pass + * the SKB directly to the networking + */ - /* - * if large frame, or SKB allocation failed, pass - * the SKB directly to the networking - */ - if (pNewMsg == NULL) { PhysAddr = ((SK_U64) pRxd->VDataHigh) << (SK_U64)32; PhysAddr |= (SK_U64) pRxd->VDataLow; @@ -1954,7 +2151,7 @@ if ((Csum1 & 0xfffe) && (Csum2 & 0xfffe)) { Result = SkCsGetReceiveInfo(pAC, &pMsg->data[14], - Csum1, Csum2); + Csum1, Csum2, pRxPort->PortIndex); if (Result == SKCS_STATUS_IP_FRAGMENT || Result == @@ -1970,123 +2167,85 @@ } /* IP frame */ } /* frame > SK_COPY_TRESHOLD */ - FrameStat = pRxd->FrameStat; - if ((FrameStat & XMR_FS_LNG_ERR) != 0) { - /* jumbo frame, count to correct statistic */ - SK_PNMI_CNT_RX_LONGFRAMES(pAC, pRxPort->PortIndex); - } - pRxd = pRxd->pNextRxd; - pRxPort->pRxdRingHead = pRxd; - pRxPort->RxdRingFree ++; - SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_RX_PROGRESS, - ("Received frame of length %d on port %d\n", - FrameLength, PortIndex)); - SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_RX_PROGRESS, - ("Number of free rx descriptors: %d\n", - pRxPort->RxdRingFree)); - - if ((Control & RX_CTRL_STAT_VALID) == RX_CTRL_STAT_VALID && - (FrameStat & XMR_FS_ANY_ERR) == 0) { - // was the following, changed to allow VLAN support - // (XMR_FS_ANY_ERR | XMR_FS_1L_VLAN | XMR_FS_2L_VLAN) - SK_DBG_MSG(NULL, SK_DBGMOD_DRV, - SK_DBGCAT_DRV_RX_PROGRESS,("V")); - ForRlmt = SK_RLMT_RX_PROTOCOL; - IsBc = (FrameStat & XMR_FS_BC)==XMR_FS_BC; - SK_RLMT_PRE_LOOKAHEAD(pAC, PortIndex, FrameLength, - IsBc, &Offset, &NumBytes); - if (NumBytes != 0) { - IsMc = (FrameStat & XMR_FS_MC)==XMR_FS_MC; - SK_RLMT_LOOKAHEAD(pAC, PortIndex, - &pMsg->data[Offset], - IsBc, IsMc, &ForRlmt); + SK_DBG_MSG(NULL, SK_DBGMOD_DRV, 1,("V")); + ForRlmt = SK_RLMT_RX_PROTOCOL; + IsBc = (FrameStat & XMR_FS_BC)==XMR_FS_BC; + SK_RLMT_PRE_LOOKAHEAD(pAC, PortIndex, FrameLength, + IsBc, &Offset, &NumBytes); + if (NumBytes != 0) { + IsMc = (FrameStat & XMR_FS_MC)==XMR_FS_MC; + SK_RLMT_LOOKAHEAD(pAC, PortIndex, + &pMsg->data[Offset], + IsBc, IsMc, &ForRlmt); + } + if (ForRlmt == SK_RLMT_RX_PROTOCOL) { + SK_DBG_MSG(NULL, SK_DBGMOD_DRV, 1,("W")); + /* send up only frames from active port */ + if ((PortIndex == pAC->ActivePort) || + (pAC->RlmtNets == 2)) { + /* frame for upper layer */ + SK_DBG_MSG(NULL, SK_DBGMOD_DRV, 1,("U")); +#ifdef xDEBUG + DumpMsg(pMsg, "Rx"); +#endif + SK_PNMI_CNT_RX_OCTETS_DELIVERED(pAC, + FrameLength, pRxPort->PortIndex); + + pMsg->dev = pAC->dev[pRxPort->PortIndex]; + pMsg->protocol = eth_type_trans(pMsg, + pAC->dev[pRxPort->PortIndex]); + netif_rx(pMsg); + pAC->dev[pRxPort->PortIndex]->last_rx = jiffies; } - if (ForRlmt == SK_RLMT_RX_PROTOCOL) { - /* send up only frames from active port */ - if (PortIndex == pAC->ActivePort) { - /* frame for upper layer */ - SK_DBG_MSG(NULL, SK_DBGMOD_DRV, - SK_DBGCAT_DRV_RX_PROGRESS, - ("U")); -#ifdef DUMP_RX - DumpMsg(pMsg, "Rx"); -#endif - pMsg->dev = pAC->dev; - pMsg->protocol = eth_type_trans(pMsg, - pAC->dev); - SK_PNMI_CNT_RX_OCTETS_DELIVERED(pAC, - FrameLength); - netif_rx(pMsg); - pAC->dev->last_rx = jiffies; - } - else { - /* drop frame */ - SK_DBG_MSG(NULL, SK_DBGMOD_DRV, - SK_DBGCAT_DRV_RX_PROGRESS, - ("D")); - DEV_KFREE_SKB_IRQ(pMsg); - } - } /* if not for rlmt */ else { - /* packet for rlmt */ + /* drop frame */ SK_DBG_MSG(NULL, SK_DBGMOD_DRV, - SK_DBGCAT_DRV_RX_PROGRESS, ("R")); - pRlmtMbuf = SkDrvAllocRlmtMbuf(pAC, - pAC->IoBase, FrameLength); - if (pRlmtMbuf != NULL) { - pRlmtMbuf->pNext = NULL; - pRlmtMbuf->Length = FrameLength; - pRlmtMbuf->PortIdx = PortIndex; - EvPara.pParaPtr = pRlmtMbuf; - memcpy((char*)(pRlmtMbuf->pData), - (char*)(pMsg->data), - FrameLength); - SkEventQueue(pAC, SKGE_RLMT, - SK_RLMT_PACKET_RECEIVED, - EvPara); - pAC->CheckQueue = SK_TRUE; - SK_DBG_MSG(NULL, SK_DBGMOD_DRV, - SK_DBGCAT_DRV_RX_PROGRESS, - ("Q")); - } - if ((pAC->dev->flags & - (IFF_PROMISC | IFF_ALLMULTI)) != 0 || - (ForRlmt & SK_RLMT_RX_PROTOCOL) == - SK_RLMT_RX_PROTOCOL) { - pMsg->dev = pAC->dev; - pMsg->protocol = eth_type_trans(pMsg, - pAC->dev); - netif_rx(pMsg); - pAC->dev->last_rx = jiffies; - } - else { - DEV_KFREE_SKB_IRQ(pMsg); - } - - } /* if packet for rlmt */ - } /* if valid frame */ + SK_DBGCAT_DRV_RX_PROGRESS, + ("D")); + DEV_KFREE_SKB(pMsg); + } + + } /* if not for rlmt */ else { - /* there is a receive error in this frame */ - if ((FrameStat & XMR_FS_1L_VLAN) != 0) { - printk("%s: Received frame" - " with VLAN Level 1 header, check" - " switch configuration\n", - pAC->dev->name); + /* packet for rlmt */ + SK_DBG_MSG(NULL, SK_DBGMOD_DRV, + SK_DBGCAT_DRV_RX_PROGRESS, ("R")); + pRlmtMbuf = SkDrvAllocRlmtMbuf(pAC, + pAC->IoBase, FrameLength); + if (pRlmtMbuf != NULL) { + pRlmtMbuf->pNext = NULL; + pRlmtMbuf->Length = FrameLength; + pRlmtMbuf->PortIdx = PortIndex; + EvPara.pParaPtr = pRlmtMbuf; + memcpy((char*)(pRlmtMbuf->pData), + (char*)(pMsg->data), + FrameLength); + SkEventQueue(pAC, SKGE_RLMT, + SK_RLMT_PACKET_RECEIVED, + EvPara); + pAC->CheckQueue = SK_TRUE; + SK_DBG_MSG(NULL, SK_DBGMOD_DRV, + SK_DBGCAT_DRV_RX_PROGRESS, + ("Q")); } - if ((FrameStat & XMR_FS_2L_VLAN) != 0) { - printk("%s: Received frame" - " with VLAN Level 2 header, check" - " switch configuration\n", - pAC->dev->name); + if ((pAC->dev[pRxPort->PortIndex]->flags & + (IFF_PROMISC | IFF_ALLMULTI)) != 0 || + (ForRlmt & SK_RLMT_RX_PROTOCOL) == + SK_RLMT_RX_PROTOCOL) { + pMsg->dev = pAC->dev[pRxPort->PortIndex]; + pMsg->protocol = eth_type_trans(pMsg, + pAC->dev[pRxPort->PortIndex]); + netif_rx(pMsg); + pAC->dev[pRxPort->PortIndex]->last_rx = jiffies; } - SK_DBG_MSG(NULL, SK_DBGMOD_DRV, - SK_DBGCAT_DRV_RX_PROGRESS, - ("skge: Error in received frame, dropped!\n" - "Control: %x\nRxStat: %x\n", - Control, FrameStat)); - DEV_KFREE_SKB_IRQ(pMsg); - } - } /* while */ + else { + DEV_KFREE_SKB(pMsg); + } + + } /* if packet for rlmt */ + } /* for ... scanning the RXD ring */ + + /* RXD ring is empty -> fill and restart */ FillRxRing(pAC, pRxPort); /* do not start if called from Close */ if (pAC->BoardLevel > 0) { @@ -2254,6 +2413,7 @@ int RxRam; /* RAM used for the active port receive queue */ int i; /* loop counter */ +if (pAC->RlmtNets == 1) { StandbyRam = SK_RLMT_STANDBY_QRXSIZE + SK_RLMT_STANDBY_QXASIZE + SK_RLMT_STANDBY_QXSSIZE; RemainingRam = pAC->GIni.GIRamSize - @@ -2274,21 +2434,40 @@ SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY, ("queue sizes settings - rx:%d txA:%d txS:%d\n", pAC->RxQueueSize,pAC->TxAQueueSize, pAC->TxSQueueSize)); +} else { + RemainingRam = pAC->GIni.GIRamSize/pAC->GIni.GIMacsFound; + RxRam = (RemainingRam * 8 / 10) & ~7; + for (i=0; i<pAC->GIni.GIMacsFound; i++) { + pAC->GIni.GP[i].PRxQSize = RxRam; + pAC->GIni.GP[i].PXSQSize = 0; + pAC->GIni.GP[i].PXAQSize = (RemainingRam - RxRam) & ~7; + } + pAC->RxQueueSize = RxRam; + pAC->TxSQueueSize = 0; + pAC->TxAQueueSize = (RemainingRam - RxRam) & ~7; +} for (i=0; i<SK_MAX_MACS; i++) { pAC->RxPort[i].RxFillLimit = pAC->RxDescrPerRing; } - for (i=0; i<pAC->GIni.GIMacsFound; i++) { - pAC->RxPort[i].RxFillLimit = pAC->RxDescrPerRing - 100; + + if (pAC->RlmtNets == 2) { + for (i=0; i<pAC->GIni.GIMacsFound; i++) { + pAC->RxPort[i].RxFillLimit = pAC->RxDescrPerRing - 100; + } + } else { + for (i=0; i<pAC->GIni.GIMacsFound; i++) { + pAC->RxPort[i].RxFillLimit = pAC->RxDescrPerRing - 100; + } + /* + * Do not set the Limit to 0, because this could cause + * wrap around with ReQueue'ed buffers (a buffer could + * be requeued in the same position, made accessable to + * the hardware, and the hardware could change its + * contents! + */ + pAC->RxPort[pAC->ActivePort].RxFillLimit = 1; } - /* - * Do not set the Limit to 0, because this could cause - * wrap around with ReQueue'ed buffers (a buffer could - * be requeued in the same position, made accessable to - * the hardware, and the hardware could change its - * contents! - */ - pAC->RxPort[pAC->ActivePort].RxFillLimit = 1; #ifdef DEBUG for (i=0; i<pAC->GIni.GIMacsFound; i++) { @@ -2316,7 +2495,10 @@ */ static int SkGeSetMacAddr(struct net_device *dev, void *p) { -SK_AC *pAC = (SK_AC*) dev->priv; + +DEV_NET *pNet = (DEV_NET*) dev->priv; +SK_AC *pAC = pNet->pAC; + struct sockaddr *addr = p; unsigned int Flags; @@ -2328,8 +2510,15 @@ memcpy(dev->dev_addr, addr->sa_data,dev->addr_len); spin_lock_irqsave(&pAC->SlowPathLock, Flags); - SkAddrOverride(pAC, pAC->IoBase, pAC->ActivePort, - (SK_MAC_ADDR*)dev->dev_addr, SK_ADDR_VIRTUAL_ADDRESS); + + if (pAC->RlmtNets == 2) + SkAddrOverride(pAC, pAC->IoBase, pNet->NetNr, + (SK_MAC_ADDR*)dev->dev_addr, SK_ADDR_VIRTUAL_ADDRESS); + else + SkAddrOverride(pAC, pAC->IoBase, pAC->ActivePort, + (SK_MAC_ADDR*)dev->dev_addr, SK_ADDR_VIRTUAL_ADDRESS); + + spin_unlock_irqrestore(&pAC->SlowPathLock, Flags); return 0; @@ -2352,37 +2541,47 @@ */ static void SkGeSetRxMode(struct net_device *dev) { -SK_AC *pAC; + +DEV_NET *pNet; +SK_AC *pAC; + struct dev_mc_list *pMcList; int i; +int PortIdx; unsigned int Flags; SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY, ("SkGeSetRxMode starts now... ")); - pAC = (SK_AC*) dev->priv; - + + pNet = (DEV_NET*) dev->priv; + pAC = pNet->pAC; + if (pAC->RlmtNets == 1) + PortIdx = pAC->ActivePort; + else + PortIdx = pNet->NetNr; + spin_lock_irqsave(&pAC->SlowPathLock, Flags); if (dev->flags & IFF_PROMISC) { SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY, ("PROMISCUOUS mode\n")); - SkAddrPromiscuousChange(pAC, pAC->IoBase, pAC->ActivePort, + SkAddrPromiscuousChange(pAC, pAC->IoBase, PortIdx, SK_PROM_MODE_LLC); } else if (dev->flags & IFF_ALLMULTI) { SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY, ("ALLMULTI mode\n")); - SkAddrPromiscuousChange(pAC, pAC->IoBase, pAC->ActivePort, + SkAddrPromiscuousChange(pAC, pAC->IoBase, PortIdx, SK_PROM_MODE_ALL_MC); } else { - SkAddrPromiscuousChange(pAC, pAC->IoBase, pAC->ActivePort, + SkAddrPromiscuousChange(pAC, pAC->IoBase, PortIdx, SK_PROM_MODE_NONE); - SkAddrMcClear(pAC, pAC->IoBase, pAC->ActivePort, 0); + SkAddrMcClear(pAC, pAC->IoBase, PortIdx, 0); SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY, ("Number of MC entries: %d ", dev->mc_count)); pMcList = dev->mc_list; for (i=0; i<dev->mc_count; i++, pMcList = pMcList->next) { - SkAddrMcAdd(pAC, pAC->IoBase, pAC->ActivePort, + SkAddrMcAdd(pAC, pAC->IoBase, PortIdx, (SK_MAC_ADDR*)pMcList->dmi_addr, 0); SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_MCA, ("%02x:%02x:%02x:%02x:%02x:%02x\n", @@ -2393,7 +2592,7 @@ pMcList->dmi_addr[4], pMcList->dmi_addr[5])); } - SkAddrMcUpdate(pAC, pAC->IoBase, pAC->ActivePort); + SkAddrMcUpdate(pAC, pAC->IoBase, PortIdx); } spin_unlock_irqrestore(&pAC->SlowPathLock, Flags); @@ -2417,6 +2616,8 @@ */ static int SkGeChangeMtu(struct net_device *dev, int NewMtu) { +DEV_NET *pNet; +DEV_NET *pOtherNet; SK_AC *pAC; unsigned int Flags; int i; @@ -2424,30 +2625,58 @@ SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY, ("SkGeChangeMtu starts now...\n")); - - pAC = (SK_AC*) dev->priv; + + pNet = (DEV_NET*) dev->priv; + pAC = pNet->pAC; + if ((NewMtu < 68) || (NewMtu > SK_JUMBO_MTU)) { return -EINVAL; } + pNet->Mtu = NewMtu; + pOtherNet = (DEV_NET*)pAC->dev[1 - pNet->NetNr]->priv; + if ((pOtherNet->Mtu > 1500) && (NewMtu <= 1500) && (pOtherNet->Up==1)) { + return(0); + } + + EvPara.Para32[0] = pNet->NetNr; + EvPara.Para32[1] = -1; + pAC->RxBufSize = NewMtu + 32; dev->mtu = NewMtu; SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY, ("New MTU: %d\n", NewMtu)); + if(pAC->BoardLevel != 2) { + return 0; + } + /* prevent reconfiguration while changing the MTU */ /* disable interrupts */ SK_OUT32(pAC->IoBase, B0_IMSK, 0); spin_lock_irqsave(&pAC->SlowPathLock, Flags); - SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_STOP, EvPara); + + /* Found more than one port */ + if ((pAC->GIni.GIMacsFound == 2 ) && + (pAC->RlmtNets == 2)) { + /* Stop both ports */ + EvPara.Para32[0] = 0; + SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_STOP, EvPara); + EvPara.Para32[0] = 1; + SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_STOP, EvPara); + } else { + SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_STOP, EvPara); + } + SkEventDispatcher(pAC, pAC->IoBase); for (i=0; i<pAC->GIni.GIMacsFound; i++) { - spin_lock(&pAC->TxPort[i][TX_PRIO_LOW].TxDesRingLock); + spin_lock_irqsave( + &pAC->TxPort[i][TX_PRIO_LOW].TxDesRingLock, Flags); + netif_stop_queue(pAC->dev[i]); } - netif_stop_queue(pAC->dev); /* * adjust number of rx buffers allocated @@ -2455,23 +2684,35 @@ if (NewMtu > 1500) { /* use less rx buffers */ for (i=0; i<pAC->GIni.GIMacsFound; i++) { - if (i == pAC->ActivePort) - pAC->RxPort[i].RxFillLimit = - pAC->RxDescrPerRing - 100; - else - pAC->RxPort[i].RxFillLimit = - pAC->RxDescrPerRing - 10; - + /* Found more than one port */ + if ((pAC->GIni.GIMacsFound == 2 ) && + (pAC->RlmtNets == 2)) { + pAC->RxPort[i].RxFillLimit = + pAC->RxDescrPerRing - 100; + } else { + if (i == pAC->ActivePort) + pAC->RxPort[i].RxFillLimit = + pAC->RxDescrPerRing - 100; + else + pAC->RxPort[i].RxFillLimit = + pAC->RxDescrPerRing - 10; + } } } else { /* use normal anoumt of rx buffers */ for (i=0; i<pAC->GIni.GIMacsFound; i++) { - if (i == pAC->ActivePort) - pAC->RxPort[i].RxFillLimit = 1; - else - pAC->RxPort[i].RxFillLimit = - pAC->RxDescrPerRing - 100; + /* Found more than one port */ + if ((pAC->GIni.GIMacsFound == 2 ) && + (pAC->RlmtNets == 2)) { + pAC->RxPort[i].RxFillLimit = 1; + } else { + if (i == pAC->ActivePort) + pAC->RxPort[i].RxFillLimit = 1; + else + pAC->RxPort[i].RxFillLimit = + pAC->RxDescrPerRing - 100; + } } } @@ -2481,6 +2722,7 @@ * enable/disable hardware support for long frames */ if (NewMtu > 1500) { +// pAC->JumboActivated = SK_TRUE; /* is never set back !!! */ pAC->GIni.GIPortUsage = SK_JUMBO_LINK; for (i=0; i<pAC->GIni.GIMacsFound; i++) { pAC->GIni.GP[i].PRxCmd = @@ -2488,10 +2730,14 @@ } } else { - pAC->GIni.GIPortUsage = SK_RED_LINK; + if ((pAC->GIni.GIMacsFound == 2 ) && + (pAC->RlmtNets == 2)) { + pAC->GIni.GIPortUsage = SK_MUL_LINK; + } else { + pAC->GIni.GIPortUsage = SK_RED_LINK; + } for (i=0; i<pAC->GIni.GIMacsFound; i++) { - pAC->GIni.GP[i].PRxCmd = - XM_RX_STRIP_FCS | XM_RX_LENERR_OK; + pAC->GIni.GP[i].PRxCmd = XM_RX_STRIP_FCS; } } @@ -2519,7 +2765,7 @@ ClearRxRing(pAC, &pAC->RxPort[i]); FillRxRing(pAC, &pAC->RxPort[i]); - // Enable transmit descriptor polling. + /* Enable transmit descriptor polling. */ SkGePollTxD(pAC, pAC->IoBase, i, SK_TRUE); FillRxRing(pAC, &pAC->RxPort[i]); }; @@ -2536,7 +2782,7 @@ } #endif - netif_start_queue(pAC->dev); + netif_start_queue(pAC->dev[pNet->PortNr]); for (i=pAC->GIni.GIMacsFound-1; i>=0; i--) { spin_unlock(&pAC->TxPort[i][TX_PRIO_LOW].TxDesRingLock); } @@ -2548,7 +2794,30 @@ SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_START, EvPara); SkEventDispatcher(pAC, pAC->IoBase); + /* Found more than one port */ + if ((pAC->GIni.GIMacsFound == 2 ) && + (pAC->RlmtNets == 2)) { + /* Start both ports */ + EvPara.Para32[0] = pAC->RlmtNets; + EvPara.Para32[1] = -1; + SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_SET_NETS, + EvPara); + + + EvPara.Para32[1] = -1; + EvPara.Para32[0] = pNet->PortNr; + SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_START, EvPara); + + if (pOtherNet->Up) { + EvPara.Para32[0] = pOtherNet->PortNr; + SkEventQueue(pAC, SKGE_RLMT, + SK_RLMT_START, EvPara); + } + } else { + SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_START, EvPara); + } + SkEventDispatcher(pAC, pAC->IoBase); spin_unlock_irqrestore(&pAC->SlowPathLock, Flags); return 0; @@ -2568,7 +2837,8 @@ */ static struct net_device_stats *SkGeStats(struct net_device *dev) { -SK_AC *pAC = (SK_AC*) dev->priv; +DEV_NET *pNet = (DEV_NET*) dev->priv; +SK_AC *pAC = pNet->pAC; SK_PNMI_STRUCT_DATA *pPnmiStruct; /* structure for all Pnmi-Data */ SK_PNMI_STAT *pPnmiStat; /* pointer to virtual XMAC stat. data */SK_PNMI_CONF *pPnmiConf; /* pointer to virtual link config. */ unsigned int Size; /* size of pnmi struct */ @@ -2580,7 +2850,7 @@ memset(pPnmiStruct, 0, sizeof(SK_PNMI_STRUCT_DATA)); spin_lock_irqsave(&pAC->SlowPathLock, Flags); Size = SK_PNMI_STRUCT_SIZE; - SkPnmiGetStruct(pAC, pAC->IoBase, pPnmiStruct, &Size); + SkPnmiGetStruct(pAC, pAC->IoBase, pPnmiStruct, &Size, pNet->NetNr); spin_unlock_irqrestore(&pAC->SlowPathLock, Flags); pPnmiStat = &pPnmiStruct->Stat[0]; pPnmiConf = &pPnmiStruct->Conf[0]; @@ -2622,7 +2892,7 @@ * Description: * This function is called if an ioctl is issued on the device. * There are three subfunction for reading, writing and test-writing - * the private MIB data structure (useful for SysKonnect-internal tools). + * the private MIB data structure (usefull for SysKonnect-internal tools). * * Returns: * 0, if everything is ok @@ -2630,14 +2900,18 @@ */ static int SkGeIoctl(struct net_device *dev, struct ifreq *rq, int cmd) { +DEV_NET *pNet; SK_AC *pAC; + SK_GE_IOCTL Ioctl; unsigned int Err = 0; int Size; SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY, ("SkGeIoctl starts now...\n")); - pAC = (SK_AC*) dev->priv; + + pNet = (DEV_NET*) dev->priv; + pAC = pNet->pAC; if(copy_from_user(&Ioctl, rq->ifr_data, sizeof(SK_GE_IOCTL))) { return -EFAULT; @@ -2653,7 +2927,7 @@ Ioctl.Len : sizeof(pAC->PnmiStruct))) { return -EFAULT; } - Size = SkGeIocMib(pAC, Ioctl.Len, cmd); + Size = SkGeIocMib(pNet, Ioctl.Len, cmd); if(copy_to_user(Ioctl.pData, &pAC->PnmiStruct, Ioctl.Len<Size? Ioctl.Len : Size)) { return -EFAULT; @@ -2688,25 +2962,30 @@ * returned size from PNMI call */ static int SkGeIocMib( -SK_AC *pAC, /* pointer to the adapter context */ +DEV_NET *pNet, /* pointer to the adapter context */ unsigned int Size, /* length of ioctl data */ int mode) /* flag for set/preset */ { unsigned int Flags; /* for spin lock */ - +SK_AC *pAC; + SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY, ("SkGeIocMib starts now...\n")); + pAC = pNet->pAC; /* access MIB */ spin_lock_irqsave(&pAC->SlowPathLock, Flags); switch(mode) { case SK_IOCTL_GETMIB: - SkPnmiGetStruct(pAC, pAC->IoBase, &pAC->PnmiStruct, &Size); + SkPnmiGetStruct(pAC, pAC->IoBase, &pAC->PnmiStruct, &Size, + pNet->NetNr); break; case SK_IOCTL_PRESETMIB: - SkPnmiPreSetStruct(pAC, pAC->IoBase, &pAC->PnmiStruct, &Size); + SkPnmiPreSetStruct(pAC, pAC->IoBase, &pAC->PnmiStruct, &Size, + pNet->NetNr); break; case SK_IOCTL_SETMIB: - SkPnmiSetStruct(pAC, pAC->IoBase, &pAC->PnmiStruct, &Size); + SkPnmiSetStruct(pAC, pAC->IoBase, &pAC->PnmiStruct, &Size, + pNet->NetNr); break; default: break; @@ -2780,7 +3059,7 @@ AutoNeg = AN_SENS; } else printk("%s: Illegal value for AutoNeg_A\n", - pAC->dev->name); + pAC->dev[0]->name); } DuplexCap = DC_BOTH; @@ -2801,18 +3080,18 @@ DuplexCap = DC_HALF; } else printk("%s: Illegal value for DupCap_A\n", - pAC->dev->name); + pAC->dev[0]->name); } /* check for illegal combinations */ if (AutoSet && AutoNeg==AN_SENS && DupSet) { printk("%s, Port A: DuplexCapabilities" - " ignored using Sense mode\n", pAC->dev->name); + " ignored using Sense mode\n", pAC->dev[0]->name); } if (AutoSet && AutoNeg==AN_OFF && DupSet && DuplexCap==DC_BOTH){ printk("%s, Port A: Illegal combination" " of values AutoNeg. and DuplexCap.\n Using " - "Full Duplex\n", pAC->dev->name); + "Full Duplex\n", pAC->dev[0]->name); DuplexCap = DC_FULL; } @@ -2824,7 +3103,7 @@ printk("%s, Port A: Duplex setting not" " possible in\n default AutoNegotiation mode" " (Sense).\n Using AutoNegotiation On\n", - pAC->dev->name); + pAC->dev[0]->name); AutoNeg = AN_ON; } @@ -2859,7 +3138,7 @@ SK_FLOW_MODE_NONE) { printk("%s, Port A: FlowControl" " impossible without AutoNegotiation," - " disabled\n", pAC->dev->name); + " disabled\n", pAC->dev[0]->name); pAC->GIni.GP[0].PFlowCtrlMode = SK_FLOW_MODE_NONE; } @@ -2878,7 +3157,7 @@ MSMode = SK_MS_MODE_SLAVE; } else printk("%s: Illegal value for Role_A\n", - pAC->dev->name); + pAC->dev[0]->name); } pAC->GIni.GP[0].PMSMode = MSMode; @@ -2927,12 +3206,12 @@ /* check for illegal combinations */ if (AutoSet && AutoNeg==AN_SENS && DupSet) { printk("%s, Port B: DuplexCapabilities" - " ignored using Sense mode\n", pAC->dev->name); + " ignored using Sense mode\n", pAC->dev[1]->name); } if (AutoSet && AutoNeg==AN_OFF && DupSet && DuplexCap==DC_BOTH){ printk("%s, Port B: Illegal combination" " of values AutoNeg. and DuplexCap.\n Using " - "Full Duplex\n", pAC->dev->name); + "Full Duplex\n", pAC->dev[1]->name); DuplexCap = DC_FULL; } @@ -2944,14 +3223,14 @@ printk("%s, Port B: Duplex setting not" " possible in\n default AutoNegotiation mode" " (Sense).\n Using AutoNegotiation On\n", - pAC->dev->name); + pAC->dev[1]->name); AutoNeg = AN_ON; } - + /* set the desired mode */ pAC->GIni.GP[1].PLinkModeConf = Capabilities[AutoNeg][DuplexCap]; - + pAC->GIni.GP[1].PFlowCtrlMode = SK_FLOW_MODE_SYM_OR_REM; if (FlowCtrl_B != NULL && pAC->Index<SK_MAX_CARD_PARAM && FlowCtrl_B[pAC->Index] != NULL) { @@ -2979,7 +3258,7 @@ SK_FLOW_MODE_NONE) { printk("%s, Port B: FlowControl" " impossible without AutoNegotiation," - " disabled\n", pAC->dev->name); + " disabled\n", pAC->dev[1]->name); pAC->GIni.GP[1].PFlowCtrlMode = SK_FLOW_MODE_NONE; } @@ -2998,7 +3277,7 @@ MSMode = SK_MS_MODE_SLAVE; } else printk("%s: Illegal value for Role_B\n", - pAC->dev->name); + pAC->dev[1]->name); } pAC->GIni.GP[1].PMSMode = MSMode; @@ -3009,8 +3288,8 @@ PrefPort[pAC->Index] != NULL) { if (strcmp(PrefPort[pAC->Index],"") == 0) { /* Auto */ pAC->ActivePort = 0; - pAC->Rlmt.MacPreferred = -1; /* auto */ - pAC->Rlmt.PrefPort = 0; + pAC->Rlmt.Net[0].Preference = -1; /* auto */ + pAC->Rlmt.Net[0].PrefPort = 0; } else if (strcmp(PrefPort[pAC->Index],"A") == 0) { /* @@ -3018,8 +3297,8 @@ * switch is issued after net up. */ Port = 0; - pAC->Rlmt.MacPreferred = Port; - pAC->Rlmt.PrefPort = Port; + pAC->Rlmt.Net[0].Preference = Port; + pAC->Rlmt.Net[0].PrefPort = Port; } else if (strcmp(PrefPort[pAC->Index],"B") == 0) { /* @@ -3027,12 +3306,14 @@ * switch is issued after net up. */ Port = 1; - pAC->Rlmt.MacPreferred = Port; - pAC->Rlmt.PrefPort = Port; + pAC->Rlmt.Net[0].Preference = Port; + pAC->Rlmt.Net[0].PrefPort = Port; } else printk("%s: Illegal value for PrefPort\n", - pAC->dev->name); + pAC->dev[0]->name); } + + pAC->RlmtNets = 1; if (RlmtMode != NULL && pAC->Index<SK_MAX_CARD_PARAM && RlmtMode[pAC->Index] != NULL) { @@ -3051,9 +3332,18 @@ SK_RLMT_CHECK_LOC_LINK | SK_RLMT_CHECK_SEG; } + else if ((strcmp(RlmtMode[pAC->Index], "DualNet") == 0) && + (pAC->GIni.GIMacsFound == 2)) { + pAC->RlmtMode = SK_RLMT_CHECK_LINK; + pAC->RlmtNets = 2; + } else { printk("%s: Illegal value for" - " RlmtMode, using default\n", pAC->dev->name); + " RlmtMode, using default\n", pAC->dev[0]->name); + +printk("MacFound = %d\nRlmtMode = %s", pAC->GIni.GIMacsFound, RlmtMode[pAC->Index]); + + pAC->RlmtMode = 0; } } @@ -3355,7 +3645,7 @@ case SK_DRV_ADAP_FAIL: SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_EVENT, ("ADAPTER FAIL EVENT\n")); - printk("%s: Adapter failed.\n", pAC->dev->name); + printk("%s: Adapter failed.\n", pAC->dev[0]->name); /* disable interrupts */ SK_OUT32(pAC->IoBase, B0_IMSK, 0); /* cgoos */ @@ -3365,9 +3655,9 @@ SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_EVENT, ("PORT FAIL EVENT, Port: %d\n", FromPort)); if (FromPort == 0) { - printk("%s: Port A failed.\n", pAC->dev->name); + printk("%s: Port A failed.\n", pAC->dev[0]->name); } else { - printk("%s: Port B failed.\n", pAC->dev->name); + printk("%s: Port B failed.\n", pAC->dev[1]->name); } /* cgoos */ break; @@ -3408,7 +3698,7 @@ SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_EVENT, ("NET UP EVENT, Port: %d ", Param.Para32[0])); printk("%s: network connection up using" - " port %c\n", pAC->dev->name, 'A'+Param.Para32[0]); + " port %c\n", pAC->dev[Param.Para32[0]]->name, 'A'+Param.Para32[0]); printk(" speed: 1000\n"); Stat = pAC->GIni.GP[FromPort].PLinkModeStatus; if (Stat == SK_LMODE_STAT_AUTOHALF || @@ -3451,7 +3741,8 @@ } } - if (Param.Para32[0] != pAC->ActivePort) { + if ((Param.Para32[0] != pAC->ActivePort) && + (pAC->RlmtNets == 1)) { NewPara.Para32[0] = pAC->ActivePort; NewPara.Para32[1] = Param.Para32[0]; SkEventQueue(pAC, SKGE_DRV, SK_DRV_SWITCH_INTERN, @@ -3462,21 +3753,21 @@ /* action list 7 */ SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_EVENT, ("NET DOWN EVENT ")); - printk("%s: network connection down\n", pAC->dev->name); + printk("%s: network connection down\n", pAC->dev[Param.Para32[1]]->name); break; case SK_DRV_SWITCH_HARD: /* SK_U32 FromPortIdx SK_U32 ToPortIdx */ SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_EVENT, ("PORT SWITCH HARD ")); case SK_DRV_SWITCH_SOFT: /* SK_U32 FromPortIdx SK_U32 ToPortIdx */ /* action list 6 */ - printk("%s: switching to port %c\n", pAC->dev->name, + printk("%s: switching to port %c\n", pAC->dev[0]->name, 'A'+Param.Para32[1]); case SK_DRV_SWITCH_INTERN: /* SK_U32 FromPortIdx SK_U32 ToPortIdx */ FromPort = Param.Para32[0]; ToPort = Param.Para32[1]; SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_EVENT, ("PORT SWITCH EVENT, From: %d To: %d (Pref %d) ", - FromPort, ToPort, pAC->Rlmt.PrefPort)); + FromPort, ToPort, pAC->Rlmt.Net[0].PrefPort)); NewPara.Para64 = FromPort; SkPnmiEvent(pAC, IoC, SK_PNMI_EVT_XMAC_RESET, NewPara); NewPara.Para64 = ToPort; @@ -3591,7 +3882,7 @@ break; } printk(KERN_INFO "%s: -- ERROR --\n Class: %s\n" - " Nr: 0x%x\n Msg: %s\n", pAC->dev->name, + " Nr: 0x%x\n Msg: %s\n", pAC->dev[0]->name, ClassStr, ErrNum, pErrorMsg); } /* SkErrorLog */ diff -u --recursive --new-file v2.4.6/linux/drivers/net/sk98lin/skgehwt.c linux/drivers/net/sk98lin/skgehwt.c --- v2.4.6/linux/drivers/net/sk98lin/skgehwt.c Fri Sep 15 14:34:19 2000 +++ linux/drivers/net/sk98lin/skgehwt.c Wed Jul 4 11:50:39 2001 @@ -1,23 +1,32 @@ /****************************************************************************** * * Name: skgehwt.c - * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.13 $ - * Date: $Date: 1999/11/22 13:31:12 $ + * Project: PCI Gigabit Ethernet Adapter + * Version: $Revision: 1.12 $ + * Date: $Date: 1998/10/15 15:11:34 $ * Purpose: Hardware Timer. * ******************************************************************************/ /****************************************************************************** * - * (C)Copyright 1998,1999 SysKonnect, + * (C)Copyright 1989-1998 SysKonnect, * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * All Rights Reserved * - * 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 IS UNPUBLISHED PROPRIETARY SOURCE CODE OF SYSKONNECT + * The copyright notice above does not evidence any + * actual or intended publication of such source code. + * + * This Module contains Proprietary Information of SysKonnect + * and should be treated as Confidential. + * + * The information in this file is provided for the exclusive use of + * the licensees of SysKonnect. + * Such users have the right to use, modify, and incorporate this code + * into products for purposes authorized by the license agreement + * provided they include this notice and the associated copyright notice + * with any such product. * The information in this file is provided "AS IS" without warranty. * ******************************************************************************/ @@ -27,9 +36,6 @@ * History: * * $Log: skgehwt.c,v $ - * Revision 1.13 1999/11/22 13:31:12 cgoos - * Changed license header to GPL. - * * Revision 1.12 1998/10/15 15:11:34 gklug * fix: ID_sccs to SysKonnectFileId * @@ -77,7 +83,7 @@ Event queue and dispatcher */ static const char SysKonnectFileId[] = - "$Header: /usr56/projects/ge/schedule/skgehwt.c,v 1.13 1999/11/22 13:31:12 cgoos Exp $" ; + "$Header: /usr56/projects/ge/schedule/skgehwt.c,v 1.12 1998/10/15 15:11:34 gklug Exp $" ; #include "h/skdrv1st.h" /* Driver Specific Definitions */ #include "h/skdrv2nd.h" /* Adapter Control- and Driver specific Def. */ diff -u --recursive --new-file v2.4.6/linux/drivers/net/sk98lin/skgeinit.c linux/drivers/net/sk98lin/skgeinit.c --- v2.4.6/linux/drivers/net/sk98lin/skgeinit.c Tue Mar 20 12:04:59 2001 +++ linux/drivers/net/sk98lin/skgeinit.c Wed Jul 4 11:50:39 2001 @@ -2,16 +2,15 @@ * * Name: skgeinit.c * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.57 $ - * Date: $Date: 2000/08/03 14:55:28 $ + * Version: $Revision: 1.63 $ + * Date: $Date: 2001/04/05 11:02:09 $ * Purpose: Contains functions to initialize the GE HW * ******************************************************************************/ /****************************************************************************** * - * (C)Copyright 1998-2000 SysKonnect, - * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * (C)Copyright 1998-2001 SysKonnect GmbH. * * 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 @@ -27,6 +26,24 @@ * History: * * $Log: skgeinit.c,v $ + * Revision 1.63 2001/04/05 11:02:09 rassmann + * Stop Port check of the STOP bit did not take 2/18 sec as wanted. + * + * Revision 1.62 2001/02/07 07:54:21 rassmann + * Corrected copyright. + * + * Revision 1.61 2001/01/31 15:31:40 gklug + * fix: problem with autosensing an SR8800 switch + * + * Revision 1.60 2000/10/18 12:22:21 cgoos + * Added workaround for half duplex hangup. + * + * Revision 1.59 2000/10/10 11:22:06 gklug + * add: in manual half duplex mode ignore carrier extension errors + * + * Revision 1.58 2000/10/02 14:10:27 rassmann + * Reading BCOM PHY after releasing reset until it returns a valid value. + * * Revision 1.57 2000/08/03 14:55:28 rassmann * Waiting for I2C to be ready before de-initializing adapter * (prevents sensors from hanging up). @@ -122,7 +139,7 @@ * chg: Default is autosensing with AUTOFULL mode * * Revision 1.31 1998/11/25 15:36:16 gklug - * fix: do NOT stop LED Timer when port should be stopped + * fix: do NOT stop LED Timer when port should be stoped * * Revision 1.30 1998/11/24 13:15:28 gklug * add: Init PCkeckPar struct member @@ -283,7 +300,7 @@ /* local variables ************************************************************/ static const char SysKonnectFileId[] = - "@(#)$Id: skgeinit.c,v 1.57 2000/08/03 14:55:28 rassmann Exp $ (C) SK "; + "@(#)$Id: skgeinit.c,v 1.63 2001/04/05 11:02:09 rassmann Exp $ (C) SK "; struct s_QOffTab { int RxQOff; /* Receive Queue Address Offset */ @@ -666,7 +683,11 @@ SK_OUT16(IoC, B3_PA_TOINI_TX1, SK_PKT_TO_MAX); SK_OUT16(IoC, B3_PA_TOINI_TX2, SK_PKT_TO_MAX); - /* enable timeout timers if jumbo frames not used */ + /* + * enable timeout timers if jumbo frames not used + * NOTE: the packet arbiter timeout interrupt is needed for + * half duplex hangup workaround + */ if (pAC->GIni.GIPortUsage != SK_JUMBO_LINK) { if (pAC->GIni.GIMacsFound == 1) { SK_OUT16(IoC, B3_PA_CTRL, PA_ENA_TO_TX1); @@ -1118,10 +1139,10 @@ * * Dir = SK_STOP_TX Stops the transmit path only and resets * the XMAC. The receive queue is still and - * the pending rx frames may still transferred + * the pending rx frames may still transfered * into the RxD. * SK_STOP_RX Stop the receive path. The tansmit path - * has to be stopped once before. + * has to be stoped once before. * SK_STOP_ALL SK_STOP_TX + SK_STOP_RX * * RstMode=SK_SOFT_RST Resets the XMAC. The PHY is still alive. @@ -1129,7 +1150,7 @@ * * Example: * 1) A Link Down event was signaled for a port. Therefore the activity - * of this port should be stopped and a hardware reset should be issued + * of this port should be stoped and a hardware reset should be issued * to enable the workaround of XMAC errata #2. But the received frames * should not be discarded. * ... @@ -1198,10 +1219,10 @@ SK_U16 Word; SK_U32 XsCsr; SK_U32 XaCsr; - int i; + int i; SK_BOOL AllPortsDis; SK_U64 ToutStart; - int ToutCnt; + int ToutCnt; pPrt = &pAC->GIni.GP[Port]; @@ -1226,7 +1247,7 @@ do { /* * Clear packet arbiter timeout to make sure - * this loop will terminate + * this loop will terminate. */ if (Port == MAC_1) { Word = PA_CLR_TO_TX1; @@ -1237,9 +1258,8 @@ SK_OUT16(IoC, B3_PA_CTRL, Word); /* - * If the transfer stucks at the XMAC the STOP command - * will not terminate if we don't flush the XMACs - * transmit FIFO ! + * If the transfer stucks at the XMAC the STOP command will not + * terminate if we don't flush the XMAC's transmit FIFO! */ XM_IN32(IoC, Port, XM_MODE, &DWord); DWord |= XM_MD_FTF; @@ -1248,7 +1268,7 @@ XsCsr = TestStopBit(pAC, IoC, pPrt->PXsQOff); XaCsr = TestStopBit(pAC, IoC, pPrt->PXaQOff); - if (ToutStart + (SK_TICKS_PER_SEC / 18) >= SkOsGetTime(pAC)) { + if (SkOsGetTime(pAC) - ToutStart > (SK_TICKS_PER_SEC / 18)) { /* * Timeout of 1/18 second reached. * This needs to be checked at 1/18 sec only. @@ -1257,9 +1277,8 @@ switch (ToutCnt) { case 1: /* - * Cache Incoherency workaround: - * Assume a start command has been - * lost while sending the frame. + * Cache Incoherency workaround: Assume a start command + * has been lost while sending the frame. */ ToutStart = SkOsGetTime(pAC); if (XsCsr & CSR_STOP) { @@ -1275,6 +1294,7 @@ * calls StopPort again. * XXX. */ + /* Fatal Error, Loop aborted */ /* Create an Error Log Entry */ SK_ERR_LOG( @@ -1290,12 +1310,12 @@ } } - /* - * Because of the ASIC problem report entry from 21.08.1998 it is - * required to wait until CSR_STOP is reset and CSR_SV_IDLE is set. - */ - } while ((XsCsr & (CSR_STOP|CSR_SV_IDLE)) != CSR_SV_IDLE || - (XaCsr & (CSR_STOP|CSR_SV_IDLE)) != CSR_SV_IDLE); + /* + * Because of the ASIC problem report entry from 21.08.1998 it is + * required to wait until CSR_STOP is reset and CSR_SV_IDLE is set. + */ + } while ((XsCsr & (CSR_STOP | CSR_SV_IDLE)) != CSR_SV_IDLE || + (XaCsr & (CSR_STOP | CSR_SV_IDLE)) != CSR_SV_IDLE); /* reset the XMAC depending on the RstMode */ if (RstMode == SK_SOFT_RST) { @@ -1362,13 +1382,13 @@ i--; } - /* finish if CSR_STOP is done or CSR_SV_IDLE is true and i==0 */ - /* - * because of the ASIC problem report entry from 21.08.98 - * it is required to wait until CSR_STOP is reset and - * CSR_SV_IDLE is set. - */ - } while ((DWord & (CSR_STOP|CSR_SV_IDLE)) != CSR_SV_IDLE && + /* finish if CSR_STOP is done or CSR_SV_IDLE is true and i==0 */ + /* + * because of the ASIC problem report entry from 21.08.98 + * it is required to wait until CSR_STOP is reset and + * CSR_SV_IDLE is set. + */ + } while ((DWord & (CSR_STOP | CSR_SV_IDLE)) != CSR_SV_IDLE && ((DWord & CSR_SV_IDLE) == 0 || i != 0)); /* The path data transfer activity is fully stopped now. */ @@ -1433,6 +1453,7 @@ pPrt->PIsave = 0; pPrt->PPrevShorts = 0; pPrt->PLinkResCt = 0; + pPrt->PAutoNegTOCt = 0; pPrt->PPrevRx = 0; pPrt->PPrevFcs = 0; pPrt->PRxLim = SK_DEF_RX_WA_LIM; @@ -1717,6 +1738,17 @@ if (pAC->GIni.GIPortUsage == SK_JUMBO_LINK) { pPrt->PRxCmd |= XM_RX_BIG_PK_OK; } + + if (pPrt->PLinkModeConf == SK_LMODE_HALF) { + /* + * If in manual half duplex mode + * the other side might be in full duplex mode + * so ignore if a carrier extension is not seen on + * frames received + */ + pPrt->PRxCmd |= XM_RX_DIS_CEXT; + } + } } /* SkGeInit2 */ @@ -1891,7 +1923,7 @@ * for PRxQSize, PXSQSize, or PXAQSize are invalid for one * or more queues. The specified port was NOT initialized. * An error log entry was generated. - * 2: The port has to be stopped before it can be initilaized again. + * 2: The port has to be stopped before it can be initialized again. */ int SkGeInitPort( SK_AC *pAC, /* adapter context */ diff -u --recursive --new-file v2.4.6/linux/drivers/net/sk98lin/skgepnmi.c linux/drivers/net/sk98lin/skgepnmi.c --- v2.4.6/linux/drivers/net/sk98lin/skgepnmi.c Tue Mar 20 12:04:59 2001 +++ linux/drivers/net/sk98lin/skgepnmi.c Wed Jul 4 11:50:39 2001 @@ -2,16 +2,15 @@ * * Name: skgepnmi.c * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.78 $ - * Date: $Date: 2000/09/12 10:44:58 $ + * Version: $Revision: 1.87 $ + * Date: $Date: 2001/04/06 13:35:09 $ * Purpose: Private Network Management Interface * ****************************************************************************/ /****************************************************************************** * - * (C)Copyright 1998,1999 SysKonnect, - * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * (C)Copyright 1998-2001 SysKonnect GmbH. * * 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 @@ -27,6 +26,37 @@ * History: * * $Log: skgepnmi.c,v $ + * Revision 1.87 2001/04/06 13:35:09 mkunz + * -Bugs fixed in handling of OID_SKGE_MTU and the VPD OID's + * + * Revision 1.86 2001/03/09 09:18:03 mkunz + * Changes in SK_DBG_MSG + * + * Revision 1.85 2001/03/08 09:37:31 mkunz + * Bugfix in ResetCounter for Pnmi.Port structure + * + * Revision 1.84 2001/03/06 09:04:55 mkunz + * Made some changes in instance calculation + * C ^VS: + * + * Revision 1.83 2001/02/15 09:15:32 mkunz + * Necessary changes for dual net mode added + * + * Revision 1.82 2001/02/07 08:24:19 mkunz + * -Made changes in handling of OID_SKGE_MTU + * + * Revision 1.81 2001/02/06 09:58:00 mkunz + * -Vpd bug fixed + * -OID_SKGE_MTU added + * -pnmi support for dual net mode. Interface function and macros extended + * + * Revision 1.80 2001/01/22 13:41:35 rassmann + * Supporting two nets on dual-port adapters. + * + * Revision 1.79 2000/12/05 14:57:40 cgoos + * SetStruct failed before first Link Up (link mode of virtual + * port "INDETERMINATED"). + * * Revision 1.78 2000/09/12 10:44:58 cgoos * Fixed SK_PNMI_STORE_U32 calls with typecasted argument. * @@ -72,7 +102,7 @@ * * Revision 1.67 1999/09/22 09:53:20 rwahl * - Read Broadcom register for updating fcs error counter (1000Base-T). - * + * * Revision 1.66 1999/08/26 13:47:56 rwahl * Added SK_DRIVER_SENDEVENT when queueing RLMT_CHANGE_THRES trap. * @@ -81,7 +111,7 @@ * * Revision 1.64 1999/05/20 09:24:12 cgoos * Changes for 1000Base-T (sensors, Master/Slave). - * + * * Revision 1.63 1999/04/13 15:11:58 mhaveman * Moved include of rlmt.h to header skgepnmi.h because some macros * are needed there. @@ -149,7 +179,7 @@ * Fixed: Couldnot delete VPD keys on UNIX. * * Revision 1.48 1998/12/09 14:11:10 mhaveman - * -Add: Debugmessage for XMAC_RESET suppressed to minimize output. + * -Add: Debugmessage for XMAC_RESET supressed to minimize output. * -Fixed: RlmtChangeThreshold will now be initialized. * -Fixed: VPD_ENTRIES_LIST extended value with unnecessary space char. * -Fixed: On VPD key creation an invalid key name could be created @@ -185,7 +215,7 @@ * Revision 1.43 1998/12/03 14:18:10 mhaveman * -Fixed problem in PnmiSetStruct. It was impossible to set any value. * -Removed VPD key evaluation for VPD_FREE_BYTES and VPD_ACTION. - * + * * Revision 1.42 1998/12/03 11:31:47 mhaveman * Inserted cast to satisfy lint. * @@ -206,7 +236,7 @@ * -Fixed bug for RX counters. On an RX overflow interrupt the high * words of all RX counters were incremented. * -SET operations on FLOWCTRL_MODE and LINK_MODE accept now the - * value 0, which has no effect. It is useful for multiple instance + * value 0, which has no effect. It is usefull for multiple instance * SETs. * * Revision 1.37 1998/11/20 08:02:04 mhaveman @@ -220,7 +250,7 @@ * * Revision 1.35 1998/11/16 07:45:34 mhaveman * SkAddrOverride now returns value and will be checked. - * + * * Revision 1.34 1998/11/10 13:40:37 mhaveman * Needed to change interface, because NT driver needs a return value * of needed buffer space on TOO_SHORT errors. Therefore all @@ -240,7 +270,7 @@ * Revision 1.30 1998/11/03 12:04:46 mhaveman * Fixed problem in SENSOR_VALUE, which wrote beyond the buffer end * Fixed alignment problem with CHIPSET. - * + * * Revision 1.29 1998/11/02 11:23:54 mhaveman * Corrected SK_ERROR_LOG to SK_ERR_LOG. Sorry. * @@ -270,14 +300,14 @@ * -Fixed sequence of error return code (INSTANCE -> ACCESS -> SHORT) * -Changed type of parameter Instance back to SK_U32 because of VPD * -Updated new VPD function calls - * + * * Revision 1.23 1998/10/23 10:16:37 mhaveman * Fixed bugs after buffer test simulation. * * Revision 1.22 1998/10/21 13:23:52 mhaveman * -Call syntax of SkOsGetTime() changed to SkOsGetTime(pAc). * -Changed calculation of hundrets of seconds. - * + * * Revision 1.20 1998/10/20 07:30:45 mhaveman * Made type changes to unsigned integer where possible. * @@ -291,12 +321,12 @@ * to HWACCESS. * -Provided all MEMCPY/MEMSET macros with (char *) pointers, because * Solaris throwed warnings when mapping to bcopy/bset. - * + * * Revision 1.17 1998/10/13 07:42:01 mhaveman * -Added OIDs OID_SKGE_TRAP_NUMBER and OID_SKGE_ALL_DATA * -Removed old cvs history entries * -Renamed MacNumber to PortNumber - * + * * Revision 1.16 1998/10/07 10:52:49 mhaveman * -Inserted handling of some OID_GEN_ Ids for windows * -Fixed problem with 803.2 statistic. @@ -332,7 +362,7 @@ static const char SysKonnectFileId[] = - "@(#) $Id: skgepnmi.c,v 1.78 2000/09/12 10:44:58 cgoos Exp $" + "@(#) $Id: skgepnmi.c,v 1.87 2001/04/06 13:35:09 mkunz Exp $" " (C) SysKonnect."; #include "h/skdrv1st.h" @@ -356,14 +386,17 @@ */ int SkPnmiInit(SK_AC *pAC, SK_IOC IoC, int level); int SkPnmiGetVar(SK_AC *pAC, SK_IOC IoC, SK_U32 Id, void *pBuf, - unsigned int *pLen, SK_U32 Instance); + unsigned int *pLen, SK_U32 Instance, SK_U32 NetIndex); int SkPnmiPreSetVar(SK_AC *pAC, SK_IOC IoC, SK_U32 Id, void *pBuf, - unsigned int *pLen, SK_U32 Instance); + unsigned int *pLen, SK_U32 Instance, SK_U32 NetIndex); int SkPnmiSetVar(SK_AC *pAC, SK_IOC IoC, SK_U32 Id, void *pBuf, - unsigned int *pLen, SK_U32 Instance); -int SkPnmiGetStruct(SK_AC *pAC, SK_IOC IoC, void *pBuf, unsigned int *pLen); -int SkPnmiPreSetStruct(SK_AC *pAC, SK_IOC IoC, void *pBuf, unsigned int *pLen); -int SkPnmiSetStruct(SK_AC *pAC, SK_IOC IoC, void *pBuf, unsigned int *pLen); + unsigned int *pLen, SK_U32 Instance, SK_U32 NetIndex); +int SkPnmiGetStruct(SK_AC *pAC, SK_IOC IoC, void *pBuf, + unsigned int *pLen, SK_U32 NetIndex); +int SkPnmiPreSetStruct(SK_AC *pAC, SK_IOC IoC, void *pBuf, + unsigned int *pLen, SK_U32 NetIndex); +int SkPnmiSetStruct(SK_AC *pAC, SK_IOC IoC, void *pBuf, + unsigned int *pLen, SK_U32 NetIndex); int SkPnmiEvent(SK_AC *pAC, SK_IOC IoC, SK_U32 Event, SK_EVPARA Param); @@ -372,7 +405,7 @@ */ static int Addr(SK_AC *pAC, SK_IOC IoC, int action, SK_U32 Id, char *pBuf, unsigned int *pLen, SK_U32 Instance, - unsigned int TableIndex); + unsigned int TableIndex, SK_U32 NetIndex); static SK_U8 CalculateLinkModeStatus(SK_AC *pAC, SK_IOC IoC, unsigned int PhysPortIndex); static SK_U8 CalculateLinkStatus(SK_AC *pAC, SK_IOC IoC, unsigned int @@ -381,14 +414,14 @@ static void CopyTrapQueue(SK_AC *pAC, char *pDstBuf); static int CsumStat(SK_AC *pAC, SK_IOC IoC, int action, SK_U32 Id, char *pBuf, unsigned int *pLen, SK_U32 Instance, - unsigned int TableIndex); + unsigned int TableIndex, SK_U32 NetIndex); static int General(SK_AC *pAC, SK_IOC IoC, int action, SK_U32 Id, char *pBuf, unsigned int *pLen, SK_U32 Instance, - unsigned int TableIndex); + unsigned int TableIndex, SK_U32 NetIndex); static SK_U64 GetPhysStatVal(SK_AC *pAC, SK_IOC IoC, unsigned int PhysPortIndex, unsigned int StatIndex); static SK_U64 GetStatVal(SK_AC *pAC, SK_IOC IoC, unsigned int LogPortIndex, - unsigned int StatIndex); + unsigned int StatIndex, SK_U32 NetIndex); static char* GetTrapEntry(SK_AC *pAC, SK_U32 TrapId, unsigned int Size); static void GetTrapQueueLen(SK_AC *pAC, unsigned int *pLen, unsigned int *pEntries); @@ -397,50 +430,50 @@ static int LookupId(SK_U32 Id); static int Mac8023Stat(SK_AC *pAC, SK_IOC IoC, int action, SK_U32 Id, char *pBuf, unsigned int *pLen, SK_U32 Instance, - unsigned int TableIndex); + unsigned int TableIndex, SK_U32 NetIndex); static int MacPrivateConf(SK_AC *pAC, SK_IOC IoC, int action, SK_U32 Id, char *pBuf, unsigned int *pLen, SK_U32 Instance, - unsigned int TableIndex); + unsigned int TableIndex, SK_U32 NetIndex); static int MacPrivateStat(SK_AC *pAC, SK_IOC IoC, int action, SK_U32 Id, char *pBuf, unsigned int *pLen, SK_U32 Instance, - unsigned int TableIndex); + unsigned int TableIndex, SK_U32 NetIndex); static int MacUpdate(SK_AC *pAC, SK_IOC IoC, unsigned int FirstMac, unsigned int LastMac); static int Monitor(SK_AC *pAC, SK_IOC IoC, int action, SK_U32 Id, char *pBuf, unsigned int *pLen, SK_U32 Instance, - unsigned int TableIndex); + unsigned int TableIndex, SK_U32 NetIndex); static int OidStruct(SK_AC *pAC, SK_IOC IoC, int action, SK_U32 Id, char *pBuf, unsigned int *pLen, SK_U32 Instance, - unsigned int TableIndex); + unsigned int TableIndex, SK_U32 NetIndex); static int Perform(SK_AC *pAC, SK_IOC IoC, int action, SK_U32 Id, char *pBuf, unsigned int* pLen, SK_U32 Instance, - unsigned int TableIndex); + unsigned int TableIndex, SK_U32 NetIndex); static int PnmiStruct(SK_AC *pAC, SK_IOC IoC, int Action, char *pBuf, - unsigned int *pLen); + unsigned int *pLen, SK_U32 NetIndex); static int PnmiVar(SK_AC *pAC, SK_IOC IoC, int Action, SK_U32 Id, - char *pBuf, unsigned int *pLen, SK_U32 Instance); + char *pBuf, unsigned int *pLen, SK_U32 Instance, SK_U32 NetIndex); static void QueueRlmtNewMacTrap(SK_AC *pAC, unsigned int ActiveMac); static void QueueRlmtPortTrap(SK_AC *pAC, SK_U32 TrapId, unsigned int PortIndex); static void QueueSensorTrap(SK_AC *pAC, SK_U32 TrapId, unsigned int SensorIndex); static void QueueSimpleTrap(SK_AC *pAC, SK_U32 TrapId); -static void ResetCounter(SK_AC *pAC, SK_IOC IoC); +static void ResetCounter(SK_AC *pAC, SK_IOC IoC, SK_U32 NetIndex); static int Rlmt(SK_AC *pAC, SK_IOC IoC, int action, SK_U32 Id, char *pBuf, unsigned int *pLen, SK_U32 Instance, - unsigned int TableIndex); + unsigned int TableIndex, SK_U32 NetIndex); static int RlmtStat(SK_AC *pAC, SK_IOC IoC, int action, SK_U32 Id, char *pBuf, unsigned int *pLen, SK_U32 Instance, - unsigned int TableIndex); -static int RlmtUpdate(SK_AC *pAC, SK_IOC IoC); + unsigned int TableIndex, SK_U32 NetIndex); +static int RlmtUpdate(SK_AC *pAC, SK_IOC IoC, SK_U32 NetIndex); static int SensorStat(SK_AC *pAC, SK_IOC IoC, int action, SK_U32 Id, char *pBuf, unsigned int *pLen, SK_U32 Instance, - unsigned int TableIndex); + unsigned int TableIndex, SK_U32 NetIndex); static int SirqUpdate(SK_AC *pAC, SK_IOC IoC); static void VirtualConf(SK_AC *pAC, SK_IOC IoC, SK_U32 Id, char *pBuf); static int Vpd(SK_AC *pAC, SK_IOC IoC, int action, SK_U32 Id, char *pBuf, unsigned int *pLen, SK_U32 Instance, - unsigned int TableIndex); + unsigned int TableIndex, SK_U32 NetIndex); /****************************************************************************** @@ -1323,11 +1356,16 @@ sizeof(SK_PNMI_RLMT_MONITOR), SK_PNMI_OFF(RlmtMonitor) + SK_PNMI_MON_OFF(RlmtMonitorAdmin), SK_PNMI_RW, Monitor, 0}, + {OID_SKGE_MTU, + 1, + 0, + SK_PNMI_MAI_OFF(MtuSize), + SK_PNMI_RW, MacPrivateConf, 0}, }; /* * Table for hardware register saving on resets and port switches -*/ + */ static const SK_PNMI_STATADDR StatAddress[SK_PNMI_MAX_IDX] = { /* 0 */ {TRUE, XM_TXF_OK}, /* 1 */ {TRUE, 0}, @@ -1445,6 +1483,7 @@ for (PortIndex = 0; PortIndex < SK_MAX_MACS; PortIndex ++) { pAC->Pnmi.Port[PortIndex].ActiveFlag = SK_FALSE; + pAC->Pnmi.DualNetActiveFlag = SK_FALSE; } break; @@ -1600,7 +1639,7 @@ * * Returns: * SK_PNMI_ERR_OK The request was successfully performed - * SK_PNMI_ERR_GENERAL A general severe internal error occurred + * SK_PNMI_ERR_GENERAL A general severe internal error occured * SK_PNMI_ERR_TOO_SHORT The passed buffer is too short to take * the data. * SK_PNMI_ERR_UNKNOWN_OID The requested OID is unknown @@ -1615,14 +1654,15 @@ SK_U32 Id, /* Object ID that is to be processed */ void *pBuf, /* Buffer to which to mgmt data will be retrieved */ unsigned int *pLen, /* On call: buffer length. On return: used buffer */ -SK_U32 Instance) /* Instance (1..n) that is to be queried or -1 */ +SK_U32 Instance, /* Instance (1..n) that is to be queried or -1 */ +SK_U32 NetIndex) /* NetIndex (0..n), in single net mode allways zero */ { SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL, - ("PNMI: SkPnmiGetVar: Called, Id=0x%x, BufLen=%d\n", Id, - *pLen)); + ("PNMI: SkPnmiGetVar: Called, Id=0x%x, BufLen=%d, Instance=%d, NetIndex=%d\n", + Id, *pLen, Instance, NetIndex)); return (PnmiVar(pAC, IoC, SK_PNMI_GET, Id, (char *)pBuf, pLen, - Instance)); + Instance, NetIndex)); } /***************************************************************************** @@ -1632,13 +1672,13 @@ * Description: * Calls a general sub-function for all this stuff. The preset does * the same as a set, but returns just before finally setting the - * new value. This is useful to check if a set might be successful. + * new value. This is usefull to check if a set might be successfull. * If as instance a -1 is passed, an array of values is supposed and * all instance of the OID will be set. * * Returns: * SK_PNMI_ERR_OK The request was successfully performed. - * SK_PNMI_ERR_GENERAL A general severe internal error occurred. + * SK_PNMI_ERR_GENERAL A general severe internal error occured. * SK_PNMI_ERR_TOO_SHORT The passed buffer is too short to contain * the correct data (e.g. a 32bit value is * needed, but a 16 bit value was passed). @@ -1657,14 +1697,16 @@ SK_U32 Id, /* Object ID that is to be processed */ void *pBuf, /* Buffer which stores the mgmt data to be set */ unsigned int *pLen, /* Total length of mgmt data */ -SK_U32 Instance) /* Instance (1..n) that is to be set or -1 */ +SK_U32 Instance, /* Instance (1..n) that is to be set or -1 */ +SK_U32 NetIndex) /* NetIndex (0..n), in single net mode allways zero */ { SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL, - ("PNMI: SkPnmiPreSetVar: Called, Id=0x%x, BufLen=%d\n", - Id, *pLen)); + ("PNMI: SkPnmiPreSetVar: Called, Id=0x%x, BufLen=%d, Instance=%d, NetIndex=%d\n", + Id, *pLen, Instance, NetIndex)); + return (PnmiVar(pAC, IoC, SK_PNMI_PRESET, Id, (char *)pBuf, pLen, - Instance)); + Instance, NetIndex)); } /***************************************************************************** @@ -1674,13 +1716,13 @@ * Description: * Calls a general sub-function for all this stuff. The preset does * the same as a set, but returns just before finally setting the - * new value. This is useful to check if a set might be successful. + * new value. This is usefull to check if a set might be successfull. * If as instance a -1 is passed, an array of values is supposed and * all instance of the OID will be set. * * Returns: * SK_PNMI_ERR_OK The request was successfully performed. - * SK_PNMI_ERR_GENERAL A general severe internal error occurred. + * SK_PNMI_ERR_GENERAL A general severe internal error occured. * SK_PNMI_ERR_TOO_SHORT The passed buffer is too short to contain * the correct data (e.g. a 32bit value is * needed, but a 16 bit value was passed). @@ -1699,14 +1741,15 @@ SK_U32 Id, /* Object ID that is to be processed */ void *pBuf, /* Buffer which stores the mgmt data to be set */ unsigned int *pLen, /* Total length of mgmt data */ -SK_U32 Instance) /* Instance (1..n) that is to be set or -1 */ +SK_U32 Instance, /* Instance (1..n) that is to be set or -1 */ +SK_U32 NetIndex) /* NetIndex (0..n), in single net mode allways zero */ { SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL, - ("PNMI: SkPnmiSetVar: Called, Id=0x%x, BufLen=%d\n", Id, - *pLen)); + ("PNMI: SkPnmiSetVar: Called, Id=0x%x, BufLen=%d, Instance=%d, NetIndex=%d\n", + Id, *pLen, Instance, NetIndex)); return (PnmiVar(pAC, IoC, SK_PNMI_SET, Id, (char *)pBuf, pLen, - Instance)); + Instance, NetIndex)); } /***************************************************************************** @@ -1723,16 +1766,18 @@ * * Returns: * SK_PNMI_ERR_OK The request was successfully performed - * SK_PNMI_ERR_GENERAL A general severe internal error occurred + * SK_PNMI_ERR_GENERAL A general severe internal error occured * SK_PNMI_ERR_TOO_SHORT The passed buffer is too short to take * the data. + * SK_PNMI_ERR_UNKNOWN_NET The requested NetIndex doesn't exist */ int SkPnmiGetStruct( SK_AC *pAC, /* Pointer to adapter context */ SK_IOC IoC, /* IO context handle */ void *pBuf, /* Buffer which will store the retrieved data */ -unsigned int *pLen) /* Length of buffer */ +unsigned int *pLen, /* Length of buffer */ +SK_U32 NetIndex) /* NetIndex (0..n), in single net mode allways zero */ { int Ret; unsigned int TableIndex; @@ -1741,11 +1786,12 @@ unsigned int InstanceCnt; SK_U32 Instance; unsigned int TmpLen; - char KeyArr[SK_PNMI_VPD_ARR_SIZE][SK_PNMI_VPD_STR_SIZE]; + char KeyArr[SK_PNMI_VPD_ENTRIES][SK_PNMI_VPD_KEY_SIZE]; + - SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL, - ("PNMI: SkPnmiGetStruct: Called, BufLen=%d\n", *pLen)); + ("PNMI: SkPnmiGetStruct: Called, BufLen=%d, NetIndex=%d\n", + *pLen, NetIndex)); if (*pLen < SK_PNMI_STRUCT_SIZE) { @@ -1759,6 +1805,13 @@ return (SK_PNMI_ERR_TOO_SHORT); } + /* + * Check NetIndex + */ + if (NetIndex >= pAC->Rlmt.NumNets) { + return (SK_PNMI_ERR_UNKNOWN_NET); + } + /* Update statistic */ SK_PNMI_CHECKFLAGS("SkPnmiGetStruct: On call"); @@ -1770,7 +1823,7 @@ return (Ret); } - if ((Ret = RlmtUpdate(pAC, IoC)) != SK_PNMI_ERR_OK) { + if ((Ret = RlmtUpdate(pAC, IoC, NetIndex)) != SK_PNMI_ERR_OK) { SK_PNMI_SET_STAT(pBuf, Ret, (SK_U32)(-1)); *pLen = SK_PNMI_MIN_STRUCT_SIZE; @@ -1812,7 +1865,6 @@ TableIndex ++) { InstanceNo = IdTable[TableIndex].InstanceNo; - for (InstanceCnt = 1; InstanceCnt <= InstanceNo; InstanceCnt ++) { @@ -1830,8 +1882,7 @@ IdTable[TableIndex].Id == OID_SKGE_VPD_ACCESS || IdTable[TableIndex].Id == OID_SKGE_VPD_ACTION) { - SK_PNMI_READ_U32(KeyArr[InstanceCnt - 1], - Instance); + SK_STRNCPY((char *)&Instance, KeyArr[InstanceCnt - 1], 4); } else { Instance = (SK_U32)InstanceCnt; @@ -1840,7 +1891,7 @@ TmpLen = *pLen - DstOffset; Ret = IdTable[TableIndex].Func(pAC, IoC, SK_PNMI_GET, IdTable[TableIndex].Id, (char *)pBuf + - DstOffset, &TmpLen, Instance, TableIndex); + DstOffset, &TmpLen, Instance, TableIndex, NetIndex); /* * An unknown instance error means that we reached @@ -1850,7 +1901,7 @@ */ if (Ret == SK_PNMI_ERR_UNKNOWN_INST) { - break; + break; } if (Ret != SK_PNMI_ERR_OK) { @@ -1884,7 +1935,7 @@ * Description: * Calls a general sub-function for all this set stuff. The preset does * the same as a set, but returns just before finally setting the - * new value. This is useful to check if a set might be successful. + * new value. This is usefull to check if a set might be successfull. * The sub-function runs through the IdTable, checks which OIDs are able * to set, and calls the handler function of the OID to perform the * preset. The return value of the function will also be stored in @@ -1893,7 +1944,7 @@ * * Returns: * SK_PNMI_ERR_OK The request was successfully performed. - * SK_PNMI_ERR_GENERAL A general severe internal error occurred. + * SK_PNMI_ERR_GENERAL A general severe internal error occured. * SK_PNMI_ERR_TOO_SHORT The passed buffer is too short to contain * the correct data (e.g. a 32bit value is * needed, but a 16 bit value was passed). @@ -1905,12 +1956,15 @@ SK_AC *pAC, /* Pointer to adapter context */ SK_IOC IoC, /* IO context handle */ void *pBuf, /* Buffer which contains the data to be set */ -unsigned int *pLen) /* Length of buffer */ +unsigned int *pLen, /* Length of buffer */ +SK_U32 NetIndex) /* NetIndex (0..n), in single net mode allways zero */ { SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL, - ("PNMI: SkPnmiPreSetStruct: Called, BufLen=%d\n", *pLen)); + ("PNMI: SkPnmiPreSetStruct: Called, BufLen=%d, NetIndex=%d\n", + *pLen, NetIndex)); - return (PnmiStruct(pAC, IoC, SK_PNMI_PRESET, (char *)pBuf, pLen)); + return (PnmiStruct(pAC, IoC, SK_PNMI_PRESET, (char *)pBuf, + pLen, NetIndex)); } /***************************************************************************** @@ -1929,7 +1983,7 @@ * * Returns: * SK_PNMI_ERR_OK The request was successfully performed. - * SK_PNMI_ERR_GENERAL A general severe internal error occurred. + * SK_PNMI_ERR_GENERAL A general severe internal error occured. * SK_PNMI_ERR_TOO_SHORT The passed buffer is too short to contain * the correct data (e.g. a 32bit value is * needed, but a 16 bit value was passed). @@ -1941,12 +1995,15 @@ SK_AC *pAC, /* Pointer to adapter context */ SK_IOC IoC, /* IO context handle */ void *pBuf, /* Buffer which contains the data to be set */ -unsigned int *pLen) /* Length of buffer */ +unsigned int *pLen, /* Length of buffer */ +SK_U32 NetIndex) /* NetIndex (0..n), in single net mode allways zero */ { SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL, - ("PNMI: SkPnmiSetStruct: Called, BufLen=%d\n", *pLen)); + ("PNMI: SkPnmiSetStruct: Called, BufLen=%d, NetIndex=%d\n", + *pLen, NetIndex)); - return (PnmiStruct(pAC, IoC, SK_PNMI_SET, (char *)pBuf, pLen)); + return (PnmiStruct(pAC, IoC, SK_PNMI_SET, (char *)pBuf, + pLen, NetIndex)); } /***************************************************************************** @@ -1981,11 +2038,6 @@ * SK_PNMI_EVT_RLMT_PORT_DOWN Generated by RLMT to notify that a port * went logically down. A trap message will * be stored to the trap buffer. - * SK_PNMI_EVT_RLMT_PORT_SWITCH Generated by RLMT to notify that the - * active port switched. PNMI will split - * this into two message ACTIVE_DOWN and - * ACTIVE_UP to be future compatible with - * load balancing and card fail over. * SK_PNMI_EVT_RLMT_SEGMENTATION Generated by RLMT to notify that two * spanning tree root bridges were * detected. A trap message will be stored @@ -1997,6 +2049,9 @@ * is now an active port. PNMI will now * add the statistic data of this port to * the virtual port. + * SK_PNMI_EVT_RLMT_SET_NETS Notifies PNMI about the net mode. The first Parameter + * contains the number of nets. 1 means single net, 2 means + * dual net. The second Parameter is -1 * * Returns: * Always 0 @@ -2009,6 +2064,7 @@ SK_EVPARA Param) /* Event dependent parameter */ { unsigned int PhysPortIndex; + unsigned int MaxNetNumber; int CounterIndex; int Ret; SK_U16 MacStatus; @@ -2022,6 +2078,7 @@ SK_U64 OldestValue; SK_U64 Delta; SK_PNMI_ESTIMATE *pEst; + SK_U32 NetIndex; #ifdef DEBUG @@ -2284,9 +2341,27 @@ case SK_PNMI_EVT_CLEAR_COUNTER: /* + * Param.Para32[0] contains the NetIndex (0 ..1). + * Param.Para32[1] is reserved, contains -1. + */ + NetIndex = (SK_U32)Param.Para32[0]; + +#ifdef DEBUG + if (NetIndex >= pAC->Rlmt.NumNets) { + + SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL, + ("PNMI: ERR: SkPnmiEvent: SK_PNMI_EVT_CLEAR_COUNTER parameter wrong, NetIndex=%d\n", + NetIndex)); + + return (0); + } +#endif + + /* * Set all counters and timestamps to zero */ - ResetCounter(pAC, IoC); + ResetCounter(pAC, IoC, NetIndex); /* the according NetIndex is required + as a Parameter of the Event */ break; case SK_PNMI_EVT_XMAC_RESET: @@ -2351,9 +2426,8 @@ } #endif /* - * Store a trap message in the trap buffer and generate - * an event for user space applications with the - * SK_DRIVER_SENDEVENT macro. + * Store a trap message in the trap buffer and generate an event for + * user space applications with the SK_DRIVER_SENDEVENT macro. */ QueueRlmtPortTrap(pAC, OID_SKGE_TRAP_RLMT_PORT_UP, (unsigned int)Param.Para32[0]); @@ -2372,9 +2446,8 @@ } #endif /* - * Store a trap message in the trap buffer and generate - * an event for user space applications with the - * SK_DRIVER_SENDEVENT macro. + * Store a trap message in the trap buffer and generate an event for + * user space applications with the SK_DRIVER_SENDEVENT macro. */ QueueRlmtPortTrap(pAC, OID_SKGE_TRAP_RLMT_PORT_DOWN, (unsigned int)Param.Para32[0]); @@ -2383,6 +2456,7 @@ case SK_PNMI_EVT_RLMT_ACTIVE_DOWN: PhysPortIndex = (unsigned int)Param.Para32[0]; + NetIndex = (SK_U32)Param.Para32[1]; #ifdef DEBUG if (PhysPortIndex >= SK_MAX_MACS) { @@ -2390,8 +2464,23 @@ ("PNMI: ERR: SkPnmiEvent: SK_PNMI_EVT_RLMT_ACTIVE_DOWN parameter too high, PhysPort=%d\n", PhysPortIndex)); } + + if (NetIndex >= pAC->Rlmt.NumNets) { + + SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL, + ("PNMI: ERR: SkPnmiEvent: SK_PNMI_EVT_RLMT_ACTIVE_DOWN parameter too high, NetIndex=%d\n", + NetIndex)); + } #endif /* + * For now, ignore event if NetIndex != 0. + */ + if (Param.Para32[1] != 0) { + + return (0); + } + + /* * Nothing to do if port is already inactive */ if (!pAC->Pnmi.Port[PhysPortIndex].ActiveFlag) { @@ -2400,9 +2489,9 @@ } /* - * Update statistic counters to calculate new offset - * for the virtual port and increment semaphore to - * indicate that an update was already done. + * Update statistic counters to calculate new offset for the virtual + * port and increment semaphore to indicate that an update was already + * done. */ if (MacUpdate(pAC, IoC, 0, pAC->GIni.GIMacsFound - 1) != SK_PNMI_ERR_OK) { @@ -2413,13 +2502,12 @@ pAC->Pnmi.MacUpdatedFlag ++; /* - * Calculate new counter offset for virtual port to - * grant continous counting on port switches. The virtual - * port consists of all currently active ports. The port - * down event indicates that a port is removed fromt the - * virtual port. Therefore add the counter value of the - * removed port to the CounterOffset for the virtual port - * to grant the same counter value. + * Calculate new counter offset for virtual port to grant continous + * counting on port switches. The virtual port consists of all currently + * active ports. The port down event indicates that a port is removed + * from the virtual port. Therefore add the counter value of the removed + * port to the CounterOffset for the virtual port to grant the same + * counter value. */ for (CounterIndex = 0; CounterIndex < SK_PNMI_MAX_IDX; CounterIndex ++) { @@ -2429,8 +2517,7 @@ continue; } - Value = GetPhysStatVal(pAC, IoC, PhysPortIndex, - CounterIndex); + Value = GetPhysStatVal(pAC, IoC, PhysPortIndex, CounterIndex); pAC->Pnmi.VirtualCounterOffset[CounterIndex] += Value; } @@ -2445,6 +2532,7 @@ case SK_PNMI_EVT_RLMT_ACTIVE_UP: PhysPortIndex = (unsigned int)Param.Para32[0]; + NetIndex = (SK_U32)Param.Para32[1]; #ifdef DEBUG if (PhysPortIndex >= SK_MAX_MACS) { @@ -2452,8 +2540,23 @@ ("PNMI: ERR: SkPnmiEvent: SK_PNMI_EVT_RLMT_ACTIVE_UP parameter too high, PhysPort=%d\n", PhysPortIndex)); } + + if (NetIndex >= pAC->Rlmt.NumNets) { + + SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL, + ("PNMI: ERR: SkPnmiEvent: SK_PNMI_EVT_RLMT_ACTIVE_UP parameter too high, NetIndex=%d\n", + NetIndex)); + } #endif /* + * For now, ignore event if NetIndex != 0. + */ + if (Param.Para32[1] != 0) { + + return (0); + } + + /* * Nothing to do if port is already active */ if (pAC->Pnmi.Port[PhysPortIndex].ActiveFlag) { @@ -2462,24 +2565,22 @@ } /* - * Statistic maintanence + * Statistic maintenance */ pAC->Pnmi.RlmtChangeCts ++; - pAC->Pnmi.RlmtChangeTime = - SK_PNMI_HUNDREDS_SEC(SkOsGetTime(pAC)); + pAC->Pnmi.RlmtChangeTime = SK_PNMI_HUNDREDS_SEC(SkOsGetTime(pAC)); /* - * Store a trap message in the trap buffer and generate - * an event for user space applications with the - * SK_DRIVER_SENDEVENT macro. + * Store a trap message in the trap buffer and generate an event for + * user space applications with the SK_DRIVER_SENDEVENT macro. */ QueueRlmtNewMacTrap(pAC, PhysPortIndex); (void)SK_DRIVER_SENDEVENT(pAC, IoC); /* - * Update statistic counters to calculate new offset - * for the virtual port and increment semaphore to indicate - * that an update was already done. + * Update statistic counters to calculate new offset for the virtual + * port and increment semaphore to indicate that an update was + * already done. */ if (MacUpdate(pAC, IoC, 0, pAC->GIni.GIMacsFound - 1) != SK_PNMI_ERR_OK) { @@ -2490,11 +2591,10 @@ pAC->Pnmi.MacUpdatedFlag ++; /* - * Calculate new counter offset for virtual port to - * grant continous counting on port switches. A new port - * is added to the virtual port. Therefore substract the - * counter value of the new port from the CounterOffset - * for the virtual port to grant the same value. + * Calculate new counter offset for virtual port to grant continous + * counting on port switches. A new port is added to the virtual port. + * Therefore substract the counter value of the new port from the + * CounterOffset for the virtual port to grant the same value. */ for (CounterIndex = 0; CounterIndex < SK_PNMI_MAX_IDX; CounterIndex ++) { @@ -2504,8 +2604,7 @@ continue; } - Value = GetPhysStatVal(pAC, IoC, PhysPortIndex, - CounterIndex); + Value = GetPhysStatVal(pAC, IoC, PhysPortIndex, CounterIndex); pAC->Pnmi.VirtualCounterOffset[CounterIndex] -= Value; } @@ -2518,40 +2617,41 @@ pAC->Pnmi.MacUpdatedFlag --; break; - case SK_PNMI_EVT_RLMT_PORT_SWITCH: + case SK_PNMI_EVT_RLMT_SEGMENTATION: /* - * This event becomes obsolete if RLMT generates directly - * the events SK_PNMI_EVT_RLMT_ACTIVE_DOWN and - * SK_PNMI_EVT_RLMT_ACTIVE_UP. The events are here emulated. - * PNMI handles that multiple ports may become active. - * Increment semaphore to indicate that an update was - * already done. + * Para.Para32[0] contains the NetIndex. */ - if (MacUpdate(pAC, IoC, 0, pAC->GIni.GIMacsFound - 1) != - SK_PNMI_ERR_OK) { - - SK_PNMI_CHECKFLAGS("SkPnmiEvent: On return"); - return (0); - } - pAC->Pnmi.MacUpdatedFlag ++; - - SkPnmiEvent(pAC, IoC, SK_PNMI_EVT_RLMT_ACTIVE_DOWN, Param); - Param.Para32[0] = Param.Para32[1]; - SkPnmiEvent(pAC, IoC, SK_PNMI_EVT_RLMT_ACTIVE_UP, Param); - - pAC->Pnmi.MacUpdatedFlag --; - break; - case SK_PNMI_EVT_RLMT_SEGMENTATION: /* - * Store a trap message in the trap buffer and generate - * an event for user space applications with the - * SK_DRIVER_SENDEVENT macro. + * Store a trap message in the trap buffer and generate an event for + * user space applications with the SK_DRIVER_SENDEVENT macro. */ QueueSimpleTrap(pAC, OID_SKGE_TRAP_RLMT_SEGMENTATION); (void)SK_DRIVER_SENDEVENT(pAC, IoC); break; + case SK_PNMI_EVT_RLMT_SET_NETS: + /* + * Param.Para32[0] contains the number of Nets. + * Param.Para32[1] is reserved, contains -1. + */ + /* + * Check number of nets + */ + MaxNetNumber = pAC->GIni.GIMacsFound; + if (((unsigned int)Param.Para32[0] < 1) + || ((unsigned int)Param.Para32[0] > MaxNetNumber)) { + return (SK_PNMI_ERR_UNKNOWN_NET); + } + + if((unsigned int)Param.Para32[0] == 1){ /* single net mode */ + pAC->Pnmi.DualNetActiveFlag = SK_FALSE; + } + else { /* dual net mode */ + pAC->Pnmi.DualNetActiveFlag = SK_TRUE; + } + break; + default: break; } @@ -2580,6 +2680,7 @@ * Returns: * SK_PNMI_ERR_XXX. For details have a look to the description of the * calling functions. + * SK_PNMI_ERR_UNKNOWN_NET The requested NetIndex doesn't exist */ static int PnmiVar( @@ -2589,7 +2690,8 @@ SK_U32 Id, /* Object ID that is to be processed */ char *pBuf, /* Buffer which stores the mgmt data to be set */ unsigned int *pLen, /* Total length of mgmt data */ -SK_U32 Instance) /* Instance (1..n) that is to be set or -1 */ +SK_U32 Instance, /* Instance (1..n) that is to be set or -1 */ +SK_U32 NetIndex) /* NetIndex (0..n), in single net mode allways zero */ { unsigned int TableIndex; int Ret; @@ -2600,11 +2702,18 @@ *pLen = 0; return (SK_PNMI_ERR_UNKNOWN_OID); } + + /* + * Check NetIndex + */ + if (NetIndex >= pAC->Rlmt.NumNets) { + return (SK_PNMI_ERR_UNKNOWN_NET); + } SK_PNMI_CHECKFLAGS("PnmiVar: On call"); Ret = IdTable[TableIndex].Func(pAC, IoC, Action, Id, pBuf, pLen, - Instance, TableIndex); + Instance, TableIndex, NetIndex); SK_PNMI_CHECKFLAGS("PnmiVar: On return"); @@ -2627,6 +2736,7 @@ * * Returns: * SK_PNMI_ERR_XXX. The codes are described in the calling functions. + * SK_PNMI_ERR_UNKNOWN_NET The requested NetIndex doesn't exist */ static int PnmiStruct( @@ -2634,7 +2744,8 @@ SK_IOC IoC, /* IO context handle */ int Action, /* Set action to be performed */ char *pBuf, /* Buffer which contains the data to be set */ -unsigned int *pLen) /* Length of buffer */ +unsigned int *pLen, /* Length of buffer */ +SK_U32 NetIndex) /* NetIndex (0..n), in single net mode allways zero */ { int Ret; unsigned int TableIndex; @@ -2660,13 +2771,20 @@ return (SK_PNMI_ERR_TOO_SHORT); } + /* + * Check NetIndex + */ + if (NetIndex >= pAC->Rlmt.NumNets) { + return (SK_PNMI_ERR_UNKNOWN_NET); + } + SK_PNMI_CHECKFLAGS("PnmiStruct: On call"); /* * Update the values of RLMT and SIRQ and increment semaphores to * indicate that an update was already done. */ - if ((Ret = RlmtUpdate(pAC, IoC)) != SK_PNMI_ERR_OK) { + if ((Ret = RlmtUpdate(pAC, IoC, NetIndex)) != SK_PNMI_ERR_OK) { SK_PNMI_SET_STAT(pBuf, Ret, (SK_U32)(-1)); *pLen = SK_PNMI_MIN_STRUCT_SIZE; @@ -2716,7 +2834,7 @@ Len = 0; Ret = IdTable[TableIndex].Func(pAC, IoC, SK_PNMI_GET, IdTable[TableIndex].Id, - NULL, &Len, Instance, TableIndex); + NULL, &Len, Instance, TableIndex, NetIndex); if (Ret == SK_PNMI_ERR_UNKNOWN_INST) { @@ -2754,7 +2872,7 @@ /* Call the OID handler function */ Ret = IdTable[TableIndex].Func(pAC, IoC, Action, IdTable[TableIndex].Id, pBuf + DstOffset, - &Len, Instance, TableIndex); + &Len, Instance, TableIndex, NetIndex); if (Ret != SK_PNMI_ERR_OK) { @@ -2816,7 +2934,7 @@ * * Returns: * SK_PNMI_ERR_OK The request was successfully performed. - * SK_PNMI_ERR_GENERAL A general severe internal error occurred. + * SK_PNMI_ERR_GENERAL A general severe internal error occured. * SK_PNMI_ERR_TOO_SHORT The passed buffer is too short to contain * the correct data (e.g. a 32bit value is * needed, but a 16 bit value was passed). @@ -2836,7 +2954,8 @@ char *pBuf, /* Buffer to which to mgmt data will be retrieved */ unsigned int *pLen, /* On call: buffer length. On return: used buffer */ SK_U32 Instance, /* Instance (1..n) that is to be queried or -1 */ -unsigned int TableIndex) /* Index to the Id table */ +unsigned int TableIndex, /* Index to the Id table */ +SK_U32 NetIndex) /* NetIndex (0..n), in single net mode allways zero */ { if (Id != OID_SKGE_ALL_DATA) { @@ -2859,13 +2978,13 @@ switch (Action) { case SK_PNMI_GET: - return (SkPnmiGetStruct(pAC, IoC, pBuf, pLen)); + return (SkPnmiGetStruct(pAC, IoC, pBuf, pLen, NetIndex)); case SK_PNMI_PRESET: - return (SkPnmiPreSetStruct(pAC, IoC, pBuf, pLen)); + return (SkPnmiPreSetStruct(pAC, IoC, pBuf, pLen, NetIndex)); case SK_PNMI_SET: - return (SkPnmiSetStruct(pAC, IoC, pBuf, pLen)); + return (SkPnmiSetStruct(pAC, IoC, pBuf, pLen, NetIndex)); } SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR004, SK_PNMI_ERR004MSG); @@ -2883,7 +3002,7 @@ * * Returns: * SK_PNMI_ERR_OK The request was successfully performed. - * SK_PNMI_ERR_GENERAL A general severe internal error occurred. + * SK_PNMI_ERR_GENERAL A general severe internal error occured. * SK_PNMI_ERR_TOO_SHORT The passed buffer is too short to contain * the correct data (e.g. a 32bit value is * needed, but a 16 bit value was passed). @@ -2903,7 +3022,8 @@ char *pBuf, /* Buffer to which to mgmt data will be retrieved */ unsigned int *pLen, /* On call: buffer length. On return: used buffer */ SK_U32 Instance, /* Instance (1..n) that is to be queried or -1 */ -unsigned int TableIndex) /* Index to the Id table */ +unsigned int TableIndex, /* Index to the Id table */ +SK_U32 NetIndex) /* NetIndex (0..n), in single net mode allways zero */ { int Ret; SK_U32 ActionOp; @@ -2992,7 +3112,7 @@ case SK_PNMI_ACT_RESETCNT: /* Set all counters and timestamps to zero */ - ResetCounter(pAC, IoC); + ResetCounter(pAC, IoC, NetIndex); break; default: @@ -3017,7 +3137,7 @@ * * Returns: * SK_PNMI_ERR_OK The request was successfully performed. - * SK_PNMI_ERR_GENERAL A general severe internal error occurred. + * SK_PNMI_ERR_GENERAL A general severe internal error occured. * SK_PNMI_ERR_TOO_SHORT The passed buffer is too short to contain * the correct data (e.g. a 32bit value is * needed, but a 16 bit value was passed). @@ -3034,7 +3154,8 @@ char *pBuf, /* Buffer to which to mgmt data will be retrieved */ unsigned int *pLen, /* On call: buffer length. On return: used buffer */ SK_U32 Instance, /* Instance (1..n) that is to be queried or -1 */ -unsigned int TableIndex) /* Index to the Id table */ +unsigned int TableIndex, /* Index to the Id table */ +SK_U32 NetIndex) /* NetIndex (0..n), in single net mode allways zero */ { int Ret; SK_U64 StatVal; @@ -3080,7 +3201,7 @@ } #else /* SK_NDIS_64BIT_CTR */ - + /* * for compatibility, at least 32bit are required for oid */ @@ -3092,7 +3213,7 @@ *pLen = sizeof(SK_U64); return (SK_PNMI_ERR_TOO_SHORT); } - + Is64BitReq = (*pLen < sizeof(SK_U64)) ? SK_FALSE : SK_TRUE; #endif /* SK_NDIS_64BIT_CTR */ break; @@ -3117,17 +3238,17 @@ switch (Id) { case OID_802_3_PERMANENT_ADDRESS: - CopyMac(pBuf, &pAC->Addr.PermanentMacAddress); + CopyMac(pBuf, &pAC->Addr.Net[NetIndex].PermanentMacAddress); *pLen = sizeof(SK_MAC_ADDR); break; case OID_802_3_CURRENT_ADDRESS: - CopyMac(pBuf, &pAC->Addr.CurrentMacAddress); + CopyMac(pBuf, &pAC->Addr.Net[NetIndex].CurrentMacAddress); *pLen = sizeof(SK_MAC_ADDR); break; default: - StatVal = GetStatVal(pAC, IoC, 0, IdTable[TableIndex].Param); + StatVal = GetStatVal(pAC, IoC, 0, IdTable[TableIndex].Param, NetIndex); /* * by default 32bit values are evaluated @@ -3159,7 +3280,7 @@ * * Returns: * SK_PNMI_ERR_OK The request was successfully performed. - * SK_PNMI_ERR_GENERAL A general severe internal error occurred. + * SK_PNMI_ERR_GENERAL A general severe internal error occured. * SK_PNMI_ERR_TOO_SHORT The passed buffer is too short to contain * the correct data (e.g. a 32bit value is * needed, but a 16 bit value was passed). @@ -3176,7 +3297,8 @@ char *pBuf, /* Buffer to which to mgmt data will be retrieved */ unsigned int *pLen, /* On call: buffer length. On return: used buffer */ SK_U32 Instance, /* Instance (1..n) that is to be queried or -1 */ -unsigned int TableIndex) /* Index to the Id table */ +unsigned int TableIndex, /* Index to the Id table */ +SK_U32 NetIndex) /* NetIndex (0..n), in single net mode allways zero */ { unsigned int LogPortMax; unsigned int LogPortIndex; @@ -3194,22 +3316,28 @@ PhysPortMax = pAC->GIni.GIMacsFound; LogPortMax = SK_PNMI_PORT_PHYS2LOG(PhysPortMax); - if ((Instance != (SK_U32)(-1))) { + if(pAC->Pnmi.DualNetActiveFlag == SK_TRUE){ /* Dual net mode */ + LogPortMax--; + } + if ((Instance != (SK_U32)(-1))) { /* Only one specific instance is queried */ + /* Check instance range */ if ((Instance < 1) || (Instance > LogPortMax)) { *pLen = 0; return (SK_PNMI_ERR_UNKNOWN_INST); } - LogPortIndex = SK_PNMI_PORT_INST2LOG(Instance); Limit = LogPortIndex + 1; } - else { + + else { /* Instance == (SK_U32)(-1), get all Instances of that OID */ + LogPortIndex = 0; Limit = LogPortMax; } + /* * Check action */ @@ -3232,7 +3360,7 @@ * Update XMAC statistic and increment semaphore to indicate that * an update was already done. */ - Ret = MacUpdate(pAC, IoC, 0, PhysPortMax - 1); + Ret = MacUpdate(pAC, IoC, 0, pAC->GIni.GIMacsFound - 1); if (Ret != SK_PNMI_ERR_OK) { *pLen = 0; @@ -3264,15 +3392,15 @@ */ case OID_SKGE_STAT_RX_TOO_LONG: StatVal = GetStatVal(pAC, IoC, LogPortIndex, - IdTable[TableIndex].Param) - + IdTable[TableIndex].Param, NetIndex) - GetStatVal(pAC, IoC, LogPortIndex, - SK_PNMI_HRX_LONGFRAMES); + SK_PNMI_HRX_LONGFRAMES, NetIndex); SK_PNMI_STORE_U64(pBuf + Offset, StatVal); break; default: StatVal = GetStatVal(pAC, IoC, LogPortIndex, - IdTable[TableIndex].Param); + IdTable[TableIndex].Param, NetIndex); SK_PNMI_STORE_U64(pBuf + Offset, StatVal); break; } @@ -3299,7 +3427,7 @@ * * Returns: * SK_PNMI_ERR_OK The request was successfully performed. - * SK_PNMI_ERR_GENERAL A general severe internal error occurred. + * SK_PNMI_ERR_GENERAL A general severe internal error occured. * SK_PNMI_ERR_TOO_SHORT The passed buffer is too short to contain * the correct data (e.g. a 32bit value is * needed, but a 16 bit value was passed). @@ -3319,7 +3447,8 @@ char *pBuf, /* Buffer to which to mgmt data will be retrieved */ unsigned int *pLen, /* On call: buffer length. On return: used buffer */ SK_U32 Instance, /* Instance (1..n) that is to be queried or -1 */ -unsigned int TableIndex) /* Index to the Id table */ +unsigned int TableIndex, /* Index to the Id table */ +SK_U32 NetIndex) /* NetIndex (0..n), in single net mode allways zero */ { int Ret; unsigned int LogPortMax; @@ -3330,24 +3459,31 @@ unsigned int Offset = 0; + /* - * Calculate instance if wished + * Calculate instance if wished. MAC index 0 is the virtual + * MAC. */ PhysPortMax = pAC->GIni.GIMacsFound; LogPortMax = SK_PNMI_PORT_PHYS2LOG(PhysPortMax); - if ((Instance != (SK_U32)(-1))) { - + if(pAC->Pnmi.DualNetActiveFlag == SK_TRUE){ /* Dual net mode */ + LogPortMax--; + } + + if ((Instance != (SK_U32)(-1))) { /* Only one specific instance is queried */ + /* Check instance range */ if ((Instance < 1) || (Instance > LogPortMax)) { *pLen = 0; return (SK_PNMI_ERR_UNKNOWN_INST); } - LogPortIndex = SK_PNMI_PORT_INST2LOG(Instance); Limit = LogPortIndex + 1; } - else { + + else { /* Instance == (SK_U32)(-1), get all Instances of that OID */ + LogPortIndex = 0; Limit = LogPortMax; } @@ -3375,34 +3511,28 @@ case OID_SKGE_PHYS_CUR_ADDR: if (LogPortIndex == 0) { - - CopyMac(pBuf + Offset, &pAC->Addr. - CurrentMacAddress); + CopyMac(pBuf + Offset, &pAC->Addr.Net[NetIndex].CurrentMacAddress); } else { - PhysPortIndex = SK_PNMI_PORT_LOG2PHYS( - pAC, LogPortIndex); + PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(pAC, LogPortIndex); - CopyMac(pBuf + Offset, &pAC->Addr. - Port[PhysPortIndex]. - CurrentMacAddress); + CopyMac(pBuf + Offset, + &pAC->Addr.Port[PhysPortIndex].CurrentMacAddress); } Offset += 6; break; case OID_SKGE_PHYS_FAC_ADDR: if (LogPortIndex == 0) { - - CopyMac(pBuf + Offset, &pAC->Addr. - PermanentMacAddress); + CopyMac(pBuf + Offset, + &pAC->Addr.Net[NetIndex].PermanentMacAddress); } else { PhysPortIndex = SK_PNMI_PORT_LOG2PHYS( pAC, LogPortIndex); - CopyMac(pBuf + Offset, &pAC->Addr. - Port[PhysPortIndex]. - PermanentMacAddress); + CopyMac(pBuf + Offset, + &pAC->Addr.Port[PhysPortIndex].PermanentMacAddress); } Offset += 6; break; @@ -3509,7 +3639,7 @@ * * Returns: * SK_PNMI_ERR_OK The request was successfully performed. - * SK_PNMI_ERR_GENERAL A general severe internal error occurred. + * SK_PNMI_ERR_GENERAL A general severe internal error occured. * SK_PNMI_ERR_TOO_SHORT The passed buffer is too short to contain * the correct data (e.g. a 32bit value is * needed, but a 16 bit value was passed). @@ -3526,7 +3656,8 @@ char *pBuf, /* Buffer to which to mgmt data will be retrieved */ unsigned int *pLen, /* On call: buffer length. On return: used buffer */ SK_U32 Instance, /* Instance (1..n) that is to be queried or -1 */ -unsigned int TableIndex) /* Index to the Id table */ +unsigned int TableIndex, /* Index to the Id table */ +SK_U32 NetIndex) /* NetIndex (0..n), in single net mode allways zero */ { unsigned int Index; unsigned int Limit; @@ -3538,15 +3669,14 @@ * Calculate instance if wished */ if (Instance != (SK_U32)(-1)) { - + if ((Instance < 1) || (Instance > SKCS_NUM_PROTOCOLS)) { *pLen = 0; return (SK_PNMI_ERR_UNKNOWN_INST); } - Index = (unsigned int)Instance - 1; - Limit = (unsigned int)Instance; + Limit = Index + 1; } else { Index = 0; @@ -3579,23 +3709,23 @@ switch (Id) { case OID_SKGE_CHKSM_RX_OK_CTS: - StatVal = pAC->Csum.ProtoStats[Index].RxOkCts; + StatVal = pAC->Csum.ProtoStats[NetIndex][Index].RxOkCts; break; case OID_SKGE_CHKSM_RX_UNABLE_CTS: - StatVal = pAC->Csum.ProtoStats[Index].RxUnableCts; + StatVal = pAC->Csum.ProtoStats[NetIndex][Index].RxUnableCts; break; case OID_SKGE_CHKSM_RX_ERR_CTS: - StatVal = pAC->Csum.ProtoStats[Index].RxErrCts; + StatVal = pAC->Csum.ProtoStats[NetIndex][Index].RxErrCts; break; case OID_SKGE_CHKSM_TX_OK_CTS: - StatVal = pAC->Csum.ProtoStats[Index].TxOkCts; + StatVal = pAC->Csum.ProtoStats[NetIndex][Index].TxOkCts; break; case OID_SKGE_CHKSM_TX_UNABLE_CTS: - StatVal = pAC->Csum.ProtoStats[Index].TxUnableCts; + StatVal = pAC->Csum.ProtoStats[NetIndex][Index].TxUnableCts; break; default: @@ -3628,7 +3758,7 @@ * * Returns: * SK_PNMI_ERR_OK The request was successfully performed. - * SK_PNMI_ERR_GENERAL A general severe internal error occurred. + * SK_PNMI_ERR_GENERAL A general severe internal error occured. * SK_PNMI_ERR_TOO_SHORT The passed buffer is too short to contain * the correct data (e.g. a 32bit value is * needed, but a 16 bit value was passed). @@ -3645,7 +3775,8 @@ char *pBuf, /* Buffer to which to mgmt data will be retrieved */ unsigned int *pLen, /* On call: buffer length. On return: used buffer */ SK_U32 Instance, /* Instance (1..n) that is to be queried or -1 */ -unsigned int TableIndex) /* Index to the Id table */ +unsigned int TableIndex, /* Index to the Id table */ +SK_U32 NetIndex) /* NetIndex (0..n), in single net mode allways zero */ { unsigned int i; unsigned int Index; @@ -3872,7 +4003,7 @@ * * Returns: * SK_PNMI_ERR_OK The request was successfully performed. - * SK_PNMI_ERR_GENERAL A general severe internal error occurred. + * SK_PNMI_ERR_GENERAL A general severe internal error occured. * SK_PNMI_ERR_TOO_SHORT The passed buffer is too short to contain * the correct data (e.g. a 32bit value is * needed, but a 16 bit value was passed). @@ -3892,13 +4023,14 @@ char *pBuf, /* Buffer to which to mgmt data will be retrieved */ unsigned int *pLen, /* On call: buffer length. On return: used buffer */ SK_U32 Instance, /* Instance (1..n) that is to be queried or -1 */ -unsigned int TableIndex) /* Index to the Id table */ +unsigned int TableIndex, /* Index to the Id table */ +SK_U32 NetIndex) /* NetIndex (0..n), in single net mode allways zero */ { SK_VPD_STATUS *pVpdStatus; unsigned int BufLen; char Buf[256]; - char KeyArr[SK_PNMI_VPD_ARR_SIZE][SK_PNMI_VPD_STR_SIZE]; - char KeyStr[SK_PNMI_VPD_STR_SIZE]; + char KeyArr[SK_PNMI_VPD_ENTRIES][SK_PNMI_VPD_KEY_SIZE]; + char KeyStr[SK_PNMI_VPD_KEY_SIZE]; unsigned int KeyNo; unsigned int Offset; unsigned int Index; @@ -3914,7 +4046,6 @@ Ret = GetVpdKeyArr(pAC, IoC, &KeyArr[0][0], sizeof(KeyArr), &KeyNo); if (Ret != SK_PNMI_ERR_OK) { - *pLen = 0; return (Ret); } @@ -3939,7 +4070,6 @@ for (Index = 0; Index < KeyNo; Index ++) { if (SK_STRCMP(KeyStr, KeyArr[Index]) == 0) { - FirstIndex = Index; LastIndex = Index+1; break; @@ -4352,7 +4482,7 @@ * * Returns: * SK_PNMI_ERR_OK The request was successfully performed. - * SK_PNMI_ERR_GENERAL A general severe internal error occurred. + * SK_PNMI_ERR_GENERAL A general severe internal error occured. * SK_PNMI_ERR_TOO_SHORT The passed buffer is too short to contain * the correct data (e.g. a 32bit value is * needed, but a 16 bit value was passed). @@ -4369,7 +4499,8 @@ char *pBuf, /* Buffer to which to mgmt data will be retrieved */ unsigned int *pLen, /* On call: buffer length. On return: used buffer */ SK_U32 Instance, /* Instance (1..n) that is to be queried or -1 */ -unsigned int TableIndex) /* Index to the Id table */ +unsigned int TableIndex, /* Index to the Id table */ +SK_U32 NetIndex) /* NetIndex (0..n), in single net mode allways zero */ { int Ret; unsigned int Index; @@ -4419,7 +4550,7 @@ } #else /* SK_NDIS_64BIT_CTR */ - + /* * for compatibility, at least 32bit are required for oid */ @@ -4431,7 +4562,7 @@ *pLen = sizeof(SK_U64); return (SK_PNMI_ERR_TOO_SHORT); } - + Is64BitReq = (*pLen < sizeof(SK_U64)) ? SK_FALSE : SK_TRUE; #endif /* SK_NDIS_64BIT_CTR */ break; @@ -4529,32 +4660,30 @@ case OID_SKGE_IN_ERRORS_CTS: case OID_GEN_RCV_ERROR: Val64RxHwErrs = - GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_MISSED) + - GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_FRAMING) + - GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_OVERFLOW)+ - GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_JABBER) + - GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_CARRIER) + - GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_IRLENGTH)+ - GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_SYMBOL) + - GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_SHORTS) + - GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_RUNT) + - GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_TOO_LONG)- - GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_LONGFRAMES)+ - GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_FCS) + - GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_CEXT); - break; + GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_MISSED, NetIndex) + + GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_FRAMING, NetIndex) + + GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_OVERFLOW, NetIndex)+ + GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_JABBER, NetIndex) + + GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_CARRIER, NetIndex) + + GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_IRLENGTH, NetIndex)+ + GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_SYMBOL, NetIndex) + + GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_SHORTS, NetIndex) + + GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_RUNT, NetIndex) + + GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_TOO_LONG, NetIndex)- + GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_LONGFRAMES, NetIndex)+ + GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_FCS, NetIndex) + + GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_CEXT, NetIndex); + break; case OID_SKGE_TX_HW_ERROR_CTS: case OID_SKGE_OUT_ERROR_CTS: case OID_GEN_XMIT_ERROR: Val64TxHwErrs = - GetStatVal(pAC, IoC, 0, - SK_PNMI_HTX_EXCESS_COL) + - GetStatVal(pAC, IoC, 0, SK_PNMI_HTX_LATE_COL)+ - GetStatVal(pAC, IoC, 0, SK_PNMI_HTX_UNDERRUN)+ - GetStatVal(pAC, IoC, 0, SK_PNMI_HTX_CARRIER)+ - GetStatVal(pAC, IoC, 0, - SK_PNMI_HTX_EXCESS_COL); + GetStatVal(pAC, IoC, 0, SK_PNMI_HTX_EXCESS_COL, NetIndex) + + GetStatVal(pAC, IoC, 0, SK_PNMI_HTX_LATE_COL, NetIndex)+ + GetStatVal(pAC, IoC, 0, SK_PNMI_HTX_UNDERRUN, NetIndex)+ + GetStatVal(pAC, IoC, 0, SK_PNMI_HTX_CARRIER, NetIndex)+ + GetStatVal(pAC, IoC, 0, SK_PNMI_HTX_EXCESS_COL, NetIndex); break; } } @@ -4766,61 +4895,142 @@ break; case OID_SKGE_TX_SW_QUEUE_LEN: - Val64 = pAC->Pnmi.TxSwQueueLen; + /* Dual net mode */ + if(pAC->Pnmi.DualNetActiveFlag == SK_TRUE){ + Val64 = pAC->Pnmi.Port[NetIndex].TxSwQueueLen; + } + /* Single net mode */ + else { + Val64 = pAC->Pnmi.Port[0].TxSwQueueLen + + pAC->Pnmi.Port[1].TxSwQueueLen; + } SK_PNMI_STORE_U64(pBuf, Val64); *pLen = sizeof(SK_U64); break; + case OID_SKGE_TX_SW_QUEUE_MAX: - Val64 = pAC->Pnmi.TxSwQueueMax; + /* Dual net mode */ + if(pAC->Pnmi.DualNetActiveFlag == SK_TRUE){ + Val64 = pAC->Pnmi.Port[NetIndex].TxSwQueueMax; + } + /* Single net mode */ + else { + Val64 = pAC->Pnmi.Port[0].TxSwQueueMax + + pAC->Pnmi.Port[1].TxSwQueueMax; + } SK_PNMI_STORE_U64(pBuf, Val64); *pLen = sizeof(SK_U64); break; case OID_SKGE_TX_RETRY: - Val64 = pAC->Pnmi.TxRetryCts; + /* Dual net mode */ + if(pAC->Pnmi.DualNetActiveFlag == SK_TRUE){ + Val64 = pAC->Pnmi.Port[NetIndex].TxRetryCts; + } + /* Single net mode */ + else { + Val64 = pAC->Pnmi.Port[0].TxRetryCts + + pAC->Pnmi.Port[1].TxRetryCts; + } SK_PNMI_STORE_U64(pBuf, Val64); *pLen = sizeof(SK_U64); break; case OID_SKGE_RX_INTR_CTS: - Val64 = pAC->Pnmi.RxIntrCts; + /* Dual net mode */ + if(pAC->Pnmi.DualNetActiveFlag == SK_TRUE){ + Val64 = pAC->Pnmi.Port[NetIndex].RxIntrCts; + } + /* Single net mode */ + else { + Val64 = pAC->Pnmi.Port[0].RxIntrCts + + pAC->Pnmi.Port[1].RxIntrCts; + } SK_PNMI_STORE_U64(pBuf, Val64); *pLen = sizeof(SK_U64); break; case OID_SKGE_TX_INTR_CTS: - Val64 = pAC->Pnmi.TxIntrCts; + /* Dual net mode */ + if(pAC->Pnmi.DualNetActiveFlag == SK_TRUE){ + Val64 = pAC->Pnmi.Port[NetIndex].TxIntrCts; + } + /* Single net mode */ + else { + Val64 = pAC->Pnmi.Port[0].TxIntrCts + + pAC->Pnmi.Port[1].TxIntrCts; + } SK_PNMI_STORE_U64(pBuf, Val64); *pLen = sizeof(SK_U64); break; case OID_SKGE_RX_NO_BUF_CTS: - Val64 = pAC->Pnmi.RxNoBufCts; + /* Dual net mode */ + if(pAC->Pnmi.DualNetActiveFlag == SK_TRUE){ + Val64 = pAC->Pnmi.Port[NetIndex].RxNoBufCts; + } + /* Single net mode */ + else { + Val64 = pAC->Pnmi.Port[0].RxNoBufCts + + pAC->Pnmi.Port[1].RxNoBufCts; + } SK_PNMI_STORE_U64(pBuf, Val64); *pLen = sizeof(SK_U64); break; case OID_SKGE_TX_NO_BUF_CTS: - Val64 = pAC->Pnmi.TxNoBufCts; + /* Dual net mode */ + if(pAC->Pnmi.DualNetActiveFlag == SK_TRUE){ + Val64 = pAC->Pnmi.Port[NetIndex].TxNoBufCts; + } + /* Single net mode */ + else { + Val64 = pAC->Pnmi.Port[0].TxNoBufCts + + pAC->Pnmi.Port[1].TxNoBufCts; + } SK_PNMI_STORE_U64(pBuf, Val64); *pLen = sizeof(SK_U64); break; case OID_SKGE_TX_USED_DESCR_NO: - Val64 = pAC->Pnmi.TxUsedDescrNo; + /* Dual net mode */ + if(pAC->Pnmi.DualNetActiveFlag == SK_TRUE){ + Val64 = pAC->Pnmi.Port[NetIndex].TxUsedDescrNo; + } + /* Single net mode */ + else { + Val64 = pAC->Pnmi.Port[0].TxUsedDescrNo + + pAC->Pnmi.Port[1].TxUsedDescrNo; + } SK_PNMI_STORE_U64(pBuf, Val64); *pLen = sizeof(SK_U64); break; case OID_SKGE_RX_DELIVERED_CTS: - Val64 = pAC->Pnmi.RxDeliveredCts; + /* Dual net mode */ + if(pAC->Pnmi.DualNetActiveFlag == SK_TRUE){ + Val64 = pAC->Pnmi.Port[NetIndex].RxDeliveredCts; + } + /* Single net mode */ + else { + Val64 = pAC->Pnmi.Port[0].RxDeliveredCts + + pAC->Pnmi.Port[1].RxDeliveredCts; + } SK_PNMI_STORE_U64(pBuf, Val64); *pLen = sizeof(SK_U64); break; case OID_SKGE_RX_OCTETS_DELIV_CTS: - Val64 = pAC->Pnmi.RxOctetsDeliveredCts; + /* Dual net mode */ + if(pAC->Pnmi.DualNetActiveFlag == SK_TRUE){ + Val64 = pAC->Pnmi.Port[NetIndex].RxOctetsDeliveredCts; + } + /* Single net mode */ + else { + Val64 = pAC->Pnmi.Port[0].RxOctetsDeliveredCts + + pAC->Pnmi.Port[1].RxOctetsDeliveredCts; + } SK_PNMI_STORE_U64(pBuf, Val64); *pLen = sizeof(SK_U64); break; @@ -4836,19 +5046,45 @@ break; case OID_SKGE_IN_ERRORS_CTS: - Val64 = Val64RxHwErrs + pAC->Pnmi.RxNoBufCts; + /* Dual net mode */ + if(pAC->Pnmi.DualNetActiveFlag == SK_TRUE){ + Val64 = Val64RxHwErrs + pAC->Pnmi.Port[NetIndex].RxNoBufCts; + } + /* Single net mode */ + else { + Val64 = Val64RxHwErrs + + pAC->Pnmi.Port[0].RxNoBufCts + + pAC->Pnmi.Port[1].RxNoBufCts; + } SK_PNMI_STORE_U64(pBuf, Val64); *pLen = sizeof(SK_U64); break; case OID_SKGE_OUT_ERROR_CTS: - Val64 = Val64TxHwErrs + pAC->Pnmi.TxNoBufCts; + /* Dual net mode */ + if(pAC->Pnmi.DualNetActiveFlag == SK_TRUE){ + Val64 = Val64TxHwErrs + pAC->Pnmi.Port[NetIndex].TxNoBufCts; + } + /* Single net mode */ + else { + Val64 = Val64TxHwErrs + + pAC->Pnmi.Port[0].TxNoBufCts + + pAC->Pnmi.Port[1].TxNoBufCts; + } SK_PNMI_STORE_U64(pBuf, Val64); *pLen = sizeof(SK_U64); break; case OID_SKGE_ERR_RECOVERY_CTS: - Val64 = pAC->Pnmi.ErrRecoveryCts; + /* Dual net mode */ + if(pAC->Pnmi.DualNetActiveFlag == SK_TRUE){ + Val64 = pAC->Pnmi.Port[NetIndex].ErrRecoveryCts; + } + /* Single net mode */ + else { + Val64 = pAC->Pnmi.Port[0].ErrRecoveryCts + + pAC->Pnmi.Port[1].ErrRecoveryCts; + } SK_PNMI_STORE_U64(pBuf, Val64); *pLen = sizeof(SK_U64); break; @@ -4867,13 +5103,12 @@ break; case OID_GEN_RCV_ERROR: - Val64 = Val64RxHwErrs + pAC->Pnmi.RxNoBufCts; + Val64 = Val64RxHwErrs + pAC->Pnmi.Port[NetIndex].RxNoBufCts; /* * by default 32bit values are evaluated */ if (!Is64BitReq) { - SK_U32 Val32; Val32 = (SK_U32)Val64; SK_PNMI_STORE_U32(pBuf, Val32); *pLen = sizeof(SK_U32); @@ -4885,13 +5120,12 @@ break; case OID_GEN_XMIT_ERROR: - Val64 = Val64TxHwErrs + pAC->Pnmi.TxNoBufCts; + Val64 = Val64TxHwErrs + pAC->Pnmi.Port[NetIndex].TxNoBufCts; /* * by default 32bit values are evaluated */ if (!Is64BitReq) { - SK_U32 Val32; Val32 = (SK_U32)Val64; SK_PNMI_STORE_U32(pBuf, Val32); *pLen = sizeof(SK_U32); @@ -4903,13 +5137,12 @@ break; case OID_GEN_RCV_NO_BUFFER: - Val64 = pAC->Pnmi.RxNoBufCts; + Val64 = pAC->Pnmi.Port[NetIndex].RxNoBufCts; /* * by default 32bit values are evaluated */ if (!Is64BitReq) { - SK_U32 Val32; Val32 = (SK_U32)Val64; SK_PNMI_STORE_U32(pBuf, Val32); *pLen = sizeof(SK_U32); @@ -4921,7 +5154,7 @@ break; case OID_GEN_TRANSMIT_QUEUE_LENGTH: - Val32 = (SK_U32)pAC->Pnmi.TxSwQueueLen; + Val32 = (SK_U32)pAC->Pnmi.Port[NetIndex].TxSwQueueLen; SK_PNMI_STORE_U32(pBuf, Val32); *pLen = sizeof(SK_U32); break; @@ -4956,7 +5189,7 @@ * * Returns: * SK_PNMI_ERR_OK The request was successfully performed. - * SK_PNMI_ERR_GENERAL A general severe internal error occurred. + * SK_PNMI_ERR_GENERAL A general severe internal error occured. * SK_PNMI_ERR_TOO_SHORT The passed buffer is too short to contain * the correct data (e.g. a 32bit value is * needed, but a 16 bit value was passed). @@ -4976,7 +5209,8 @@ char *pBuf, /* Buffer to which to mgmt data will be retrieved */ unsigned int *pLen, /* On call: buffer length. On return: used buffer */ SK_U32 Instance, /* Instance (1..n) that is to be queried or -1 */ -unsigned int TableIndex) /* Index to the Id table */ +unsigned int TableIndex, /* Index to the Id table */ +SK_U32 NetIndex) /* NetIndex (0..n), in single net mode allways zero */ { int Ret; unsigned int PhysPortIndex; @@ -5049,7 +5283,7 @@ * statistic always up to date some time. Then we can * remove this type of call. */ - if ((Ret = RlmtUpdate(pAC, IoC)) != SK_PNMI_ERR_OK) { + if ((Ret = RlmtUpdate(pAC, IoC, NetIndex)) != SK_PNMI_ERR_OK) { *pLen = 0; return (Ret); @@ -5062,7 +5296,7 @@ switch (Id) { case OID_SKGE_RLMT_MODE: - *pBuf = (char)pAC->Rlmt.RlmtMode; + *pBuf = (char)pAC->Rlmt.Net[0].RlmtMode; *pLen = sizeof(char); break; @@ -5088,8 +5322,7 @@ if (pAC->Pnmi.Port[PhysPortIndex].ActiveFlag) { - *pBuf = (char)SK_PNMI_PORT_PHYS2LOG( - PhysPortIndex); + *pBuf = (char)SK_PNMI_PORT_PHYS2LOG(PhysPortIndex); break; } } @@ -5097,8 +5330,7 @@ break; case OID_SKGE_RLMT_PORT_PREFERRED: - *pBuf = (char)SK_PNMI_PORT_PHYS2LOG( - pAC->Rlmt.MacPreferred); + *pBuf = (char)SK_PNMI_PORT_PHYS2LOG(pAC->Rlmt.Net[NetIndex].Preference); *pLen = sizeof(char); break; @@ -5165,6 +5397,7 @@ /* Send an event to RLMT to change the mode */ SK_MEMSET((char *)&EventParam, 0, sizeof(EventParam)); EventParam.Para32[0] |= (SK_U32)(*pBuf); + EventParam.Para32[1] = 0; if (SkRlmtEvent(pAC, IoC, SK_RLMT_MODE_CHANGE, EventParam) > 0) { @@ -5204,6 +5437,7 @@ */ SK_MEMSET((char *)&EventParam, 0, sizeof(EventParam)); EventParam.Para32[0] = (SK_U32)(*pBuf) - 1; + EventParam.Para32[1] = NetIndex; if (SkRlmtEvent(pAC, IoC, SK_RLMT_PREFPORT_CHANGE, EventParam) > 0) { @@ -5264,7 +5498,7 @@ * * Returns: * SK_PNMI_ERR_OK The request was successfully performed. - * SK_PNMI_ERR_GENERAL A general severe internal error occurred. + * SK_PNMI_ERR_GENERAL A general severe internal error occured. * SK_PNMI_ERR_TOO_SHORT The passed buffer is too short to contain * the correct data (e.g. a 32bit value is * needed, but a 16 bit value was passed). @@ -5281,7 +5515,8 @@ char *pBuf, /* Buffer to which to mgmt data will be retrieved */ unsigned int *pLen, /* On call: buffer length. On return: used buffer */ SK_U32 Instance, /* Instance (1..n) that is to be queried or -1 */ -unsigned int TableIndex) /* Index to the Id table */ +unsigned int TableIndex, /* Index to the Id table */ +SK_U32 NetIndex) /* NetIndex (0..n), in single net mode allways zero */ { unsigned int PhysPortMax; unsigned int PhysPortIndex; @@ -5291,26 +5526,40 @@ SK_U32 Val32; SK_U64 Val64; - /* * Calculate the port indexes from the instance */ PhysPortMax = pAC->GIni.GIMacsFound; if ((Instance != (SK_U32)(-1))) { - + /* Check instance range */ if ((Instance < 1) || (Instance > PhysPortMax)) { *pLen = 0; return (SK_PNMI_ERR_UNKNOWN_INST); } + /* Single net mode */ PhysPortIndex = Instance - 1; + + /* Dual net mode */ + if(pAC->Pnmi.DualNetActiveFlag == SK_TRUE){ + PhysPortIndex = NetIndex; + } + + /* Both net modes */ Limit = PhysPortIndex + 1; } else { + /* Single net mode */ PhysPortIndex = 0; Limit = PhysPortMax; + + /* Dual net mode */ + if(pAC->Pnmi.DualNetActiveFlag == SK_TRUE){ + PhysPortIndex = NetIndex; + Limit = PhysPortIndex + 1; + } } /* @@ -5360,7 +5609,7 @@ * Update statistic and increment semaphores to indicate that * an update was already done. */ - if ((Ret = RlmtUpdate(pAC, IoC)) != SK_PNMI_ERR_OK) { + if ((Ret = RlmtUpdate(pAC, IoC, NetIndex)) != SK_PNMI_ERR_OK) { *pLen = 0; return (Ret); @@ -5449,7 +5698,7 @@ * * Returns: * SK_PNMI_ERR_OK The request was successfully performed. - * SK_PNMI_ERR_GENERAL A general severe internal error occurred. + * SK_PNMI_ERR_GENERAL A general severe internal error occured. * SK_PNMI_ERR_TOO_SHORT The passed buffer is too short to contain * the correct data (e.g. a 32bit value is * needed, but a 16 bit value was passed). @@ -5469,7 +5718,8 @@ char *pBuf, /* Buffer to which to mgmt data will be retrieved */ unsigned int *pLen, /* On call: buffer length. On return: used buffer */ SK_U32 Instance, /* Instance (1..n) that is to be queried or -1 */ -unsigned int TableIndex) /* Index to the Id table */ +unsigned int TableIndex, /* Index to the Id table */ +SK_U32 NetIndex) /* NetIndex (0..n), in single net mode allways zero */ { unsigned int PhysPortMax; unsigned int PhysPortIndex; @@ -5480,6 +5730,7 @@ char Val8; int Ret; SK_EVPARA EventParam; + SK_U32 Val32; /* @@ -5489,18 +5740,23 @@ PhysPortMax = pAC->GIni.GIMacsFound; LogPortMax = SK_PNMI_PORT_PHYS2LOG(PhysPortMax); - if ((Instance != (SK_U32)(-1))) { + if(pAC->Pnmi.DualNetActiveFlag == SK_TRUE){ /* Dual net mode */ + LogPortMax--; + } + if ((Instance != (SK_U32)(-1))) { /* Only one specific instance is queried */ + /* Check instance range */ if ((Instance < 1) || (Instance > LogPortMax)) { *pLen = 0; return (SK_PNMI_ERR_UNKNOWN_INST); } - LogPortIndex = SK_PNMI_PORT_INST2LOG(Instance); Limit = LogPortIndex + 1; } - else { + + else { /* Instance == (SK_U32)(-1), get all Instances of that OID */ + LogPortIndex = 0; Limit = LogPortMax; } @@ -5535,10 +5791,17 @@ } break; + case OID_SKGE_MTU: + if (*pLen < sizeof(SK_U32)) { + + *pLen = sizeof(SK_U32); + return (SK_PNMI_ERR_TOO_SHORT); + } + break; + default: SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR041, SK_PNMI_ERR041MSG); - *pLen = 0; return (SK_PNMI_ERR_GENERAL); } @@ -5755,6 +6018,12 @@ Offset += sizeof(char); break; + case OID_SKGE_MTU: + Val32 = SK_DRIVER_GET_MTU(pAC, IoC, NetIndex); + SK_PNMI_STORE_U32(pBuf + Offset, Val32); + Offset += sizeof(SK_U32); + break; + default: SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR042, SK_PNMI_ERR042MSG); @@ -5790,7 +6059,20 @@ } break; - default: + case OID_SKGE_MTU: + if (*pLen < sizeof(SK_U32)) { + + *pLen = sizeof(SK_U32); + return (SK_PNMI_ERR_TOO_SHORT); + } + if (*pLen != sizeof(SK_U32)) { + + *pLen = 0; + return (SK_PNMI_ERR_BAD_VALUE); + } + break; + + default: *pLen = 0; return (SK_PNMI_ERR_READ_ONLY); } @@ -5812,7 +6094,8 @@ break; } if (Val8 < SK_LMODE_HALF || - Val8 > SK_LMODE_AUTOSENSE) { + (LogPortIndex != 0 && Val8 > SK_LMODE_AUTOSENSE) || + (LogPortIndex == 0 && Val8 > SK_LMODE_INDETERMINATED)) { *pLen = 0; return (SK_PNMI_ERR_BAD_VALUE); @@ -5887,7 +6170,8 @@ break; } if (Val8 < SK_FLOW_MODE_NONE || - Val8 > SK_FLOW_MODE_SYM_OR_REM) { + (LogPortIndex != 0 && Val8 > SK_FLOW_MODE_SYM_OR_REM) || + (LogPortIndex == 0 && Val8 > SK_FLOW_MODE_INDETERMINATED)) { *pLen = 0; return (SK_PNMI_ERR_BAD_VALUE); @@ -5963,7 +6247,8 @@ break; } if (Val8 < SK_MS_MODE_AUTO || - Val8 > SK_MS_MODE_SLAVE) { + (LogPortIndex != 0 && Val8 > SK_MS_MODE_SLAVE) || + (LogPortIndex == 0 && Val8 > SK_MS_MODE_INDETERMINATED)) { *pLen = 0; return (SK_PNMI_ERR_BAD_VALUE); @@ -6026,10 +6311,35 @@ return (SK_PNMI_ERR_GENERAL); } } - + Offset += sizeof(char); break; + case OID_SKGE_MTU : + /* Check the value range */ + Val32 = *(SK_U32*)(pBuf + Offset); + if (Val32 == 0) { + /* mtu of this port remains unchanged */ + Offset += sizeof(SK_U32); + break; + } + if (SK_DRIVER_PRESET_MTU(pAC, IoC, NetIndex, Val32) != 0) { + *pLen = 0; + return (SK_PNMI_ERR_BAD_VALUE); + } + + /* The preset ends here */ + if (Action == SK_PNMI_PRESET) { + return (SK_PNMI_ERR_OK); + } + + if (SK_DRIVER_SET_MTU(pAC, IoC, NetIndex, Val32) != 0) { + return (SK_PNMI_ERR_GENERAL); + } + + Offset += sizeof(SK_U32); + break; + default: SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR045, SK_PNMI_ERR045MSG); @@ -6052,7 +6362,7 @@ * * Returns: * SK_PNMI_ERR_OK The request was successfully performed. - * SK_PNMI_ERR_GENERAL A general severe internal error occurred. + * SK_PNMI_ERR_GENERAL A general severe internal error occured. * SK_PNMI_ERR_TOO_SHORT The passed buffer is too short to contain * the correct data (e.g. a 32bit value is * needed, but a 16 bit value was passed). @@ -6072,7 +6382,8 @@ char *pBuf, /* Buffer to which to mgmt data will be retrieved */ unsigned int *pLen, /* On call: buffer length. On return: used buffer */ SK_U32 Instance, /* Instance (1..n) that is to be queried or -1 */ -unsigned int TableIndex) /* Index to the Id table */ +unsigned int TableIndex, /* Index to the Id table */ +SK_U32 NetIndex) /* NetIndex (0..n), in single net mode allways zero */ { unsigned int Index; unsigned int Limit; @@ -6502,7 +6813,7 @@ * * Description: * The COMMON module only tells us if the mode is half or full duplex. - * But in the decade of auto sensing it is useful for the user to + * But in the decade of auto sensing it is usefull for the user to * know if the mode was negotiated or forced. Therefore we have a * look to the mode, which was last used by the negotiation process. * @@ -6566,8 +6877,8 @@ unsigned int KeyArrLen, /* Length of array in bytes */ unsigned int *pKeyNo) /* Number of keys */ { - unsigned int BufKeysLen = 128; - char BufKeys[128]; + unsigned int BufKeysLen = SK_PNMI_VPD_BUFSIZE; + char BufKeys[SK_PNMI_VPD_BUFSIZE]; unsigned int StartOffset; unsigned int Offset; int Index; @@ -6598,12 +6909,12 @@ * errorlog notification. This case should not happen because * the maximum number of keys is limited due to RAM limitations */ - if (*pKeyNo > SK_PNMI_VPD_ARR_SIZE) { + if (*pKeyNo > SK_PNMI_VPD_ENTRIES) { SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR015, SK_PNMI_ERR015MSG); - *pKeyNo = SK_PNMI_VPD_ARR_SIZE; + *pKeyNo = SK_PNMI_VPD_ENTRIES; } /* @@ -6618,15 +6929,15 @@ continue; } - if (Offset - StartOffset > SK_PNMI_VPD_STR_SIZE) { + if (Offset - StartOffset > SK_PNMI_VPD_KEY_SIZE) { SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR016, SK_PNMI_ERR016MSG); return (SK_PNMI_ERR_GENERAL); } - SK_STRNCPY(pKeyArr + Index * SK_PNMI_VPD_STR_SIZE, - &BufKeys[StartOffset], SK_PNMI_VPD_STR_SIZE); + SK_STRNCPY(pKeyArr + Index * SK_PNMI_VPD_KEY_SIZE, + &BufKeys[StartOffset], SK_PNMI_VPD_KEY_SIZE); Index ++; StartOffset = Offset + 1; @@ -6635,8 +6946,8 @@ /* Last key not zero terminated? Get it anyway */ if (StartOffset < Offset) { - SK_STRNCPY(pKeyArr + Index * SK_PNMI_VPD_STR_SIZE, - &BufKeys[StartOffset], SK_PNMI_VPD_STR_SIZE); + SK_STRNCPY(pKeyArr + Index * SK_PNMI_VPD_KEY_SIZE, + &BufKeys[StartOffset], SK_PNMI_VPD_KEY_SIZE); } return (SK_PNMI_ERR_OK); @@ -6698,7 +7009,8 @@ static int RlmtUpdate( SK_AC *pAC, /* Pointer to adapter context */ -SK_IOC IoC) /* IO context handle */ +SK_IOC IoC, /* IO context handle */ +SK_U32 NetIndex) /* NetIndex (0..n), in single net mode allways zero */ { SK_EVPARA EventParam; @@ -6711,6 +7023,8 @@ /* Send an synchronuous update event to the module */ SK_MEMSET((char *)&EventParam, 0, sizeof(EventParam)); + EventParam.Para32[0] = NetIndex; + EventParam.Para32[1] = (SK_U32)-1; if (SkRlmtEvent(pAC, IoC, SK_RLMT_STATS_UPDATE, EventParam) > 0) { SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR048, @@ -6764,7 +7078,7 @@ /* * It is an auto-clearing register. If the command bits - * went to zero again, the statistics are transferred. + * went to zero again, the statistics are transfered. * Normally the command should be executed immediately. * But just to be sure we execute a loop. */ @@ -6807,40 +7121,49 @@ */ static SK_U64 GetStatVal( -SK_AC *pAC, /* Pointer to adapter context */ -SK_IOC IoC, /* IO context handle */ +SK_AC *pAC, /* Pointer to adapter context */ +SK_IOC IoC, /* IO context handle */ unsigned int LogPortIndex, /* Index of the logical Port to be processed */ -unsigned int StatIndex) /* Index to statistic value */ +unsigned int StatIndex, /* Index to statistic value */ +SK_U32 NetIndex) /* NetIndex (0..n), in single net mode allways zero */ { unsigned int PhysPortIndex; unsigned int PhysPortMax; SK_U64 Val = 0; - if (LogPortIndex == 0) { + if(pAC->Pnmi.DualNetActiveFlag == SK_TRUE){ /* Dual net mode */ - PhysPortMax = pAC->GIni.GIMacsFound; + PhysPortIndex = NetIndex; + Val = GetPhysStatVal(pAC, IoC, PhysPortIndex, StatIndex); + } /* end of dual net mode */ - /* Add counter of all active ports */ - for (PhysPortIndex = 0; PhysPortIndex < PhysPortMax; - PhysPortIndex ++) { + else { /* single net mode */ - if (pAC->Pnmi.Port[PhysPortIndex].ActiveFlag) { + if (LogPortIndex == 0) { - Val += GetPhysStatVal(pAC, IoC, PhysPortIndex, - StatIndex); - } - } + PhysPortMax = pAC->GIni.GIMacsFound; - /* Correct value because of port switches */ - Val += pAC->Pnmi.VirtualCounterOffset[StatIndex]; - } - else { - /* Get counter value of physical port */ - PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(pAC, LogPortIndex); - Val = GetPhysStatVal(pAC, IoC, PhysPortIndex, StatIndex); - } + /* Add counter of all active ports */ + for (PhysPortIndex = 0; PhysPortIndex < PhysPortMax; + PhysPortIndex ++) { + + if (pAC->Pnmi.Port[PhysPortIndex].ActiveFlag) { + + Val += GetPhysStatVal(pAC, IoC, PhysPortIndex, + StatIndex); + } + } + /* Correct value because of port switches */ + Val += pAC->Pnmi.VirtualCounterOffset[StatIndex]; + } + else { + /* Get counter value of physical port */ + PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(pAC, LogPortIndex); + Val = GetPhysStatVal(pAC, IoC, PhysPortIndex, StatIndex); + } + } /* end of single net mode */ return (Val); } @@ -6862,8 +7185,8 @@ */ static SK_U64 GetPhysStatVal( -SK_AC *pAC, /* Pointer to adapter context */ -SK_IOC IoC, /* IO context handle */ +SK_AC *pAC, /* Pointer to adapter context */ +SK_IOC IoC, /* IO context handle */ unsigned int PhysPortIndex, /* Index of the logical Port to be processed */ unsigned int StatIndex) /* Index to statistic value */ { @@ -6959,7 +7282,8 @@ static void ResetCounter( SK_AC *pAC, /* Pointer to adapter context */ -SK_IOC IoC) /* IO context handle */ +SK_IOC IoC, /* IO context handle */ +SK_U32 NetIndex) { unsigned int PhysPortIndex; SK_EVPARA EventParam; @@ -6971,7 +7295,10 @@ SkEventQueue(pAC, SKGE_I2C, SK_I2CEV_CLEAR, EventParam); /* Notify RLMT module */ + EventParam.Para32[0] = NetIndex; + EventParam.Para32[1] = (SK_U32)-1; SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_STATS_CLEAR, EventParam); + EventParam.Para32[1] = 0; /* Notify SIRQ module */ SkEventQueue(pAC, SKGE_HWAC, SK_HWEV_CLEAR_STAT, EventParam); @@ -7019,16 +7346,16 @@ sizeof(pAC->Pnmi.RlmtChangeEstimate.EstValue)); pAC->Pnmi.RlmtChangeEstimate.EstValueIndex = 0; pAC->Pnmi.RlmtChangeEstimate.Estimate = 0; - pAC->Pnmi.TxSwQueueMax = 0; - pAC->Pnmi.TxRetryCts = 0; - pAC->Pnmi.RxIntrCts = 0; - pAC->Pnmi.TxIntrCts = 0; - pAC->Pnmi.RxNoBufCts = 0; - pAC->Pnmi.TxNoBufCts = 0; - pAC->Pnmi.TxUsedDescrNo = 0; - pAC->Pnmi.RxDeliveredCts = 0; - pAC->Pnmi.RxOctetsDeliveredCts = 0; - pAC->Pnmi.ErrRecoveryCts = 0; + pAC->Pnmi.Port[NetIndex].TxSwQueueMax = 0; + pAC->Pnmi.Port[NetIndex].TxRetryCts = 0; + pAC->Pnmi.Port[NetIndex].RxIntrCts = 0; + pAC->Pnmi.Port[NetIndex].TxIntrCts = 0; + pAC->Pnmi.Port[NetIndex].RxNoBufCts = 0; + pAC->Pnmi.Port[NetIndex].TxNoBufCts = 0; + pAC->Pnmi.Port[NetIndex].TxUsedDescrNo = 0; + pAC->Pnmi.Port[NetIndex].RxDeliveredCts = 0; + pAC->Pnmi.Port[NetIndex].RxOctetsDeliveredCts = 0; + pAC->Pnmi.Port[NetIndex].ErrRecoveryCts = 0; } /***************************************************************************** @@ -7037,7 +7364,7 @@ * * Description: * The trap buffer stores various events. A user application somehow - * gets notified that an event occurred and retrieves the trap buffer + * gets notified that an event occured and retrieves the trap buffer * contens (or simply polls the buffer). The buffer is organized as * a ring which stores the newest traps at the beginning. The oldest * traps are overwritten by the newest ones. Each trap entry has a diff -u --recursive --new-file v2.4.6/linux/drivers/net/sk98lin/skgesirq.c linux/drivers/net/sk98lin/skgesirq.c --- v2.4.6/linux/drivers/net/sk98lin/skgesirq.c Tue Mar 20 12:04:59 2001 +++ linux/drivers/net/sk98lin/skgesirq.c Wed Jul 4 11:50:39 2001 @@ -2,16 +2,15 @@ * * Name: skgesirq.c * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.55 $ - * Date: $Date: 2000/06/19 08:36:25 $ + * Version: $Revision: 1.65 $ + * Date: $Date: 2001/02/23 13:41:51 $ * Purpose: Special IRQ module * ******************************************************************************/ /****************************************************************************** * - * (C)Copyright 1998,1999 SysKonnect, - * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * (C)Copyright 1998-2000 SysKonnect GmbH. * * 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 @@ -27,6 +26,37 @@ * History: * * $Log: skgesirq.c,v $ + * Revision 1.65 2001/02/23 13:41:51 gklug + * fix: PHYS2INST should be used correctly for Dual Net operation + * chg: do no longer work with older PNMI + * + * Revision 1.64 2001/02/15 11:27:04 rassmann + * Working with RLMT v1 if SK_MAX_NETS undefined. + * + * Revision 1.63 2001/02/06 10:44:23 mkunz + * - NetIndex added to interface functions of pnmi V4 with dual net support + * + * Revision 1.62 2001/01/31 15:31:41 gklug + * fix: problem with autosensing an SR8800 switch + * + * Revision 1.61 2000/11/09 11:30:09 rassmann + * WA: Waiting after releasing reset until BCom chip is accessible. + * + * Revision 1.60 2000/10/18 12:37:48 cgoos + * Reinserted the comment for version 1.56. + * + * Revision 1.59 2000/10/18 12:22:20 cgoos + * Added workaround for half duplex hangup. + * + * Revision 1.58 2000/09/28 13:06:04 gklug + * fix: BCOM may NOT be touched if XMAC is in RESET state + * + * Revision 1.57 2000/09/08 12:38:39 cgoos + * Added forgotten variable declaration. + * + * Revision 1.56 2000/09/08 08:12:13 cgoos + * Changed handling of parity errors in SkGeHwErr (correct reset of error). + * * Revision 1.55 2000/06/19 08:36:25 cgoos * Changed comment. * @@ -216,39 +246,38 @@ * ******************************************************************************/ - /* - Special Interrupt handler - - The following abstract should show how this module is included - in the driver path: - - In the ISR of the driver the bits for frame transmission complete and - for receive complete are checked and handled by the driver itself. - The bits of the slow path mask are checked after this and then the - entry into the so-called "slow path" is prepared. It is an implemetors - decision whether this is executed directly or just scheduled by - disabling the mask. In the interrupt service routine events may be - generated, so it would be a good idea to call the EventDispatcher - right after this ISR. - - The Interrupt service register of the adapter is NOT read by this - module. SO if the drivers implemetor needs a while loop around the - slow data paths Interrupt bits, he needs to call the SkGeIsr() for - each loop entered. - - However, the XMAC Interrupt status registers are read in a while loop. - -*/ + * Special Interrupt handler + * + * The following abstract should show how this module is included + * in the driver path: + * + * In the ISR of the driver the bits for frame transmission complete and + * for receive complete are checked and handled by the driver itself. + * The bits of the slow path mask are checked after this and then the + * entry into the so-called "slow path" is prepared. It is an implemetors + * decision whether this is executed directly or just scheduled by + * disabling the mask. In the interrupt service routine events may be + * generated, so it would be a good idea to call the EventDispatcher + * right after this ISR. + * + * The Interrupt service register of the adapter is NOT read by this + * module. SO if the drivers implemetor needs a while loop around the + * slow data paths Interrupt bits, he needs to call the SkGeIsr() for + * each loop entered. + * + * However, the XMAC Interrupt status registers are read in a while loop. + * + */ + static const char SysKonnectFileId[] = - "$Id: skgesirq.c,v 1.55 2000/06/19 08:36:25 cgoos Exp $" ; + "$Id: skgesirq.c,v 1.65 2001/02/23 13:41:51 gklug Exp $" ; #include "h/skdrv1st.h" /* Driver Specific Definitions */ #include "h/skgepnmi.h" /* PNMI Definitions */ #include "h/skrlmt.h" /* RLMT Definitions */ #include "h/skdrv2nd.h" /* Adapter Control- and Driver specific Def. */ - /* local function prototypes */ static int SkGePortCheckUpXmac(SK_AC*, SK_IOC, int); static int SkGePortCheckUpBcom(SK_AC*, SK_IOC, int); @@ -257,21 +286,31 @@ static void SkPhyIsrBcom(SK_AC*, SK_IOC, int, SK_U16); static void SkPhyIsrLone(SK_AC*, SK_IOC, int, SK_U16); +/* + * Define an array of RX counter which are checked + * in AutoSense mode to check whether a link is not able to autonegotiate. + */ +static const SK_U32 SkGeRxOids[]= { + OID_SKGE_STAT_RX_64, + OID_SKGE_STAT_RX_127, + OID_SKGE_STAT_RX_255, + OID_SKGE_STAT_RX_511, + OID_SKGE_STAT_RX_1023, + OID_SKGE_STAT_RX_MAX, +} ; #ifdef __C2MAN__ /* - Special IRQ function - - General Description: - + * Special IRQ function + * + * General Description: + * */ intro() {} #endif -/* - * Define return codes of SkGePortCheckUp and CheckShort - */ +/* Define return codes of SkGePortCheckUp and CheckShort. */ #define SK_HW_PS_NONE 0 /* No action needed */ #define SK_HW_PS_RESTART 1 /* Restart needed */ #define SK_HW_PS_LINK 2 /* Link Up actions needed */ @@ -287,13 +326,13 @@ * */ void SkHWInitDefSense( -SK_AC *pAC, /* adapter context */ -SK_IOC IoC, /* IO context */ +SK_AC *pAC, /* adapter context */ +SK_IOC IoC, /* IO context */ int Port) /* Port Index (MAC_1 + n) */ { SK_GEPORT *pPrt; - pPrt = &pAC->GIni.GP[Port] ; + pPrt = &pAC->GIni.GP[Port]; pPrt->PAutoNegTimeOut = 0; @@ -302,15 +341,16 @@ return; } - SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_IRQ, + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ, ("AutoSensing: First mode %d on Port %d\n", - (int) SK_LMODE_AUTOFULL, + (int)SK_LMODE_AUTOFULL, Port)); pPrt->PLinkMode = SK_LMODE_AUTOFULL; return; -} +} /* SkHWInitDefSense */ + /****************************************************************************** * @@ -323,29 +363,30 @@ * */ SK_U8 SkHWSenseGetNext( -SK_AC *pAC, /* adapter context */ -SK_IOC IoC, /* IO context */ +SK_AC *pAC, /* adapter context */ +SK_IOC IoC, /* IO context */ int Port) /* Port Index (MAC_1 + n) */ { SK_GEPORT *pPrt; - pPrt = &pAC->GIni.GP[Port] ; + pPrt = &pAC->GIni.GP[Port]; pPrt->PAutoNegTimeOut = 0; if (pPrt->PLinkModeConf != SK_LMODE_AUTOSENSE) { /* Leave all as configured */ - return(pPrt->PLinkModeConf); + return (pPrt->PLinkModeConf); } if (pPrt->PLinkMode == SK_LMODE_AUTOFULL) { /* Return next mode AUTOBOTH */ - return(SK_LMODE_AUTOBOTH); + return (SK_LMODE_AUTOBOTH); } /* Return default autofull */ - return(SK_LMODE_AUTOFULL); -} + return (SK_LMODE_AUTOFULL); +} /* SkHWSenseGetNext */ + /****************************************************************************** * @@ -360,12 +401,12 @@ void SkHWSenseSetNext( SK_AC *pAC, /* adapter context */ SK_IOC IoC, /* IO context */ -int Port, /* Port Index (MAC_1 + n) */ +int Port, /* Port Index (MAC_1 + n) */ SK_U8 NewMode) /* New Mode to be written in sense mode */ { SK_GEPORT *pPrt; - pPrt = &pAC->GIni.GP[Port] ; + pPrt = &pAC->GIni.GP[Port]; pPrt->PAutoNegTimeOut = 0; @@ -373,13 +414,13 @@ return; } - SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_IRQ, - ("AutoSensing: next mode %d on Port %d\n", (int) NewMode, - Port)); + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ, + ("AutoSensing: next mode %d on Port %d\n", (int)NewMode, Port)); pPrt->PLinkMode = NewMode; return; -} +} /* SkHWSenseSetNext */ + /****************************************************************************** * @@ -394,47 +435,44 @@ void SkHWLinkDown( SK_AC *pAC, /* adapter context */ SK_IOC IoC, /* IO context */ -int Port) /* Port Index (MAC_1 + n) */ +int Port) /* Port Index (MAC_1 + n) */ { SK_GEPORT *pPrt; SK_U16 Word; - pPrt = &pAC->GIni.GP[Port] ; + pPrt = &pAC->GIni.GP[Port]; - /* Disable all XMAC interrupts */ + /* Disable all XMAC interrupts. */ XM_OUT16(IoC, Port, XM_IMSK, 0xffff); - /* Disable Receive and Transmitter */ + /* Disable Receiver and Transmitter. */ XM_IN16(IoC, Port, XM_MMU_CMD, &Word); - XM_OUT16(IoC, Port, XM_MMU_CMD, Word & ~(XM_MMU_ENA_RX|XM_MMU_ENA_TX)); + XM_OUT16(IoC, Port, XM_MMU_CMD, Word & ~(XM_MMU_ENA_RX | XM_MMU_ENA_TX)); - /* disable all PHY interrupts */ - switch (pAC->GIni.GP[Port].PhyType) { + /* Disable all PHY interrupts. */ + switch (pPrt->PhyType) { case SK_PHY_BCOM: - /* make sure that PHY is initialized */ + /* Make sure that PHY is initialized. */ if (pAC->GIni.GP[Port].PState) { - /* Workaround BCOM Errata (#10523) all BCom */ - /* Disable Power Management if link is down */ - PHY_READ(IoC, pPrt, Port, PHY_BCOM_AUX_CTRL, - &Word); - PHY_WRITE(IoC, pPrt, Port, PHY_BCOM_AUX_CTRL, + /* NOT allowed if BCOM is in RESET state */ + /* Workaround BCOM Errata (#10523) all BCom. */ + /* Disable Power Management if link is down. */ + PHY_READ(IoC, pPrt, Port, PHY_BCOM_AUX_CTRL, &Word); + PHY_WRITE(IoC, pPrt, Port, PHY_BCOM_AUX_CTRL, Word | PHY_B_AC_DIS_PM); + PHY_WRITE(IoC, pPrt, Port, PHY_BCOM_INT_MASK, 0xffff); } - PHY_WRITE(IoC, pPrt, Port, PHY_BCOM_INT_MASK, - 0xffff); break; case SK_PHY_LONE: - PHY_WRITE(IoC, pPrt, Port, PHY_LONE_INT_ENAB, - 0x0); + PHY_WRITE(IoC, pPrt, Port, PHY_LONE_INT_ENAB, 0x0); break; case SK_PHY_NAT: /* todo: National - PHY_WRITE(IoC, pPrt, Port, PHY_NAT_INT_MASK, - 0xffff); */ + PHY_WRITE(IoC, pPrt, Port, PHY_NAT_INT_MASK, 0xffff); */ break; } - /* Init default sense mode */ + /* Init default sense mode. */ SkHWInitDefSense(pAC, IoC, Port); if (!pPrt->PHWLinkUp) { @@ -444,27 +482,25 @@ SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_IRQ, ("Link down Port %d\n", Port)); - /* Set Link to DOWN */ + /* Set Link to DOWN. */ pPrt->PHWLinkUp = SK_FALSE; /* Reset Port stati */ pPrt->PLinkModeStatus = SK_LMODE_STAT_UNKNOWN; - pPrt->PFlowCtrlStatus = SK_FLOW_STAT_NONE ; + pPrt->PFlowCtrlStatus = SK_FLOW_STAT_NONE; /* - * Reinit Phy especially when the AutoSense default is set now + * Reinit Phy especially when the AutoSense default is set now. */ SkXmInitPhy(pAC, IoC, Port, SK_FALSE); - /* - * GP0: used for workaround of Rev. C - * Errata 2 - */ + /* GP0: used for workaround of Rev. C Errata 2. */ + + /* Do NOT signal to RLMT. */ - /* Do NOT signal to RLMT */ + /* Do NOT start the timer here. */ +} /* SkHWLinkDown */ - /* Do NOT start the timer here */ -} /****************************************************************************** * @@ -477,21 +513,21 @@ * */ void SkHWLinkUp( -SK_AC *pAC, /* adapter context */ -SK_IOC IoC, /* IO context */ +SK_AC *pAC, /* adapter context */ +SK_IOC IoC, /* IO context */ int Port) /* Port Index (MAC_1 + n) */ { SK_GEPORT *pPrt; - pPrt = &pAC->GIni.GP[Port] ; + pPrt = &pAC->GIni.GP[Port]; if (pPrt->PHWLinkUp) { /* We do NOT need to proceed on active link */ return; } - pPrt->PHWLinkUp = SK_TRUE ; - pPrt->PAutoNegFail = SK_FALSE ; + pPrt->PHWLinkUp = SK_TRUE; + pPrt->PAutoNegFail = SK_FALSE; pPrt->PLinkModeStatus = SK_LMODE_STAT_UNKNOWN; if (pPrt->PLinkMode != SK_LMODE_AUTOHALF && @@ -504,17 +540,19 @@ /* Set Link Mode */ if (pPrt->PLinkMode == SK_LMODE_FULL) { pPrt->PLinkModeStatus = SK_LMODE_STAT_FULL; - } else { + } + else { pPrt->PLinkModeStatus = SK_LMODE_STAT_HALF; } /* No flow control without autonegotiation */ - pPrt->PFlowCtrlStatus = SK_FLOW_STAT_NONE ; + pPrt->PFlowCtrlStatus = SK_FLOW_STAT_NONE; /* RX/TX enable */ SkXmRxTxEnable(pAC, IoC, Port); } -} +} /* SkHWLinkUp */ + /****************************************************************************** * @@ -522,27 +560,28 @@ * */ static void SkMacParity( -SK_AC *pAC, /* adapter context */ -SK_IOC IoC, /* IO context */ +SK_AC *pAC, /* adapter context */ +SK_IOC IoC, /* IO context */ int Port) /* Port Index of the port failed */ { SK_EVPARA Para; SK_GEPORT *pPrt; /* GIni Port struct pointer */ SK_U64 TxMax; /* TxMax Counter */ - unsigned int Len; + unsigned Len; pPrt = &pAC->GIni.GP[Port]; /* Clear IRQ */ - SK_OUT16(IoC, MR_ADDR(Port,TX_MFF_CTRL1), MFF_CLR_PERR) ; + SK_OUT16(IoC, MR_ADDR(Port,TX_MFF_CTRL1), MFF_CLR_PERR); if (pPrt->PCheckPar) { if (Port == MAC_1) { SK_ERR_LOG(pAC, SK_ERRCL_HW , SKERR_SIRQ_E016, - SKERR_SIRQ_E016MSG) ; - } else { + SKERR_SIRQ_E016MSG); + } + else { SK_ERR_LOG(pAC, SK_ERRCL_HW , SKERR_SIRQ_E017, - SKERR_SIRQ_E017MSG) ; + SKERR_SIRQ_E017MSG); } Para.Para64 = Port; SkEventQueue(pAC, SKGE_DRV, SK_DRV_PORT_FAIL, Para); @@ -552,17 +591,18 @@ return; } - /* Check whether frames with a size of 1k were sent */ Len = sizeof(SK_U64); - SkPnmiGetVar(pAC, IoC, OID_SKGE_STAT_TX_MAX, (char *) &TxMax, - &Len, (SK_U32) SK_PNMI_PORT_PHYS2INST(Port)); + SkPnmiGetVar(pAC, IoC, OID_SKGE_STAT_TX_MAX, (char *)&TxMax, + &Len, (SK_U32)SK_PNMI_PORT_PHYS2INST(pAC, Port), + pAC->Rlmt.Port[Port].Net->NetNumber); if (TxMax > 0) { /* From now on check the parity */ pPrt->PCheckPar = SK_TRUE; } -} +} /* SkMacParity */ + /****************************************************************************** * @@ -578,17 +618,22 @@ SK_U32 HwStatus) /* Interrupt status word */ { SK_EVPARA Para; + SK_U16 Word; - if (HwStatus & IS_IRQ_STAT) { - SK_ERR_LOG(pAC, SK_ERRCL_HW , SKERR_SIRQ_E013, - SKERR_SIRQ_E013MSG) ; - Para.Para64 = 0; - SkEventQueue(pAC, SKGE_DRV, SK_DRV_ADAP_FAIL, Para); - } + if ((HwStatus & IS_IRQ_MST_ERR) || (HwStatus & IS_IRQ_STAT)) { + if (HwStatus & IS_IRQ_STAT) { + SK_ERR_LOG(pAC, SK_ERRCL_HW , SKERR_SIRQ_E013, SKERR_SIRQ_E013MSG); + } + else { + SK_ERR_LOG(pAC, SK_ERRCL_HW , SKERR_SIRQ_E012, SKERR_SIRQ_E012MSG); + } + + /* Reset all bits in the PCI STATUS register */ + SK_OUT8(IoC, B2_TST_CTRL1, TST_CFG_WRITE_ON); + SK_IN16(IoC, PCI_C(PCI_STATUS), &Word); + SK_OUT16(IoC, PCI_C(PCI_STATUS), Word | PCI_ERRBITS); + SK_OUT8(IoC, B2_TST_CTRL1, TST_CFG_WRITE_OFF); - if (HwStatus & IS_IRQ_MST_ERR) { - SK_ERR_LOG(pAC, SK_ERRCL_HW , SKERR_SIRQ_E012, - SKERR_SIRQ_E012MSG) ; Para.Para64 = 0; SkEventQueue(pAC, SKGE_DRV, SK_DRV_ADAP_FAIL, Para); } @@ -596,57 +641,54 @@ if (HwStatus & IS_NO_STAT_M1) { /* Ignore it */ /* This situation is also indicated in the descriptor */ - SK_OUT16(IoC, MR_ADDR(MAC_1,RX_MFF_CTRL1), MFF_CLR_INSTAT) ; + SK_OUT16(IoC, MR_ADDR(MAC_1,RX_MFF_CTRL1), MFF_CLR_INSTAT); } if (HwStatus & IS_NO_STAT_M2) { /* Ignore it */ /* This situation is also indicated in the descriptor */ - SK_OUT16(IoC, MR_ADDR(MAC_2,RX_MFF_CTRL1), MFF_CLR_INSTAT) ; + SK_OUT16(IoC, MR_ADDR(MAC_2,RX_MFF_CTRL1), MFF_CLR_INSTAT); } if (HwStatus & IS_NO_TIST_M1) { /* Ignore it */ /* This situation is also indicated in the descriptor */ - SK_OUT16(IoC, MR_ADDR(MAC_1,RX_MFF_CTRL1), MFF_CLR_INTIST) ; + SK_OUT16(IoC, MR_ADDR(MAC_1,RX_MFF_CTRL1), MFF_CLR_INTIST); } if (HwStatus & IS_NO_TIST_M2) { /* Ignore it */ /* This situation is also indicated in the descriptor */ - SK_OUT16(IoC, MR_ADDR(MAC_2,RX_MFF_CTRL1), MFF_CLR_INTIST) ; + SK_OUT16(IoC, MR_ADDR(MAC_2,RX_MFF_CTRL1), MFF_CLR_INTIST); } if (HwStatus & IS_RAM_RD_PAR) { - SK_OUT16(IoC, B3_RI_CTRL, RI_CLR_RD_PERR) ; - SK_ERR_LOG(pAC, SK_ERRCL_HW , SKERR_SIRQ_E014, - SKERR_SIRQ_E014MSG) ; + SK_OUT16(IoC, B3_RI_CTRL, RI_CLR_RD_PERR); + SK_ERR_LOG(pAC, SK_ERRCL_HW , SKERR_SIRQ_E014, SKERR_SIRQ_E014MSG); Para.Para64 = 0; SkEventQueue(pAC, SKGE_DRV, SK_DRV_ADAP_FAIL, Para); } if (HwStatus & IS_RAM_WR_PAR) { - SK_OUT16(IoC, B3_RI_CTRL, RI_CLR_WR_PERR) ; - SK_ERR_LOG(pAC, SK_ERRCL_HW , SKERR_SIRQ_E015, - SKERR_SIRQ_E015MSG) ; + SK_OUT16(IoC, B3_RI_CTRL, RI_CLR_WR_PERR); + SK_ERR_LOG(pAC, SK_ERRCL_HW , SKERR_SIRQ_E015, SKERR_SIRQ_E015MSG); Para.Para64 = 0; SkEventQueue(pAC, SKGE_DRV, SK_DRV_ADAP_FAIL, Para); } if (HwStatus & IS_M1_PAR_ERR) { - SkMacParity(pAC, IoC, MAC_1) ; + SkMacParity(pAC, IoC, MAC_1); } if (HwStatus & IS_M2_PAR_ERR) { - SkMacParity(pAC, IoC, MAC_2) ; + SkMacParity(pAC, IoC, MAC_2); } if (HwStatus & IS_R1_PAR_ERR) { /* Clear IRQ */ - SK_OUT32(IoC, B0_R1_CSR, CSR_IRQ_CL_P) ; + SK_OUT32(IoC, B0_R1_CSR, CSR_IRQ_CL_P); - SK_ERR_LOG(pAC, SK_ERRCL_HW , SKERR_SIRQ_E018, - SKERR_SIRQ_E018MSG) ; + SK_ERR_LOG(pAC, SK_ERRCL_HW , SKERR_SIRQ_E018, SKERR_SIRQ_E018MSG); Para.Para64 = MAC_1; SkEventQueue(pAC, SKGE_DRV, SK_DRV_PORT_FAIL, Para); Para.Para32[0] = MAC_1; @@ -655,17 +697,16 @@ if (HwStatus & IS_R2_PAR_ERR) { /* Clear IRQ */ - SK_OUT32(IoC, B0_R2_CSR, CSR_IRQ_CL_P) ; + SK_OUT32(IoC, B0_R2_CSR, CSR_IRQ_CL_P); - SK_ERR_LOG(pAC, SK_ERRCL_HW , SKERR_SIRQ_E019, - SKERR_SIRQ_E019MSG) ; + SK_ERR_LOG(pAC, SK_ERRCL_HW , SKERR_SIRQ_E019, SKERR_SIRQ_E019MSG); Para.Para64 = MAC_2; SkEventQueue(pAC, SKGE_DRV, SK_DRV_PORT_FAIL, Para); Para.Para32[0] = MAC_2; SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_LINK_DOWN, Para); } +} /* SkGeHwErr */ -} /****************************************************************************** * @@ -680,13 +721,13 @@ SK_IOC IoC, /* IO context */ SK_U32 Istatus) /* Interrupt status word */ { - SK_U32 RegVal32; /* Read register Value */ SK_EVPARA Para; + SK_U32 RegVal32; /* Read register Value */ SK_U16 XmIsr; if (Istatus & IS_HW_ERR) { - SK_IN32(IoC, B0_HWE_ISRC, &RegVal32) ; - SkGeHwErr(pAC, IoC, RegVal32) ; + SK_IN32(IoC, B0_HWE_ISRC, &RegVal32); + SkGeHwErr(pAC, IoC, RegVal32); } /* @@ -694,41 +735,101 @@ */ /* Check whether XMACs are correctly initialized */ if ((Istatus & (IS_PA_TO_RX1 | IS_PA_TO_TX1)) && - !pAC->GIni.GP[MAC_1].PState) { - /* XMAC was not initialized but Packet timeout occurred */ + !pAC->GIni.GP[MAC_1].PState) { + /* XMAC was not initialized but Packet timeout occured */ SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_SIRQ_E004, - SKERR_SIRQ_E004MSG) ; + SKERR_SIRQ_E004MSG); } if ((Istatus & (IS_PA_TO_RX2 | IS_PA_TO_TX2)) && !pAC->GIni.GP[MAC_2].PState) { - /* XMAC was not initialized but Packet timeout occurred */ + /* XMAC was not initialized but Packet timeout occured */ SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_SIRQ_E005, - SKERR_SIRQ_E005MSG) ; + SKERR_SIRQ_E005MSG); } if (Istatus & IS_PA_TO_RX1) { /* Means network is filling us up */ SK_ERR_LOG(pAC, SK_ERRCL_HW | SK_ERRCL_INIT, SKERR_SIRQ_E002, - SKERR_SIRQ_E002MSG) ; - SK_OUT16(IoC, B3_PA_CTRL, PA_CLR_TO_RX1) ; + SKERR_SIRQ_E002MSG); + SK_OUT16(IoC, B3_PA_CTRL, PA_CLR_TO_RX1); } if (Istatus & IS_PA_TO_RX2) { /* Means network is filling us up */ SK_ERR_LOG(pAC, SK_ERRCL_HW | SK_ERRCL_INIT, SKERR_SIRQ_E003, - SKERR_SIRQ_E003MSG) ; - SK_OUT16(IoC, B3_PA_CTRL, PA_CLR_TO_RX2) ; + SKERR_SIRQ_E003MSG); + SK_OUT16(IoC, B3_PA_CTRL, PA_CLR_TO_RX2); } if (Istatus & IS_PA_TO_TX1) { + unsigned int Len; + SK_U64 Octets; + SK_GEPORT *pPrt = &pAC->GIni.GP[0]; + /* May be a normal situation in a server with a slow network */ - SK_OUT16(IoC, B3_PA_CTRL, PA_CLR_TO_TX1) ; + SK_OUT16(IoC, B3_PA_CTRL, PA_CLR_TO_TX1); + + /* + * workaround: if in half duplex mode, check for tx hangup. + * Read number of TX'ed bytes, wait for 10 ms, then compare + * the number with current value. If nothing changed, we + * assume that tx is hanging and do a FIFO flush (see event + * routine). + */ + if ((pPrt->PLinkModeStatus == SK_LMODE_STAT_HALF || + pPrt->PLinkModeStatus == SK_LMODE_STAT_AUTOHALF) && + !pPrt->HalfDupTimerActive) { + /* + * many more pack. arb. timeouts may come in between, + * we ignore those + */ + pPrt->HalfDupTimerActive = SK_TRUE; + + Len = sizeof(SK_U64); + SkPnmiGetVar(pAC, IoC, OID_SKGE_STAT_TX_OCTETS, (char *) &Octets, + &Len, (SK_U32) SK_PNMI_PORT_PHYS2INST(pAC, 0), + pAC->Rlmt.Port[0].Net->NetNumber); + pPrt->LastOctets = Octets; + Para.Para32[0] = 0; + SkTimerStart(pAC, IoC, + &pPrt->HalfDupChkTimer, + SK_HALFDUP_CHK_TIME, + SKGE_HWAC, + SK_HWEV_HALFDUP_CHK, + Para); + } } if (Istatus & IS_PA_TO_TX2) { + unsigned int Len; + SK_U64 Octets; + SK_GEPORT *pPrt = &pAC->GIni.GP[1]; + /* May be a normal situation in a server with a slow network */ - SK_OUT16(IoC, B3_PA_CTRL, PA_CLR_TO_TX2) ; + SK_OUT16(IoC, B3_PA_CTRL, PA_CLR_TO_TX2); + + /* + * workaround: see above + */ + if ((pPrt->PLinkModeStatus == SK_LMODE_STAT_HALF || + pPrt->PLinkModeStatus == SK_LMODE_STAT_AUTOHALF) && + !pPrt->HalfDupTimerActive) { + pPrt->HalfDupTimerActive = SK_TRUE; + + Len = sizeof(SK_U64); + SkPnmiGetVar(pAC, IoC, OID_SKGE_STAT_TX_OCTETS, (char *) &Octets, + &Len, (SK_U32) SK_PNMI_PORT_PHYS2INST(pAC, 1), + pAC->Rlmt.Port[1].Net->NetNumber); + pPrt->LastOctets = Octets; + Para.Para32[0] = 1; + SkTimerStart(pAC, IoC, + &pPrt->HalfDupChkTimer, + SK_HALFDUP_CHK_TIME, + SKGE_HWAC, + SK_HWEV_HALFDUP_CHK, + Para); + } } /* @@ -736,9 +837,9 @@ */ if (Istatus & IS_R1_C) { /* Clear IRQ */ - SK_OUT32(IoC, B0_R1_CSR, CSR_IRQ_CL_C) ; + SK_OUT32(IoC, B0_R1_CSR, CSR_IRQ_CL_C); SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_SIRQ_E006, - SKERR_SIRQ_E006MSG) ; + SKERR_SIRQ_E006MSG); Para.Para64 = MAC_1; SkEventQueue(pAC, SKGE_DRV, SK_DRV_PORT_FAIL, Para); Para.Para32[0] = MAC_1; @@ -747,9 +848,9 @@ if (Istatus & IS_R2_C) { /* Clear IRQ */ - SK_OUT32(IoC, B0_R2_CSR, CSR_IRQ_CL_C) ; + SK_OUT32(IoC, B0_R2_CSR, CSR_IRQ_CL_C); SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_SIRQ_E007, - SKERR_SIRQ_E007MSG) ; + SKERR_SIRQ_E007MSG); Para.Para64 = MAC_2; SkEventQueue(pAC, SKGE_DRV, SK_DRV_PORT_FAIL, Para); Para.Para32[0] = MAC_2; @@ -758,9 +859,9 @@ if (Istatus & IS_XS1_C) { /* Clear IRQ */ - SK_OUT32(IoC, B0_XS1_CSR, CSR_IRQ_CL_C) ; + SK_OUT32(IoC, B0_XS1_CSR, CSR_IRQ_CL_C); SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_SIRQ_E008, - SKERR_SIRQ_E008MSG) ; + SKERR_SIRQ_E008MSG); Para.Para64 = MAC_1; SkEventQueue(pAC, SKGE_DRV, SK_DRV_PORT_FAIL, Para); Para.Para32[0] = MAC_1; @@ -769,9 +870,9 @@ if (Istatus & IS_XA1_C) { /* Clear IRQ */ - SK_OUT32(IoC, B0_XA1_CSR, CSR_IRQ_CL_C) ; + SK_OUT32(IoC, B0_XA1_CSR, CSR_IRQ_CL_C); SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_SIRQ_E009, - SKERR_SIRQ_E009MSG) ; + SKERR_SIRQ_E009MSG); Para.Para64 = MAC_1; SkEventQueue(pAC, SKGE_DRV, SK_DRV_PORT_FAIL, Para); Para.Para32[0] = MAC_1; @@ -780,9 +881,9 @@ if (Istatus & IS_XS2_C) { /* Clear IRQ */ - SK_OUT32(IoC, B0_XS2_CSR, CSR_IRQ_CL_C) ; + SK_OUT32(IoC, B0_XS2_CSR, CSR_IRQ_CL_C); SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_SIRQ_E010, - SKERR_SIRQ_E010MSG) ; + SKERR_SIRQ_E010MSG); Para.Para64 = MAC_2; SkEventQueue(pAC, SKGE_DRV, SK_DRV_PORT_FAIL, Para); Para.Para32[0] = MAC_2; @@ -791,9 +892,9 @@ if (Istatus & IS_XA2_C) { /* Clear IRQ */ - SK_OUT32(IoC, B0_XA2_CSR, CSR_IRQ_CL_C) ; + SK_OUT32(IoC, B0_XA2_CSR, CSR_IRQ_CL_C); SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_SIRQ_E011, - SKERR_SIRQ_E011MSG) ; + SKERR_SIRQ_E011MSG); Para.Para64 = MAC_2; SkEventQueue(pAC, SKGE_DRV, SK_DRV_PORT_FAIL, Para); Para.Para32[0] = MAC_2; @@ -801,52 +902,59 @@ } /* - * external reg interrupt + * External reg interrupt. */ if (Istatus & IS_EXT_REG) { SK_U16 PhyInt; SK_U16 PhyIMsk; - int i; - /* test IRQs from PHY */ - for (i=0; i<pAC->GIni.GIMacsFound; i++) { - switch (pAC->GIni.GP[i].PhyType) { + int i; + SK_GEPORT *pPrt; /* GIni Port struct pointer */ + + /* Test IRQs from PHY. */ + for (i = 0; i < pAC->GIni.GIMacsFound; i++) { + pPrt = &pAC->GIni.GP[i]; + switch (pPrt->PhyType) { case SK_PHY_XMAC: break; case SK_PHY_BCOM: - if(pAC->GIni.GP[i].PState) { - PHY_READ(IoC, &pAC->GIni.GP[i], i, - PHY_BCOM_INT_STAT, &PhyInt); - PHY_READ(IoC, &pAC->GIni.GP[i], i, - PHY_BCOM_INT_MASK, &PhyIMsk); + if (pPrt->PState) { + PHY_READ(IoC, pPrt, i, PHY_BCOM_INT_STAT, &PhyInt); + PHY_READ(IoC, pPrt, i, PHY_BCOM_INT_MASK, &PhyIMsk); + +#ifdef xDEBUG + if (PhyInt & PhyIMsk) { + CMSMPrintString( + pAC->pConfigTable, + MSG_TYPE_RUNTIME_INFO, + "SirqIsr - Stat: %x", + (void *)PhyInt, + (void *)NULL); + } +#endif /* DEBUG */ - if (PhyInt & (~PhyIMsk)) { - SK_DBG_MSG(pAC,SK_DBGMOD_HWM, + if (PhyInt & ~PhyIMsk) { + SK_DBG_MSG( + pAC, + SK_DBGMOD_HWM, SK_DBGCAT_IRQ, - ("Port %d Bcom Int: %x " - " Mask: %x\n", - i, PhyInt, PhyIMsk)); - SkPhyIsrBcom(pAC, IoC, i, - (SK_U16) - (PhyInt & (~PhyIMsk))); + ("Port %d Bcom Int: %x Mask: %x\n", + i, PhyInt, PhyIMsk)); + SkPhyIsrBcom(pAC, IoC, i, PhyInt); } } - else { - } break; case SK_PHY_LONE: - PHY_READ(IoC, &pAC->GIni.GP[i], i, - PHY_LONE_INT_STAT, &PhyInt); - PHY_READ(IoC, &pAC->GIni.GP[i], i, - PHY_LONE_INT_ENAB, &PhyIMsk); + PHY_READ(IoC, pPrt, i, PHY_LONE_INT_STAT, &PhyInt); + PHY_READ(IoC, pPrt, i, PHY_LONE_INT_ENAB, &PhyIMsk); if (PhyInt & PhyIMsk) { - SK_DBG_MSG(pAC,SK_DBGMOD_HWM, + SK_DBG_MSG( + pAC, + SK_DBGMOD_HWM, SK_DBGCAT_IRQ, - ("Port %d Lone Int: %x " - " Mask: %x\n", + ("Port %d Lone Int: %x Mask: %x\n", i, PhyInt, PhyIMsk)); - SkPhyIsrLone(pAC, IoC, i, - (SK_U16) (PhyInt & PhyIMsk)); + SkPhyIsrLone(pAC, IoC, i, PhyInt); } break; case SK_PHY_NAT: @@ -869,12 +977,12 @@ * us only a link going down. */ /* clear interrupt */ - SK_OUT8(IoC, MR_ADDR(MAC_1,LNK_SYNC_CTRL), LED_CLR_IRQ); + SK_OUT8(IoC, MR_ADDR(MAC_1, LNK_SYNC_CTRL), LED_CLR_IRQ); } /* Check MAC after link sync counter */ if (Istatus & IS_MAC1) { - XM_IN16(IoC, MAC_1, XM_ISRC, &XmIsr) ; + XM_IN16(IoC, MAC_1, XM_ISRC, &XmIsr); SkXmIrq(pAC, IoC, MAC_1, XmIsr); } @@ -889,7 +997,7 @@ /* Check MAC after link sync counter */ if (Istatus & IS_MAC2) { - XM_IN16(IoC, MAC_2, XM_ISRC, &XmIsr) ; + XM_IN16(IoC, MAC_2, XM_ISRC, &XmIsr); SkXmIrq(pAC, IoC, MAC_2, XmIsr); } @@ -900,20 +1008,9 @@ if (Istatus & IS_TIMINT) { SkHwtIsr(pAC, IoC); } -} +} /* SkGeSirqIsr */ + -/* - * Define an array of RX counter which are checked - * in AutoSense mode to check whether a link is not able to autonegotiate. - */ -static const SK_U32 SkGeRxOids[]= { - OID_SKGE_STAT_RX_64, - OID_SKGE_STAT_RX_127, - OID_SKGE_STAT_RX_255, - OID_SKGE_STAT_RX_511, - OID_SKGE_STAT_RX_1023, - OID_SKGE_STAT_RX_MAX, -} ; /****************************************************************************** * * SkGePortCheckShorts - Implementing of the Workaround Errata # 2 @@ -923,19 +1020,19 @@ * 1 Restart needed on this port */ int SkGePortCheckShorts( -SK_AC *pAC, /* Adapters context */ +SK_AC *pAC, /* Adapter Context */ SK_IOC IoC, /* IO Context */ -int Port) /* Which port should be checked */ +int Port) /* Which port should be checked */ { - SK_U64 Shorts; /* Short Event Counter */ + SK_U64 Shorts; /* Short Event Counter */ SK_U64 CheckShorts; /* Check value for Short Event Counter */ - SK_U64 RxCts; /* RX Counter (packets on network) */ - SK_U64 RxTmp; /* RX temp. Counter */ - SK_U64 FcsErrCts; /* FCS Error Counter */ - SK_GEPORT *pPrt; /* GIni Port struct pointer */ - unsigned int Len; - int Rtv; /* Return value */ - int i; + SK_U64 RxCts; /* RX Counter (packets on network) */ + SK_U64 RxTmp; /* RX temp. Counter */ + SK_U64 FcsErrCts; /* FCS Error Counter */ + SK_GEPORT *pPrt; /* GIni Port struct pointer */ + unsigned Len; + int Rtv; /* Return value */ + int i; pPrt = &pAC->GIni.GP[Port]; @@ -946,8 +1043,9 @@ * Extra precaution: check for short Event counter */ Len = sizeof(SK_U64); - SkPnmiGetVar(pAC, IoC, OID_SKGE_STAT_RX_SHORTS, (char *) &Shorts, - &Len, (SK_U32) SK_PNMI_PORT_PHYS2INST(Port)); + SkPnmiGetVar(pAC, IoC, OID_SKGE_STAT_RX_SHORTS, (char *)&Shorts, + &Len, (SK_U32)SK_PNMI_PORT_PHYS2INST(pAC, Port), + pAC->Rlmt.Port[Port].Net->NetNumber); /* * Read RX counter (packets seen on the network and not neccesarily @@ -956,9 +1054,10 @@ Len = sizeof(SK_U64); RxCts = 0; - for (i = 0; i < sizeof(SkGeRxOids)/sizeof(SK_U32) ; i++) { - SkPnmiGetVar(pAC, IoC, SkGeRxOids[i], (char *) &RxTmp, - &Len, (SK_U32) SK_PNMI_PORT_PHYS2INST(Port)); + for (i = 0; i < sizeof(SkGeRxOids)/sizeof(SK_U32); i++) { + SkPnmiGetVar(pAC, IoC, SkGeRxOids[i], (char *)&RxTmp, + &Len, (SK_U32)SK_PNMI_PORT_PHYS2INST(pAC, Port), + pAC->Rlmt.Port[Port].Net->NetNumber); RxCts += RxTmp; } @@ -973,19 +1072,20 @@ * Reset Link Restart counter */ pPrt->PLinkResCt = 0; + pPrt->PAutoNegTOCt = 0; /* If link is up check for 2 */ CheckShorts = 2; Len = sizeof(SK_U64); SkPnmiGetVar(pAC, IoC, OID_SKGE_STAT_RX_FCS, - (char *) &FcsErrCts, &Len, - (SK_U32) SK_PNMI_PORT_PHYS2INST(Port)); + (char *)&FcsErrCts, &Len, (SK_U32)SK_PNMI_PORT_PHYS2INST(pAC, Port), + pAC->Rlmt.Port[Port].Net->NetNumber); if (pPrt->PLinkModeConf == SK_LMODE_AUTOSENSE && pPrt->PLipaAutoNeg == SK_LIPA_UNKNOWN && (pPrt->PLinkMode == SK_LMODE_HALF || - pPrt->PLinkMode == SK_LMODE_FULL)) { + pPrt->PLinkMode == SK_LMODE_FULL)) { /* * This is autosensing and we are in the fallback * manual full/half duplex mode. @@ -997,8 +1097,9 @@ */ pPrt->PPrevFcs = FcsErrCts; pPrt->PPrevShorts = Shorts; - return(SK_HW_PS_RESTART); - } else { + return (SK_HW_PS_RESTART); + } + else { pPrt->PLipaAutoNeg = SK_LIPA_MANUAL; } } @@ -1006,20 +1107,18 @@ if (((RxCts - pPrt->PPrevRx) > pPrt->PRxLim) || (!(FcsErrCts - pPrt->PPrevFcs))) { /* - * Note: The compare with zero above has to be done - * the way shown, otherwise the Linux driver will - * have a problem. + * Note: The compare with zero above has to be done the way shown, + * otherwise the Linux driver will have a problem. */ /* - * we received a bunch of frames or no - * CRC error occurred on the network -> - * ok. + * We received a bunch of frames or no CRC error occured on the + * network -> ok. */ pPrt->PPrevRx = RxCts; pPrt->PPrevFcs = FcsErrCts; pPrt->PPrevShorts = Shorts; - return(SK_HW_PS_NONE) ; + return (SK_HW_PS_NONE); } pPrt->PPrevFcs = FcsErrCts; @@ -1027,7 +1126,7 @@ if ((Shorts - pPrt->PPrevShorts) > CheckShorts) { - SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_IRQ, + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ, ("Short Event Count Restart Port %d \n", Port)); Rtv = SK_HW_PS_RESTART; } @@ -1035,13 +1134,13 @@ pPrt->PPrevShorts = Shorts; pPrt->PPrevRx = RxCts; - return(Rtv); -} + return (Rtv); +} /* SkGePortCheckShorts*/ /****************************************************************************** * - * SkGePortCheckUp - Implementing of the Workaround Errata # 2 + * SkGePortCheckUp - Implementation of the Workaround for Errata #2 * * return: * 0 o.k. nothing needed @@ -1049,15 +1148,11 @@ * 2 Link came up */ int SkGePortCheckUp( -SK_AC *pAC, /* Adapters context */ +SK_AC *pAC, /* Adapter Context */ SK_IOC IoC, /* IO Context */ -int Port) /* Which port should be checked */ +int Port) /* Which port should be checked */ { - SK_GEPORT *pPrt; /* GIni Port struct pointer */ - - pPrt = &pAC->GIni.GP[Port]; - - switch (pPrt->PhyType) { + switch (pAC->GIni.GP[Port].PhyType) { case SK_PHY_XMAC: return (SkGePortCheckUpXmac(pAC, IoC, Port)); case SK_PHY_BCOM: @@ -1067,9 +1162,8 @@ case SK_PHY_NAT: return (SkGePortCheckUpNat(pAC, IoC, Port)); } - - return(SK_HW_PS_NONE) ; -} + return (SK_HW_PS_NONE); +} /* SkGePortCheckUp */ /****************************************************************************** @@ -1082,75 +1176,69 @@ * 2 Link came up */ static int SkGePortCheckUpXmac( -SK_AC *pAC, /* Adapters context */ +SK_AC *pAC, /* Adapter Context */ SK_IOC IoC, /* IO Context */ -int Port) /* Which port should be checked */ +int Port) /* Which port should be checked */ { + SK_U64 Shorts; /* Short Event Counter */ SK_GEPORT *pPrt; /* GIni Port struct pointer */ - SK_BOOL AutoNeg; /* Is Autonegotiation used ? */ - SK_U16 Isrc; /* Interrupt source register */ + unsigned Len; + int Done; SK_U32 GpReg; /* General Purpose register value */ + SK_U16 Isrc; /* Interrupt source register */ SK_U16 IsrcSum; /* Interrupt source register sum */ SK_U16 LpAb; /* Link Partner Ability */ SK_U16 ResAb; /* Resolved Ability */ - SK_U64 Shorts; /* Short Event Counter */ - unsigned int Len; - SK_U8 NextMode; /* Next AutoSensing Mode */ SK_U16 ExtStat; /* Extended Status Register */ - int Done; + SK_BOOL AutoNeg; /* Is Autonegotiation used ? */ + SK_U8 NextMode; /* Next AutoSensing Mode */ pPrt = &pAC->GIni.GP[Port]; if (pPrt->PHWLinkUp) { if (pPrt->PhyType != SK_PHY_XMAC) { - return(SK_HW_PS_NONE) ; + return (SK_HW_PS_NONE); } else { - return(SkGePortCheckShorts(pAC, IoC, Port)) ; + return (SkGePortCheckShorts(pAC, IoC, Port)); } } IsrcSum = pPrt->PIsave; pPrt->PIsave = 0; - /* Now wait for each ports link */ + /* Now wait for each port's link. */ if (pPrt->PLinkMode == SK_LMODE_HALF || pPrt->PLinkMode == SK_LMODE_FULL) { AutoNeg = SK_FALSE; - } else { + } + else { AutoNeg = SK_TRUE; } if (pPrt->PLinkBroken) { /* Link was broken */ - XM_IN32(IoC,Port,XM_GP_PORT, &GpReg) ; + XM_IN32(IoC,Port,XM_GP_PORT, &GpReg); if ((GpReg & XM_GP_INP_ASS) == 0) { /* The Link is in sync */ - XM_IN16(IoC,Port,XM_ISRC, &Isrc) ; + XM_IN16(IoC,Port,XM_ISRC, &Isrc); IsrcSum |= Isrc; SkXmAutoNegLipaXmac(pAC, IoC, Port, IsrcSum); if ((Isrc & XM_IS_INP_ASS) == 0) { /* It has been in sync since last Time */ /* Restart the PORT */ - - SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_IRQ, - ("Link in sync Restart Port %d\n", - Port)); + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ, + ("Link in sync Restart Port %d\n", Port)); - /* - * We now need to reinitialize the PrevSHorts - * counter. - */ + /* We now need to reinitialize the PrevShorts counter. */ Len = sizeof(SK_U64); - SkPnmiGetVar(pAC, IoC, - OID_SKGE_STAT_RX_SHORTS, - (char *) &Shorts, - &Len, - (SK_U32) SK_PNMI_PORT_PHYS2INST(Port)); + SkPnmiGetVar(pAC, IoC, OID_SKGE_STAT_RX_SHORTS, (char *)&Shorts, + &Len, (SK_U32)SK_PNMI_PORT_PHYS2INST(pAC, Port), + pAC->Rlmt.Port[Port].Net->NetNumber); pPrt->PPrevShorts = Shorts; - pAC->GIni.GP[Port].PLinkBroken = SK_FALSE ; + pAC->GIni.GP[Port].PLinkBroken = SK_FALSE; /* * Link Restart Workaround: @@ -1165,61 +1253,60 @@ pAC->GIni.GP[Port].PLinkResCt ++; pPrt->PAutoNegTimeOut = 0; - if (pAC->GIni.GP[Port].PLinkResCt < - SK_MAX_LRESTART) { - return(SK_HW_PS_RESTART) ; + if (pAC->GIni.GP[Port].PLinkResCt < SK_MAX_LRESTART) { + return (SK_HW_PS_RESTART); } SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL, - ("Do NOT restart on Port %d %x %x\n", - Port, Isrc, IsrcSum)); + ("Do NOT restart on Port %d %x %x\n", Port, Isrc, IsrcSum)); pAC->GIni.GP[Port].PLinkResCt = 0; - } else { - pPrt->PIsave = (SK_U16) (IsrcSum & (XM_IS_AND)); + } + else { + pPrt->PIsave = (SK_U16)(IsrcSum & (XM_IS_AND)); SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL, - ("Save Sync/nosync Port %d %x %x\n", - Port, Isrc, IsrcSum)); + ("Save Sync/nosync Port %d %x %x\n", Port, Isrc, IsrcSum)); + /* Do nothing more if link is broken */ - return(SK_HW_PS_NONE) ; + return (SK_HW_PS_NONE); } - } else { + } + else { /* Do nothing more if link is broken */ - return(SK_HW_PS_NONE) ; + return (SK_HW_PS_NONE); } - } else { + } + else { /* Link was not broken, check if it is */ - XM_IN16(IoC,Port,XM_ISRC, &Isrc) ; + XM_IN16(IoC, Port, XM_ISRC, &Isrc); IsrcSum |= Isrc; if ((Isrc & XM_IS_INP_ASS) == XM_IS_INP_ASS) { - XM_IN16(IoC,Port,XM_ISRC, &Isrc) ; + XM_IN16(IoC, Port, XM_ISRC, &Isrc); IsrcSum |= Isrc; if ((Isrc & XM_IS_INP_ASS) == XM_IS_INP_ASS) { - XM_IN16(IoC,Port,XM_ISRC, &Isrc) ; + XM_IN16(IoC, Port, XM_ISRC, &Isrc); IsrcSum |= Isrc; if ((Isrc & XM_IS_INP_ASS) == XM_IS_INP_ASS) { - pPrt->PLinkBroken = SK_TRUE ; + pPrt->PLinkBroken = SK_TRUE; /* * Re-Init Link partner Autoneg flag */ pPrt->PLipaAutoNeg = SK_LIPA_UNKNOWN; - SK_DBG_MSG(pAC,SK_DBGMOD_HWM, - SK_DBGCAT_IRQ, - ("Link broken Port %d\n", - Port)); + SK_DBG_MSG(pAC,SK_DBGMOD_HWM, SK_DBGCAT_IRQ, + ("Link broken Port %d\n", Port)); - /* cable removed-> reinit Sensemode */ - /* Init default sense mode */ + /* Cable removed-> reinit sense mode. */ + /* Init default sense mode. */ SkHWInitDefSense(pAC, IoC, Port); - return(SK_HW_PS_RESTART) ; + return (SK_HW_PS_RESTART); } } - } else { + } + else { SkXmAutoNegLipaXmac(pAC, IoC, Port, Isrc); - if (SkGePortCheckShorts(pAC, IoC, Port) == - SK_HW_PS_RESTART) { - return(SK_HW_PS_RESTART) ; + if (SkGePortCheckShorts(pAC, IoC, Port) == SK_HW_PS_RESTART) { + return (SK_HW_PS_RESTART); } } } @@ -1228,18 +1315,15 @@ * here we usually can check whether the link is in sync and * autonegotiation is done. */ - XM_IN32(IoC,Port,XM_GP_PORT, &GpReg) ; - XM_IN16(IoC,Port,XM_ISRC, &Isrc) ; + XM_IN32(IoC, Port, XM_GP_PORT, &GpReg); + XM_IN16(IoC, Port, XM_ISRC, &Isrc); IsrcSum |= Isrc; SkXmAutoNegLipaXmac(pAC, IoC, Port, IsrcSum); if ((GpReg & XM_GP_INP_ASS) != 0 || (IsrcSum & XM_IS_INP_ASS) != 0) { if ((GpReg & XM_GP_INP_ASS) == 0) { - /* - * Save Autonegotiation Done interrupt only if link - * is in sync - */ - pPrt->PIsave = (SK_U16) (IsrcSum & (XM_IS_AND)); + /* Save Autonegotiation Done interrupt only if link is in sync. */ + pPrt->PIsave = (SK_U16)(IsrcSum & (XM_IS_AND)); } #ifdef DEBUG if (pPrt->PIsave & (XM_IS_AND)) { @@ -1247,44 +1331,40 @@ ("AutoNeg done rescheduled Port %d\n", Port)); } #endif - return(SK_HW_PS_NONE) ; + return (SK_HW_PS_NONE); } if (AutoNeg) { if (IsrcSum & XM_IS_AND) { - SkHWLinkUp(pAC, IoC, Port) ; + SkHWLinkUp(pAC, IoC, Port); Done = SkXmAutoNegDone(pAC,IoC,Port); if (Done != SK_AND_OK) { - /* Get PHY parameters, for debugging only */ - PHY_READ(IoC, pPrt, Port, PHY_XMAC_AUNE_LP, - &LpAb); - PHY_READ(IoC, pPrt, Port, PHY_XMAC_RES_ABI, - &ResAb); + /* Get PHY parameters, for debuging only */ + PHY_READ(IoC, pPrt, Port, PHY_XMAC_AUNE_LP, &LpAb); + PHY_READ(IoC, pPrt, Port, PHY_XMAC_RES_ABI, &ResAb); SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL, ("AutoNeg FAIL Port %d (LpAb %x, ResAb %x)\n", Port, LpAb, ResAb)); /* Try next possible mode */ NextMode = SkHWSenseGetNext(pAC, IoC, Port); - SkHWLinkDown(pAC, IoC, Port) ; + SkHWLinkDown(pAC, IoC, Port); if (Done == SK_AND_DUP_CAP) { /* GoTo next mode */ - SkHWSenseSetNext(pAC, IoC, Port, - NextMode); + SkHWSenseSetNext(pAC, IoC, Port, NextMode); } - return(SK_HW_PS_RESTART) ; - - } else { + return (SK_HW_PS_RESTART); + } + else { /* - * Dummy Read extended status to prevent - * extra link down/ups + * Dummy Read extended status to prevent extra link down/ups * (clear Page Received bit if set) */ PHY_READ(IoC, pPrt, Port, PHY_XMAC_AUNE_EXP, &ExtStat); SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL, ("AutoNeg done Port %d\n", Port)); - return(SK_HW_PS_LINK) ; + return (SK_HW_PS_LINK); } } @@ -1294,7 +1374,12 @@ pPrt->PAutoNegTimeOut ++; if (pPrt->PAutoNegTimeOut >= SK_AND_MAX_TO) { /* - * Timeout occurred. + * Increase the Timeout counter. + */ + pPrt->PAutoNegTOCt ++; + + /* + * Timeout occured. * What do we need now? */ SK_DBG_MSG(pAC,SK_DBGMOD_HWM, @@ -1304,42 +1389,57 @@ if (pPrt->PLinkModeConf == SK_LMODE_AUTOSENSE && pPrt->PLipaAutoNeg != SK_LIPA_AUTO) { /* - * Timeout occurred + * Timeout occured * Set Link manually up. */ - SkHWSenseSetNext(pAC, IoC, Port, - SK_LMODE_FULL); - SK_DBG_MSG(pAC,SK_DBGMOD_HWM, - SK_DBGCAT_IRQ, - ("Set manual full duplex Port %d\n", - Port)); + SkHWSenseSetNext(pAC, IoC, Port, SK_LMODE_FULL); + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ, + ("Set manual full duplex Port %d\n", Port)); + } + + if (pPrt->PLinkModeConf == SK_LMODE_AUTOSENSE && + pPrt->PLipaAutoNeg == SK_LIPA_AUTO && + pPrt->PAutoNegTOCt >= SK_MAX_ANEG_TO) { + /* + * This is rather complicated. + * we need to check here whether the LIPA_AUTO + * we saw before is false alert. We saw at one + * switch ( SR8800) that on boot time it sends + * just one autoneg packet and does no further + * autonegotiation. + * Solution: we restart the autosensing after + * a few timeouts. + */ + pPrt->PAutoNegTOCt = 0; + pPrt->PLipaAutoNeg = SK_LIPA_UNKNOWN; + SkHWInitDefSense(pAC, IoC, Port); } /* * Do the restart */ - return(SK_HW_PS_RESTART) ; + return (SK_HW_PS_RESTART); } - } else { + } + else { /* * Link is up and we don't need more. */ #ifdef DEBUG if (pPrt->PLipaAutoNeg == SK_LIPA_AUTO) { - SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL, - ("ERROR: Lipa auto detected on port %d\n", - Port)); + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, + ("ERROR: Lipa auto detected on port %d\n", Port)); } #endif SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_IRQ, ("Link sync(GP), Port %d\n", Port)); - SkHWLinkUp(pAC, IoC, Port) ; - return(SK_HW_PS_LINK) ; + SkHWLinkUp(pAC, IoC, Port); + return (SK_HW_PS_LINK); } - return(SK_HW_PS_NONE) ; -} + return (SK_HW_PS_NONE); +} /* SkGePortCheckUpXmac */ /****************************************************************************** @@ -1352,59 +1452,216 @@ * 2 Link came up */ static int SkGePortCheckUpBcom( -SK_AC *pAC, /* Adapters context */ -SK_IOC IoC, /* IO Context */ -int Port) /* Which port should be checked */ +SK_AC *pAC, /* Adapter Context */ +SK_IOC IoC, /* IO Context */ +int Port) /* Which port should be checked */ { SK_GEPORT *pPrt; /* GIni Port struct pointer */ - SK_BOOL AutoNeg; /* Is Autonegotiation used ? */ + int Done; SK_U16 Isrc; /* Interrupt source register */ - SK_U16 LpAb; /* Link Partner Ability */ - SK_U16 ExtStat; /* Extended Status Register */ SK_U16 PhyStat; /* Phy Status Register */ - int Done; - SK_U16 ResAb; - SK_U16 SWord; + SK_U16 ResAb; /* Master/Slave resolution */ + SK_U16 Ctrl; /* Broadcom control flags */ +#ifdef DEBUG + SK_U16 LpAb; + SK_U16 ExtStat; +#endif /* DEBUG */ + SK_BOOL AutoNeg; /* Is Autonegotiation used ? */ pPrt = &pAC->GIni.GP[Port]; /* Check for No HCD Link events (#10523) */ PHY_READ(IoC, pPrt, Port, PHY_BCOM_INT_STAT, &Isrc); - if ((Isrc & PHY_B_IS_NO_HDCL) == PHY_B_IS_NO_HDCL) { - /* Workaround BCOM Errata */ - /* enable and disable Loopback mode if NO HCD occurs */ - PHY_READ(IoC, pPrt, Port, PHY_BCOM_CTRL, &SWord); - PHY_WRITE(IoC, pPrt, Port, PHY_BCOM_CTRL, SWord | PHY_CT_LOOP); - PHY_WRITE(IoC, pPrt, Port, PHY_BCOM_CTRL, SWord & ~PHY_CT_LOOP); +#ifdef xDEBUG + if ((Isrc & ~0x1800) == 0x70) { + SK_U32 Stat1, Stat2, Stat3; + + Stat1 = 0; + PHY_READ(pAC, pPrt, Port, PHY_BCOM_INT_MASK, &Stat1); + CMSMPrintString( + pAC->pConfigTable, + MSG_TYPE_RUNTIME_INFO, + "CheckUp1 - Stat: %x, Mask: %x", + (void *)Isrc, + (void *)Stat1); + + Stat1 = 0; + PHY_READ(pAC, pPrt, Port, PHY_BCOM_CTRL, &Stat1); + Stat2 = 0; + PHY_READ(pAC, pPrt, Port, PHY_BCOM_STAT, &Stat2); + Stat1 = Stat1 << 16 | Stat2; + Stat2 = 0; + PHY_READ(pAC, pPrt, Port, PHY_BCOM_AUNE_ADV, &Stat2); + Stat3 = 0; + PHY_READ(pAC, pPrt, Port, PHY_BCOM_AUNE_LP, &Stat3); + Stat2 = Stat2 << 16 | Stat3; + CMSMPrintString( + pAC->pConfigTable, + MSG_TYPE_RUNTIME_INFO, + "Ctrl/Stat: %x, AN Adv/LP: %x", + (void *)Stat1, + (void *)Stat2); + + Stat1 = 0; + PHY_READ(pAC, pPrt, Port, PHY_BCOM_AUNE_EXP, &Stat1); + Stat2 = 0; + PHY_READ(pAC, pPrt, Port, PHY_BCOM_EXT_STAT, &Stat2); + Stat1 = Stat1 << 16 | Stat2; + Stat2 = 0; + PHY_READ(pAC, pPrt, Port, PHY_BCOM_1000T_CTRL, &Stat2); + Stat3 = 0; + PHY_READ(pAC, pPrt, Port, PHY_BCOM_1000T_STAT, &Stat3); + Stat2 = Stat2 << 16 | Stat3; + CMSMPrintString( + pAC->pConfigTable, + MSG_TYPE_RUNTIME_INFO, + "AN Exp/IEEE Ext: %x, 1000T Ctrl/Stat: %x", + (void *)Stat1, + (void *)Stat2); + + Stat1 = 0; + PHY_READ(pAC, pPrt, Port, PHY_BCOM_P_EXT_CTRL, &Stat1); + Stat2 = 0; + PHY_READ(pAC, pPrt, Port, PHY_BCOM_P_EXT_STAT, &Stat2); + Stat1 = Stat1 << 16 | Stat2; + Stat2 = 0; + PHY_READ(pAC, pPrt, Port, PHY_BCOM_AUX_CTRL, &Stat2); + Stat3 = 0; + PHY_READ(pAC, pPrt, Port, PHY_BCOM_AUX_STAT, &Stat3); + Stat2 = Stat2 << 16 | Stat3; + CMSMPrintString( + pAC->pConfigTable, + MSG_TYPE_RUNTIME_INFO, + "PHY Ext Ctrl/Stat: %x, Aux Ctrl/Stat: %x", + (void *)Stat1, + (void *)Stat2); + } +#endif /* DEBUG */ + + if ((Isrc & (PHY_B_IS_NO_HDCL /* | PHY_B_IS_NO_HDC */)) != 0) { + /* + * Workaround BCOM Errata: + * enable and disable loopback mode if "NO HCD" occurs. + */ + PHY_READ(IoC, pPrt, Port, PHY_BCOM_CTRL, &Ctrl); + PHY_WRITE(IoC, pPrt, Port, PHY_BCOM_CTRL, Ctrl | PHY_CT_LOOP); + PHY_WRITE(IoC, pPrt, Port, PHY_BCOM_CTRL, Ctrl & ~PHY_CT_LOOP); SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, ("No HCD Link event, Port %d\n", Port)); +#ifdef xDEBUG + CMSMPrintString( + pAC->pConfigTable, + MSG_TYPE_RUNTIME_INFO, + "No HCD link event, port %d.", + (void *)Port, + (void *)NULL); +#endif /* DEBUG */ } + /* Not obsolete: link status bit is latched to 0 and autoclearing! */ PHY_READ(IoC, pPrt, Port, PHY_BCOM_STAT, &PhyStat); if (pPrt->PHWLinkUp) { - return(SK_HW_PS_NONE) ; + return (SK_HW_PS_NONE); } - pPrt->PIsave = 0; +#ifdef xDEBUG + { + SK_U32 Stat1, Stat2, Stat3; + + Stat1 = 0; + PHY_READ(pAC, pPrt, Port, PHY_BCOM_INT_MASK, &Stat1); + CMSMPrintString( + pAC->pConfigTable, + MSG_TYPE_RUNTIME_INFO, + "CheckUp1a - Stat: %x, Mask: %x", + (void *)Isrc, + (void *)Stat1); + + Stat1 = 0; + PHY_READ(pAC, pPrt, Port, PHY_BCOM_CTRL, &Stat1); + Stat2 = 0; + PHY_READ(pAC, pPrt, Port, PHY_BCOM_STAT, &PhyStat); + Stat1 = Stat1 << 16 | PhyStat; + Stat2 = 0; + PHY_READ(pAC, pPrt, Port, PHY_BCOM_AUNE_ADV, &Stat2); + Stat3 = 0; + PHY_READ(pAC, pPrt, Port, PHY_BCOM_AUNE_LP, &Stat3); + Stat2 = Stat2 << 16 | Stat3; + CMSMPrintString( + pAC->pConfigTable, + MSG_TYPE_RUNTIME_INFO, + "Ctrl/Stat: %x, AN Adv/LP: %x", + (void *)Stat1, + (void *)Stat2); + + Stat1 = 0; + PHY_READ(pAC, pPrt, Port, PHY_BCOM_AUNE_EXP, &Stat1); + Stat2 = 0; + PHY_READ(pAC, pPrt, Port, PHY_BCOM_EXT_STAT, &Stat2); + Stat1 = Stat1 << 16 | Stat2; + Stat2 = 0; + PHY_READ(pAC, pPrt, Port, PHY_BCOM_1000T_CTRL, &Stat2); + Stat3 = 0; + PHY_READ(pAC, pPrt, Port, PHY_BCOM_1000T_STAT, &ResAb); + Stat2 = Stat2 << 16 | ResAb; + CMSMPrintString( + pAC->pConfigTable, + MSG_TYPE_RUNTIME_INFO, + "AN Exp/IEEE Ext: %x, 1000T Ctrl/Stat: %x", + (void *)Stat1, + (void *)Stat2); + + Stat1 = 0; + PHY_READ(pAC, pPrt, Port, PHY_BCOM_P_EXT_CTRL, &Stat1); + Stat2 = 0; + PHY_READ(pAC, pPrt, Port, PHY_BCOM_P_EXT_STAT, &Stat2); + Stat1 = Stat1 << 16 | Stat2; + Stat2 = 0; + PHY_READ(pAC, pPrt, Port, PHY_BCOM_AUX_CTRL, &Stat2); + Stat3 = 0; + PHY_READ(pAC, pPrt, Port, PHY_BCOM_AUX_STAT, &Stat3); + Stat2 = Stat2 << 16 | Stat3; + CMSMPrintString( + pAC->pConfigTable, + MSG_TYPE_RUNTIME_INFO, + "PHY Ext Ctrl/Stat: %x, Aux Ctrl/Stat: %x", + (void *)Stat1, + (void *)Stat2); + } +#endif /* DEBUG */ - /* Now wait for each port's link */ - if (pPrt->PLinkMode == SK_LMODE_HALF || - pPrt->PLinkMode == SK_LMODE_FULL) { + /* Now wait for each port's link. */ + if (pPrt->PLinkMode == SK_LMODE_HALF || pPrt->PLinkMode == SK_LMODE_FULL) { AutoNeg = SK_FALSE; - } else { + } + else { AutoNeg = SK_TRUE; } /* - * here we usually can check whether the link is in sync and + * Here we usually can check whether the link is in sync and * autonegotiation is done. */ - XM_IN16(IoC, Port, XM_ISRC, &Isrc) ; +#if 0 +/* RA;:;: obsolete */ + XM_IN16(IoC, Port, XM_ISRC, &Isrc); +#endif /* 0 */ PHY_READ(IoC, pPrt, Port, PHY_BCOM_STAT, &PhyStat); +#ifdef xDEBUG + if ((PhyStat & PHY_ST_LSYNC) >> 2 != (ExtStat & PHY_B_PES_LS) >> 8) { + CMSMPrintString( + pAC->pConfigTable, + MSG_TYPE_RUNTIME_INFO, + "PhyStat != ExtStat: %x %x", + (void *)PhyStat, + (void *)ExtStat); + } +#endif /* DEBUG */ + SkXmAutoNegLipaBcom(pAC, IoC, Port, PhyStat); SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, @@ -1412,28 +1669,22 @@ PHY_READ(IoC, pPrt, Port, PHY_BCOM_1000T_STAT, &ResAb); - if ((PhyStat & PHY_ST_LSYNC) == 0) { - if (ResAb & (PHY_B_1000S_MSF)) { - /* Error */ - SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL, - ("Master/Slave Fault port %d\n", Port)); - pPrt->PAutoNegFail = SK_TRUE; - pPrt->PMSStatus = SK_MS_STAT_FAULT; - return (SK_AND_OTHER); - } - return (SK_HW_PS_NONE); - } - - if (ResAb & (PHY_B_1000S_MSF)) { + if (ResAb & PHY_B_1000S_MSF) { /* Error */ - SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL, + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, ("Master/Slave Fault port %d\n", Port)); pPrt->PAutoNegFail = SK_TRUE; pPrt->PMSStatus = SK_MS_STAT_FAULT; - return (SK_AND_OTHER); - } else if (ResAb & PHY_B_1000S_MSR) { + return (SK_HW_PS_RESTART); + } + + if ((PhyStat & PHY_ST_LSYNC) == 0) { + return (SK_HW_PS_NONE); + } + else if (ResAb & PHY_B_1000S_MSR) { pPrt->PMSStatus = SK_MS_STAT_MASTER; - } else { + } + else { pPrt->PMSStatus = SK_MS_STAT_SLAVE; } @@ -1443,76 +1694,73 @@ if (AutoNeg) { if (PhyStat & PHY_ST_AN_OVER) { SkHWLinkUp(pAC, IoC, Port); - Done = SkXmAutoNegDone(pAC,IoC,Port); + Done = SkXmAutoNegDone(pAC, IoC, Port); if (Done != SK_AND_OK) { - /* Get PHY parameters, for debugging only */ - PHY_READ(IoC, pPrt, Port, - PHY_BCOM_AUNE_LP, - &LpAb); - PHY_READ(IoC, pPrt, Port, - PHY_BCOM_1000T_STAT, - &ExtStat); - SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL, - ("AutoNeg FAIL Port %d (LpAb %x, " - "1000TStat %x)\n", - Port, LpAb, ExtStat)); - return(SK_HW_PS_RESTART) ; - - } else { - /* - * Dummy Read interrupt status to prevent - * extra link down/ups - */ - PHY_READ(IoC, pPrt, Port, PHY_BCOM_INT_STAT, - &ExtStat); - SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL, +#ifdef DEBUG + /* Get PHY parameters, for debugging only. */ + PHY_READ(IoC, pPrt, Port, PHY_BCOM_AUNE_LP, &LpAb); + PHY_READ(IoC, pPrt, Port, PHY_BCOM_1000T_STAT, &ExtStat); + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, + ("AutoNeg FAIL Port %d (LpAb %x, 1000TStat %x)\n", + Port, LpAb, ExtStat)); +#endif /* DEBUG */ + return (SK_HW_PS_RESTART); + } + else { +#ifdef xDEBUG + /* Dummy read ISR to prevent extra link downs/ups. */ + PHY_READ(IoC, pPrt, Port, PHY_BCOM_INT_STAT, &ExtStat); + + if ((ExtStat & ~0x1800) != 0) { + CMSMPrintString( + pAC->pConfigTable, + MSG_TYPE_RUNTIME_INFO, + "CheckUp2 - Stat: %x", + (void *)ExtStat, + (void *)NULL); + } +#endif /* DEBUG */ + + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, ("AutoNeg done Port %d\n", Port)); - return(SK_HW_PS_LINK) ; + return (SK_HW_PS_LINK); } } - } else { + } + else { /* !AutoNeg */ /* * Link is up and we don't need more. */ #ifdef DEBUG if (pPrt->PLipaAutoNeg == SK_LIPA_AUTO) { - SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL, - ("ERROR: Lipa auto detected on port %d\n", - Port)); + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, + ("ERROR: Lipa auto detected on port %d\n", Port)); } #endif -#if 0 - PHY_READ(IoC, pPrt, Port, PHY_BCOM_1000T_STAT, &ResAb); - if (ResAb & (PHY_B_1000S_MSF)) { - /* Error */ - SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL, - ("Master/Slave Fault port %d\n", Port)); - pPrt->PAutoNegFail = SK_TRUE; - pPrt->PMSStatus = SK_MS_STAT_FAULT; - return (SK_AND_OTHER); - } else if (ResAb & PHY_B_1000S_MSR) { - pPrt->PMSStatus = SK_MS_STAT_MASTER ; - } else { - pPrt->PMSStatus = SK_MS_STAT_SLAVE ; - } -#endif /* 0 */ - - - /* - * Dummy Read interrupt status to prevent - * extra link down/ups - */ +#ifdef xDEBUG + /* Dummy read ISR to prevent extra link downs/ups. */ PHY_READ(IoC, pPrt, Port, PHY_BCOM_INT_STAT, &ExtStat); + + if ((ExtStat & ~0x1800) != 0) { + CMSMPrintString( + pAC->pConfigTable, + MSG_TYPE_RUNTIME_INFO, + "CheckUp3 - Stat: %x", + (void *)ExtStat, + (void *)NULL); + } +#endif /* DEBUG */ - SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_IRQ, + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ, ("Link sync(GP), Port %d\n", Port)); - SkHWLinkUp(pAC, IoC, Port) ; - return(SK_HW_PS_LINK) ; + SkHWLinkUp(pAC, IoC, Port); + return (SK_HW_PS_LINK); } - return(SK_HW_PS_NONE) ; -} + return (SK_HW_PS_NONE); +} /* SkGePortCheckUpBcom */ + /****************************************************************************** * @@ -1524,24 +1772,24 @@ * 2 Link came up */ static int SkGePortCheckUpLone( -SK_AC *pAC, /* Adapters context */ +SK_AC *pAC, /* Adapter Context */ SK_IOC IoC, /* IO Context */ -int Port) /* Which port should be checked */ +int Port) /* Which port should be checked */ { SK_GEPORT *pPrt; /* GIni Port struct pointer */ - SK_BOOL AutoNeg; /* Is Autonegotiation used ? */ + int Done; SK_U16 Isrc; /* Interrupt source register */ SK_U16 LpAb; /* Link Partner Ability */ - SK_U8 NextMode; /* Next AutoSensing Mode */ SK_U16 ExtStat; /* Extended Status Register */ SK_U16 PhyStat; /* Phy Status Register */ SK_U16 StatSum; - int Done; + SK_BOOL AutoNeg; /* Is Autonegotiation used ? */ + SK_U8 NextMode; /* Next AutoSensing Mode */ pPrt = &pAC->GIni.GP[Port]; if (pPrt->PHWLinkUp) { - return(SK_HW_PS_NONE) ; + return (SK_HW_PS_NONE); } StatSum = pPrt->PIsave; @@ -1551,7 +1799,8 @@ if (pPrt->PLinkMode == SK_LMODE_HALF || pPrt->PLinkMode == SK_LMODE_FULL) { AutoNeg = SK_FALSE; - } else { + } + else { AutoNeg = SK_TRUE; } @@ -1559,7 +1808,7 @@ * here we usually can check whether the link is in sync and * autonegotiation is done. */ - XM_IN16(IoC, Port, XM_ISRC, &Isrc) ; + XM_IN16(IoC, Port, XM_ISRC, &Isrc); PHY_READ(IoC, pPrt, Port, PHY_LONE_STAT, &PhyStat); StatSum |= PhyStat; @@ -1568,53 +1817,52 @@ /* * Save Autonegotiation Done bit */ - pPrt->PIsave = (SK_U16) (StatSum & PHY_ST_AN_OVER); + pPrt->PIsave = (SK_U16)(StatSum & PHY_ST_AN_OVER); #ifdef DEBUG if (pPrt->PIsave & PHY_ST_AN_OVER) { SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL, ("AutoNeg done rescheduled Port %d\n", Port)); } #endif - return(SK_HW_PS_NONE) ; + return (SK_HW_PS_NONE); } if (AutoNeg) { if (StatSum & PHY_ST_AN_OVER) { - SkHWLinkUp(pAC, IoC, Port) ; + SkHWLinkUp(pAC, IoC, Port); Done = SkXmAutoNegDone(pAC,IoC,Port); if (Done != SK_AND_OK) { - /* Get PHY parameters, for debugging only */ + /* Get PHY parameters, for debuging only */ PHY_READ(IoC, pPrt, Port, PHY_LONE_AUNE_LP, &LpAb); PHY_READ(IoC, pPrt, Port, PHY_LONE_1000T_STAT, &ExtStat); - SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL, + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, ("AutoNeg FAIL Port %d (LpAb %x, 1000TStat %x)\n", Port, LpAb, ExtStat)); /* Try next possible mode */ NextMode = SkHWSenseGetNext(pAC, IoC, Port); - SkHWLinkDown(pAC, IoC, Port) ; + SkHWLinkDown(pAC, IoC, Port); if (Done == SK_AND_DUP_CAP) { /* GoTo next mode */ - SkHWSenseSetNext(pAC, IoC, Port, - NextMode); + SkHWSenseSetNext(pAC, IoC, Port, NextMode); } - return(SK_HW_PS_RESTART) ; + return (SK_HW_PS_RESTART); - } else { + } + else { /* * Dummy Read interrupt status to prevent * extra link down/ups */ - PHY_READ(IoC, pPrt, Port, PHY_LONE_INT_STAT, - &ExtStat); - SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL, + PHY_READ(IoC, pPrt, Port, PHY_LONE_INT_STAT, &ExtStat); + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, ("AutoNeg done Port %d\n", Port)); - return(SK_HW_PS_LINK) ; + return (SK_HW_PS_LINK); } } @@ -1624,7 +1872,7 @@ pPrt->PAutoNegTimeOut ++; if (pPrt->PAutoNegTimeOut >= SK_AND_MAX_TO) { /* - * Timeout occurred. + * Timeout occured. * What do we need now? */ SK_DBG_MSG(pAC,SK_DBGMOD_HWM, @@ -1634,7 +1882,7 @@ if (pPrt->PLinkModeConf == SK_LMODE_AUTOSENSE && pPrt->PLipaAutoNeg != SK_LIPA_AUTO) { /* - * Timeout occurred + * Timeout occured * Set Link manually up. */ SkHWSenseSetNext(pAC, IoC, Port, @@ -1648,17 +1896,17 @@ /* * Do the restart */ - return(SK_HW_PS_RESTART) ; + return (SK_HW_PS_RESTART); } - } else { + } + else { /* * Link is up and we don't need more. */ #ifdef DEBUG if (pPrt->PLipaAutoNeg == SK_LIPA_AUTO) { - SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL, - ("ERROR: Lipa auto detected on port %d\n", - Port)); + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, + ("ERROR: Lipa auto detected on port %d\n", Port)); } #endif @@ -1668,14 +1916,14 @@ */ PHY_READ(IoC, pPrt, Port, PHY_LONE_INT_STAT, &ExtStat); - SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_IRQ, + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ, ("Link sync(GP), Port %d\n", Port)); - SkHWLinkUp(pAC, IoC, Port) ; - return(SK_HW_PS_LINK) ; + SkHWLinkUp(pAC, IoC, Port); + return (SK_HW_PS_LINK); } - return(SK_HW_PS_NONE) ; -} + return (SK_HW_PS_NONE); +} /* SkGePortCheckUpLone*/ /****************************************************************************** @@ -1688,13 +1936,13 @@ * 2 Link came up */ static int SkGePortCheckUpNat( -SK_AC *pAC, /* Adapters context */ +SK_AC *pAC, /* Adapter Context */ SK_IOC IoC, /* IO Context */ -int Port) /* Which port should be checked */ +int Port) /* Which port should be checked */ { /* todo: National */ - return(SK_HW_PS_NONE) ; -} + return (SK_HW_PS_NONE); +} /* SkGePortCheckUpNat */ /****************************************************************************** @@ -1706,17 +1954,21 @@ * Notes: */ int SkGeSirqEvent( -SK_AC *pAC, /* Adapters context */ +SK_AC *pAC, /* Adapter Context */ SK_IOC IoC, /* Io Context */ SK_U32 Event, /* Module specific Event */ SK_EVPARA Para) /* Event specific Parameter */ { - SK_U32 Port; - SK_U32 Time; - SK_U8 Val8 ; - int PortStat; + SK_U64 Octets; + SK_GEPORT *pPrt; /* GIni Port struct pointer */ + SK_U32 Port; + SK_U32 Time; + unsigned Len; + int PortStat; + SK_U8 Val8; Port = Para.Para32[0]; + pPrt = & pAC->GIni.GP[Port]; switch (Event) { case SK_HWEV_WATIM: @@ -1725,7 +1977,7 @@ switch (PortStat) { case SK_HW_PS_RESTART: - if (pAC->GIni.GP[Port].PHWLinkUp) { + if (pPrt->PHWLinkUp) { /* * Set Link to down. */ @@ -1735,16 +1987,7 @@ * Signal directly to RLMT to ensure correct * sequence of SWITCH and RESET event. */ - Para.Para32[0] = (SK_U32) Port; SkRlmtEvent(pAC, IoC, SK_RLMT_LINK_DOWN, Para); - - /* Start workaround Errata #2 timer */ - SkTimerStart(pAC, IoC, - &pAC->GIni.GP[Port].PWaTimer, - SK_WA_INA_TIME, - SKGE_HWAC, - SK_HWEV_WATIM, - Para); } /* Restart needed */ @@ -1757,39 +2000,38 @@ break; } - + /* Start again the check Timer */ - if (pAC->GIni.GP[Port].PHWLinkUp) { + if (pPrt->PHWLinkUp) { Time = SK_WA_ACT_TIME; - } else { + } + else { Time = SK_WA_INA_TIME; } - /* todo: still needed for non-Xmac-PHYs ??? */ - /* Start workaround Errata #2 timer */ - SkTimerStart(pAC, IoC, &pAC->GIni.GP[Port].PWaTimer, Time, - SKGE_HWAC, SK_HWEV_WATIM, Para); - + /* Todo: still needed for non-XMAC PHYs??? */ + /* Start workaround Errata #2 timer. */ + SkTimerStart(pAC, IoC, &pAC->GIni.GP[Port].PWaTimer, + Time, SKGE_HWAC, SK_HWEV_WATIM, Para); break; case SK_HWEV_PORT_START: - if (pAC->GIni.GP[Port].PHWLinkUp) { + if (pPrt->PHWLinkUp) { /* * Signal directly to RLMT to ensure correct * sequence of SWITCH and RESET event. */ - Para.Para32[0] = (SK_U32) Port; SkRlmtEvent(pAC, IoC, SK_RLMT_LINK_DOWN, Para); } - SkHWLinkDown(pAC, IoC, Port) ; + SkHWLinkDown(pAC, IoC, Port); /* Schedule Port RESET */ SkEventQueue(pAC, SKGE_DRV, SK_DRV_PORT_RESET, Para); /* Start workaround Errata #2 timer */ - SkTimerStart(pAC, IoC, &pAC->GIni.GP[Port].PWaTimer, - SK_WA_INA_TIME,SKGE_HWAC,SK_HWEV_WATIM,Para); + SkTimerStart(pAC, IoC, &pPrt->PWaTimer, SK_WA_INA_TIME, + SKGE_HWAC, SK_HWEV_WATIM, Para); break; case SK_HWEV_PORT_STOP: @@ -1798,13 +2040,13 @@ * Signal directly to RLMT to ensure correct * sequence of SWITCH and RESET event. */ - Para.Para32[0] = (SK_U32) Port; SkRlmtEvent(pAC, IoC, SK_RLMT_LINK_DOWN, Para); } + /* Stop Workaround Timer */ - SkTimerStop(pAC, IoC, &pAC->GIni.GP[Port].PWaTimer) ; + SkTimerStop(pAC, IoC, &pPrt->PWaTimer); - SkHWLinkDown(pAC, IoC, Port) ; + SkHWLinkDown(pAC, IoC, Port); break; case SK_HWEV_UPDATE_STAT: @@ -1813,18 +2055,18 @@ case SK_HWEV_CLEAR_STAT: /* We do NOT need to clear any statistics */ - for (Port = 0; Port < (SK_U32) pAC->GIni.GIMacsFound; Port++) { - pAC->GIni.GP[Port].PPrevRx = 0; - pAC->GIni.GP[Port].PPrevFcs = 0; - pAC->GIni.GP[Port].PPrevShorts = 0; + for (Port = 0; Port < (SK_U32)pAC->GIni.GIMacsFound; Port++) { + pPrt->PPrevRx = 0; + pPrt->PPrevFcs = 0; + pPrt->PPrevShorts = 0; } break; case SK_HWEV_SET_LMODE: - Val8 = (SK_U8) Para.Para32[1]; - if (pAC->GIni.GP[Port].PLinkModeConf != Val8) { + Val8 = (SK_U8)Para.Para32[1]; + if (pPrt->PLinkModeConf != Val8) { /* Set New link mode */ - pAC->GIni.GP[Port].PLinkModeConf = Val8; + pPrt->PLinkModeConf = Val8; /* Restart Port */ SkEventQueue(pAC, SKGE_HWAC, SK_HWEV_PORT_STOP, Para); @@ -1833,10 +2075,10 @@ break; case SK_HWEV_SET_FLOWMODE: - Val8 = (SK_U8) Para.Para32[1]; - if (pAC->GIni.GP[Port].PFlowCtrlMode != Val8) { + Val8 = (SK_U8)Para.Para32[1]; + if (pPrt->PFlowCtrlMode != Val8) { /* Set New Flow Control mode */ - pAC->GIni.GP[Port].PFlowCtrlMode = Val8; + pPrt->PFlowCtrlMode = Val8; /* Restart Port */ SkEventQueue(pAC, SKGE_HWAC, SK_HWEV_PORT_STOP, Para); @@ -1845,10 +2087,10 @@ break; case SK_HWEV_SET_ROLE: - Val8 = (SK_U8) Para.Para32[1]; - if (pAC->GIni.GP[Port].PMSMode != Val8) { + Val8 = (SK_U8)Para.Para32[1]; + if (pPrt->PMSMode != Val8) { /* Set New link mode */ - pAC->GIni.GP[Port].PMSMode = Val8; + pPrt->PMSMode = Val8; /* Restart Port */ SkEventQueue(pAC, SKGE_HWAC, SK_HWEV_PORT_STOP, Para); @@ -1856,14 +2098,31 @@ } break; + case SK_HWEV_HALFDUP_CHK: + /* + * half duplex hangup workaround. See packet arbiter timeout + * interrupt for description + */ + pPrt->HalfDupTimerActive = SK_FALSE; + if (pPrt->PLinkModeStatus == SK_LMODE_STAT_HALF || + pPrt->PLinkModeStatus == SK_LMODE_STAT_AUTOHALF) { + Len = sizeof(SK_U64); + SkPnmiGetVar(pAC, IoC, OID_SKGE_STAT_TX_OCTETS, (char *)&Octets, + &Len, (SK_U32)SK_PNMI_PORT_PHYS2INST(pAC, Port), + pAC->Rlmt.Port[Port].Net->NetNumber); + if (pPrt->LastOctets == Octets) { + /* TX hanging, do a FIFO flush restarts it. */ + SkXmFlushTxFifo(pAC, IoC, Port); + } + } + break; default: - SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_SIRQ_E001, - SKERR_SIRQ_E001MSG); + SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_SIRQ_E001, SKERR_SIRQ_E001MSG); break; } - return(0) ; -} + return (0); +} /* SkGeSirqEvent */ /****************************************************************************** @@ -1875,17 +2134,20 @@ * Returns: N/A */ static void SkPhyIsrBcom( -SK_AC *pAC, /* Adapters context */ +SK_AC *pAC, /* Adapter Context */ SK_IOC IoC, /* Io Context */ -int Port, /* Port Num = PHY Num */ -SK_U16 IStatus) /* Interrupts masked with PHY-Mask */ +int Port, /* Port Num = PHY Num */ +SK_U16 IStatus) /* Interrupt Status */ { + SK_GEPORT *pPrt; /* GIni Port struct pointer */ SK_EVPARA Para; + pPrt = &pAC->GIni.GP[Port]; + if (IStatus & PHY_B_IS_PSE) { - /* incorrectable pair swap error */ + /* Incorrectable pair swap error. */ SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_SIRQ_E022, - SKERR_SIRQ_E022MSG) ; + SKERR_SIRQ_E022MSG); } if (IStatus & PHY_B_IS_MDXI_SC) { @@ -1901,19 +2163,19 @@ } if (IStatus & (PHY_B_IS_AN_PR | PHY_B_IS_LST_CHANGE)) { + Para.Para32[0] = (SK_U32)Port; + SkHWLinkDown(pAC, IoC, Port); /* Signal to RLMT */ - Para.Para32[0] = (SK_U32) Port; SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_LINK_DOWN, Para); /* Start workaround Errata #2 timer */ - SkTimerStart(pAC, IoC, &pAC->GIni.GP[Port].PWaTimer, - SK_WA_INA_TIME,SKGE_HWAC,SK_HWEV_WATIM,Para); + SkTimerStart(pAC, IoC, &pPrt->PWaTimer, + SK_WA_INA_TIME, SKGE_HWAC, SK_HWEV_WATIM, Para); } if (IStatus & PHY_B_IS_NO_HDCL) { - /* not used */ } if (IStatus & PHY_B_IS_NO_HDC) { @@ -1947,8 +2209,7 @@ if (IStatus & PHY_B_IS_CRC_ER) { /* not used */ } - -} +} /* SkPhyIsrBcom */ /****************************************************************************** @@ -1960,10 +2221,10 @@ * Returns: N/A */ static void SkPhyIsrLone( -SK_AC *pAC, /* Adapters context */ -SK_IOC IoC, /* Io Context */ +SK_AC *pAC, /* Adapter Context */ +SK_IOC IoC, /* Io Context */ int Port, /* Port Num = PHY Num */ -SK_U16 IStatus) /* Interrupts masked with PHY-Mask */ +SK_U16 IStatus) /* Interrupt Status */ { SK_EVPARA Para; @@ -1999,19 +2260,17 @@ SkHWLinkDown(pAC, IoC, Port); /* Signal to RLMT */ - Para.Para32[0] = (SK_U32) Port; + Para.Para32[0] = (SK_U32)Port; SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_LINK_DOWN, Para); /* Start workaround Errata #2 timer */ SkTimerStart(pAC, IoC, &pAC->GIni.GP[Port].PWaTimer, - SK_WA_INA_TIME,SKGE_HWAC,SK_HWEV_WATIM,Para); + SK_WA_INA_TIME, SKGE_HWAC, SK_HWEV_WATIM, Para); } if (IStatus & PHY_L_IS_MDINT) { /* not used */ } - -} - +} /* SkPhyIsrLone */ /* End of File */ diff -u --recursive --new-file v2.4.6/linux/drivers/net/sk98lin/ski2c.c linux/drivers/net/sk98lin/ski2c.c --- v2.4.6/linux/drivers/net/sk98lin/ski2c.c Tue Mar 20 12:04:59 2001 +++ linux/drivers/net/sk98lin/ski2c.c Wed Jul 4 11:50:39 2001 @@ -2,17 +2,16 @@ * * Name: ski2c.c * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.44 $ - * Date: $Date: 2000/08/07 15:49:03 $ - * Purpose: Funktions to access Voltage and Temperature Sensor - * (taken from Monalisa (taken from Concentrator)) + * Version: $Revision: 1.47 $ + * Date: $Date: 2001/04/05 11:38:09 $ + * Purpose: Functions to access Voltage and Temperature Sensor + * (taken from Monalisa (taken from Concentrator)) * ******************************************************************************/ /****************************************************************************** * - * (C)Copyright 1998-2000 SysKonnect, - * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * (C)Copyright 1998-2001 SysKonnect GmbH. * * 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 @@ -28,12 +27,22 @@ * History: * * $Log: ski2c.c,v $ + * Revision 1.47 2001/04/05 11:38:09 rassmann + * Set SenState to idle in SkI2cWaitIrq(). + * Changed error message in SkI2cWaitIrq(). + * + * Revision 1.46 2001/04/02 14:03:35 rassmann + * Changed pAC to IoC in SK_IN32(). + * + * Revision 1.45 2001/03/21 12:12:49 rassmann + * Resetting I2C_READY interrupt in SkI2cInit1(). + * * Revision 1.44 2000/08/07 15:49:03 gklug - * fix: SK_INFAST only in NetWare driver + * Fix: SK_INFAST only in NetWare driver. * * Revision 1.43 2000/08/03 14:28:17 rassmann - * - Added function to wait for I2C being ready before resetting the board. - * - Replaced one duplicate "out of range" message with correct one. + * Added function to wait for I2C being ready before resetting the board. + * Replaced one duplicate "out of range" message with correct one. * * Revision 1.42 1999/11/22 13:35:12 cgoos * Changed license header to GPL. @@ -180,10 +189,10 @@ /* - I2C Protocol -*/ + * I2C Protocol + */ static const char SysKonnectFileId[] = - "$Id: ski2c.c,v 1.44 2000/08/07 15:49:03 gklug Exp $"; + "$Id: ski2c.c,v 1.47 2001/04/05 11:38:09 rassmann Exp $"; #include "h/skdrv1st.h" /* Driver Specific Definitions */ #include "h/lm80.h" @@ -191,7 +200,7 @@ #ifdef __C2MAN__ /* - I2C protocol implemetation. + I2C protocol implementation. General Description: @@ -486,7 +495,7 @@ { int i; - for (i=0; i<8; i++) { + for (i = 0; i < 8; i++) { if (Byte & (1<<(7-i))) { SkI2cSndBit(IoC, 1); } else { @@ -510,7 +519,7 @@ int i; int Byte = 0; - for (i=0; i<8; i++) { + for (i = 0; i < 8; i++) { Byte <<= 1; Byte |= SkI2cRcvBit(IoC); } @@ -601,13 +610,14 @@ if (SkOsGetTime(pAC) - StartTime > SK_TICKS_PER_SEC / 8) { SK_I2C_STOP(IoC); #ifndef SK_DIAG - SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_I2C_E002, SKERR_I2C_E002MSG); + SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_I2C_E016, SKERR_I2C_E016MSG); #endif /* !SK_DIAG */ return; } - SK_IN32(pAC, B0_ISRC, &IrqSrc); + SK_IN32(IoC, B0_ISRC, &IrqSrc); } while ((IrqSrc & IS_I2C_READY) == 0); + pSen->SenState = SK_SEN_IDLE; return; } /* SkI2cWaitIrq */ @@ -662,10 +672,11 @@ /* * read a sensor's value * - * This function read a sensors value from the I2C sensor chip. The sensor + * This function reads a sensor's value from the I2C sensor chip. The sensor * is defined by its index into the sensors database in the struct pAC points * to. - * Returns 1 if the read is completed + * Returns + * 1 if the read is completed * 0 if the read must be continued (I2C Bus still allocated) */ int SkI2cReadSensor( @@ -695,7 +706,7 @@ pAC->I2c.DummyReads = SK_MAX_SENSORS; #endif - for (i=0; i < SK_MAX_SENSORS; i ++) { + for (i = 0; i < SK_MAX_SENSORS; i ++) { switch (i) { case 0: pAC->I2c.SenTable[i].SenDesc = "Temperature"; @@ -875,16 +886,19 @@ #ifndef SK_DIAG pAC->I2c.DummyReads = pAC->I2c.MaxSens; + + /* Clear the interrupt source */ + SK_OUT32(IoC, B2_I2C_IRQ, I2C_CLR_IRQ); #endif /* !SK_DIAG */ - /* Now we are IO initialized */ + /* Now we are I/O initialized */ pAC->I2c.InitLevel = SK_INIT_IO; return(0); } /* SkI2cInit1 */ /* - * Init level 2: Start first sensors read + * Init level 2: Start first sensor read. */ static int SkI2cInit2( SK_AC *pAC, /* Adapter Context */ @@ -923,12 +937,13 @@ * Level 0: * Initialize only the data structures. Do NOT access hardware. * Level 1: - * Initialize hardware through SK_IN?OUT commands. Do NOT use interrupts. + * Initialize hardware through SK_IN / SK_OUT commands. Do NOT use interrupts. * Level 2: * Everything is possible. Interrupts may be used from now on. * - * return: 0 = success - * other = error. + * return: + * 0 = success + * other = error. */ int SkI2cInit( SK_AC *pAC, /* Adapter Context */ @@ -986,7 +1001,7 @@ SK_EVPARA ParaLocal; SK_BOOL TooHigh; /* Is sensor too high? */ SK_BOOL TooLow; /* Is sensor too low? */ - SK_U64 CurrTime; /* current Time */ + SK_U64 CurrTime; /* Current Time */ SK_BOOL DoTrapSend; /* We need to send a trap */ SK_BOOL DoErrLog; /* We need to log the error */ SK_BOOL IsError; /* We need to log the error */ @@ -1000,13 +1015,10 @@ /* Get the current time */ CurrTime = SkOsGetTime(pAC); - /* Set para to the most useful setting: - * The current sensor. - */ + /* Set para to the most useful setting: The current sensor. */ ParaLocal.Para64 = (SK_U64) pAC->I2c.CurrSens; - /* Check the Value against the thresholds */ - /* First: Error Thresholds */ + /* Check the Value against the thresholds. First: Error Thresholds */ TooHigh = (pSen->SenValue > pSen->SenThreErrHigh); TooLow = (pSen->SenValue < pSen->SenThreErrLow); @@ -1192,11 +1204,11 @@ SK_U32 Event, /* Module specific Event */ SK_EVPARA Para) /* Event specific Parameter */ { - int ReadComplete; + int ReadComplete; SK_SENSOR *pSen; SK_U32 Time; SK_EVPARA ParaLocal; - int i; + int i; switch (Event) { case SK_I2CEV_IRQ: @@ -1224,16 +1236,16 @@ } break; case SK_I2CEV_CLEAR: - for (i=0; i < SK_MAX_SENSORS; i ++) { + for (i = 0; i < SK_MAX_SENSORS; i ++) { pAC->I2c.SenTable[i].SenErrFlag = SK_SEN_ERR_OK; pAC->I2c.SenTable[i].SenErrCts = 0; pAC->I2c.SenTable[i].SenWarnCts = 0; pAC->I2c.SenTable[i].SenBegErrTS = 0; pAC->I2c.SenTable[i].SenBegWarnTS = 0; - pAC->I2c.SenTable[i].SenLastErrTrapTS = (SK_U64) 0; - pAC->I2c.SenTable[i].SenLastErrLogTS = (SK_U64) 0; - pAC->I2c.SenTable[i].SenLastWarnTrapTS = (SK_U64) 0; - pAC->I2c.SenTable[i].SenLastWarnLogTS = (SK_U64) 0; + pAC->I2c.SenTable[i].SenLastErrTrapTS = (SK_U64)0; + pAC->I2c.SenTable[i].SenLastErrLogTS = (SK_U64)0; + pAC->I2c.SenTable[i].SenLastWarnTrapTS = (SK_U64)0; + pAC->I2c.SenTable[i].SenLastWarnLogTS = (SK_U64)0; } break; default: diff -u --recursive --new-file v2.4.6/linux/drivers/net/sk98lin/skproc.c linux/drivers/net/sk98lin/skproc.c --- v2.4.6/linux/drivers/net/sk98lin/skproc.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/sk98lin/skproc.c Wed Jul 4 11:50:39 2001 @@ -0,0 +1,435 @@ +/****************************************************************************** + * + * Name: skproc.c + * Project: GEnesis, PCI Gigabit Ethernet Adapter + * Version: $Revision: 1.2.2.2 $ + * Date: $Date: 2001/03/15 12:50:13 $ + * Purpose: Funktions to display statictic data + * + ******************************************************************************/ + +/****************************************************************************** + * + * (C)Copyright 1998-2001 SysKonnect GmbH. + * + * 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. + * + * Created 22-Nov-2000 + * Author: Mirko Lindner (mlindner@syskonnect.de) + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ +/****************************************************************************** + * + * History: + * + * $Log: skproc.c,v $ + * Revision 1.2.2.2 2001/03/15 12:50:13 mlindner + * fix: ProcFS owner protection + * + * Revision 1.2.2.1 2001/03/12 16:43:48 mlindner + * chg: 2.4 requirements for procfs + * + * Revision 1.1 2001/01/22 14:15:31 mlindner + * added ProcFs functionality + * Dual Net functionality integrated + * Rlmt networks added + * + * + ******************************************************************************/ + +#include <linux/proc_fs.h> + +#include "h/skdrv1st.h" +#include "h/skdrv2nd.h" +#define ZEROPAD 1 /* pad with zero */ +#define SIGN 2 /* unsigned/signed long */ +#define PLUS 4 /* show plus */ +#define SPACE 8 /* space if plus */ +#define LEFT 16 /* left justified */ +//#define SPECIAL 32 /* 0x */ +#define LARGE 64 + +extern void proc_fill_inode(struct inode *inode, int fill); +extern char * SkNumber(char * str, long long num, int base, int size, + int precision ,int type); +int proc_read(char *buffer, + char **buffer_location, + off_t offset, + int buffer_length, + int *eof, + void *data); + +static const char SK_Root_Dir_entry[] = "sk98lin"; +extern struct net_device *root_dev; + + +struct proc_dir_entry pSkRootDir = { + 0, + sizeof(SK_Root_Dir_entry)-1, + (const char*)SK_Root_Dir_entry, + S_IFDIR | S_IRUGO, + 2, 0, 0, 0, NULL, + NULL +}; + + +/***************************************************************************** + * + * proc_read - print "summaries" entry + * + * Description: + * This function fills the proc entry with statistic data about + * the ethernet device. + * + * + * Returns: buffer with statistic data + * + */ +int proc_read(char *buffer, +char **buffer_location, +off_t offset, +int buffer_length, +int *eof, +void *data) +{ + int len = 0; + int t; + int i; + DEV_NET *pNet; + SK_AC *pAC; + char test_buf[100]; + unsigned int Flags; + unsigned int Size; + struct net_device *next; + struct net_device *SkgeProcDev = root_dev; + + SK_PNMI_STRUCT_DATA *pPnmiStruct; + SK_PNMI_STAT *pPnmiStat; + struct proc_dir_entry *file = (struct proc_dir_entry*) data; + + while (SkgeProcDev) { + pNet = (DEV_NET*) SkgeProcDev->priv; + pAC = pNet->pAC; + next = pAC->Next; + pPnmiStruct = &pAC->PnmiStruct; + /* NetIndex in GetStruct is now required, zero is only dummy */ + + for (t=pAC->GIni.GIMacsFound; t > 0; t--) { + if ((pAC->GIni.GIMacsFound == 2) && pAC->RlmtNets == 1) + t--; + + spin_lock_irqsave(&pAC->SlowPathLock, Flags); + Size = SK_PNMI_STRUCT_SIZE; + SkPnmiGetStruct(pAC, pAC->IoBase, + pPnmiStruct, &Size, t-1); + spin_unlock_irqrestore(&pAC->SlowPathLock, Flags); + + if (strcmp(pAC->dev[t-1]->name, file->name) == 0) { + pPnmiStat = &pPnmiStruct->Stat[0]; + len = sprintf(buffer, + "\nDetailed statistic for device %s\n", + pAC->dev[t-1]->name); + len += sprintf(buffer + len, + "==================================\n"); + + /* Board statistics */ + len += sprintf(buffer + len, + "\nBoard statistics\n\n"); + len += sprintf(buffer + len, + "Active Port %c\n", + 'A' + pAC->Rlmt.Net[t-1].Port[pAC->Rlmt. + Net[t-1].PrefPort]->PortNumber); + len += sprintf(buffer + len, + "Preferred Port %c\n", + 'A' + pAC->Rlmt.Net[t-1].Port[pAC->Rlmt. + Net[t-1].PrefPort]->PortNumber); + + len += sprintf(buffer + len, + "Bus speed (Mhz) %d\n", + pPnmiStruct->BusSpeed); + + len += sprintf(buffer + len, + "Bus width (Bit) %d\n", + pPnmiStruct->BusWidth); + + for (i=0; i < SK_MAX_SENSORS; i ++) { + if (strcmp(pAC->I2c.SenTable[i].SenDesc, + "Temperature") == 0 ) { + len += sprintf(buffer + len, + "Temperature (C) %d.%d\n", + pAC->I2c.SenTable[i].SenValue / 10, + pAC->I2c.SenTable[i].SenValue % 10); + len += sprintf(buffer + len, + "Temperature (F) %d.%d\n", + ((((pAC->I2c.SenTable[i].SenValue) + *10)*9)/5 + 3200)/100, + ((((pAC->I2c.SenTable[i].SenValue) + *10)*9)/5 + 3200) % 10); + } else if (strcmp(pAC->I2c.SenTable[i].SenDesc, + "Speed Fan") == 0 ) { + len += sprintf(buffer + len, + "Speed Fan %d\n", + pAC->I2c.SenTable[i].SenValue); + } else { + len += sprintf(buffer + len, + "%-20s %d.%d\n", + pAC->I2c.SenTable[i].SenDesc, + pAC->I2c.SenTable[i].SenValue / 1000, + pAC->I2c.SenTable[i].SenValue % 1000); + } + } + + /*Receive statistics */ + + len += sprintf(buffer + len, + "\nReceive statistics\n\n"); + + len += sprintf(buffer + len, + "Received bytes %s\n", + SkNumber(test_buf, pPnmiStat->StatRxOctetsOkCts, + 10,0,-1,0)); + len += sprintf(buffer + len, + "Received packets %s\n", + SkNumber(test_buf, pPnmiStat->StatRxOkCts, + 10,0,-1,0)); + len += sprintf(buffer + len, + "Received errors %s\n", + SkNumber(test_buf, pPnmiStat->StatRxFcsCts, + 10,0,-1,0)); + len += sprintf(buffer + len, + "Received dropped %s\n", + SkNumber(test_buf, pPnmiStruct->RxNoBufCts, + 10,0,-1,0)); + len += sprintf(buffer + len, + "Received multicast %s\n", + SkNumber(test_buf, pPnmiStat->StatRxMulticastOkCts, + 10,0,-1,0)); + len += sprintf(buffer + len, + "Received errors types\n"); + len += sprintf(buffer + len, + " length errors %s\n", + SkNumber(test_buf, pPnmiStat->StatRxRuntCts, + 10, 0, -1, 0)); + len += sprintf(buffer + len, + " over errors %s\n", + SkNumber(test_buf, pPnmiStat->StatRxFifoOverflowCts, + 10, 0, -1, 0)); + len += sprintf(buffer + len, + " crc errors %s\n", + SkNumber(test_buf, pPnmiStat->StatRxFcsCts, + 10, 0, -1, 0)); + len += sprintf(buffer + len, + " frame errors %s\n", + SkNumber(test_buf, pPnmiStat->StatRxFramingCts, + 10, 0, -1, 0)); + len += sprintf(buffer + len, + " fifo errors %s\n", + SkNumber(test_buf, pPnmiStat->StatRxFifoOverflowCts, + 10, 0, -1, 0)); + len += sprintf(buffer + len, + " missed errors %s\n", + SkNumber(test_buf, pPnmiStat->StatRxMissedCts, + 10, 0, -1, 0)); + + /*Transmit statistics */ + len += sprintf(buffer + len, + "\nTransmit statistics\n\n"); + + len += sprintf(buffer + len, + "Transmit bytes %s\n", + SkNumber(test_buf, pPnmiStat->StatTxOctetsOkCts, + 10,0,-1,0)); + len += sprintf(buffer + len, + "Transmit packets %s\n", + SkNumber(test_buf, pPnmiStat->StatTxOkCts, + 10,0,-1,0)); + len += sprintf(buffer + len, + "Transmit errors %s\n", + SkNumber(test_buf, pPnmiStat->StatTxSingleCollisionCts, + 10,0,-1,0)); + len += sprintf(buffer + len, + "Transmit dropped %s\n", + SkNumber(test_buf, pPnmiStruct->TxNoBufCts, + 10,0,-1,0)); + len += sprintf(buffer + len, + "Transmit collisions %s\n", + SkNumber(test_buf, pPnmiStat->StatTxSingleCollisionCts, + 10,0,-1,0)); + len += sprintf(buffer + len, + "Transmited errors types\n"); + len += sprintf(buffer + len, + " aborted errors %ld\n", + pAC->stats.tx_aborted_errors); + len += sprintf(buffer + len, + " carrier errors %s\n", + SkNumber(test_buf, pPnmiStat->StatTxCarrierCts, + 10, 0, -1, 0)); + len += sprintf(buffer + len, + " fifo errors %s\n", + SkNumber(test_buf, pPnmiStat->StatTxFifoUnderrunCts, + 10, 0, -1, 0)); + len += sprintf(buffer + len, + " heartbeat errors %s\n", + SkNumber(test_buf, pPnmiStat->StatTxCarrierCts, + 10, 0, -1, 0)); + len += sprintf(buffer + len, + " window errors %ld\n", + pAC->stats.tx_window_errors); + } + } + SkgeProcDev = next; + } + if (offset >= len) { + *eof = 1; + return 0; + } + + *buffer_location = buffer + offset; + if (buffer_length >= len - offset) { + *eof = 1; + } + return (min(buffer_length, len - offset)); +} + + + + + +/***************************************************************************** + * + * SkDoDiv - convert 64bit number + * + * Description: + * This function "converts" a long long number. + * + * Returns: + * remainder of division + */ +static long SkDoDiv (long long Dividend, int Divisor, long long *pErg) +{ + long Rest; + long long Ergebnis; + long Akku; + + + Akku = Dividend >> 32; + + Ergebnis = ((long long) (Akku / Divisor)) << 32; + Rest = Akku % Divisor ; + + Akku = Rest << 16; + Akku |= ((Dividend & 0xFFFF0000) >> 16); + + + Ergebnis += ((long long) (Akku / Divisor)) << 16; + Rest = Akku % Divisor ; + + Akku = Rest << 16; + Akku |= (Dividend & 0xFFFF); + + Ergebnis += (Akku / Divisor); + Rest = Akku % Divisor ; + + *pErg = Ergebnis; + return (Rest); +} + + +#if 0 +#define do_div(n,base) ({ \ +long long __res; \ +__res = ((unsigned long long) n) % (unsigned) base; \ +n = ((unsigned long long) n) / (unsigned) base; \ +__res; }) + +#endif + + +/***************************************************************************** + * + * SkNumber - Print results + * + * Description: + * This function converts a long long number into a string. + * + * Returns: + * number as string + */ +char * SkNumber(char * str, long long num, int base, int size, int precision + ,int type) +{ + char c,sign,tmp[66], *strorg = str; + const char *digits="0123456789abcdefghijklmnopqrstuvwxyz"; + int i; + + if (type & LARGE) + digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + if (type & LEFT) + type &= ~ZEROPAD; + if (base < 2 || base > 36) + return 0; + c = (type & ZEROPAD) ? '0' : ' '; + sign = 0; + if (type & SIGN) { + if (num < 0) { + sign = '-'; + num = -num; + size--; + } else if (type & PLUS) { + sign = '+'; + size--; + } else if (type & SPACE) { + sign = ' '; + size--; + } + } + if (type & SPECIAL) { + if (base == 16) + size -= 2; + else if (base == 8) + size--; + } + i = 0; + if (num == 0) + tmp[i++]='0'; + else while (num != 0) + tmp[i++] = digits[SkDoDiv(num,base, &num)]; + + if (i > precision) + precision = i; + size -= precision; + if (!(type&(ZEROPAD+LEFT))) + while(size-->0) + *str++ = ' '; + if (sign) + *str++ = sign; + if (type & SPECIAL) { + if (base==8) + *str++ = '0'; + else if (base==16) { + *str++ = '0'; + *str++ = digits[33]; + } + } + if (!(type & LEFT)) + while (size-- > 0) + *str++ = c; + while (i < precision--) + *str++ = '0'; + while (i-- > 0) + *str++ = tmp[i]; + while (size-- > 0) + *str++ = ' '; + + str[0] = '\0'; + + return strorg; +} + + + diff -u --recursive --new-file v2.4.6/linux/drivers/net/sk98lin/skqueue.c linux/drivers/net/sk98lin/skqueue.c --- v2.4.6/linux/drivers/net/sk98lin/skqueue.c Tue Mar 20 12:04:59 2001 +++ linux/drivers/net/sk98lin/skqueue.c Wed Jul 4 11:50:39 2001 @@ -1,23 +1,32 @@ /****************************************************************************** * * Name: skqueue.c - * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.15 $ - * Date: $Date: 1999/11/22 13:36:29 $ + * Project: PCI Gigabit Ethernet Adapter + * Version: $Revision: 1.14 $ + * Date: $Date: 1998/10/15 15:11:35 $ * Purpose: Management of an event queue. * ******************************************************************************/ /****************************************************************************** * - * (C)Copyright 1998,1999 SysKonnect, + * (C)Copyright 1989-1998 SysKonnect, * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * All Rights Reserved * - * 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 IS UNPUBLISHED PROPRIETARY SOURCE CODE OF SYSKONNECT + * The copyright notice above does not evidence any + * actual or intended publication of such source code. + * + * This Module contains Proprietary Information of SysKonnect + * and should be treated as Confidential. + * + * The information in this file is provided for the exclusive use of + * the licensees of SysKonnect. + * Such users have the right to use, modify, and incorporate this code + * into products for purposes authorized by the license agreement + * provided they include this notice and the associated copyright notice + * with any such product. * The information in this file is provided "AS IS" without warranty. * ******************************************************************************/ @@ -27,9 +36,6 @@ * History: * * $Log: skqueue.c,v $ - * Revision 1.15 1999/11/22 13:36:29 cgoos - * Changed license header to GPL. - * * Revision 1.14 1998/10/15 15:11:35 gklug * fix: ID_sccs to SysKonnectFileId * @@ -82,7 +88,7 @@ Event queue and dispatcher */ static const char SysKonnectFileId[] = - "$Header: /usr56/projects/ge/schedule/skqueue.c,v 1.15 1999/11/22 13:36:29 cgoos Exp $" ; + "$Header: /usr56/projects/ge/schedule/skqueue.c,v 1.14 1998/10/15 15:11:35 gklug Exp $" ; #include "h/skdrv1st.h" /* Driver Specific Definitions */ #include "h/skqueue.h" /* Queue Definitions */ @@ -147,7 +153,7 @@ * send command to state machine * end * return error reported by individual Event function - * 0 if no error occurred. + * 0 if no error occured. */ int SkEventDispatcher( SK_AC *pAC, /* Adapters Context */ diff -u --recursive --new-file v2.4.6/linux/drivers/net/sk98lin/skrlmt.c linux/drivers/net/sk98lin/skrlmt.c --- v2.4.6/linux/drivers/net/sk98lin/skrlmt.c Fri Sep 15 14:34:19 2000 +++ linux/drivers/net/sk98lin/skrlmt.c Wed Jul 4 11:50:39 2001 @@ -2,16 +2,15 @@ * * Name: skrlmt.c * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.49 $ - * Date: $Date: 1999/11/22 13:38:02 $ + * Version: $Revision: 1.61 $ + * Date: $Date: 2001/03/14 12:52:08 $ * Purpose: Manage links on SK-NET Adapters, esp. redundant ones. * ******************************************************************************/ /****************************************************************************** * - * (C)Copyright 1998,1999 SysKonnect, - * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * (C)Copyright 1998-2001 SysKonnect GmbH. * * 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 @@ -27,15 +26,53 @@ * History: * * $Log: skrlmt.c,v $ + * Revision 1.61 2001/03/14 12:52:08 rassmann + * Fixed reporting of active port up/down to PNMI. + * + * Revision 1.60 2001/02/21 16:02:25 gklug + * fix: when RLMT starts set Active Port for PNMI + * + * Revision 1.59 2001/02/16 14:38:19 rassmann + * Initializing some pointers earlier in the init phase. + * Rx Mbufs are freed if the net which they belong to is stopped. + * + * Revision 1.58 2001/02/14 14:06:31 rassmann + * Editorial changes. + * + * Revision 1.57 2001/02/05 14:25:26 rassmann + * Prepared RLMT for transparent operation. + * + * Revision 1.56 2001/01/30 10:29:09 rassmann + * Not checking switching befor RlmtStart. + * Editorial changes. + * + * Revision 1.55 2001/01/22 13:41:38 rassmann + * Supporting two nets on dual-port adapters. + * + * Revision 1.54 2000/11/30 13:25:07 rassmann + * Setting SK_TICK_INCR to 1 by default. + * + * Revision 1.53 2000/11/30 10:48:07 cgoos + * Changed definition of SK_RLMT_BC_DELTA. + * + * Revision 1.52 2000/11/27 12:50:03 rassmann + * Checking ports after receiving broadcasts. + * + * Revision 1.51 2000/11/17 08:58:00 rassmann + * Moved CheckSwitch from SK_RLMT_PACKET_RECEIVED to SK_RLMT_TIM event. + * + * Revision 1.50 2000/11/09 12:24:34 rassmann + * Indicating that segmentation check is not running anymore after + * SkRlmtCheckSeg(). + * Restarting segmentation timer after segmentation log. + * Editorial changes. + * * Revision 1.49 1999/11/22 13:38:02 cgoos * Changed license header to GPL. * Added initialization to some variables to avoid compiler warnings. * * Revision 1.48 1999/10/04 14:01:17 rassmann - * Corrected reaction to reception of BPDU frames. - * Added parameter descriptions to "For Readme" section skrlmt.txt. - * Clarified usage of lookahead result *pForRlmt. - * Requested driver to present RLMT packets as soon as poosible. + * Corrected reaction to reception of BPDU frames (#10441). * * Revision 1.47 1999/07/20 12:53:36 rassmann * Fixed documentation errors for lookahead macros. @@ -66,7 +103,7 @@ * * Revision 1.40 1999/01/22 13:17:30 rassmann * Informing PNMI of NET_UP. - * Clearing RLMT multicast addresses before first setting them. + * Clearing RLMT multicast addresses before setting them for the first time. * Reporting segmentation earlier, setting a "quiet time" * after a report. * @@ -218,13 +255,13 @@ #ifndef lint static const char SysKonnectFileId[] = - "@(#) $Id: skrlmt.c,v 1.49 1999/11/22 13:38:02 cgoos Exp $ (C) SysKonnect."; + "@(#) $Id: skrlmt.c,v 1.61 2001/03/14 12:52:08 rassmann Exp $ (C) SysKonnect."; #endif /* !defined(lint) */ #define __SKRLMT_C #ifdef __cplusplus -xxxx /* not supported yet - force error */ +#error C++ is not yet supported. extern "C" { #endif /* cplusplus */ @@ -245,11 +282,13 @@ #ifndef SK_LITTLE_ENDIAN /* First 32 bits */ #define OFFS_LO32 1 + /* Second 32 bits */ #define OFFS_HI32 0 #else /* SK_LITTLE_ENDIAN */ /* First 32 bits */ #define OFFS_LO32 0 + /* Second 32 bits */ #define OFFS_HI32 1 #endif /* SK_LITTLE_ENDIAN */ @@ -258,58 +297,60 @@ /* ----- Private timeout values ----- */ -#define SK_RLMT_MIN_TO_VAL 125000 /* 1/8 sec. */ -#define SK_RLMT_DEF_TO_VAL 1000000 /* 1 sec. */ +#define SK_RLMT_MIN_TO_VAL 125000 /* 1/8 sec. */ +#define SK_RLMT_DEF_TO_VAL 1000000 /* 1 sec. */ #define SK_RLMT_PORTDOWN_TIM_VAL 900000 /* another 0.9 sec. */ #define SK_RLMT_PORTSTART_TIM_VAL 100000 /* 0.1 sec. */ #define SK_RLMT_PORTUP_TIM_VAL 2500000 /* 2.5 sec. */ -#define SK_RLMT_SEG_TO_VAL 900000000 /* 15 min. */ +#define SK_RLMT_SEG_TO_VAL 900000000 /* 15 min. */ + +/* Assume tick counter increment is 1 - may be set OS-dependent. */ +#ifndef SK_TICK_INCR +#define SK_TICK_INCR SK_CONSTU64(1) +#endif /* !defined(SK_TICK_INCR) */ /* * Amount that a time stamp must be later to be recognized as "substantially - * later". This is about 1/128 sec. + * later". This is about 1/128 sec, but above 1 tick counter increment. */ - -#define SK_RLMT_BC_DELTA ((SK_TICKS_PER_SEC >> 7) + 1) +#define SK_RLMT_BC_DELTA (1 + ((SK_TICKS_PER_SEC >> 7) > SK_TICK_INCR ? \ + (SK_TICKS_PER_SEC >> 7) : SK_TICK_INCR)) /* ----- Private RLMT defaults ----- */ -#define SK_RLMT_DEF_PREF_PORT 0 /* "Lower" port. */ -#define SK_RLMT_DEF_MODE SK_RLMT_CHECK_LINK /* Default RLMT Mode. */ +#define SK_RLMT_DEF_PREF_PORT 0 /* "Lower" port. */ +#define SK_RLMT_DEF_MODE SK_RLMT_CHECK_LINK /* Default RLMT Mode. */ /* ----- Private RLMT checking states ----- */ -#define SK_RLMT_RCS_SEG 1 /* RLMT Check State: check seg. */ -#define SK_RLMT_RCS_START_SEG 2 /* RLMT Check State: start check seg. */ -#define SK_RLMT_RCS_SEND_SEG 4 /* RLMT Check State: send BPDU packet */ -#define SK_RLMT_RCS_REPORT_SEG 8 /* RLMT Check State: report seg. */ +#define SK_RLMT_RCS_SEG 1 /* RLMT Check State: check seg. */ +#define SK_RLMT_RCS_START_SEG 2 /* RLMT Check State: start check seg. */ +#define SK_RLMT_RCS_SEND_SEG 4 /* RLMT Check State: send BPDU packet */ +#define SK_RLMT_RCS_REPORT_SEG 8 /* RLMT Check State: report seg. */ /* ----- Private PORT checking states ----- */ -#define SK_RLMT_PCS_TX 1 /* Port Check State: check tx. */ -#define SK_RLMT_PCS_RX 2 /* Port Check State: check rx. */ +#define SK_RLMT_PCS_TX 1 /* Port Check State: check tx. */ +#define SK_RLMT_PCS_RX 2 /* Port Check State: check rx. */ /* ----- Private PORT events ----- */ /* Note: Update simulation when changing these. */ - #define SK_RLMT_PORTSTART_TIM 1100 /* Port start timeout. */ -#define SK_RLMT_PORTUP_TIM 1101 /* Port can now go up. */ +#define SK_RLMT_PORTUP_TIM 1101 /* Port can now go up. */ #define SK_RLMT_PORTDOWN_RX_TIM 1102 /* Port did not receive once ... */ -#define SK_RLMT_PORTDOWN 1103 /* Port went down. */ +#define SK_RLMT_PORTDOWN 1103 /* Port went down. */ #define SK_RLMT_PORTDOWN_TX_TIM 1104 /* Partner did not receive ... */ /* ----- Private RLMT events ----- */ /* Note: Update simulation when changing these. */ - -#define SK_RLMT_TIM 2100 /* RLMT timeout. */ -#define SK_RLMT_SEG_TIM 2101 /* RLMT segmentation check timeout. */ +#define SK_RLMT_TIM 2100 /* RLMT timeout. */ +#define SK_RLMT_SEG_TIM 2101 /* RLMT segmentation check timeout. */ #define TO_SHORTEN(tim) ((tim) / 2) /* Error numbers and messages. */ - #define SKERR_RLMT_E001 (SK_ERRBASE_RLMT + 0) #define SKERR_RLMT_E001_MSG "No Packet." #define SKERR_RLMT_E002 (SKERR_RLMT_E001 + 1) @@ -333,78 +374,70 @@ #define SKERR_RLMT_E010_MSG "Ignored illegal Preferred Port." /* LLC field values. */ - -#define LLC_COMMAND_RESPONSE_BIT 1 -#define LLC_TEST_COMMAND 0xE3 -#define LLC_UI 0x03 +#define LLC_COMMAND_RESPONSE_BIT 1 +#define LLC_TEST_COMMAND 0xE3 +#define LLC_UI 0x03 /* RLMT Packet fields. */ - -#define SK_RLMT_DSAP 0 -#define SK_RLMT_SSAP 0 -#define SK_RLMT_CTRL (LLC_TEST_COMMAND) -#define SK_RLMT_INDICATOR0 0x53 /* S */ -#define SK_RLMT_INDICATOR1 0x4B /* K */ -#define SK_RLMT_INDICATOR2 0x2D /* - */ -#define SK_RLMT_INDICATOR3 0x52 /* R */ -#define SK_RLMT_INDICATOR4 0x4C /* L */ -#define SK_RLMT_INDICATOR5 0x4D /* M */ -#define SK_RLMT_INDICATOR6 0x54 /* T */ -#define SK_RLMT_PACKET_VERSION 0 +#define SK_RLMT_DSAP 0 +#define SK_RLMT_SSAP 0 +#define SK_RLMT_CTRL (LLC_TEST_COMMAND) +#define SK_RLMT_INDICATOR0 0x53 /* S */ +#define SK_RLMT_INDICATOR1 0x4B /* K */ +#define SK_RLMT_INDICATOR2 0x2D /* - */ +#define SK_RLMT_INDICATOR3 0x52 /* R */ +#define SK_RLMT_INDICATOR4 0x4C /* L */ +#define SK_RLMT_INDICATOR5 0x4D /* M */ +#define SK_RLMT_INDICATOR6 0x54 /* T */ +#define SK_RLMT_PACKET_VERSION 0 /* RLMT SPT Flag values. */ - -#define SK_RLMT_SPT_FLAG_CHANGE 0x01 -#define SK_RLMT_SPT_FLAG_CHANGE_ACK 0x80 +#define SK_RLMT_SPT_FLAG_CHANGE 0x01 +#define SK_RLMT_SPT_FLAG_CHANGE_ACK 0x80 /* RLMT SPT Packet fields. */ - -#define SK_RLMT_SPT_DSAP 0x42 -#define SK_RLMT_SPT_SSAP 0x42 -#define SK_RLMT_SPT_CTRL (LLC_UI) -#define SK_RLMT_SPT_PROTOCOL_ID0 0x00 -#define SK_RLMT_SPT_PROTOCOL_ID1 0x00 +#define SK_RLMT_SPT_DSAP 0x42 +#define SK_RLMT_SPT_SSAP 0x42 +#define SK_RLMT_SPT_CTRL (LLC_UI) +#define SK_RLMT_SPT_PROTOCOL_ID0 0x00 +#define SK_RLMT_SPT_PROTOCOL_ID1 0x00 #define SK_RLMT_SPT_PROTOCOL_VERSION_ID 0x00 -#define SK_RLMT_SPT_BPDU_TYPE 0x00 -#define SK_RLMT_SPT_FLAGS 0x00 /* ?? */ -#define SK_RLMT_SPT_ROOT_ID0 0xFF /* Lowest possible priority. */ -#define SK_RLMT_SPT_ROOT_ID1 0xFF /* Lowest possible priority. */ +#define SK_RLMT_SPT_BPDU_TYPE 0x00 +#define SK_RLMT_SPT_FLAGS 0x00 /* ?? */ +#define SK_RLMT_SPT_ROOT_ID0 0xFF /* Lowest possible priority. */ +#define SK_RLMT_SPT_ROOT_ID1 0xFF /* Lowest possible priority. */ /* Remaining 6 bytes will be the current port address. */ - -#define SK_RLMT_SPT_ROOT_PATH_COST0 0x00 -#define SK_RLMT_SPT_ROOT_PATH_COST1 0x00 -#define SK_RLMT_SPT_ROOT_PATH_COST2 0x00 -#define SK_RLMT_SPT_ROOT_PATH_COST3 0x00 -#define SK_RLMT_SPT_BRIDGE_ID0 0xFF /* Lowest possible priority. */ -#define SK_RLMT_SPT_BRIDGE_ID1 0xFF /* Lowest possible priority. */ +#define SK_RLMT_SPT_ROOT_PATH_COST0 0x00 +#define SK_RLMT_SPT_ROOT_PATH_COST1 0x00 +#define SK_RLMT_SPT_ROOT_PATH_COST2 0x00 +#define SK_RLMT_SPT_ROOT_PATH_COST3 0x00 +#define SK_RLMT_SPT_BRIDGE_ID0 0xFF /* Lowest possible priority. */ +#define SK_RLMT_SPT_BRIDGE_ID1 0xFF /* Lowest possible priority. */ /* Remaining 6 bytes will be the current port address. */ - -#define SK_RLMT_SPT_PORT_ID0 0xFF /* Lowest possible priority. */ -#define SK_RLMT_SPT_PORT_ID1 0xFF /* Lowest possible priority. */ -#define SK_RLMT_SPT_MSG_AGE0 0x00 -#define SK_RLMT_SPT_MSG_AGE1 0x00 -#define SK_RLMT_SPT_MAX_AGE0 0x00 -#define SK_RLMT_SPT_MAX_AGE1 0xFF -#define SK_RLMT_SPT_HELLO_TIME0 0x00 -#define SK_RLMT_SPT_HELLO_TIME1 0xFF -#define SK_RLMT_SPT_FWD_DELAY0 0x00 -#define SK_RLMT_SPT_FWD_DELAY1 0x40 +#define SK_RLMT_SPT_PORT_ID0 0xFF /* Lowest possible priority. */ +#define SK_RLMT_SPT_PORT_ID1 0xFF /* Lowest possible priority. */ +#define SK_RLMT_SPT_MSG_AGE0 0x00 +#define SK_RLMT_SPT_MSG_AGE1 0x00 +#define SK_RLMT_SPT_MAX_AGE0 0x00 +#define SK_RLMT_SPT_MAX_AGE1 0xFF +#define SK_RLMT_SPT_HELLO_TIME0 0x00 +#define SK_RLMT_SPT_HELLO_TIME1 0xFF +#define SK_RLMT_SPT_FWD_DELAY0 0x00 +#define SK_RLMT_SPT_FWD_DELAY1 0x40 /* Size defines. */ - -#define SK_RLMT_MIN_PACKET_SIZE 34 -#define SK_RLMT_MAX_PACKET_SIZE (SK_RLMT_MAX_TX_BUF_SIZE) -#define SK_PACKET_DATA_LEN (SK_RLMT_MAX_PACKET_SIZE - \ - SK_RLMT_MIN_PACKET_SIZE) +#define SK_RLMT_MIN_PACKET_SIZE 34 +#define SK_RLMT_MAX_PACKET_SIZE (SK_RLMT_MAX_TX_BUF_SIZE) +#define SK_PACKET_DATA_LEN (SK_RLMT_MAX_PACKET_SIZE - \ + SK_RLMT_MIN_PACKET_SIZE) /* ----- RLMT packet types ----- */ - -#define SK_PACKET_ANNOUNCE 1 /* Port announcement. */ -#define SK_PACKET_ALIVE 2 /* Alive packet to port. */ -#define SK_PACKET_ADDR_CHANGED 3 /* Port address changed. */ -#define SK_PACKET_CHECK_TX 4 /* Check your tx line. */ +#define SK_PACKET_ANNOUNCE 1 /* Port announcement. */ +#define SK_PACKET_ALIVE 2 /* Alive packet to port. */ +#define SK_PACKET_ADDR_CHANGED 3 /* Port address changed. */ +#define SK_PACKET_CHECK_TX 4 /* Check your tx line. */ #ifdef SK_LITTLE_ENDIAN #define SK_U16_TO_NETWORK_ORDER(Val,Addr) { \ @@ -426,7 +459,6 @@ /* typedefs *******************************************************************/ /* RLMT packet. Length: SK_RLMT_MAX_PACKET_SIZE (60) bytes. */ - typedef struct s_RlmtPacket { SK_U8 DstAddr[SK_MAC_ADDR_LEN]; SK_U8 SrcAddr[SK_MAC_ADDR_LEN]; @@ -437,8 +469,8 @@ SK_U8 Indicator[7]; SK_U8 RlmtPacketType[2]; SK_U8 Align1[2]; - SK_U8 Random[4]; /* Random value of requesting(!) station. */ - SK_U8 RlmtPacketVersion[2]; /* RLMT Packet version */ + SK_U8 Random[4]; /* Random value of requesting(!) station. */ + SK_U8 RlmtPacketVersion[2]; /* RLMT Packet version. */ SK_U8 Data[SK_PACKET_DATA_LEN]; } SK_RLMT_PACKET; @@ -465,9 +497,9 @@ /* global variables ***********************************************************/ -SK_MAC_ADDR SkRlmtMcAddr = {{0x01, 0x00, 0x5A, 0x52, 0x4C, 0x4D}}; -SK_MAC_ADDR BridgeMcAddr = {{0x01, 0x80, 0xC2, 0x00, 0x00, 0x00}}; -SK_MAC_ADDR BcAddr = {{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}}; +SK_MAC_ADDR SkRlmtMcAddr = {{0x01, 0x00, 0x5A, 0x52, 0x4C, 0x4D}}; +SK_MAC_ADDR BridgeMcAddr = {{0x01, 0x80, 0xC2, 0x00, 0x00, 0x00}}; +SK_MAC_ADDR BcAddr = {{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}}; /* local variables ************************************************************/ @@ -477,10 +509,16 @@ RLMT_STATIC void SkRlmtCheckSwitch( SK_AC *pAC, - SK_IOC IoC); + SK_IOC IoC, + SK_U32 NetIdx); RLMT_STATIC void SkRlmtCheckSeg( SK_AC *pAC, - SK_IOC IoC); + SK_IOC IoC, + SK_U32 NetIdx); +RLMT_STATIC void SkRlmtEvtSetNets( + SK_AC *pAC, + SK_IOC IoC, + SK_EVPARA Para); /****************************************************************************** * @@ -506,7 +544,7 @@ * =========== * * Determine the adapter's random value. - * Set the hw registers, the "logical adapter address", the + * Set the hw registers, the "logical MAC address", the * RLMT multicast address, and eventually the BPDU multicast address. * * Context: @@ -516,18 +554,15 @@ * Nothing. */ void SkRlmtInit( -SK_AC *pAC, /* adapter context */ -SK_IOC IoC, /* I/O context */ -int Level) /* initialization level */ +SK_AC *pAC, /* Adapter Context */ +SK_IOC IoC, /* I/O Context */ +int Level) /* Initialization Level */ { SK_U32 i, j; SK_U64 Random; SK_EVPARA Para; - SK_DBG_MSG( - pAC, - SK_DBGMOD_RLMT, - SK_DBGCAT_INIT, + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_INIT, ("RLMT Init level %d.\n", Level)) switch (Level) { @@ -541,68 +576,70 @@ pAC->Rlmt.Port[i].PortStarted = SK_FALSE; pAC->Rlmt.Port[i].PortNoRx = SK_FALSE; pAC->Rlmt.Port[i].RootIdSet = SK_FALSE; - } - - pAC->Rlmt.RlmtState = SK_RLMT_RS_INIT; - pAC->Rlmt.RootIdSet = SK_FALSE; - pAC->Rlmt.MacPreferred = 0xFFFFFFFF; /* Automatic. */ - pAC->Rlmt.PrefPort = SK_RLMT_DEF_PREF_PORT; - pAC->Rlmt.MacActive = pAC->Rlmt.PrefPort; /* Just assuming. */ - pAC->Rlmt.RlmtMode = SK_RLMT_DEF_MODE; - pAC->Rlmt.TimeoutValue = SK_RLMT_DEF_TO_VAL; + pAC->Rlmt.Port[i].PortNumber = i; + pAC->Rlmt.Port[i].Net = &pAC->Rlmt.Net[0]; + pAC->Rlmt.Port[i].AddrPort = &pAC->Addr.Port[i]; + } + + pAC->Rlmt.NumNets = 1; + for (i = 0; i < SK_MAX_NETS; i++) { + pAC->Rlmt.Net[i].RlmtState = SK_RLMT_RS_INIT; + pAC->Rlmt.Net[i].RootIdSet = SK_FALSE; + pAC->Rlmt.Net[i].Preference = 0xFFFFFFFF; /* Automatic. */ + pAC->Rlmt.Net[i].PrefPort = SK_RLMT_DEF_PREF_PORT; + /* Just assuming. */ + pAC->Rlmt.Net[i].ActivePort = pAC->Rlmt.Net[i].PrefPort; + pAC->Rlmt.Net[i].RlmtMode = SK_RLMT_DEF_MODE; + pAC->Rlmt.Net[i].TimeoutValue = SK_RLMT_DEF_TO_VAL; + pAC->Rlmt.Net[i].NetNumber = i; + } + + pAC->Rlmt.Net[0].Port[0] = &pAC->Rlmt.Port[0]; + pAC->Rlmt.Net[0].Port[1] = &pAC->Rlmt.Port[1]; +#if SK_MAX_NETS > 1 + pAC->Rlmt.Net[1].Port[0] = &pAC->Rlmt.Port[1]; +#endif /* SK_MAX_NETS > 1 */ break; case SK_INIT_IO: /* GIMacsFound first available here. */ - SK_DBG_MSG( - pAC, - SK_DBGMOD_RLMT, - SK_DBGCAT_INIT, - ("RLMT: %d MACs were detected.\n", - pAC->GIni.GIMacsFound)) + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_INIT, + ("RLMT: %d MACs were detected.\n", pAC->GIni.GIMacsFound)) - /* Initialize HW registers? */ + pAC->Rlmt.Net[0].NumPorts = pAC->GIni.GIMacsFound; + /* Initialize HW registers? */ if (pAC->GIni.GIMacsFound < 2) { - Para.Para32[0] = SK_RLMT_CHECK_LINK; + Para.Para32[0] = SK_RLMT_MODE_CLS; + Para.Para32[1] = 0; (void)SkRlmtEvent(pAC, IoC, SK_RLMT_MODE_CHANGE, Para); } break; case SK_INIT_RUN: + /* Ensure RLMT is set to one net. */ + if (pAC->Rlmt.NumNets > 1) { + Para.Para32[0] = 1; + Para.Para32[1] = -1; + SkRlmtEvtSetNets(pAC, IoC, Para); + } + for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) { Random = SkOsGetTime(pAC); *(SK_U32*)&pAC->Rlmt.Port[i].Random = *(SK_U32*)&Random; for (j = 0; j < 4; j++) { - pAC->Rlmt.Port[i].Random[j] ^= pAC->Addr.Port[i - ].CurrentMacAddress.a[SK_MAC_ADDR_LEN - - 1 - j]; + pAC->Rlmt.Port[i].Random[j] ^= pAC->Rlmt.Port[i].AddrPort-> + CurrentMacAddress.a[SK_MAC_ADDR_LEN - 1 - j]; } - (void)SkAddrMcClear( - pAC, - IoC, - i, - SK_ADDR_PERMANENT | SK_MC_SW_ONLY); + (void)SkAddrMcClear(pAC, IoC, i, SK_ADDR_PERMANENT | SK_MC_SW_ONLY); /* Add RLMT MC address. */ + (void)SkAddrMcAdd(pAC, IoC, i, &SkRlmtMcAddr, SK_ADDR_PERMANENT); - (void)SkAddrMcAdd( - pAC, - IoC, - i, - &SkRlmtMcAddr, - SK_ADDR_PERMANENT); - - if (pAC->Rlmt.RlmtMode & SK_RLMT_CHECK_SEG) { + if (pAC->Rlmt.Net[0].RlmtMode & SK_RLMT_CHECK_SEG) { /* Add BPDU MC address. */ - - (void)SkAddrMcAdd( - pAC, - IoC, - i, - &BridgeMcAddr, - SK_ADDR_PERMANENT); + (void)SkAddrMcAdd(pAC, IoC, i, &BridgeMcAddr, SK_ADDR_PERMANENT); } (void)SkAddrMcUpdate(pAC, IoC, i); @@ -612,9 +649,7 @@ default: /* error */ break; } - return; - } /* SkRlmtInit */ @@ -639,32 +674,33 @@ * Nothing */ RLMT_STATIC void SkRlmtBuildCheckChain( -SK_AC *pAC) /* adapter context */ +SK_AC *pAC, /* Adapter Context */ +SK_U32 NetIdx) /* Net Number */ { - SK_U32 i; - SK_U32 NumMacsUp; - SK_U32 FirstMacUp=0; - SK_U32 PrevMacUp=0; + SK_U32 i; + SK_U32 NumMacsUp; + SK_RLMT_PORT * FirstMacUp; + SK_RLMT_PORT * PrevMacUp; - if (!(pAC->Rlmt.RlmtMode & SK_RLMT_CHECK_LOC_LINK)) { - for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) { - pAC->Rlmt.Port[i].PortsChecked = 0; + FirstMacUp = NULL; + PrevMacUp = NULL; + + if (!(pAC->Rlmt.Net[NetIdx].RlmtMode & SK_RLMT_CHECK_LOC_LINK)) { + for (i = 0; i < pAC->Rlmt.Net[i].NumPorts; i++) { + pAC->Rlmt.Net[NetIdx].Port[i]->PortsChecked = 0; } - return; /* Nothing to build. */ + return; /* Done. */ } - - SK_DBG_MSG( - pAC, - SK_DBGMOD_RLMT, - SK_DBGCAT_CTRL, + + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, ("SkRlmtBuildCheckChain.\n")) NumMacsUp = 0; - for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) { - pAC->Rlmt.Port[i].PortsChecked = 0; - pAC->Rlmt.Port[i].PortsSuspect = 0; - pAC->Rlmt.Port[i].CheckingState &= + for (i = 0; i < pAC->Rlmt.Net[NetIdx].NumPorts; i++) { + pAC->Rlmt.Net[NetIdx].Port[i]->PortsChecked = 0; + pAC->Rlmt.Net[NetIdx].Port[i]->PortsSuspect = 0; + pAC->Rlmt.Net[NetIdx].Port[i]->CheckingState &= ~(SK_RLMT_PCS_RX | SK_RLMT_PCS_TX); /* @@ -673,156 +709,43 @@ * 1. the next port that is not LinkDown and * 2. the next port that is not PortDown. */ - - if (!pAC->Rlmt.Port[i].LinkDown) { + if (!pAC->Rlmt.Net[NetIdx].Port[i]->LinkDown) { if (NumMacsUp == 0) { - FirstMacUp = i; + FirstMacUp = pAC->Rlmt.Net[NetIdx].Port[i]; } else { - pAC->Rlmt.Port[PrevMacUp].PortCheck[ - pAC->Rlmt.Port[ - PrevMacUp].PortsChecked].CheckAddr = - pAC->Addr.Port[i].CurrentMacAddress; - pAC->Rlmt.Port[PrevMacUp].PortCheck[ - pAC->Rlmt.Port[ - PrevMacUp].PortsChecked].SuspectTx = - SK_FALSE; - pAC->Rlmt.Port[PrevMacUp].PortsChecked++; + pAC->Rlmt.Net[NetIdx].Port[i]->PortCheck[ + pAC->Rlmt.Net[NetIdx].Port[i]->PortsChecked].CheckAddr = + pAC->Rlmt.Net[NetIdx].Port[i]->AddrPort->CurrentMacAddress; + PrevMacUp->PortCheck[ + PrevMacUp->PortsChecked].SuspectTx = SK_FALSE; + PrevMacUp->PortsChecked++; } - PrevMacUp = i; + PrevMacUp = pAC->Rlmt.Net[NetIdx].Port[i]; NumMacsUp++; } } if (NumMacsUp > 1) { - pAC->Rlmt.Port[PrevMacUp].PortCheck[pAC->Rlmt.Port[ - PrevMacUp].PortsChecked].CheckAddr = - pAC->Addr.Port[FirstMacUp].CurrentMacAddress; - pAC->Rlmt.Port[PrevMacUp].PortCheck[pAC->Rlmt.Port[ - PrevMacUp].PortsChecked].SuspectTx = SK_FALSE; - pAC->Rlmt.Port[PrevMacUp].PortsChecked++; + PrevMacUp->PortCheck[PrevMacUp->PortsChecked].CheckAddr = + FirstMacUp->AddrPort->CurrentMacAddress; + PrevMacUp->PortCheck[PrevMacUp->PortsChecked].SuspectTx = + SK_FALSE; + PrevMacUp->PortsChecked++; } #ifdef DEBUG - for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) { - SK_DBG_MSG( - pAC, - SK_DBGMOD_RLMT, - SK_DBGCAT_CTRL, - ("Port %d checks %d other ports: %2X.\n", - i, - pAC->Rlmt.Port[i].PortsChecked, - pAC->Rlmt.Port[i].PortCheck[0].CheckAddr.a[5])) + for (i = 0; i < pAC->Rlmt.Net[NetIdx].NumPorts; i++) { + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("Port %d checks %d other ports: %2X.\n", NetIdx, + pAC->Rlmt.Net[NetIdx].Port[i]->PortsChecked, + pAC->Rlmt.Net[NetIdx].Port[i]->PortCheck[0].CheckAddr.a[5])) } #endif /* DEBUG */ return; } /* SkRlmtBuildCheckChain */ -#ifdef SK_RLMT_SLOW_LOOKAHEAD - -/****************************************************************************** - * - * SkRlmtLookaheadPacket - examine received packet shortly, count s-th - * - * Description: - * This routine examines each received packet fast and short and - * increments some counters. - * The received packet has to be stored virtually contiguous. - * This function does the following: - * - Increment some counters. - * - Ensure length is sufficient. - * - Ensure that destination address is physical port address, - * RLMT multicast, or BPDU multicast address. - * - * Notes: - * This function is fully reentrant while the fast path is not blocked. - * - * Context: - * isr/dpr, not pageable - * - * Returns: - * SK_FALSE packet for upper layers - * SK_TRUE packet for RLMT - */ -SK_BOOL SkRlmtLookaheadPacket( -SK_AC *pAC, /* adapter context */ -SK_U32 PortIdx, /* receiving port */ -SK_U8 *pLaPacket, /* received packet's data */ -unsigned PacketLength, /* received packet's length */ /* Necessary? */ -unsigned LaLength) /* lookahead length */ -{ - int i; - SK_BOOL IsBc; /* Broadcast address? */ - int RxDest; /* Receive destination? */ - int Offset; /* Offset of data to present to LOOKAHEAD. */ - int NumBytes; /* #Bytes to present to LOOKAHEAD. */ - SK_RLMT_PACKET *pRPacket; - SK_ADDR_PORT *pAPort; - -#ifdef DEBUG - PacketLength = PacketLength; -#endif /* DEBUG */ - - pRPacket = (SK_RLMT_PACKET*)pLaPacket; - pAPort = &pAC->Addr.Port[PortIdx]; - -#ifdef DEBUG - if (pLaPacket == NULL) { - - /* Create error log entry. */ - - SK_ERR_LOG( - pAC, - SK_ERRCL_SW, - SKERR_RLMT_E001, - SKERR_RLMT_E001_MSG); - - SK_DBG_MSG( - pAC, - SK_DBGMOD_RLMT, - SK_DBGCAT_RX, - ("SkRlmtLookaheadPacket: NULL pointer.\n")) - - return (SK_FALSE); - } -#endif /* DEBUG */ - - /* Drivers should get IsBc from the descriptor. */ - - IsBc = SK_TRUE; - for (i = 0; IsBc && i < SK_MAC_ADDR_LEN; i++) { - IsBc = IsBc && (pLaPacket[i] == 0xFF); - } - - SK_RLMT_PRE_LOOKAHEAD( - pAC, - PortIdx, - PacketLength, - IsBc, - &Offset, - &NumBytes) - - if (NumBytes == 0) { - return (SK_FALSE); - } - - SK_RLMT_LOOKAHEAD( - pAC, - PortIdx, - &pLaPacket[Offset], - IsBc, - pLaPacket[0] & 1, /* Drivers: Get info from descriptor. */ - &RxDest) - - if (RxDest & SK_RLMT_RX_RLMT) { - return (SK_TRUE); - } - - return (SK_FALSE); -} /* SkRlmtLookaheadPacket */ - -#endif /* SK_RLMT_SLOW_LOOKAHEAD */ /****************************************************************************** * @@ -838,20 +761,19 @@ * NULL or pointer to RLMT mbuf */ RLMT_STATIC SK_MBUF *SkRlmtBuildPacket( -SK_AC *pAC, /* adapter context */ -SK_IOC IoC, /* I/O context */ -SK_U32 PortIdx, /* sending port */ +SK_AC *pAC, /* Adapter Context */ +SK_IOC IoC, /* I/O Context */ +SK_U32 PortNumber, /* Sending port */ SK_U16 PacketType, /* RLMT packet type */ -SK_MAC_ADDR *SrcAddr, /* source address */ -SK_MAC_ADDR *DestAddr) /* destination address */ +SK_MAC_ADDR *SrcAddr, /* Source address */ +SK_MAC_ADDR *DestAddr) /* Destination address */ { int i; SK_U16 Length; SK_MBUF *pMb; SK_RLMT_PACKET *pPacket; - if ((pMb = SkDrvAllocRlmtMbuf(pAC, IoC, SK_RLMT_MAX_PACKET_SIZE)) != - NULL) { + if ((pMb = SkDrvAllocRlmtMbuf(pAC, IoC, SK_RLMT_MAX_PACKET_SIZE)) != NULL) { pPacket = (SK_RLMT_PACKET*)pMb->pData; for (i = 0; i < SK_MAC_ADDR_LEN; i++) { pPacket->DstAddr[i] = DestAddr->a[i]; @@ -868,17 +790,14 @@ pPacket->Indicator[5] = SK_RLMT_INDICATOR5; pPacket->Indicator[6] = SK_RLMT_INDICATOR6; - SK_U16_TO_NETWORK_ORDER( - PacketType, - &pPacket->RlmtPacketType[0]); + SK_U16_TO_NETWORK_ORDER(PacketType, &pPacket->RlmtPacketType[0]); for (i = 0; i < 4; i++) { - pPacket->Random[i] = pAC->Rlmt.Port[PortIdx].Random[i]; + pPacket->Random[i] = pAC->Rlmt.Port[PortNumber].Random[i]; } SK_U16_TO_NETWORK_ORDER( - SK_RLMT_PACKET_VERSION, - &pPacket->RlmtPacketVersion[0]); + SK_RLMT_PACKET_VERSION, &pPacket->RlmtPacketVersion[0]); for (i = 0; i < SK_PACKET_DATA_LEN; i++) { pPacket->Data[i] = 0x00; @@ -886,12 +805,12 @@ Length = SK_RLMT_MAX_PACKET_SIZE; /* Or smaller. */ pMb->Length = Length; - pMb->PortIdx = PortIdx; + pMb->PortIdx = PortNumber; Length -= 14; SK_U16_TO_NETWORK_ORDER(Length, &pPacket->TypeLen[0]); if (PacketType == SK_PACKET_ALIVE) { - pAC->Rlmt.Port[PortIdx].TxHelloCts++; + pAC->Rlmt.Port[PortNumber].TxHelloCts++; } } @@ -913,13 +832,13 @@ * NULL or pointer to RLMT mbuf */ RLMT_STATIC SK_MBUF *SkRlmtBuildSpanningTreePacket( -SK_AC *pAC, /* adapter context */ -SK_IOC IoC, /* I/O context */ -SK_U32 PortIdx) /* sending port */ +SK_AC *pAC, /* Adapter Context */ +SK_IOC IoC, /* I/O Context */ +SK_U32 PortNumber) /* Sending port */ { - unsigned i; - SK_U16 Length; - SK_MBUF *pMb; + unsigned i; + SK_U16 Length; + SK_MBUF *pMb; SK_SPTREE_PACKET *pSPacket; if ((pMb = SkDrvAllocRlmtMbuf(pAC, IoC, SK_RLMT_MAX_PACKET_SIZE)) != @@ -928,7 +847,7 @@ for (i = 0; i < SK_MAC_ADDR_LEN; i++) { pSPacket->DstAddr[i] = BridgeMcAddr.a[i]; pSPacket->SrcAddr[i] = - pAC->Addr.Port[PortIdx].CurrentMacAddress.a[i]; + pAC->Addr.Port[PortNumber].CurrentMacAddress.a[i]; } pSPacket->DSap = SK_RLMT_SPT_DSAP; pSPacket->SSap = SK_RLMT_SPT_SSAP; @@ -949,13 +868,13 @@ pSPacket->BridgeId[1] = SK_RLMT_SPT_BRIDGE_ID1; /* - * Use virtual address as bridge ID and filter these packets + * Use logical MAC address as bridge ID and filter these packets * on receive. */ - for (i = 0; i < SK_MAC_ADDR_LEN; i++) { pSPacket->BridgeId[i + 2] = pSPacket->RootId[i + 2] = - pAC->Addr.CurrentMacAddress.a[i]; + pAC->Addr.Net[pAC->Rlmt.Port[PortNumber].Net->NetNumber]. + CurrentMacAddress.a[i]; } pSPacket->PortId[0] = SK_RLMT_SPT_PORT_ID0; pSPacket->PortId[1] = SK_RLMT_SPT_PORT_ID1; @@ -970,11 +889,11 @@ Length = SK_RLMT_MAX_PACKET_SIZE; /* Or smaller. */ pMb->Length = Length; - pMb->PortIdx = PortIdx; + pMb->PortIdx = PortNumber; Length -= 14; SK_U16_TO_NETWORK_ORDER(Length, &pSPacket->TypeLen[0]); - pAC->Rlmt.Port[PortIdx].TxSpHelloReqCts++; + pAC->Rlmt.Port[PortNumber].TxSpHelloReqCts++; } return (pMb); @@ -996,36 +915,22 @@ * Nothing. */ RLMT_STATIC void SkRlmtSend( -SK_AC *pAC, /* adapter context */ -SK_IOC IoC, /* I/O context */ -SK_U32 PortIdx) +SK_AC *pAC, /* Adapter Context */ +SK_IOC IoC, /* I/O Context */ +SK_U32 PortNumber) /* Sending port */ { unsigned j; SK_EVPARA Para; SK_RLMT_PORT *pRPort; - pRPort = &pAC->Rlmt.Port[PortIdx]; - if (pAC->Rlmt.RlmtMode & SK_RLMT_CHECK_LOC_LINK) { - if (pRPort->CheckingState & - (SK_RLMT_PCS_TX | SK_RLMT_PCS_RX)) { - - /* - * Port is suspicious. Send the RLMT packet to the - * RLMT multicast address. - */ - - if ((Para.pParaPtr = SkRlmtBuildPacket( - pAC, - IoC, - PortIdx, - SK_PACKET_ALIVE, - &pAC->Addr.Port[PortIdx].CurrentMacAddress, + pRPort = &pAC->Rlmt.Port[PortNumber]; + if (pAC->Rlmt.Port[PortNumber].Net->RlmtMode & SK_RLMT_CHECK_LOC_LINK) { + if (pRPort->CheckingState & (SK_RLMT_PCS_TX | SK_RLMT_PCS_RX)) { + /* Port is suspicious. Send the RLMT packet to the RLMT mc addr. */ + if ((Para.pParaPtr = SkRlmtBuildPacket(pAC, IoC, PortNumber, + SK_PACKET_ALIVE, &pAC->Addr.Port[PortNumber].CurrentMacAddress, &SkRlmtMcAddr)) != NULL) { - SkEventQueue( - pAC, - SKGE_DRV, - SK_DRV_RLMT_SEND, - Para); + SkEventQueue(pAC, SKGE_DRV, SK_DRV_RLMT_SEND, Para); } } else { @@ -1033,61 +938,33 @@ * Send a directed RLMT packet to all ports that are * checked by the indicated port. */ - for (j = 0; j < pRPort->PortsChecked; j++) { - if ((Para.pParaPtr = - SkRlmtBuildPacket( - pAC, - IoC, - PortIdx, - SK_PACKET_ALIVE, - &pAC->Addr.Port[PortIdx].CurrentMacAddress, - &pRPort->PortCheck[j].CheckAddr) - ) != NULL) { - SkEventQueue( - pAC, - SKGE_DRV, - SK_DRV_RLMT_SEND, - Para); + if ((Para.pParaPtr = SkRlmtBuildPacket(pAC, IoC, PortNumber, + SK_PACKET_ALIVE, &pAC->Addr.Port[PortNumber].CurrentMacAddress, + &pRPort->PortCheck[j].CheckAddr)) != NULL) { + SkEventQueue(pAC, SKGE_DRV, SK_DRV_RLMT_SEND, Para); } } } } - if ((pAC->Rlmt.RlmtMode & SK_RLMT_CHECK_SEG) && - (pAC->Rlmt.CheckingState & SK_RLMT_RCS_SEND_SEG)) { - + if ((pAC->Rlmt.Port[PortNumber].Net->RlmtMode & SK_RLMT_CHECK_SEG) && + (pAC->Rlmt.Port[PortNumber].Net->CheckingState & SK_RLMT_RCS_SEND_SEG)) { /* * Send a BPDU packet to make a connected switch tell us * the correct root bridge. */ - if ((Para.pParaPtr = - SkRlmtBuildSpanningTreePacket( - pAC, - IoC, - PortIdx) - ) != NULL) { - - pAC->Rlmt.CheckingState &= ~SK_RLMT_RCS_SEND_SEG; + SkRlmtBuildSpanningTreePacket(pAC, IoC, PortNumber)) != NULL) { + pAC->Rlmt.Port[PortNumber].Net->CheckingState &= ~SK_RLMT_RCS_SEND_SEG; pRPort->RootIdSet = SK_FALSE; - SkEventQueue( - pAC, - SKGE_DRV, - SK_DRV_RLMT_SEND, - Para); - SK_DBG_MSG( - pAC, - SK_DBGMOD_RLMT, - SK_DBGCAT_TX, - ("SkRlmtSend: BPDU Packet on Port %u.\n", - PortIdx)) + SkEventQueue(pAC, SKGE_DRV, SK_DRV_RLMT_SEND, Para); + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_TX, + ("SkRlmtSend: BPDU Packet on Port %u.\n", PortNumber)) } - } - - return; - + } + return; } /* SkRlmtSend */ @@ -1099,61 +976,51 @@ * This routine checks if a port who received a non-BPDU packet * needs to go up or needs to be stopped going down. * -* Context: + * Context: * runtime, pageable? * * Returns: * Nothing. */ RLMT_STATIC void SkRlmtPortReceives( -SK_AC *pAC, /* adapter context */ -SK_IOC IoC, /* I/O context */ -SK_U32 PortIdx) /* port to check */ +SK_AC *pAC, /* Adapter Context */ +SK_IOC IoC, /* I/O Context */ +SK_U32 PortNumber) /* Port to check */ { SK_RLMT_PORT *pRPort; - SK_EVPARA Para; + SK_EVPARA Para; - pRPort = &pAC->Rlmt.Port[PortIdx]; + pRPort = &pAC->Rlmt.Port[PortNumber]; pRPort->PortNoRx = SK_FALSE; if ((pRPort->PortState == SK_RLMT_PS_DOWN) && !(pRPort->CheckingState & SK_RLMT_PCS_TX)) { - /* * Port is marked down (rx), but received a non-BPDU packet. * Bring it up. */ - - SK_DBG_MSG( - pAC, - SK_DBGMOD_RLMT, - SK_DBGCAT_RX, + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX, ("SkRlmtPacketReceive: Received on PortDown.\n")) pRPort->PortState = SK_RLMT_PS_GOING_UP; pRPort->GuTimeStamp = SkOsGetTime(pAC); - Para.Para32[0] = PortIdx; - SkTimerStart( - pAC, - IoC, - &pRPort->UpTimer, - SK_RLMT_PORTUP_TIM_VAL, - SKGE_RLMT, - SK_RLMT_PORTUP_TIM, - Para); - SkRlmtCheckSwitch(pAC, IoC); - } + Para.Para32[0] = PortNumber; + Para.Para32[1] = (SK_U32)-1; + SkTimerStart(pAC, IoC, &pRPort->UpTimer, SK_RLMT_PORTUP_TIM_VAL, + SKGE_RLMT, SK_RLMT_PORTUP_TIM, Para); + pRPort->CheckingState &= ~SK_RLMT_PCS_RX; + /* pAC->Rlmt.CheckSwitch = SK_TRUE; */ + SkRlmtCheckSwitch(pAC, IoC, pRPort->Net->NetNumber); + } /* PortDown && !SuspectTx */ else if (pRPort->CheckingState & SK_RLMT_PCS_RX) { - SK_DBG_MSG( - pAC, - SK_DBGMOD_RLMT, - SK_DBGCAT_RX, + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX, ("SkRlmtPacketReceive: Stop bringing port down.\n")) SkTimerStop(pAC, IoC, &pRPort->DownRxTimer); - SkRlmtCheckSwitch(pAC, IoC); - } + pRPort->CheckingState &= ~SK_RLMT_PCS_RX; + /* pAC->Rlmt.CheckSwitch = SK_TRUE; */ + SkRlmtCheckSwitch(pAC, IoC, pRPort->Net->NetNumber); + } /* PortGoingDown */ - pRPort->CheckingState &= ~SK_RLMT_PCS_RX; return; } /* SkRlmtPortReceives */ @@ -1163,7 +1030,7 @@ * SkRlmtPacketReceive - receive a packet for closer examination * * Description: - * This routine examines a packet more closely than SkRlmtLookahead*(). + * This routine examines a packet more closely than SK_RLMT_LOOKAHEAD. * * Context: * runtime, pageable? @@ -1172,32 +1039,29 @@ * Nothing. */ RLMT_STATIC void SkRlmtPacketReceive( -SK_AC *pAC, /* adapter context */ -SK_IOC IoC, /* I/O context */ -SK_MBUF *pMb) /* received packet */ +SK_AC *pAC, /* Adapter Context */ +SK_IOC IoC, /* I/O Context */ +SK_MBUF *pMb) /* Received packet */ { #ifdef xDEBUG extern void DumpData(char *p, int size); #endif /* DEBUG */ - int i; - unsigned j; - SK_U16 PacketType; - SK_U32 PortIdx; + int i; + unsigned j; + SK_U16 PacketType; + SK_U32 PortNumber; SK_ADDR_PORT *pAPort; SK_RLMT_PORT *pRPort; SK_RLMT_PACKET *pRPacket; SK_SPTREE_PACKET *pSPacket; - SK_EVPARA Para; + SK_EVPARA Para; + + PortNumber = pMb->PortIdx; + pAPort = &pAC->Addr.Port[PortNumber]; + pRPort = &pAC->Rlmt.Port[PortNumber]; - PortIdx = pMb->PortIdx; - pAPort = &pAC->Addr.Port[PortIdx]; - pRPort = &pAC->Rlmt.Port[PortIdx]; - - SK_DBG_MSG( - pAC, - SK_DBGMOD_RLMT, - SK_DBGCAT_RX, - ("SkRlmtPacketReceive: PortIdx == %d.\n", PortIdx)) + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX, + ("SkRlmtPacketReceive: PortNumber == %d.\n", PortNumber)) pRPacket = (SK_RLMT_PACKET*)pMb->pData; pSPacket = (SK_SPTREE_PACKET*)pRPacket; @@ -1207,7 +1071,7 @@ #endif /* DEBUG */ if ((pRPort->PacketsPerTimeSlot - pRPort->BpduPacketsPerTimeSlot) != 0) { - SkRlmtPortReceives(pAC, IoC, PortIdx); + SkRlmtPortReceives(pAC, IoC, PortNumber); } /* Check destination address. */ @@ -1216,15 +1080,8 @@ !SK_ADDR_EQUAL(SkRlmtMcAddr.a, pRPacket->DstAddr) && !SK_ADDR_EQUAL(BridgeMcAddr.a, pRPacket->DstAddr)) { - /* - * Not sent to current MAC or registered MC address - * => Trash it. - */ - - SK_DBG_MSG( - pAC, - SK_DBGMOD_RLMT, - SK_DBGCAT_RX, + /* Not sent to current MAC or registered MC address => Trash it. */ + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX, ("SkRlmtPacketReceive: Not for me.\n")) SkDrvFreeRlmtMbuf(pAC, IoC, pMb); @@ -1241,19 +1098,17 @@ * Check for duplicate address here: * If Packet.Random != My.Random => DupAddr. */ - for (i = 3; i >= 0; i--) { - if (pRPort->Random[i] != - pRPacket->Random[i]) { + if (pRPort->Random[i] != pRPacket->Random[i]) { break; } } /* - * CAUTION: Do not check for duplicate MAC - * address in RLMT Alive Reply packets. + * CAUTION: Do not check for duplicate MAC address in RLMT Alive Reply + * packets (they have the LLC_COMMAND_RESPONSE_BIT set in + * pRPacket->SSap). */ - if (i >= 0 && pRPacket->DSap == SK_RLMT_DSAP && pRPacket->Ctrl == SK_RLMT_CTRL && pRPacket->SSap == SK_RLMT_SSAP && @@ -1264,43 +1119,28 @@ pRPacket->Indicator[4] == SK_RLMT_INDICATOR4 && pRPacket->Indicator[5] == SK_RLMT_INDICATOR5 && pRPacket->Indicator[6] == SK_RLMT_INDICATOR6) { - SK_DBG_MSG( - pAC, - SK_DBGMOD_RLMT, - SK_DBGCAT_RX, + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX, ("SkRlmtPacketReceive: Duplicate MAC Address.\n")) /* Error Log entry. */ - - SK_ERR_LOG( - pAC, - SK_ERRCL_COMM, - SKERR_RLMT_E006, - SKERR_RLMT_E006_MSG); + SK_ERR_LOG(pAC, SK_ERRCL_COMM, SKERR_RLMT_E006, SKERR_RLMT_E006_MSG); } else { /* Simply trash it. */ - - SK_DBG_MSG( - pAC, - SK_DBGMOD_RLMT, - SK_DBGCAT_RX, + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX, ("SkRlmtPacketReceive: Sent by me.\n")) } SkDrvFreeRlmtMbuf(pAC, IoC, pMb); - return; } /* Check SuspectTx entries. */ - if (pRPort->PortsSuspect > 0) { for (j = 0; j < pRPort->PortsChecked; j++) { if (pRPort->PortCheck[j].SuspectTx && SK_ADDR_EQUAL( - pRPacket->SrcAddr, - pRPort->PortCheck[j].CheckAddr.a)) { + pRPacket->SrcAddr, pRPort->PortCheck[j].CheckAddr.a)) { pRPort->PortCheck[j].SuspectTx = SK_FALSE; pRPort->PortsSuspect--; break; @@ -1309,7 +1149,6 @@ } /* Determine type of packet. */ - if (pRPacket->DSap == SK_RLMT_DSAP && pRPacket->Ctrl == SK_RLMT_CTRL && (pRPacket->SSap & ~LLC_COMMAND_RESPONSE_BIT) == SK_RLMT_SSAP && @@ -1322,7 +1161,6 @@ pRPacket->Indicator[6] == SK_RLMT_INDICATOR6) { /* It's an RLMT packet. */ - PacketType = (SK_U16)((pRPacket->RlmtPacketType[0] << 8) | pRPacket->RlmtPacketType[1]); @@ -1330,14 +1168,10 @@ case SK_PACKET_ANNOUNCE: /* Not yet used. */ #if 0 /* Build the check chain. */ - SkRlmtBuildCheckChain(pAC); #endif /* 0 */ - SK_DBG_MSG( - pAC, - SK_DBGMOD_RLMT, - SK_DBGCAT_RX, + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX, ("SkRlmtPacketReceive: Announce.\n")) SkDrvFreeRlmtMbuf(pAC, IoC, pMb); @@ -1345,221 +1179,145 @@ case SK_PACKET_ALIVE: if (pRPacket->SSap & LLC_COMMAND_RESPONSE_BIT) { - SK_DBG_MSG( - pAC, - SK_DBGMOD_RLMT, - SK_DBGCAT_RX, + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX, ("SkRlmtPacketReceive: Alive Reply.\n")) - /* Alive Reply Packet. */ - -#if 0 - pRPort->RlmtAcksPerTimeSlot++; -#endif /* 0 */ - - if (!(pAC->Addr.Port[PortIdx].PromMode & - SK_PROM_MODE_LLC) || + if (!(pAC->Addr.Port[PortNumber].PromMode & SK_PROM_MODE_LLC) || SK_ADDR_EQUAL( - pRPacket->DstAddr, - pAPort->CurrentMacAddress.a)) { - + pRPacket->DstAddr, pAPort->CurrentMacAddress.a)) { /* Obviously we could send something. */ - - if (pRPort->CheckingState & - SK_RLMT_PCS_TX) { - pRPort->CheckingState &= - ~SK_RLMT_PCS_TX; - SkTimerStop( - pAC, - IoC, - &pRPort->DownTxTimer); + if (pRPort->CheckingState & SK_RLMT_PCS_TX) { + pRPort->CheckingState &= ~SK_RLMT_PCS_TX; + SkTimerStop(pAC, IoC, &pRPort->DownTxTimer); } - if ((pRPort->PortState == - SK_RLMT_PS_DOWN) && - !(pRPort->CheckingState & - SK_RLMT_PCS_RX)) { - pRPort->PortState = - SK_RLMT_PS_GOING_UP; - pRPort->GuTimeStamp = - SkOsGetTime(pAC); - - SkTimerStop( - pAC, - IoC, - &pRPort->DownTxTimer); - - Para.Para32[0] = PortIdx; - SkTimerStart( - pAC, - IoC, - &pRPort->UpTimer, - SK_RLMT_PORTUP_TIM_VAL, - SKGE_RLMT, - SK_RLMT_PORTUP_TIM, - Para); + if ((pRPort->PortState == SK_RLMT_PS_DOWN) && + !(pRPort->CheckingState & SK_RLMT_PCS_RX)) { + pRPort->PortState = SK_RLMT_PS_GOING_UP; + pRPort->GuTimeStamp = SkOsGetTime(pAC); + + SkTimerStop(pAC, IoC, &pRPort->DownTxTimer); + + Para.Para32[0] = PortNumber; + Para.Para32[1] = (SK_U32)-1; + SkTimerStart(pAC, IoC, &pRPort->UpTimer, + SK_RLMT_PORTUP_TIM_VAL, SKGE_RLMT, + SK_RLMT_PORTUP_TIM, Para); } } /* Mark sending port as alive? */ - SkDrvFreeRlmtMbuf(pAC, IoC, pMb); } else { /* Alive Request Packet. */ - SK_DBG_MSG( - pAC, - SK_DBGMOD_RLMT, - SK_DBGCAT_RX, + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX, ("SkRlmtPacketReceive: Alive Request.\n")) pRPort->RxHelloCts++; -#if 0 - pRPort->RlmtChksPerTimeSlot++; -#endif /* 0 */ /* Answer. */ - for (i = 0; i < SK_MAC_ADDR_LEN; i++) { - pRPacket->DstAddr[i] = - pRPacket->SrcAddr[i]; - pRPacket->SrcAddr[i] = pAC->Addr.Port[ - PortIdx].CurrentMacAddress.a[i]; + pRPacket->DstAddr[i] = pRPacket->SrcAddr[i]; + pRPacket->SrcAddr[i] = + pAC->Addr.Port[PortNumber].CurrentMacAddress.a[i]; } pRPacket->SSap |= LLC_COMMAND_RESPONSE_BIT; Para.pParaPtr = pMb; - SkEventQueue( - pAC, - SKGE_DRV, - SK_DRV_RLMT_SEND, - Para); + SkEventQueue(pAC, SKGE_DRV, SK_DRV_RLMT_SEND, Para); } break; case SK_PACKET_CHECK_TX: - SK_DBG_MSG( - pAC, - SK_DBGMOD_RLMT, - SK_DBGCAT_RX, + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX, ("SkRlmtPacketReceive: Check your tx line.\n")) - /* - * A port checking us requests us to check our tx line. - */ - + /* A port checking us requests us to check our tx line. */ pRPort->CheckingState |= SK_RLMT_PCS_TX; /* Start PortDownTx timer. */ - - Para.Para32[0] = PortIdx; - SkTimerStart( - pAC, - IoC, - &pRPort->DownTxTimer, - SK_RLMT_PORTDOWN_TIM_VAL, - SKGE_RLMT, - SK_RLMT_PORTDOWN_TX_TIM, - Para); + Para.Para32[0] = PortNumber; + Para.Para32[1] = (SK_U32)-1; + SkTimerStart(pAC, IoC, &pRPort->DownTxTimer, + SK_RLMT_PORTDOWN_TIM_VAL, SKGE_RLMT, + SK_RLMT_PORTDOWN_TX_TIM, Para); SkDrvFreeRlmtMbuf(pAC, IoC, pMb); - if ((Para.pParaPtr = SkRlmtBuildPacket( - pAC, - IoC, - PortIdx, - SK_PACKET_ALIVE, - &pAC->Addr.Port[PortIdx].CurrentMacAddress, + if ((Para.pParaPtr = SkRlmtBuildPacket(pAC, IoC, PortNumber, + SK_PACKET_ALIVE, &pAC->Addr.Port[PortNumber].CurrentMacAddress, &SkRlmtMcAddr)) != NULL) { - SkEventQueue( - pAC, - SKGE_DRV, - SK_DRV_RLMT_SEND, - Para); + SkEventQueue(pAC, SKGE_DRV, SK_DRV_RLMT_SEND, Para); } break; case SK_PACKET_ADDR_CHANGED: - SK_DBG_MSG( - pAC, - SK_DBGMOD_RLMT, - SK_DBGCAT_RX, + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX, ("SkRlmtPacketReceive: Address Change.\n")) /* Build the check chain. */ - - SkRlmtBuildCheckChain(pAC); + SkRlmtBuildCheckChain(pAC, pRPort->Net->NetNumber); SkDrvFreeRlmtMbuf(pAC, IoC, pMb); break; default: - SK_DBG_MSG( - pAC, - SK_DBGMOD_RLMT, - SK_DBGCAT_RX, + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX, ("SkRlmtPacketReceive: Unknown RLMT packet.\n")) /* RA;:;: ??? */ - SkDrvFreeRlmtMbuf(pAC, IoC, pMb); } } else if (pSPacket->DSap == SK_RLMT_SPT_DSAP && pSPacket->Ctrl == SK_RLMT_SPT_CTRL && - (pSPacket->SSap & ~LLC_COMMAND_RESPONSE_BIT) == - SK_RLMT_SPT_SSAP) { - SK_DBG_MSG( - pAC, - SK_DBGMOD_RLMT, - SK_DBGCAT_RX, + (pSPacket->SSap & ~LLC_COMMAND_RESPONSE_BIT) == SK_RLMT_SPT_SSAP) { + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX, ("SkRlmtPacketReceive: BPDU Packet.\n")) /* Spanning Tree packet. */ - pRPort->RxSpHelloCts++; - if (!SK_ADDR_EQUAL( - &pSPacket->RootId[2], - &pAC->Addr.CurrentMacAddress.a[0])) { - + if (!SK_ADDR_EQUAL(&pSPacket->RootId[2], &pAC->Addr.Net[pAC->Rlmt. + Port[PortNumber].Net->NetNumber].CurrentMacAddress.a[0])) { /* * Check segmentation if a new root bridge is set and * the segmentation check is not currently running. */ - - if (!SK_ADDR_EQUAL( - &pSPacket->RootId[2], - &pRPort->Root.Id[2]) && - (pAC->Rlmt.LinksUp > 1) && - (pAC->Rlmt.RlmtMode & SK_RLMT_CHECK_SEG) && - !(pAC->Rlmt.CheckingState & SK_RLMT_RCS_SEG)) { - pAC->Rlmt.CheckingState |= - SK_RLMT_RCS_START_SEG | - SK_RLMT_RCS_SEND_SEG; + if (!SK_ADDR_EQUAL(&pSPacket->RootId[2], &pRPort->Root.Id[2]) && + (pAC->Rlmt.Port[PortNumber].Net->LinksUp > 1) && + (pAC->Rlmt.Port[PortNumber].Net->RlmtMode & SK_RLMT_CHECK_SEG) + != 0 && (pAC->Rlmt.Port[PortNumber].Net->CheckingState & + SK_RLMT_RCS_SEG) == 0) { + pAC->Rlmt.Port[PortNumber].Net->CheckingState |= + SK_RLMT_RCS_START_SEG | SK_RLMT_RCS_SEND_SEG; } /* Store tree view of this port. */ - for (i = 0; i < 8; i++) { pRPort->Root.Id[i] = pSPacket->RootId[i]; } pRPort->RootIdSet = SK_TRUE; + + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_DUMP, + ("Root ID %d: %02x %02x %02x %02x %02x %02x %02x %02x.\n", + PortNumber, + pRPort->Root.Id[0], pRPort->Root.Id[1], + pRPort->Root.Id[2], pRPort->Root.Id[3], + pRPort->Root.Id[4], pRPort->Root.Id[5], + pRPort->Root.Id[6], pRPort->Root.Id[7])) } SkDrvFreeRlmtMbuf(pAC, IoC, pMb); - - if (pAC->Rlmt.CheckingState & SK_RLMT_RCS_REPORT_SEG) { - SkRlmtCheckSeg(pAC, IoC); + if ((pAC->Rlmt.Port[PortNumber].Net->CheckingState & + SK_RLMT_RCS_REPORT_SEG) != 0) { + SkRlmtCheckSeg(pAC, IoC, pAC->Rlmt.Port[PortNumber].Net->NetNumber); } } else { - SK_DBG_MSG( - pAC, - SK_DBGMOD_RLMT, - SK_DBGCAT_RX, + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX, ("SkRlmtPacketReceive: Unknown Packet Type.\n")) /* Unknown packet. */ - SkDrvFreeRlmtMbuf(pAC, IoC, pMb); } return; @@ -1625,25 +1383,21 @@ * New timeout value. */ RLMT_STATIC SK_U32 SkRlmtCheckPort( -SK_AC *pAC, /* adapter context */ -SK_IOC IoC, /* I/O context */ -SK_U32 PortIdx) /* port to check */ +SK_AC *pAC, /* Adapter Context */ +SK_IOC IoC, /* I/O Context */ +SK_U32 PortNumber) /* Port to check */ { - unsigned i; - SK_U32 NewTimeout; + unsigned i; + SK_U32 NewTimeout; SK_RLMT_PORT *pRPort; - SK_EVPARA Para; + SK_EVPARA Para; - pRPort = &pAC->Rlmt.Port[PortIdx]; + pRPort = &pAC->Rlmt.Port[PortNumber]; if ((pRPort->PacketsPerTimeSlot - pRPort->BpduPacketsPerTimeSlot) == 0) { - SK_DBG_MSG( - pAC, - SK_DBGMOD_RLMT, - SK_DBGCAT_CTRL, + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, ("SkRlmtCheckPort %d: No (%d) receives in last time slot.\n", - PortIdx, - pRPort->PacketsPerTimeSlot)) + PortNumber, pRPort->PacketsPerTimeSlot)) /* * Check segmentation if there was no receive at least twice @@ -1651,46 +1405,35 @@ * check is not currently running. */ - if (pRPort->PortNoRx && (pAC->Rlmt.LinksUp > 1) && - (pAC->Rlmt.RlmtMode & SK_RLMT_CHECK_SEG) && - !(pAC->Rlmt.CheckingState & SK_RLMT_RCS_SEG)) { - pAC->Rlmt.CheckingState |= + if (pRPort->PortNoRx && (pAC->Rlmt.Port[PortNumber].Net->LinksUp > 1) && + (pAC->Rlmt.Port[PortNumber].Net->RlmtMode & SK_RLMT_CHECK_SEG) && + !(pAC->Rlmt.Port[PortNumber].Net->CheckingState & SK_RLMT_RCS_SEG)) { + pAC->Rlmt.Port[PortNumber].Net->CheckingState |= SK_RLMT_RCS_START_SEG | SK_RLMT_RCS_SEND_SEG; } - SK_DBG_MSG( - pAC, - SK_DBGMOD_RLMT, - SK_DBGCAT_CTRL, + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, ("SkRlmtCheckPort: PortsSuspect %d, PcsRx %d.\n", - pRPort->PortsSuspect, - pRPort->CheckingState & SK_RLMT_PCS_RX)) + pRPort->PortsSuspect, pRPort->CheckingState & SK_RLMT_PCS_RX)) if (pRPort->PortState != SK_RLMT_PS_DOWN) { - NewTimeout = TO_SHORTEN(pAC->Rlmt.TimeoutValue); + NewTimeout = TO_SHORTEN(pAC->Rlmt.Port[PortNumber].Net->TimeoutValue); if (NewTimeout < SK_RLMT_MIN_TO_VAL) { NewTimeout = SK_RLMT_MIN_TO_VAL; } if (!(pRPort->CheckingState & SK_RLMT_PCS_RX)) { - Para.Para32[0] = PortIdx; + Para.Para32[0] = PortNumber; pRPort->CheckingState |= SK_RLMT_PCS_RX; /* - * What shall we do if the port checked - * by this one receives our request - * frames? What's bad - our rx line - * or his tx line? + * What shall we do if the port checked by this one receives + * our request frames? What's bad - our rx line or his tx line? */ - - SkTimerStart( - pAC, - IoC, - &pRPort->DownRxTimer, - SK_RLMT_PORTDOWN_TIM_VAL, - SKGE_RLMT, - SK_RLMT_PORTDOWN_RX_TIM, - Para); + Para.Para32[1] = (SK_U32)-1; + SkTimerStart(pAC, IoC, &pRPort->DownRxTimer, + SK_RLMT_PORTDOWN_TIM_VAL, SKGE_RLMT, + SK_RLMT_PORTDOWN_RX_TIM, Para); for (i = 0; i < pRPort->PortsChecked; i++) { if (pRPort->PortCheck[i].SuspectTx) { @@ -1699,19 +1442,10 @@ pRPort->PortCheck[i].SuspectTx = SK_TRUE; pRPort->PortsSuspect++; if ((Para.pParaPtr = - SkRlmtBuildPacket( - pAC, - IoC, - PortIdx, - SK_PACKET_CHECK_TX, - &pAC->Addr.Port[PortIdx].CurrentMacAddress, - &pRPort->PortCheck[i].CheckAddr) - ) != NULL) { - SkEventQueue( - pAC, - SKGE_DRV, - SK_DRV_RLMT_SEND, - Para); + SkRlmtBuildPacket(pAC, IoC, PortNumber, SK_PACKET_CHECK_TX, + &pAC->Addr.Port[PortNumber].CurrentMacAddress, + &pRPort->PortCheck[i].CheckAddr)) != NULL) { + SkEventQueue(pAC, SKGE_DRV, SK_DRV_RLMT_SEND, Para); } } } @@ -1722,17 +1456,17 @@ pRPort->PortNoRx = SK_TRUE; } else { /* A non-BPDU packet was received. */ - SK_DBG_MSG( - pAC, - SK_DBGMOD_RLMT, - SK_DBGCAT_CTRL, + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, ("SkRlmtCheckPort %d: %d (%d) receives in last time slot.\n", - PortIdx, - pRPort->PacketsPerTimeSlot - - pRPort->BpduPacketsPerTimeSlot, + PortNumber, + pRPort->PacketsPerTimeSlot - pRPort->BpduPacketsPerTimeSlot, pRPort->PacketsPerTimeSlot)) - SkRlmtPortReceives(pAC, IoC, PortIdx); + SkRlmtPortReceives(pAC, IoC, PortNumber); + if (pAC->Rlmt.CheckSwitch) { + SkRlmtCheckSwitch(pAC, IoC, pRPort->Net->NetNumber); + } + NewTimeout = SK_RLMT_DEF_TO_VAL; } @@ -1755,82 +1489,69 @@ * SK_BOOL */ RLMT_STATIC SK_BOOL SkRlmtSelectBcRx( -SK_AC *pAC, /* adapter context */ -SK_IOC IoC, /* I/O context */ -SK_U32 A, /* active port */ -SK_U32 P, /* preferred port */ -SK_U32 *N) /* new active port */ +SK_AC *pAC, /* Adapter Context */ +SK_IOC IoC, /* I/O Context */ +SK_U32 Active, /* Active port */ +SK_U32 PrefPort, /* Preferred port */ +SK_U32 *pSelect) /* New active port */ { SK_U64 BcTimeStamp; SK_U32 i; SK_BOOL PortFound; - BcTimeStamp = 0; /* Not totally necessary, but feeling better. */ + BcTimeStamp = 0; /* Not totally necessary, but feeling better. */ PortFound = SK_FALSE; /* Select port with the latest TimeStamp. */ - for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) { - SK_DBG_MSG( - pAC, - SK_DBGMOD_RLMT, - SK_DBGCAT_CTRL, - ("TimeStamp Port %d: %.08x%.08x.\n", - i, - *((SK_U32*)(&pAC->Rlmt.Port[i].BcTimeStamp) + OFFS_HI32), - *((SK_U32*)(&pAC->Rlmt.Port[i].BcTimeStamp) + OFFS_LO32))) - if (!pAC->Rlmt.Port[i].PortDown && - !pAC->Rlmt.Port[i].PortNoRx) { - if (!PortFound || - pAC->Rlmt.Port[i].BcTimeStamp > BcTimeStamp) { +#ifdef xDEBUG + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("TimeStamp Port %d: %08x %08x.\n", + i, + *((SK_U32*)(&pAC->Rlmt.Port[i].BcTimeStamp) + OFFS_HI32), + *((SK_U32*)(&pAC->Rlmt.Port[i].BcTimeStamp) + OFFS_LO32))) +#endif /* DEBUG */ + if (!pAC->Rlmt.Port[i].PortDown && !pAC->Rlmt.Port[i].PortNoRx) { + if (!PortFound || pAC->Rlmt.Port[i].BcTimeStamp > BcTimeStamp) { BcTimeStamp = pAC->Rlmt.Port[i].BcTimeStamp; - *N = i; + *pSelect = i; PortFound = SK_TRUE; } } } if (PortFound) { - SK_DBG_MSG( - pAC, - SK_DBGMOD_RLMT, - SK_DBGCAT_CTRL, - ("Port %d received the last broadcast.\n", *N)) +#if 0 + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("Port %d received the last broadcast.\n", *pSelect)) +#endif /* 0 */ /* Look if another port's time stamp is similar. */ - for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) { - if (i == *N) { + if (i == *pSelect) { continue; } - if (!pAC->Rlmt.Port[i].PortDown && - !pAC->Rlmt.Port[i].PortNoRx && + if (!pAC->Rlmt.Port[i].PortDown && !pAC->Rlmt.Port[i].PortNoRx && (pAC->Rlmt.Port[i].BcTimeStamp > - BcTimeStamp - SK_RLMT_BC_DELTA || - pAC->Rlmt.Port[i].BcTimeStamp - + SK_RLMT_BC_DELTA > BcTimeStamp)) { + BcTimeStamp - SK_RLMT_BC_DELTA || + pAC->Rlmt.Port[i].BcTimeStamp + + SK_RLMT_BC_DELTA > BcTimeStamp)) { PortFound = SK_FALSE; - SK_DBG_MSG( - pAC, - SK_DBGMOD_RLMT, - SK_DBGCAT_CTRL, - ("Port %d received a broadcast %s.\n", - i, - "at a similar time")) +#ifdef xDEBUG + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("Port %d received a broadcast at a similar time.\n", i)) +#endif /* DEBUG */ break; } } } -#ifdef DEBUG +#ifdef xDEBUG if (PortFound) { - SK_DBG_MSG( - pAC, - SK_DBGMOD_RLMT, - SK_DBGCAT_CTRL, - ("SK_RLMT_CHECK_SWITCH found Port %d receiving %s.\n", - *N, - "the substantially latest broadcast")) + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_CHECK_SWITCH found Port %d receiving the substantially latest broadcast (%d).\n", + *pSelect, + BcTimeStamp - pAC->Rlmt.Port[1 - *pSelect].BcTimeStamp)) } #endif /* DEBUG */ @@ -1852,11 +1573,11 @@ * SK_BOOL */ RLMT_STATIC SK_BOOL SkRlmtSelectNotSuspect( -SK_AC *pAC, /* adapter context */ -SK_IOC IoC, /* I/O context */ -SK_U32 A, /* active port */ -SK_U32 P, /* preferred port */ -SK_U32 *N) /* new active port */ +SK_AC *pAC, /* Adapter Context */ +SK_IOC IoC, /* I/O Context */ +SK_U32 Active, /* Active port */ +SK_U32 PrefPort, /* Preferred port */ +SK_U32 *pSelect) /* New active port */ { SK_U32 i; SK_BOOL PortFound; @@ -1864,32 +1585,25 @@ PortFound = SK_FALSE; /* Select first port that is PortUp && !SuspectRx. */ - for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) { if (!pAC->Rlmt.Port[i].PortDown && !(pAC->Rlmt.Port[i].CheckingState & SK_RLMT_PCS_RX)) { - *N = i; - if (!pAC->Rlmt.Port[A].PortDown && - !(pAC->Rlmt.Port[A].CheckingState & - SK_RLMT_PCS_RX)) { - *N = A; - } - if (!pAC->Rlmt.Port[P].PortDown && - !(pAC->Rlmt.Port[P].CheckingState & - SK_RLMT_PCS_RX)) { - *N = P; + *pSelect = i; + if (!pAC->Rlmt.Port[Active].PortDown && + !(pAC->Rlmt.Port[Active].CheckingState & SK_RLMT_PCS_RX)) { + *pSelect = Active; + } + if (!pAC->Rlmt.Port[PrefPort].PortDown && + !(pAC->Rlmt.Port[PrefPort].CheckingState & SK_RLMT_PCS_RX)) { + *pSelect = PrefPort; } PortFound = SK_TRUE; - SK_DBG_MSG( - pAC, - SK_DBGMOD_RLMT, - SK_DBGCAT_CTRL, + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, ("SK_RLMT_CHECK_SWITCH found Port %d up and not check RX.\n", - *N)) + *pSelect)) break; } } - return (PortFound); } /* SkRlmtSelectNotSuspect */ @@ -1908,12 +1622,12 @@ * SK_BOOL */ RLMT_STATIC SK_BOOL SkRlmtSelectUp( -SK_AC *pAC, /* adapter context */ -SK_IOC IoC, /* I/O context */ -SK_U32 A, /* active port */ -SK_U32 P, /* preferred port */ -SK_U32 *N, /* new active port */ -SK_BOOL AutoNegDone) /* successfully auto-negotiated? */ +SK_AC *pAC, /* Adapter Context */ +SK_IOC IoC, /* I/O Context */ +SK_U32 Active, /* Active port */ +SK_U32 PrefPort, /* Preferred port */ +SK_U32 *pSelect, /* New active port */ +SK_BOOL AutoNegDone) /* Successfully auto-negotiated? */ { SK_U32 i; SK_BOOL PortFound; @@ -1921,30 +1635,24 @@ PortFound = SK_FALSE; /* Select first port that is PortUp. */ - for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) { if (pAC->Rlmt.Port[i].PortState == SK_RLMT_PS_UP && pAC->GIni.GP[i].PAutoNegFail != AutoNegDone) { - *N = i; - if (pAC->Rlmt.Port[A].PortState == SK_RLMT_PS_UP && - pAC->GIni.GP[A].PAutoNegFail != AutoNegDone) { - *N = A; - } - if (pAC->Rlmt.Port[P].PortState == SK_RLMT_PS_UP && - pAC->GIni.GP[P].PAutoNegFail != AutoNegDone) { - *N = P; + *pSelect = i; + if (pAC->Rlmt.Port[Active].PortState == SK_RLMT_PS_UP && + pAC->GIni.GP[Active].PAutoNegFail != AutoNegDone) { + *pSelect = Active; + } + if (pAC->Rlmt.Port[PrefPort].PortState == SK_RLMT_PS_UP && + pAC->GIni.GP[PrefPort].PAutoNegFail != AutoNegDone) { + *pSelect = PrefPort; } PortFound = SK_TRUE; - SK_DBG_MSG( - pAC, - SK_DBGMOD_RLMT, - SK_DBGCAT_CTRL, - ("SK_RLMT_CHECK_SWITCH found Port %d up.\n", - *N)) + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_CHECK_SWITCH found Port %d up.\n", *pSelect)) break; } } - return (PortFound); } /* SkRlmtSelectUp */ @@ -1963,26 +1671,26 @@ * SK_BOOL */ RLMT_STATIC SK_BOOL SkRlmtSelectGoingUp( -SK_AC *pAC, /* adapter context */ -SK_IOC IoC, /* I/O context */ -SK_U32 A, /* active port */ -SK_U32 P, /* preferred port */ -SK_U32 *N, /* new active port */ -SK_BOOL AutoNegDone) /* successfully auto-negotiated? */ +SK_AC *pAC, /* Adapter Context */ +SK_IOC IoC, /* I/O Context */ +SK_U32 Active, /* Active port */ +SK_U32 PrefPort, /* Preferred port */ +SK_U32 *pSelect, /* New active port */ +SK_BOOL AutoNegDone) /* Successfully auto-negotiated? */ { - SK_U64 GuTimeStamp=0; + SK_U64 GuTimeStamp; SK_U32 i; SK_BOOL PortFound; + GuTimeStamp = 0; PortFound = SK_FALSE; /* Select port that is PortGoingUp for the longest time. */ - for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) { if (pAC->Rlmt.Port[i].PortState == SK_RLMT_PS_GOING_UP && pAC->GIni.GP[i].PAutoNegFail != AutoNegDone) { - GuTimeStamp = pAC->Rlmt.Port[i].GuTimeStamp; - *N = i; + GuTimeStamp = pAC->Rlmt.Port[i].GuTimeStamp; + *pSelect = i; PortFound = SK_TRUE; break; } @@ -1992,22 +1700,17 @@ return (SK_FALSE); } - for (i = *N + 1; i < (SK_U32)pAC->GIni.GIMacsFound; i++) { + for (i = *pSelect + 1; i < (SK_U32)pAC->GIni.GIMacsFound; i++) { if (pAC->Rlmt.Port[i].PortState == SK_RLMT_PS_GOING_UP && - pAC->Rlmt.Port[i].GuTimeStamp < GuTimeStamp && + pAC->Rlmt.Port[i].GuTimeStamp < GuTimeStamp && pAC->GIni.GP[i].PAutoNegFail != AutoNegDone) { - - GuTimeStamp = pAC->Rlmt.Port[i].GuTimeStamp; - *N = i; + GuTimeStamp = pAC->Rlmt.Port[i].GuTimeStamp; + *pSelect = i; } } - SK_DBG_MSG( - pAC, - SK_DBGMOD_RLMT, - SK_DBGCAT_CTRL, - ("SK_RLMT_CHECK_SWITCH found Port %d going up.\n", *N)) - + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_CHECK_SWITCH found Port %d going up.\n", *pSelect)) return (SK_TRUE); } /* SkRlmtSelectGoingUp */ @@ -2026,12 +1729,12 @@ * SK_BOOL */ RLMT_STATIC SK_BOOL SkRlmtSelectDown( -SK_AC *pAC, /* adapter context */ -SK_IOC IoC, /* I/O context */ -SK_U32 A, /* active port */ -SK_U32 P, /* preferred port */ -SK_U32 *N, /* new active port */ -SK_BOOL AutoNegDone) /* successfully auto-negotiated? */ +SK_AC *pAC, /* Adapter Context */ +SK_IOC IoC, /* I/O Context */ +SK_U32 Active, /* Active port */ +SK_U32 PrefPort, /* Preferred port */ +SK_U32 *pSelect, /* New active port */ +SK_BOOL AutoNegDone) /* Successfully auto-negotiated? */ { SK_U32 i; SK_BOOL PortFound; @@ -2039,30 +1742,24 @@ PortFound = SK_FALSE; /* Select first port that is PortDown. */ - for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) { if (pAC->Rlmt.Port[i].PortState == SK_RLMT_PS_DOWN && pAC->GIni.GP[i].PAutoNegFail != AutoNegDone) { - *N = i; - if (pAC->Rlmt.Port[A].PortState == SK_RLMT_PS_DOWN && - pAC->GIni.GP[A].PAutoNegFail != AutoNegDone) { - *N = A; - } - if (pAC->Rlmt.Port[P].PortState == SK_RLMT_PS_DOWN && - pAC->GIni.GP[P].PAutoNegFail != AutoNegDone) { - *N = P; + *pSelect = i; + if (pAC->Rlmt.Port[Active].PortState == SK_RLMT_PS_DOWN && + pAC->GIni.GP[Active].PAutoNegFail != AutoNegDone) { + *pSelect = Active; + } + if (pAC->Rlmt.Port[PrefPort].PortState == SK_RLMT_PS_DOWN && + pAC->GIni.GP[PrefPort].PAutoNegFail != AutoNegDone) { + *pSelect = PrefPort; } PortFound = SK_TRUE; - SK_DBG_MSG( - pAC, - SK_DBGMOD_RLMT, - SK_DBGCAT_CTRL, - ("SK_RLMT_CHECK_SWITCH found Port %d down.\n", - *N)) + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_CHECK_SWITCH found Port %d down.\n", *pSelect)) break; } } - return (PortFound); } /* SkRlmtSelectDown */ @@ -2082,58 +1779,50 @@ * Nothing. */ RLMT_STATIC void SkRlmtCheckSwitch( -SK_AC *pAC, /* adapter context */ -SK_IOC IoC) /* I/O context */ +SK_AC *pAC, /* Adapter Context */ +SK_IOC IoC, /* I/O Context */ +SK_U32 NetIdx) /* Net index */ { SK_EVPARA Para; - SK_U32 A; - SK_U32 P; + SK_U32 Active; + SK_U32 PrefPort; SK_U32 i; SK_BOOL PortFound; - if (pAC->Rlmt.RlmtState == SK_RLMT_RS_INIT) { - return; - } - - A = pAC->Rlmt.MacActive; /* Index of active port. */ - P = pAC->Rlmt.PrefPort; /* Index of preferred port. */ + Active = pAC->Rlmt.Net[NetIdx].ActivePort; /* Index of active port. */ + PrefPort = pAC->Rlmt.Net[NetIdx].PrefPort; /* Index of preferred port. */ PortFound = SK_FALSE; + pAC->Rlmt.CheckSwitch = SK_FALSE; - if (pAC->Rlmt.LinksUp == 0) { - - /* - * Last link went down - shut down the net. - */ - - pAC->Rlmt.RlmtState = SK_RLMT_RS_NET_DOWN; + if (pAC->Rlmt.Net[NetIdx].LinksUp == 0) { + /* Last link went down - shut down the net. */ + pAC->Rlmt.Net[NetIdx].RlmtState = SK_RLMT_RS_NET_DOWN; Para.Para32[0] = SK_RLMT_NET_DOWN_TEMP; - SkEventQueue( - pAC, - SKGE_DRV, - SK_DRV_NET_DOWN, - Para); + Para.Para32[1] = NetIdx; + SkEventQueue(pAC, SKGE_DRV, SK_DRV_NET_DOWN, Para); + Para.Para32[0] = pAC->Rlmt.Net[NetIdx]. + Port[pAC->Rlmt.Net[NetIdx].ActivePort]->PortNumber; + Para.Para32[1] = NetIdx; + SkEventQueue(pAC, SKGE_PNMI, SK_PNMI_EVT_RLMT_ACTIVE_DOWN, Para); return; - } - else if (pAC->Rlmt.LinksUp == 1 && - pAC->Rlmt.RlmtState == SK_RLMT_RS_NET_DOWN) { - + } /* pAC->Rlmt.LinksUp == 0 */ + else if (pAC->Rlmt.Net[NetIdx].LinksUp == 1 && + pAC->Rlmt.Net[NetIdx].RlmtState == SK_RLMT_RS_NET_DOWN) { /* First link came up - get the net up. */ - - pAC->Rlmt.RlmtState = SK_RLMT_RS_NET_UP; + pAC->Rlmt.Net[NetIdx].RlmtState = SK_RLMT_RS_NET_UP; /* - * If pAC->Rlmt.MacActive != Para.Para32[0], + * If pAC->Rlmt.ActivePort != Para.Para32[0], * the DRV switches to the port that came up. */ - - for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) { - if (!pAC->Rlmt.Port[i].LinkDown) { - if (!pAC->Rlmt.Port[A].LinkDown) { - i = A; + for (i = 0; i < pAC->Rlmt.Net[NetIdx].NumPorts; i++) { + if (!pAC->Rlmt.Net[NetIdx].Port[i]->LinkDown) { + if (!pAC->Rlmt.Net[NetIdx].Port[Active]->LinkDown) { + i = Active; } - if (!pAC->Rlmt.Port[P].LinkDown) { - i = P; + if (!pAC->Rlmt.Net[NetIdx].Port[PrefPort]->LinkDown) { + i = PrefPort; } PortFound = SK_TRUE; break; @@ -2141,184 +1830,143 @@ } if (PortFound) { - Para.Para32[0] = pAC->Rlmt.MacActive; - Para.Para32[1] = i; - SkEventQueue( - pAC, - SKGE_PNMI, - SK_PNMI_EVT_RLMT_PORT_SWITCH, - Para); - - pAC->Rlmt.MacActive = i; - Para.Para32[0] = i; + Para.Para32[0] = pAC->Rlmt.Net[NetIdx].Port[i]->PortNumber; + Para.Para32[1] = NetIdx; + SkEventQueue(pAC, SKGE_PNMI, SK_PNMI_EVT_RLMT_ACTIVE_UP, Para); + + pAC->Rlmt.Net[NetIdx].ActivePort = i; + Para.Para32[0] = pAC->Rlmt.Net[NetIdx].Port[i]->PortNumber; + Para.Para32[1] = NetIdx; SkEventQueue(pAC, SKGE_DRV, SK_DRV_NET_UP, Para); - if ((Para.pParaPtr = SkRlmtBuildPacket( - pAC, - IoC, - i, - SK_PACKET_ANNOUNCE, - &pAC->Addr.CurrentMacAddress, - &SkRlmtMcAddr) - ) != NULL) { - + if ((pAC->Rlmt.Net[NetIdx].RlmtMode & SK_RLMT_TRANSPARENT) == 0 && + (Para.pParaPtr = SkRlmtBuildPacket(pAC, IoC, + pAC->Rlmt.Net[NetIdx].Port[i]->PortNumber, + SK_PACKET_ANNOUNCE, &pAC->Addr.Net[NetIdx]. + CurrentMacAddress, &SkRlmtMcAddr)) != NULL) { /* - * Send packet to RLMT multicast address - * to force switches to learn the new - * location of the address. + * Send announce packet to RLMT multicast address to force + * switches to learn the new location of the logical MAC address. */ - - SkEventQueue( - pAC, - SKGE_DRV, - SK_DRV_RLMT_SEND, - Para); + SkEventQueue(pAC, SKGE_DRV, SK_DRV_RLMT_SEND, Para); } } else { - SK_ERR_LOG( - pAC, - SK_ERRCL_SW, - SKERR_RLMT_E007, - SKERR_RLMT_E007_MSG); + SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_RLMT_E007, SKERR_RLMT_E007_MSG); } return; - } - else { - Para.Para32[0] = A; + } /* LinksUp == 1 && RlmtState == SK_RLMT_RS_NET_DOWN */ + else { /* Cannot be reached in dual-net mode. */ + Para.Para32[0] = Active; /* * Preselection: - * If RLMT Mode != CheckLinkState - * select port that received a broadcast frame - * substantially later than all other ports - * else select first port that is not SuspectRx - * else select first port that is PortUp - * else select port that is PortGoingUp for the longest time - * else select first port that is PortDown - * else stop. + * If RLMT Mode != CheckLinkState + * select port that received a broadcast frame substantially later + * than all other ports + * else select first port that is not SuspectRx + * else select first port that is PortUp + * else select port that is PortGoingUp for the longest time + * else select first port that is PortDown + * else stop. * * For the preselected port: - * If ActivePort is equal in quality, select ActivePort. + * If ActivePort is equal in quality, select ActivePort. * - * If PrefPort is equal in quality, select PrefPort. + * If PrefPort is equal in quality, select PrefPort. * - * If MacActive != SelectedPort, - * If old ActivePort is LinkDown, - * SwitchHard - * else - * SwitchSoft + * If ActivePort != SelectedPort, + * If old ActivePort is LinkDown, + * SwitchHard + * else + * SwitchSoft */ - - if (pAC->Rlmt.RlmtMode != SK_RLMT_CHECK_LINK) { + if (pAC->Rlmt.Net[0].RlmtMode != SK_RLMT_MODE_CLS) { if (!PortFound) { - PortFound = SkRlmtSelectBcRx(pAC, IoC, - A, P, &Para.Para32[1]); + PortFound = SkRlmtSelectBcRx( + pAC, IoC, Active, PrefPort, &Para.Para32[1]); } if (!PortFound) { - PortFound = SkRlmtSelectNotSuspect(pAC, IoC, - A, P, &Para.Para32[1]); + PortFound = SkRlmtSelectNotSuspect( + pAC, IoC, Active, PrefPort, &Para.Para32[1]); } - } + } /* pAC->Rlmt.RlmtMode != SK_RLMT_MODE_CLS */ if (!PortFound) { - PortFound = SkRlmtSelectUp(pAC, IoC, - A, P, &Para.Para32[1], AUTONEG_SUCCESS); + PortFound = SkRlmtSelectUp( + pAC, IoC, Active, PrefPort, &Para.Para32[1], AUTONEG_SUCCESS); } if (!PortFound) { - PortFound = SkRlmtSelectUp(pAC, IoC, - A, P, &Para.Para32[1], AUTONEG_FAILED); + PortFound = SkRlmtSelectUp( + pAC, IoC, Active, PrefPort, &Para.Para32[1], AUTONEG_FAILED); } if (!PortFound) { - PortFound = SkRlmtSelectGoingUp(pAC, IoC, - A, P, &Para.Para32[1], AUTONEG_SUCCESS); + PortFound = SkRlmtSelectGoingUp( + pAC, IoC, Active, PrefPort, &Para.Para32[1], AUTONEG_SUCCESS); } if (!PortFound) { - PortFound = SkRlmtSelectGoingUp(pAC, IoC, - A, P,&Para.Para32[1], AUTONEG_FAILED); + PortFound = SkRlmtSelectGoingUp( + pAC, IoC, Active, PrefPort, &Para.Para32[1], AUTONEG_FAILED); } - if (pAC->Rlmt.RlmtMode != SK_RLMT_CHECK_LINK) { + if (pAC->Rlmt.Net[0].RlmtMode != SK_RLMT_MODE_CLS) { if (!PortFound) { PortFound = SkRlmtSelectDown(pAC, IoC, - A, P,&Para.Para32[1], AUTONEG_SUCCESS); + Active, PrefPort, &Para.Para32[1], AUTONEG_SUCCESS); } if (!PortFound) { PortFound = SkRlmtSelectDown(pAC, IoC, - A, P,&Para.Para32[1], AUTONEG_FAILED); + Active, PrefPort, &Para.Para32[1], AUTONEG_FAILED); } - } + } /* pAC->Rlmt.RlmtMode != SK_RLMT_MODE_CLS */ if (PortFound) { - if (Para.Para32[1] != A) { - pAC->Rlmt.MacActive = Para.Para32[1]; - SK_HWAC_LINK_LED( - pAC, - IoC, - Para.Para32[1], - SK_LED_ACTIVE); - if (pAC->Rlmt.Port[A].LinkDown) { - SkEventQueue( - pAC, - SKGE_DRV, - SK_DRV_SWITCH_HARD, - Para); + if (Para.Para32[1] != Active) { + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("Active: %d, Para1: %d.\n", Active, Para.Para32[1])) + pAC->Rlmt.Net[NetIdx].ActivePort = Para.Para32[1]; + Para.Para32[0] = pAC->Rlmt.Net[NetIdx]. + Port[Para.Para32[0]]->PortNumber; + Para.Para32[1] = pAC->Rlmt.Net[NetIdx]. + Port[Para.Para32[1]]->PortNumber; + SK_HWAC_LINK_LED(pAC, IoC, Para.Para32[1], SK_LED_ACTIVE); + if (pAC->Rlmt.Port[Active].LinkDown) { + SkEventQueue(pAC, SKGE_DRV, SK_DRV_SWITCH_HARD, Para); } else { - SK_HWAC_LINK_LED( - pAC, - IoC, - Para.Para32[0], - SK_LED_STANDBY); - SkEventQueue( - pAC, - SKGE_DRV, - SK_DRV_SWITCH_SOFT, - Para); + SK_HWAC_LINK_LED(pAC, IoC, Para.Para32[0], SK_LED_STANDBY); + SkEventQueue(pAC, SKGE_DRV, SK_DRV_SWITCH_SOFT, Para); } - SkEventQueue( - pAC, - SKGE_PNMI, - SK_PNMI_EVT_RLMT_PORT_SWITCH, - Para); - if ((Para.pParaPtr = SkRlmtBuildPacket( - pAC, - IoC, - Para.Para32[1], - SK_PACKET_ANNOUNCE, - &pAC->Addr.CurrentMacAddress, - &SkRlmtMcAddr) - ) != NULL) { - + Para.Para32[1] = NetIdx; + Para.Para32[0] = + pAC->Rlmt.Net[NetIdx].Port[Para.Para32[0]]->PortNumber; + SkEventQueue(pAC, SKGE_PNMI, SK_PNMI_EVT_RLMT_ACTIVE_DOWN, Para); + Para.Para32[0] = pAC->Rlmt.Net[NetIdx]. + Port[pAC->Rlmt.Net[NetIdx].ActivePort]->PortNumber; + SkEventQueue(pAC, SKGE_PNMI, SK_PNMI_EVT_RLMT_ACTIVE_UP, Para); + if ((pAC->Rlmt.Net[NetIdx].RlmtMode & SK_RLMT_TRANSPARENT) == 0 && + (Para.pParaPtr = SkRlmtBuildPacket(pAC, IoC, Para.Para32[0], + SK_PACKET_ANNOUNCE, &pAC->Addr.Net[NetIdx].CurrentMacAddress, + &SkRlmtMcAddr)) != NULL) { /* - * Send "new" packet to RLMT multicast - * address to force switches to learn - * the new location of the MAC address. + * Send announce packet to RLMT multicast address to force + * switches to learn the new location of the logical + * MAC address. */ - - SkEventQueue( - pAC, - SKGE_DRV, - SK_DRV_RLMT_SEND, - Para); - } - } - } + SkEventQueue(pAC, SKGE_DRV, SK_DRV_RLMT_SEND, Para); + } /* (Para.pParaPtr = SkRlmtBuildPacket(...)) != NULL */ + } /* Para.Para32[1] != Active */ + } /* PortFound */ else { - SK_ERR_LOG( - pAC, - SK_ERRCL_SW, - SKERR_RLMT_E004, - SKERR_RLMT_E004_MSG); + SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_RLMT_E004, SKERR_RLMT_E004_MSG); } - } - + } /* LinksUp > 1 || LinksUp == 1 && RlmtState != SK_RLMT_RS_NET_DOWN */ return; } /* SkRlmtCheckSwitch */ @@ -2338,66 +1986,65 @@ * Nothing. */ RLMT_STATIC void SkRlmtCheckSeg( -SK_AC *pAC, /* adapter context */ -SK_IOC IoC) /* I/O context */ +SK_AC *pAC, /* Adapter Context */ +SK_IOC IoC, /* I/O Context */ +SK_U32 NetIdx) /* Net number */ { - SK_BOOL Equal; - SK_U32 i, j; + SK_EVPARA Para; + SK_RLMT_NET *pNet; + SK_U32 i, j; + SK_BOOL Equal; - pAC->Rlmt.RootIdSet = SK_FALSE; + pNet = &pAC->Rlmt.Net[NetIdx]; + pNet->RootIdSet = SK_FALSE; Equal = SK_TRUE; - for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) { - if (pAC->Rlmt.Port[i].LinkDown || - !pAC->Rlmt.Port[i].RootIdSet) { + + for (i = 0; i < pNet->NumPorts; i++) { + if (pNet->Port[i]->LinkDown || !pNet->Port[i]->RootIdSet) { continue; } - SK_DBG_MSG( - pAC, - SK_DBGMOD_RLMT, - SK_DBGCAT_CTRL, - ("Root ID %d: %02x %02x %02x %02x %02x %02x %02x %02x.\n", - i, - pAC->Rlmt.Port[i].Root.Id[0], - pAC->Rlmt.Port[i].Root.Id[1], - pAC->Rlmt.Port[i].Root.Id[2], - pAC->Rlmt.Port[i].Root.Id[3], - pAC->Rlmt.Port[i].Root.Id[4], - pAC->Rlmt.Port[i].Root.Id[5], - pAC->Rlmt.Port[i].Root.Id[6], - pAC->Rlmt.Port[i].Root.Id[7])) - - if (!pAC->Rlmt.RootIdSet) { - pAC->Rlmt.Root = pAC->Rlmt.Port[i].Root; - pAC->Rlmt.RootIdSet = SK_TRUE; + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_DUMP, + ("Root ID %d: %02x %02x %02x %02x %02x %02x %02x %02x.\n", i, + pNet->Port[i]->Root.Id[0], pNet->Port[i]->Root.Id[1], + pNet->Port[i]->Root.Id[2], pNet->Port[i]->Root.Id[3], + pNet->Port[i]->Root.Id[4], pNet->Port[i]->Root.Id[5], + pNet->Port[i]->Root.Id[6], pNet->Port[i]->Root.Id[7])) + + if (!pNet->RootIdSet) { + pNet->Root = pNet->Port[i]->Root; + pNet->RootIdSet = SK_TRUE; continue; } for (j = 0; j < 8; j ++) { - Equal &= pAC->Rlmt.Port[i].Root.Id[j] == - pAC->Rlmt.Root.Id[j]; + Equal &= pNet->Port[i]->Root.Id[j] == pNet->Root.Id[j]; if (!Equal) { break; } } if (!Equal) { - SK_ERR_LOG( - pAC, - SK_ERRCL_COMM, - SKERR_RLMT_E005, - SKERR_RLMT_E005_MSG); -#ifdef SK_PNMI_EVT_SEGMENTATION - SkEventQueue( - pAC, - SKGE_PNMI, - SK_PNMI_EVT_SEGMENTATION, - Para); -#endif /* SK_PNMI_EVT_SEGMENTATION */ - pAC->Rlmt.CheckingState &= ~SK_RLMT_RCS_REPORT_SEG; + SK_ERR_LOG(pAC, SK_ERRCL_COMM, SKERR_RLMT_E005, SKERR_RLMT_E005_MSG); + Para.Para32[0] = NetIdx; + Para.Para32[1] = (SK_U32)-1; + SkEventQueue(pAC, SKGE_PNMI, SK_PNMI_EVT_RLMT_SEGMENTATION, Para); + + pNet->CheckingState &= ~SK_RLMT_RCS_REPORT_SEG; + + /* 2000-03-06 RA: New. */ + Para.Para32[0] = NetIdx; + Para.Para32[1] = (SK_U32)-1; + SkTimerStart(pAC, IoC, &pNet->SegTimer, SK_RLMT_SEG_TO_VAL, + SKGE_RLMT, SK_RLMT_SEG_TIM, Para); break; } - } + } /* for (i = 0; i < pNet->NumPorts; i++) */ + + /* 2000-03-06 RA: Moved here. */ + /* Segmentation check not running anymore. */ + pNet->CheckingState &= ~SK_RLMT_RCS_SEG; + } /* SkRlmtCheckSeg */ @@ -2417,1005 +2064,1340 @@ * Nothing */ RLMT_STATIC void SkRlmtPortStart( -SK_AC *pAC, /* adapter context */ -SK_IOC IoC, /* I/O context */ -SK_U32 PortIdx) /* event code */ +SK_AC *pAC, /* Adapter Context */ +SK_IOC IoC, /* I/O Context */ +SK_U32 PortNumber) /* Port number */ { SK_EVPARA Para; - pAC->Rlmt.Port[PortIdx].PortState = SK_RLMT_PS_LINK_DOWN; - pAC->Rlmt.Port[PortIdx].PortStarted = SK_TRUE; - pAC->Rlmt.Port[PortIdx].LinkDown = SK_TRUE; - pAC->Rlmt.Port[PortIdx].PortDown = SK_TRUE; - pAC->Rlmt.Port[PortIdx].CheckingState = 0; - pAC->Rlmt.Port[PortIdx].RootIdSet = SK_FALSE; - Para.Para32[0] = PortIdx; + pAC->Rlmt.Port[PortNumber].PortState = SK_RLMT_PS_LINK_DOWN; + pAC->Rlmt.Port[PortNumber].PortStarted = SK_TRUE; + pAC->Rlmt.Port[PortNumber].LinkDown = SK_TRUE; + pAC->Rlmt.Port[PortNumber].PortDown = SK_TRUE; + pAC->Rlmt.Port[PortNumber].CheckingState = 0; + pAC->Rlmt.Port[PortNumber].RootIdSet = SK_FALSE; + Para.Para32[0] = PortNumber; + Para.Para32[1] = (SK_U32)-1; SkEventQueue(pAC, SKGE_HWAC, SK_HWEV_PORT_START, Para); } /* SkRlmtPortStart */ /****************************************************************************** * - * SkRlmtEvent - a PORT- or an RLMT-specific event happened + * SkRlmtEvtPortStartTim - PORT_START_TIM * * Description: - * This routine handles PORT- and RLMT-specific events. + * This routine handles PORT_START_TIM events. * * Context: * runtime, pageable? * may be called after SK_INIT_IO * * Returns: - * 0 + * Nothing */ -int SkRlmtEvent( -SK_AC *pAC, /* adapter context */ -SK_IOC IoC, /* I/O context */ -SK_U32 Event, /* event code */ -SK_EVPARA Para) /* event-specific parameter */ +RLMT_STATIC void SkRlmtEvtPortStartTim( +SK_AC *pAC, /* Adapter Context */ +SK_IOC IoC, /* I/O Context */ +SK_EVPARA Para) /* SK_U32 PortNumber; SK_U32 -1 */ { - SK_U32 i, j; - SK_RLMT_PORT *pRPort; - SK_EVPARA Para2; - SK_MBUF *pMb; - SK_MBUF *pNextMb; - SK_MAC_ADDR *pOldMacAddr; - SK_MAC_ADDR *pNewMacAddr; - SK_U32 Timeout; - SK_U32 NewTimeout; - SK_U32 PrevRlmtMode; - - switch (Event) { - case SK_RLMT_PORTSTART_TIM: /* From RLMT via TIME. */ - SK_DBG_MSG( - pAC, - SK_DBGMOD_RLMT, - SK_DBGCAT_CTRL, - ("SK_RLMT_PORTSTART_TIMEOUT Port %d Event (%d) BEGIN.\n", Para.Para32[0], Event)) - - /* - * Used to start non-preferred ports if the preferred one - * does not come up. - * This timeout needs only be set when starting the first - * (preferred) port. - */ + SK_U32 i; - if (pAC->Rlmt.Port[Para.Para32[0]].LinkDown) { + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_PORTSTART_TIMEOUT Port %d Event BEGIN.\n", Para.Para32[0])) - /* PORT_START failed. */ + if (Para.Para32[1] != (SK_U32)-1) { + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("Bad Parameter.\n")) + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_PORTSTART_TIMEOUT Event EMPTY.\n")) + return; + } - for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) { - if (!pAC->Rlmt.Port[i].PortStarted) { - SkRlmtPortStart(pAC, IoC, i); - } + /* + * Used to start non-preferred ports if the preferred one + * does not come up. + * This timeout needs only be set when starting the first + * (preferred) port. + */ + if (pAC->Rlmt.Port[Para.Para32[0]].LinkDown) { + /* PORT_START failed. */ + for (i = 0; i < pAC->Rlmt.Port[Para.Para32[0]].Net->NumPorts; i++) { + if (!pAC->Rlmt.Port[Para.Para32[0]].Net->Port[i]->PortStarted) { + SkRlmtPortStart(pAC, IoC, + pAC->Rlmt.Port[Para.Para32[0]].Net->Port[i]->PortNumber); } } + } - SK_DBG_MSG( - pAC, - SK_DBGMOD_RLMT, - SK_DBGCAT_CTRL, - ("SK_RLMT_PORTSTART_TIMEOUT Event (%d) END.\n", Event)) - break; + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_PORTSTART_TIMEOUT Event END.\n")) +} /* SkRlmtEvtPortStartTim */ - case SK_RLMT_LINK_UP: /* From SIRQ. */ - SK_DBG_MSG( - pAC, - SK_DBGMOD_RLMT, - SK_DBGCAT_CTRL, - ("SK_RLMT_LINK_UP Port %d Event (%d) BEGIN.\n", - Para.Para32[0], Event)) - - pRPort = &pAC->Rlmt.Port[Para.Para32[0]]; - - if (!pRPort->PortStarted) { - SK_ERR_LOG( - pAC, - SK_ERRCL_SW, - SKERR_RLMT_E008, - SKERR_RLMT_E008_MSG); - - SK_DBG_MSG( - pAC, - SK_DBGMOD_RLMT, - SK_DBGCAT_CTRL, - ("SK_RLMT_LINK_UP Event (%d) EMPTY.\n", Event)) - break; - } - if (!pRPort->LinkDown) { - /* RA;:;: Any better solution? */ +/****************************************************************************** + * + * SkRlmtEvtLinkUp - LINK_UP + * + * Description: + * This routine handles LLINK_UP events. + * + * Context: + * runtime, pageable? + * may be called after SK_INIT_IO + * + * Returns: + * Nothing + */ +RLMT_STATIC void SkRlmtEvtLinkUp( +SK_AC *pAC, /* Adapter Context */ +SK_IOC IoC, /* I/O Context */ +SK_EVPARA Para) /* SK_U32 PortNumber; SK_U32 Undefined */ +{ + SK_U32 i; + SK_RLMT_PORT *pRPort; + SK_EVPARA Para2; - SK_DBG_MSG( - pAC, - SK_DBGMOD_RLMT, - SK_DBGCAT_CTRL, - ("SK_RLMT_LINK_UP Event (%d) EMPTY.\n", Event)) - break; - } + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_LINK_UP Port %d Event BEGIN.\n", Para.Para32[0])) - SkTimerStop(pAC, IoC, &pRPort->UpTimer); - SkTimerStop(pAC, IoC, &pRPort->DownRxTimer); - SkTimerStop(pAC, IoC, &pRPort->DownTxTimer); + pRPort = &pAC->Rlmt.Port[Para.Para32[0]]; + if (!pRPort->PortStarted) { + SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_RLMT_E008, SKERR_RLMT_E008_MSG); - /* Do something if timer already fired? */ + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_LINK_UP Event EMPTY.\n")) + return; + } - pRPort->LinkDown = SK_FALSE; - pRPort->PortState = SK_RLMT_PS_GOING_UP; - pRPort->GuTimeStamp = SkOsGetTime(pAC); - pRPort->BcTimeStamp = 0; - if (pAC->Rlmt.LinksUp == 0) { - SK_HWAC_LINK_LED( - pAC, - IoC, - Para.Para32[0], - SK_LED_ACTIVE); - } - else { - SK_HWAC_LINK_LED( - pAC, - IoC, - Para.Para32[0], - SK_LED_STANDBY); + if (!pRPort->LinkDown) { + /* RA;:;: Any better solution? */ + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_LINK_UP Event EMPTY.\n")) + return; + } + + SkTimerStop(pAC, IoC, &pRPort->UpTimer); + SkTimerStop(pAC, IoC, &pRPort->DownRxTimer); + SkTimerStop(pAC, IoC, &pRPort->DownTxTimer); + + /* Do something if timer already fired? */ + + pRPort->LinkDown = SK_FALSE; + pRPort->PortState = SK_RLMT_PS_GOING_UP; + pRPort->GuTimeStamp = SkOsGetTime(pAC); + pRPort->BcTimeStamp = 0; + pRPort->Net->LinksUp++; + if (pRPort->Net->LinksUp == 1) { + SK_HWAC_LINK_LED(pAC, IoC, Para.Para32[0], SK_LED_ACTIVE); + } + else { + SK_HWAC_LINK_LED(pAC, IoC, Para.Para32[0], SK_LED_STANDBY); + } + + for (i = 0; i < pRPort->Net->NumPorts; i++) { + if (!pRPort->Net->Port[i]->PortStarted) { + SkRlmtPortStart(pAC, IoC, pRPort->Net->Port[i]->PortNumber); } - pAC->Rlmt.LinksUp++; + } - for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) { - if (!pAC->Rlmt.Port[i].PortStarted) { - SkRlmtPortStart(pAC, IoC, i); - } + SkRlmtCheckSwitch(pAC, IoC, pRPort->Net->NetNumber); + + if (pRPort->Net->LinksUp >= 2) { + if (pRPort->Net->RlmtMode & SK_RLMT_CHECK_LOC_LINK) { + /* Build the check chain. */ + SkRlmtBuildCheckChain(pAC, pRPort->Net->NetNumber); } + } - SkRlmtCheckSwitch(pAC, IoC); + /* If the first link comes up, start the periodical RLMT timeout. */ + if (pRPort->Net->NumPorts > 1 && pRPort->Net->LinksUp == 1 && + (pRPort->Net->RlmtMode & SK_RLMT_CHECK_OTHERS) != 0) { + Para2.Para32[0] = pRPort->Net->NetNumber; + Para2.Para32[1] = (SK_U32)-1; + SkTimerStart(pAC, IoC, &pRPort->Net->LocTimer, + pRPort->Net->TimeoutValue, SKGE_RLMT, SK_RLMT_TIM, Para2); + } - if (pAC->Rlmt.LinksUp >= 2) { - if (pAC->Rlmt.RlmtMode & SK_RLMT_CHECK_LOC_LINK) { + Para2 = Para; + Para2.Para32[1] = (SK_U32)-1; + SkTimerStart(pAC, IoC, &pRPort->UpTimer, SK_RLMT_PORTUP_TIM_VAL, + SKGE_RLMT, SK_RLMT_PORTUP_TIM, Para2); + + /* Later: if (pAC->Rlmt.RlmtMode & SK_RLMT_CHECK_LOC_LINK) && */ + if ((pRPort->Net->RlmtMode & SK_RLMT_TRANSPARENT) == 0 && + (pRPort->Net->RlmtMode & SK_RLMT_CHECK_LINK) != 0 && + (Para2.pParaPtr = + SkRlmtBuildPacket(pAC, IoC, Para.Para32[0], SK_PACKET_ANNOUNCE, + &pAC->Addr.Port[Para.Para32[0]].CurrentMacAddress, &SkRlmtMcAddr) + ) != NULL) { + /* Send "new" packet to RLMT multicast address. */ + SkEventQueue(pAC, SKGE_DRV, SK_DRV_RLMT_SEND, Para2); + } + + if (pRPort->Net->RlmtMode & SK_RLMT_CHECK_SEG) { + if ((Para2.pParaPtr = + SkRlmtBuildSpanningTreePacket(pAC, IoC, Para.Para32[0])) != NULL) { + pAC->Rlmt.Port[Para.Para32[0]].RootIdSet = SK_FALSE; + pRPort->Net->CheckingState |= + SK_RLMT_RCS_SEG | SK_RLMT_RCS_REPORT_SEG; - /* Build the check chain. */ + SkEventQueue(pAC, SKGE_DRV, SK_DRV_RLMT_SEND, Para2); - SkRlmtBuildCheckChain(pAC); - } + Para.Para32[1] = (SK_U32)-1; + SkTimerStart(pAC, IoC, &pRPort->Net->SegTimer, + SK_RLMT_SEG_TO_VAL, SKGE_RLMT, SK_RLMT_SEG_TIM, Para); } + } - /* - * If the first link comes up, start the periodical - * RLMT timeout. - */ + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_LINK_UP Event END.\n")) +} /* SkRlmtEvtLinkUp */ - if (pAC->GIni.GIMacsFound > 1 && pAC->Rlmt.LinksUp == 1 && - (pAC->Rlmt.RlmtMode & SK_RLMT_CHECK_OTHERS)) { - SkTimerStart( - pAC, - IoC, - &pAC->Rlmt.LocTimer, - pAC->Rlmt.TimeoutValue, - SKGE_RLMT, - SK_RLMT_TIM, - Para); - } - - SkTimerStart( - pAC, - IoC, - &pRPort->UpTimer, - SK_RLMT_PORTUP_TIM_VAL, - SKGE_RLMT, - SK_RLMT_PORTUP_TIM, - Para); - /* - * Later: - * if (pAC->Rlmt.RlmtMode & SK_RLMT_CHECK_LOC_LINK) && - */ +/****************************************************************************** + * + * SkRlmtEvtPortUpTim - PORT_UP_TIM + * + * Description: + * This routine handles PORT_UP_TIM events. + * + * Context: + * runtime, pageable? + * may be called after SK_INIT_IO + * + * Returns: + * Nothing + */ +RLMT_STATIC void SkRlmtEvtPortUpTim( +SK_AC *pAC, /* Adapter Context */ +SK_IOC IoC, /* I/O Context */ +SK_EVPARA Para) /* SK_U32 PortNumber; SK_U32 -1 */ +{ + SK_RLMT_PORT *pRPort; - if ((pAC->Rlmt.RlmtMode & SK_RLMT_CHECK_LINK) && - (Para2.pParaPtr = SkRlmtBuildPacket( - pAC, - IoC, - Para.Para32[0], - SK_PACKET_ANNOUNCE, - &pAC->Addr.Port[Para.Para32[0]].CurrentMacAddress, - &SkRlmtMcAddr) - ) != NULL) { + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_PORTUP_TIM Port %d Event BEGIN.\n", Para.Para32[0])) - /* Send "new" packet to RLMT multicast address. */ + if (Para.Para32[1] != (SK_U32)-1) { + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("Bad Parameter.\n")) + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_PORTUP_TIM Event EMPTY.\n")) + return; + } - SkEventQueue(pAC, SKGE_DRV, SK_DRV_RLMT_SEND, Para2); - } + pRPort = &pAC->Rlmt.Port[Para.Para32[0]]; + if (pRPort->LinkDown || (pRPort->PortState == SK_RLMT_PS_UP)) { + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_PORTUP_TIM Port %d Event EMPTY.\n", Para.Para32[0])) + return; + } - if (pAC->Rlmt.RlmtMode & SK_RLMT_CHECK_SEG) { - if ((Para2.pParaPtr = - SkRlmtBuildSpanningTreePacket( - pAC, - IoC, - Para.Para32[0]) - ) != NULL) { - - pAC->Rlmt.Port[Para.Para32[0]].RootIdSet = - SK_FALSE; - pAC->Rlmt.CheckingState |= - SK_RLMT_RCS_SEG | - SK_RLMT_RCS_REPORT_SEG; - - SkEventQueue( - pAC, - SKGE_DRV, - SK_DRV_RLMT_SEND, - Para2); - - SkTimerStart( - pAC, - IoC, - &pAC->Rlmt.SegTimer, - SK_RLMT_SEG_TO_VAL, - SKGE_RLMT, - SK_RLMT_SEG_TIM, - Para); - } + pRPort->PortDown = SK_FALSE; + pRPort->PortState = SK_RLMT_PS_UP; + pRPort->Net->PortsUp++; + if (pRPort->Net->RlmtState != SK_RLMT_RS_INIT) { + if (pAC->Rlmt.NumNets <= 1) { + SkRlmtCheckSwitch(pAC, IoC, pRPort->Net->NetNumber); } + SkEventQueue(pAC, SKGE_PNMI, SK_PNMI_EVT_RLMT_PORT_UP, Para); + } - SK_DBG_MSG( - pAC, - SK_DBGMOD_RLMT, - SK_DBGCAT_CTRL, - ("SK_RLMT_LINK_UP Event (%d) END.\n", Event)) - break; + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_PORTUP_TIM Event END.\n")) +} /* SkRlmtEvtPortUpTim */ - case SK_RLMT_PORTUP_TIM: /* From RLMT via TIME. */ - SK_DBG_MSG( - pAC, - SK_DBGMOD_RLMT, - SK_DBGCAT_CTRL, - ("SK_RLMT_PORTUP_TIM Port %d Event (%d) BEGIN.\n", Para.Para32[0], Event)) - - pRPort = &pAC->Rlmt.Port[Para.Para32[0]]; - - if (pRPort->LinkDown || (pRPort->PortState == SK_RLMT_PS_UP)) { - SK_DBG_MSG( - pAC, - SK_DBGMOD_RLMT, - SK_DBGCAT_CTRL, - ("SK_RLMT_PORTUP_TIM Port %d Event (%d) EMPTY.\n", - Para.Para32[0], - Event)) - break; - } - pRPort->PortDown = SK_FALSE; - pRPort->PortState = SK_RLMT_PS_UP; - pAC->Rlmt.PortsUp++; +/****************************************************************************** + * + * SkRlmtEvtPortDownTim - PORT_DOWN_* + * + * Description: + * This routine handles PORT_DOWN_* events. + * + * Context: + * runtime, pageable? + * may be called after SK_INIT_IO + * + * Returns: + * Nothing + */ +RLMT_STATIC void SkRlmtEvtPortDownX( +SK_AC *pAC, /* Adapter Context */ +SK_IOC IoC, /* I/O Context */ +SK_U32 Event, /* Event code */ +SK_EVPARA Para) /* SK_U32 PortNumber; SK_U32 -1 */ +{ + SK_RLMT_PORT *pRPort; + + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_PORTDOWN* Port %d Event (%d) BEGIN.\n", + Para.Para32[0], Event)) + + if (Para.Para32[1] != (SK_U32)-1) { + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("Bad Parameter.\n")) + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_PORTDOWN* Event EMPTY.\n")) + return; + } - if (pAC->Rlmt.RlmtState != SK_RLMT_RS_INIT) { - SkRlmtCheckSwitch(pAC, IoC); + pRPort = &pAC->Rlmt.Port[Para.Para32[0]]; + if (!pRPort->PortStarted || (Event == SK_RLMT_PORTDOWN_TX_TIM && + !(pRPort->CheckingState & SK_RLMT_PCS_TX))) { + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_PORTDOWN* Event (%d) EMPTY.\n", Event)) + return; + } + + /* Stop port's timers. */ + SkTimerStop(pAC, IoC, &pRPort->UpTimer); + SkTimerStop(pAC, IoC, &pRPort->DownRxTimer); + SkTimerStop(pAC, IoC, &pRPort->DownTxTimer); - SkEventQueue( - pAC, - SKGE_PNMI, - SK_PNMI_EVT_RLMT_PORT_UP, - Para); - } + if (pRPort->PortState != SK_RLMT_PS_LINK_DOWN) { + pRPort->PortState = SK_RLMT_PS_DOWN; + } - SK_DBG_MSG( - pAC, - SK_DBGMOD_RLMT, - SK_DBGCAT_CTRL, - ("SK_RLMT_PORTUP_TIM Event (%d) END.\n", Event)) - break; + if (!pRPort->PortDown) { + pRPort->Net->PortsUp--; + pRPort->PortDown = SK_TRUE; + SkEventQueue(pAC, SKGE_PNMI, SK_PNMI_EVT_RLMT_PORT_DOWN, Para); + } - case SK_RLMT_PORTDOWN: /* From RLMT. */ - case SK_RLMT_PORTDOWN_RX_TIM: /* From RLMT via TIME. */ - case SK_RLMT_PORTDOWN_TX_TIM: /* From RLMT via TIME. */ - SK_DBG_MSG( - pAC, - SK_DBGMOD_RLMT, - SK_DBGCAT_CTRL, - ("SK_RLMT_PORTDOWN* Port %d Event (%d) BEGIN.\n", Para.Para32[0], Event)) - - pRPort = &pAC->Rlmt.Port[Para.Para32[0]]; - - if (!pRPort->PortStarted || - (Event == SK_RLMT_PORTDOWN_TX_TIM && - !(pRPort->CheckingState & SK_RLMT_PCS_TX))) { - SK_DBG_MSG( - pAC, - SK_DBGMOD_RLMT, - SK_DBGCAT_CTRL, - ("SK_RLMT_PORTDOWN* Event (%d) EMPTY.\n", Event)) - break; + pRPort->PacketsPerTimeSlot = 0; + /* pRPort->DataPacketsPerTimeSlot = 0; */ + pRPort->BpduPacketsPerTimeSlot = 0; + + /* + * RA;:;: To be checked: + * - actions at RLMT_STOP: We should not switch anymore. + */ + if (pRPort->Net->RlmtState != SK_RLMT_RS_INIT) { + if (Para.Para32[0] == + pRPort->Net->Port[pRPort->Net->ActivePort]->PortNumber) { + /* Active Port went down. */ + SkRlmtCheckSwitch(pAC, IoC, pRPort->Net->NetNumber); } - /* Stop port's timers. */ + } - SkTimerStop(pAC, IoC, &pRPort->UpTimer); - SkTimerStop(pAC, IoC, &pRPort->DownRxTimer); - SkTimerStop(pAC, IoC, &pRPort->DownTxTimer); + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_PORTDOWN* Event (%d) END.\n", Event)) +} /* SkRlmtEvtPortDownX */ - if (pRPort->PortState != SK_RLMT_PS_LINK_DOWN) { - pRPort->PortState = SK_RLMT_PS_DOWN; - } - if (!pRPort->PortDown) { - pAC->Rlmt.PortsUp--; - pRPort->PortDown = SK_TRUE; +/****************************************************************************** + * + * SkRlmtEvtLinkDown - LINK_DOWN + * + * Description: + * This routine handles LINK_DOWN events. + * + * Context: + * runtime, pageable? + * may be called after SK_INIT_IO + * + * Returns: + * Nothing + */ +RLMT_STATIC void SkRlmtEvtLinkDown( +SK_AC *pAC, /* Adapter Context */ +SK_IOC IoC, /* I/O Context */ +SK_EVPARA Para) /* SK_U32 PortNumber; SK_U32 Undefined */ +{ + SK_RLMT_PORT *pRPort; - SkEventQueue( - pAC, - SKGE_PNMI, - SK_PNMI_EVT_RLMT_PORT_DOWN, - Para); + pRPort = &pAC->Rlmt.Port[Para.Para32[0]]; + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_LINK_DOWN Port %d Event BEGIN.\n", Para.Para32[0])) + + if (!pAC->Rlmt.Port[Para.Para32[0]].LinkDown) { + pRPort->Net->LinksUp--; + pRPort->LinkDown = SK_TRUE; + pRPort->PortState = SK_RLMT_PS_LINK_DOWN; + SK_HWAC_LINK_LED(pAC, IoC, Para.Para32[0], SK_LED_OFF); + + if ((pRPort->Net->RlmtMode & SK_RLMT_CHECK_LOC_LINK) != 0) { + /* Build the check chain. */ + SkRlmtBuildCheckChain(pAC, pRPort->Net->NetNumber); } - pRPort->PacketsPerTimeSlot = 0; - pRPort->DataPacketsPerTimeSlot = 0; - pRPort->BpduPacketsPerTimeSlot = 0; -#if 0 - pRPort->RlmtChksPerTimeSlot = 0; - pRPort->RlmtAcksPerTimeSlot = 0; -#endif /* 0 */ + /* Ensure that port is marked down. */ + Para.Para32[1] = -1; + (void)SkRlmtEvent(pAC, IoC, SK_RLMT_PORTDOWN, Para); + } - /* - * RA;:;: To be checked: - * - actions at RLMT_STOP: We should not switch anymore. - */ + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_LINK_DOWN Event END.\n")) +} /* SkRlmtEvtLinkDown */ + + +/****************************************************************************** + * + * SkRlmtEvtPortAddr - PORT_ADDR + * + * Description: + * This routine handles PORT_ADDR events. + * + * Context: + * runtime, pageable? + * may be called after SK_INIT_IO + * + * Returns: + * Nothing + */ +RLMT_STATIC void SkRlmtEvtPortAddr( +SK_AC *pAC, /* Adapter Context */ +SK_IOC IoC, /* I/O Context */ +SK_EVPARA Para) /* SK_U32 PortNumber; SK_U32 -1 */ +{ + SK_U32 i, j; + SK_RLMT_PORT *pRPort; + SK_MAC_ADDR *pOldMacAddr; + SK_MAC_ADDR *pNewMacAddr; - if (pAC->Rlmt.RlmtState != SK_RLMT_RS_INIT) { - if (Para.Para32[0] == pAC->Rlmt.MacActive) { + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_PORT_ADDR Port %d Event BEGIN.\n", Para.Para32[0])) - /* Active Port went down. */ + if (Para.Para32[1] != (SK_U32)-1) { + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("Bad Parameter.\n")) + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_PORT_ADDR Event EMPTY.\n")) + return; + } - SkRlmtCheckSwitch(pAC, IoC); + /* Port's physical MAC address changed. */ + pOldMacAddr = &pAC->Addr.Port[Para.Para32[0]].PreviousMacAddress; + pNewMacAddr = &pAC->Addr.Port[Para.Para32[0]].CurrentMacAddress; + + /* + * NOTE: This is not scalable for solutions where ports are + * checked remotely. There, we need to send an RLMT + * address change packet - and how do we ensure delivery? + */ + for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) { + pRPort = &pAC->Rlmt.Port[i]; + for (j = 0; j < pRPort->PortsChecked; j++) { + if (SK_ADDR_EQUAL( + pRPort->PortCheck[j].CheckAddr.a, pOldMacAddr->a)) { + pRPort->PortCheck[j].CheckAddr = *pNewMacAddr; } } + } - SK_DBG_MSG( - pAC, - SK_DBGMOD_RLMT, - SK_DBGCAT_CTRL, - ("SK_RLMT_PORTDOWN* Event (%d) END.\n", Event)) - break; + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_PORT_ADDR Event END.\n")) +} /* SkRlmtEvtPortAddr */ - case SK_RLMT_LINK_DOWN: /* From SIRQ. */ - SK_DBG_MSG( - pAC, - SK_DBGMOD_RLMT, - SK_DBGCAT_CTRL, - ("SK_RLMT_LINK_DOWN Port %d Event (%d) BEGIN.\n", - Para.Para32[0], Event)) - - if (!pAC->Rlmt.Port[Para.Para32[0]].LinkDown) { - pAC->Rlmt.LinksUp--; - pAC->Rlmt.Port[Para.Para32[0]].LinkDown = SK_TRUE; - pAC->Rlmt.Port[Para.Para32[0]].PortState = - SK_RLMT_PS_LINK_DOWN; - SK_HWAC_LINK_LED( - pAC, - IoC, - Para.Para32[0], - SK_LED_OFF); - - if (pAC->Rlmt.RlmtMode & SK_RLMT_CHECK_LOC_LINK) { - - /* Build the check chain. */ - - SkRlmtBuildCheckChain(pAC); - } - - /* Ensure that port is marked down. */ - - (void)SkRlmtEvent( - pAC, - IoC, - SK_RLMT_PORTDOWN, - Para); - } - - SK_DBG_MSG( - pAC, - SK_DBGMOD_RLMT, - SK_DBGCAT_CTRL, - ("SK_RLMT_LINK_DOWN Event (%d) END.\n", Event)) - break; - case SK_RLMT_PORT_ADDR: /* From ADDR. */ - SK_DBG_MSG( - pAC, - SK_DBGMOD_RLMT, - SK_DBGCAT_CTRL, - ("SK_RLMT_PORT_ADDR Port %d Event (%d) BEGIN.\n", Para.Para32[0], Event)) - - /* Port's physical MAC address changed. */ - - pOldMacAddr = - &pAC->Addr.Port[Para.Para32[0]].PreviousMacAddress; - pNewMacAddr = - &pAC->Addr.Port[Para.Para32[0]].CurrentMacAddress; +/****************************************************************************** + * + * SkRlmtEvtStart - START + * + * Description: + * This routine handles START events. + * + * Context: + * runtime, pageable? + * may be called after SK_INIT_IO + * + * Returns: + * Nothing + */ +RLMT_STATIC void SkRlmtEvtStart( +SK_AC *pAC, /* Adapter Context */ +SK_IOC IoC, /* I/O Context */ +SK_EVPARA Para) /* SK_U32 NetNumber; SK_U32 -1 */ +{ + SK_EVPARA Para2; + SK_U32 PortIdx; + SK_U32 PortNumber; - /* - * NOTE: This is not scalable for solutions where ports are - * checked remotely. There, we need to send an RLMT - * address change packet - and how do we ensure delivery? - */ + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_START Net %d Event BEGIN.\n", Para.Para32[0])) - for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) { - pRPort = &pAC->Rlmt.Port[i]; - for (j = 0; j < pRPort->PortsChecked; j++) { - if (SK_ADDR_EQUAL( - pRPort->PortCheck[j].CheckAddr.a, - pOldMacAddr->a)) { - pRPort->PortCheck[j].CheckAddr = - *pNewMacAddr; - } - } - } + if (Para.Para32[1] != (SK_U32)-1) { + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("Bad Parameter.\n")) + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_START Event EMPTY.\n")) + return; + } - SK_DBG_MSG( - pAC, - SK_DBGMOD_RLMT, - SK_DBGCAT_CTRL, - ("SK_RLMT_PORT_ADDR Event (%d) END.\n", Event)) - break; + if (Para.Para32[0] >= pAC->Rlmt.NumNets) { + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("Bad NetNumber %d.\n", Para.Para32[0])) + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_START Event EMPTY.\n")) + return; + } - /* ----- RLMT events ----- */ + if (pAC->Rlmt.Net[Para.Para32[0]].RlmtState != SK_RLMT_RS_INIT) { + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_START Event EMPTY.\n")) + return; + } - case SK_RLMT_START: /* From DRV. */ - SK_DBG_MSG( - pAC, - SK_DBGMOD_RLMT, - SK_DBGCAT_CTRL, - ("SK_RLMT_START Event (%d) BEGIN.\n", Event)) - - if (pAC->Rlmt.RlmtState != SK_RLMT_RS_INIT) { - SK_DBG_MSG( - pAC, - SK_DBGMOD_RLMT, - SK_DBGCAT_CTRL, - ("SK_RLMT_START Event (%d) EMPTY.\n", Event)) - break; - } + if (pAC->Rlmt.NetsStarted >= pAC->Rlmt.NumNets) { + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("All nets should have been started.\n")) + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_START Event EMPTY.\n")) + return; + } - if (pAC->Rlmt.PrefPort >= (SK_U32)pAC->GIni.GIMacsFound) { - SK_ERR_LOG( - pAC, - SK_ERRCL_SW, - SKERR_RLMT_E009, - SKERR_RLMT_E009_MSG); - - /* Change PrefPort to internal default. */ - - Para.Para32[0] = 0xFFFFFFFF; - (void)SkRlmtEvent( - pAC, - IoC, - SK_RLMT_PREFPORT_CHANGE, - Para); - } -#if 0 - if (pAC->GIni.GIMacsFound == 1 && - pAC->Rlmt.RlmtMode != SK_RLMT_CHECK_LINK) { - Para.Para32[0] = SK_RLMT_CHECK_LINK; - (void)SkRlmtEvent( - pAC, - IoC, - SK_RLMT_MODE_CHANGE, - Para); - } -#endif /* 0 */ - pAC->Rlmt.LinksUp = 0; - pAC->Rlmt.PortsUp = 0; - pAC->Rlmt.CheckingState = 0; - pAC->Rlmt.RlmtState = SK_RLMT_RS_NET_DOWN; - - SkRlmtPortStart(pAC, IoC, pAC->Rlmt.PrefPort); - - /* Start Timer (for first port only). */ - - Para2.Para32[0] = pAC->Rlmt.PrefPort; - SkTimerStart( - pAC, - IoC, - &pAC->Rlmt.Port[pAC->Rlmt.PrefPort].UpTimer, - SK_RLMT_PORTSTART_TIM_VAL, - SKGE_RLMT, - SK_RLMT_PORTSTART_TIM, - Para2); - - SK_DBG_MSG( - pAC, - SK_DBGMOD_RLMT, - SK_DBGCAT_CTRL, - ("SK_RLMT_START Event (%d) END.\n", Event)) - break; + if (pAC->Rlmt.Net[Para.Para32[0]].PrefPort >= + pAC->Rlmt.Net[Para.Para32[0]].NumPorts) { + SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_RLMT_E009, SKERR_RLMT_E009_MSG); - case SK_RLMT_STOP: /* From DRV. */ - SK_DBG_MSG( - pAC, - SK_DBGMOD_RLMT, - SK_DBGCAT_CTRL, - ("SK_RLMT_STOP Event (%d) BEGIN.\n", Event)) - - if (pAC->Rlmt.RlmtState == SK_RLMT_RS_INIT) { - SK_DBG_MSG( - pAC, - SK_DBGMOD_RLMT, - SK_DBGCAT_CTRL, - ("SK_RLMT_STOP Event (%d) EMPTY.\n", Event)) - break; - } + /* Change PrefPort to internal default. */ + Para2.Para32[0] = 0xFFFFFFFF; + Para2.Para32[1] = Para.Para32[0]; + (void)SkRlmtEvent(pAC, IoC, SK_RLMT_PREFPORT_CHANGE, Para2); + } - /* Stop RLMT timers. */ + PortIdx = pAC->Rlmt.Net[Para.Para32[0]].PrefPort; + PortNumber = pAC->Rlmt.Net[Para.Para32[0]].Port[PortIdx]->PortNumber; - SkTimerStop(pAC, IoC, &pAC->Rlmt.LocTimer); - SkTimerStop(pAC, IoC, &pAC->Rlmt.SegTimer); + pAC->Rlmt.Net[Para.Para32[0]].LinksUp = 0; + pAC->Rlmt.Net[Para.Para32[0]].PortsUp = 0; + pAC->Rlmt.Net[Para.Para32[0]].CheckingState = 0; + pAC->Rlmt.Net[Para.Para32[0]].RlmtState = SK_RLMT_RS_NET_DOWN; - /* Stop Net. */ + /* Start preferred port. */ + SkRlmtPortStart(pAC, IoC, PortNumber); - pAC->Rlmt.RlmtState = SK_RLMT_RS_INIT; - pAC->Rlmt.RootIdSet = SK_FALSE; - Para2.Para32[0] = SK_RLMT_NET_DOWN_FINAL; - SkEventQueue(pAC, SKGE_DRV, SK_DRV_NET_DOWN, Para2); + /* Start Timer (for first port only). */ + Para2.Para32[0] = PortNumber; + Para2.Para32[1] = (SK_U32)-1; + SkTimerStart(pAC, IoC, &pAC->Rlmt.Port[PortNumber].UpTimer, + SK_RLMT_PORTSTART_TIM_VAL, SKGE_RLMT, SK_RLMT_PORTSTART_TIM, Para2); - /* Stop ports. */ + pAC->Rlmt.NetsStarted++; - for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) { - if (pAC->Rlmt.Port[i].PortState != SK_RLMT_PS_INIT) { - SkTimerStop( - pAC, - IoC, - &pAC->Rlmt.Port[i].UpTimer); - SkTimerStop( - pAC, - IoC, - &pAC->Rlmt.Port[i].DownRxTimer); - SkTimerStop( - pAC, - IoC, - &pAC->Rlmt.Port[i].DownTxTimer); - - pAC->Rlmt.Port[i].PortState = SK_RLMT_PS_INIT; - pAC->Rlmt.Port[i].RootIdSet = SK_FALSE; - pAC->Rlmt.Port[i].PortStarted = SK_FALSE; - Para2.Para32[0] = i; - SkEventQueue( - pAC, - SKGE_HWAC, - SK_HWEV_PORT_STOP, - Para2); - } - } + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_START Event END.\n")) +} /* SkRlmtEvtStart */ - SK_DBG_MSG( - pAC, - SK_DBGMOD_RLMT, - SK_DBGCAT_CTRL, - ("SK_RLMT_STOP Event (%d) END.\n", Event)) - break; - case SK_RLMT_TIM: /* From RLMT via TIME. */ -#if 0 - SK_DBG_MSG( - pAC, - SK_DBGMOD_RLMT, - SK_DBGCAT_CTRL, - ("SK_RLMT_TIM Event (%d) BEGIN.\n", Event)) -#endif /* 0 */ +/****************************************************************************** + * + * SkRlmtEvtStop - STOP + * + * Description: + * This routine handles STOP events. + * + * Context: + * runtime, pageable? + * may be called after SK_INIT_IO + * + * Returns: + * Nothing + */ +RLMT_STATIC void SkRlmtEvtStop( +SK_AC *pAC, /* Adapter Context */ +SK_IOC IoC, /* I/O Context */ +SK_EVPARA Para) /* SK_U32 NetNumber; SK_U32 -1 */ +{ + SK_EVPARA Para2; + SK_U32 PortNumber; + SK_U32 i; - if (!(pAC->Rlmt.RlmtMode & SK_RLMT_CHECK_OTHERS) || - pAC->Rlmt.LinksUp == 0) { + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_STOP Net %d Event BEGIN.\n", Para.Para32[0])) - /* - * Mode changed or all links down: - * No more link checking. - */ + if (Para.Para32[1] != (SK_U32)-1) { + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("Bad Parameter.\n")) + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_STOP Event EMPTY.\n")) + return; + } - break; + if (Para.Para32[0] >= pAC->Rlmt.NumNets) { + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("Bad NetNumber %d.\n", Para.Para32[0])) + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_STOP Event EMPTY.\n")) + return; + } + + if (pAC->Rlmt.Net[Para.Para32[0]].RlmtState == SK_RLMT_RS_INIT) { + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_STOP Event EMPTY.\n")) + return; + } + + if (pAC->Rlmt.NetsStarted == 0) { + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("All nets are stopped.\n")) + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_STOP Event EMPTY.\n")) + return; + } + + /* Stop RLMT timers. */ + SkTimerStop(pAC, IoC, &pAC->Rlmt.Net[Para.Para32[0]].LocTimer); + SkTimerStop(pAC, IoC, &pAC->Rlmt.Net[Para.Para32[0]].SegTimer); + + /* Stop net. */ + pAC->Rlmt.Net[Para.Para32[0]].RlmtState = SK_RLMT_RS_INIT; + pAC->Rlmt.Net[Para.Para32[0]].RootIdSet = SK_FALSE; + Para2.Para32[0] = SK_RLMT_NET_DOWN_FINAL; + Para2.Para32[1] = Para.Para32[0]; /* Net# */ + SkEventQueue(pAC, SKGE_DRV, SK_DRV_NET_DOWN, Para2); + + /* Stop ports. */ + for (i = 0; i < pAC->Rlmt.Net[Para.Para32[0]].NumPorts; i++) { + PortNumber = pAC->Rlmt.Net[Para.Para32[0]].Port[i]->PortNumber; + if (pAC->Rlmt.Port[PortNumber].PortState != SK_RLMT_PS_INIT) { + SkTimerStop(pAC, IoC, &pAC->Rlmt.Port[PortNumber].UpTimer); + SkTimerStop(pAC, IoC, &pAC->Rlmt.Port[PortNumber].DownRxTimer); + SkTimerStop(pAC, IoC, &pAC->Rlmt.Port[PortNumber].DownTxTimer); + + pAC->Rlmt.Port[PortNumber].PortState = SK_RLMT_PS_INIT; + pAC->Rlmt.Port[PortNumber].RootIdSet = SK_FALSE; + pAC->Rlmt.Port[PortNumber].PortStarted = SK_FALSE; + Para2.Para32[0] = PortNumber; + Para2.Para32[1] = (SK_U32)-1; + SkEventQueue(pAC, SKGE_HWAC, SK_HWEV_PORT_STOP, Para2); } + } + + pAC->Rlmt.NetsStarted--; + + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_STOP Event END.\n")) +} /* SkRlmtEvtStop */ + + +/****************************************************************************** + * + * SkRlmtEvtTim - TIM + * + * Description: + * This routine handles TIM events. + * + * Context: + * runtime, pageable? + * may be called after SK_INIT_IO + * + * Returns: + * Nothing + */ +RLMT_STATIC void SkRlmtEvtTim( +SK_AC *pAC, /* Adapter Context */ +SK_IOC IoC, /* I/O Context */ +SK_EVPARA Para) /* SK_U32 NetNumber; SK_U32 -1 */ +{ + SK_RLMT_PORT *pRPort; + SK_U32 Timeout; + SK_U32 NewTimeout; + SK_U32 PortNumber; + SK_U32 i; #if 0 - pAC->Rlmt.SwitchCheckCounter--; - if (pAC->Rlmt.SwitchCheckCounter == 0) { - pAC->Rlmt.SwitchCheckCounter; - } + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_TIM Event BEGIN.\n")) #endif /* 0 */ - NewTimeout = SK_RLMT_DEF_TO_VAL; - for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) { - pRPort = &pAC->Rlmt.Port[i]; - if (!pRPort->LinkDown) { - Timeout = SkRlmtCheckPort(pAC, IoC, i); - if (Timeout < NewTimeout) { - NewTimeout = Timeout; - } + if (Para.Para32[1] != (SK_U32)-1) { + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("Bad Parameter.\n")) + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_TIM Event EMPTY.\n")) + return; + } - /* - * This counter should be set to 0 for all - * ports before the first frame is sent in the - * next loop. - */ + if ((pAC->Rlmt.Net[Para.Para32[0]].RlmtMode & SK_RLMT_CHECK_OTHERS) == 0 || + pAC->Rlmt.Net[Para.Para32[0]].LinksUp == 0) { + /* Mode changed or all links down: No more link checking. */ + return; + } - pRPort->PacketsPerTimeSlot = 0; - pRPort->DataPacketsPerTimeSlot = 0; - pRPort->BpduPacketsPerTimeSlot = 0; #if 0 - pRPort->RlmtChksPerTimeSlot = 0; - pRPort->RlmtAcksPerTimeSlot = 0; + pAC->Rlmt.SwitchCheckCounter--; + if (pAC->Rlmt.SwitchCheckCounter == 0) { + pAC->Rlmt.SwitchCheckCounter; + } #endif /* 0 */ + + NewTimeout = SK_RLMT_DEF_TO_VAL; + for (i = 0; i < pAC->Rlmt.Net[Para.Para32[0]].NumPorts; i++) { + PortNumber = pAC->Rlmt.Net[Para.Para32[0]].Port[i]->PortNumber; + pRPort = &pAC->Rlmt.Port[PortNumber]; + if (!pRPort->LinkDown) { + Timeout = SkRlmtCheckPort(pAC, IoC, PortNumber); + if (Timeout < NewTimeout) { + NewTimeout = Timeout; } - } - pAC->Rlmt.TimeoutValue = NewTimeout; - if (pAC->Rlmt.LinksUp > 1) { /* - * If checking remote ports, also send packets if - * (LinksUp == 1) && - * this port checks at least one (remote) port. + * These counters should be set to 0 for all ports before the + * first frame is sent in the next loop. */ + pRPort->PacketsPerTimeSlot = 0; + /* pRPort->DataPacketsPerTimeSlot = 0; */ + pRPort->BpduPacketsPerTimeSlot = 0; + } + } + pAC->Rlmt.Net[Para.Para32[0]].TimeoutValue = NewTimeout; - /* - * Must be new loop, as SkRlmtCheckPort can request to - * check segmentation when e.g. checking the last port. - */ + if (pAC->Rlmt.Net[Para.Para32[0]].LinksUp > 1) { + /* + * If checking remote ports, also send packets if + * (LinksUp == 1) && + * this port checks at least one (remote) port. + */ - for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) { - pRPort = &pAC->Rlmt.Port[i]; - if (!pRPort->LinkDown) { /* !PortDown? */ - SkRlmtSend(pAC, IoC, i); - } + /* + * Must be new loop, as SkRlmtCheckPort can request to + * check segmentation when e.g. checking the last port. + */ + for (i = 0; i < pAC->Rlmt.Net[Para.Para32[0]].NumPorts; i++) { + if (!pAC->Rlmt.Net[Para.Para32[0]].Port[i]->LinkDown) { + SkRlmtSend(pAC, IoC, + pAC->Rlmt.Net[Para.Para32[0]].Port[i]->PortNumber); } } + } - SkTimerStart( - pAC, - IoC, - &pAC->Rlmt.LocTimer, - pAC->Rlmt.TimeoutValue, - SKGE_RLMT, - SK_RLMT_TIM, - Para); - - if (pAC->Rlmt.LinksUp > 1 && - (pAC->Rlmt.RlmtMode & SK_RLMT_CHECK_SEG) && - (pAC->Rlmt.CheckingState & SK_RLMT_RCS_START_SEG)) { - SkTimerStart( - pAC, - IoC, - &pAC->Rlmt.SegTimer, - SK_RLMT_SEG_TO_VAL, - SKGE_RLMT, - SK_RLMT_SEG_TIM, - Para); - pAC->Rlmt.CheckingState &= - ~SK_RLMT_RCS_START_SEG; - pAC->Rlmt.CheckingState |= - SK_RLMT_RCS_SEG | SK_RLMT_RCS_REPORT_SEG; - } + SkTimerStart(pAC, IoC, &pAC->Rlmt.Net[Para.Para32[0]].LocTimer, + pAC->Rlmt.Net[Para.Para32[0]].TimeoutValue, SKGE_RLMT, SK_RLMT_TIM, + Para); + + if (pAC->Rlmt.Net[Para.Para32[0]].LinksUp > 1 && + (pAC->Rlmt.Net[Para.Para32[0]].RlmtMode & SK_RLMT_CHECK_SEG) && + (pAC->Rlmt.Net[Para.Para32[0]].CheckingState & SK_RLMT_RCS_START_SEG)) { + SkTimerStart(pAC, IoC, &pAC->Rlmt.Net[Para.Para32[0]].SegTimer, + SK_RLMT_SEG_TO_VAL, SKGE_RLMT, SK_RLMT_SEG_TIM, Para); + pAC->Rlmt.Net[Para.Para32[0]].CheckingState &= ~SK_RLMT_RCS_START_SEG; + pAC->Rlmt.Net[Para.Para32[0]].CheckingState |= + SK_RLMT_RCS_SEG | SK_RLMT_RCS_REPORT_SEG; + } #if 0 - SK_DBG_MSG( - pAC, - SK_DBGMOD_RLMT, - SK_DBGCAT_CTRL, - ("SK_RLMT_TIM Event (%d) END.\n", Event)) + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_TIM Event END.\n")) #endif /* 0 */ - break; +} /* SkRlmtEvtTim */ - case SK_RLMT_SEG_TIM: - SK_DBG_MSG( - pAC, - SK_DBGMOD_RLMT, - SK_DBGCAT_CTRL, - ("SK_RLMT_SEG_TIM Event (%d) BEGIN.\n", Event)) -#ifdef DEBUG - for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) { - SK_U8 InAddr8[6]; - SK_U16 *InAddr; - SK_ADDR_PORT *pAPort; - - InAddr = (SK_U16 *)&InAddr8[0]; - pAPort = &pAC->Addr.Port[i]; - for (j = 0; - j < pAPort->NextExactMatchRlmt; - j++) { - - /* Get exact match address j from port i. */ - - XM_INADDR(IoC, i, XM_EXM(j), InAddr); - SK_DBG_MSG( - pAC, - SK_DBGMOD_RLMT, - SK_DBGCAT_CTRL, - ("MC address %d on Port %u: %02x %02x %02x %02x %02x %02x -- %02x %02x %02x %02x %02x %02x.\n", - j, - i, - InAddr8[0], - InAddr8[1], - InAddr8[2], - InAddr8[3], - InAddr8[4], - InAddr8[5], - pAPort->Exact[j].a[0], - pAPort->Exact[j].a[1], - pAPort->Exact[j].a[2], - pAPort->Exact[j].a[3], - pAPort->Exact[j].a[4], - pAPort->Exact[j].a[5])) - } +/****************************************************************************** + * + * SkRlmtEvtSegTim - SEG_TIM + * + * Description: + * This routine handles SEG_TIM events. + * + * Context: + * runtime, pageable? + * may be called after SK_INIT_IO + * + * Returns: + * Nothing + */ +RLMT_STATIC void SkRlmtEvtSegTim( +SK_AC *pAC, /* Adapter Context */ +SK_IOC IoC, /* I/O Context */ +SK_EVPARA Para) /* SK_U32 NetNumber; SK_U32 -1 */ +{ +#ifdef XDEBUG + int j; +#endif /* DEBUG */ + + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_SEG_TIM Event BEGIN.\n")) + + if (Para.Para32[1] != (SK_U32)-1) { + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("Bad Parameter.\n")) + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_SEG_TIM Event EMPTY.\n")) + return; + } + +#ifdef xDEBUG + for (j = 0; i < pAC->Rlmt.Net[Para.Para32[0]].NumPorts; j++) { + SK_ADDR_PORT *pAPort; + SK_U32 k; + SK_U16 *InAddr; + SK_U8 InAddr8[6]; + + InAddr = (SK_U16 *)&InAddr8[0]; + pAPort = pAC->Rlmt.Net[Para.Para32[0]].Port[j]->AddrPort; + for (k = 0; k < pAPort->NextExactMatchRlmt; k++) { + /* Get exact match address k from port j. */ + XM_INADDR(IoC, pAC->Rlmt.Net[Para.Para32[0]].Port[j]->PortNumber, + XM_EXM(k), InAddr); + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("MC address %d on Port %u: %02x %02x %02x %02x %02x %02x -- %02x %02x %02x %02x %02x %02x.\n", + k, pAC->Rlmt.Net[Para.Para32[0]].Port[j]->PortNumber, + InAddr8[0], InAddr8[1], InAddr8[2], + InAddr8[3], InAddr8[4], InAddr8[5], + pAPort->Exact[k].a[0], pAPort->Exact[k].a[1], + pAPort->Exact[k].a[2], pAPort->Exact[k].a[3], + pAPort->Exact[k].a[4], pAPort->Exact[k].a[5])) } + } #endif /* DEBUG */ - pAC->Rlmt.CheckingState &= ~SK_RLMT_RCS_SEG; + SkRlmtCheckSeg(pAC, IoC, Para.Para32[0]); - SkRlmtCheckSeg(pAC, IoC); + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_SEG_TIM Event END.\n")) +} /* SkRlmtEvtSegTim */ - SK_DBG_MSG( - pAC, - SK_DBGMOD_RLMT, - SK_DBGCAT_CTRL, - ("SK_RLMT_SEG_TIM Event (%d) END.\n", Event)) - break; - case SK_RLMT_PACKET_RECEIVED: /* From DRV. */ - SK_DBG_MSG( - pAC, - SK_DBGMOD_RLMT, - SK_DBGCAT_CTRL, - ("SK_RLMT_PACKET_RECEIVED Event (%d) BEGIN.\n", Event)) +/****************************************************************************** + * + * SkRlmtEvtPacketRx - PACKET_RECEIVED + * + * Description: + * This routine handles PACKET_RECEIVED events. + * + * Context: + * runtime, pageable? + * may be called after SK_INIT_IO + * + * Returns: + * Nothing + */ +RLMT_STATIC void SkRlmtEvtPacketRx( +SK_AC *pAC, /* Adapter Context */ +SK_IOC IoC, /* I/O Context */ +SK_EVPARA Para) /* SK_MBUF *pMb */ +{ + SK_MBUF *pMb; + SK_MBUF *pNextMb; + SK_U32 NetNumber; + +#if 0 + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_PACKET_RECEIVED Event BEGIN.\n")) +#endif /* 0 */ - /* Should we ignore frames during port switching? */ + /* Should we ignore frames during port switching? */ #ifdef DEBUG - pMb = Para.pParaPtr; - if (pMb == NULL) { - SK_DBG_MSG( - pAC, - SK_DBGMOD_RLMT, - SK_DBGCAT_CTRL, - ("No mbuf.\n")) - } - else if (pMb->pNext != NULL) { - SK_DBG_MSG( - pAC, - SK_DBGMOD_RLMT, - SK_DBGCAT_CTRL, - ("More than one mbuf or pMb->pNext not set.\n")) - } + pMb = Para.pParaPtr; + if (pMb == NULL) { + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, ("No mbuf.\n")) + } + else if (pMb->pNext != NULL) { + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("More than one mbuf or pMb->pNext not set.\n")) + } #endif /* DEBUG */ - for (pMb = Para.pParaPtr; pMb != NULL; pMb = pNextMb) { - pNextMb = pMb->pNext; - pMb->pNext = NULL; + for (pMb = Para.pParaPtr; pMb != NULL; pMb = pNextMb) { + pNextMb = pMb->pNext; + pMb->pNext = NULL; + + NetNumber = pAC->Rlmt.Port[pMb->PortIdx].Net->NetNumber; + if (pAC->Rlmt.Net[NetNumber].RlmtState == SK_RLMT_RS_INIT) { + SkDrvFreeRlmtMbuf(pAC, IoC, pMb); + } + else { SkRlmtPacketReceive(pAC, IoC, pMb); } + } - SK_DBG_MSG( - pAC, - SK_DBGMOD_RLMT, - SK_DBGCAT_CTRL, - ("SK_RLMT_PACKET_RECEIVED Event (%d) END.\n", Event)) - break; +#if 0 + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_PACKET_RECEIVED Event END.\n")) +#endif /* 0 */ +} /* SkRlmtEvtPacketRx */ - case SK_RLMT_STATS_CLEAR: /* From PNMI. */ - SK_DBG_MSG( - pAC, - SK_DBGMOD_RLMT, - SK_DBGCAT_CTRL, - ("SK_RLMT_STATS_CLEAR Event (%d) BEGIN.\n", Event)) - /* Clear statistics for virtual and physical ports. */ +/****************************************************************************** + * + * SkRlmtEvtStatsClear - STATS_CLEAR + * + * Description: + * This routine handles STATS_CLEAR events. + * + * Context: + * runtime, pageable? + * may be called after SK_INIT_IO + * + * Returns: + * Nothing + */ +RLMT_STATIC void SkRlmtEvtStatsClear( +SK_AC *pAC, /* Adapter Context */ +SK_IOC IoC, /* I/O Context */ +SK_EVPARA Para) /* SK_U32 NetNumber; SK_U32 -1 */ +{ + SK_U32 i; + SK_RLMT_PORT *pRPort; + + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_STATS_CLEAR Event BEGIN.\n")) - for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) { - pAC->Rlmt.Port[i].TxHelloCts = 0; - pAC->Rlmt.Port[i].RxHelloCts = 0; - pAC->Rlmt.Port[i].TxSpHelloReqCts = 0; - pAC->Rlmt.Port[i].RxSpHelloCts = 0; - } + if (Para.Para32[1] != (SK_U32)-1) { + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("Bad Parameter.\n")) + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_STATS_CLEAR Event EMPTY.\n")) + return; + } - SK_DBG_MSG( - pAC, - SK_DBGMOD_RLMT, - SK_DBGCAT_CTRL, - ("SK_RLMT_STATS_CLEAR Event (%d) END.\n", Event)) - break; + if (Para.Para32[0] >= pAC->Rlmt.NumNets) { + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("Bad NetNumber %d.\n", Para.Para32[0])) + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_STATS_CLEAR Event EMPTY.\n")) + return; + } + + /* Clear statistics for logical and physical ports. */ + for (i = 0; i < pAC->Rlmt.Net[Para.Para32[0]].NumPorts; i++) { + pRPort = + &pAC->Rlmt.Port[pAC->Rlmt.Net[Para.Para32[0]].Port[i]->PortNumber]; + pRPort->TxHelloCts = 0; + pRPort->RxHelloCts = 0; + pRPort->TxSpHelloReqCts = 0; + pRPort->RxSpHelloCts = 0; + } + + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_STATS_CLEAR Event END.\n")) +} /* SkRlmtEvtStatsClear */ + + +/****************************************************************************** + * + * SkRlmtEvtStatsUpdate - STATS_UPDATE + * + * Description: + * This routine handles STATS_UPDATE events. + * + * Context: + * runtime, pageable? + * may be called after SK_INIT_IO + * + * Returns: + * Nothing + */ +RLMT_STATIC void SkRlmtEvtStatsUpdate( +SK_AC *pAC, /* Adapter Context */ +SK_IOC IoC, /* I/O Context */ +SK_EVPARA Para) /* SK_U32 NetNumber; SK_U32 -1 */ +{ + if (Para.Para32[1] != (SK_U32)-1) { + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("Bad Parameter.\n")) + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_STATS_UPDATE Event EMPTY.\n")) + return; + } + + if (Para.Para32[0] >= pAC->Rlmt.NumNets) { + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("Bad NetNumber %d.\n", Para.Para32[0])) + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_STATS_UPDATE Event EMPTY.\n")) + return; + } - case SK_RLMT_STATS_UPDATE: /* From PNMI. */ #if 0 - SK_DBG_MSG( - pAC, - SK_DBGMOD_RLMT, - SK_DBGCAT_CTRL, - ("SK_RLMT_STATS_UPDATE Event (%d) BEGIN.\n", Event)) - - /* Update statistics. */ - - /* Currently always up-to-date. */ - - SK_DBG_MSG( - pAC, - SK_DBGMOD_RLMT, - SK_DBGCAT_CTRL, - ("SK_RLMT_STATS_UPDATE Event (%d) END.\n", Event)) + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_STATS_UPDATE Event BEGIN.\n")) + + /* Update statistics - currently always up-to-date. */ + + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_STATS_UPDATE Event END.\n")) #endif /* 0 */ - break; +} /* SkRlmtEvtStatsUpdate */ - case SK_RLMT_PREFPORT_CHANGE: /* From PNMI. */ - SK_DBG_MSG( - pAC, - SK_DBGMOD_RLMT, - SK_DBGCAT_CTRL, - ("SK_RLMT_PREFPORT_CHANGE to Port %d Event (%d) BEGIN.\n", Para.Para32[0], Event)) - /* 0xFFFFFFFF == auto-mode. */ +/****************************************************************************** + * + * SkRlmtEvtPrefportChange - PREFPORT_CHANGE + * + * Description: + * This routine handles PREFPORT_CHANGE events. + * + * Context: + * runtime, pageable? + * may be called after SK_INIT_IO + * + * Returns: + * Nothing + */ +RLMT_STATIC void SkRlmtEvtPrefportChange( +SK_AC *pAC, /* Adapter Context */ +SK_IOC IoC, /* I/O Context */ +SK_EVPARA Para) /* SK_U32 PortIndex; SK_U32 NetNumber */ +{ + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_PREFPORT_CHANGE to Port %d Event BEGIN.\n", Para.Para32[0])) + + if (Para.Para32[1] >= pAC->Rlmt.NumNets) { + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("Bad NetNumber %d.\n", Para.Para32[1])) + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_PREFPORT_CHANGE Event EMPTY.\n")) + return; + } - if (Para.Para32[0] == 0xFFFFFFFF) { - pAC->Rlmt.PrefPort = SK_RLMT_DEF_PREF_PORT; - } - else { - if (Para.Para32[0] >= (SK_U32)pAC->GIni.GIMacsFound) { - SK_ERR_LOG( - pAC, - SK_ERRCL_SW, - SKERR_RLMT_E010, - SKERR_RLMT_E010_MSG); - - SK_DBG_MSG( - pAC, - SK_DBGMOD_RLMT, - SK_DBGCAT_CTRL, - ("SK_RLMT_PREFPORT_CHANGE Event (%d) EMPTY.\n", Event)) - break; - } + /* 0xFFFFFFFF == auto-mode. */ + if (Para.Para32[0] == 0xFFFFFFFF) { + pAC->Rlmt.Net[Para.Para32[1]].PrefPort = SK_RLMT_DEF_PREF_PORT; + } + else { + if (Para.Para32[0] >= pAC->Rlmt.Net[Para.Para32[1]].NumPorts) { + SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_RLMT_E010, SKERR_RLMT_E010_MSG); - pAC->Rlmt.PrefPort = Para.Para32[0]; + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_PREFPORT_CHANGE Event EMPTY.\n")) + return; } - pAC->Rlmt.MacPreferred = Para.Para32[0]; + pAC->Rlmt.Net[Para.Para32[1]].PrefPort = Para.Para32[0]; + } - SkRlmtCheckSwitch(pAC, IoC); + pAC->Rlmt.Net[Para.Para32[1]].Preference = Para.Para32[0]; - SK_DBG_MSG( - pAC, - SK_DBGMOD_RLMT, - SK_DBGCAT_CTRL, - ("SK_RLMT_PREFPORT_CHANGE Event (%d) END.\n", Event)) - break; + if (pAC->Rlmt.Net[Para.Para32[1]].RlmtState != SK_RLMT_RS_INIT) { + SkRlmtCheckSwitch(pAC, IoC, Para.Para32[1]); + } - case SK_RLMT_MODE_CHANGE: /* From PNMI. */ - SK_DBG_MSG( - pAC, - SK_DBGMOD_RLMT, - SK_DBGCAT_CTRL, - ("SK_RLMT_MODE_CHANGE Event (%d) BEGIN.\n", Event)) + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_PREFPORT_CHANGE Event END.\n")) +} /* SkRlmtEvtPrefportChange */ - if (pAC->GIni.GIMacsFound < 2) { - pAC->Rlmt.RlmtMode = SK_RLMT_CHECK_LINK; - SK_DBG_MSG( - pAC, - SK_DBGMOD_RLMT, - SK_DBGCAT_CTRL, - ("Forced RLMT mode to CLS on single link adapter.\n")) - SK_DBG_MSG( - pAC, - SK_DBGMOD_RLMT, - SK_DBGCAT_CTRL, - ("SK_RLMT_MODE_CHANGE Event (%d) EMPTY.\n", - Event)) - break; + +/****************************************************************************** + * + * SkRlmtEvtSetNets - SET_NETS + * + * Description: + * This routine handles SET_NETS events. + * + * Context: + * runtime, pageable? + * may be called after SK_INIT_IO + * + * Returns: + * Nothing + */ +RLMT_STATIC void SkRlmtEvtSetNets( +SK_AC *pAC, /* Adapter Context */ +SK_IOC IoC, /* I/O Context */ +SK_EVPARA Para) /* SK_U32 NumNets; SK_U32 -1 */ +{ + int i; + + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_SET_NETS Event BEGIN.\n")) + + if (Para.Para32[1] != (SK_U32)-1) { + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("Bad Parameter.\n")) + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_SET_NETS Event EMPTY.\n")) + return; + } + + if (Para.Para32[0] == 0 || Para.Para32[0] > SK_MAX_NETS || + Para.Para32[0] > (SK_U32)pAC->GIni.GIMacsFound) { + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("Bad number of nets: %d.\n", Para.Para32[0])) + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_SET_NETS Event EMPTY.\n")) + return; + } + + if (Para.Para32[0] == pAC->Rlmt.NumNets) { /* No change. */ + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_SET_NETS Event EMPTY.\n")) + return; + } + + /* Entering and leaving dual mode only allowed while nets are stopped. */ + if (pAC->Rlmt.NetsStarted > 0) { + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("Changing dual mode only allowed while all nets are stopped.\n")) + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_SET_NETS Event EMPTY.\n")) + return; + } + + if (Para.Para32[0] == 1) { + if (pAC->Rlmt.NumNets > 1) { + /* Clear logical MAC addr from second net's active port. */ + (void)SkAddrOverride(pAC, IoC, pAC->Rlmt.Net[1].Port[pAC->Addr. + Net[1].ActivePort]->PortNumber, NULL, SK_ADDR_CLEAR_LOGICAL); + pAC->Rlmt.Net[1].NumPorts = 0; + } + + pAC->Rlmt.NumNets = Para.Para32[0]; + for (i = 0; (SK_U32)i < pAC->Rlmt.NumNets; i++) { + pAC->Rlmt.Net[i].RlmtState = SK_RLMT_RS_INIT; + pAC->Rlmt.Net[i].RootIdSet = SK_FALSE; + pAC->Rlmt.Net[i].Preference = 0xFFFFFFFF; /* "Automatic" */ + pAC->Rlmt.Net[i].PrefPort = SK_RLMT_DEF_PREF_PORT; + /* Just assuming. */ + pAC->Rlmt.Net[i].ActivePort = pAC->Rlmt.Net[i].PrefPort; + pAC->Rlmt.Net[i].RlmtMode = SK_RLMT_DEF_MODE; + pAC->Rlmt.Net[i].TimeoutValue = SK_RLMT_DEF_TO_VAL; + pAC->Rlmt.Net[i].NetNumber = i; + } + + pAC->Rlmt.Port[1].Net= &pAC->Rlmt.Net[0]; + pAC->Rlmt.Net[0].NumPorts = pAC->GIni.GIMacsFound; + + SkEventQueue(pAC, SKGE_PNMI, SK_PNMI_EVT_RLMT_SET_NETS, Para); + + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("RLMT: Changed to one net with two ports.\n")) + } + else if (Para.Para32[0] == 2) { + pAC->Rlmt.Port[1].Net= &pAC->Rlmt.Net[1]; + pAC->Rlmt.Net[1].NumPorts = pAC->GIni.GIMacsFound - 1; + pAC->Rlmt.Net[0].NumPorts = + pAC->GIni.GIMacsFound - pAC->Rlmt.Net[1].NumPorts; + + pAC->Rlmt.NumNets = Para.Para32[0]; + for (i = 0; (SK_U32)i < pAC->Rlmt.NumNets; i++) { + pAC->Rlmt.Net[i].RlmtState = SK_RLMT_RS_INIT; + pAC->Rlmt.Net[i].RootIdSet = SK_FALSE; + pAC->Rlmt.Net[i].Preference = 0xFFFFFFFF; /* "Automatic" */ + pAC->Rlmt.Net[i].PrefPort = SK_RLMT_DEF_PREF_PORT; + /* Just assuming. */ + pAC->Rlmt.Net[i].ActivePort = pAC->Rlmt.Net[i].PrefPort; + pAC->Rlmt.Net[i].RlmtMode = SK_RLMT_DEF_MODE; + pAC->Rlmt.Net[i].TimeoutValue = SK_RLMT_DEF_TO_VAL; + + pAC->Rlmt.Net[i].NetNumber = i; + } + + /* Set logical MAC addr on second net's active port. */ + (void)SkAddrOverride(pAC, IoC, pAC->Rlmt.Net[1].Port[pAC->Addr. + Net[1].ActivePort]->PortNumber, NULL, SK_ADDR_SET_LOGICAL); + + SkEventQueue(pAC, SKGE_PNMI, SK_PNMI_EVT_RLMT_SET_NETS, Para); + + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("RLMT: Changed to two nets with one port each.\n")) + } + else { + /* Not implemented for more than two nets. */ + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SetNets not implemented for more than two nets.\n")) + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_SET_NETS Event EMPTY.\n")) + return; + } + + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_SET_NETS Event END.\n")) +} /* SkRlmtSetNets */ + + +/****************************************************************************** + * + * SkRlmtEvtModeChange - MODE_CHANGE + * + * Description: + * This routine handles MODE_CHANGE events. + * + * Context: + * runtime, pageable? + * may be called after SK_INIT_IO + * + * Returns: + * Nothing + */ +RLMT_STATIC void SkRlmtEvtModeChange( +SK_AC *pAC, /* Adapter Context */ +SK_IOC IoC, /* I/O Context */ +SK_EVPARA Para) /* SK_U32 NewMode; SK_U32 NetNumber */ +{ + SK_EVPARA Para2; + SK_U32 i; + SK_U32 PrevRlmtMode; + + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_MODE_CHANGE Event BEGIN.\n")) + + if (Para.Para32[1] >= pAC->Rlmt.NumNets) { + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("Bad NetNumber %d.\n", Para.Para32[1])) + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_MODE_CHANGE Event EMPTY.\n")) + return; + } + + Para.Para32[0] |= SK_RLMT_CHECK_LINK; + + if (pAC->Rlmt.Net[Para.Para32[1]].NumPorts < 2 && + Para.Para32[0] != SK_RLMT_MODE_CLS) { + pAC->Rlmt.Net[Para.Para32[1]].RlmtMode = SK_RLMT_MODE_CLS; + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("Forced RLMT mode to CLS on single port net.\n")) + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_MODE_CHANGE Event EMPTY.\n")) + return; + } + + /* Update RLMT mode. */ + PrevRlmtMode = pAC->Rlmt.Net[Para.Para32[1]].RlmtMode; + pAC->Rlmt.Net[Para.Para32[1]].RlmtMode = Para.Para32[0]; + + if ((PrevRlmtMode & SK_RLMT_CHECK_LOC_LINK) != + (pAC->Rlmt.Net[Para.Para32[1]].RlmtMode & SK_RLMT_CHECK_LOC_LINK)) { + /* SK_RLMT_CHECK_LOC_LINK bit changed. */ + if ((PrevRlmtMode & SK_RLMT_CHECK_OTHERS) == 0 && + pAC->Rlmt.Net[Para.Para32[1]].NumPorts > 1 && + pAC->Rlmt.Net[Para.Para32[1]].PortsUp >= 1) { + /* 20001207 RA: Was "PortsUp == 1". */ + Para2.Para32[0] = Para.Para32[1]; + Para2.Para32[1] = (SK_U32)-1; + SkTimerStart(pAC, IoC, &pAC->Rlmt.Net[Para.Para32[1]].LocTimer, + pAC->Rlmt.Net[Para.Para32[1]].TimeoutValue, + SKGE_RLMT, SK_RLMT_TIM, Para2); } + } - /* Update RLMT mode. */ + if ((PrevRlmtMode & SK_RLMT_CHECK_SEG) != + (pAC->Rlmt.Net[Para.Para32[1]].RlmtMode & SK_RLMT_CHECK_SEG)) { + /* SK_RLMT_CHECK_SEG bit changed. */ + for (i = 0; i < pAC->Rlmt.Net[Para.Para32[1]].NumPorts; i++) { + (void)SkAddrMcClear(pAC, IoC, + pAC->Rlmt.Net[Para.Para32[1]].Port[i]->PortNumber, + SK_ADDR_PERMANENT | SK_MC_SW_ONLY); - PrevRlmtMode = pAC->Rlmt.RlmtMode; - pAC->Rlmt.RlmtMode = Para.Para32[0] | SK_RLMT_CHECK_LINK; + /* Add RLMT MC address. */ + (void)SkAddrMcAdd(pAC, IoC, + pAC->Rlmt.Net[Para.Para32[1]].Port[i]->PortNumber, + &SkRlmtMcAddr, SK_ADDR_PERMANENT); - SK_DBG_MSG( - pAC, - SK_DBGMOD_RLMT, - SK_DBGCAT_CTRL, - ("RLMT: Changed Mode to %X.\n", pAC->Rlmt.RlmtMode)) - - if ((PrevRlmtMode & SK_RLMT_CHECK_LOC_LINK) != - (pAC->Rlmt.RlmtMode & SK_RLMT_CHECK_LOC_LINK)) { - if (!(PrevRlmtMode & SK_RLMT_CHECK_OTHERS) && - pAC->GIni.GIMacsFound > 1 && - pAC->Rlmt.PortsUp == 1) { - SkTimerStart( - pAC, - IoC, - &pAC->Rlmt.LocTimer, - pAC->Rlmt.TimeoutValue, - SKGE_RLMT, - SK_RLMT_TIM, - Para); - } - } - - if ((PrevRlmtMode & SK_RLMT_CHECK_SEG) != - (pAC->Rlmt.RlmtMode & SK_RLMT_CHECK_SEG)) { - - for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) { - (void)SkAddrMcClear( - pAC, - IoC, - i, - SK_ADDR_PERMANENT | SK_MC_SW_ONLY); - - /* Add RLMT MC address. */ - - (void)SkAddrMcAdd( - pAC, - IoC, - i, - &SkRlmtMcAddr, - SK_ADDR_PERMANENT); - - if (pAC->Rlmt.RlmtMode & SK_RLMT_CHECK_SEG) { - /* Add BPDU MC address. */ - - (void)SkAddrMcAdd( - pAC, - IoC, - i, - &BridgeMcAddr, - SK_ADDR_PERMANENT); - - if (pAC->Rlmt.RlmtState != - SK_RLMT_RS_INIT) { - if (!pAC->Rlmt.Port[i].LinkDown && - (Para2.pParaPtr = - SkRlmtBuildSpanningTreePacket( - pAC, - IoC, - i) - ) != NULL) { - - pAC->Rlmt.Port[i - ].RootIdSet = - SK_FALSE; - - SkEventQueue( - pAC, - SKGE_DRV, - SK_DRV_RLMT_SEND, - Para2); - } + if ((pAC->Rlmt.Net[Para.Para32[1]].RlmtMode & + SK_RLMT_CHECK_SEG) != 0) { + /* Add BPDU MC address. */ + (void)SkAddrMcAdd(pAC, IoC, + pAC->Rlmt.Net[Para.Para32[1]].Port[i]->PortNumber, + &BridgeMcAddr, SK_ADDR_PERMANENT); + + if (pAC->Rlmt.Net[Para.Para32[1]].RlmtState != SK_RLMT_RS_INIT) { + if (!pAC->Rlmt.Net[Para.Para32[1]].Port[i]->LinkDown && + (Para2.pParaPtr = SkRlmtBuildSpanningTreePacket( + pAC, IoC, i)) != NULL) { + pAC->Rlmt.Net[Para.Para32[1]].Port[i]->RootIdSet = + SK_FALSE; + SkEventQueue(pAC, SKGE_DRV, SK_DRV_RLMT_SEND, Para2); } } - - (void)SkAddrMcUpdate(pAC, IoC, i); } + (void)SkAddrMcUpdate(pAC, IoC, + pAC->Rlmt.Net[Para.Para32[1]].Port[i]->PortNumber); + } /* for ... */ + + if ((pAC->Rlmt.Net[Para.Para32[1]].RlmtMode & SK_RLMT_CHECK_SEG) != 0) { + Para2.Para32[0] = Para.Para32[1]; + Para2.Para32[1] = (SK_U32)-1; + SkTimerStart(pAC, IoC, &pAC->Rlmt.Net[Para.Para32[1]].SegTimer, + SK_RLMT_SEG_TO_VAL, SKGE_RLMT, SK_RLMT_SEG_TIM, Para2); + } + } /* SK_RLMT_CHECK_SEG bit changed. */ + + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, + ("SK_RLMT_MODE_CHANGE Event END.\n")) +} /* SkRlmtEvtModeChange */ - if (pAC->Rlmt.RlmtMode & SK_RLMT_CHECK_SEG) { - SkTimerStart( - pAC, - IoC, - &pAC->Rlmt.SegTimer, - SK_RLMT_SEG_TO_VAL, - SKGE_RLMT, - SK_RLMT_SEG_TIM, - Para); - } - } - SK_DBG_MSG( - pAC, - SK_DBGMOD_RLMT, - SK_DBGCAT_CTRL, - ("SK_RLMT_MODE_CHANGE Event (%d) END.\n", Event)) +/****************************************************************************** + * + * SkRlmtEvent - a PORT- or an RLMT-specific event happened + * + * Description: + * This routine calls subroutines to handle PORT- and RLMT-specific events. + * + * Context: + * runtime, pageable? + * may be called after SK_INIT_IO + * + * Returns: + * 0 + */ +int SkRlmtEvent( +SK_AC *pAC, /* Adapter Context */ +SK_IOC IoC, /* I/O Context */ +SK_U32 Event, /* Event code */ +SK_EVPARA Para) /* Event-specific parameter */ +{ + switch (Event) { + + /* ----- PORT events ----- */ + + case SK_RLMT_PORTSTART_TIM: /* From RLMT via TIME. */ + SkRlmtEvtPortStartTim(pAC, IoC, Para); + break; + case SK_RLMT_LINK_UP: /* From SIRQ. */ + SkRlmtEvtLinkUp(pAC, IoC, Para); + break; + case SK_RLMT_PORTUP_TIM: /* From RLMT via TIME. */ + SkRlmtEvtPortUpTim(pAC, IoC, Para); break; + case SK_RLMT_PORTDOWN: /* From RLMT. */ + case SK_RLMT_PORTDOWN_RX_TIM: /* From RLMT via TIME. */ + case SK_RLMT_PORTDOWN_TX_TIM: /* From RLMT via TIME. */ + SkRlmtEvtPortDownX(pAC, IoC, Event, Para); + break; + case SK_RLMT_LINK_DOWN: /* From SIRQ. */ + SkRlmtEvtLinkDown(pAC, IoC, Para); + break; + case SK_RLMT_PORT_ADDR: /* From ADDR. */ + SkRlmtEvtPortAddr(pAC, IoC, Para); + break; + + /* ----- RLMT events ----- */ + + case SK_RLMT_START: /* From DRV. */ + SkRlmtEvtStart(pAC, IoC, Para); + break; + case SK_RLMT_STOP: /* From DRV. */ + SkRlmtEvtStop(pAC, IoC, Para); + break; + case SK_RLMT_TIM: /* From RLMT via TIME. */ + SkRlmtEvtTim(pAC, IoC, Para); + break; + case SK_RLMT_SEG_TIM: + SkRlmtEvtSegTim(pAC, IoC, Para); + break; + case SK_RLMT_PACKET_RECEIVED: /* From DRV. */ + SkRlmtEvtPacketRx(pAC, IoC, Para); + break; + case SK_RLMT_STATS_CLEAR: /* From PNMI. */ + SkRlmtEvtStatsClear(pAC, IoC, Para); + break; + case SK_RLMT_STATS_UPDATE: /* From PNMI. */ + SkRlmtEvtStatsUpdate(pAC, IoC, Para); + break; + case SK_RLMT_PREFPORT_CHANGE: /* From PNMI. */ + SkRlmtEvtPrefportChange(pAC, IoC, Para); + break; + case SK_RLMT_MODE_CHANGE: /* From PNMI. */ + SkRlmtEvtModeChange(pAC, IoC, Para); + break; + case SK_RLMT_SET_NETS: /* From DRV. */ + SkRlmtEvtSetNets(pAC, IoC, Para); + break; + + /* ----- Unknown events ----- */ default: /* Create error log entry. */ - SK_DBG_MSG( - pAC, - SK_DBGMOD_RLMT, - SK_DBGCAT_CTRL, + SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, ("Unknown RLMT Event %d.\n", Event)) - - SK_ERR_LOG( - pAC, - SK_ERRCL_SW, - SKERR_RLMT_E003, - SKERR_RLMT_E003_MSG); + SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_RLMT_E003, SKERR_RLMT_E003_MSG); break; - } + } /* switch() */ return (0); } /* SkRlmtEvent */ diff -u --recursive --new-file v2.4.6/linux/drivers/net/sk98lin/sktimer.c linux/drivers/net/sk98lin/sktimer.c --- v2.4.6/linux/drivers/net/sk98lin/sktimer.c Fri Sep 15 14:34:19 2000 +++ linux/drivers/net/sk98lin/sktimer.c Wed Jul 4 11:50:39 2001 @@ -1,23 +1,32 @@ /****************************************************************************** * * Name: sktimer.c - * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.12 $ - * Date: $Date: 1999/11/22 13:38:51 $ + * Project: PCI Gigabit Ethernet Adapter + * Version: $Revision: 1.11 $ + * Date: $Date: 1998/12/17 13:24:13 $ * Purpose: High level timer functions. * ******************************************************************************/ /****************************************************************************** * - * (C)Copyright 1998,1999 SysKonnect, + * (C)Copyright 1989-1998 SysKonnect, * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * All Rights Reserved * - * 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 IS UNPUBLISHED PROPRIETARY SOURCE CODE OF SYSKONNECT + * The copyright notice above does not evidence any + * actual or intended publication of such source code. + * + * This Module contains Proprietary Information of SysKonnect + * and should be treated as Confidential. + * + * The information in this file is provided for the exclusive use of + * the licensees of SysKonnect. + * Such users have the right to use, modify, and incorporate this code + * into products for purposes authorized by the license agreement + * provided they include this notice and the associated copyright notice + * with any such product. * The information in this file is provided "AS IS" without warranty. * ******************************************************************************/ @@ -27,9 +36,6 @@ * History: * * $Log: sktimer.c,v $ - * Revision 1.12 1999/11/22 13:38:51 cgoos - * Changed license header to GPL. - * * Revision 1.11 1998/12/17 13:24:13 gklug * fix: restart problem: do NOT destroy timer queue if init 1 is done * @@ -76,7 +82,7 @@ Event queue and dispatcher */ static const char SysKonnectFileId[] = - "$Header: /usr56/projects/ge/schedule/sktimer.c,v 1.12 1999/11/22 13:38:51 cgoos Exp $" ; + "$Header: /usr56/projects/ge/schedule/sktimer.c,v 1.11 1998/12/17 13:24:13 gklug Exp $" ; #include "h/skdrv1st.h" /* Driver Specific Definitions */ #include "h/skdrv2nd.h" /* Adapter Control- and Driver specific Def. */ diff -u --recursive --new-file v2.4.6/linux/drivers/net/sk98lin/skvpd.c linux/drivers/net/sk98lin/skvpd.c --- v2.4.6/linux/drivers/net/sk98lin/skvpd.c Fri Sep 15 14:34:19 2000 +++ linux/drivers/net/sk98lin/skvpd.c Wed Jul 4 11:50:39 2001 @@ -2,15 +2,15 @@ * * Name: skvpd.c * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.27 $ - * Date: $Date: 2000/08/10 11:29:06 $ + * Version: $Revision: 1.26 $ + * Date: $Date: 2000/06/13 08:00:01 $ * Purpose: Shared software to read and write VPD data * ******************************************************************************/ /****************************************************************************** * - * (C)Copyright 1998-2000 SysKonnect, + * (C)Copyright 1998,1999 SysKonnect, * a business unit of Schneider & Koch & Co. Datensysteme GmbH. * * This program is free software; you can redistribute it and/or modify @@ -27,12 +27,6 @@ * History: * * $Log: skvpd.c,v $ - * Revision 1.27 2000/08/10 11:29:06 rassmann - * Editorial changes. - * Preserving 32-bit alignment in structs for the adapter context. - * Removed unused function VpdWriteDword() (#if 0). - * Made VpdReadKeyword() available for SKDIAG only. - * * Revision 1.26 2000/06/13 08:00:01 mkarl * additional cast to avoid compile problems in 64 bit environment * @@ -72,7 +66,7 @@ * * Revision 1.14 1998/10/28 07:20:38 gklug * chg: Interface functions to use IoC as parameter as well - * fix: VpdRead/WriteDWord now returns SK_U32 + * fix: VpdRead/WriteDWord now return SK_U32 * chg: VPD_IN/OUT names conform to SK_IN/OUT * add: usage of VPD_IN/OUT8 macros * add: VpdRead/Write Stream functions to r/w a stream of data @@ -130,7 +124,7 @@ Please refer skvpd.txt for infomation how to include this module */ static const char SysKonnectFileId[] = - "@(#)$Id: skvpd.c,v 1.27 2000/08/10 11:29:06 rassmann Exp $ (C) SK"; + "@(#)$Id: skvpd.c,v 1.26 2000/06/13 08:00:01 mkarl Exp $ (C) SK" ; #include "h/skdrv1st.h" #include "h/sktypes.h" @@ -144,9 +138,9 @@ static SK_VPD_PARA *vpd_find_para( SK_AC *pAC, char *key, - SK_VPD_PARA *p); + SK_VPD_PARA *p) ; #else /* SK_KR_PROTO */ -static SK_VPD_PARA *vpd_find_para(); +static SK_VPD_PARA *vpd_find_para() ; #endif /* SK_KR_PROTO */ /* @@ -161,29 +155,28 @@ SK_IOC IoC, /* IO Context */ int event) /* event to wait for (VPD_READ / VPD_write) completion*/ { - SK_U64 start_time; - SK_U16 state; + SK_U64 start_time ; + SK_U16 state ; SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_CTRL, - ("vpd wait for %s\n",event?"Write":"Read")); - start_time = SkOsGetTime(pAC); + ("vpd wait for %s\n",event?"Write":"Read")) ; + start_time = SkOsGetTime(pAC) ; do { if (SkOsGetTime(pAC) - start_time > SK_TICKS_PER_SEC/16) { - VPD_STOP(pAC,IoC); + VPD_STOP(pAC,IoC) ; SK_DBG_MSG(pAC,SK_DBGMOD_VPD, SK_DBGCAT_FATAL|SK_DBGCAT_ERR, - ("ERROR:vpd wait timeout\n")); - return(1); + ("ERROR:vpd wait timeout\n")) ; + return(1) ; } - VPD_IN16(pAC,IoC,PCI_VPD_ADR_REG,&state); + VPD_IN16(pAC,IoC,PCI_VPD_ADR_REG,&state) ; SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_CTRL, - ("state = %x, event %x\n",state,event)); - } while((int)(state & PCI_VPD_FLAG) == event); + ("state = %x, event %x\n",state,event)) ; + } while((int)(state & PCI_VPD_FLAG) == event) ; - return(0); + return(0) ; } -#ifdef SKDIAG /* * Read the dword at address 'addr' from the VPD EEPROM. @@ -200,31 +193,27 @@ SK_IOC IoC, /* IO Context */ int addr) /* VPD address */ { - SK_U32 Rtv; + SK_U32 Rtv ; /* start VPD read */ SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_CTRL, - ("vpd read dword at 0x%x\n",addr)); - addr &= ~VPD_WRITE; /* ensure the R/W bit is set to read */ + ("vpd read dword at 0x%x\n",addr)) ; + addr &= ~VPD_WRITE ; /* ensure the R/W bit is set to read */ - VPD_OUT16(pAC,IoC,PCI_VPD_ADR_REG, (SK_U16) addr); + VPD_OUT16(pAC,IoC,PCI_VPD_ADR_REG, (SK_U16) addr) ; /* ignore return code here */ - (void)VpdWait(pAC,IoC,VPD_READ); + (void)VpdWait(pAC,IoC,VPD_READ) ; /* Don't swap here, it's a data stream of bytes */ - Rtv = 0; + Rtv = 0 ; - VPD_IN32(pAC,IoC,PCI_VPD_DAT_REG,&Rtv); + VPD_IN32(pAC,IoC,PCI_VPD_DAT_REG,&Rtv) ; SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_CTRL, - ("vpd read dword data = 0x%x\n",Rtv)); - return (Rtv); + ("vpd read dword data = 0x%x\n",Rtv)) ; + return (Rtv) ; } -#endif // SKDIAG - -#if 0 - /* Write the dword 'data' at address 'addr' into the VPD EEPROM, and verify that the data is written. @@ -244,8 +233,8 @@ Returns 0: success - 1: error, I2C transfer does not terminate - 2: error, data verify error + 1: error, I2C transfer does not terminate + 2: error, data verify error */ static int VpdWriteDWord( @@ -257,30 +246,28 @@ /* start VPD write */ /* Don't swap here, it's a data stream of bytes */ SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_CTRL, - ("vpd write dword at addr 0x%x, data = 0x%x\n",addr,data)); - VPD_OUT32(pAC,IoC,PCI_VPD_DAT_REG, (SK_U32)data); + ("vpd write dword at addr 0x%x, data = 0x%x\n",addr,data)) ; + VPD_OUT32(pAC,IoC,PCI_VPD_DAT_REG, (SK_U32)data) ; /* But do it here */ - addr |= VPD_WRITE; + addr |= VPD_WRITE ; - VPD_OUT16(pAC,IoC,PCI_VPD_ADR_REG, (SK_U16)(addr | VPD_WRITE)); + VPD_OUT16(pAC,IoC,PCI_VPD_ADR_REG, (SK_U16)(addr | VPD_WRITE)) ; /* this may take up to 10,6 ms */ if (VpdWait(pAC,IoC,VPD_WRITE)) { SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR, - ("Write Timed Out\n")); - return(1); - }; + ("Write Timed Out\n")) ; + return(1) ; + } ; /* verify data */ if (VpdReadDWord(pAC,IoC,addr) != data) { SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR|SK_DBGCAT_FATAL, - ("Data Verify Error\n")); - return(2); + ("Data Verify Error\n")) ; + return(2) ; } - return(0); -} /* VpdWriteDWord */ - -#endif /* 0 */ + return(0) ; +} /* * Read one Stream of 'len' bytes of VPD data, starting at 'addr' from @@ -295,12 +282,12 @@ int Addr, /* VPD start address */ int Len) /* number of bytes to read / to write */ { - int i; - int j; - SK_U16 AdrReg; - int Rtv; + int i ; + int j ; + SK_U16 AdrReg ; + int Rtv ; SK_U8 * pComp; /* Compare pointer */ - SK_U8 Data; /* Input Data for Compare */ + SK_U8 Data ; /* Input Data for Compare */ /* Init Compare Pointer */ pComp = (SK_U8 *) buf; @@ -312,56 +299,56 @@ * So it is initialized even if only a few bytes * are written. */ - AdrReg = (SK_U16) Addr; - AdrReg &= ~VPD_WRITE; /* READ operation */ + AdrReg = (SK_U16) Addr ; + AdrReg &= ~VPD_WRITE ; /* READ operation */ - VPD_OUT16(pAC,IoC,PCI_VPD_ADR_REG, AdrReg); + VPD_OUT16(pAC,IoC,PCI_VPD_ADR_REG, AdrReg) ; /* ignore return code here */ - Rtv = VpdWait(pAC,IoC,VPD_READ); + Rtv = VpdWait(pAC,IoC,VPD_READ) ; if (Rtv != 0) { - return(i); + return(i) ; } } /* Write current Byte */ VPD_OUT8(pAC,IoC,PCI_VPD_DAT_REG+(i%sizeof(SK_U32)), - *(SK_U8*)buf); + *(SK_U8*)buf) ; if (((i%sizeof(SK_U32)) == 3) || (i == (Len - 1))) { /* New Address needs to be written to VPD_ADDR reg */ - AdrReg = (SK_U16) Addr; + AdrReg = (SK_U16) Addr ; Addr += sizeof(SK_U32); - AdrReg |= VPD_WRITE; /* WRITE operation */ + AdrReg |= VPD_WRITE ; /* WRITE operation */ - VPD_OUT16(pAC,IoC,PCI_VPD_ADR_REG, AdrReg); + VPD_OUT16(pAC,IoC,PCI_VPD_ADR_REG, AdrReg) ; /* Wait for termination */ - Rtv = VpdWait(pAC,IoC,VPD_WRITE); + Rtv = VpdWait(pAC,IoC,VPD_WRITE) ; if (Rtv != 0) { SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR, - ("Write Timed Out\n")); - return(i - (i%sizeof(SK_U32))); + ("Write Timed Out\n")) ; + return(i - (i%sizeof(SK_U32))) ; } /* * Now re-read to verify */ - AdrReg &= ~VPD_WRITE; /* READ operation */ + AdrReg &= ~VPD_WRITE ; /* READ operation */ - VPD_OUT16(pAC,IoC,PCI_VPD_ADR_REG, AdrReg); + VPD_OUT16(pAC,IoC,PCI_VPD_ADR_REG, AdrReg) ; /* Wait for termination */ - Rtv = VpdWait(pAC,IoC,VPD_READ); + Rtv = VpdWait(pAC,IoC,VPD_READ) ; if (Rtv != 0) { SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR, - ("Verify Timed Out\n")); - return(i - (i%sizeof(SK_U32))); + ("Verify Timed Out\n")) ; + return(i - (i%sizeof(SK_U32))) ; } for (j = 0; j <= (int) (i%sizeof(SK_U32)); j ++, pComp ++ ) { - VPD_IN8(pAC,IoC,PCI_VPD_DAT_REG+j, &Data); + VPD_IN8(pAC,IoC,PCI_VPD_DAT_REG+j, &Data) ; if (Data != *pComp) { /* Verify Error */ SK_DBG_MSG(pAC,SK_DBGMOD_VPD, @@ -391,31 +378,31 @@ int Addr, /* VPD start address */ int Len) /* number of bytes to read / to write */ { - int i; - SK_U16 AdrReg; - int Rtv; + int i ; + SK_U16 AdrReg ; + int Rtv ; for (i=0; i < Len; i ++, buf++) { if ((i%sizeof(SK_U32)) == 0) { /* New Address needs to be written to VPD_ADDR reg */ - AdrReg = (SK_U16) Addr; + AdrReg = (SK_U16) Addr ; Addr += sizeof(SK_U32); - AdrReg &= ~VPD_WRITE; /* READ operation */ + AdrReg &= ~VPD_WRITE ; /* READ operation */ - VPD_OUT16(pAC,IoC,PCI_VPD_ADR_REG, AdrReg); + VPD_OUT16(pAC,IoC,PCI_VPD_ADR_REG, AdrReg) ; /* ignore return code here */ - Rtv = VpdWait(pAC,IoC,VPD_READ); + Rtv = VpdWait(pAC,IoC,VPD_READ) ; if (Rtv != 0) { - return(i); + return(i) ; } } VPD_IN8(pAC,IoC,PCI_VPD_DAT_REG+(i%sizeof(SK_U32)), - (SK_U8 *)buf); + (SK_U8 *)buf) ; } - return(Len); + return(Len) ; } /* @@ -432,29 +419,29 @@ int len, /* number of bytes to read / to write */ int dir) /* transfer direction may be VPD_READ or VPD_WRITE */ { - int Rtv; /* Return value */ - int vpd_rom_size; - SK_U32 our_reg2; + int Rtv ; /* Return value */ + int vpd_rom_size ; + SK_U32 our_reg2 ; SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_CTRL, ("vpd %s block, addr = 0x%x, len = %d\n", - dir?"write":"read",addr,len)); + dir?"write":"read",addr,len)) ; if (len == 0) - return (0); + return (0) ; - VPD_IN32(pAC,IoC,PCI_OUR_REG_2,&our_reg2); + VPD_IN32(pAC,IoC,PCI_OUR_REG_2,&our_reg2) ; vpd_rom_size = 256 << ((our_reg2 & PCI_VPD_ROM_SZ) >> 14); if (addr > vpd_rom_size - 4) { SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR|SK_DBGCAT_FATAL, ("Address error: 0x%x, exp. < 0x%x\n", - addr, vpd_rom_size - 4)); - return (0); + addr, vpd_rom_size - 4)) ; + return (0) ; } if (addr + len > vpd_rom_size) { - len = vpd_rom_size - addr; + len = vpd_rom_size - addr ; SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR, - ("Warning: len was cut to %d\n",len)); + ("Warning: len was cut to %d\n",len)) ; } if (dir == VPD_READ) { @@ -463,7 +450,7 @@ Rtv = VpdWriteStream(pAC, IoC, buf, addr, len); } - return (Rtv); + return (Rtv) ; } #ifdef SKDIAG @@ -480,7 +467,7 @@ int addr, /* start reading at the VPD address */ int len) /* number of bytes to read */ { - return (VpdTransferBlock(pAC, IoC, buf, addr, len, VPD_READ)); + return (VpdTransferBlock(pAC, IoC, buf, addr, len, VPD_READ)) ; } /* @@ -495,7 +482,7 @@ int addr, /* start writing at the VPD address */ int len) /* number of bytes to write */ { - return (VpdTransferBlock(pAC, IoC, buf, addr, len, VPD_WRITE)); + return (VpdTransferBlock(pAC, IoC, buf, addr, len, VPD_WRITE)) ; } #endif /* SKDIAG */ @@ -512,64 +499,64 @@ SK_AC *pAC, /* Adapters context */ SK_IOC IoC) /* IO Context */ { - SK_VPD_PARA *r, rp; /* RW or RV */ - int i; - unsigned char x; + SK_VPD_PARA *r, rp ; /* RW or RV */ + int i ; + unsigned char x ; - SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_INIT,("VpdInit .. ")); + SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_INIT,("VpdInit .. ")) ; /* read the VPD data into the VPD buffer */ if (VpdTransferBlock(pAC,IoC,pAC->vpd.vpd_buf,0,VPD_SIZE,VPD_READ) != VPD_SIZE) { SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR, - ("Block Read Error\n")); - return(1); + ("Block Read Error\n")) ; + return(1) ; } /* find the end tag of the RO area */ if (!(r = vpd_find_para(pAC,VPD_RV,&rp))) { SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR | SK_DBGCAT_FATAL, - ("Encoding Error: RV Tag not found\n")); - return (1); + ("Encoding Error: RV Tag not found\n")) ; + return (1) ; } if (r->p_val + r->p_len > pAC->vpd.vpd_buf + VPD_SIZE/2) { SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR | SK_DBGCAT_FATAL, - ("Encoding Error: Invalid VPD struct size\n")); - return (1); + ("Encoding Error: Invalid VPD struct size\n")) ; + return (1) ; } - pAC->vpd.v.vpd_free_ro = r->p_len - 1; + pAC->vpd.v.vpd_free_ro = r->p_len - 1 ; /* test the checksum */ for (i = 0, x = 0; (unsigned)i<=(unsigned)VPD_SIZE/2 - r->p_len; i++) { - x += pAC->vpd.vpd_buf[i]; + x += pAC->vpd.vpd_buf[i] ; } if (x != 0) { /* checksum error */ SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR | SK_DBGCAT_FATAL, - ("VPD Checksum Error\n")); - return (1); + ("VPD Checksum Error\n")) ; + return (1) ; } /* find and check the end tag of the RW area */ if (!(r = vpd_find_para(pAC,VPD_RW,&rp))) { SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR | SK_DBGCAT_FATAL, - ("Encoding Error: RV Tag not found\n")); - return (1); + ("Encoding Error: RV Tag not found\n")) ; + return (1) ; } if (r->p_val < pAC->vpd.vpd_buf + VPD_SIZE/2) { SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR | SK_DBGCAT_FATAL, - ("Encoding Error: Invalid VPD struct size\n")); - return (1); + ("Encoding Error: Invalid VPD struct size\n")) ; + return (1) ; } - pAC->vpd.v.vpd_free_rw = r->p_len; + pAC->vpd.v.vpd_free_rw = r->p_len ; /* everything seems to be ok */ - pAC->vpd.v.vpd_status |= VPD_VALID; + pAC->vpd.v.vpd_status |= VPD_VALID ; SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_INIT, ("done. Free RO = %d, Free RW = %d\n", - pAC->vpd.v.vpd_free_ro, pAC->vpd.v.vpd_free_rw)); + pAC->vpd.v.vpd_free_ro, pAC->vpd.v.vpd_free_rw)) ; - return(0); + return(0) ; } /* @@ -585,62 +572,62 @@ SK_VPD_PARA *p) /* parameter description struct */ { char *v ; /* points to vpd buffer */ - int max; /* Maximum Number of Iterations */ + int max ; /* Maximum Number of Iterations */ - v = pAC->vpd.vpd_buf; - max = 128; + v = pAC->vpd.vpd_buf ; + max = 128 ; SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_CTRL, - ("vpd find para %s .. ",key)); + ("vpd find para %s .. ",key)) ; /* check mandatory resource type ID string (Product Name) */ if (*v != (char) RES_ID) { SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR | SK_DBGCAT_FATAL, - ("Error: 0x%x missing\n",RES_ID)); - return (0); + ("Error: 0x%x missing\n",RES_ID)) ; + return (0) ; } if (strcmp(key,VPD_NAME) == 0) { - p->p_len = VPD_GET_RES_LEN(v); - p->p_val = VPD_GET_VAL(v); + p->p_len = VPD_GET_RES_LEN(v) ; + p->p_val = VPD_GET_VAL(v) ; SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_CTRL, - ("found, len = %d\n",p->p_len)); - return(p); + ("found, len = %d\n",p->p_len)) ; + return(p) ; } - v += 3 + VPD_GET_RES_LEN(v) + 3; - for (;; ) { + v += 3 + VPD_GET_RES_LEN(v) + 3 ; + for ( ; ; ) { if (SK_MEMCMP(key,v,2) == 0) { - p->p_len = VPD_GET_VPD_LEN(v); - p->p_val = VPD_GET_VAL(v); + p->p_len = VPD_GET_VPD_LEN(v) ; + p->p_val = VPD_GET_VAL(v) ; SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_CTRL, - ("found, len = %d\n",p->p_len)); - return (p); + ("found, len = %d\n",p->p_len)) ; + return (p) ; } /* exit when reaching the "RW" Tag or the maximum of itera. */ - max--; + max-- ; if (SK_MEMCMP(VPD_RW,v,2) == 0 || max == 0) { - break; + break ; } if (SK_MEMCMP(VPD_RV,v,2) == 0) { - v += 3 + VPD_GET_VPD_LEN(v) + 3; /* skip VPD-W */ + v += 3 + VPD_GET_VPD_LEN(v) + 3 ; /* skip VPD-W */ } else { - v += 3 + VPD_GET_VPD_LEN(v); + v += 3 + VPD_GET_VPD_LEN(v) ; } SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_CTRL, - ("scanning '%c%c' len = %d\n",v[0],v[1],v[2])); + ("scanning '%c%c' len = %d\n",v[0],v[1],v[2])) ; } #ifdef DEBUG - SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_CTRL,("not found\n")); + SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_CTRL,("not found\n")) ; if (max == 0) { SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR | SK_DBGCAT_FATAL, - ("Key/Len Encoding error\n")); + ("Key/Len Encoding error\n")) ; } #endif - return (0); + return (0) ; } /* @@ -654,24 +641,24 @@ char *end, /* end of memory block to move */ int n) /* number of bytes the memory block has to be moved */ { - char *p; - int i; /* number of byte copied */ + char *p ; + int i ; /* number of byte copied */ if (n == 0) - return; + return ; - i = (int) (end - start + 1); + i = (int) (end - start + 1) ; if (n < 0) { - p = start + n; + p = start + n ; while (i != 0) { - *p++ = *start++; - i--; + *p++ = *start++ ; + i-- ; } } else { - p = end + n; + p = end + n ; while (i != 0) { - *p-- = *end--; - i--; + *p-- = *end-- ; + i-- ; } } } @@ -687,13 +674,13 @@ int len, /* length of the value string */ char *ip) /* inseration point */ { - SK_VPD_KEY *p; + SK_VPD_KEY *p ; - p = (SK_VPD_KEY *) ip; - p->p_key[0] = key[0]; - p->p_key[1] = key[1]; - p->p_len = (unsigned char) len; - SK_MEMCPY(&p->p_val,buf,len); + p = (SK_VPD_KEY *) ip ; + p->p_key[0] = key[0] ; + p->p_key[1] = key[1] ; + p->p_len = (unsigned char) len ; + SK_MEMCPY(&p->p_val,buf,len) ; } /* @@ -707,46 +694,46 @@ SK_AC *pAC, /* common data base */ char *etp) /* end pointer input position */ { - SK_VPD_KEY *p; - unsigned char x; - int i; + SK_VPD_KEY *p ; + unsigned char x ; + int i ; SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_CTRL, - ("vpd modify endtag at 0x%x = '%c%c'\n",etp,etp[0],etp[1])); + ("vpd modify endtag at 0x%x = '%c%c'\n",etp,etp[0],etp[1])) ; - p = (SK_VPD_KEY *) etp; + p = (SK_VPD_KEY *) etp ; if (p->p_key[0] != 'R' || (p->p_key[1] != 'V' && p->p_key[1] != 'W')) { /* something wrong here, encoding error */ SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR | SK_DBGCAT_FATAL, - ("Encoding Error: invalid end tag\n")); - return(1); + ("Encoding Error: invalid end tag\n")) ; + return(1) ; } if (etp > pAC->vpd.vpd_buf + VPD_SIZE/2) { /* create "RW" tag */ - p->p_len = (unsigned char)(pAC->vpd.vpd_buf+VPD_SIZE-etp-3-1); - pAC->vpd.v.vpd_free_rw = (int) p->p_len; - i = pAC->vpd.v.vpd_free_rw; - etp += 3; + p->p_len = (unsigned char)(pAC->vpd.vpd_buf+VPD_SIZE-etp-3-1) ; + pAC->vpd.v.vpd_free_rw = (int) p->p_len ; + i = pAC->vpd.v.vpd_free_rw ; + etp += 3 ; } else { /* create "RV" tag */ - p->p_len = (unsigned char)(pAC->vpd.vpd_buf+VPD_SIZE/2-etp-3); - pAC->vpd.v.vpd_free_ro = (int) p->p_len - 1; + p->p_len = (unsigned char)(pAC->vpd.vpd_buf+VPD_SIZE/2-etp-3) ; + pAC->vpd.v.vpd_free_ro = (int) p->p_len - 1 ; /* setup checksum */ for (i = 0, x = 0; i < VPD_SIZE/2 - p->p_len; i++) { - x += pAC->vpd.vpd_buf[i]; + x += pAC->vpd.vpd_buf[i] ; } - p->p_val = (char) 0 - x; - i = pAC->vpd.v.vpd_free_ro; - etp += 4; + p->p_val = (char) 0 - x ; + i = pAC->vpd.v.vpd_free_ro ; + etp += 4 ; } while (i) { - *etp++ = 0x00; - i--; + *etp++ = 0x00 ; + i-- ; } - return (0); + return (0) ; } /* @@ -771,76 +758,76 @@ int type, /* VPD_RO_KEY or VPD_RW_KEY */ int op) /* operation to do: ADD_KEY or OWR_KEY */ { - SK_VPD_PARA vp; - char *etp; /* end tag position */ - int free; /* remaining space in selected area */ - char *ip; /* input position inside the VPD buffer */ - int rtv; /* return code */ - int head; /* additional haeder bytes to move */ - int found; /* additinoal bytes if the keyword was found */ + SK_VPD_PARA vp ; + char *etp ; /* end tag position */ + int free ; /* remaining space in selected area */ + char *ip ; /* input position inside the VPD buffer */ + int rtv ; /* return code */ + int head ; /* additional haeder bytes to move */ + int found ; /* additinoal bytes if the keyword was found */ SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_CTRL, - ("vpd setup para key = %s, val = %s\n",key,buf)); + ("vpd setup para key = %s, val = %s\n",key,buf)) ; - rtv = 0; - ip = 0; + rtv = 0 ; + ip = 0 ; if (type == VPD_RW_KEY) { /* end tag is "RW" */ - free = pAC->vpd.v.vpd_free_rw; - etp = pAC->vpd.vpd_buf + (VPD_SIZE - free - 1 - 3); + free = pAC->vpd.v.vpd_free_rw ; + etp = pAC->vpd.vpd_buf + (VPD_SIZE - free - 1 - 3) ; } else { /* end tag is "RV" */ - free = pAC->vpd.v.vpd_free_ro; - etp = pAC->vpd.vpd_buf + (VPD_SIZE/2 - free - 4); + free = pAC->vpd.v.vpd_free_ro ; + etp = pAC->vpd.vpd_buf + (VPD_SIZE/2 - free - 4) ; } SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_CTRL, ("Free RO = %d, Free RW = %d\n", - pAC->vpd.v.vpd_free_ro, pAC->vpd.v.vpd_free_rw)); + pAC->vpd.v.vpd_free_ro, pAC->vpd.v.vpd_free_rw)) ; - head = 0; - found = 0; + head = 0 ; + found = 0 ; if (op == OWR_KEY) { if (vpd_find_para(pAC,key,&vp)) { - found = 3; - ip = vp.p_val - 3; - free += vp.p_len + 3; + found = 3 ; + ip = vp.p_val - 3 ; + free += vp.p_len + 3 ; SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_CTRL, - ("Overwrite Key\n")); + ("Overwrite Key\n")) ; } else { - op = ADD_KEY; + op = ADD_KEY ; SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_CTRL, - ("Add Key\n")); + ("Add Key\n")) ; } } if (op == ADD_KEY) { - ip = etp; - vp.p_len = 0; - head = 3; + ip = etp ; + vp.p_len = 0 ; + head = 3 ; } if (len + 3 > free) { if (free < 7) { SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR, ("VPD Buffer Overflow, keyword not written\n")); - return (4); + return (4) ; } /* cut it again */ - len = free - 3; - rtv = 2; + len = free - 3 ; + rtv = 2 ; SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR, - ("VPD Buffer Full, Keyword was cut\n")); + ("VPD Buffer Full, Keyword was cut\n")) ; } - vpd_move_para(ip + vp.p_len + found, etp+2, len-vp.p_len+head); - vpd_insert_key(key, buf, len, ip); + vpd_move_para(ip + vp.p_len + found, etp+2, len-vp.p_len+head) ; + vpd_insert_key(key, buf, len, ip) ; if (vpd_mod_endtag(pAC, etp + len - vp.p_len + head)) { - pAC->vpd.v.vpd_status &= ~VPD_VALID; + pAC->vpd.v.vpd_status &= ~VPD_VALID ; SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR, - ("VPD Encoding Error\n")); - return(6); + ("VPD Encoding Error\n")) ; + return(6) ; } - return (rtv); + return (rtv) ; } @@ -848,7 +835,7 @@ * Read the contents of the VPD EEPROM and copy it to the * VPD buffer if not already done. * - * return: A pointer to the vpd_status structure. The structure contains + * return: A pointer to the vpd_status structure. The structure contain * this fields. */ SK_VPD_STATUS *VpdStat( @@ -856,9 +843,9 @@ SK_IOC IoC) /* IO Context */ { if (!(pAC->vpd.v.vpd_status & VPD_VALID)) { - (void)VpdInit(pAC,IoC); + (void)VpdInit(pAC,IoC) ; } - return(&pAC->vpd.v); + return(&pAC->vpd.v) ; } @@ -891,67 +878,67 @@ int *len, /* buffer length */ int *elements) /* number of keywords returned */ { - char *v; - int n; + char *v ; + int n ; - SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_RX,("list vpd keys .. ")); - *elements = 0; + SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_RX,("list vpd keys .. ")) ; + *elements = 0 ; if (!(pAC->vpd.v.vpd_status & VPD_VALID)) { if (VpdInit(pAC,IoC) != 0 ) { - *len = 0; + *len = 0 ; SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR, - ("VPD Init Error, terminated\n")); - return(6); + ("VPD Init Error, terminated\n")) ; + return(6) ; } } if ((signed)strlen(VPD_NAME) + 1 <= *len) { - v = pAC->vpd.vpd_buf; - strcpy(buf,VPD_NAME); - n = strlen(VPD_NAME) + 1; - buf += n; - *elements = 1; + v = pAC->vpd.vpd_buf ; + strcpy(buf,VPD_NAME) ; + n = strlen(VPD_NAME) + 1 ; + buf += n ; + *elements = 1 ; SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_RX, - ("'%c%c' ",v[0],v[1])); + ("'%c%c' ",v[0],v[1])) ; } else { - *len = 0; + *len = 0 ; SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR, - ("buffer overflow\n")); - return(2); + ("buffer overflow\n")) ; + return(2) ; } - v += 3 + VPD_GET_RES_LEN(v) + 3; - for (;; ) { + v += 3 + VPD_GET_RES_LEN(v) + 3 ; + for ( ; ; ) { /* exit when reaching the "RW" Tag */ if (SK_MEMCMP(VPD_RW,v,2) == 0) { - break; + break ; } if (SK_MEMCMP(VPD_RV,v,2) == 0) { - v += 3 + VPD_GET_VPD_LEN(v) + 3; /* skip VPD-W */ - continue; + v += 3 + VPD_GET_VPD_LEN(v) + 3 ; /* skip VPD-W */ + continue ; } if (n+3 <= *len) { - SK_MEMCPY(buf,v,2); - buf += 2; - *buf++ = '\0'; - n += 3; - v += 3 + VPD_GET_VPD_LEN(v); - *elements += 1; + SK_MEMCPY(buf,v,2) ; + buf += 2 ; + *buf++ = '\0' ; + n += 3 ; + v += 3 + VPD_GET_VPD_LEN(v) ; + *elements += 1 ; SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_RX, - ("'%c%c' ",v[0],v[1])); + ("'%c%c' ",v[0],v[1])) ; } else { - *len = n; + *len = n ; SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR, - ("buffer overflow\n")); - return (2); + ("buffer overflow\n")) ; + return (2) ; } } - SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_RX,("\n")); - *len = n; - return(0); + SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_RX,("\n")) ; + *len = n ; + return(0) ; } @@ -975,34 +962,34 @@ char *buf, /* buffer where to copy the keyword value */ int *len) /* buffer length */ { - SK_VPD_PARA *p, vp; + SK_VPD_PARA *p, vp ; - SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_RX,("vpd read %s .. ",key)); + SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_RX,("vpd read %s .. ",key)) ; if (!(pAC->vpd.v.vpd_status & VPD_VALID)) { if (VpdInit(pAC,IoC) != 0 ) { - *len = 0; + *len = 0 ; SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR, - ("vpd init error\n")); - return(6); + ("vpd init error\n")) ; + return(6) ; } } if ((p = vpd_find_para(pAC,key,&vp))) { if (p->p_len > (*(unsigned *)len)-1) { - p->p_len = *len - 1; + p->p_len = *len - 1 ; } - SK_MEMCPY(buf,p->p_val,p->p_len); - buf[p->p_len] = '\0'; - *len = p->p_len; + SK_MEMCPY(buf,p->p_val,p->p_len) ; + buf[p->p_len] = '\0' ; + *len = p->p_len ; SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_RX, ("%c%c%c%c.., len = %d\n", - buf[0],buf[1],buf[2],buf[3],*len)); + buf[0],buf[1],buf[2],buf[3],*len)) ; } else { - *len = 0; - SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR,("not found\n")); - return (1); + *len = 0 ; + SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR,("not found\n")) ; + return (1) ; } - return (0); + return (0) ; } @@ -1020,9 +1007,9 @@ key[1] < '0' || key[1] > 'Z' || (key[1] > '9' && key[1] < 'A') || strlen(key) != 2) { - return (SK_FALSE); + return (SK_FALSE) ; } - return (SK_TRUE); + return (SK_TRUE) ; } /* @@ -1044,46 +1031,46 @@ char *key, /* keyword to write (allowed values "Yx", "Vx") */ char *buf) /* buffer where the keyword value can be read from */ { - int len; /* lenght of the keyword to write */ - int rtv; /* return code */ - int rtv2; + int len ; /* lenght of the keyword to write */ + int rtv ; /* return code */ + int rtv2 ; SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_TX, - ("vpd write %s = %s\n",key,buf)); + ("vpd write %s = %s\n",key,buf)) ; if ((*key != 'Y' && *key != 'V') || key[1] < '0' || key[1] > 'Z' || (key[1] > '9' && key[1] < 'A') || strlen(key) != 2) { SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR, - ("illegal key tag, keyword not written\n")); - return (5); + ("illegal key tag, keyword not written\n")) ; + return (5) ; } if (!(pAC->vpd.v.vpd_status & VPD_VALID)) { if (VpdInit(pAC,IoC) != 0 ) { SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR, - ("vpd init error\n")); - return(6); + ("vpd init error\n")) ; + return(6) ; } } - rtv = 0; - len = strlen(buf); + rtv = 0 ; + len = strlen(buf) ; if (len > VPD_MAX_LEN) { /* cut it */ - len = VPD_MAX_LEN; - rtv = 2; + len = VPD_MAX_LEN ; + rtv = 2 ; SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR, - ("keyword to long, cut after %d bytes\n",VPD_MAX_LEN)); + ("keyword to long, cut after %d bytes\n",VPD_MAX_LEN)) ; } if ((rtv2 = VpdSetupPara(pAC,key,buf,len,VPD_RW_KEY,OWR_KEY)) != 0) { SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR, - ("vpd write error\n")); - return(rtv2); + ("vpd write error\n")) ; + return(rtv2) ; } - return (rtv); + return (rtv) ; } /* @@ -1103,15 +1090,15 @@ SK_IOC IoC, /* IO Context */ char *key) /* keyword to read (e.g. "MN") */ { - SK_VPD_PARA *p, vp; - char *etp; + SK_VPD_PARA *p, vp ; + char *etp ; - SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_TX,("vpd delete key %s\n",key)); + SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_TX,("vpd delete key %s\n",key)) ; if (!(pAC->vpd.v.vpd_status & VPD_VALID)) { if (VpdInit(pAC,IoC) != 0 ) { SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR, - ("vpd init error\n")); - return(6); + ("vpd init error\n")) ; + return(6) ; } } @@ -1119,27 +1106,27 @@ if (p->p_val < pAC->vpd.vpd_buf + VPD_SIZE/2) { /* try to delete read only keyword */ SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR, - ("cannot delete RO keyword\n")); - return (5); + ("cannot delete RO keyword\n")) ; + return (5) ; } - etp = pAC->vpd.vpd_buf + (VPD_SIZE-pAC->vpd.v.vpd_free_rw-1-3); + etp = pAC->vpd.vpd_buf + (VPD_SIZE-pAC->vpd.v.vpd_free_rw-1-3) ; vpd_move_para(vp.p_val+vp.p_len, etp+2, - - ((int)(vp.p_len + 3))); + - ((int)(vp.p_len + 3))) ; if (vpd_mod_endtag(pAC, etp - vp.p_len - 3)) { - pAC->vpd.v.vpd_status &= ~VPD_VALID; + pAC->vpd.v.vpd_status &= ~VPD_VALID ; SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR, - ("vpd encoding error\n")); - return(6); + ("vpd encoding error\n")) ; + return(6) ; } } else { SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR, - ("keyword not found\n")); - return (1); + ("keyword not found\n")) ; + return (1) ; } - return (0); + return (0) ; } /* @@ -1153,18 +1140,18 @@ SK_AC *pAC, /* Adapters context */ SK_IOC IoC) /* IO Context */ { - SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_TX,("vpd update .. ")); + SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_TX,("vpd update .. ")) ; if (pAC->vpd.v.vpd_status & VPD_VALID) { if (VpdTransferBlock(pAC,IoC,pAC->vpd.vpd_buf + VPD_SIZE/2, VPD_SIZE/2, VPD_SIZE/2, VPD_WRITE) != VPD_SIZE/2) { SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR, - ("transfer timed out\n")); - return(3); + ("transfer timed out\n")) ; + return(3) ; } } - SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_TX,("done\n")); - return (0); + SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_TX,("done\n")) ; + return (0) ; } @@ -1184,32 +1171,32 @@ SK_IOC IoC, /* IO Context */ char *msg) /* error log message */ { - SK_VPD_PARA *v, vf; /* VF */ - int len; + SK_VPD_PARA *v, vf ; /* VF */ + int len ; SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_TX, - ("vpd error log msg %s\n",msg)); + ("vpd error log msg %s\n",msg)) ; if (!(pAC->vpd.v.vpd_status & VPD_VALID)) { if (VpdInit(pAC,IoC) != 0 ) { SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR, - ("vpd init error\n")); - return; + ("vpd init error\n")) ; + return ; } } - len = strlen(msg); + len = strlen(msg) ; if (len > VPD_MAX_LEN) { /* cut it */ - len = VPD_MAX_LEN; + len = VPD_MAX_LEN ; } if ((v = vpd_find_para(pAC,VPD_VF,&vf))) { - SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_TX,("overwrite VL\n")); - (void)VpdSetupPara(pAC,VPD_VL,msg,len,VPD_RW_KEY,OWR_KEY); + SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_TX,("overwrite VL\n")) ; + (void)VpdSetupPara(pAC,VPD_VL,msg,len,VPD_RW_KEY,OWR_KEY) ; } else { - SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_TX,("write VF\n")); - (void)VpdSetupPara(pAC,VPD_VF,msg,len,VPD_RW_KEY,ADD_KEY); + SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_TX,("write VF\n")) ; + (void)VpdSetupPara(pAC,VPD_VF,msg,len,VPD_RW_KEY,ADD_KEY) ; } - (void)VpdUpdate(pAC,IoC); + (void)VpdUpdate(pAC,IoC) ; } diff -u --recursive --new-file v2.4.6/linux/drivers/net/sk98lin/skxmac2.c linux/drivers/net/sk98lin/skxmac2.c --- v2.4.6/linux/drivers/net/sk98lin/skxmac2.c Tue Mar 20 12:04:59 2001 +++ linux/drivers/net/sk98lin/skxmac2.c Wed Jul 4 11:50:39 2001 @@ -2,16 +2,15 @@ * * Name: skxmac2.c * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.53 $ - * Date: $Date: 2000/07/27 12:22:11 $ + * Version: $Revision: 1.61 $ + * Date: $Date: 2001/02/09 15:40:59 $ * Purpose: Contains functions to initialize the XMAC II * ******************************************************************************/ /****************************************************************************** * - * (C)Copyright 1998,1999 SysKonnect, - * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * (C)Copyright 1998-2001 SysKonnect GmbH. * * 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 @@ -27,6 +26,30 @@ * History: * * $Log: skxmac2.c,v $ + * Revision 1.61 2001/02/09 15:40:59 rassmann + * Editorial changes. + * + * Revision 1.60 2001/02/07 15:02:01 cgoos + * Added workaround for Fujitsu switch link down. + * + * Revision 1.59 2001/01/10 09:38:06 cgoos + * Fixed Broadcom C0/A1 Id check for workaround. + * + * Revision 1.58 2000/11/29 11:30:38 cgoos + * Changed DEBUG sections with NW output to xDEBUG + * + * Revision 1.57 2000/11/27 12:40:40 rassmann + * Suppressing preamble after first access to BCom, not before (#10556). + * + * Revision 1.56 2000/11/09 12:32:48 rassmann + * Renamed variables. + * + * Revision 1.55 2000/11/09 11:30:10 rassmann + * WA: Waiting after releasing reset until BCom chip is accessible. + * + * Revision 1.54 2000/10/02 14:10:27 rassmann + * Reading BCOM PHY after releasing reset until it returns a valid value. + * * Revision 1.53 2000/07/27 12:22:11 gklug * fix: possible endless loop in XmHardRst. * @@ -40,10 +63,10 @@ * Changed license header to GPL. * * Revision 1.49 1999/11/22 08:12:13 malthoff - * Add workaround for power consumption feature of Bcom C0 chip. + * Add workaround for power consumption feature of BCom C0 chip. * * Revision 1.48 1999/11/16 08:39:01 malthoff - * Fix: MDIO preamble suppression is port dependend. + * Fix: MDIO preamble suppression is port dependent. * * Revision 1.47 1999/08/27 08:55:35 malthoff * 1000BT: Optimizing MDIO transfer by oppressing MDIO preamble. @@ -79,8 +102,7 @@ * Changes for 1000Base-T. * * Revision 1.38 1999/04/08 14:35:10 malthoff - * Add code for enabling signal detect. Enabling signal - * detect is disabled. + * Add code for enabling signal detect. Enabling signal detect is disabled. * * Revision 1.37 1999/03/12 13:42:54 malthoff * Add: Jumbo Frame Support. @@ -234,11 +256,11 @@ /* local variables ************************************************************/ static const char SysKonnectFileId[] = - "@(#)$Id: skxmac2.c,v 1.53 2000/07/27 12:22:11 gklug Exp $ (C) SK "; + "@(#)$Id: skxmac2.c,v 1.61 2001/02/09 15:40:59 rassmann Exp $ (C) SK "; /* BCOM PHY magic pattern list */ typedef struct s_PhyHack { - int PhyReg; /* Phy register */ + int PhyReg; /* Phy register */ SK_U16 PhyVal; /* Value to write */ } BCOM_HACK; @@ -278,7 +300,7 @@ * o don't set XMR_FS_ERR in frame SK_BIG_PK_OK_ON/OFF * status for frames > 1514 bytes * - * for incoming packets may be enabled/disabled by this function. + * for incomming packets may be enabled/disabled by this function. * Additional modes may be added later. * Multiple modes can be enabled/disabled at the same time. * The new configuration is stored into the HWAC port configuration @@ -293,12 +315,12 @@ void SkXmSetRxCmd( SK_AC *pAC, /* adapter context */ SK_IOC IoC, /* IO context */ -int Port, /* The XMAC to handle with belongs to this Port */ -int Mode) /* Mode is SK_STRIP_FCS_ON/OFF, SK_STRIP_PAD_ON/OFF, - SK_LENERR_OK_ON/OFF, or SK_BIG_PK_OK_ON/OFF */ +int Port, /* The XMAC to handle with belongs to this Port */ +int Mode) /* Mode is SK_STRIP_FCS_ON/OFF, SK_STRIP_PAD_ON/OFF, + SK_LENERR_OK_ON/OFF, or SK_BIG_PK_OK_ON/OFF */ { - SK_GEPORT *pPrt; - SK_U16 OldRxMode; + SK_GEPORT *pPrt; + SK_U16 OldRxMode; pPrt = &pAC->GIni.GP[Port]; OldRxMode = pPrt->PRxCmd; @@ -343,7 +365,8 @@ if (OldRxMode != pPrt->PRxCmd) { XM_OUT16(IoC, Port, XM_RX_CMD, pPrt->PRxCmd); } -} +} /* SkXmSetRxCmd*/ + /****************************************************************************** * @@ -360,12 +383,12 @@ void SkXmClrExactAddr( SK_AC *pAC, /* adapter context */ SK_IOC IoC, /* IO context */ -int Port, /* The XMAC to handle with belongs to this Port */ -int StartNum, /* Begin with this Address Register Index (0..15) */ -int StopNum) /* Stop after finished with this Register Idx (0..15) */ +int Port, /* The XMAC to handle with belongs to this Port */ +int StartNum, /* Begin with this Address Register Index (0..15) */ +int StopNum) /* Stop after finished with this Register Idx (0..15) */ { - int i; - SK_U16 ZeroAddr[3] = { 0x0000, 0x0000, 0x0000 }; + int i; + SK_U16 ZeroAddr[3] = {0x0000, 0x0000, 0x0000}; if ((unsigned)StartNum > 15 || (unsigned)StopNum > 15 || StartNum > StopNum) { @@ -377,7 +400,8 @@ for (i = StartNum; i <= StopNum; i++) { XM_OUTADDR(IoC, Port, XM_EXM(i), &ZeroAddr[0]); } -} +} /* SkXmClrExactAddr */ + /****************************************************************************** * @@ -393,12 +417,13 @@ static void SkXmClrSrcCheck( SK_AC *pAC, /* adapter context */ SK_IOC IoC, /* IO context */ -int Port) /* The XMAC to handle with belongs to this Port (MAC_1 + n) */ +int Port) /* The XMAC to handle with belongs to this Port (MAC_1 + n) */ { - SK_U16 ZeroAddr[3] = { 0x0000, 0x0000, 0x0000 }; + SK_U16 ZeroAddr[3] = {0x0000, 0x0000, 0x0000}; XM_OUTHASH(IoC, Port, XM_SRC_CHK, &ZeroAddr); -} +} /* SkXmClrSrcCheck */ + /****************************************************************************** * @@ -413,12 +438,13 @@ static void SkXmClrHashAddr( SK_AC *pAC, /* adapter context */ SK_IOC IoC, /* IO context */ -int Port) /* The XMAC to handle with belongs to this Port (MAC_1 + n) */ +int Port) /* The XMAC to handle with belongs to this Port (MAC_1 + n) */ { - SK_U16 ZeroAddr[4] = { 0x0000, 0x0000, 0x0000, 0x0000 }; + SK_U16 ZeroAddr[4] = {0x0000, 0x0000, 0x0000, 0x0000}; XM_OUTHASH(IoC, Port, XM_HSM, &ZeroAddr); -} +} /* SkXmClrHashAddr*/ + /****************************************************************************** * @@ -433,14 +459,15 @@ void SkXmFlushTxFifo( SK_AC *pAC, /* adapter context */ SK_IOC IoC, /* IO context */ -int Port) /* The XMAC to handle with belongs to this Port (MAC_1 + n) */ +int Port) /* The XMAC to handle with belongs to this Port (MAC_1 + n) */ { SK_U32 MdReg; XM_IN32(IoC, Port, XM_MODE, &MdReg); MdReg |= XM_MD_FTF; XM_OUT32(IoC, Port, XM_MODE, MdReg); -} +} /* SkXmFlushTxFifo */ + /****************************************************************************** * @@ -455,14 +482,15 @@ void SkXmFlushRxFifo( SK_AC *pAC, /* adapter context */ SK_IOC IoC, /* IO context */ -int Port) /* The XMAC to handle with belongs to this Port (MAC_1 + n) */ +int Port) /* The XMAC to handle with belongs to this Port (MAC_1 + n) */ { SK_U32 MdReg; XM_IN32(IoC, Port, XM_MODE, &MdReg); MdReg |= XM_MD_FRF; XM_OUT32(IoC, Port, XM_MODE, MdReg); -} +} /* SkXmFlushRxFifo*/ + /****************************************************************************** * @@ -502,10 +530,10 @@ void SkXmSoftRst( SK_AC *pAC, /* adapter context */ SK_IOC IoC, /* IO context */ -int Port) /* port to stop (MAC_1 + n) */ +int Port) /* port to stop (MAC_1 + n) */ { SK_GEPORT *pPrt; - SK_U16 Word; + SK_U16 Word; pPrt = &pAC->GIni.GP[Port]; @@ -527,13 +555,11 @@ /* disable all PHY IRQs */ switch (pAC->GIni.GP[Port].PhyType) { - case SK_PHY_BCOM: - PHY_WRITE(IoC, pPrt, Port, PHY_BCOM_INT_MASK, - 0xffff); + case SK_PHY_BCOM: + PHY_WRITE(IoC, pPrt, Port, PHY_BCOM_INT_MASK, 0xffff); break; case SK_PHY_LONE: - PHY_WRITE(IoC, pPrt, Port, PHY_LONE_INT_ENAB, - 0x0); + PHY_WRITE(IoC, pPrt, Port, PHY_LONE_INT_ENAB, 0x0); break; case SK_PHY_NAT: /* todo: National @@ -554,7 +580,8 @@ SkXmFlushRxFifo(pAC, IoC, Port); pAC->GIni.GP[Port].PState = SK_PRT_STOP; -} +} /* SkXmSoftRst*/ + /****************************************************************************** * @@ -578,18 +605,17 @@ void SkXmHardRst( SK_AC *pAC, /* adapter context */ SK_IOC IoC, /* IO context */ -int Port) /* port to stop (MAC_1 + n) */ +int Port) /* port to stop (MAC_1 + n) */ { - SK_U16 Word; - int i; - int TOut; SK_U32 Reg; + int i; + int TOut; + SK_U16 Word; - for (i=0; i<4; i++) { + for (i = 0; i < 4; i++) { /* TX_MFF_CTRL1 is a 32 bit register but only the lowest 16 */ /* bit contains buttoms to press */ - SK_OUT16(IoC, MR_ADDR(Port, TX_MFF_CTRL1), - (SK_U16) MFF_CLR_MAC_RST); + SK_OUT16(IoC, MR_ADDR(Port, TX_MFF_CTRL1), (SK_U16)MFF_CLR_MAC_RST); TOut = 0; do { @@ -610,7 +636,6 @@ /* For external PHYs there must be special handling */ if (pAC->GIni.GP[Port].PhyType != SK_PHY_XMAC) { - /* reset external PHY */ SK_IN32(IoC, B2_GP_IO, &Reg); if (Port == 0) { @@ -628,7 +653,8 @@ } pAC->GIni.GP[Port].PState = SK_PRT_RESET; -} +} /* SkXmHardRst */ + /****************************************************************************** * @@ -639,8 +665,7 @@ * The XMAC must be reset or stopped before calling this function. * * Note: - * The XMACs Rx and Tx state machine is still disabled when - * returning. + * The XMAC's Rx and Tx state machine is still disabled when returning. * * Returns: * nothing @@ -648,12 +673,13 @@ void SkXmInitMac( SK_AC *pAC, /* adapter context */ SK_IOC IoC, /* IO context */ -int Port) /* Port Index (MAC_1 + n) */ +int Port) /* Port Index (MAC_1 + n) */ { - SK_GEPORT *pPrt; - SK_U16 SWord; - int i; - SK_U32 Reg; + SK_GEPORT *pPrt; + SK_U32 Reg; + int i; + SK_U16 SWord; + SK_U16 PhyId; pPrt = &pAC->GIni.GP[Port]; @@ -661,79 +687,118 @@ /* Port State: SK_PRT_STOP */ /* Verify that the reset bit is cleared */ SK_IN16(IoC, MR_ADDR(Port, TX_MFF_CTRL1), &SWord); - if (SWord & (SK_U16) MFF_SET_MAC_RST) { + if (SWord & (SK_U16)MFF_SET_MAC_RST) { /* PState does not match HW state */ - SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E006, - SKERR_HWI_E006MSG); - /* correct it */ + SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E006, SKERR_HWI_E006MSG); + /* Correct it. */ pPrt->PState = SK_PRT_RESET; } } + if (pPrt->PState == SK_PRT_RESET) { /* * clear HW reset * Note: The SW reset is self clearing, therefore there is * nothing to do here. */ - SK_OUT16(IoC, MR_ADDR(Port, TX_MFF_CTRL1), - (SK_U16) MFF_CLR_MAC_RST); - - /* - * clear PHY reset - */ - if (pAC->GIni.GP[Port].PhyType != SK_PHY_XMAC) { + SK_OUT16(IoC, MR_ADDR(Port, TX_MFF_CTRL1), (SK_U16)MFF_CLR_MAC_RST); + /* Ensure that XMAC reset release is done (errata from LReinbold?). */ + SK_IN16(IoC, MR_ADDR(Port, TX_MFF_CTRL1), &SWord); + + /* Clear PHY reset. */ + if (pAC->GIni.GP[Port].PhyType != SK_PHY_XMAC) { SK_IN32(IoC, B2_GP_IO, &Reg); if (Port == 0) { - Reg |= GP_DIR_0; /* set to output */ + Reg |= GP_DIR_0; /* Set to output. */ Reg |= GP_IO_0; } else { - Reg |= GP_DIR_2; /* set to output */ + Reg |= GP_DIR_2; /* Set to output. */ Reg |= GP_IO_2; } SK_OUT32(IoC, B2_GP_IO, Reg); - /* enable GMII interface */ + /* Enable GMII interface. */ XM_OUT16(IoC, Port, XM_HW_CFG, XM_HW_GMII_MD); - /* optimize MDIO transfer by oppressing preamble */ + PHY_READ(IoC, pPrt, Port, PHY_XMAC_ID1, &PhyId); +#ifdef xDEBUG + if (SWord == 0xFFFF) { + i = 1; + do { + PHY_READ(IoC, pPrt, Port, PHY_XMAC_ID1, &SWord); + i++; + /* Limit retries; else machine may hang. */ + } while (SWord == 0xFFFF && i < 500000); + + CMSMPrintString( + pAC->pConfigTable, + MSG_TYPE_RUNTIME_INFO, + "ID1 is %x after %d reads.", + (void *)SWord, + (void *)i); + + /* Trigger PCI analyzer */ + /* SK_IN32(IoC, 0x012c, &Reg); */ + } +#endif /* DEBUG */ + + /* + * Optimize MDIO transfer by suppressing preamble. + * Must be done AFTER first access to BCOM chip. + */ XM_IN16(IoC, Port, XM_MMU_CMD, &SWord); XM_OUT16(IoC, Port, XM_MMU_CMD, SWord | XM_MMU_NO_PRE); - /* Workaround BCOM Errata for the A1 type */ - /* Write magic patterns to reserved registers */ - PHY_READ(IoC, pPrt, Port, PHY_XMAC_ID1, &SWord); - if (SWord == 0x6041) { + if (PhyId == 0x6044) { + /* Workaround BCOM Errata for the C0 type. */ + /* Write magic patterns to reserved registers. */ i = 0; - while (BcomRegA1Hack[i].PhyReg != 0) { - PHY_WRITE(IoC, pPrt, Port, - BcomRegA1Hack[i].PhyReg, - BcomRegA1Hack[i].PhyVal); + while (BcomRegC0Hack[i].PhyReg != 0) { + PHY_WRITE(IoC, pPrt, Port, BcomRegC0Hack[i].PhyReg, + BcomRegC0Hack[i].PhyVal); i++; } } - /* Workaround BCOM Errata for the C0 type */ - /* Write magic patterns to reserved registers */ - if (SWord == 0x6044) { + else if (PhyId == 0x6041) { + /* Workaround BCOM Errata for the A1 type. */ + /* Write magic patterns to reserved registers. */ i = 0; - while (BcomRegC0Hack[i].PhyReg != 0) { - PHY_WRITE(IoC, pPrt, Port, - BcomRegC0Hack[i].PhyReg, - BcomRegC0Hack[i].PhyVal); + while (BcomRegA1Hack[i].PhyReg != 0) { + PHY_WRITE(IoC, pPrt, Port, BcomRegA1Hack[i].PhyReg, + BcomRegA1Hack[i].PhyVal); i++; } } - /* Workaround BCOM Errata (#10523) for all BCom PHYs*/ - /* Disable Power Management after reset */ + + /* Workaround BCOM Errata (#10523) for all BCom PHYs. */ + /* Disable Power Management after reset. */ PHY_READ(IoC, pPrt, Port, PHY_BCOM_AUX_CTRL, &SWord); +#ifdef xDEBUG + if (SWord == 0xFFFF) { + i = 1; + do { + PHY_READ(IoC, pPrt, Port, PHY_BCOM_AUX_CTRL, &SWord); + i++; + /* Limit retries; else machine may hang. */ + } while (SWord == 0xFFFF && i < 500000); + + CMSMPrintString( + pAC->pConfigTable, + MSG_TYPE_RUNTIME_INFO, + "AUX_CTRL is %x after %d reads.", + (void *)SWord, + (void *)i); + + /* Trigger PCI analyzer */ + /* SK_IN32(IoC, 0x012c, &Reg); */ + } +#endif /* DEBUG */ PHY_WRITE(IoC, pPrt, Port, PHY_BCOM_AUX_CTRL, SWord | PHY_B_AC_DIS_PM); - /* - * PHY LED initialization is performed in - * SkGeXmitLED() (but not here). - */ + /* PHY LED initialization is done in SkGeXmitLED(), not here. */ } /* Dummy read the Interrupt source register */ @@ -741,7 +806,7 @@ /* * The autonegotiation process starts immediately after - * clearing the reset. Autonegotiation process should be + * clearing the reset. The autonegotiation process should be * started by the SIRQ, therefore stop it here immediately. */ SkXmInitPhy(pAC, IoC, Port, SK_FALSE); @@ -755,8 +820,8 @@ /* * configure the XMACs Station Address - * B2_MAC_2 = xx xx xx xx xx x1 is programmed to XMAC A - * B2_MAC_3 = xx xx xx xx xx x2 is programmed to XMAC B + * B2_MAC_2 = xx xx xx xx xx x1 is programed to XMAC A + * B2_MAC_3 = xx xx xx xx xx x2 is programed to XMAC B */ for (i = 0; i < 3; i++) { /* @@ -849,7 +914,8 @@ * This should be done after the autonegotiation process * has been completed successfully. */ -} +} /* SkXmInitMac*/ + /****************************************************************************** * @@ -866,7 +932,7 @@ void SkXmInitDupMd( SK_AC *pAC, /* adapter context */ SK_IOC IoC, /* IO context */ -int Port) /* Port Index (MAC_1 + n) */ +int Port) /* Port Index (MAC_1 + n) */ { switch (pAC->GIni.GP[Port].PLinkModeStatus) { case SK_LMODE_STAT_AUTOHALF: @@ -895,7 +961,8 @@ SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E007, SKERR_HWI_E007MSG); break; } -} +} /* SkXmInitDupMd */ + /****************************************************************************** * @@ -913,11 +980,11 @@ void SkXmInitPauseMd( SK_AC *pAC, /* adapter context */ SK_IOC IoC, /* IO context */ -int Port) /* Port Index (MAC_1 + n) */ +int Port) /* Port Index (MAC_1 + n) */ { SK_GEPORT *pPrt; - SK_U16 Word; SK_U32 DWord; + SK_U16 Word; pPrt = &pAC->GIni.GP[Port]; @@ -976,8 +1043,7 @@ /* Disable Pause Mode in MAC Rx FIFO */ SK_OUT16(IoC, MR_ADDR(Port,RX_MFF_CTRL1), MFF_DIS_PAUSE); } - -} +} /* SkXmInitPauseMd*/ /****************************************************************************** @@ -995,7 +1061,7 @@ void SkXmInitPhy( SK_AC *pAC, /* adapter context */ SK_IOC IoC, /* IO context */ -int Port, /* Port Index (MAC_1 + n) */ +int Port, /* Port Index (MAC_1 + n) */ SK_BOOL DoLoop) /* Should a Phy LOOback be set-up? */ { SK_GEPORT *pPrt; @@ -1015,7 +1081,8 @@ SkXmInitPhyNat(pAC, IoC, Port, DoLoop); break; } -} +} /* SkXmInitPhy*/ + /****************************************************************************** * @@ -1032,11 +1099,11 @@ static void SkXmInitPhyXmac( SK_AC *pAC, /* adapter context */ SK_IOC IoC, /* IO context */ -int Port, /* Port Index (MAC_1 + n) */ +int Port, /* Port Index (MAC_1 + n) */ SK_BOOL DoLoop) /* Should a Phy LOOback be set-up? */ { SK_GEPORT *pPrt; - SK_U16 Crtl; + SK_U16 Ctrl; pPrt = &pAC->GIni.GP[Port]; @@ -1047,67 +1114,69 @@ ("InitPhyXmac: no autonegotiation Port %d\n", Port)); /* No Autonegiotiation */ /* Set DuplexMode in Config register */ - Crtl = (pPrt->PLinkMode == SK_LMODE_FULL ? PHY_CT_DUP_MD : 0); + Ctrl = (pPrt->PLinkMode == SK_LMODE_FULL ? PHY_CT_DUP_MD : 0); /* * Do NOT enable Autonegotiation here. This would hold * the link down because no IDLES are transmitted */ - } else { + } + else { SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL, ("InitPhyXmac: with autonegotiation Port %d\n", Port)); /* Set Autonegotiation advertisement */ - Crtl = 0; + Ctrl = 0; /* Set Full/half duplex capabilities */ switch (pPrt->PLinkMode) { case SK_LMODE_AUTOHALF: - Crtl |= PHY_X_AN_HD; + Ctrl |= PHY_X_AN_HD; break; case SK_LMODE_AUTOFULL: - Crtl |= PHY_X_AN_FD; + Ctrl |= PHY_X_AN_FD; break; case SK_LMODE_AUTOBOTH: - Crtl |= PHY_X_AN_FD | PHY_X_AN_HD; + Ctrl |= PHY_X_AN_FD | PHY_X_AN_HD; break; default: SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, - SKERR_HWI_E015, SKERR_HWI_E015MSG) ; + SKERR_HWI_E015, SKERR_HWI_E015MSG); } switch (pPrt->PFlowCtrlMode) { case SK_FLOW_MODE_NONE: - Crtl |= PHY_X_P_NO_PAUSE; + Ctrl |= PHY_X_P_NO_PAUSE; break; case SK_FLOW_MODE_LOC_SEND: - Crtl |= PHY_X_P_ASYM_MD; + Ctrl |= PHY_X_P_ASYM_MD; break; case SK_FLOW_MODE_SYMMETRIC: - Crtl |= PHY_X_P_SYM_MD; + Ctrl |= PHY_X_P_SYM_MD; break; case SK_FLOW_MODE_SYM_OR_REM: - Crtl |= PHY_X_P_BOTH_MD; + Ctrl |= PHY_X_P_BOTH_MD; break; default: SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, - SKERR_HWI_E016, SKERR_HWI_E016MSG) ; + SKERR_HWI_E016, SKERR_HWI_E016MSG); } /* Write AutoNeg Advertisement Register */ - PHY_WRITE(IoC, pPrt, Port, PHY_XMAC_AUNE_ADV, Crtl) ; + PHY_WRITE(IoC, pPrt, Port, PHY_XMAC_AUNE_ADV, Ctrl); /* Restart Autonegotiation */ - Crtl = PHY_CT_ANE | PHY_CT_RE_CFG; + Ctrl = PHY_CT_ANE | PHY_CT_RE_CFG; } if (DoLoop) { /* Set the Phy Loopback bit, too */ - Crtl |= PHY_CT_LOOP; + Ctrl |= PHY_CT_LOOP; } /* Write to the Phy control register */ - PHY_WRITE(IoC, pPrt, Port, PHY_XMAC_CTRL, Crtl) ; -} + PHY_WRITE(IoC, pPrt, Port, PHY_XMAC_CTRL, Ctrl); +} /* SkXmInitPhyXmac*/ + /****************************************************************************** * @@ -1124,23 +1193,29 @@ static void SkXmInitPhyBcom( SK_AC *pAC, /* adapter context */ SK_IOC IoC, /* IO context */ -int Port, /* Port Index (MAC_1 + n) */ +int Port, /* Port Index (MAC_1 + n) */ SK_BOOL DoLoop) /* Should a Phy LOOback be set-up? */ { SK_GEPORT *pPrt; - SK_U16 Crtl1 = PHY_B_CT_SP1000; - SK_U16 Crtl2 = 0; - SK_U16 Crtl3 = PHY_SEL_TYPE; - SK_U16 Crtl4 = PHY_B_PEC_EN_LTR; - SK_U16 Crtl5 = PHY_B_AC_TX_TST; + SK_U16 Ctrl1; + SK_U16 Ctrl2; + SK_U16 Ctrl3; + SK_U16 Ctrl4; + SK_U16 Ctrl5; + + Ctrl1 = PHY_B_CT_SP1000; + Ctrl2 = 0; + Ctrl3 = PHY_SEL_TYPE; + Ctrl4 = PHY_B_PEC_EN_LTR; + Ctrl5 = PHY_B_AC_TX_TST; pPrt = &pAC->GIni.GP[Port]; - /* manuell Master/Slave ? */ + /* manually Master/Slave ? */ if (pPrt->PMSMode != SK_MS_MODE_AUTO) { - Crtl2 |= PHY_B_1000C_MSE; + Ctrl2 |= PHY_B_1000C_MSE; if (pPrt->PMSMode == SK_MS_MODE_MASTER) { - Crtl2 |= PHY_B_1000C_MSC; + Ctrl2 |= PHY_B_1000C_MSC; } } /* Autonegotiation ? */ @@ -1150,18 +1225,19 @@ ("InitPhyBcom: no autonegotiation Port %d\n", Port)); /* No Autonegiotiation */ /* Set DuplexMode in Config register */ - Crtl1 |= (pPrt->PLinkMode == SK_LMODE_FULL ? PHY_CT_DUP_MD : 0); + Ctrl1 |= (pPrt->PLinkMode == SK_LMODE_FULL ? PHY_CT_DUP_MD : 0); - /* Determine Master/Slave manuell if not already done */ + /* Determine Master/Slave manually if not already done. */ if (pPrt->PMSMode == SK_MS_MODE_AUTO) { - Crtl2 |= PHY_B_1000C_MSE; /* set it to Slave */ + Ctrl2 |= PHY_B_1000C_MSE; /* set it to Slave */ } /* * Do NOT enable Autonegotiation here. This would hold * the link down because no IDLES are transmitted */ - } else { + } + else { SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL, ("InitPhyBcom: with autonegotiation Port %d\n", Port)); /* Set Autonegotiation advertisement */ @@ -1169,31 +1245,31 @@ /* Set Full/half duplex capabilities */ switch (pPrt->PLinkMode) { case SK_LMODE_AUTOHALF: - Crtl2 |= PHY_B_1000C_AHD; + Ctrl2 |= PHY_B_1000C_AHD; break; case SK_LMODE_AUTOFULL: - Crtl2 |= PHY_B_1000C_AFD; + Ctrl2 |= PHY_B_1000C_AFD; break; case SK_LMODE_AUTOBOTH: - Crtl2 |= PHY_B_1000C_AFD | PHY_B_1000C_AHD; + Ctrl2 |= PHY_B_1000C_AFD | PHY_B_1000C_AHD; break; default: SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, - SKERR_HWI_E015, SKERR_HWI_E015MSG) ; + SKERR_HWI_E015, SKERR_HWI_E015MSG); } switch (pPrt->PFlowCtrlMode) { case SK_FLOW_MODE_NONE: - Crtl3 |= PHY_B_P_NO_PAUSE; + Ctrl3 |= PHY_B_P_NO_PAUSE; break; case SK_FLOW_MODE_LOC_SEND: - Crtl3 |= PHY_B_P_ASYM_MD; + Ctrl3 |= PHY_B_P_ASYM_MD; break; case SK_FLOW_MODE_SYMMETRIC: - Crtl3 |= PHY_B_P_SYM_MD; + Ctrl3 |= PHY_B_P_SYM_MD; break; case SK_FLOW_MODE_SYM_OR_REM: - Crtl3 |= PHY_B_P_BOTH_MD; + Ctrl3 |= PHY_B_P_BOTH_MD; break; default: SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, @@ -1201,7 +1277,7 @@ } /* Restart Autonegotiation */ - Crtl1 |= PHY_CT_ANE | PHY_CT_RE_CFG; + Ctrl1 |= PHY_CT_ANE | PHY_CT_RE_CFG; } @@ -1210,39 +1286,40 @@ init order of LEDs and XMAC. (MAl) */ /* Write 1000Base-T Control Register */ - PHY_WRITE(IoC, pPrt, Port, PHY_BCOM_1000T_CTRL, Crtl2); + PHY_WRITE(IoC, pPrt, Port, PHY_BCOM_1000T_CTRL, Ctrl2); SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL, - ("1000Base-T Control Reg = %x\n", Crtl2)); + ("1000Base-T Control Reg = %x\n", Ctrl2)); /* Write AutoNeg Advertisement Register */ - PHY_WRITE(IoC, pPrt, Port, PHY_BCOM_AUNE_ADV, Crtl3); + PHY_WRITE(IoC, pPrt, Port, PHY_BCOM_AUNE_ADV, Ctrl3); SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL, - ("AutoNeg Advertisment Reg = %x\n", Crtl3)); + ("AutoNeg Advertisment Reg = %x\n", Ctrl3)); if (DoLoop) { /* Set the Phy Loopback bit, too */ - Crtl1 |= PHY_CT_LOOP; + Ctrl1 |= PHY_CT_LOOP; } if (pAC->GIni.GIPortUsage == SK_JUMBO_LINK) { /* configure fifo to high latency for xmission of ext. packets*/ - Crtl4 |= PHY_B_PEC_HIGH_LA; + Ctrl4 |= PHY_B_PEC_HIGH_LA; /* configure reception of extended packets */ - Crtl5 |= PHY_B_AC_LONG_PACK; + Ctrl5 |= PHY_B_AC_LONG_PACK; - PHY_WRITE(IoC, pPrt, Port, PHY_BCOM_AUX_CTRL, Crtl5); + PHY_WRITE(IoC, pPrt, Port, PHY_BCOM_AUX_CTRL, Ctrl5); } /* Configure LED Traffic Mode and Jumbo Frame usage if specified */ - PHY_WRITE(IoC, pPrt, Port, PHY_BCOM_P_EXT_CTRL, Crtl4); + PHY_WRITE(IoC, pPrt, Port, PHY_BCOM_P_EXT_CTRL, Ctrl4); /* Write to the Phy control register */ - PHY_WRITE(IoC, pPrt, Port, PHY_BCOM_CTRL, Crtl1); + PHY_WRITE(IoC, pPrt, Port, PHY_BCOM_CTRL, Ctrl1); SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL, - ("PHY Control Reg = %x\n", Crtl1)); -} + ("PHY Control Reg = %x\n", Ctrl1)); +} /* SkXmInitPhyBcom */ + /****************************************************************************** * @@ -1259,21 +1336,25 @@ static void SkXmInitPhyLone( SK_AC *pAC, /* adapter context */ SK_IOC IoC, /* IO context */ -int Port, /* Port Index (MAC_1 + n) */ +int Port, /* Port Index (MAC_1 + n) */ SK_BOOL DoLoop) /* Should a Phy LOOback be set-up? */ { SK_GEPORT *pPrt; - SK_U16 Crtl1 = PHY_L_CT_SP1000; - SK_U16 Crtl2 = 0; - SK_U16 Crtl3 = PHY_SEL_TYPE; + SK_U16 Ctrl1; + SK_U16 Ctrl2; + SK_U16 Ctrl3; + + Ctrl1 = PHY_L_CT_SP1000; + Ctrl2 = 0; + Ctrl3 = PHY_SEL_TYPE; pPrt = &pAC->GIni.GP[Port]; - /* manuell Master/Slave ? */ + /* manually Master/Slave ? */ if (pPrt->PMSMode != SK_MS_MODE_AUTO) { - Crtl2 |= PHY_L_1000C_MSE; + Ctrl2 |= PHY_L_1000C_MSE; if (pPrt->PMSMode == SK_MS_MODE_MASTER) { - Crtl2 |= PHY_L_1000C_MSC; + Ctrl2 |= PHY_L_1000C_MSC; } } /* Autonegotiation ? */ @@ -1289,18 +1370,19 @@ ("InitPhyLone: no autonegotiation Port %d\n", Port)); /* No Autonegiotiation */ /* Set DuplexMode in Config register */ - Crtl1 = (pPrt->PLinkMode == SK_LMODE_FULL ? PHY_CT_DUP_MD : 0); + Ctrl1 = (pPrt->PLinkMode == SK_LMODE_FULL ? PHY_CT_DUP_MD : 0); - /* Determine Master/Slave manuell if not already done */ + /* Determine Master/Slave manually if not already done. */ if (pPrt->PMSMode == SK_MS_MODE_AUTO) { - Crtl2 |= PHY_L_1000C_MSE; /* set it to Slave */ + Ctrl2 |= PHY_L_1000C_MSE; /* set it to Slave */ } /* * Do NOT enable Autonegotiation here. This would hold * the link down because no IDLES are transmitted */ - } else { + } + else { SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL, ("InitPhyLone: with autonegotiation Port %d\n", Port)); /* Set Autonegotiation advertisement */ @@ -1308,31 +1390,31 @@ /* Set Full/half duplex capabilities */ switch (pPrt->PLinkMode) { case SK_LMODE_AUTOHALF: - Crtl2 |= PHY_L_1000C_AHD; + Ctrl2 |= PHY_L_1000C_AHD; break; case SK_LMODE_AUTOFULL: - Crtl2 |= PHY_L_1000C_AFD; + Ctrl2 |= PHY_L_1000C_AFD; break; case SK_LMODE_AUTOBOTH: - Crtl2 |= PHY_L_1000C_AFD | PHY_L_1000C_AHD; + Ctrl2 |= PHY_L_1000C_AFD | PHY_L_1000C_AHD; break; default: SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, - SKERR_HWI_E015, SKERR_HWI_E015MSG) ; + SKERR_HWI_E015, SKERR_HWI_E015MSG); } switch (pPrt->PFlowCtrlMode) { case SK_FLOW_MODE_NONE: - Crtl3 |= PHY_L_P_NO_PAUSE; + Ctrl3 |= PHY_L_P_NO_PAUSE; break; case SK_FLOW_MODE_LOC_SEND: - Crtl3 |= PHY_L_P_ASYM_MD; + Ctrl3 |= PHY_L_P_ASYM_MD; break; case SK_FLOW_MODE_SYMMETRIC: - Crtl3 |= PHY_L_P_SYM_MD; + Ctrl3 |= PHY_L_P_SYM_MD; break; case SK_FLOW_MODE_SYM_OR_REM: - Crtl3 |= PHY_L_P_BOTH_MD; + Ctrl3 |= PHY_L_P_BOTH_MD; break; default: SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, @@ -1340,7 +1422,7 @@ } /* Restart Autonegotiation */ - Crtl1 = PHY_CT_ANE | PHY_CT_RE_CFG; + Ctrl1 = PHY_CT_ANE | PHY_CT_RE_CFG; } @@ -1349,19 +1431,19 @@ init order of LEDs and XMAC. (MAl) */ /* Write 1000Base-T Control Register */ - PHY_WRITE(IoC, pPrt, Port, PHY_LONE_1000T_CTRL, Crtl2); + PHY_WRITE(IoC, pPrt, Port, PHY_LONE_1000T_CTRL, Ctrl2); SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL, - ("1000Base-T Control Reg = %x\n", Crtl2)); + ("1000Base-T Control Reg = %x\n", Ctrl2)); /* Write AutoNeg Advertisement Register */ - PHY_WRITE(IoC, pPrt, Port, PHY_LONE_AUNE_ADV, Crtl3); + PHY_WRITE(IoC, pPrt, Port, PHY_LONE_AUNE_ADV, Ctrl3); SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL, - ("AutoNeg Advertisment Reg = %x\n", Crtl3)); + ("AutoNeg Advertisment Reg = %x\n", Ctrl3)); if (DoLoop) { /* Set the Phy Loopback bit, too */ - Crtl1 |= PHY_CT_LOOP; + Ctrl1 |= PHY_CT_LOOP; } if (pAC->GIni.GIPortUsage == SK_JUMBO_LINK) { @@ -1372,10 +1454,11 @@ } /* Write to the Phy control register */ - PHY_WRITE(IoC, pPrt, Port, PHY_LONE_CTRL, Crtl1); + PHY_WRITE(IoC, pPrt, Port, PHY_LONE_CTRL, Ctrl1); SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL, - ("PHY Control Reg = %x\n", Crtl1)); -} + ("PHY Control Reg = %x\n", Ctrl1)); +} /* SkXmInitPhyLone*/ + /****************************************************************************** * @@ -1392,11 +1475,12 @@ static void SkXmInitPhyNat( SK_AC *pAC, /* adapter context */ SK_IOC IoC, /* IO context */ -int Port, /* Port Index (MAC_1 + n) */ +int Port, /* Port Index (MAC_1 + n) */ SK_BOOL DoLoop) /* Should a Phy LOOback be set-up? */ { /* todo: National */ -} +} /* SkXmInitPhyNat*/ + /****************************************************************************** * @@ -1409,7 +1493,7 @@ void SkXmAutoNegLipaXmac( SK_AC *pAC, /* adapter context */ SK_IOC IoC, /* IO context */ -int Port, /* Port Index (MAC_1 + n) */ +int Port, /* Port Index (MAC_1 + n) */ SK_U16 IStatus) /* Interrupt Status word to analyse */ { SK_GEPORT *pPrt; @@ -1423,7 +1507,8 @@ ("AutoNegLipa: AutoNeg detected on port %d %x\n", Port, IStatus)); pPrt->PLipaAutoNeg = SK_LIPA_AUTO; } -} +} /* SkXmAutoNegLipaXmac*/ + /****************************************************************************** * @@ -1436,21 +1521,20 @@ void SkXmAutoNegLipaBcom( SK_AC *pAC, /* adapter context */ SK_IOC IoC, /* IO context */ -int Port, /* Port Index (MAC_1 + n) */ +int Port, /* Port Index (MAC_1 + n) */ SK_U16 PhyStat) /* PHY Status word to analyse */ { SK_GEPORT *pPrt; pPrt = &pAC->GIni.GP[Port]; - if (pPrt->PLipaAutoNeg != SK_LIPA_AUTO && - (PhyStat & (PHY_ST_AN_OVER))) { - + if (pPrt->PLipaAutoNeg != SK_LIPA_AUTO && (PhyStat & PHY_ST_AN_OVER)) { SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL, ("AutoNegLipa: AutoNeg detected on port %d %x\n", Port, PhyStat)); pPrt->PLipaAutoNeg = SK_LIPA_AUTO; } -} +} /* SkXmAutoNegLipaBcom*/ + /****************************************************************************** * @@ -1477,7 +1561,8 @@ ("AutoNegLipa: AutoNeg detected on port %d %x\n", Port, PhyStat)); pPrt->PLipaAutoNeg = SK_LIPA_AUTO; } -} +} /* SkXmAutoNegLipaLone*/ + /****************************************************************************** * @@ -1490,7 +1575,7 @@ void SkXmAutoNegLipaNat( SK_AC *pAC, /* adapter context */ SK_IOC IoC, /* IO context */ -int Port, /* Port Index (MAC_1 + n) */ +int Port, /* Port Index (MAC_1 + n) */ SK_U16 PhyStat) /* PHY Status word to analyse */ { SK_GEPORT *pPrt; @@ -1504,7 +1589,9 @@ ("AutoNegLipa: AutoNeg detected on port %d %x\n", Port, PhyStat)); pPrt->PLipaAutoNeg = SK_LIPA_AUTO; } -} +} /* SkXmAutoNegLipaNat*/ + + /****************************************************************************** * * SkXmAutoNegDone() - Auto negotiation handling @@ -1525,13 +1612,9 @@ int SkXmAutoNegDone( SK_AC *pAC, /* adapter context */ SK_IOC IoC, /* IO context */ -int Port) /* Port Index (MAC_1 + n) */ +int Port) /* Port Index (MAC_1 + n) */ { - SK_GEPORT *pPrt; - - pPrt = &pAC->GIni.GP[Port]; - - switch (pPrt->PhyType) { + switch (pAC->GIni.GP[Port].PhyType) { case SK_PHY_XMAC: return (SkXmAutoNegDoneXmac(pAC, IoC, Port)); case SK_PHY_BCOM: @@ -1541,8 +1624,9 @@ case SK_PHY_NAT: return (SkXmAutoNegDoneNat(pAC, IoC, Port)); } - return(SK_AND_OTHER); -} + return (SK_AND_OTHER); +} /* SkXmAutoNegDone*/ + /****************************************************************************** * @@ -1562,11 +1646,11 @@ static int SkXmAutoNegDoneXmac( SK_AC *pAC, /* adapter context */ SK_IOC IoC, /* IO context */ -int Port) /* Port Index (MAC_1 + n) */ +int Port) /* Port Index (MAC_1 + n) */ { SK_GEPORT *pPrt; - SK_U16 ResAb ; /* Resolved Ability */ - SK_U16 LPAb ; /* Link Partner Ability */ + SK_U16 ResAb; /* Resolved Ability */ + SK_U16 LPAb; /* Link Partner Ability */ SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL, ("AutoNegDoneXmac" "Port %d\n",Port)); @@ -1582,21 +1666,23 @@ /* Error */ SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL, ("AutoNegFail: Remote fault bit set Port %d\n", Port)); - pPrt->PAutoNegFail = SK_TRUE ; - return (SK_AND_OTHER) ; + pPrt->PAutoNegFail = SK_TRUE; + return (SK_AND_OTHER); } /* Check Duplex mismatch */ if ((ResAb & (PHY_X_RS_HD | PHY_X_RS_FD)) == PHY_X_RS_FD) { - pPrt->PLinkModeStatus = SK_LMODE_STAT_AUTOFULL ; - } else if ((ResAb & (PHY_X_RS_HD | PHY_X_RS_FD)) == PHY_X_RS_HD) { - pPrt->PLinkModeStatus = SK_LMODE_STAT_AUTOHALF ; - } else { + pPrt->PLinkModeStatus = SK_LMODE_STAT_AUTOFULL; + } + else if ((ResAb & (PHY_X_RS_HD | PHY_X_RS_FD)) == PHY_X_RS_HD) { + pPrt->PLinkModeStatus = SK_LMODE_STAT_AUTOHALF; + } + else { /* Error */ SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL, ("AutoNegFail: Duplex mode mismatch port %d\n", Port)); - pPrt->PAutoNegFail = SK_TRUE ; - return (SK_AND_DUP_CAP) ; + pPrt->PAutoNegFail = SK_TRUE; + return (SK_AND_DUP_CAP); } /* Check PAUSE mismatch */ @@ -1607,25 +1693,29 @@ (LPAb & PHY_X_P_SYM_MD)) { /* Symmetric PAUSE */ pPrt->PFlowCtrlStatus = SK_FLOW_STAT_SYMMETRIC; - } else if (pPrt->PFlowCtrlMode == SK_FLOW_MODE_SYM_OR_REM && + } + else if (pPrt->PFlowCtrlMode == SK_FLOW_MODE_SYM_OR_REM && (LPAb & PHY_X_RS_PAUSE) == PHY_X_P_ASYM_MD) { /* Enable PAUSE receive, disable PAUSE transmit */ pPrt->PFlowCtrlStatus = SK_FLOW_STAT_REM_SEND; - } else if (pPrt->PFlowCtrlMode == SK_FLOW_MODE_LOC_SEND && + } + else if (pPrt->PFlowCtrlMode == SK_FLOW_MODE_LOC_SEND && (LPAb & PHY_X_RS_PAUSE) == PHY_X_P_BOTH_MD) { /* Disable PAUSE receive, enable PAUSE transmit */ pPrt->PFlowCtrlStatus = SK_FLOW_STAT_LOC_SEND; - } else { + } + else { /* PAUSE mismatch -> no PAUSE */ pPrt->PFlowCtrlStatus = SK_FLOW_STAT_NONE; } /* We checked everything and may now enable the link */ - pPrt->PAutoNegFail = SK_FALSE ; + pPrt->PAutoNegFail = SK_FALSE; SkXmRxTxEnable(pAC, IoC, Port); - return(SK_AND_OK) ; -} + return (SK_AND_OK); +} /* SkXmAutoNegDoneXmac*/ + /****************************************************************************** * @@ -1645,82 +1735,99 @@ static int SkXmAutoNegDoneBcom( SK_AC *pAC, /* adapter context */ SK_IOC IoC, /* IO context */ -int Port) /* Port Index (MAC_1 + n) */ +int Port) /* Port Index (MAC_1 + n) */ { SK_GEPORT *pPrt; - SK_U16 ResAb ; /* Resolved Ability */ - SK_U16 LPAb ; /* Link Partner Ability */ + SK_U16 LPAb; /* Link Partner Ability */ SK_U16 AuxStat; /* Auxiliary Status */ - SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL, ("AutoNegDoneBcom," - " Port %d\n",Port)); +#if 0 +01-Sep-2000 RA;:;: + SK_U16 ResAb; /* Resolved Ability */ +#endif /* 0 */ + + SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL, + ("AutoNegDoneBcom, Port %d\n", Port)); pPrt = &pAC->GIni.GP[Port]; - /* Get PHY parameters */ + /* Get PHY parameters. */ PHY_READ(IoC, pPrt, Port, PHY_BCOM_AUNE_LP, &LPAb); +#if 0 +01-Sep-2000 RA;:;: PHY_READ(IoC, pPrt, Port, PHY_BCOM_1000T_STAT, &ResAb); +#endif /* 0 */ PHY_READ(IoC, pPrt, Port, PHY_BCOM_AUX_STAT, &AuxStat); if (LPAb & PHY_B_AN_RF) { - /* Remote fault bit is set */ - /* Error */ - SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL, + /* Remote fault bit is set: Error. */ + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, ("AutoNegFail: Remote fault bit set Port %d\n", Port)); - pPrt->PAutoNegFail = SK_TRUE ; - return (SK_AND_OTHER) ; + pPrt->PAutoNegFail = SK_TRUE; + return (SK_AND_OTHER); } - /* Check Duplex mismatch */ + /* Check Duplex mismatch. */ if ((AuxStat & PHY_B_AS_AN_RES) == PHY_B_RES_1000FD) { - pPrt->PLinkModeStatus = SK_LMODE_STAT_AUTOFULL ; - } else if ((AuxStat & PHY_B_AS_AN_RES) == PHY_B_RES_1000HD) { - pPrt->PLinkModeStatus = SK_LMODE_STAT_AUTOHALF ; - } else { - /* Error */ + pPrt->PLinkModeStatus = SK_LMODE_STAT_AUTOFULL; + } + else if ((AuxStat & PHY_B_AS_AN_RES) == PHY_B_RES_1000HD) { + pPrt->PLinkModeStatus = SK_LMODE_STAT_AUTOHALF; + } + else { + /* Error. */ SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL, ("AutoNegFail: Duplex mode mismatch port %d\n", Port)); - pPrt->PAutoNegFail = SK_TRUE ; - return (SK_AND_DUP_CAP) ; + pPrt->PAutoNegFail = SK_TRUE; + return (SK_AND_DUP_CAP); } - /* Check Master/Slave resolution */ - if (ResAb & (PHY_B_1000S_MSF)) { - /* Error */ - SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL, +#if 0 +01-Sep-2000 RA;:;: + /* Check Master/Slave resolution. */ + if (ResAb & PHY_B_1000S_MSF) { + /* Error. */ + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, ("Master/Slave Fault port %d\n", Port)); pPrt->PAutoNegFail = SK_TRUE; pPrt->PMSStatus = SK_MS_STAT_FAULT; return (SK_AND_OTHER); - } else if (ResAb & PHY_B_1000S_MSR) { - pPrt->PMSStatus = SK_MS_STAT_MASTER ; - } else { - pPrt->PMSStatus = SK_MS_STAT_SLAVE ; } + else if (ResAb & PHY_B_1000S_MSR) { + pPrt->PMSStatus = SK_MS_STAT_MASTER; + } + else { + pPrt->PMSStatus = SK_MS_STAT_SLAVE; + } +#endif /* 0 */ - /* Check PAUSE mismatch */ - /* We are NOT using chapter 4.23 of the Xaqti manual */ - /* We are using IEEE 802.3z/D5.0 Table 37-4 */ + /* Check PAUSE mismatch. */ + /* We are NOT using chapter 4.23 of the Xaqti manual. */ + /* We are using IEEE 802.3z/D5.0 Table 37-4. */ if ((AuxStat & (PHY_B_AS_PRR | PHY_B_AS_PRT)) == (PHY_B_AS_PRR | PHY_B_AS_PRT)) { - /* Symmetric PAUSE */ + /* Symmetric PAUSE. */ pPrt->PFlowCtrlStatus = SK_FLOW_STAT_SYMMETRIC; - } else if ((AuxStat & (PHY_B_AS_PRR | PHY_B_AS_PRT)) == PHY_B_AS_PRR) { - /* Enable PAUSE receive, disable PAUSE transmit */ + } + else if ((AuxStat & (PHY_B_AS_PRR | PHY_B_AS_PRT)) == PHY_B_AS_PRR) { + /* Enable PAUSE receive, disable PAUSE transmit. */ pPrt->PFlowCtrlStatus = SK_FLOW_STAT_REM_SEND; - } else if ((AuxStat & (PHY_B_AS_PRR | PHY_B_AS_PRT)) == PHY_B_AS_PRT) { - /* Disable PAUSE receive, enable PAUSE transmit */ + } + else if ((AuxStat & (PHY_B_AS_PRR | PHY_B_AS_PRT)) == PHY_B_AS_PRT) { + /* Disable PAUSE receive, enable PAUSE transmit. */ pPrt->PFlowCtrlStatus = SK_FLOW_STAT_LOC_SEND; - } else { - /* PAUSE mismatch -> no PAUSE */ + } + else { + /* PAUSE mismatch -> no PAUSE. */ pPrt->PFlowCtrlStatus = SK_FLOW_STAT_NONE; } - /* We checked everything and may now enable the link */ - pPrt->PAutoNegFail = SK_FALSE ; + /* We checked everything and may now enable the link. */ + pPrt->PAutoNegFail = SK_FALSE; SkXmRxTxEnable(pAC, IoC, Port); - return(SK_AND_OK) ; -} + return (SK_AND_OK); +} /* SkXmAutoNegDoneBcom*/ + /****************************************************************************** * @@ -1740,11 +1847,11 @@ static int SkXmAutoNegDoneLone( SK_AC *pAC, /* adapter context */ SK_IOC IoC, /* IO context */ -int Port) /* Port Index (MAC_1 + n) */ +int Port) /* Port Index (MAC_1 + n) */ { SK_GEPORT *pPrt; - SK_U16 ResAb ; /* Resolved Ability */ - SK_U16 LPAb ; /* Link Partner Ability */ + SK_U16 ResAb; /* Resolved Ability */ + SK_U16 LPAb; /* Link Partner Ability */ SK_U16 QuickStat; /* Auxiliary Status */ SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL, ("AutoNegDoneLone" @@ -1761,15 +1868,16 @@ /* Error */ SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL, ("AutoNegFail: Remote fault bit set Port %d\n", Port)); - pPrt->PAutoNegFail = SK_TRUE ; - return (SK_AND_OTHER) ; + pPrt->PAutoNegFail = SK_TRUE; + return (SK_AND_OTHER); } /* Check Duplex mismatch */ if (QuickStat & PHY_L_QS_DUP_MOD) { - pPrt->PLinkModeStatus = SK_LMODE_STAT_AUTOFULL ; - } else { - pPrt->PLinkModeStatus = SK_LMODE_STAT_AUTOHALF ; + pPrt->PLinkModeStatus = SK_LMODE_STAT_AUTOFULL; + } + else { + pPrt->PLinkModeStatus = SK_LMODE_STAT_AUTOHALF; } /* Check Master/Slave resolution */ @@ -1778,12 +1886,14 @@ SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL, ("Master/Slave Fault port %d\n", Port)); pPrt->PAutoNegFail = SK_TRUE; - pPrt->PMSStatus = SK_MS_STAT_FAULT ; + pPrt->PMSStatus = SK_MS_STAT_FAULT; return (SK_AND_OTHER); - } else if (ResAb & PHY_L_1000S_MSR) { - pPrt->PMSStatus = SK_MS_STAT_MASTER ; - } else { - pPrt->PMSStatus = SK_MS_STAT_SLAVE ; + } + else if (ResAb & PHY_L_1000S_MSR) { + pPrt->PMSStatus = SK_MS_STAT_MASTER; + } + else { + pPrt->PMSStatus = SK_MS_STAT_SLAVE; } /* Check PAUSE mismatch */ @@ -1825,11 +1935,12 @@ } /* We checked everything and may now enable the link */ - pPrt->PAutoNegFail = SK_FALSE ; + pPrt->PAutoNegFail = SK_FALSE; SkXmRxTxEnable(pAC, IoC, Port); - return(SK_AND_OK); -} + return (SK_AND_OK); +} /* SkXmAutoNegDoneLone */ + /****************************************************************************** * @@ -1851,11 +1962,12 @@ static int SkXmAutoNegDoneNat( SK_AC *pAC, /* adapter context */ SK_IOC IoC, /* IO context */ -int Port) /* Port Index (MAC_1 + n) */ +int Port) /* Port Index (MAC_1 + n) */ { /* todo: National */ - return(SK_AND_OK); -} + return (SK_AND_OK); +} /* SkXmAutoNegDoneNat*/ + /****************************************************************************** * @@ -1873,10 +1985,10 @@ int SkXmRxTxEnable( SK_AC *pAC, /* adapter context */ SK_IOC IoC, /* IO context */ -int Port) /* Port Index (MAC_1 + n) */ +int Port) /* Port Index (MAC_1 + n) */ { SK_GEPORT *pPrt; - SK_U16 Reg ; /* 16bit register value */ + SK_U16 Reg; /* 16bit register value */ SK_U16 IntMask; /* XMac interrupt mask */ SK_U16 SWord; @@ -1884,7 +1996,7 @@ if (!pPrt->PHWLinkUp) { /* The Hardware link is NOT up */ - return(0) ; + return (0); } if ((pPrt->PLinkMode == SK_LMODE_AUTOHALF || @@ -1892,7 +2004,7 @@ pPrt->PLinkMode == SK_LMODE_AUTOBOTH) && pPrt->PAutoNegFail) { /* Autonegotiation is not done or failed */ - return(0) ; + return (0); } /* Set Dup Mode and Pause Mode */ @@ -1929,14 +2041,11 @@ /* Workaround BCOM Errata (#10523) for all BCom Phys */ /* Enable Power Management after link up */ PHY_READ(IoC, pPrt, Port, PHY_BCOM_AUX_CTRL, &SWord); - PHY_WRITE(IoC, pPrt, Port, PHY_BCOM_AUX_CTRL, - SWord & ~PHY_B_AC_DIS_PM); - PHY_WRITE(IoC, pPrt, Port, PHY_BCOM_INT_MASK, - PHY_B_DEF_MSK); + PHY_WRITE(IoC, pPrt, Port, PHY_BCOM_AUX_CTRL, SWord & ~PHY_B_AC_DIS_PM); + PHY_WRITE(IoC, pPrt, Port, PHY_BCOM_INT_MASK, PHY_B_DEF_MSK); break; case SK_PHY_LONE: - PHY_WRITE(IoC, pPrt, Port, PHY_LONE_INT_ENAB, - PHY_L_DEF_MSK); + PHY_WRITE(IoC, pPrt, Port, PHY_LONE_INT_ENAB, PHY_L_DEF_MSK); break; case SK_PHY_NAT: /* todo National: @@ -1948,9 +2057,10 @@ XM_OUT16(IoC, Port, XM_MMU_CMD, Reg | XM_MMU_ENA_RX | XM_MMU_ENA_TX); return (0); -} +} /* SkXmRxTxEnable*/ #ifndef SK_DIAG + /****************************************************************************** * * SkXmIrq() - Interrupt service routine @@ -1976,11 +2086,12 @@ void SkXmIrq( SK_AC *pAC, /* adapter context */ SK_IOC IoC, /* IO context */ -int Port, /* Port Index (MAC_1 + n) */ +int Port, /* Port Index (MAC_1 + n) */ SK_U16 IStatus) /* Interrupt status read from the XMAC */ { SK_GEPORT *pPrt; SK_EVPARA Para; + SK_U16 IStatus2; pPrt = &pAC->GIni.GP[Port]; @@ -1992,7 +2103,7 @@ } /* - * LinkPartner Autonegable ? + * LinkPartner Autonegable? */ if (pPrt->PhyType == SK_PHY_XMAC) { SkXmAutoNegLipaXmac(pAC, IoC, Port, IStatus); @@ -2004,11 +2115,22 @@ if (!pPrt->PHWLinkUp) { /* Spurious XMAC interrupt */ SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ, - ("SkXmIrq: spurious interrupt on port %d\n", - Port)); + ("SkXmIrq: spurious interrupt on port %d\n", Port)); return; } + if (IStatus & XM_IS_INP_ASS) { + /* Reread ISR Register if link is not in sync */ + XM_IN16(IoC, Port, XM_ISRC, &IStatus2); + + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ, + ("SkXmIrq: Link async. Double check port %d %x %x\n", + Port, IStatus, IStatus2)); + IStatus &= ~XM_IS_INP_ASS; + IStatus |= IStatus2; + + } + if (IStatus & XM_IS_LNK_AE) { /* not used GP0 is used instead */ } @@ -2030,7 +2152,7 @@ /* Start workaround Errata #2 timer */ SkTimerStart(pAC, IoC, &pAC->GIni.GP[Port].PWaTimer, - SK_WA_INA_TIME,SKGE_HWAC,SK_HWEV_WATIM,Para); + SK_WA_INA_TIME, SKGE_HWAC, SK_HWEV_WATIM, Para); } if (IStatus & XM_IS_RX_PAGE) { @@ -2069,7 +2191,7 @@ if (IStatus & XM_IS_TXF_UR) { /* may NOT happen -> error log */ SK_ERR_LOG(pAC, SK_ERRCL_HW , SKERR_SIRQ_E020, - SKERR_SIRQ_E020MSG) ; + SKERR_SIRQ_E020MSG); } if (IStatus & XM_IS_TX_COMP) { @@ -2080,7 +2202,8 @@ /* not served here */ } -} +} /* SkXmIrq*/ + #endif /* !SK_DIAG */ /* End of file */ diff -u --recursive --new-file v2.4.6/linux/drivers/net/sk_g16.c linux/drivers/net/sk_g16.c --- v2.4.6/linux/drivers/net/sk_g16.c Tue Jul 3 17:08:20 2001 +++ linux/drivers/net/sk_g16.c Wed Jul 4 11:50:39 2001 @@ -542,12 +542,13 @@ { int ioaddr; /* I/O port address used for POS regs */ int *port, ports[] = SK_IO_PORTS; /* SK_G16 supported ports */ + static unsigned version_printed; /* get preconfigured base_addr from dev which is done in Space.c */ int base_addr = dev->base_addr; - PRINTK(("%s: %s", SK_NAME, rcsid)); - rcsid = NULL; /* We do not want to use this further */ + if (version_printed++ == 0) + PRINTK(("%s: %s", SK_NAME, rcsid)); if (base_addr > 0x0ff) /* Check a single specified address */ { @@ -2078,7 +2079,7 @@ * YY/MM/DD uid Description -*/ -void SK_print_ram(struct net_device *dev) +void __init SK_print_ram(struct net_device *dev) { int i; diff -u --recursive --new-file v2.4.6/linux/drivers/net/sk_mca.c linux/drivers/net/sk_mca.c --- v2.4.6/linux/drivers/net/sk_mca.c Tue Feb 13 13:15:05 2001 +++ linux/drivers/net/sk_mca.c Wed Jul 4 11:50:39 2001 @@ -91,6 +91,7 @@ #include <linux/delay.h> #include <linux/time.h> #include <linux/mca.h> +#include <linux/init.h> #include <asm/processor.h> #include <asm/bitops.h> #include <asm/io.h> @@ -151,7 +152,7 @@ /* deduce resources out of POS registers */ -static void getaddrs(int slot, int junior, int *base, int *irq, +static void __init getaddrs(int slot, int junior, int *base, int *irq, skmca_medium * medium) { u_char pos0, pos1, pos2; @@ -197,7 +198,7 @@ is disabled and won't get detected using the standard probe. We therefore have to scan the slots manually :-( */ -static int dofind(int *junior, int firstslot) +static int __init dofind(int *junior, int firstslot) { int slot; unsigned int id; @@ -524,7 +525,7 @@ /* probe for device's irq */ -static int ProbeIRQ(struct SKMCA_NETDEV *dev) +static int __init ProbeIRQ(struct SKMCA_NETDEV *dev) { unsigned long imaskval, njiffies, irq; u16 csr0val; @@ -1072,7 +1073,7 @@ static int startslot; /* counts through slots when probing multiple devices */ -int skmca_probe(struct SKMCA_NETDEV *dev) +int __init skmca_probe(struct SKMCA_NETDEV *dev) { int force_detect = 0; int junior, slot, i; @@ -1250,8 +1251,8 @@ }; #endif -int irq = 0; -int io = 0; +int irq; +int io; int init_module(void) { diff -u --recursive --new-file v2.4.6/linux/drivers/net/skfp/ess.c linux/drivers/net/skfp/ess.c --- v2.4.6/linux/drivers/net/skfp/ess.c Wed Jul 5 10:56:13 2000 +++ linux/drivers/net/skfp/ess.c Wed Jul 4 11:50:39 2001 @@ -258,8 +258,16 @@ * Extract message parameters */ p = (void *) sm_to_para(smc,sm,SMT_P320F) ; + if (!p) { + printk(KERN_ERR "ESS: sm_to_para failed"); + return fs; + } payload = ((struct smt_p_320f *)p)->mib_payload ; p = (void *) sm_to_para(smc,sm,SMT_P3210) ; + if (!p) { + printk(KERN_ERR "ESS: sm_to_para failed"); + return fs; + } overhead = ((struct smt_p_3210 *)p)->mib_overhead ; DB_ESSN(2,"payload= %lx overhead= %lx\n",payload,overhead) ; diff -u --recursive --new-file v2.4.6/linux/drivers/net/smc-ultra.c linux/drivers/net/smc-ultra.c --- v2.4.6/linux/drivers/net/smc-ultra.c Tue Jul 3 17:08:20 2001 +++ linux/drivers/net/smc-ultra.c Tue Jul 17 18:53:55 2001 @@ -10,9 +10,10 @@ This software may be used and distributed according to the terms of the GNU General Public License, incorporated herein by reference. - The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O - Center of Excellence in Space Data and Information Sciences - Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771 + The author may be reached as becker@scyld.com, or C/O + Scyld Computing Corporation + 410 Severn Ave., Suite 210 + Annapolis MD 21403 This driver uses the cards in the 8390-compatible mode. Most of the run-time complexity is handled by the generic code in diff -u --recursive --new-file v2.4.6/linux/drivers/net/smc9194.c linux/drivers/net/smc9194.c --- v2.4.6/linux/drivers/net/smc9194.c Tue Jul 3 17:08:20 2001 +++ linux/drivers/net/smc9194.c Tue Jul 17 18:53:55 2001 @@ -25,7 +25,7 @@ . . Sources: . o SMC databook - . o skeleton.c by Donald Becker ( becker@cesdis.gsfc.nasa.gov ) + . o skeleton.c by Donald Becker ( becker@scyld.com ) . o ( a LOT of advice from Becker as well ) . . History: diff -u --recursive --new-file v2.4.6/linux/drivers/net/starfire.c linux/drivers/net/starfire.c --- v2.4.6/linux/drivers/net/starfire.c Tue Jul 3 17:08:20 2001 +++ linux/drivers/net/starfire.c Thu Jul 19 18:11:13 2001 @@ -85,13 +85,18 @@ - Fixed 2.2.x compatibility issues introduced in 1.3.1 - Fixed ethtool ioctl returning uninitialized memory + LK1.3.3 (Ion Badulescu) + - Initialize the TxMode register properly + - Set the MII registers _after_ resetting it + - Don't dereference dev->priv after unregister_netdev() has freed it + TODO: - implement tx_timeout() properly */ #define DRV_NAME "starfire" -#define DRV_VERSION "1.03+LK1.3.2" -#define DRV_RELDATE "June 04, 2001" +#define DRV_VERSION "1.03+LK1.3.3" +#define DRV_RELDATE "July 05, 2001" /* * Adaptec's license for their Novell drivers (which is where I got the @@ -192,12 +197,6 @@ #define skb_first_frag_len(skb) (skb->len) #endif /* not ZEROCOPY */ -#if !defined(__OPTIMIZE__) -#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/version.h> #include <linux/module.h> #include <linux/kernel.h> @@ -559,7 +558,7 @@ unsigned int cur_tx, dirty_tx; unsigned int rx_buf_sz; /* Based on MTU+slack. */ unsigned int tx_full:1, /* The Tx queue is full. */ - /* These values are keep track of the transceiver/media in use. */ + /* These values keep track of the transceiver/media in use. */ autoneg:1, /* Autonegotiation allowed. */ full_duplex:1, /* Full-duplex operation. */ speed100:1; /* Set if speed == 100MBit. */ @@ -572,6 +571,7 @@ unsigned char phys[PHY_CNT]; /* MII device addresses. */ }; + static int mdio_read(struct net_device *dev, int phy_id, int location); static void mdio_write(struct net_device *dev, int phy_id, int location, int value); static int netdev_open(struct net_device *dev); @@ -589,7 +589,7 @@ static int netdev_close(struct net_device *dev); static void netdev_media_change(struct net_device *dev); - + static int __devinit starfire_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) @@ -615,9 +615,9 @@ if (pci_enable_device (pdev)) return -EIO; - ioaddr = pci_resource_start (pdev, 0); - io_size = pci_resource_len (pdev, 0); - if (!ioaddr || ((pci_resource_flags (pdev, 0) & IORESOURCE_MEM) == 0)) { + ioaddr = pci_resource_start(pdev, 0); + io_size = pci_resource_len(pdev, 0); + if (!ioaddr || ((pci_resource_flags(pdev, 0) & IORESOURCE_MEM) == 0)) { printk (KERN_ERR DRV_NAME " %d: no PCI MEM resources, aborting\n", card_idx); return -ENODEV; } @@ -777,14 +777,13 @@ err_out_free_res: pci_release_regions (pdev); err_out_free_netdev: - unregister_netdev (dev); - kfree (dev); + unregister_netdev(dev); + kfree(dev); return -ENODEV; } - -/* Read the MII Management Data I/O (MDIO) interfaces. */ +/* Read the MII Management Data I/O (MDIO) interfaces. */ static int mdio_read(struct net_device *dev, int phy_id, int location) { long mdio_addr = dev->base_addr + MIICtrl + (phy_id<<7) + (location<<2); @@ -800,6 +799,7 @@ return result & 0xffff; } + static void mdio_write(struct net_device *dev, int phy_id, int location, int value) { long mdio_addr = dev->base_addr + MIICtrl + (phy_id<<7) + (location<<2); @@ -808,7 +808,7 @@ return; } - + static int netdev_open(struct net_device *dev) { struct netdev_private *np = dev->priv; @@ -931,6 +931,8 @@ /* Initialize other registers. */ /* Configure the PCI bus bursts and FIFO thresholds. */ np->tx_mode = 0x0C04; /* modified when link is up. */ + writel(0x8000 | np->tx_mode, ioaddr + TxMode); + writel(np->tx_mode, ioaddr + TxMode); np->tx_threshold = 4; writel(np->tx_threshold, ioaddr + TxThreshold); @@ -986,12 +988,12 @@ struct netdev_private *np = dev->priv; u16 reg0; - mdio_write(dev, np->phys[0], MII_ADVERTISE, np->advertising); mdio_write(dev, np->phys[0], MII_BMCR, BMCR_RESET); udelay(500); while (mdio_read(dev, np->phys[0], MII_BMCR) & BMCR_RESET); reg0 = mdio_read(dev, np->phys[0], MII_BMCR); + mdio_write(dev, np->phys[0], MII_ADVERTISE, np->advertising); if (np->autoneg) { reg0 |= BMCR_ANENABLE | BMCR_ANRESTART; @@ -1098,6 +1100,7 @@ return; } + static int start_tx(struct sk_buff *skb, struct net_device *dev) { struct netdev_private *np = dev->priv; @@ -1214,6 +1217,7 @@ return 0; } + /* The interrupt handler does all of the Rx thread work and cleans up after the Tx thread. */ static void intr_handler(int irq, void *dev_instance, struct pt_regs *rgs) @@ -1350,6 +1354,7 @@ #endif } + /* This routine is logically part of the interrupt handler, but separated for clarity and better register allocation. */ static int netdev_rx(struct net_device *dev) @@ -1407,11 +1412,9 @@ memcpy(skb_put(skb, pkt_len), np->rx_info[entry].skb->tail, pkt_len); #endif } else { - char *temp; - pci_unmap_single(np->pci_dev, np->rx_info[entry].mapping, np->rx_buf_sz, PCI_DMA_FROMDEVICE); skb = np->rx_info[entry].skb; - temp = skb_put(skb, pkt_len); + skb_put(skb, pkt_len); np->rx_info[entry].skb = NULL; np->rx_info[entry].mapping = 0; } @@ -1570,6 +1573,7 @@ np->stats.tx_fifo_errors++; } + static struct net_device_stats *get_stats(struct net_device *dev) { long ioaddr = dev->base_addr; @@ -1596,6 +1600,7 @@ return &np->stats; } + /* The little-endian AUTODIN II ethernet CRC calculations. A big-endian version is also available. This is slow but compact code. Do not use this routine for bulk data, @@ -1622,6 +1627,7 @@ return crc; } + static void set_rx_mode(struct net_device *dev) { long ioaddr = dev->base_addr; @@ -1658,7 +1664,7 @@ memset(mc_filter, 0, sizeof(mc_filter)); for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; - i++, mclist = mclist->next) { + i++, mclist = mclist->next) { int bit_nr = ether_crc_le(ETH_ALEN, mclist->dmi_addr) >> 23; __u32 *fptr = (__u32 *) &mc_filter[(bit_nr >> 4) & ~1]; @@ -1679,7 +1685,6 @@ } - static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr) { struct ethtool_cmd ecmd; @@ -1779,7 +1784,6 @@ } - static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { struct netdev_private *np = dev->priv; @@ -1808,10 +1812,11 @@ u16 value = data->val_in; switch (data->reg_num) { case 0: - if (value & 0x9000) /* Autonegotiation. */ + if (value & (BMCR_RESET | BMCR_ANENABLE)) + /* Autonegotiation. */ np->autoneg = 1; else { - np->full_duplex = (value & 0x0100) ? 1 : 0; + np->full_duplex = (value & BMCR_FULLDPLX) ? 1 : 0; np->autoneg = 0; } break; @@ -1921,27 +1926,26 @@ BUG(); np = dev->priv; - - unregister_netdev(dev); - iounmap((char *)dev->base_addr); - pci_release_regions(pdev); - if (np->tx_done_q) - pci_free_consistent(np->pci_dev, PAGE_SIZE, + pci_free_consistent(pdev, PAGE_SIZE, np->tx_done_q, np->tx_done_q_dma); if (np->rx_done_q) - pci_free_consistent(np->pci_dev, PAGE_SIZE, + pci_free_consistent(pdev, + sizeof(struct rx_done_desc) * DONE_Q_SIZE, np->rx_done_q, np->rx_done_q_dma); if (np->tx_ring) - pci_free_consistent(np->pci_dev, PAGE_SIZE, + pci_free_consistent(pdev, PAGE_SIZE, np->tx_ring, np->tx_ring_dma); if (np->rx_ring) - pci_free_consistent(np->pci_dev, PAGE_SIZE, + pci_free_consistent(pdev, PAGE_SIZE, np->rx_ring, np->rx_ring_dma); - kfree(dev); + unregister_netdev(dev); /* Will also free np!! */ + iounmap((char *)dev->base_addr); + pci_release_regions(pdev); pci_set_drvdata(pdev, NULL); + kfree(dev); } diff -u --recursive --new-file v2.4.6/linux/drivers/net/stnic.c linux/drivers/net/stnic.c --- v2.4.6/linux/drivers/net/stnic.c Wed Apr 11 21:24:52 2001 +++ linux/drivers/net/stnic.c Tue Jul 10 20:16:30 2001 @@ -146,6 +146,11 @@ ei_status.name = dev->name; ei_status.word16 = 1; +#ifdef __LITTLE_ENDIAN__ + ei_status.bigendian = 0; +#else + ei_status.bigendian = 1; +#endif ei_status.tx_start_page = START_PG; ei_status.rx_start_page = START_PG + TX_PAGES; ei_status.stop_page = STOP_PG; @@ -154,6 +159,7 @@ ei_status.get_8390_hdr = &stnic_get_hdr; ei_status.block_input = &stnic_block_input; ei_status.block_output = &stnic_block_output; + stnic_init (dev); printk (KERN_INFO "NS ST-NIC 83902A\n"); diff -u --recursive --new-file v2.4.6/linux/drivers/net/sun3lance.c linux/drivers/net/sun3lance.c --- v2.4.6/linux/drivers/net/sun3lance.c Tue Jul 3 17:08:20 2001 +++ linux/drivers/net/sun3lance.c Wed Jul 4 11:50:39 2001 @@ -881,7 +881,7 @@ #ifdef MODULE -static char devicename[9] = { 0, }; +static char devicename[9]; static struct net_device sun3lance_dev = { diff -u --recursive --new-file v2.4.6/linux/drivers/net/sundance.c linux/drivers/net/sundance.c --- v2.4.6/linux/drivers/net/sundance.c Tue Jul 3 17:08:20 2001 +++ linux/drivers/net/sundance.c Tue Jul 17 18:53:55 2001 @@ -60,6 +60,8 @@ #define TX_RING_SIZE 16 #define TX_QUEUE_LEN 10 /* Limit ring entries actually used. */ #define RX_RING_SIZE 32 +#define TX_TOTAL_SIZE TX_RING_SIZE*sizeof(struct netdev_desc) +#define RX_TOTAL_SIZE RX_RING_SIZE*sizeof(struct netdev_desc) /* Operational parameters that usually are not changed. */ /* Time in jiffies before concluding the transmitter is hung. */ @@ -104,11 +106,6 @@ KERN_INFO DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " Written by Donald Becker\n" KERN_INFO " http://www.scyld.com/network/sundance.html\n"; -/* Condensed operations for readability. */ -#define virt_to_le32desc(addr) cpu_to_le32(virt_to_bus(addr)) -#define le32desc_to_virt(addr) bus_to_virt(le32_to_cpu(addr)) - - MODULE_AUTHOR("Donald Becker <becker@scyld.com>"); MODULE_DESCRIPTION("Sundance Alta Ethernet driver"); MODULE_PARM(max_interrupt_work, "i"); @@ -265,22 +262,54 @@ multiple times should be defined symbolically. */ enum alta_offsets { - DMACtrl=0x00, TxListPtr=0x04, TxDMACtrl=0x08, TxDescPoll=0x0a, - RxDMAStatus=0x0c, RxListPtr=0x10, RxDMACtrl=0x14, RxDescPoll=0x16, - LEDCtrl=0x1a, ASICCtrl=0x30, - EEData=0x34, EECtrl=0x36, TxThreshold=0x3c, - FlashAddr=0x40, FlashData=0x44, TxStatus=0x46, DownCounter=0x48, - IntrClear=0x4a, IntrEnable=0x4c, IntrStatus=0x4e, - MACCtrl0=0x50, MACCtrl1=0x52, StationAddr=0x54, - MaxTxSize=0x5A, RxMode=0x5c, MIICtrl=0x5e, - MulticastFilter0=0x60, MulticastFilter1=0x64, - RxOctetsLow=0x68, RxOctetsHigh=0x6a, TxOctetsLow=0x6c, TxOctetsHigh=0x6e, - TxFramesOK=0x70, RxFramesOK=0x72, StatsCarrierError=0x74, - StatsLateColl=0x75, StatsMultiColl=0x76, StatsOneColl=0x77, - StatsTxDefer=0x78, RxMissed=0x79, StatsTxXSDefer=0x7a, StatsTxAbort=0x7b, - StatsBcastTx=0x7c, StatsBcastRx=0x7d, StatsMcastTx=0x7e, StatsMcastRx=0x7f, + DMACtrl = 0x00, + TxListPtr = 0x04, + TxDMACtrl = 0x08, + TxDescPoll = 0x0a, + RxDMAStatus = 0x0c, + RxListPtr = 0x10, + RxDMACtrl = 0x14, + RxDescPoll = 0x16, + LEDCtrl = 0x1a, + ASICCtrl = 0x30, + EEData = 0x34, + EECtrl = 0x36, + TxThreshold = 0x3c, + FlashAddr = 0x40, + FlashData = 0x44, + TxStatus = 0x46, + DownCounter = 0x18, + IntrClear = 0x4a, + IntrEnable = 0x4c, + IntrStatus = 0x4e, + MACCtrl0 = 0x50, + MACCtrl1 = 0x52, + StationAddr = 0x54, + MaxTxSize = 0x5A, + RxMode = 0x5c, + MIICtrl = 0x5e, + MulticastFilter0 = 0x60, + MulticastFilter1 = 0x64, + RxOctetsLow = 0x68, + RxOctetsHigh = 0x6a, + TxOctetsLow = 0x6c, + TxOctetsHigh = 0x6e, + TxFramesOK = 0x70, + RxFramesOK = 0x72, + StatsCarrierError = 0x74, + StatsLateColl = 0x75, + StatsMultiColl = 0x76, + StatsOneColl = 0x77, + StatsTxDefer = 0x78, + RxMissed = 0x79, + StatsTxXSDefer = 0x7a, + StatsTxAbort = 0x7b, + StatsBcastTx = 0x7c, + StatsBcastRx = 0x7d, + StatsMcastTx = 0x7e, + StatsMcastRx = 0x7f, /* Aliased and bogus values! */ - RxStatus=0x0c, + RxStatus = 0x0c, }; /* Bits in the interrupt status/mask registers. */ @@ -319,8 +348,13 @@ /* Bits in netdev_desc.status */ enum desc_status_bits { - DescOwn=0x8000, DescEndPacket=0x4000, DescEndRing=0x2000, - LastFrag=0x80000000, DescIntrOnTx=0x8000, DescIntrOnDMADone=0x80000000, + DescOwn=0x8000, + DescEndPacket=0x4000, + DescEndRing=0x2000, + LastFrag=0x80000000, + DescIntrOnTx=0x8000, + DescIntrOnDMADone=0x80000000, + DisableAlign = 0x00000001, }; #define PRIV_ALIGN 15 /* Required alignment mask */ @@ -329,19 +363,17 @@ #define MII_CNT 4 struct netdev_private { /* Descriptor rings first for alignment. */ - struct netdev_desc rx_ring[RX_RING_SIZE]; - struct netdev_desc tx_ring[TX_RING_SIZE]; - /* The addresses of receive-in-place skbuffs. */ + struct netdev_desc *rx_ring; + struct netdev_desc *tx_ring; struct sk_buff* rx_skbuff[RX_RING_SIZE]; - /* The saved address of a sent-in-place packet/buffer, for later free(). */ struct sk_buff* tx_skbuff[TX_RING_SIZE]; + dma_addr_t tx_ring_dma; + dma_addr_t rx_ring_dma; struct net_device_stats stats; struct timer_list timer; /* Media monitoring timer. */ /* Frequently used values: keep some adjacent for cache effect. */ spinlock_t lock; int chip_id, drv_flags; - /* Note: Cache paragraph grouped variables. */ - struct netdev_desc *rx_head_desc; unsigned int cur_rx, dirty_rx; /* Producer/consumer ring indices */ unsigned int rx_buf_sz; /* Based on MTU+slack. */ spinlock_t txlock; /* Group with Tx control cache line. */ @@ -396,6 +428,9 @@ int irq; int i, option = card_idx < MAX_UNITS ? options[card_idx] : 0; long ioaddr; + void *ring_space; + dma_addr_t ring_dma; + /* when built into the kernel, we only print version if device is found */ #ifndef MODULE @@ -440,6 +475,18 @@ np->pci_dev = pdev; spin_lock_init(&np->lock); + ring_space = pci_alloc_consistent(pdev, TX_TOTAL_SIZE, &ring_dma); + if (!ring_space) + goto err_out_cleardev; + np->tx_ring = (struct netdev_desc *)ring_space; + np->tx_ring_dma = ring_dma; + + ring_space = pci_alloc_consistent(pdev, RX_TOTAL_SIZE, &ring_dma); + if (!ring_space) + goto err_out_unmap_tx; + np->rx_ring = (struct netdev_desc *)ring_space; + np->rx_ring_dma = ring_dma; + if (dev->mem_start) option = dev->mem_start; @@ -473,7 +520,7 @@ i = register_netdev(dev); if (i) - goto err_out_cleardev; + goto err_out_unmap_rx; printk(KERN_INFO "%s: %s at 0x%lx, ", dev->name, pci_id_tbl[chip_idx].name, ioaddr); @@ -511,6 +558,10 @@ card_idx++; return 0; +err_out_unmap_rx: + pci_free_consistent(pdev, RX_TOTAL_SIZE, np->rx_ring, np->rx_ring_dma); +err_out_unmap_tx: + pci_free_consistent(pdev, TX_TOTAL_SIZE, np->tx_ring, np->tx_ring_dma); err_out_cleardev: pci_set_drvdata(pdev, NULL); #ifndef USE_IO_OPS @@ -549,7 +600,7 @@ /* Set iff a MII transceiver on any interface requires mdio preamble. This only set with older tranceivers, so the extra code size of a per-interface flag is not worthwhile. */ -static char mii_preamble_required; +static const char mii_preamble_required = 1; enum mii_reg_bits { MDIO_ShiftClk=0x0001, MDIO_Data=0x0002, MDIO_EnbOutput=0x0004, @@ -649,7 +700,7 @@ init_ring(dev); - writel(virt_to_bus(np->rx_ring), ioaddr + RxListPtr); + writel(np->rx_ring_dma, ioaddr + RxListPtr); /* The Tx list pointer is written as packets are queued. */ for (i = 0; i < 6; i++) @@ -665,6 +716,7 @@ np->mcastlock = (spinlock_t) SPIN_LOCK_UNLOCKED; set_rx_mode(dev); + writew(0, ioaddr + IntrEnable); writew(0, ioaddr + DownCounter); /* Set the chip to poll every N*320nsec. */ writeb(100, ioaddr + RxDescPoll); @@ -779,17 +831,15 @@ np->dirty_rx = np->dirty_tx = 0; np->rx_buf_sz = (dev->mtu <= 1500 ? PKT_BUF_SZ : dev->mtu + 32); - np->rx_head_desc = &np->rx_ring[0]; /* Initialize all Rx descriptors. */ for (i = 0; i < RX_RING_SIZE; i++) { - np->rx_ring[i].next_desc = virt_to_le32desc(&np->rx_ring[i+1]); + np->rx_ring[i].next_desc = cpu_to_le32(np->rx_ring_dma + + ((i+1)%RX_RING_SIZE)*sizeof(*np->rx_ring)); np->rx_ring[i].status = 0; np->rx_ring[i].frag[0].length = 0; np->rx_skbuff[i] = 0; } - /* Wrap the ring. */ - np->rx_ring[i-1].next_desc = virt_to_le32desc(&np->rx_ring[0]); /* Fill in the Rx buffers. Handle allocation failure gracefully. */ for (i = 0; i < RX_RING_SIZE; i++) { @@ -797,9 +847,11 @@ np->rx_skbuff[i] = skb; if (skb == NULL) break; - skb->dev = dev; /* Mark as being used by this device. */ + skb->dev = dev; /* Mark as being used by this device. */ skb_reserve(skb, 2); /* 16 byte align the IP header. */ - np->rx_ring[i].frag[0].addr = virt_to_le32desc(skb->tail); + np->rx_ring[i].frag[0].addr = cpu_to_le32( + pci_map_single(np->pci_dev, skb->tail, np->rx_buf_sz, + PCI_DMA_FROMDEVICE)); np->rx_ring[i].frag[0].length = cpu_to_le32(np->rx_buf_sz | LastFrag); } np->dirty_rx = (unsigned int)(i - RX_RING_SIZE); @@ -828,11 +880,13 @@ txdesc->next_desc = 0; /* Note: disable the interrupt generation here before releasing. */ txdesc->status = - cpu_to_le32((entry<<2) | DescIntrOnDMADone | DescIntrOnTx); - txdesc->frag[0].addr = virt_to_le32desc(skb->data); + cpu_to_le32((entry<<2) | DescIntrOnDMADone | DescIntrOnTx | DisableAlign); + txdesc->frag[0].addr = cpu_to_le32(pci_map_single(np->pci_dev, + skb->data, skb->len, PCI_DMA_TODEVICE)); txdesc->frag[0].length = cpu_to_le32(skb->len | LastFrag); if (np->last_tx) - np->last_tx->next_desc = virt_to_le32desc(txdesc); + np->last_tx->next_desc = cpu_to_le32(np->tx_ring_dma + + entry*sizeof(struct netdev_desc)); np->last_tx = txdesc; np->cur_tx++; @@ -846,7 +900,8 @@ } /* Side effect: The read wakes the potentially-idle transmit channel. */ if (readl(dev->base_addr + TxListPtr) == 0) - writel(virt_to_bus(&np->tx_ring[entry]), dev->base_addr + TxListPtr); + writel(np->tx_ring_dma + entry*sizeof(*np->tx_ring), + dev->base_addr + TxListPtr); dev->trans_start = jiffies; @@ -873,9 +928,8 @@ do { int intr_status = readw(ioaddr + IntrStatus); writew(intr_status & (IntrRxDone | IntrRxDMADone | IntrPCIErr | - IntrDrvRqst |IntrTxDone|IntrTxDMADone | - StatsMax | LinkChange), - ioaddr + IntrStatus); + IntrDrvRqst | IntrTxDone | IntrTxDMADone | StatsMax | + LinkChange), ioaddr + IntrStatus); if (debug > 4) printk(KERN_DEBUG "%s: Interrupt, status %4.4x.\n", @@ -908,8 +962,9 @@ if (tx_status & 0x10) { /* Reset the Tx. */ writew(0x001c, ioaddr + ASICCtrl + 2); #if 0 /* Do we need to reset the Tx pointer here? */ - writel(virt_to_bus(&np->tx_ring[np->dirty_tx]), - dev->base_addr + TxListPtr); + writel(np->tx_ring_dma + + np->dirty_tx*sizeof(*np->tx_ring), + dev->base_addr + TxListPtr); #endif } if (tx_status & 0x1e) /* Restart the Tx. */ @@ -924,10 +979,16 @@ } for (; np->cur_tx - np->dirty_tx > 0; np->dirty_tx++) { int entry = np->dirty_tx % TX_RING_SIZE; + struct sk_buff *skb; + if ( ! (np->tx_ring[entry].status & 0x00010000)) break; + skb = np->tx_skbuff[entry]; /* Free the original skb. */ - dev_kfree_skb_irq(np->tx_skbuff[entry]); + pci_unmap_single(np->pci_dev, + np->tx_ring[entry].frag[0].addr, + skb->len, PCI_DMA_TODEVICE); + dev_kfree_skb_irq(skb); np->tx_skbuff[entry] = 0; } if (np->tx_full @@ -947,6 +1008,7 @@ "status=0x%4.4x / 0x%4.4x.\n", dev->name, intr_status, readw(ioaddr + IntrClear)); /* Re-enable us in 3.2msec. */ + writew(0, ioaddr + IntrEnable); writew(1000, ioaddr + DownCounter); writew(IntrDrvRqst, ioaddr + IntrEnable); break; @@ -974,16 +1036,23 @@ } /* If EOP is set on the next entry, it's a new packet. Send it up. */ - while (np->rx_head_desc->status & DescOwn) { - struct netdev_desc *desc = np->rx_head_desc; - u32 frame_status = le32_to_cpu(desc->status); - int pkt_len = frame_status & 0x1fff; /* Chip omits the CRC. */ + while (1) { + struct netdev_desc *desc = &(np->rx_ring[entry]); + u32 frame_status; + int pkt_len; + if (!(desc->status & DescOwn)) + break; + frame_status = le32_to_cpu(desc->status); + pkt_len = frame_status & 0x1fff; /* Chip omits the CRC. */ if (debug > 4) printk(KERN_DEBUG " netdev_rx() status was %8.8x.\n", frame_status); if (--boguscnt < 0) break; + pci_dma_sync_single(np->pci_dev, desc->frag[0].addr, + np->rx_buf_sz, PCI_DMA_FROMDEVICE); + if (frame_status & 0x001f4000) { /* There was a error. */ if (debug > 2) @@ -1017,6 +1086,10 @@ eth_copy_and_sum(skb, np->rx_skbuff[entry]->tail, pkt_len, 0); skb_put(skb, pkt_len); } else { + pci_unmap_single(np->pci_dev, + desc->frag[0].addr, + np->rx_buf_sz, + PCI_DMA_FROMDEVICE); skb_put(skb = np->rx_skbuff[entry], pkt_len); np->rx_skbuff[entry] = NULL; } @@ -1026,7 +1099,6 @@ dev->last_rx = jiffies; } entry = (++np->cur_rx) % RX_RING_SIZE; - np->rx_head_desc = &np->rx_ring[entry]; } /* Refill the Rx ring buffers. */ @@ -1037,10 +1109,12 @@ skb = dev_alloc_skb(np->rx_buf_sz); np->rx_skbuff[entry] = skb; if (skb == NULL) - break; /* Better luck next round. */ - skb->dev = dev; /* Mark as being used by this device. */ + break; /* Better luck next round. */ + skb->dev = dev; /* Mark as being used by this device. */ skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ - np->rx_ring[entry].frag[0].addr = virt_to_le32desc(skb->tail); + np->rx_ring[entry].frag[0].addr = cpu_to_le32( + pci_map_single(np->pci_dev, skb->tail, + np->rx_buf_sz, PCI_DMA_FROMDEVICE)); } /* Perhaps we need not reset this field. */ np->rx_ring[entry].frag[0].length = @@ -1060,6 +1134,7 @@ if (intr_status & IntrDrvRqst) { /* Stop the down counter and turn interrupts back on. */ printk("%s: Turning interrupts back on.\n", dev->name); + writew(0, ioaddr + IntrEnable); writew(0, ioaddr + DownCounter); writew(IntrRxDone | IntrRxDMADone | IntrPCIErr | IntrDrvRqst | IntrTxDone | StatsMax | LinkChange, ioaddr + IntrEnable); @@ -1226,6 +1301,7 @@ { long ioaddr = dev->base_addr; struct netdev_private *np = dev->priv; + struct sk_buff *skb; int i; netif_stop_queue(dev); @@ -1248,13 +1324,13 @@ #ifdef __i386__ if (debug > 2) { printk("\n"KERN_DEBUG" Tx ring at %8.8x:\n", - (int)virt_to_bus(np->tx_ring)); + (int)(np->tx_ring_dma)); for (i = 0; i < TX_RING_SIZE; i++) printk(" #%d desc. %4.4x %8.8x %8.8x.\n", i, np->tx_ring[i].status, np->tx_ring[i].frag[0].addr, np->tx_ring[i].frag[0].length); printk("\n"KERN_DEBUG " Rx ring %8.8x:\n", - (int)virt_to_bus(np->rx_ring)); + (int)(np->rx_ring_dma)); for (i = 0; i < /*RX_RING_SIZE*/4 ; i++) { printk(KERN_DEBUG " #%d desc. %4.4x %4.4x %8.8x\n", i, np->rx_ring[i].status, np->rx_ring[i].frag[0].addr, @@ -1271,15 +1347,24 @@ for (i = 0; i < RX_RING_SIZE; i++) { np->rx_ring[i].status = 0; np->rx_ring[i].frag[0].addr = 0xBADF00D0; /* An invalid address. */ - if (np->rx_skbuff[i]) { - dev_kfree_skb(np->rx_skbuff[i]); + skb = np->rx_skbuff[i]; + if (skb) { + pci_unmap_single(np->pci_dev, + np->rx_ring[i].frag[0].addr, np->rx_buf_sz, + PCI_DMA_FROMDEVICE); + dev_kfree_skb(skb); + np->rx_skbuff[i] = 0; } - np->rx_skbuff[i] = 0; } for (i = 0; i < TX_RING_SIZE; i++) { - if (np->tx_skbuff[i]) - dev_kfree_skb(np->tx_skbuff[i]); - np->tx_skbuff[i] = 0; + skb = np->tx_skbuff[i]; + if (skb) { + pci_unmap_single(np->pci_dev, + np->tx_ring[i].frag[0].addr, skb->len, + PCI_DMA_TODEVICE); + dev_kfree_skb(skb); + np->tx_skbuff[i] = 0; + } } return 0; @@ -1291,15 +1376,20 @@ /* No need to check MOD_IN_USE, as sys_delete_module() checks. */ if (dev) { + struct netdev_private *np = dev->priv; + unregister_netdev(dev); + pci_free_consistent(pdev, RX_TOTAL_SIZE, np->rx_ring, + np->rx_ring_dma); + pci_free_consistent(pdev, TX_TOTAL_SIZE, np->tx_ring, + np->tx_ring_dma); pci_release_regions(pdev); #ifndef USE_IO_OPS iounmap((char *)(dev->base_addr)); #endif kfree(dev); + pci_set_drvdata(pdev, NULL); } - - pci_set_drvdata(pdev, NULL); } static struct pci_driver sundance_driver = { diff -u --recursive --new-file v2.4.6/linux/drivers/net/tokenring/ibmtr.c linux/drivers/net/tokenring/ibmtr.c --- v2.4.6/linux/drivers/net/tokenring/ibmtr.c Tue Jul 3 17:08:20 2001 +++ linux/drivers/net/tokenring/ibmtr.c Tue Jul 17 18:53:55 2001 @@ -7,10 +7,11 @@ * This device driver should work with Any IBM Token Ring Card that does * not use DMA. * - * I used Donald Becker's (becker@cesdis.gsfc.nasa.gov) device driver work + * I used Donald Becker's (becker@scyld.com) device driver work * as a base for most of my initial work. * - * Changes by Peter De Schrijver (Peter.Deschrijver@linux.cc.kuleuven.ac.be) : + * Changes by Peter De Schrijver + * (Peter.Deschrijver@linux.cc.kuleuven.ac.be) : * * + changed name to ibmtr.c in anticipation of other tr boards. * + changed reset code and adapter open code. @@ -47,6 +48,7 @@ * + added -DPCMCIA to support PCMCIA * + detecting PCMCIA Card Removal in interrupt handler. If * ISRP is FF, then a PCMCIA card has been removed + * 10/2000 Burt needed a new method to avoid crashing the OS * * Changes by Paul Norton (pnorton@cts.com) : * + restructured the READ.LOG logic to prevent the transmit SRB @@ -83,7 +85,7 @@ * Changes by Jochen Friedrich to enable RFC1469 Option 2 multicasting * i.e. using functional address C0 00 00 04 00 00 to transmit and * receive multicast packets. - * + * * Changes by Mike Sullivan (based on original sram patch by Dave Grothe * to support windowing into on adapter shared ram. * i.e. Use LANAID to setup a PnP configuration with 16K RAM. Paging @@ -91,6 +93,13 @@ * * Changes by Peter De Schrijver (p2@mind.be) : * + fixed a problem with PCMCIA card removal + * + * Change by Mike Sullivan et al.: + * + added turbo card support. No need to use lanaid to configure + * the adapter into isa compatiblity mode. + * + * Changes by Burt Silverman to allow the computer to behave nicely when + * a cable is pulled or not in place, or a PCMCIA card is removed hot. */ /* change the define of IBMTR_DEBUG_MESSAGES to a nonzero value @@ -100,207 +109,247 @@ #include <linux/module.h> -#define NO_AUTODETECT 1 -#undef NO_AUTODETECT -/* #undef ENABLE_PAGING */ -#define ENABLE_PAGING 1 - +#ifdef PCMCIA +#undef MODULE +#undef ENABLE_PAGING +#else +#define ENABLE_PAGING 1 +#endif #define FALSE 0 #define TRUE (!FALSE) -/* changes the output format of driver initialisation */ -#define TR_NEWFORMAT 1 +/* changes the output format of driver initialization */ #define TR_VERBOSE 0 /* some 95 OS send many non UI frame; this allow removing the warning */ #define TR_FILTERNONUI 1 -/* version and credits */ -static char *version = -"ibmtr.c: v1.3.57 8/ 7/94 Peter De Schrijver and Mark Swanson\n" -" v2.1.125 10/20/98 Paul Norton <pnorton@ieee.org>\n" -" v2.2.0 12/30/98 Joel Sloan <jjs@c-me.com>\n" -" v2.2.1 02/08/00 Mike Sullivan <sullivam@us.ibm.com>\n"; - -static char pcchannelid[] = { - 0x05, 0x00, 0x04, 0x09, - 0x04, 0x03, 0x04, 0x0f, - 0x03, 0x06, 0x03, 0x01, - 0x03, 0x01, 0x03, 0x00, - 0x03, 0x09, 0x03, 0x09, - 0x03, 0x00, 0x02, 0x00 -}; - -static char mcchannelid[] = { - 0x04, 0x0d, 0x04, 0x01, - 0x05, 0x02, 0x05, 0x03, - 0x03, 0x06, 0x03, 0x03, - 0x05, 0x08, 0x03, 0x04, - 0x03, 0x05, 0x03, 0x01, - 0x03, 0x08, 0x02, 0x00 -}; - -#include <linux/kernel.h> #include <linux/sched.h> -#include <linux/errno.h> -#include <linux/timer.h> -#include <linux/in.h> #include <linux/ioport.h> -#include <linux/string.h> -#include <linux/skbuff.h> -#include <linux/interrupt.h> -#include <linux/delay.h> #include <linux/netdevice.h> #include <linux/trdevice.h> -#include <linux/stddef.h> -#include <linux/init.h> -#include <linux/spinlock.h> #include <linux/ibmtr.h> #include <net/checksum.h> #include <asm/io.h> -#include <asm/system.h> -#include <asm/bitops.h> - - #define DPRINTK(format, args...) printk("%s: " format, dev->name , ## args) #define DPRINTD(format, args...) DummyCall("%s: " format, dev->name , ## args) #define MIN(X, Y) ((X) < (Y) ? (X) : (Y)) #define MAX(X, Y) ((X) > (Y) ? (X) : (Y)) -#if TR_NEWFORMAT +/* version and credits */ +#ifndef PCMCIA +static char version[] __initdata = + "\nibmtr.c: v1.3.57 8/ 7/94 Peter De Schrijver and Mark Swanson\n" + " v2.1.125 10/20/98 Paul Norton <pnorton@ieee.org>\n" + " v2.2.0 12/30/98 Joel Sloan <jjs@c-me.com>\n" + " v2.2.1 02/08/00 Mike Sullivan <sullivam@us.ibm.com>\n" + " v2.2.2 07/27/00 Burt Silverman <burts@us.ibm.com>\n" + " v2.4.0 03/01/01 Mike Sullivan <sullivan@us.ibm.com>\n"; +#endif + /* this allows displaying full adapter information */ -const char *channel_def[] __initdata = { - "ISA", "MCA", "ISA P&P" +char *channel_def[] __initdata = { "ISA", "MCA", "ISA P&P" }; + +static char pcchannelid[] __devinitdata = { + 0x05, 0x00, 0x04, 0x09, + 0x04, 0x03, 0x04, 0x0f, + 0x03, 0x06, 0x03, 0x01, + 0x03, 0x01, 0x03, 0x00, + 0x03, 0x09, 0x03, 0x09, + 0x03, 0x00, 0x02, 0x00 +}; + +static char mcchannelid[] __devinitdata = { + 0x04, 0x0d, 0x04, 0x01, + 0x05, 0x02, 0x05, 0x03, + 0x03, 0x06, 0x03, 0x03, + 0x05, 0x08, 0x03, 0x04, + 0x03, 0x05, 0x03, 0x01, + 0x03, 0x08, 0x02, 0x00 }; -char __init *adapter_def(char type) +char __devinit *adapter_def(char type) { - switch (type) - { - case 0xF : return "PC Adapter | PC Adapter II | Adapter/A"; - case 0xE : return "16/4 Adapter | 16/4 Adapter/A (long)"; - case 0xD : return "16/4 Adapter/A (short) | 16/4 ISA-16 Adapter"; - case 0xC : return "Auto 16/4 Adapter"; - default : return "adapter (unknown type)"; + switch (type) { + case 0xF: return "PC Adapter | PC Adapter II | Adapter/A"; + case 0xE: return "16/4 Adapter | 16/4 Adapter/A (long)"; + case 0xD: return "16/4 Adapter/A (short) | 16/4 ISA-16 Adapter"; + case 0xC: return "Auto 16/4 Adapter"; + default: return "adapter (unknown type)"; }; }; -#endif -#if !TR_NEWFORMAT -unsigned char ibmtr_debug_trace=1; /* Patch or otherwise alter to - control tokenring tracing. */ -#else -unsigned char ibmtr_debug_trace=0; -#endif -#define TRC_INIT 0x01 /* Trace initialization & PROBEs */ -#define TRC_INITV 0x02 /* verbose init trace points */ +#define TRC_INIT 0x01 /* Trace initialization & PROBEs */ +#define TRC_INITV 0x02 /* verbose init trace points */ +unsigned char ibmtr_debug_trace = 0; -int ibmtr_probe(struct net_device *dev); +int ibmtr_probe(struct net_device *dev); static int ibmtr_probe1(struct net_device *dev, int ioaddr); -static unsigned char get_sram_size(struct tok_info *adapt_info); -#ifdef PCMCIA -extern unsigned char pcmcia_reality_check(unsigned char gss); -#endif -static int tok_init_card(struct net_device *dev); -void tok_interrupt(int irq, void *dev_id, struct pt_regs *regs); -static int trdev_init(struct net_device *dev); +static unsigned char get_sram_size(struct tok_info *adapt_info); +static int trdev_init(struct net_device *dev); +static int tok_open(struct net_device *dev); +static int tok_init_card(struct net_device *dev); +void tok_open_adapter(unsigned long dev_addr); +static void open_sap(unsigned char type, struct net_device *dev); +static void tok_set_multicast_list(struct net_device *dev); +static int tok_send_packet(struct sk_buff *skb, struct net_device *dev); +static int tok_close(struct net_device *dev); +void tok_interrupt(int irq, void *dev_id, struct pt_regs *regs); static void initial_tok_int(struct net_device *dev); -static void open_sap(unsigned char type,struct net_device *dev); -void tok_open_adapter(unsigned long dev_addr); -static void tr_rx(struct net_device *dev); -static void tr_tx(struct net_device *dev); -static int tok_open(struct net_device *dev); -static int tok_close(struct net_device *dev); -static int tok_send_packet(struct sk_buff *skb, struct net_device *dev); -static struct net_device_stats * tok_get_stats(struct net_device *dev); -static void tok_set_multicast_list(struct net_device *dev); -void ibmtr_readlog(struct net_device *dev); -void ibmtr_reset_timer(struct timer_list *tmr, struct net_device *dev); -int ibmtr_change_mtu(struct net_device *dev, int mtu); +static void tr_tx(struct net_device *dev); +static void tr_rx(struct net_device *dev); +void ibmtr_reset_timer(struct timer_list*tmr,struct net_device *dev); +static void tok_rerun(unsigned long dev_addr); +void ibmtr_readlog(struct net_device *dev); +static struct net_device_stats *tok_get_stats(struct net_device *dev); +int ibmtr_change_mtu(struct net_device *dev, int mtu); +static void find_turbo_adapters(int *iolist); -static unsigned int ibmtr_portlist[] __initdata = { - 0xa20, 0xa24, 0 +static int ibmtr_portlist[IBMTR_MAX_ADAPTERS+1] __devinitdata = { + 0xa20, 0xa24, 0, 0, 0 }; +static int __devinitdata turbo_io[IBMTR_MAX_ADAPTERS] = {0}; +static int __devinitdata turbo_irq[IBMTR_MAX_ADAPTERS] = {0}; +static int __devinitdata turbo_searched = 0; -static __u32 ibmtr_mem_base = 0xd0000; +#ifndef PCMCIA +static __u32 ibmtr_mem_base __initdata = 0xd0000; +#endif -static void __init PrtChanID(char *pcid, short stride) +static void __devinit PrtChanID(char *pcid, short stride) { short i, j; - for (i=0, j=0; i<24; i++, j+=stride) + for (i = 0, j = 0; i < 24; i++, j += stride) printk("%1x", ((int) pcid[j]) & 0x0f); printk("\n"); } -static void __init HWPrtChanID (__u32 pcid, short stride) +static void __devinit HWPrtChanID(__u32 pcid, short stride) { short i, j; - for (i=0, j=0; i<24; i++, j+=stride) - printk("%1x", ((int)isa_readb(pcid + j)) & 0x0f); + for (i = 0, j = 0; i < 24; i++, j += stride) + printk("%1x", ((int) readb(pcid + j)) & 0x0f); printk("\n"); } -/* +static void __devinit find_turbo_adapters(int *iolist) { + int ram_addr; + int index=0; + __u32 chanid; + int found_turbo=0; + unsigned char *tchanid, ctemp; + int i,j; + + if (turbo_searched == 1) return; + turbo_searched=1; + for (ram_addr=0xC0000; ram_addr < 0xE0000; ram_addr+=0x2000) { + + __u32 intf_tbl=0; + + found_turbo=1; + chanid=(CHANNEL_ID + ram_addr); + tchanid=pcchannelid; + ctemp=isa_readb(chanid) & 0x0f; + if (ctemp != *tchanid) continue; + for (i=2,j=1; i<=46; i=i+2,j++) { + if ((isa_readb(chanid+i) & 0x0f) != tchanid[j]){ + found_turbo=0; + break; + } + } + if (!found_turbo) continue; + + isa_writeb(0x90, ram_addr+0x1E01); + for(i=2; i<0x0f; i++) { + isa_writeb(0x00, ram_addr+0x1E01+i); + } + isa_writeb(0x00, ram_addr+0x1E01); + for(i=jiffies+TR_BUSY_INTERVAL; time_before_eq(jiffies,i);); + intf_tbl=ntohs(isa_readw(ram_addr+ACA_OFFSET+ACA_RW+WRBR_EVEN)); + if (intf_tbl) { +#if IBMTR_DEBUG_MESSAGES + printk("ibmtr::find_turbo_adapters, Turbo found at " + "ram_addr %x\n",ram_addr); + printk("ibmtr::find_turbo_adapters, interface_table "); + for(i=0; i<6; i++) { + printk("%x:",isa_readb(ram_addr+intf_tbl+i)); + } + printk("\n"); +#endif + turbo_io[index]=ntohs(isa_readw(ram_addr+intf_tbl+4)); + turbo_irq[index]=isa_readb(ram_addr+intf_tbl+3); + outb(0, turbo_io[index] + ADAPTRESET); + for(i=jiffies+TR_RST_TIME;time_before_eq(jiffies,i);); + outb(0, turbo_io[index] + ADAPTRESETREL); + index++; + continue; + } +#if IBMTR_DEBUG_MESSAGES + printk("ibmtr::find_turbo_adapters, ibmtr card found at" + " %x but not a Turbo model\n",ram_addr); +#endif + } + for(i=0; i<IBMTR_MAX_ADAPTERS; i++) { + if(!turbo_io[i]) break; + for (j=0; j<IBMTR_MAX_ADAPTERS; j++) { + if ( iolist[j] && iolist[j] != turbo_io[i]) continue; + iolist[j]=turbo_io[i]; + break; + } + } +} + +/**************************************************************************** * ibmtr_probe(): Routine specified in the network device structure * to probe for an IBM Token Ring Adapter. Routine outline: * I. Interrogate hardware to determine if an adapter exists * and what the speeds and feeds are * II. Setup data structures to control execution based upon * adapter characteristics. - * III. Initialize adapter operation * * We expect ibmtr_probe to be called once for each device entry * which references it. - * - * Argument 'dev' should never be NULL. If we are built into - * the kernel, Space.c passed up a net_device. If we are - * -DMODULE, init_module allocates net_devices for us. - */ - -int __init ibmtr_probe(struct net_device *dev) + ****************************************************************************/ + +int __devinit ibmtr_probe(struct net_device *dev) { - int i; - int base_addr = dev->base_addr; + int i; + int base_addr = dev->base_addr; - if (base_addr > 0x1ff) - { - /* - * Check a single specified location. - */ - - if (ibmtr_probe1(dev, base_addr)) - return -ENODEV; - else - return 0; + if (base_addr && base_addr <= 0x1ff) /* Don't probe at all. */ + return -ENXIO; + if (base_addr > 0x1ff) { /* Check a single specified location. */ + if (!ibmtr_probe1(dev, base_addr)) return 0; + return -ENODEV; } - else if (base_addr != 0) /* Don't probe at all. */ - return -ENXIO; - - for (i = 0; ibmtr_portlist[i]; i++) - { - int ioaddr = ibmtr_portlist[i]; - if (check_region(ioaddr, IBMTR_IO_EXTENT)) - continue; - if (!ibmtr_probe1(dev, ioaddr)) - return 0; - } + find_turbo_adapters(ibmtr_portlist); + for (i = 0; ibmtr_portlist[i]; i++) { + int ioaddr = ibmtr_portlist[i]; - return -ENODEV; + if (check_region(ioaddr, IBMTR_IO_EXTENT)) continue; + if (!ibmtr_probe1(dev, ioaddr)) return 0; + } + return -ENODEV; } -static int __init ibmtr_probe1(struct net_device *dev, int PIOaddr) +/*****************************************************************************/ + +static int __devinit ibmtr_probe1(struct net_device *dev, int PIOaddr) { - unsigned char segment=0, intr=0, irq=0, i=0, j=0, cardpresent=NOTOK,temp=0; - __u32 t_mmio=0; - struct tok_info *ti=0; + + unsigned char segment, intr=0, irq=0, i, j, cardpresent=NOTOK, temp=0; + __u32 t_mmio = 0; + struct tok_info *ti = 0; __u32 cd_chanid; unsigned char *tchanid, ctemp; #ifndef PCMCIA - unsigned long timeout; + unsigned char t_irq=0; + unsigned long timeout; + static int version_printed; #endif #ifndef MODULE @@ -309,466 +358,414 @@ #endif #endif - /* Query the adapter PIO base port which will return - * indication of where MMIO was placed. We also have a - * coded interrupt number. - */ - - segment = inb(PIOaddr); - - /* - * Out of range values so we'll assume non-existent IO device + /* Query the adapter PIO base port which will return + * indication of where MMIO was placed. We also have a + * coded interrupt number. */ - - if (segment < 0x40 || segment > 0xe0) - return -ENODEV; - + segment = inb(PIOaddr); + if (segment < 0x40 || segment > 0xe0) { + /* Out of range values so we'll assume non-existent IO device + * but this is not necessarily a problem, esp if a turbo + * adapter is being used. */ +#if IBMTR_DEBUG_MESSAGES + DPRINTK("ibmtr_probe1(): unhappy that inb(0x%X) == 0x%X, " + "Hardware Problem?\n",PIOaddr,segment); +#endif + return -ENODEV; + } /* - * Compute the linear base address of the MMIO area - * as LINUX doesn't care about segments + * Compute the linear base address of the MMIO area + * as LINUX doesn't care about segments */ - - t_mmio=(((__u32)(segment & 0xfc) << 11) + 0x80000); - intr = segment & 0x03; /* low bits is coded interrupt # */ + t_mmio = (u32)ioremap(((__u32) (segment & 0xfc) << 11) + 0x80000,2048); + if (!t_mmio) { + DPRINTK("Cannot remap mmiobase memory area") ; + return -ENODEV ; + } + intr = segment & 0x03; /* low bits is coded interrupt # */ if (ibmtr_debug_trace & TRC_INIT) - DPRINTK("PIOaddr: %4hx seg/intr: %2x mmio base: %08X intr: %d\n", - PIOaddr, (int)segment, t_mmio, (int)intr); - - /* - * Now we will compare expected 'channelid' strings with - * what we is there to learn of ISA/MCA or not TR card - */ - - cd_chanid = (CHANNEL_ID + t_mmio); /* for efficiency */ - tchanid=pcchannelid; - cardpresent=TR_ISA; /* try ISA */ + DPRINTK("PIOaddr: %4hx seg/intr: %2x mmio base: %08X intr: %d\n" + , PIOaddr, (int) segment, t_mmio, (int) intr); /* - * Suboptimize knowing first byte different + * Now we will compare expected 'channelid' strings with + * what we is there to learn of ISA/MCA or not TR card */ - - ctemp = isa_readb(cd_chanid) & 0x0f; - if (ctemp != *tchanid) { /* NOT ISA card, try MCA */ - tchanid=mcchannelid; - cardpresent=TR_MCA; - if (ctemp != *tchanid) /* Neither ISA nor MCA */ - cardpresent=NOTOK; - } - - if (cardpresent != NOTOK) - { - /* - * Know presumed type, try rest of ID - */ - for (i=2,j=1; i<=46; i=i+2,j++) - { - if ((isa_readb(cd_chanid+i) & 0x0f) != tchanid[j]) { - cardpresent=NOTOK; /* match failed, not TR card */ - break; - } +#ifdef PCMCIA + ti = dev->priv; /*BMS moved up here */ + t_mmio = ti->mmio; /*BMS to get virtual address */ + irq = ti->irq; /*BMS to display the irq! */ +#endif + cd_chanid = (CHANNEL_ID + t_mmio); /* for efficiency */ + tchanid = pcchannelid; + cardpresent = TR_ISA; /* try ISA */ + + /* Suboptimize knowing first byte different */ + ctemp = readb(cd_chanid) & 0x0f; + if (ctemp != *tchanid) { /* NOT ISA card, try MCA */ + tchanid = mcchannelid; + cardpresent = TR_MCA; + if (ctemp != *tchanid) /* Neither ISA nor MCA */ + cardpresent = NOTOK; + } + if (cardpresent != NOTOK) { + /* Know presumed type, try rest of ID */ + for (i = 2, j = 1; i <= 46; i = i + 2, j++) { + if( (readb(cd_chanid+i)&0x0f) == tchanid[j]) continue; + /* match failed, not TR card */ + cardpresent = NOTOK; + break; } } - /* - * If we have an ISA board check for the ISA P&P version, - * as it has different IRQ settings + * If we have an ISA board check for the ISA P&P version, + * as it has different IRQ settings */ - - if (cardpresent == TR_ISA && (isa_readb(AIPFID + t_mmio)==0x0e)) - cardpresent=TR_ISAPNP; - - if (cardpresent == NOTOK) { /* "channel_id" did not match, report */ - if (ibmtr_debug_trace & TRC_INIT) { - DPRINTK("Channel ID string not found for PIOaddr: %4hx\n", PIOaddr); - DPRINTK("Expected for ISA: "); PrtChanID(pcchannelid,1); - DPRINTK(" found: "); HWPrtChanID(cd_chanid,2); - DPRINTK("Expected for MCA: "); PrtChanID(mcchannelid,1); - } - return -ENODEV; + if (cardpresent == TR_ISA && (readb(AIPFID + t_mmio) == 0x0e)) + cardpresent = TR_ISAPNP; + if (cardpresent == NOTOK) { /* "channel_id" did not match, report */ + if (!(ibmtr_debug_trace & TRC_INIT)) return -ENODEV; + DPRINTK( "Channel ID string not found for PIOaddr: %4hx\n", + PIOaddr); + DPRINTK("Expected for ISA: "); + PrtChanID(pcchannelid, 1); + DPRINTK(" found: "); +/* BMS Note that this can be misleading, when hardware is flaky, because you + are reading it a second time here. So with my flaky hardware, I'll see my- + self in this block, with the HW ID matching the ISA ID exactly! */ + HWPrtChanID(cd_chanid, 2); + DPRINTK("Expected for MCA: "); + PrtChanID(mcchannelid, 1); } - /* Now, allocate some of the pl0 buffers for this driver.. */ - - /* If called from PCMCIA, ti is already set up, so no need to + /* If called from PCMCIA, it is already set up, so no need to waste the memory, just use the existing structure */ - #ifndef PCMCIA - ti = (struct tok_info *)kmalloc(sizeof(struct tok_info), GFP_KERNEL); - if (ti == NULL) - return -ENOMEM; - + ti = (struct tok_info *) kmalloc(sizeof(struct tok_info), GFP_KERNEL); + if (ti == NULL) return -ENOMEM; memset(ti, 0, sizeof(struct tok_info)); -#else - ti = dev->priv ; + ti->mmio = t_mmio; + dev->priv = ti; /* this seems like the logical use of the + field ... let's try some empirical tests + using the token-info structure -- that + should fit with out future hope of multiple + adapter support as well /dwm */ + for(i=0; i<IBMTR_MAX_ADAPTERS; i++) { + if (turbo_io[i] != PIOaddr) continue; +#if IBMTR_DEBUG_MESSAGES + printk("ibmtr::tr_probe1, setting PIOaddr %x to Turbo\n" , + PIOaddr); +#endif + ti->turbo=1; + t_irq=turbo_irq[i]; + } #endif - ti->mmio= t_mmio; ti->readlog_pending = 0; - init_waitqueue_head(&ti->wait_for_tok_int); init_waitqueue_head(&ti->wait_for_reset); - dev->priv = ti; /* this seems like the logical use of the - field ... let's try some empirical tests - using the token-info structure -- that - should fit with out future hope of multiple - adapter support as well /dwm */ - - /* if PCMCIA, then the card is recognized as TR_ISAPNP - * and there is no need to set up the interrupt, it is already done. */ - + /* if PCMCIA, the card can be recognized as either TR_ISA or TR_ISAPNP + * depending which card is inserted. */ + #ifndef PCMCIA - switch (cardpresent) - { - case TR_ISA: - if (intr==0) - irq=9; /* irq2 really is irq9 */ - if (intr==1) - irq=3; - if (intr==2) - irq=6; - if (intr==3) - irq=7; - ti->global_int_enable=GLOBAL_INT_ENABLE+((irq==9) ? 2 : irq); - ti->adapter_int_enable=PIOaddr+ADAPTINTREL; - ti->sram=0; -#if !TR_NEWFORMAT - DPRINTK("ti->global_int_enable: %04X\n",ti->global_int_enable); -#endif - break; - case TR_MCA: - if (intr==0) - irq=9; - if (intr==1) - irq=3; - if (intr==2) - irq=10; - if (intr==3) - irq=11; - ti->global_int_enable=0; - ti->adapter_int_enable=0; - ti->sram=((__u32)(inb(PIOaddr+ADAPTRESETREL) & 0xfe) << 12); - break; - case TR_ISAPNP: - if (intr==0) - irq=9; - if (intr==1) - irq=3; - if (intr==2) - irq=10; - if (intr==3) - irq=11; - timeout = jiffies + TR_SPIN_INTERVAL; - while(!isa_readb(ti->mmio + ACA_OFFSET + ACA_RW + RRR_EVEN)) - if (time_after(jiffies, timeout)) { - DPRINTK("Hardware timeout during initialization.\n"); - kfree(ti); - return -ENODEV; - } - - ti->sram=((__u32)isa_readb(ti->mmio + ACA_OFFSET + ACA_RW + RRR_EVEN)<<12); - ti->global_int_enable=PIOaddr+ADAPTINTREL; - ti->adapter_int_enable=PIOaddr+ADAPTINTREL; - break; - } -#endif + switch (cardpresent) { + case TR_ISA: + if (intr == 0) irq = 9; /* irq2 really is irq9 */ + if (intr == 1) irq = 3; + if (intr == 2) irq = 6; + if (intr == 3) irq = 7; + ti->adapter_int_enable = PIOaddr + ADAPTINTREL; + break; + case TR_MCA: + if (intr == 0) irq = 9; + if (intr == 1) irq = 3; + if (intr == 2) irq = 10; + if (intr == 3) irq = 11; + ti->global_int_enable = 0; + ti->adapter_int_enable = 0; + ti->sram_virt=(__u32)(inb(PIOaddr+ADAPTRESETREL) & 0xfe) << 12; + break; + case TR_ISAPNP: + if (!t_irq) { + if (intr == 0) irq = 9; + if (intr == 1) irq = 3; + if (intr == 2) irq = 10; + if (intr == 3) irq = 11; + } else + irq=t_irq; + timeout = jiffies + TR_SPIN_INTERVAL; + while (!readb(ti->mmio + ACA_OFFSET + ACA_RW + RRR_EVEN)){ + if (!time_after(jiffies, timeout)) continue; + DPRINTK( "Hardware timeout during initialization.\n"); + kfree(ti); + return -ENODEV; + } + ti->sram_virt = + ((__u32)readb(ti->mmio+ACA_OFFSET+ACA_RW+RRR_EVEN)<<12); + ti->adapter_int_enable = PIOaddr + ADAPTINTREL; + break; + } /*end switch (cardpresent) */ +#endif /*not PCMCIA */ - if (ibmtr_debug_trace & TRC_INIT) { /* just report int */ - DPRINTK("irq=%d",irq); - if (ibmtr_debug_trace & TRC_INITV) { /* full chat in verbose only */ - DPRINTK(", ti->mmio=%08X",ti->mmio); - printk(", segment=%02X",segment); + if (ibmtr_debug_trace & TRC_INIT) { /* just report int */ + DPRINTK("irq=%d", irq); + printk(", sram_virt=0x%x", ti->sram_virt); + if(ibmtr_debug_trace&TRC_INITV){ /* full chat in verbose only */ + DPRINTK(", ti->mmio=%08X", ti->mmio); + printk(", segment=%02X", segment); } printk(".\n"); } /* Get hw address of token ring card */ -#if !TR_NEWFORMAT - DPRINTK("hw address: "); -#endif - j=0; - for (i=0; i<0x18; i=i+2) - { + j = 0; + for (i = 0; i < 0x18; i = i + 2) { /* technical reference states to do this */ - temp = isa_readb(ti->mmio + AIP + i) & 0x0f; -#if !TR_NEWFORMAT - printk("%1X",ti->hw_address[j]=temp); -#else - ti->hw_address[j]=temp; -#endif - if(j&1) - dev->dev_addr[(j/2)]=ti->hw_address[j]+(ti->hw_address[j-1]<<4); + temp = readb(ti->mmio + AIP + i) & 0x0f; + ti->hw_address[j] = temp; + if (j & 1) + dev->dev_addr[(j / 2)] = + ti->hw_address[j]+ (ti->hw_address[j - 1] << 4); ++j; } -#ifndef TR_NEWFORMAT - printk("\n"); -#endif - - /* get Adapter type: 'F' = Adapter/A, 'E' = 16/4 Adapter II,...*/ - ti->adapter_type = isa_readb(ti->mmio + AIPADAPTYPE); + /* get Adapter type: 'F' = Adapter/A, 'E' = 16/4 Adapter II,... */ + ti->adapter_type = readb(ti->mmio + AIPADAPTYPE); /* get Data Rate: F=4Mb, E=16Mb, D=4Mb & 16Mb ?? */ - ti->data_rate = isa_readb(ti->mmio + AIPDATARATE); + ti->data_rate = readb(ti->mmio + AIPDATARATE); /* Get Early Token Release support?: F=no, E=4Mb, D=16Mb, C=4&16Mb */ - ti->token_release = isa_readb(ti->mmio + AIPEARLYTOKEN); + ti->token_release = readb(ti->mmio + AIPEARLYTOKEN); /* How much shared RAM is on adapter ? */ -#ifdef PCMCIA - ti->avail_shared_ram = pcmcia_reality_check(get_sram_size(ti)); - ibmtr_mem_base = ti->sram_base << 12 ; -#else - ti->avail_shared_ram = get_sram_size(ti); -#endif - /* We need to set or do a bunch of work here based on previous results.. */ + if (ti->turbo) { + ti->avail_shared_ram=127; + } else { + ti->avail_shared_ram = get_sram_size(ti);/*in 512 byte units */ + } + /* We need to set or do a bunch of work here based on previous results*/ /* Support paging? What sizes?: F=no, E=16k, D=32k, C=16 & 32k */ - ti->shared_ram_paging = isa_readb(ti->mmio + AIPSHRAMPAGE); + ti->shared_ram_paging = readb(ti->mmio + AIPSHRAMPAGE); - /* Available DHB 4Mb size: F=2048, E=4096, D=4464 */ - switch (isa_readb(ti->mmio + AIP4MBDHB)) { - case 0xe : - ti->dhb_size4mb = 4096; - break; - case 0xd : - ti->dhb_size4mb = 4464; - break; - default : - ti->dhb_size4mb = 2048; - break; + /* Available DHB 4Mb size: F=2048, E=4096, D=4464 */ + switch (readb(ti->mmio + AIP4MBDHB)) { + case 0xe: ti->dhb_size4mb = 4096; break; + case 0xd: ti->dhb_size4mb = 4464; break; + default: ti->dhb_size4mb = 2048; break; } /* Available DHB 16Mb size: F=2048, E=4096, D=8192, C=16384, B=17960 */ - switch (isa_readb(ti->mmio + AIP16MBDHB)) { - case 0xe : - ti->dhb_size16mb = 4096; - break; - case 0xd : - ti->dhb_size16mb = 8192; - break; - case 0xc : - ti->dhb_size16mb = 16384; - break; - case 0xb : - ti->dhb_size16mb = 17960; - break; - default : - ti->dhb_size16mb = 2048; - break; + switch (readb(ti->mmio + AIP16MBDHB)) { + case 0xe: ti->dhb_size16mb = 4096; break; + case 0xd: ti->dhb_size16mb = 8192; break; + case 0xc: ti->dhb_size16mb = 16384; break; + case 0xb: ti->dhb_size16mb = 17960; break; + default: ti->dhb_size16mb = 2048; break; } -#if !TR_NEWFORMAT - DPRINTK("atype=%x, drate=%x, trel=%x, asram=%dK, srp=%x, " - "dhb(4mb=%x, 16mb=%x)\n",ti->adapter_type, - ti->data_rate, ti->token_release, ti->avail_shared_ram/2, - ti->shared_ram_paging, ti->dhb_size4mb, ti->dhb_size16mb); -#endif - - /* We must figure out how much shared memory space this adapter - * will occupy so that if there are two adapters we can fit both - * in. Given a choice, we will limit this adapter to 32K. The - * maximum space will will use for two adapters is 64K so if the - * adapter we are working on demands 64K (it also doesn't support - * paging), then only one adapter can be supported. + /* We must figure out how much shared memory space this adapter + * will occupy so that if there are two adapters we can fit both + * in. Given a choice, we will limit this adapter to 32K. The + * maximum space will will use for two adapters is 64K so if the + * adapter we are working on demands 64K (it also doesn't support + * paging), then only one adapter can be supported. */ /* - * determine how much of total RAM is mapped into PC space + * determine how much of total RAM is mapped into PC space */ - ti->mapped_ram_size=1<<((((isa_readb(ti->mmio+ ACA_OFFSET + ACA_RW + RRR_ODD)) >>2) & 0x03) + 4); - ti->page_mask=0; - if (ti->shared_ram_paging == 0xf) { /* No paging in adapter */ - ti->mapped_ram_size = ti->avail_shared_ram; - } else { -#ifdef ENABLE_PAGING - unsigned char pg_size=0; -#endif - -#if !TR_NEWFORMAT - DPRINTK("shared ram page size: %dK\n",ti->mapped_ram_size/2); -#endif + ti->mapped_ram_size= /*sixteen to onehundredtwentyeight 512byte blocks*/ + 1<< ((readb(ti->mmio+ACA_OFFSET+ACA_RW+RRR_ODD) >> 2 & 0x03) + 4); + ti->page_mask = 0; + if (ti->turbo) ti->page_mask=0xf0; + else if (ti->shared_ram_paging == 0xf); /* No paging in adapter */ + else { #ifdef ENABLE_PAGING - switch(ti->shared_ram_paging) - { + unsigned char pg_size = 0; + /* BMS: page size: PCMCIA, use configuration register; + ISAPNP, use LANAIDC config tool from www.ibm.com */ + switch (ti->shared_ram_paging) { case 0xf: break; case 0xe: - ti->page_mask=(ti->mapped_ram_size==32) ? 0xc0 : 0; - pg_size=32; /* 16KB page size */ + ti->page_mask = (ti->mapped_ram_size == 32) ? 0xc0 : 0; + pg_size = 32; /* 16KB page size */ break; case 0xd: - ti->page_mask=(ti->mapped_ram_size==64) ? 0x80 : 0; - pg_size=64; /* 32KB page size */ + ti->page_mask = (ti->mapped_ram_size == 64) ? 0x80 : 0; + pg_size = 64; /* 32KB page size */ break; case 0xc: - switch (ti->mapped_ram_size) { - case 32: - ti->page_mask=0xc0; - pg_size=32; - break; - case 64: - ti->page_mask=0x80; - pg_size=64; - break; - } + switch (ti->mapped_ram_size) { + case 32: + ti->page_mask = 0xc0; + pg_size = 32; + break; + case 64: + ti->page_mask = 0x80; + pg_size = 64; + break; + } break; default: - DPRINTK("Unknown shared ram paging info %01X\n",ti->shared_ram_paging); + DPRINTK("Unknown shared ram paging info %01X\n", + ti->shared_ram_paging); kfree(ti); return -ENODEV; break; - } + } /*end switch shared_ram_paging */ - if (ibmtr_debug_trace & TRC_INIT) - DPRINTK("Shared RAM paging code: " - "%02X mapped RAM size: %dK shared RAM size: %dK page mask: %0xX\n:", - ti->shared_ram_paging, ti->mapped_ram_size/2, ti->avail_shared_ram/2, ti->page_mask); - - if (ti->page_mask) { - if (pg_size > ti->mapped_ram_size) { - DPRINTK("Page size (%d) > mapped ram window (%d), can't page.\n", - pg_size/2, ti->mapped_ram_size/2); - ti->page_mask = 0; /* reset paging */ - } - } else if (pg_size > ti->mapped_ram_size) { - DPRINTK("Page size (%d) > mapped ram window (%d), can't page.\n", - pg_size/2, ti->mapped_ram_size/2); - } -#endif + if (ibmtr_debug_trace & TRC_INIT) + DPRINTK("Shared RAM paging code: %02X, " + "mapped RAM size: %dK, shared RAM size: %dK, " + "page mask: %02X\n:", + ti->shared_ram_paging, ti->mapped_ram_size / 2, + ti->avail_shared_ram / 2, ti->page_mask); +#endif /*ENABLE_PAGING */ } + +#ifndef PCMCIA /* finish figuring the shared RAM address */ - if (cardpresent==TR_ISA) { - static __u32 ram_bndry_mask[]={0xffffe000, 0xffffc000, 0xffff8000, 0xffff0000}; + if (cardpresent == TR_ISA) { + static __u32 ram_bndry_mask[] = + { 0xffffe000, 0xffffc000, 0xffff8000, 0xffff0000 }; __u32 new_base, rrr_32, chk_base, rbm; - rrr_32 = ((isa_readb(ti->mmio+ ACA_OFFSET + ACA_RW + RRR_ODD))>>2) & 0x00000003; + rrr_32=readb(ti->mmio+ACA_OFFSET+ACA_RW+RRR_ODD) >> 2 & 0x03; rbm = ram_bndry_mask[rrr_32]; - new_base = (ibmtr_mem_base + (~rbm)) & rbm; /* up to boundary */ - chk_base = new_base + (ti->mapped_ram_size<<9); + new_base = (ibmtr_mem_base + (~rbm)) & rbm;/* up to boundary */ + chk_base = new_base + (ti->mapped_ram_size << 9); if (chk_base > (ibmtr_mem_base + IBMTR_SHARED_RAM_SIZE)) { - DPRINTK("Shared RAM for this adapter (%05x) exceeds driver" - " limit (%05x), adapter not started.\n", - chk_base, ibmtr_mem_base + IBMTR_SHARED_RAM_SIZE); + DPRINTK("Shared RAM for this adapter (%05x) exceeds " + "driver limit (%05x), adapter not started.\n", + chk_base, ibmtr_mem_base + IBMTR_SHARED_RAM_SIZE); kfree(ti); - return -ENODEV; - } else { /* seems cool, record what we have figured out */ + return -ENODEV; + } else { /* seems cool, record what we have figured out */ ti->sram_base = new_base >> 12; ibmtr_mem_base = chk_base; } } - -#if !TR_NEWFORMAT - DPRINTK("Using %dK shared RAM\n",ti->mapped_ram_size/2); -#endif + else ti->sram_base = ti->sram_virt >> 12; /* The PCMCIA has already got the interrupt line and the io port, so no chance of anybody else getting it - MLP */ - -#ifndef PCMCIA - if (request_irq (dev->irq = irq, &tok_interrupt,0,"ibmtr", dev) != 0) { - DPRINTK("Could not grab irq %d. Halting Token Ring driver.\n",irq); + if (request_irq(dev->irq = irq, &tok_interrupt, 0, "ibmtr", dev) != 0) { + DPRINTK("Could not grab irq %d. Halting Token Ring driver.\n", + irq); kfree(ti); return -ENODEV; } - /*?? Now, allocate some of the PIO PORTs for this driver.. */ - request_region(PIOaddr,IBMTR_IO_EXTENT,"ibmtr"); /* record PIOaddr range as busy */ + /* record PIOaddr range as busy */ + request_region(PIOaddr, IBMTR_IO_EXTENT, "ibmtr"); + if (!version_printed++) { + printk(version); + } #endif - -#if !TR_NEWFORMAT - DPRINTK("%s",version); /* As we have passed card identification, - let the world know we're here! */ -#else - - if (version) { - printk("%s",version); - version = NULL; - } DPRINTK("%s %s found\n", - channel_def[cardpresent-1], adapter_def(ti->adapter_type)); + channel_def[cardpresent - 1], adapter_def(ti->adapter_type)); DPRINTK("using irq %d, PIOaddr %hx, %dK shared RAM.\n", - irq, PIOaddr, ti->mapped_ram_size/2); + irq, PIOaddr, ti->mapped_ram_size / 2); DPRINTK("Hardware address : %02X:%02X:%02X:%02X:%02X:%02X\n", dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]); - if (ti->page_mask) - DPRINTK("Shared RAM paging enabled. Page size: %uK Shared Ram size %dK\n", - ((ti->page_mask ^ 0xff)+1)>>2,ti->avail_shared_ram/2); - else - DPRINTK("Shared RAM paging disabled. ti->page_mask %x\n",ti->page_mask); -#endif + if (ti->page_mask) + DPRINTK("Shared RAM paging enabled. " + "Page size: %uK Shared Ram size %dK\n", + ((ti->page_mask^0xff)+1) >>2, ti->avail_shared_ram / 2); + else + DPRINTK("Shared RAM paging disabled. ti->page_mask %x\n", + ti->page_mask); + /* Calculate the maximum DHB we can use */ + /* two cases where avail_shared_ram doesn't equal mapped_ram_size: + 1. avail_shared_ram is 127 but mapped_ram_size is 128 (typical) + 2. user has configured adapter for less than avail_shared_ram + but is not using paging (she should use paging, I believe) + */ if (!ti->page_mask) { - ti->avail_shared_ram=ti->mapped_ram_size; + ti->avail_shared_ram= + MIN(ti->mapped_ram_size,ti->avail_shared_ram); } + switch (ti->avail_shared_ram) { - case 16 : /* 8KB shared RAM */ - ti->dhb_size4mb = MIN(ti->dhb_size4mb, 2048); + case 16: /* 8KB shared RAM */ + ti->dhb_size4mb = MIN(ti->dhb_size4mb, 2048); ti->rbuf_len4 = 1032; - ti->rbuf_cnt4 = 2; + ti->rbuf_cnt4=2; ti->dhb_size16mb = MIN(ti->dhb_size16mb, 2048); ti->rbuf_len16 = 1032; - ti->rbuf_cnt16 = 2; + ti->rbuf_cnt16=2; break; - case 32 : /* 16KB shared RAM */ - ti->dhb_size4mb = MIN(ti->dhb_size4mb, 2048); - ti->rbuf_len4 = 520; - ti->rbuf_cnt4 = 9; - ti->dhb_size16mb = MIN(ti->dhb_size16mb, 2048); - ti->rbuf_len16 = 1032; /* 1024 usable */ - ti->rbuf_cnt16 = 4; + case 32: /* 16KB shared RAM */ + ti->dhb_size4mb = MIN(ti->dhb_size4mb, 4464); + ti->rbuf_len4 = 1032; + ti->rbuf_cnt4=4; + ti->dhb_size16mb = MIN(ti->dhb_size16mb, 4096); + ti->rbuf_len16 = 1032; /*1024 usable */ + ti->rbuf_cnt16=4; break; - case 64 : /* 32KB shared RAM */ - ti->dhb_size4mb = MIN(ti->dhb_size4mb, 2048); + case 64: /* 32KB shared RAM */ + ti->dhb_size4mb = MIN(ti->dhb_size4mb, 4464); ti->rbuf_len4 = 1032; - ti->rbuf_cnt4 = 6; - ti->dhb_size16mb = MIN(ti->dhb_size16mb, 2048); + ti->rbuf_cnt4=6; + ti->dhb_size16mb = MIN(ti->dhb_size16mb, 10240); ti->rbuf_len16 = 1032; - ti->rbuf_cnt16 = 10; + ti->rbuf_cnt16=6; break; - case 127 : /* 63KB shared RAM */ - ti->dhb_size4mb = MIN(ti->dhb_size4mb, 2048); + case 127: /* 63.5KB shared RAM */ + ti->dhb_size4mb = MIN(ti->dhb_size4mb, 4464); ti->rbuf_len4 = 1032; - ti->rbuf_cnt4 = 6; - ti->dhb_size16mb = MIN(ti->dhb_size16mb, 2048); + ti->rbuf_cnt4=6; + ti->dhb_size16mb = MIN(ti->dhb_size16mb, 16384); ti->rbuf_len16 = 1032; - ti->rbuf_cnt16 = 16; + ti->rbuf_cnt16=16; break; - case 128 : /* 64KB shared RAM */ - ti->dhb_size4mb = MIN(ti->dhb_size4mb, 2048); + case 128: /* 64KB shared RAM */ + ti->dhb_size4mb = MIN(ti->dhb_size4mb, 4464); ti->rbuf_len4 = 1032; - ti->rbuf_cnt4 = 6; - ti->dhb_size16mb = MIN(ti->dhb_size16mb, 2048); + ti->rbuf_cnt4=6; + ti->dhb_size16mb = MIN(ti->dhb_size16mb, 17960); ti->rbuf_len16 = 1032; - ti->rbuf_cnt16 = 18; + ti->rbuf_cnt16=16; break; - default : - ti->dhb_size4mb = 2048; + default: + ti->dhb_size4mb = 2048; ti->rbuf_len4 = 1032; - ti->rbuf_cnt4 = 2; + ti->rbuf_cnt4=2; ti->dhb_size16mb = 2048; ti->rbuf_len16 = 1032; - ti->rbuf_cnt16 = 2; + ti->rbuf_cnt16=2; break; } - - ti->maxmtu16 = (ti->rbuf_len16*ti->rbuf_cnt16)-((ti->rbuf_cnt16)<<3)-TR_HLEN; - ti->maxmtu4 = (ti->rbuf_len4*ti->rbuf_cnt4)-((ti->rbuf_cnt4)<<3)-TR_HLEN; - DPRINTK("Maximum MTU 16Mbps: %d, 4Mbps: %d\n", - ti->maxmtu16, ti->maxmtu4); - - dev->base_addr=PIOaddr; /* set the value for device */ - + /* this formula is not smart enough for the paging case + ti->rbuf_cnt<x> = (ti->avail_shared_ram * BLOCKSZ - ADAPT_PRIVATE - + ARBLENGTH - SSBLENGTH - DLC_MAX_SAP * SAPLENGTH - + DLC_MAX_STA * STALENGTH - ti->dhb_size<x>mb * NUM_DHB - + SRBLENGTH - ASBLENGTH) / ti->rbuf_len<x>; + */ + ti->maxmtu16 = (ti->rbuf_len16 - 8) * ti->rbuf_cnt16 - TR_HLEN; + ti->maxmtu4 = (ti->rbuf_len4 - 8) * ti->rbuf_cnt4 - TR_HLEN; + /*BMS assuming 18 bytes of Routing Information (usually works) */ + DPRINTK("Maximum Receive Internet Protocol MTU 16Mbps: %d, 4Mbps: %d\n", + ti->maxmtu16, ti->maxmtu4); + + dev->base_addr = PIOaddr; /* set the value for device */ + dev->mem_start = ti->sram_base << 12; + dev->mem_end = dev->mem_start + (ti->mapped_ram_size << 9) - 1; trdev_init(dev); - tok_init_card(dev); + return 0; /* Return 0 to indicate we have found a Token Ring card. */ +} /*ibmtr_probe1() */ - return 0; /* Return 0 to indicate we have found a Token Ring card. */ -} +/*****************************************************************************/ /* query the adapter for the size of shared RAM */ +/* the function returns the RAM size in units of 512 bytes */ -static unsigned char __init get_sram_size(struct tok_info *adapt_info) +static unsigned char __devinit get_sram_size(struct tok_info *adapt_info) { - unsigned char avail_sram_code; - static unsigned char size_code[]={ 0,16,32,64,127,128 }; + static unsigned char size_code[] = { 0, 16, 32, 64, 127, 128 }; /* Adapter gives 'F' -- use RRR bits 3,2 'E' -- 8kb 'D' -- 16kb @@ -776,30 +773,27 @@ 'B' - 64KB less 512 bytes at top (WARNING ... must zero top bytes in INIT */ - avail_sram_code=0xf-isa_readb(adapt_info->mmio + AIPAVAILSHRAM); - if (avail_sram_code) - return size_code[avail_sram_code]; - else /* for code 'F', must compute size from RRR(3,2) bits */ - return 1<<((isa_readb(adapt_info->mmio+ ACA_OFFSET + ACA_RW + RRR_ODD)>>2)+4); + avail_sram_code = 0xf - readb(adapt_info->mmio + AIPAVAILSHRAM); + if (avail_sram_code) return size_code[avail_sram_code]; + else /* for code 'F', must compute size from RRR(3,2) bits */ + return 1 << + ((readb(adapt_info->mmio+ACA_OFFSET+ACA_RW+RRR_ODD)>>2&3)+4); } -static int __init trdev_init(struct net_device *dev) -{ - struct tok_info *ti=(struct tok_info *)dev->priv; +/*****************************************************************************/ - /* init the spinlock */ - spin_lock_init(&ti->lock); +static int __devinit trdev_init(struct net_device *dev) +{ + struct tok_info *ti = (struct tok_info *) dev->priv; SET_PAGE(ti->srb_page); - ti->open_status = CLOSED; - - dev->init = tok_init_card; - dev->open = tok_open; - dev->stop = tok_close; - dev->hard_start_xmit = tok_send_packet; - dev->get_stats = tok_get_stats; + ti->open_failure = NO ; + dev->open = tok_open; + dev->stop = tok_close; + dev->hard_start_xmit = tok_send_packet; + dev->get_stats = tok_get_stats; dev->set_multicast_list = tok_set_multicast_list; - dev->change_mtu = ibmtr_change_mtu; + dev->change_mtu = ibmtr_change_mtu; #ifndef MODULE #ifndef PCMCIA @@ -809,23 +803,173 @@ return 0; } +/*****************************************************************************/ + +static int tok_init_card(struct net_device *dev) +{ + struct tok_info *ti; + short PIOaddr; + unsigned long i; + + PIOaddr = dev->base_addr; + ti = (struct tok_info *) dev->priv; + /* Special processing for first interrupt after reset */ + ti->do_tok_int = FIRST_INT; + /* Reset adapter */ + writeb(~INT_ENABLE, ti->mmio + ACA_OFFSET + ACA_RESET + ISRP_EVEN); + outb(0, PIOaddr + ADAPTRESET); + + current->state=TASK_UNINTERRUPTIBLE; + schedule_timeout(TR_RST_TIME); /* wait 50ms */ + + outb(0, PIOaddr + ADAPTRESETREL); +#ifdef ENABLE_PAGING + if (ti->page_mask) + writeb(SRPR_ENABLE_PAGING,ti->mmio+ACA_OFFSET+ACA_RW+SRPR_EVEN); +#endif + writeb(INT_ENABLE, ti->mmio + ACA_OFFSET + ACA_SET + ISRP_EVEN); + i = sleep_on_timeout(&ti->wait_for_reset, 4 * HZ); + return i? 0 : -EAGAIN; +} + +/*****************************************************************************/ +static int tok_open(struct net_device *dev) +{ + struct tok_info *ti = (struct tok_info *) dev->priv; + int i; + + /*the case we were left in a failure state during a previous open */ + if (ti->open_failure == YES) { + DPRINTK("Last time you were disconnected, how about now?\n"); + printk("You can't insert with an ICS connector half-cocked.\n"); + } + + ti->open_status = CLOSED; /* CLOSED or OPEN */ + ti->sap_status = CLOSED; /* CLOSED or OPEN */ + ti->open_failure = NO; /* NO or YES */ + ti->open_mode = MANUAL; /* MANUAL or AUTOMATIC */ + /* 12/2000 not typical Linux, but we can use RUNNING to let us know when + the network has crapped out or cables are disconnected. Useful because + the IFF_UP flag stays up the whole time, until ifconfig tr0 down. + */ + dev->flags &= ~IFF_RUNNING; + + ti->sram_virt &= ~1; /* to reverse what we do in tok_close */ + /* init the spinlock */ + ti->lock = (spinlock_t) SPIN_LOCK_UNLOCKED; + + i = tok_init_card(dev); + if (i) return i; + + while (1){ + tok_open_adapter((unsigned long) dev); + i= interruptible_sleep_on_timeout(&ti->wait_for_reset, 25 * HZ); + /* sig catch: estimate opening adapter takes more than .5 sec*/ + if (i>(245*HZ)/10) break; /* fancier than if (i==25*HZ) */ + if (i==0) break; + if (ti->open_status == OPEN && ti->sap_status==OPEN) { + netif_start_queue(dev); + MOD_INC_USE_COUNT; + DPRINTK("Adapter is up and running\n"); + return 0; + } + current->state=TASK_INTERRUPTIBLE; + i=schedule_timeout(TR_RETRY_INTERVAL); /* wait 30 seconds */ + if(i!=0) break; /*prob. a signal, like the i>24*HZ case above */ + } + outb(0, dev->base_addr + ADAPTRESET);/* kill pending interrupts*/ + DPRINTK("TERMINATED via signal\n"); /*BMS useful */ + return -EAGAIN; +} + +/*****************************************************************************/ + +#define COMMAND_OFST 0 +#define OPEN_OPTIONS_OFST 8 +#define NUM_RCV_BUF_OFST 24 +#define RCV_BUF_LEN_OFST 26 +#define DHB_LENGTH_OFST 28 +#define NUM_DHB_OFST 30 +#define DLC_MAX_SAP_OFST 32 +#define DLC_MAX_STA_OFST 33 + +void tok_open_adapter(unsigned long dev_addr) +{ + struct net_device *dev = (struct net_device *) dev_addr; + struct tok_info *ti; + int i; + + ti = (struct tok_info *) dev->priv; + SET_PAGE(ti->init_srb_page); + writeb(~SRB_RESP_INT, ti->mmio + ACA_OFFSET + ACA_RESET + ISRP_ODD); + for (i = 0; i < sizeof(struct dir_open_adapter); i++) + writeb(0, ti->init_srb + i); + writeb(DIR_OPEN_ADAPTER, ti->init_srb + COMMAND_OFST); + writew(htons(OPEN_PASS_BCON_MAC), ti->init_srb + OPEN_OPTIONS_OFST); + if (ti->ring_speed == 16) { + writew(htons(ti->dhb_size16mb), ti->init_srb + DHB_LENGTH_OFST); + writew(htons(ti->rbuf_cnt16), ti->init_srb + NUM_RCV_BUF_OFST); + writew(htons(ti->rbuf_len16), ti->init_srb + RCV_BUF_LEN_OFST); + } else { + writew(htons(ti->dhb_size4mb), ti->init_srb + DHB_LENGTH_OFST); + writew(htons(ti->rbuf_cnt4), ti->init_srb + NUM_RCV_BUF_OFST); + writew(htons(ti->rbuf_len4), ti->init_srb + RCV_BUF_LEN_OFST); + } + writeb(NUM_DHB, /* always 2 */ ti->init_srb + NUM_DHB_OFST); + writeb(DLC_MAX_SAP, ti->init_srb + DLC_MAX_SAP_OFST); + writeb(DLC_MAX_STA, ti->init_srb + DLC_MAX_STA_OFST); + ti->srb = ti->init_srb; /* We use this one in the interrupt handler */ + ti->srb_page = ti->init_srb_page; + DPRINTK("Opening adapter: Xmit bfrs: %d X %d, Rcv bfrs: %d X %d\n", + readb(ti->init_srb + NUM_DHB_OFST), + ntohs(readw(ti->init_srb + DHB_LENGTH_OFST)), + ntohs(readw(ti->init_srb + NUM_RCV_BUF_OFST)), + ntohs(readw(ti->init_srb + RCV_BUF_LEN_OFST))); + writeb(INT_ENABLE, ti->mmio + ACA_OFFSET + ACA_SET + ISRP_EVEN); + writeb(CMD_IN_SRB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD); +} + +/*****************************************************************************/ + +static void open_sap(unsigned char type, struct net_device *dev) +{ + int i; + struct tok_info *ti = (struct tok_info *) dev->priv; + + SET_PAGE(ti->srb_page); + for (i = 0; i < sizeof(struct dlc_open_sap); i++) + writeb(0, ti->srb + i); + +#define MAX_I_FIELD_OFST 14 +#define SAP_VALUE_OFST 16 +#define SAP_OPTIONS_OFST 17 +#define STATION_COUNT_OFST 18 + + writeb(DLC_OPEN_SAP, ti->srb + COMMAND_OFST); + writew(htons(MAX_I_FIELD), ti->srb + MAX_I_FIELD_OFST); + writeb(SAP_OPEN_IND_SAP | SAP_OPEN_PRIORITY, ti->srb+ SAP_OPTIONS_OFST); + writeb(SAP_OPEN_STATION_CNT, ti->srb + STATION_COUNT_OFST); + writeb(type, ti->srb + SAP_VALUE_OFST); + writeb(CMD_IN_SRB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD); +} + + +/*****************************************************************************/ static void tok_set_multicast_list(struct net_device *dev) { - struct tok_info *ti=(struct tok_info *)dev->priv; + struct tok_info *ti = (struct tok_info *) dev->priv; struct dev_mc_list *mclist; unsigned char address[4]; int i; - if(ti->open_status==CLOSED) - return; - + /*BMS the next line is CRUCIAL or you may be sad when you */ + /*BMS ifconfig tr down or hot unplug a PCMCIA card ??hownowbrowncow*/ + if (/*BMSHELPdev->start == 0 ||*/ ti->open_status != OPEN) return; address[0] = address[1] = address[2] = address[3] = 0; - mclist = dev->mc_list; - for (i=0; i< dev->mc_count; i++) - { + for (i = 0; i < dev->mc_count; i++) { address[0] |= mclist->dmi_addr[2]; address[1] |= mclist->dmi_addr[3]; address[2] |= mclist->dmi_addr[4]; @@ -833,76 +977,168 @@ mclist = mclist->next; } SET_PAGE(ti->srb_page); - for (i=0; i<sizeof(struct srb_set_funct_addr); i++) - isa_writeb(0, ti->srb+i); + for (i = 0; i < sizeof(struct srb_set_funct_addr); i++) + writeb(0, ti->srb + i); - isa_writeb(DIR_SET_FUNC_ADDR, - ti->srb + offsetof(struct srb_set_funct_addr, command)); +#define FUNCT_ADDRESS_OFST 6 + writeb(DIR_SET_FUNC_ADDR, ti->srb + COMMAND_OFST); + for (i = 0; i < 4; i++) + writeb(address[i], ti->srb + FUNCT_ADDRESS_OFST + i); + writeb(CMD_IN_SRB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD); +#if TR_VERBOSE DPRINTK("Setting functional address: "); - - for (i=0; i<4; i++) - { - isa_writeb(address[i], - ti->srb + offsetof(struct srb_set_funct_addr, funct_address)+i); - printk("%02X ", address[i]); - } - isa_writeb(CMD_IN_SRB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD); + for (i=0;i<4;i++) printk("%02X ", address[i]); printk("\n"); +#endif } -static int tok_open(struct net_device *dev) -{ - struct tok_info *ti=(struct tok_info *)dev->priv; +/*****************************************************************************/ - if (ti->open_status==CLOSED) tok_init_card(dev); +#define STATION_ID_OFST 4 - if (ti->open_status==IN_PROGRESS) sleep_on(&ti->wait_for_reset); +static int tok_send_packet(struct sk_buff *skb, struct net_device *dev) +{ + struct tok_info *ti; + unsigned long flags; + ti = (struct tok_info *) dev->priv; - if (ti->open_status==SUCCESS) { - /* NEED to see smem size *AND* reset high 512 bytes if needed */ - netif_start_queue(dev); - MOD_INC_USE_COUNT; + netif_stop_queue(dev); - return 0; - } else return -EAGAIN; + /* lock against other CPUs */ + spin_lock_irqsave(&(ti->lock), flags); -} + /* Save skb; we'll need it when the adapter asks for the data */ + ti->current_skb = skb; + SET_PAGE(ti->srb_page); + writeb(XMIT_UI_FRAME, ti->srb + COMMAND_OFST); + writew(ti->exsap_station_id, ti->srb + STATION_ID_OFST); + writeb(CMD_IN_SRB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD); + spin_unlock_irqrestore(&(ti->lock), flags); + dev->trans_start = jiffies; + return 0; +} + +/*****************************************************************************/ static int tok_close(struct net_device *dev) { + struct tok_info *ti = (struct tok_info *) dev->priv; - struct tok_info *ti=(struct tok_info *) dev->priv; - - if(ti->open_status!=CLOSED) { - netif_stop_queue(dev); - SET_PAGE(ti->srb_page); - isa_writeb(DIR_CLOSE_ADAPTER, - ti->srb + offsetof(struct srb_close_adapter, command)); - isa_writeb(CMD_IN_SRB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD); - - ti->open_status=CLOSED; + /* Important for PCMCIA hot unplug, otherwise, we'll pull the card, */ + /* unloading the module from memory, and then if a timer pops, ouch */ + del_timer(&ti->tr_timer); + outb(0, dev->base_addr + ADAPTRESET); + ti->sram_virt |= 1; + ti->open_status = CLOSED; - sleep_on(&ti->wait_for_tok_int); + netif_stop_queue(dev); + DPRINTK("Adapter is closed.\n"); + MOD_DEC_USE_COUNT; + return 0; +} - SET_PAGE(ti->srb_page); - if (isa_readb(ti->srb + offsetof(struct srb_close_adapter, ret_code))) - DPRINTK("close adapter failed: %02X\n", - (int)isa_readb(ti->srb + offsetof(struct srb_close_adapter, ret_code))); +/*****************************************************************************/ -#ifdef PCMCIA - ti->sram = 0 ; -#endif - DPRINTK("Adapter closed.\n"); - MOD_DEC_USE_COUNT; +#define RETCODE_OFST 2 +#define OPEN_ERROR_CODE_OFST 6 +#define ASB_ADDRESS_OFST 8 +#define SRB_ADDRESS_OFST 10 +#define ARB_ADDRESS_OFST 12 +#define SSB_ADDRESS_OFST 14 + +static char *printphase[]= {"Lobe media test","Physical insertion", + "Address verification","Roll call poll","Request Parameters"}; +static char *printerror[]={"Function failure","Signal loss","Reserved", + "Frequency error","Timeout","Ring failure","Ring beaconing", + "Duplicate node address", + "Parameter request-retry count exceeded","Remove received", + "IMPL force received","Duplicate modifier", + "No monitor detected","Monitor contention failed for RPL"}; + +void dir_open_adapter (struct net_device *dev) { + + struct tok_info *ti = (struct tok_info *) dev->priv; + unsigned char ret_code; + __u16 err; + + ti->srb = ntohs(readw(ti->init_srb + SRB_ADDRESS_OFST)); + ti->ssb = ntohs(readw(ti->init_srb + SSB_ADDRESS_OFST)); + ti->arb = ntohs(readw(ti->init_srb + ARB_ADDRESS_OFST)); + ti->asb = ntohs(readw(ti->init_srb + ASB_ADDRESS_OFST)); + if (ti->page_mask) { + ti->srb_page = (ti->srb >> 8) & ti->page_mask; + ti->srb &= ~(ti->page_mask << 8); + ti->ssb_page = (ti->ssb >> 8) & ti->page_mask; + ti->ssb &= ~(ti->page_mask << 8); + ti->arb_page = (ti->arb >> 8) & ti->page_mask; + ti->arb &= ~(ti->page_mask << 8); + ti->asb_page = (ti->asb >> 8) & ti->page_mask; + ti->asb &= ~(ti->page_mask << 8); + } + ti->srb += ti->sram_virt; + ti->ssb += ti->sram_virt; + ti->arb += ti->sram_virt; + ti->asb += ti->sram_virt; + ti->current_skb = NULL; + ret_code = readb(ti->init_srb + RETCODE_OFST); + err = ntohs(readw(ti->init_srb + OPEN_ERROR_CODE_OFST)); + if (!ret_code) { + ti->open_status = OPEN; /* TR adapter is now available */ + if (ti->open_mode == AUTOMATIC) { + DPRINTK("Adapter reopened.\n"); + } + writeb(~SRB_RESP_INT, ti->mmio+ACA_OFFSET+ACA_RESET+ISRP_ODD); + open_sap(EXTENDED_SAP, dev); + return; } - - return 0; + ti->open_failure = YES; + if (ret_code == 7){ + if (err == 0x24) { + if (!ti->auto_speedsave) { + DPRINTK("Open failed: Adapter speed must match " + "ring speed if Automatic Ring Speed Save is " + "disabled.\n"); + ti->open_action = FAIL; + }else + DPRINTK("Retrying open to adjust to " + "ring speed, "); + } else if (err == 0x2d) { + DPRINTK("Physical Insertion: No Monitor Detected, "); + printk("retrying after %ds delay...\n", + TR_RETRY_INTERVAL/HZ); + } else if (err == 0x11) { + DPRINTK("Lobe Media Function Failure (0x11), "); + printk(" retrying after %ds delay...\n", + TR_RETRY_INTERVAL/HZ); + } else { + char **prphase = printphase; + char **prerror = printerror; + DPRINTK("TR Adapter misc open failure, error code = "); + printk("0x%x, Phase: %s, Error: %s\n", + err, prphase[err/16 -1], prerror[err%16 -1]); + printk(" retrying after %ds delay...\n", + TR_RETRY_INTERVAL/HZ); + } + } else DPRINTK("open failed: ret_code = %02X..., ", ret_code); + if (ti->open_action != FAIL) { + if (ti->open_mode==AUTOMATIC){ + ti->open_action = REOPEN; + ibmtr_reset_timer(&(ti->tr_timer), dev); + return; + } + wake_up(&ti->wait_for_reset); + return; + } + DPRINTK("FAILURE, CAPUT\n"); } -void tok_interrupt (int irq, void *dev_id, struct pt_regs *regs) +/******************************************************************************/ + +void tok_interrupt(int irq, void *dev_id, struct pt_regs *regs) { unsigned char status; + /* unsigned char status_even ; */ struct tok_info *ti; struct net_device *dev; #ifdef ENABLE_PAGING @@ -911,839 +1147,621 @@ dev = dev_id; #if TR_VERBOSE - DPRINTK("Int from tok_driver, dev : %p\n",dev); + DPRINTK("Int from tok_driver, dev : %p irq%d regs=%p\n", dev,irq,regs); #endif - ti = (struct tok_info *) dev->priv; + ti = (struct tok_info *) dev->priv; + if (ti->sram_virt & 1) + return; /* PCMCIA card extraction flag */ spin_lock(&(ti->lock)); #ifdef ENABLE_PAGING - save_srpr=isa_readb(ti->mmio+ACA_OFFSET+ACA_RW+SRPR_EVEN); + save_srpr = readb(ti->mmio + ACA_OFFSET + ACA_RW + SRPR_EVEN); #endif - /* Disable interrupts till processing is finished */ - isa_writeb((~INT_ENABLE), ti->mmio + ACA_OFFSET + ACA_RESET + ISRP_EVEN); + /* Disable interrupts till processing is finished */ + writeb((~INT_ENABLE), ti->mmio + ACA_OFFSET + ACA_RESET + ISRP_EVEN); /* Reset interrupt for ISA boards */ - if (ti->adapter_int_enable) - outb(0,ti->adapter_int_enable); - else - outb(0,ti->global_int_enable); - - - switch (ti->do_tok_int) { - - case NOT_FIRST: - - /* Begin the regular interrupt handler HERE inline to avoid - the extra levels of logic and call depth for the - original solution. */ - - status=isa_readb(ti->mmio + ACA_OFFSET + ACA_RW + ISRP_ODD); -#ifdef PCMCIA - /* Check if the PCMCIA card was pulled. */ - if (status == 0xFF) - { - DPRINTK("PCMCIA card removed.\n"); - ti->open_status=CLOSED; - goto return_point ; - } - - /* Check ISRP EVEN too. */ - if ( isa_readb (ti->mmio + ACA_OFFSET + ACA_RW + ISRP_EVEN) == 0xFF) - { - DPRINTK("PCMCIA card removed.\n"); - ti->open_status=CLOSED; - goto return_point ; - } + if (ti->adapter_int_enable) + outb(0, ti->adapter_int_enable); + else /* used for PCMCIA cards */ + outb(0, ti->global_int_enable); + if (ti->do_tok_int == FIRST_INT){ + initial_tok_int(dev); +#ifdef ENABLE_PAGING + writeb(save_srpr, ti->mmio + ACA_OFFSET + ACA_RW + SRPR_EVEN); #endif + spin_unlock(&(ti->lock)); + return; + } + /* Begin interrupt handler HERE inline to avoid the extra + levels of logic and call depth for the original solution. */ + status = readb(ti->mmio + ACA_OFFSET + ACA_RW + ISRP_ODD); + /*BMSstatus_even = readb (ti->mmio + ACA_OFFSET + ACA_RW + ISRP_EVEN) */ + /*BMSdebugprintk("tok_interrupt: ISRP_ODD = 0x%x ISRP_EVEN = 0x%x\n", */ + /*BMS status,status_even); */ + if (status & ADAP_CHK_INT) { + int i; + __u32 check_reason; + __u8 check_reason_page = 0; + check_reason = + ntohs(readw(ti->mmio+ ACA_OFFSET+ACA_RW + WWCR_EVEN)); + if (ti->page_mask) { + check_reason_page = (check_reason >> 8) & ti->page_mask; + check_reason &= ~(ti->page_mask << 8); + } + check_reason += ti->sram_virt; + SET_PAGE(check_reason_page); - if (status & ADAP_CHK_INT) { - - int i; - __u32 check_reason; - __u8 check_reason_page=0; - - check_reason=ntohs(isa_readw(ti->sram + ACA_OFFSET + ACA_RW +WWCR_EVEN)); - if (ti->page_mask) { - check_reason_page=(check_reason>>8) & ti->page_mask; - check_reason &= ~(ti->page_mask << 8); + DPRINTK("Adapter check interrupt\n"); + DPRINTK("8 reason bytes follow: "); + for (i = 0; i < 8; i++, check_reason++) + printk("%02X ", (int) readb(check_reason)); + printk("\n"); + writeb(~ADAP_CHK_INT, ti->mmio+ ACA_OFFSET+ACA_RESET+ ISRP_ODD); + status = readb(ti->mmio + ACA_OFFSET + ACA_RW + ISRA_EVEN); + DPRINTK("ISRA_EVEN == 0x02%x\n",status); + ti->open_status = CLOSED; + ti->sap_status = CLOSED; + ti->open_mode = AUTOMATIC; + dev->flags &= ~IFF_RUNNING; + netif_stop_queue(dev); + ti->open_action = RESTART; + outb(0, dev->base_addr + ADAPTRESET); + ibmtr_reset_timer(&(ti->tr_timer), dev);/*BMS try to reopen*/ + return; + } + if (readb(ti->mmio + ACA_OFFSET + ACA_RW + ISRP_EVEN) + & (TCR_INT | ERR_INT | ACCESS_INT)) { + DPRINTK("adapter error: ISRP_EVEN : %02x\n", + (int)readb(ti->mmio+ ACA_OFFSET + ACA_RW + ISRP_EVEN)); + writeb(~(TCR_INT | ERR_INT | ACCESS_INT), + ti->mmio + ACA_OFFSET + ACA_RESET + ISRP_EVEN); + status= readb(ti->mmio+ ACA_OFFSET + ACA_RW + ISRA_EVEN);/*BMS*/ + DPRINTK("ISRA_EVEN == 0x02%x\n",status);/*BMS*/ + writeb(INT_ENABLE, ti->mmio + ACA_OFFSET + ACA_SET + ISRP_EVEN); +#ifdef ENABLE_PAGING + writeb(save_srpr, ti->mmio + ACA_OFFSET + ACA_RW + SRPR_EVEN); +#endif + spin_unlock(&(ti->lock)); + return; + } + if (status & SRB_RESP_INT) { /* SRB response */ + SET_PAGE(ti->srb_page); +#if TR_VERBOSE + DPRINTK("SRB resp: cmd=%02X rsp=%02X\n", + readb(ti->srb), readb(ti->srb + RETCODE_OFST)); +#endif + switch (readb(ti->srb)) { /* SRB command check */ + case XMIT_DIR_FRAME:{ + unsigned char xmit_ret_code; + xmit_ret_code = readb(ti->srb + RETCODE_OFST); + if (xmit_ret_code == 0xff) break; + DPRINTK("error on xmit_dir_frame request: %02X\n", + xmit_ret_code); + if (ti->current_skb) { + dev_kfree_skb_irq(ti->current_skb); + ti->current_skb = NULL; } - check_reason += ti->sram; - SET_PAGE(check_reason_page); - - DPRINTK("Adapter check interrupt\n"); - DPRINTK("8 reason bytes follow: "); - for(i=0; i<8; i++, check_reason++) - printk("%02X ", (int)isa_readb(check_reason)); - printk("\n"); - - isa_writeb((~ADAP_CHK_INT), ti->mmio + ACA_OFFSET + ACA_RESET + ISRP_ODD); - isa_writeb(INT_ENABLE, ti->mmio + ACA_OFFSET + ACA_SET + ISRP_EVEN); - - } else if (isa_readb(ti->mmio + ACA_OFFSET + ACA_RW + ISRP_EVEN) - & (TCR_INT | ERR_INT | ACCESS_INT)) { + /*dev->tbusy = 0;*/ + netif_wake_queue(dev); + if (ti->readlog_pending) + ibmtr_readlog(dev); + break; + } + case XMIT_UI_FRAME:{ + unsigned char xmit_ret_code; - DPRINTK("adapter error: ISRP_EVEN : %02x\n", - (int)isa_readb(ti->mmio + ACA_OFFSET + ACA_RW + ISRP_EVEN)); - isa_writeb(~(TCR_INT | ERR_INT | ACCESS_INT), - ti->mmio + ACA_OFFSET + ACA_RESET + ISRP_EVEN); - isa_writeb(INT_ENABLE, ti->mmio + ACA_OFFSET + ACA_SET + ISRP_EVEN); - - } else if (status - & (SRB_RESP_INT | ASB_FREE_INT | ARB_CMD_INT | SSB_RESP_INT)) { - /* SRB, ASB, ARB or SSB response */ + xmit_ret_code = readb(ti->srb + RETCODE_OFST); + if (xmit_ret_code == 0xff) break; + DPRINTK("error on xmit_ui_frame request: %02X\n", + xmit_ret_code); + if (ti->current_skb) { + dev_kfree_skb_irq(ti->current_skb); + ti->current_skb = NULL; + } + netif_wake_queue(dev); + if (ti->readlog_pending) + ibmtr_readlog(dev); + break; + } + case DIR_OPEN_ADAPTER: + dir_open_adapter(dev); + break; + case DLC_OPEN_SAP: + if (readb(ti->srb + RETCODE_OFST)) { + DPRINTK("open_sap failed: ret_code = %02X, " + "retrying\n", + (int) readb(ti->srb + RETCODE_OFST)); + ti->open_action = REOPEN; + ibmtr_reset_timer(&(ti->tr_timer), dev); + break; + } + ti->exsap_station_id = readw(ti->srb + STATION_ID_OFST); + ti->sap_status = OPEN;/* TR adapter is now available */ + if (ti->open_mode==MANUAL){ + wake_up(&ti->wait_for_reset); + break; + } + netif_wake_queue(dev); + dev->flags |= IFF_RUNNING;/*BMS 12/2000*/ + break; + case DIR_INTERRUPT: + case DIR_MOD_OPEN_PARAMS: + case DIR_SET_GRP_ADDR: + case DIR_SET_FUNC_ADDR: + case DLC_CLOSE_SAP: + if (readb(ti->srb + RETCODE_OFST)) + DPRINTK("error on %02X: %02X\n", + (int) readb(ti->srb + COMMAND_OFST), + (int) readb(ti->srb + RETCODE_OFST)); + break; + case DIR_READ_LOG: + if (readb(ti->srb + RETCODE_OFST)){ + DPRINTK("error on dir_read_log: %02X\n", + (int) readb(ti->srb + RETCODE_OFST)); + netif_wake_queue(dev); + break; + } +#if IBMTR_DEBUG_MESSAGES - if (status & SRB_RESP_INT) { /* SRB response */ - SET_PAGE(ti->srb_page); +#define LINE_ERRORS_OFST 0 +#define INTERNAL_ERRORS_OFST 1 +#define BURST_ERRORS_OFST 2 +#define AC_ERRORS_OFST 3 +#define ABORT_DELIMITERS_OFST 4 +#define LOST_FRAMES_OFST 6 +#define RECV_CONGEST_COUNT_OFST 7 +#define FRAME_COPIED_ERRORS_OFST 8 +#define FREQUENCY_ERRORS_OFST 9 +#define TOKEN_ERRORS_OFST 10 + + DPRINTK("Line errors %02X, Internal errors %02X, " + "Burst errors %02X\n" "A/C errors %02X, " + "Abort delimiters %02X, Lost frames %02X\n" + "Receive congestion count %02X, " + "Frame copied errors %02X\nFrequency errors %02X, " + "Token errors %02X\n", + (int) readb(ti->srb + LINE_ERRORS_OFST), + (int) readb(ti->srb + INTERNAL_ERRORS_OFST), + (int) readb(ti->srb + BURST_ERRORS_OFST), + (int) readb(ti->srb + AC_ERRORS_OFST), + (int) readb(ti->srb + ABORT_DELIMITERS_OFST), + (int) readb(ti->srb + LOST_FRAMES_OFST), + (int) readb(ti->srb + RECV_CONGEST_COUNT_OFST), + (int) readb(ti->srb + FRAME_COPIED_ERRORS_OFST), + (int) readb(ti->srb + FREQUENCY_ERRORS_OFST), + (int) readb(ti->srb + TOKEN_ERRORS_OFST)); +#endif + netif_wake_queue(dev); + break; + default: + DPRINTK("Unknown command %02X encountered\n", + (int) readb(ti->srb)); + } /* end switch SRB command check */ + writeb(~SRB_RESP_INT, ti->mmio+ ACA_OFFSET+ACA_RESET+ ISRP_ODD); + } /* if SRB response */ + if (status & ASB_FREE_INT) { /* ASB response */ + SET_PAGE(ti->asb_page); #if TR_VERBOSE - DPRINTK("SRB resp: cmd=%02X rsp=%02X\n", - isa_readb(ti->srb), - isa_readb(ti->srb + offsetof(struct srb_xmit, ret_code))); -#endif - - switch(isa_readb(ti->srb)) { /* SRB command check */ - - case XMIT_DIR_FRAME: { - unsigned char xmit_ret_code; - - xmit_ret_code=isa_readb(ti->srb + offsetof(struct srb_xmit, ret_code)); - if (xmit_ret_code != 0xff) { - DPRINTK("error on xmit_dir_frame request: %02X\n", - xmit_ret_code); - if (ti->current_skb) { - dev_kfree_skb_irq(ti->current_skb); - ti->current_skb=NULL; - } - netif_wake_queue(dev); - if (ti->readlog_pending) ibmtr_readlog(dev); - } - } - break; - - case XMIT_UI_FRAME: { - unsigned char xmit_ret_code; - - xmit_ret_code=isa_readb(ti->srb + offsetof(struct srb_xmit, ret_code)); - if (xmit_ret_code != 0xff) { - DPRINTK("error on xmit_ui_frame request: %02X\n", - xmit_ret_code); - if (ti->current_skb) { - dev_kfree_skb_irq(ti->current_skb); - ti->current_skb=NULL; - } - netif_wake_queue(dev); - if (ti->readlog_pending) - ibmtr_readlog(dev); - } - } - break; - - case DIR_OPEN_ADAPTER: { - unsigned char open_ret_code; - __u16 open_error_code; - - ti->srb=ntohs(isa_readw(ti->init_srb +offsetof(struct srb_open_response, srb_addr))); - ti->ssb=ntohs(isa_readw(ti->init_srb +offsetof(struct srb_open_response, ssb_addr))); - ti->arb=ntohs(isa_readw(ti->init_srb +offsetof(struct srb_open_response, arb_addr))); - ti->asb=ntohs(isa_readw(ti->init_srb +offsetof(struct srb_open_response, asb_addr))); - if (ti->page_mask) { - ti->srb_page=(ti->srb>>8) & ti->page_mask; - ti->srb &= ~(ti->page_mask<<8); - ti->ssb_page=(ti->ssb>>8) & ti->page_mask; - ti->ssb &= ~(ti->page_mask<<8); - ti->arb_page=(ti->arb>>8) & ti->page_mask; - ti->arb &= ~(ti->page_mask<<8); - ti->asb_page=(ti->asb>>8) & ti->page_mask; - ti->asb &= ~(ti->page_mask<<8); - } - ti->srb+=ti->sram; - ti->ssb+=ti->sram; - ti->arb+=ti->sram; - ti->asb+=ti->sram; - - ti->current_skb=NULL; - - open_ret_code = isa_readb(ti->init_srb +offsetof(struct srb_open_response, ret_code)); - open_error_code = ntohs(isa_readw(ti->init_srb +offsetof(struct srb_open_response, error_code))); - - if (open_ret_code==7) { - - if (!ti->auto_ringspeedsave && (open_error_code==0x24)) { - DPRINTK("Open failed: Adapter speed must match ring " - "speed if Automatic Ring Speed Save is disabled.\n"); - ti->open_status=FAILURE; - wake_up(&ti->wait_for_reset); - } else if (open_error_code==0x24) - DPRINTK("Retrying open to adjust to ring speed.\n"); - else if ((open_error_code==0x2d) && ti->auto_ringspeedsave) - DPRINTK("No signal detected for Auto Speed Detection.\n"); - else if (open_error_code==0x11) - { - if (ti->retry_count--) - DPRINTK("Ring broken/disconnected, retrying...\n"); - else { - DPRINTK("Ring broken/disconnected, open failed.\n"); - ti->open_status = FAILURE; - } - } - else DPRINTK("Unrecoverable error: error code = %04x.\n", - open_error_code); - - } else if (!open_ret_code) { -#if !TR_NEWFORMAT - DPRINTK("board opened...\n"); -#else - DPRINTK("Adapter initialized and opened.\n"); + DPRINTK("ASB resp: cmd=%02X\n", readb(ti->asb)); #endif - isa_writeb(~(SRB_RESP_INT), - ti->mmio + ACA_OFFSET + ACA_RESET + ISRP_ODD); - isa_writeb(~(CMD_IN_SRB), - ti->mmio + ACA_OFFSET + ACA_RESET + ISRA_ODD); - open_sap(EXTENDED_SAP,dev); - - /* YdW probably hates me */ - goto skip_reset; - } else - DPRINTK("open failed: ret_code = %02X, retrying\n", - open_ret_code); - - if (ti->open_status != FAILURE) { - ibmtr_reset_timer(&(ti->tr_timer), dev); - } - - } - break; - - case DIR_CLOSE_ADAPTER: - wake_up(&ti->wait_for_tok_int); - break; - - case DLC_OPEN_SAP: - if (isa_readb(ti->srb+offsetof(struct dlc_open_sap, ret_code))) { - DPRINTK("open_sap failed: ret_code = %02X,retrying\n", - (int)isa_readb(ti->srb+offsetof(struct dlc_open_sap, ret_code))); - ibmtr_reset_timer(&(ti->tr_timer), dev); - } else { - ti->exsap_station_id= - isa_readw(ti->srb+offsetof(struct dlc_open_sap, station_id)); - ti->open_status=SUCCESS; /* TR adapter is now available */ - wake_up(&ti->wait_for_reset); - } - break; - - case DIR_INTERRUPT: - case DIR_MOD_OPEN_PARAMS: - case DIR_SET_GRP_ADDR: - case DIR_SET_FUNC_ADDR: - case DLC_CLOSE_SAP: - if (isa_readb(ti->srb+offsetof(struct srb_interrupt, ret_code))) - DPRINTK("error on %02X: %02X\n", - (int)isa_readb(ti->srb+offsetof(struct srb_interrupt, command)), - (int)isa_readb(ti->srb+offsetof(struct srb_interrupt, ret_code))); - break; - - case DIR_READ_LOG: - if (isa_readb(ti->srb+offsetof(struct srb_read_log, ret_code))) - DPRINTK("error on dir_read_log: %02X\n", - (int)isa_readb(ti->srb+offsetof(struct srb_read_log, ret_code))); - else - if (IBMTR_DEBUG_MESSAGES) { - DPRINTK( - "Line errors %02X, Internal errors %02X, Burst errors %02X\n" - "A/C errors %02X, Abort delimiters %02X, Lost frames %02X\n" - "Receive congestion count %02X, Frame copied errors %02X\n" - "Frequency errors %02X, Token errors %02X\n", - (int)isa_readb(ti->srb+offsetof(struct srb_read_log, - line_errors)), - (int)isa_readb(ti->srb+offsetof(struct srb_read_log, - internal_errors)), - (int)isa_readb(ti->srb+offsetof(struct srb_read_log, - burst_errors)), - (int)isa_readb(ti->srb+offsetof(struct srb_read_log, A_C_errors)), - (int)isa_readb(ti->srb+offsetof(struct srb_read_log, - abort_delimiters)), - (int)isa_readb(ti->srb+offsetof(struct srb_read_log, - lost_frames)), - (int)isa_readb(ti->srb+offsetof(struct srb_read_log, - recv_congest_count)), - (int)isa_readb(ti->srb+offsetof(struct srb_read_log, - frame_copied_errors)), - (int)isa_readb(ti->srb+offsetof(struct srb_read_log, - frequency_errors)), - (int)isa_readb(ti->srb+offsetof(struct srb_read_log, - token_errors))); - } - netif_wake_queue(dev); - break; - - default: - DPRINTK("Unknown command %02X encountered\n", - (int)isa_readb(ti->srb)); - - } /* SRB command check */ - isa_writeb(~CMD_IN_SRB, ti->mmio + ACA_OFFSET + ACA_RESET + ISRA_ODD); - isa_writeb(~SRB_RESP_INT, ti->mmio + ACA_OFFSET + ACA_RESET + ISRP_ODD); + switch (readb(ti->asb)) { /* ASB command check */ + case REC_DATA: + case XMIT_UI_FRAME: + case XMIT_DIR_FRAME: + break; + default: + DPRINTK("unknown command in asb %02X\n", + (int) readb(ti->asb)); + } /* switch ASB command check */ + if (readb(ti->asb + 2) != 0xff) /* checks ret_code */ + DPRINTK("ASB error %02X in cmd %02X\n", + (int) readb(ti->asb + 2), (int) readb(ti->asb)); + writeb(~ASB_FREE_INT, ti->mmio+ ACA_OFFSET+ACA_RESET+ ISRP_ODD); + } /* if ASB response */ - skip_reset:; - } /* SRB response */ +#define STATUS_OFST 6 +#define NETW_STATUS_OFST 6 - if (status & ASB_FREE_INT) { /* ASB response */ - SET_PAGE(ti->asb_page); + if (status & ARB_CMD_INT) { /* ARB response */ + SET_PAGE(ti->arb_page); #if TR_VERBOSE - DPRINTK("ASB resp: cmd=%02X\n", isa_readb(ti->asb)); - #endif - - switch(isa_readb(ti->asb)) { /* ASB command check */ - - case REC_DATA: - case XMIT_UI_FRAME: - case XMIT_DIR_FRAME: - break; - - default: - DPRINTK("unknown command in asb %02X\n", - (int)isa_readb(ti->asb)); - - } /* ASB command check */ - - if (isa_readb(ti->asb+2)!=0xff) /* checks ret_code */ - DPRINTK("ASB error %02X in cmd %02X\n", - (int)isa_readb(ti->asb+2),(int)isa_readb(ti->asb)); - isa_writeb(~ASB_FREE_INT, ti->mmio + ACA_OFFSET + ACA_RESET + ISRP_ODD); - - } /* ASB response */ - - if (status & ARB_CMD_INT) { /* ARB response */ - SET_PAGE(ti->arb_page); -#if TR_VERBOSE - DPRINTK("ARB resp: cmd=%02X rsp=%02X\n", - isa_readb(ti->arb), - isa_readb(ti->arb + offsetof(struct arb_dlc_status, status))); + DPRINTK("ARB resp: cmd=%02X\n", readb(ti->arb)); #endif - switch (isa_readb(ti->arb)) { /* ARB command check */ - - case DLC_STATUS: - DPRINTK("DLC_STATUS new status: %02X on station %02X\n", - ntohs(isa_readw(ti->arb + offsetof(struct arb_dlc_status, status))), - ntohs(isa_readw(ti->arb - +offsetof(struct arb_dlc_status, station_id)))); - break; - - case REC_DATA: - tr_rx(dev); - break; - - case RING_STAT_CHANGE: { - unsigned short ring_status; - - ring_status=ntohs(isa_readw(ti->arb - +offsetof(struct arb_ring_stat_change, ring_status))); - - if (ring_status & (SIGNAL_LOSS | LOBE_FAULT)) { - - DPRINTK("Signal loss/Lobe fault\n"); - DPRINTK("We try to reopen the adapter.\n"); - ibmtr_reset_timer(&(ti->tr_timer), dev); - } else if (ring_status & (HARD_ERROR | XMIT_BEACON - | AUTO_REMOVAL | REMOVE_RECV | RING_RECOVER)) - DPRINTK("New ring status: %02X\n", ring_status); - - if (ring_status & LOG_OVERFLOW) { - if (netif_queue_stopped(dev)) - ti->readlog_pending = 1; - else - ibmtr_readlog(dev); - } - } - break; - - case XMIT_DATA_REQ: - tr_tx(dev); - break; - - default: - DPRINTK("Unknown command %02X in arb\n", - (int)isa_readb(ti->arb)); - break; - - } /* ARB command check */ - - isa_writeb(~ARB_CMD_INT, ti->mmio + ACA_OFFSET + ACA_RESET + ISRP_ODD); - isa_writeb(ARB_FREE, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD); - - } /* ARB response */ - - if (status & SSB_RESP_INT) { /* SSB response */ - unsigned char retcode; - SET_PAGE(ti->ssb_page); + switch (readb(ti->arb)) { /* ARB command check */ + case DLC_STATUS: + DPRINTK("DLC_STATUS new status: %02X on station %02X\n", + ntohs(readw(ti->arb + STATUS_OFST)), + ntohs(readw(ti->arb+ STATION_ID_OFST))); + break; + case REC_DATA: + tr_rx(dev); + break; + case RING_STAT_CHANGE:{ + unsigned short ring_status; + ring_status= ntohs(readw(ti->arb + NETW_STATUS_OFST)); + if (ibmtr_debug_trace & TRC_INIT) + DPRINTK("Ring Status Change...(0x%x)\n", + ring_status); + if(ring_status& (REMOVE_RECV|AUTO_REMOVAL|LOBE_FAULT)){ + netif_stop_queue(dev); + dev->flags &= ~IFF_RUNNING;/*not typical Linux*/ + DPRINTK("Remove received, or Auto-removal error" + ", or Lobe fault\n"); + DPRINTK("We'll try to reopen the closed adapter" + " after a %d second delay.\n", + TR_RETRY_INTERVAL/HZ); + /*I was confused: I saw the TR reopening but */ + /*forgot:with an RJ45 in an RJ45/ICS adapter */ + /*but adapter not in the ring, the TR will */ + /* open, and then soon close and come here. */ + ti->open_mode = AUTOMATIC; + ti->open_status = CLOSED; /*12/2000 BMS*/ + ti->open_action = REOPEN; + ibmtr_reset_timer(&(ti->tr_timer), dev); + } else if (ring_status & LOG_OVERFLOW) { + if(netif_queue_stopped(dev)) + ti->readlog_pending = 1; + else + ibmtr_readlog(dev); + } + break; + } + case XMIT_DATA_REQ: + tr_tx(dev); + break; + default: + DPRINTK("Unknown command %02X in arb\n", + (int) readb(ti->arb)); + break; + } /* switch ARB command check */ + writeb(~ARB_CMD_INT, ti->mmio+ ACA_OFFSET+ACA_RESET + ISRP_ODD); + writeb(ARB_FREE, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD); + } /* if ARB response */ + if (status & SSB_RESP_INT) { /* SSB response */ + unsigned char retcode; + SET_PAGE(ti->ssb_page); #if TR_VERBOSE - DPRINTK("SSB resp: cmd=%02X rsp=%02X\n", - isa_readb(ti->ssb), isa_readb(ti->ssb+2)); + DPRINTK("SSB resp: cmd=%02X rsp=%02X\n", + readb(ti->ssb), readb(ti->ssb + 2)); #endif - switch (isa_readb(ti->ssb)) { /* SSB command check */ - - case XMIT_DIR_FRAME: - case XMIT_UI_FRAME: - retcode = isa_readb(ti->ssb+2); - if (retcode && (retcode != 0x22)) /* checks ret_code */ - DPRINTK("xmit ret_code: %02X xmit error code: %02X\n", - (int)retcode, (int)isa_readb(ti->ssb+6)); - else ti->tr_stats.tx_packets++; - break; - - case XMIT_XID_CMD: - DPRINTK("xmit xid ret_code: %02X\n", (int)isa_readb(ti->ssb+2)); - break; - - default: - DPRINTK("Unknown command %02X in ssb\n", (int)isa_readb(ti->ssb)); - - } /* SSB command check */ - - isa_writeb(~SSB_RESP_INT, ti->mmio + ACA_OFFSET + ACA_RESET + ISRP_ODD); - isa_writeb(SSB_FREE, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD); - - } /* SSB response */ - - } /* SRB, ARB, ASB or SSB response */ - - isa_writeb(INT_ENABLE, ti->mmio + ACA_OFFSET + ACA_SET + ISRP_EVEN); - break; - case FIRST_INT: - initial_tok_int(dev); - break; - - default: - DPRINTK("Unexpected interrupt from tr adapter\n"); - - } -#ifdef PCMCIA - return_point: -#endif + switch (readb(ti->ssb)) { /* SSB command check */ + case XMIT_DIR_FRAME: + case XMIT_UI_FRAME: + retcode = readb(ti->ssb + 2); + if (retcode && (retcode != 0x22))/* checks ret_code */ + DPRINTK("xmit ret_code: %02X xmit error code: " + "%02X\n", + (int)retcode, (int)readb(ti->ssb + 6)); + else + ti->tr_stats.tx_packets++; + break; + case XMIT_XID_CMD: + DPRINTK("xmit xid ret_code: %02X\n", + (int) readb(ti->ssb + 2)); + default: + DPRINTK("Unknown command %02X in ssb\n", + (int) readb(ti->ssb)); + } /* SSB command check */ + writeb(~SSB_RESP_INT, ti->mmio+ ACA_OFFSET+ACA_RESET+ ISRP_ODD); + writeb(SSB_FREE, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD); + } /* if SSB response */ #ifdef ENABLE_PAGING - isa_writeb(save_srpr, ti->mmio+ACA_OFFSET+ACA_RW+SRPR_EVEN); + writeb(save_srpr, ti->mmio + ACA_OFFSET + ACA_RW + SRPR_EVEN); #endif - + writeb(INT_ENABLE, ti->mmio + ACA_OFFSET + ACA_SET + ISRP_EVEN); spin_unlock(&(ti->lock)); -} +} /*tok_interrupt */ + +/*****************************************************************************/ + +#define INIT_STATUS_OFST 1 +#define INIT_STATUS_2_OFST 2 +#define ENCODED_ADDRESS_OFST 8 static void initial_tok_int(struct net_device *dev) { - __u32 encoded_addr; - __u32 hw_encoded_addr; + __u32 encoded_addr, hw_encoded_addr; struct tok_info *ti; - ti=(struct tok_info *) dev->priv; + unsigned char init_status; /*BMS 12/2000*/ - ti->do_tok_int=NOT_FIRST; + ti = (struct tok_info *) dev->priv; -#ifndef TR_NEWFORMAT - DPRINTK("Initial tok int received\n"); -#endif + ti->do_tok_int = NOT_FIRST; /* we assign the shared-ram address for ISA devices */ - if(!ti->sram) { - isa_writeb(ti->sram_base, ti->mmio + ACA_OFFSET + ACA_RW + RRR_EVEN); - ti->sram=((__u32)ti->sram_base << 12); - } - ti->init_srb=ntohs((unsigned short)isa_readw(ti->mmio+ ACA_OFFSET + WRBR_EVEN)); + writeb(ti->sram_base, ti->mmio + ACA_OFFSET + ACA_RW + RRR_EVEN); +#ifndef PCMCIA + ti->sram_virt = (u32)ioremap(((__u32)ti->sram_base << 12), ti->avail_shared_ram); +#endif + ti->init_srb = ntohs(readw(ti->mmio + ACA_OFFSET + WRBR_EVEN)); if (ti->page_mask) { - ti->init_srb_page=(ti->init_srb>>8)&ti->page_mask; - ti->init_srb &= ~(ti->page_mask<<8); + ti->init_srb_page = (ti->init_srb >> 8) & ti->page_mask; + ti->init_srb &= ~(ti->page_mask << 8); + } + ti->init_srb += ti->sram_virt; + if (ti->page_mask && ti->avail_shared_ram == 127) { + int last_512 = 0xfe00, i; + int last_512_page=0; + last_512_page=(last_512>>8)&ti->page_mask; + last_512 &= ~(ti->page_mask << 8); + /* initialize high section of ram (if necessary) */ + SET_PAGE(last_512_page); + for (i = 0; i < 512; i++) + writeb(0, ti->sram_virt + last_512 + i); } - ti->init_srb+=ti->sram; - - if (ti->avail_shared_ram == 127) { - int i; - int last_512=0xfe00; - if (ti->page_mask) { - last_512 &= ~(ti->page_mask<<8); - } - /* initialize high section of ram (if necessary) */ - SET_PAGE(0xc0); - for (i=0; i<512; i++) { - isa_writeb(0,ti->sram+last_512+i); - } - } SET_PAGE(ti->init_srb_page); - dev->mem_start = ti->sram; - dev->mem_end = ti->sram + (ti->mapped_ram_size<<9) - 1; - #if TR_VERBOSE { - int i; - DPRINTK("init_srb(%lx):", (long)ti->init_srb); - for (i=0;i<17;i++) printk("%02X ", (int)isa_readb(ti->init_srb+i)); - printk("\n"); - } -#endif - - hw_encoded_addr = isa_readw(ti->init_srb - + offsetof(struct srb_init_response, encoded_address)); - -#if !TR_NEWFORMAT - DPRINTK("srb_init_response->encoded_address: %04X\n", hw_encoded_addr); - DPRINTK("ntohs(srb_init_response->encoded_address): %04X\n", - ntohs(hw_encoded_addr)); -#endif - - encoded_addr=(ti->sram + ntohs(hw_encoded_addr)); - ti->ring_speed = isa_readb(ti->init_srb+offsetof(struct srb_init_response, init_status)) & 0x01 ? 16 : 4; -#if !TR_NEWFORMAT - DPRINTK("encoded addr (%04X,%04X,%08X): ", hw_encoded_addr, - ntohs(hw_encoded_addr), encoded_addr); -#else - DPRINTK("Initial interrupt : %d Mbps, shared RAM base %08x.\n", - ti->ring_speed, ti->sram); -#endif - - ti->auto_ringspeedsave=isa_readb(ti->init_srb - +offsetof(struct srb_init_response, init_status_2)) & 0x4 ? TRUE : FALSE; - -#if !TR_NEWFORMAT - for(i=0;i<TR_ALEN;i++) { - dev->dev_addr[i]=isa_readb(encoded_addr + i); - printk("%02X%s", dev->dev_addr[i], (i==TR_ALEN-1) ? "" : ":" ); - } - printk("\n"); -#endif - - tok_open_adapter((unsigned long)dev); -} - -static int tok_init_card(struct net_device *dev) -{ - struct tok_info *ti; - short PIOaddr; - unsigned long i; - PIOaddr = dev->base_addr; - ti=(struct tok_info *) dev->priv; - - /* Special processing for first interrupt after reset */ - ti->do_tok_int=FIRST_INT; - - /* Reset adapter */ - netif_stop_queue(dev); - - isa_writeb(~INT_ENABLE, ti->mmio + ACA_OFFSET + ACA_RESET + ISRP_EVEN); - -#if !TR_NEWFORMAT - DPRINTK("resetting card\n"); -#endif - - outb(0, PIOaddr+ADAPTRESET); - for (i=jiffies+TR_RESET_INTERVAL; time_before_eq(jiffies, i);); /* wait 50ms */ - outb(0,PIOaddr+ADAPTRESETREL); -#ifdef ENABLE_PAGING - if(ti->page_mask) - isa_writeb(SRPR_ENABLE_PAGING, ti->mmio + ACA_OFFSET + ACA_RW + SRPR_EVEN); -#endif - -#if !TR_NEWFORMAT - DPRINTK("card reset\n"); -#endif - - ti->open_status=IN_PROGRESS; - isa_writeb(INT_ENABLE, ti->mmio + ACA_OFFSET + ACA_SET + ISRP_EVEN); - return 0; -} - -static void open_sap(unsigned char type,struct net_device *dev) -{ int i; - struct tok_info *ti=(struct tok_info *) dev->priv; - - SET_PAGE(ti->srb_page); - for (i=0; i<sizeof(struct dlc_open_sap); i++) - isa_writeb(0, ti->srb+i); - isa_writeb(DLC_OPEN_SAP, ti->srb + offsetof(struct dlc_open_sap, command)); - isa_writew(htons(MAX_I_FIELD), - ti->srb + offsetof(struct dlc_open_sap, max_i_field)); - isa_writeb(SAP_OPEN_IND_SAP | SAP_OPEN_PRIORITY, - ti->srb + offsetof(struct dlc_open_sap, sap_options)); - isa_writeb(SAP_OPEN_STATION_CNT, - ti->srb + offsetof(struct dlc_open_sap, station_count)); - isa_writeb(type, ti->srb + offsetof(struct dlc_open_sap, sap_value)); - - isa_writeb(CMD_IN_SRB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD); - -} - -void tok_open_adapter(unsigned long dev_addr) -{ - - struct net_device *dev=(struct net_device *)dev_addr; - struct tok_info *ti; - int i; - - ti=(struct tok_info *) dev->priv; - -#if !TR_NEWFORMAT - DPRINTK("now opening the board...\n"); + DPRINTK("ti->init_srb_page=0x%x\n", ti->init_srb_page); + DPRINTK("init_srb(%x):", (ti->init_srb) ); + for (i = 0; i < 20; i++) + printk("%02X ", (int) readb(ti->init_srb + i)); + printk("\n"); + } #endif - isa_writeb(~SRB_RESP_INT, ti->mmio + ACA_OFFSET + ACA_RESET + ISRP_ODD); - isa_writeb(~CMD_IN_SRB, ti->mmio + ACA_OFFSET + ACA_RESET + ISRA_ODD); + hw_encoded_addr = readw(ti->init_srb + ENCODED_ADDRESS_OFST); + encoded_addr = ntohs(hw_encoded_addr); + init_status= /*BMS 12/2000 check for shallow mode possibility (Turbo)*/ + readb(ti->init_srb+offsetof(struct srb_init_response,init_status)); + /*printk("Initial interrupt: init_status= 0x%02x\n",init_status);*/ + ti->ring_speed = init_status & 0x01 ? 16 : 4; + DPRINTK("Initial interrupt : %d Mbps, shared RAM base %08x.\n", + ti->ring_speed, (unsigned int)dev->mem_start); + ti->auto_speedsave=readb(ti->init_srb+INIT_STATUS_2_OFST)&4?TRUE:FALSE; - for (i=0; i<sizeof(struct dir_open_adapter); i++) - isa_writeb(0, ti->init_srb+i); + if (ti->open_mode == MANUAL) wake_up(&ti->wait_for_reset); + else tok_open_adapter((unsigned long)dev); + +} /*initial_tok_int() */ - isa_writeb(DIR_OPEN_ADAPTER, - ti->init_srb + offsetof(struct dir_open_adapter, command)); - isa_writew(htons(OPEN_PASS_BCON_MAC), - ti->init_srb + offsetof(struct dir_open_adapter, open_options)); - if (ti->ring_speed == 16) { - isa_writew(htons(ti->dhb_size16mb), - ti->init_srb + offsetof(struct dir_open_adapter, dhb_length)); - isa_writew(htons(ti->rbuf_cnt16), - ti->init_srb + offsetof(struct dir_open_adapter, num_rcv_buf)); - isa_writew(htons(ti->rbuf_len16), - ti->init_srb + offsetof(struct dir_open_adapter, rcv_buf_len)); - } else { - isa_writew(htons(ti->dhb_size4mb), - ti->init_srb + offsetof(struct dir_open_adapter, dhb_length)); - isa_writew(htons(ti->rbuf_cnt4), - ti->init_srb + offsetof(struct dir_open_adapter, num_rcv_buf)); - isa_writew(htons(ti->rbuf_len4), - ti->init_srb + offsetof(struct dir_open_adapter, rcv_buf_len)); - } - isa_writeb(NUM_DHB, /* always 2 */ - ti->init_srb + offsetof(struct dir_open_adapter, num_dhb)); - isa_writeb(DLC_MAX_SAP, - ti->init_srb + offsetof(struct dir_open_adapter, dlc_max_sap)); - isa_writeb(DLC_MAX_STA, - ti->init_srb + offsetof(struct dir_open_adapter, dlc_max_sta)); - - ti->srb=ti->init_srb; /* We use this one in the interrupt handler */ - ti->srb_page=ti->init_srb_page; - DPRINTK("Opend adapter: Xmit bfrs: %d X %d, Rcv bfrs: %d X %d\n", - isa_readb(ti->init_srb+offsetof(struct dir_open_adapter,num_dhb)), - ntohs(isa_readw(ti->init_srb+offsetof(struct dir_open_adapter,dhb_length))), - ntohs(isa_readw(ti->init_srb+offsetof(struct dir_open_adapter,num_rcv_buf))), - ntohs(isa_readw(ti->init_srb+offsetof(struct dir_open_adapter,rcv_buf_len))) ); +/*****************************************************************************/ - isa_writeb(INT_ENABLE, ti->mmio + ACA_OFFSET + ACA_SET + ISRP_EVEN); - isa_writeb(CMD_IN_SRB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD); +#define CMD_CORRELATE_OFST 1 +#define DHB_ADDRESS_OFST 6 -} +#define FRAME_LENGTH_OFST 6 +#define HEADER_LENGTH_OFST 8 +#define RSAP_VALUE_OFST 9 static void tr_tx(struct net_device *dev) { - struct tok_info *ti=(struct tok_info *) dev->priv; - struct trh_hdr *trhdr=(struct trh_hdr *)ti->current_skb->data; + struct tok_info *ti = (struct tok_info *) dev->priv; + struct trh_hdr *trhdr = (struct trh_hdr *) ti->current_skb->data; unsigned int hdr_len; - __u32 dhb; + __u32 dhb=0,dhb_base; unsigned char xmit_command; - int i; - struct trllc *llc; - struct srb_xmit xsrb; - __u8 dhb_page=0; - __u8 llc_ssap; + int i,dhb_len=0x4000,src_len,src_offset; + struct trllc *llc; + struct srb_xmit xsrb; + __u8 dhb_page = 0; + __u8 llc_ssap; SET_PAGE(ti->asb_page); - if (isa_readb(ti->asb + offsetof(struct asb_xmit_resp, ret_code))!=0xFF) - DPRINTK("ASB not free !!!\n"); - /* in providing the transmit interrupts, - is telling us it is ready for data and - providing a shared memory address for us - to stuff with data. Here we compute the - effective address where we will place data.*/ - SET_PAGE(ti->arb_page); - dhb=ntohs(isa_readw(ti->arb + offsetof(struct arb_xmit_req, dhb_address))); - if (ti->page_mask) { - dhb_page=(dhb >> 8) & ti->page_mask; - dhb &= ~(ti->page_mask << 8); - } - dhb+=ti->sram; - + if (readb(ti->asb+RETCODE_OFST) != 0xFF) DPRINTK("ASB not free !!!\n"); + + /* in providing the transmit interrupts, is telling us it is ready for + data and providing a shared memory address for us to stuff with data. + Here we compute the effective address where we will place data. + */ + SET_PAGE(ti->arb_page); + dhb=dhb_base=ntohs(readw(ti->arb + DHB_ADDRESS_OFST)); + if (ti->page_mask) { + dhb_page = (dhb_base >> 8) & ti->page_mask; + dhb=dhb_base & ~(ti->page_mask << 8); + } + dhb += ti->sram_virt; + /* Figure out the size of the 802.5 header */ - if (!(trhdr->saddr[0] & 0x80)) /* RIF present? */ - hdr_len=sizeof(struct trh_hdr)-TR_MAXRIFLEN; - else - hdr_len=((ntohs(trhdr->rcf) & TR_RCF_LEN_MASK)>>8) - +sizeof(struct trh_hdr)-TR_MAXRIFLEN; - - llc = (struct trllc *)(ti->current_skb->data + hdr_len); - - llc_ssap=llc->ssap; - SET_PAGE(ti->srb_page); - isa_memcpy_fromio(&xsrb, ti->srb, sizeof(xsrb)); - SET_PAGE(ti->asb_page); - xmit_command=xsrb.command; - - isa_writeb(xmit_command, ti->asb + offsetof(struct asb_xmit_resp, command)); - isa_writew(xsrb.station_id, - ti->asb + offsetof(struct asb_xmit_resp, station_id)); - isa_writeb(llc_ssap, ti->asb + offsetof(struct asb_xmit_resp, rsap_value)); - isa_writeb(xsrb.cmd_corr, - ti->asb + offsetof(struct asb_xmit_resp, cmd_corr)); - isa_writeb(0, ti->asb + offsetof(struct asb_xmit_resp, ret_code)); - - if ((xmit_command==XMIT_XID_CMD) || (xmit_command==XMIT_TEST_CMD)) { - - isa_writew(htons(0x11), - ti->asb + offsetof(struct asb_xmit_resp, frame_length)); - isa_writeb(0x0e, ti->asb + offsetof(struct asb_xmit_resp, hdr_length)); - SET_PAGE(dhb_page); - isa_writeb(AC, dhb); - isa_writeb(LLC_FRAME, dhb+1); + if (!(trhdr->saddr[0] & 0x80)) /* RIF present? */ + hdr_len = sizeof(struct trh_hdr) - TR_MAXRIFLEN; + else + hdr_len = ((ntohs(trhdr->rcf) & TR_RCF_LEN_MASK) >> 8) + + sizeof(struct trh_hdr) - TR_MAXRIFLEN; - for (i=0; i<TR_ALEN; i++) isa_writeb((int)0x0FF, dhb+i+2); - for (i=0; i<TR_ALEN; i++) isa_writeb(0, dhb+i+TR_ALEN+2); + llc = (struct trllc *) (ti->current_skb->data + hdr_len); - isa_writeb(RESP_IN_ASB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD); - return; + llc_ssap = llc->ssap; + SET_PAGE(ti->srb_page); + memcpy_fromio(&xsrb, ti->srb, sizeof(xsrb)); + SET_PAGE(ti->asb_page); + xmit_command = xsrb.command; + writeb(xmit_command, ti->asb + COMMAND_OFST); + writew(xsrb.station_id, ti->asb + STATION_ID_OFST); + writeb(llc_ssap, ti->asb + RSAP_VALUE_OFST); + writeb(xsrb.cmd_corr, ti->asb + CMD_CORRELATE_OFST); + writeb(0, ti->asb + RETCODE_OFST); + if ((xmit_command == XMIT_XID_CMD) || (xmit_command == XMIT_TEST_CMD)) { + writew(htons(0x11), ti->asb + FRAME_LENGTH_OFST); + writeb(0x0e, ti->asb + HEADER_LENGTH_OFST); + SET_PAGE(dhb_page); + writeb(AC, dhb); + writeb(LLC_FRAME, dhb + 1); + for (i = 0; i < TR_ALEN; i++) + writeb((int) 0x0FF, dhb + i + 2); + for (i = 0; i < TR_ALEN; i++) + writeb(0, dhb + i + TR_ALEN + 2); + writeb(RESP_IN_ASB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD); + return; } - /* - * the token ring packet is copied from sk_buff to the adapter - * buffer identified in the command data received with the interrupt. + * the token ring packet is copied from sk_buff to the adapter + * buffer identified in the command data received with the interrupt. */ - isa_writeb(hdr_len, ti->asb + offsetof(struct asb_xmit_resp, hdr_length)); - isa_writew(htons(ti->current_skb->len), - ti->asb + offsetof(struct asb_xmit_resp, frame_length)); - - SET_PAGE(dhb_page); - isa_memcpy_toio(dhb, ti->current_skb->data, ti->current_skb->len); - - isa_writeb(RESP_IN_ASB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD); - ti->tr_stats.tx_bytes+=ti->current_skb->len; + writeb(hdr_len, ti->asb + HEADER_LENGTH_OFST); + writew(htons(ti->current_skb->len), ti->asb + FRAME_LENGTH_OFST); + src_len=ti->current_skb->len; + src_offset=0; + dhb=dhb_base; + while(1) { + if (ti->page_mask) { + dhb_page=(dhb >> 8) & ti->page_mask; + dhb=dhb & ~(ti->page_mask << 8); + dhb_len=0x4000-dhb; /* remaining size of this page */ + } + dhb+=ti->sram_virt; + SET_PAGE(dhb_page); + if (src_len > dhb_len) { + memcpy_toio(dhb,&ti->current_skb->data[src_offset], + dhb_len); + src_len -= dhb_len; + src_offset += dhb_len; + dhb_base+=dhb_len; + dhb=dhb_base; + continue; + } + memcpy_toio(dhb, &ti->current_skb->data[src_offset], src_len); + break; + } + writeb(RESP_IN_ASB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD); + ti->tr_stats.tx_bytes += ti->current_skb->len; dev_kfree_skb_irq(ti->current_skb); - ti->current_skb=NULL; + ti->current_skb = NULL; netif_wake_queue(dev); - if (ti->readlog_pending) ibmtr_readlog(dev); -} + if (ti->readlog_pending) + ibmtr_readlog(dev); +} /*tr_tx */ + +/*****************************************************************************/ + + +#define RECEIVE_BUFFER_OFST 6 +#define LAN_HDR_LENGTH_OFST 8 +#define DLC_HDR_LENGTH_OFST 9 + +#define DSAP_OFST 0 +#define SSAP_OFST 1 +#define LLC_OFST 2 +#define PROTID_OFST 3 +#define ETHERTYPE_OFST 6 static void tr_rx(struct net_device *dev) { - struct tok_info *ti=(struct tok_info *) dev->priv; + struct tok_info *ti = (struct tok_info *) dev->priv; __u32 rbuffer, rbufdata; - __u8 rbuffer_page=0; + __u8 rbuffer_page = 0; __u32 llc; unsigned char *data; unsigned int rbuffer_len, lan_hdr_len, hdr_len, ip_len, length; + unsigned char dlc_hdr_len; struct sk_buff *skb; unsigned int skb_size = 0; - int IPv4_p = 0; + int IPv4_p = 0; unsigned int chksum = 0; struct iphdr *iph; struct arb_rec_req rarb; SET_PAGE(ti->arb_page); - isa_memcpy_fromio(&rarb, ti->arb, sizeof(rarb)); - rbuffer=ntohs(rarb.rec_buf_addr)+2; + memcpy_fromio(&rarb, ti->arb, sizeof(rarb)); + rbuffer = ntohs(rarb.rec_buf_addr) ; if (ti->page_mask) { - rbuffer_page=(rbuffer >> 8) & ti->page_mask; - rbuffer &= ~(ti->page_mask<<8); + rbuffer_page = (rbuffer >> 8) & ti->page_mask; + rbuffer &= ~(ti->page_mask << 8); } - rbuffer += ti->sram; - + rbuffer += ti->sram_virt; + SET_PAGE(ti->asb_page); - if(isa_readb(ti->asb + offsetof(struct asb_rec, ret_code))!=0xFF) - DPRINTK("ASB not free !!!\n"); - isa_writeb(REC_DATA, - ti->asb + offsetof(struct asb_rec, command)); - isa_writew(rarb.station_id, - ti->asb + offsetof(struct asb_rec, station_id)); - isa_writew(rarb.rec_buf_addr, - ti->asb + offsetof(struct asb_rec, rec_buf_addr)); + if (readb(ti->asb + RETCODE_OFST) !=0xFF) DPRINTK("ASB not free !!!\n"); - lan_hdr_len=rarb.lan_hdr_len; + writeb(REC_DATA, ti->asb + COMMAND_OFST); + writew(rarb.station_id, ti->asb + STATION_ID_OFST); + writew(rarb.rec_buf_addr, ti->asb + RECEIVE_BUFFER_OFST); + + lan_hdr_len = rarb.lan_hdr_len; + if (lan_hdr_len > sizeof(struct trh_hdr)) { + DPRINTK("Linux cannot handle greater than 18 bytes RIF\n"); + return; + } /*BMS I added this above just to be very safe */ + dlc_hdr_len = readb(ti->arb + DLC_HDR_LENGTH_OFST); hdr_len = lan_hdr_len + sizeof(struct trllc) + sizeof(struct iphdr); SET_PAGE(rbuffer_page); - llc=(rbuffer + offsetof(struct rec_buf, data) + lan_hdr_len); + llc = (rbuffer + offsetof(struct rec_buf, data) + lan_hdr_len); #if TR_VERBOSE DPRINTK("offsetof data: %02X lan_hdr_len: %02X\n", - (unsigned int)offsetof(struct rec_buf,data), (unsigned int)lan_hdr_len); - DPRINTK("llc: %08X rec_buf_addr: %04X ti->sram: %lx\n", llc, - ntohs(rarb.rec_buf_addr), - (long)ti->sram); + (__u32) offsetof(struct rec_buf, data), (unsigned int) lan_hdr_len); + DPRINTK("llc: %08X rec_buf_addr: %04X dev->mem_start: %lX\n", + llc, ntohs(rarb.rec_buf_addr), dev->mem_start); DPRINTK("dsap: %02X, ssap: %02X, llc: %02X, protid: %02X%02X%02X, " "ethertype: %04X\n", - (int)isa_readb(llc + offsetof(struct trllc, dsap)), - (int)isa_readb(llc + offsetof(struct trllc, ssap)), - (int)isa_readb(llc + offsetof(struct trllc, llc)), - (int)isa_readb(llc + offsetof(struct trllc, protid)), - (int)isa_readb(llc + offsetof(struct trllc, protid)+1), - (int)isa_readb(llc + offsetof(struct trllc, protid)+2), - (int)isa_readw(llc + offsetof(struct trllc, ethertype))); -#endif - if (isa_readb(llc + offsetof(struct trllc, llc))!=UI_CMD) { - SET_PAGE(ti->asb_page); - isa_writeb(DATA_LOST, ti->asb + offsetof(struct asb_rec, ret_code)); + (int) readb(llc + DSAP_OFST), (int) readb(llc + SSAP_OFST), + (int) readb(llc + LLC_OFST), (int) readb(llc + PROTID_OFST), + (int) readb(llc+PROTID_OFST+1),(int)readb(llc+PROTID_OFST + 2), + (int) ntohs(readw(llc + ETHERTYPE_OFST))); +#endif + if (readb(llc + offsetof(struct trllc, llc)) != UI_CMD) { + SET_PAGE(ti->asb_page); + writeb(DATA_LOST, ti->asb + RETCODE_OFST); ti->tr_stats.rx_dropped++; - isa_writeb(RESP_IN_ASB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD); + writeb(RESP_IN_ASB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD); return; } - length = ntohs(rarb.frame_len); - if ((isa_readb(llc + offsetof(struct trllc, dsap))==EXTENDED_SAP) && - (isa_readb(llc + offsetof(struct trllc, ssap))==EXTENDED_SAP) && - (length>=hdr_len)) { - IPv4_p = 1; - } - + if (readb(llc + DSAP_OFST) == EXTENDED_SAP && + readb(llc + SSAP_OFST) == EXTENDED_SAP && + length >= hdr_len) IPv4_p = 1; #if TR_VERBOSE - if (!IPv4_p){ +#define SADDR_OFST 8 +#define DADDR_OFST 2 - __u32 trhhdr; + if (!IPv4_p) { - trhhdr=(rbuffer+offsetof(struct rec_buf,data)); + __u32 trhhdr; - DPRINTK("Probably non-IP frame received.\n"); - DPRINTK("ssap: %02X dsap: %02X saddr: %02X:%02X:%02X:%02X:%02X:%02X " - "daddr: %02X:%02X:%02X:%02X:%02X:%02X\n", - (int)isa_readb(llc + offsetof(struct trllc, ssap)), - (int)isa_readb(llc + offsetof(struct trllc, dsap)), - (int)isa_readb(trhhdr + offsetof(struct trh_hdr, saddr)), - (int)isa_readb(trhhdr + offsetof(struct trh_hdr, saddr)+1), - (int)isa_readb(trhhdr + offsetof(struct trh_hdr, saddr)+2), - (int)isa_readb(trhhdr + offsetof(struct trh_hdr, saddr)+3), - (int)isa_readb(trhhdr + offsetof(struct trh_hdr, saddr)+4), - (int)isa_readb(trhhdr + offsetof(struct trh_hdr, saddr)+5), - (int)isa_readb(trhhdr + offsetof(struct trh_hdr, daddr)), - (int)isa_readb(trhhdr + offsetof(struct trh_hdr, daddr)+1), - (int)isa_readb(trhhdr + offsetof(struct trh_hdr, daddr)+2), - (int)isa_readb(trhhdr + offsetof(struct trh_hdr, daddr)+3), - (int)isa_readb(trhhdr + offsetof(struct trh_hdr, daddr)+4), - (int)isa_readb(trhhdr + offsetof(struct trh_hdr, daddr)+5)); - } -#endif - - skb_size = length; - - if (!(skb=dev_alloc_skb(skb_size))) { - DPRINTK("out of memory. frame dropped.\n"); - ti->tr_stats.rx_dropped++; + trhhdr = (rbuffer + offsetof(struct rec_buf, data)); + + DPRINTK("Probably non-IP frame received.\n"); + DPRINTK("ssap: %02X dsap: %02X " + "saddr: %02X:%02X:%02X:%02X:%02X:%02X " + "daddr: %02X:%02X:%02X:%02X:%02X:%02X\n", + readb(llc + SSAP_OFST), readb(llc + DSAP_OFST), + readb(trhhdr+SADDR_OFST), readb(trhhdr+ SADDR_OFST+1), + readb(trhhdr+SADDR_OFST+2), readb(trhhdr+SADDR_OFST+3), + readb(trhhdr+SADDR_OFST+4), readb(trhhdr+SADDR_OFST+5), + readb(trhhdr+DADDR_OFST), readb(trhhdr+DADDR_OFST + 1), + readb(trhhdr+DADDR_OFST+2), readb(trhhdr+DADDR_OFST+3), + readb(trhhdr+DADDR_OFST+4), readb(trhhdr+DADDR_OFST+5)); + } +#endif + + /*BMS handle the case she comes in with few hops but leaves with many */ + skb_size=length-lan_hdr_len+sizeof(struct trh_hdr)+sizeof(struct trllc); + + if (!(skb = dev_alloc_skb(skb_size))) { + DPRINTK("out of memory. frame dropped.\n"); + ti->tr_stats.rx_dropped++; SET_PAGE(ti->asb_page); - isa_writeb(DATA_LOST, ti->asb + offsetof(struct asb_rec, ret_code)); - isa_writeb(RESP_IN_ASB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD); - return; - } - - skb_put(skb, length); - skb_reserve(skb, sizeof(struct trh_hdr)-lan_hdr_len+sizeof(struct trllc)); - skb->dev=dev; - data=skb->data; - rbuffer_len=ntohs(isa_readw(rbuffer + offsetof(struct rec_buf, buf_len))); - rbufdata = rbuffer + offsetof(struct rec_buf,data); + writeb(DATA_LOST, ti->asb + offsetof(struct asb_rec, ret_code)); + writeb(RESP_IN_ASB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD); + return; + } + /*BMS again, if she comes in with few but leaves with many */ + skb_reserve(skb, sizeof(struct trh_hdr) - lan_hdr_len); + skb_put(skb, length); + skb->dev = dev; + data = skb->data; + rbuffer_len = ntohs(readw(rbuffer + offsetof(struct rec_buf, buf_len))); + rbufdata = rbuffer + offsetof(struct rec_buf, data); if (IPv4_p) { - /* Copy the headers without checksumming */ - isa_memcpy_fromio(data, rbufdata, hdr_len); + /* Copy the headers without checksumming */ + memcpy_fromio(data, rbufdata, hdr_len); /* Watch for padded packets and bogons */ - iph=(struct iphdr*)(data + lan_hdr_len + sizeof(struct trllc)); + iph= (struct iphdr *)(data+ lan_hdr_len + sizeof(struct trllc)); ip_len = ntohs(iph->tot_len) - sizeof(struct iphdr); length -= hdr_len; if ((ip_len <= length) && (ip_len > 7)) @@ -1751,107 +1769,123 @@ data += hdr_len; rbuffer_len -= hdr_len; rbufdata += hdr_len; - } - + } /* Copy the payload... */ +#define BUFFER_POINTER_OFST 2 +#define BUFFER_LENGTH_OFST 6 for (;;) { + if (ibmtr_debug_trace&TRC_INITV && length < rbuffer_len) + DPRINTK("CURIOUS, length=%d < rbuffer_len=%d\n", + length,rbuffer_len); if (IPv4_p) - chksum = csum_partial_copy_nocheck(bus_to_virt(rbufdata), data, - length < rbuffer_len ? length : rbuffer_len, - chksum); + chksum=csum_partial_copy_nocheck((void*)rbufdata, + data,length<rbuffer_len?length:rbuffer_len,chksum); else - isa_memcpy_fromio(data, rbufdata, rbuffer_len); - rbuffer = ntohs(isa_readw(rbuffer)); + memcpy_fromio(data, rbufdata, rbuffer_len); + rbuffer = ntohs(readw(rbuffer+BUFFER_POINTER_OFST)) ; if (!rbuffer) break; + rbuffer -= 2; length -= rbuffer_len; data += rbuffer_len; if (ti->page_mask) { - rbuffer_page=(rbuffer>>8) & ti->page_mask; - rbuffer &= ~(ti->page_mask << 8); + rbuffer_page = (rbuffer >> 8) & ti->page_mask; + rbuffer &= ~(ti->page_mask << 8); } - rbuffer += ti->sram; + rbuffer += ti->sram_virt; SET_PAGE(rbuffer_page); - rbuffer_len = ntohs(isa_readw(rbuffer + offsetof(struct rec_buf, buf_len))); + rbuffer_len = ntohs(readw(rbuffer + BUFFER_LENGTH_OFST)); rbufdata = rbuffer + offsetof(struct rec_buf, data); } SET_PAGE(ti->asb_page); - isa_writeb(0, ti->asb + offsetof(struct asb_rec, ret_code)); + writeb(0, ti->asb + offsetof(struct asb_rec, ret_code)); - isa_writeb(RESP_IN_ASB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD); + writeb(RESP_IN_ASB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD); ti->tr_stats.rx_bytes += skb->len; - ti->tr_stats.rx_packets++; + ti->tr_stats.rx_packets++; - skb->protocol = tr_type_trans(skb,dev); - if (IPv4_p && (skb->protocol == ETH_P_IP)) { - skb->csum = chksum; + skb->protocol = tr_type_trans(skb, dev); + if (IPv4_p) { + skb->csum = chksum; skb->ip_summed = 1; } netif_rx(skb); dev->last_rx = jiffies; +} /*tr_rx */ + +/*****************************************************************************/ + +void ibmtr_reset_timer(struct timer_list *tmr, struct net_device *dev) +{ + tmr->expires = jiffies + TR_RETRY_INTERVAL; + tmr->data = (unsigned long) dev; + tmr->function = tok_rerun; + init_timer(tmr); + add_timer(tmr); } -static int tok_send_packet(struct sk_buff *skb, struct net_device *dev) +/*****************************************************************************/ + +void tok_rerun(unsigned long dev_addr){ + + struct net_device *dev = (struct net_device *)dev_addr; + struct tok_info *ti = (struct tok_info *) dev->priv; + + if ( ti->open_action == RESTART){ + ti->do_tok_int = FIRST_INT; + outb(0, dev->base_addr + ADAPTRESETREL); +#ifdef ENABLE_PAGING + if (ti->page_mask) + writeb(SRPR_ENABLE_PAGING, + ti->mmio + ACA_OFFSET + ACA_RW + SRPR_EVEN); +#endif + + writeb(INT_ENABLE, ti->mmio + ACA_OFFSET + ACA_SET + ISRP_EVEN); + } else + tok_open_adapter(dev_addr); +} + +/*****************************************************************************/ + +void ibmtr_readlog(struct net_device *dev) { struct tok_info *ti; - unsigned long flags; - ti=(struct tok_info *) dev->priv; - netif_stop_queue(dev); - - /* lock against other CPUs */ - spin_lock_irqsave(&(ti->lock), flags); + ti = (struct tok_info *) dev->priv; - /* Save skb; we'll need it when the adapter asks for the data */ - ti->current_skb=skb; + ti->readlog_pending = 0; SET_PAGE(ti->srb_page); - isa_writeb(XMIT_UI_FRAME, ti->srb + offsetof(struct srb_xmit, command)); - isa_writew(ti->exsap_station_id, ti->srb - +offsetof(struct srb_xmit, station_id)); - isa_writeb(CMD_IN_SRB, (ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD)); - spin_unlock_irqrestore(&(ti->lock), flags); - dev->trans_start=jiffies; - return 0; -} + writeb(DIR_READ_LOG, ti->srb); + writeb(INT_ENABLE, ti->mmio + ACA_OFFSET + ACA_SET + ISRP_EVEN); + writeb(CMD_IN_SRB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD); -void ibmtr_reset_timer(struct timer_list *tmr, struct net_device *dev) { - tmr->expires = jiffies + TR_RETRY_INTERVAL; - tmr->data = (unsigned long) dev; - tmr->function = tok_open_adapter; - init_timer(tmr); - add_timer(tmr); -} + netif_stop_queue(dev); -void ibmtr_readlog(struct net_device *dev) { - struct tok_info *ti; - ti=(struct tok_info *) dev->priv; - - ti->readlog_pending = 0; - SET_PAGE(ti->srb_page); - isa_writeb(DIR_READ_LOG, ti->srb); - isa_writeb(INT_ENABLE, ti->mmio + ACA_OFFSET + ACA_SET + ISRP_EVEN); - isa_writeb(CMD_IN_SRB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD); - - netif_stop_queue(dev); } +/*****************************************************************************/ + /* tok_get_stats(): Basically a scaffold routine which will return the address of the tr_statistics structure associated with this device -- the tr.... structure is an ethnet look-alike so at least for this iteration may suffice. */ -static struct net_device_stats * tok_get_stats(struct net_device *dev) { +static struct net_device_stats *tok_get_stats(struct net_device *dev) +{ struct tok_info *toki; - toki=(struct tok_info *) dev->priv; + toki = (struct tok_info *) dev->priv; return (struct net_device_stats *) &toki->tr_stats; } -int ibmtr_change_mtu(struct net_device *dev, int mtu) { +/*****************************************************************************/ + +int ibmtr_change_mtu(struct net_device *dev, int mtu) +{ struct tok_info *ti = (struct tok_info *) dev->priv; - + if (ti->ring_speed == 16 && mtu > ti->maxmtu16) return -EINVAL; if (ti->ring_speed == 4 && mtu > ti->maxmtu4) @@ -1860,12 +1894,12 @@ return 0; } -#ifndef PCMCIA +/*****************************************************************************/ #ifdef MODULE /* 3COM 3C619C supports 8 interrupts, 32 I/O ports */ -static struct net_device* dev_ibmtr[IBMTR_MAX_ADAPTERS]; -static int io[IBMTR_MAX_ADAPTERS] = {0xa20,0xa24}; +static struct net_device *dev_ibmtr[IBMTR_MAX_ADAPTERS]; +static int io[IBMTR_MAX_ADAPTERS] = { 0xa20, 0xa24 }; static int irq[IBMTR_MAX_ADAPTERS]; static int mem[IBMTR_MAX_ADAPTERS]; @@ -1875,50 +1909,61 @@ int init_module(void) { - int i; - for (i = 0; io[i] && (i<IBMTR_MAX_ADAPTERS); i++) { - irq[i] = 0; + int i; + int count=0; + + find_turbo_adapters(io); + for (i = 0; io[i] && (i < IBMTR_MAX_ADAPTERS); i++) { + irq[i] = 0; mem[i] = 0; dev_ibmtr[i] = NULL; - dev_ibmtr[i] = init_trdev(dev_ibmtr[i], 0); - if (dev_ibmtr[i] == NULL) { - if (i == 0) - return -ENOMEM; - break; + dev_ibmtr[i] = init_trdev(dev_ibmtr[i], 0); + if (dev_ibmtr[i] == NULL) { + if (i==0) + return -ENOMEM; + break ; } - - dev_ibmtr[i]->base_addr = io[i]; - dev_ibmtr[i]->irq = irq[i]; + dev_ibmtr[i]->base_addr = io[i]; + dev_ibmtr[i]->irq = irq[i]; dev_ibmtr[i]->mem_start = mem[i]; - dev_ibmtr[i]->init = &ibmtr_probe; - - if (register_trdev(dev_ibmtr[i]) != 0) { + dev_ibmtr[i]->init = &ibmtr_probe; + if (register_trdev(dev_ibmtr[i]) != 0) { kfree(dev_ibmtr[i]); dev_ibmtr[i] = NULL; - if (i == 0) { - printk("ibmtr: register_trdev() returned non-zero.\n"); - return -EIO; - } else { - return 0; - } - } + continue; + } + count++; } - return 0; -} + if (count) return 0; + printk("ibmtr: register_trdev() returned non-zero.\n"); + return -EIO; +} /*init_module */ void cleanup_module(void) { - int i; + int i,j; - for (i = 0; i < IBMTR_MAX_ADAPTERS; i++) - if (dev_ibmtr[i]) { - unregister_trdev(dev_ibmtr[i]); - free_irq(dev_ibmtr[i]->irq, dev_ibmtr[i]); - release_region(dev_ibmtr[i]->base_addr, IBMTR_IO_EXTENT); - kfree(dev_ibmtr[i]->priv); - kfree(dev_ibmtr[i]); - dev_ibmtr[i] = NULL; + for (i = 0; i < IBMTR_MAX_ADAPTERS; i++){ + if(!dev_ibmtr[i]) continue; + if (dev_ibmtr[i]->base_addr) { + outb(0,dev_ibmtr[i]->base_addr+ADAPTRESET); + for(j=jiffies+TR_RST_TIME; + time_before_eq(jiffies,j);) ; + outb(0,dev_ibmtr[i]->base_addr+ADAPTRESETREL); } + unregister_trdev(dev_ibmtr[i]); + free_irq(dev_ibmtr[i]->irq, dev_ibmtr[i]); + release_region(dev_ibmtr[i]->base_addr, IBMTR_IO_EXTENT); +#ifndef PCMCIA + { + struct tok_info *ti = (struct tok_info *)dev_ibmtr[i]->priv ; + iounmap((u32 *)ti->mmio) ; + iounmap((u32 *)ti->sram_virt) ; + } +#endif + kfree(dev_ibmtr[i]->priv); + kfree(dev_ibmtr[i]); + dev_ibmtr[i] = NULL; + } } -#endif /* MODULE */ -#endif +#endif /* MODULE */ diff -u --recursive --new-file v2.4.6/linux/drivers/net/tulip/21142.c linux/drivers/net/tulip/21142.c --- v2.4.6/linux/drivers/net/tulip/21142.c Tue Jul 3 17:08:20 2001 +++ linux/drivers/net/tulip/21142.c Tue Jul 17 18:53:55 2001 @@ -195,7 +195,7 @@ } } if ( ! setup_done) { - tp->csr6 = dev->if_port & 1 ? 0x83860000 : 0x82420000; + tp->csr6 = (dev->if_port & 1 ? 0x838E0000 : 0x82420000) | (tp->csr6 & 0x20ff); if (tp->full_duplex) tp->csr6 |= 0x0200; outl(1, ioaddr + CSR13); @@ -230,7 +230,8 @@ t21142_start_nway(dev); tp->timer.expires = RUN_AT(3*HZ); add_timer(&tp->timer); - } + } else if (dev->if_port == 5) + outl(inl(ioaddr + CSR14) & ~0x080, ioaddr + CSR14); } else if (dev->if_port == 0 || dev->if_port == 4) { if ((csr12 & 4) == 0) printk(KERN_INFO"%s: 21143 10baseT link beat good.\n", @@ -249,7 +250,7 @@ printk(KERN_INFO"%s: 21143 100baseTx sensed media.\n", dev->name); dev->if_port = 3; - tp->csr6 = 0x83860000; + tp->csr6 = 0x838E0000 | (tp->csr6 & 0x20ff); outl(0x0003FF7F, ioaddr + CSR14); outl(0x0301, ioaddr + CSR12); tulip_restart_rxtx(tp); diff -u --recursive --new-file v2.4.6/linux/drivers/net/tulip/ChangeLog linux/drivers/net/tulip/ChangeLog --- v2.4.6/linux/drivers/net/tulip/ChangeLog Tue Jul 3 17:08:20 2001 +++ linux/drivers/net/tulip/ChangeLog Tue Jul 17 18:53:55 2001 @@ -1,3 +1,35 @@ +2001-07-17 Erik A. Hendriks <hendriks@lanl.gov> + + * 21142.c: Merge fix from tulip.c 0.92w which prevents the + overwriting of csr6 bits we want to preserve. + +2001-07-10 Jeff Golds <jgolds@resilience.com> + + * tulip_core.c: Fix two comments + +2001-07-06 Stephen Degler <sdegler@degler.net> + + * media.c: + The media selection process at the end of NWAY is busted + because for the case of MII/SYM it needs to be: + + csr13 <- 0 + csr14 <- 0 + csr6 <- the value calculated is okay. + + In the other media cases csr14 is computed by + t21142_csr14val[dev->if_port], which seems ok. The value of + zero as opposed to 3FFFFF comes straight from appendix D of the + 21143 data book, and it makes logical sense because you're + bypassing all the SIA interface when you usa MII or SYM (see + figure 1-1 in the data book if your're visually oriented) + +2001-07-03 Jeff Golds <jgolds@resilience.com> + + * tulip_core.c (tulip_clean_tx_ring): + Clear status for in-progress Tx's, and count + Tx errors for all packets being released. + 2001-06-16 Jeff Garzik <jgarzik@mandrakesoft.com> * tulip.h, tulip_core.c: diff -u --recursive --new-file v2.4.6/linux/drivers/net/tulip/media.c linux/drivers/net/tulip/media.c --- v2.4.6/linux/drivers/net/tulip/media.c Tue Jul 3 17:08:20 2001 +++ linux/drivers/net/tulip/media.c Tue Jul 17 18:53:55 2001 @@ -232,7 +232,7 @@ outl(csr13val, ioaddr + CSR13); } else { csr13val = 1; - csr14val = 0x0003FFFF; + csr14val = 0; csr15dir = (setup[0]<<16) | 0x0008; csr15val = (setup[1]<<16) | 0x0008; if (dev->if_port <= 4) diff -u --recursive --new-file v2.4.6/linux/drivers/net/tulip/tulip_core.c linux/drivers/net/tulip/tulip_core.c --- v2.4.6/linux/drivers/net/tulip/tulip_core.c Tue Jul 3 17:08:20 2001 +++ linux/drivers/net/tulip/tulip_core.c Tue Jul 17 18:53:55 2001 @@ -742,7 +742,7 @@ return 0; } -static void tulip_release_unconsumed_tx_buffers(struct tulip_private *tp) +static void tulip_clean_tx_ring(struct tulip_private *tp) { unsigned int dirty_tx; @@ -751,10 +751,12 @@ int entry = dirty_tx % TX_RING_SIZE; int status = le32_to_cpu(tp->tx_ring[entry].status); - if (status > 0) - break; /* It has been Txed */ + if (status < 0) { + tp->stats.tx_errors++; /* It wasn't Txed */ + tp->tx_ring[entry].status = 0; + } - /* Check for Rx filter setup frames. */ + /* Check for Tx filter setup frames. */ if (tp->tx_buffers[entry].skb == NULL) { /* test because dummy frames not mapped */ if (tp->tx_buffers[entry].mapping) @@ -764,7 +766,6 @@ PCI_DMA_TODEVICE); continue; } - tp->stats.tx_errors++; pci_unmap_single(tp->pdev, tp->tx_buffers[entry].mapping, tp->tx_buffers[entry].skb->len, @@ -797,7 +798,7 @@ tulip_refill_rx(dev); /* release any unconsumed transmit buffers */ - tulip_release_unconsumed_tx_buffers(tp); + tulip_clean_tx_ring(tp); /* 21040 -- Leave the card in 10baseT state. */ if (tp->chip_id == DC21040) @@ -1434,7 +1435,7 @@ ioaddr = pci_resource_start (pdev, 0); irq = pdev->irq; - /* init_etherdev ensures aligned and zeroed private structures */ + /* alloc_etherdev ensures aligned and zeroed private structures */ dev = alloc_etherdev (sizeof (*tp)); if (!dev) { printk (KERN_ERR PFX "ether device alloc failed, aborting\n"); @@ -1467,7 +1468,7 @@ /* * initialize private data structure 'tp' - * it is zeroed and aligned in init_etherdev + * it is zeroed and aligned in alloc_etherdev */ tp = dev->priv; diff -u --recursive --new-file v2.4.6/linux/drivers/net/via-rhine.c linux/drivers/net/via-rhine.c --- v2.4.6/linux/drivers/net/via-rhine.c Tue Jul 3 17:08:20 2001 +++ linux/drivers/net/via-rhine.c Tue Jul 17 18:53:55 2001 @@ -64,6 +64,11 @@ (media selection + eeprom reload) - David Vrabel: merges from D-Link "1.11" version (disable WOL and PME on startup) + + LK1.1.10: + - Manfred Spraul: use "singlecopy" for unaligned buffers + don't allocate bounce buffers for !ReqTxAlign cards + */ @@ -118,7 +123,6 @@ /* max time out delay time */ #define W_MAX_TIMEOUT 0x0FFFU - #if !defined(__OPTIMIZE__) || !defined(__KERNEL__) #warning You must compile this file with the correct options! #warning See the last lines of the source file. @@ -147,7 +151,7 @@ /* These identify the driver base version and may not be removed. */ static char version[] __devinitdata = -KERN_INFO "via-rhine.c:v1.10-LK1.1.9 05/31/2001 Written by Donald Becker\n" +KERN_INFO "via-rhine.c:v1.10-LK1.1.10 07/12/2001 Written by Donald Becker\n" KERN_INFO " http://www.scyld.com/network/via-rhine.html\n"; static char shortname[] __devinitdata = "via-rhine"; @@ -641,6 +645,8 @@ dev->do_ioctl = mii_ioctl; dev->tx_timeout = via_rhine_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; + if (np->drv_flags & ReqTxAlign) + dev->features |= NETIF_F_SG|NETIF_F_HW_CSUM; i = register_netdev(dev); if (i) @@ -723,14 +729,16 @@ printk(KERN_ERR "Could not allocate DMA memory.\n"); return -ENOMEM; } - np->tx_bufs = pci_alloc_consistent(np->pdev, PKT_BUF_SZ * TX_RING_SIZE, + if (np->drv_flags & ReqTxAlign) { + np->tx_bufs = pci_alloc_consistent(np->pdev, PKT_BUF_SZ * TX_RING_SIZE, &np->tx_bufs_dma); - if (np->tx_bufs == NULL) { - pci_free_consistent(np->pdev, - RX_RING_SIZE * sizeof(struct rx_desc) + - TX_RING_SIZE * sizeof(struct tx_desc), - ring, ring_dma); - return -ENOMEM; + if (np->tx_bufs == NULL) { + pci_free_consistent(np->pdev, + RX_RING_SIZE * sizeof(struct rx_desc) + + TX_RING_SIZE * sizeof(struct tx_desc), + ring, ring_dma); + return -ENOMEM; + } } np->rx_ring = ring; @@ -738,7 +746,6 @@ np->rx_ring_dma = ring_dma; np->tx_ring_dma = ring_dma + RX_RING_SIZE * sizeof(struct rx_desc); - return 0; } @@ -1100,17 +1107,23 @@ /* Caution: the write order is important here, set the field with the "ownership" bits last. */ - /* lock eth irq */ - spin_lock_irq (&np->lock); - /* Calculate the next Tx descriptor entry. */ entry = np->cur_tx % TX_RING_SIZE; np->tx_skbuff[entry] = skb; - if ((np->drv_flags & ReqTxAlign) && ((long)skb->data & 3)) { + if ((np->drv_flags & ReqTxAlign) && + (((long)skb->data & 3) || skb_shinfo(skb)->nr_frags != 0 || skb->ip_summed == CHECKSUM_HW) + ) { /* Must use alignment buffer. */ - memcpy(np->tx_buf[entry], skb->data, skb->len); + if (skb->len > PKT_BUF_SZ) { + /* packet too long, drop it */ + dev_kfree_skb(skb); + np->tx_skbuff[entry] = NULL; + np->stats.tx_dropped++; + return 0; + } + skb_copy_and_csum_dev(skb, np->tx_buf[entry]); np->tx_skbuff_dma[entry] = 0; np->tx_ring[entry].addr = cpu_to_le32(np->tx_bufs_dma + (np->tx_buf[entry] - np->tx_bufs)); @@ -1122,7 +1135,12 @@ np->tx_ring[entry].desc_length = cpu_to_le32(0x00E08000 | (skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN)); + + /* lock eth irq */ + spin_lock_irq (&np->lock); + wmb(); np->tx_ring[entry].tx_status = cpu_to_le32(DescOwn); + wmb(); np->cur_tx++; diff -u --recursive --new-file v2.4.6/linux/drivers/net/wan/Config.in linux/drivers/net/wan/Config.in --- v2.4.6/linux/drivers/net/wan/Config.in Thu Apr 12 12:11:39 2001 +++ linux/drivers/net/wan/Config.in Wed Jul 4 11:50:39 2001 @@ -49,7 +49,7 @@ dep_tristate ' Sealevel Systems 4021 support' CONFIG_SEALEVEL_4021 m - dep_tristate ' SyncLink HDLC/SYNCPPP support' CONFIG_SYNCLINK_SYNCPPP m + tristate ' SyncLink HDLC/SYNCPPP support' CONFIG_SYNCLINK_SYNCPPP tristate ' Generic HDLC driver' CONFIG_HDLC if [ "$CONFIG_HDLC" != "n" ]; then diff -u --recursive --new-file v2.4.6/linux/drivers/net/wan/sbni.c linux/drivers/net/wan/sbni.c --- v2.4.6/linux/drivers/net/wan/sbni.c Tue Mar 20 12:05:01 2001 +++ linux/drivers/net/wan/sbni.c Tue Jul 17 18:53:55 2001 @@ -22,7 +22,7 @@ * // - for bug hunting and many ideas * // Alan Cox (Alan.Cox@linux.org) * // - for consulting in some hardcore questions - * // Donald Becker (becker@cesdis.gsfc.nasa.gov) + * // Donald Becker (becker@scyld.com) * // - for pretty nice skeleton * * More info and useful utilities to work w/ SBNI you can find at diff -u --recursive --new-file v2.4.6/linux/drivers/net/wavelan.c linux/drivers/net/wavelan.c --- v2.4.6/linux/drivers/net/wavelan.c Wed Apr 25 14:36:23 2001 +++ linux/drivers/net/wavelan.c Tue Jul 17 18:53:55 2001 @@ -4302,7 +4302,7 @@ * It is based on other device drivers and information * either written or supplied by: * Ajay Bakre (bakre@paul.rutgers.edu), - * Donald Becker (becker@cesdis.gsfc.nasa.gov), + * Donald Becker (becker@scyld.com), * Loeke Brederveld (Loeke.Brederveld@Utrecht.NCR.com), * Anders Klemets (klemets@it.kth.se), * Vladimir V. Kolpakov (w@stier.koenig.ru), diff -u --recursive --new-file v2.4.6/linux/drivers/net/wd.c linux/drivers/net/wd.c --- v2.4.6/linux/drivers/net/wd.c Tue Jul 3 17:08:20 2001 +++ linux/drivers/net/wd.c Tue Jul 17 18:53:55 2001 @@ -8,9 +8,10 @@ This software may be used and distributed according to the terms of the GNU General Public License, incorporated herein by reference. - The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O - Center of Excellence in Space Data and Information Sciences - Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771 + The author may be reached as becker@scyld.com, or C/O + Scyld Computing Corporation + 410 Severn Ave., Suite 210 + Annapolis MD 21403 This is a driver for WD8003 and WD8013 "compatible" ethercards. diff -u --recursive --new-file v2.4.6/linux/drivers/net/winbond-840.c linux/drivers/net/winbond-840.c --- v2.4.6/linux/drivers/net/winbond-840.c Tue Jul 3 17:08:20 2001 +++ linux/drivers/net/winbond-840.c Tue Jul 17 18:53:55 2001 @@ -32,15 +32,19 @@ synchronize tx_q_bytes software reset in tx_timeout Copyright (C) 2000 Manfred Spraul - + * further cleanups + power management. + support for big endian descriptors + Copyright (C) 2001 Manfred Spraul + TODO: - * according to the documentation, the chip supports big endian - descriptors. Remove cpu_to_le32, enable BE descriptors. + * enable pci_power_off + * Wake-On-LAN */ - + #define DRV_NAME "winbond-840" -#define DRV_VERSION "1.01" -#define DRV_RELDATE "5/15/2000" +#define DRV_VERSION "1.01-c" +#define DRV_RELDATE "6/30/2000" /* Automatically extracted configuration info: @@ -86,8 +90,11 @@ There are no ill effects from too-large receive rings. */ #define TX_RING_SIZE 16 #define TX_QUEUE_LEN 10 /* Limit ring entries actually used. */ +#define TX_QUEUE_LEN_RESTART 5 #define RX_RING_SIZE 32 +#define TX_BUFLIMIT (1024-128) + /* The presumed FIFO size for working around the Tx-FIFO-overflow bug. To avoid overflowing we don't queue again until we have room for a full-size packet. @@ -95,7 +102,6 @@ #define TX_FIFO_SIZE (2048) #define TX_BUG_FIFO_LIMIT (TX_FIFO_SIZE-1514-16) -#define TX_BUFLIMIT (1024-128) /* Operational parameters that usually are not changed. */ /* Time in jiffies before concluding the transmitter is hung. */ @@ -129,10 +135,12 @@ #include <linux/delay.h> #include <linux/ethtool.h> #include <linux/mii.h> +#include <linux/rtnetlink.h> #include <asm/uaccess.h> #include <asm/processor.h> /* Processor type for cache alignment. */ #include <asm/bitops.h> #include <asm/io.h> +#include <asm/irq.h> /* These identify the driver base version and may not be removed. */ static char version[] __devinitdata = @@ -197,6 +205,8 @@ correctly detect a full FIFO, and queuing more than 2048 bytes may result in silent data corruption. +Test with 'ping -s 10000' on a fast computer. + */ @@ -316,7 +326,7 @@ struct w840_tx_desc { s32 status; s32 length; - u32 buffer1, buffer2; /* We use only buffer 1. */ + u32 buffer1, buffer2; }; /* Bits in network_desc.status */ @@ -349,35 +359,36 @@ unsigned int cur_rx, dirty_rx; /* Producer/consumer ring indices */ unsigned int rx_buf_sz; /* Based on MTU+slack. */ unsigned int cur_tx, dirty_tx; - int tx_q_bytes; - unsigned int tx_full:1; /* The Tx queue is full. */ + unsigned int tx_q_bytes; + unsigned int tx_full; /* The Tx queue is full. */ /* These values are keep track of the transceiver/media in use. */ unsigned int full_duplex:1; /* Full-duplex operation requested. */ unsigned int duplex_lock:1; - unsigned int medialock:1; /* Do not sense media. */ - unsigned int default_port:4; /* Last dev->if_port value. */ /* MII transceiver section. */ int mii_cnt; /* MII device addresses. */ u16 advertising; /* NWay media advertisement */ unsigned char phys[MII_CNT]; /* MII device addresses, but only the first is used */ + u32 mii; }; static int eeprom_read(long ioaddr, int location); static int mdio_read(struct net_device *dev, int phy_id, int location); static void mdio_write(struct net_device *dev, int phy_id, int location, int value); static int netdev_open(struct net_device *dev); -static void check_duplex(struct net_device *dev); +static int update_link(struct net_device *dev); static void netdev_timer(unsigned long data); static void init_rxtx_rings(struct net_device *dev); static void free_rxtx_rings(struct netdev_private *np); static void init_registers(struct net_device *dev); static void tx_timeout(struct net_device *dev); -static int alloc_ring(struct net_device *dev); +static int alloc_ringdesc(struct net_device *dev); +static void free_ringdesc(struct netdev_private *np); static int start_tx(struct sk_buff *skb, struct net_device *dev); static void intr_handler(int irq, void *dev_instance, struct pt_regs *regs); static void netdev_error(struct net_device *dev, int intr_status); static int netdev_rx(struct net_device *dev); static inline unsigned ether_crc(int length, unsigned char *data); +static u32 __set_rx_mode(struct net_device *dev); static void set_rx_mode(struct net_device *dev); static struct net_device_stats *get_stats(struct net_device *dev); static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); @@ -425,7 +436,6 @@ goto err_out_free_res; #endif - /* Warning: broken for big-endian machines. */ for (i = 0; i < 3; i++) ((u16 *)dev->dev_addr)[i] = le16_to_cpu(eeprom_read(ioaddr, i)); @@ -451,9 +461,9 @@ if (option > 0) { if (option & 0x200) np->full_duplex = 1; - np->default_port = option & 15; - if (np->default_port) - np->medialock = 1; + if (option & 15) + printk(KERN_INFO "%s: ignoring user supplied media type %d", + dev->name, option & 15); } if (find_cnt < MAX_UNITS && full_duplex[find_cnt] > 0) np->full_duplex = 1; @@ -488,9 +498,11 @@ if (mii_status != 0xffff && mii_status != 0x0000) { np->phys[phy_idx++] = phy; np->advertising = mdio_read(dev, phy, 4); - printk(KERN_INFO "%s: MII PHY found at address %d, status " + np->mii = (mdio_read(dev, phy, 2) << 16)+ + mdio_read(dev, phy, 3); + printk(KERN_INFO "%s: MII PHY %8.8xh found at address %d, status " "0x%4.4x advertising %4.4x.\n", - dev->name, phy, mii_status, np->advertising); + dev->name, np->mii, phy, mii_status, np->advertising); } } np->mii_cnt = phy_idx; @@ -673,18 +685,22 @@ writel(0x00000001, ioaddr + PCIBusCfg); /* Reset */ + netif_device_detach(dev); i = request_irq(dev->irq, &intr_handler, SA_SHIRQ, dev->name, dev); if (i) - return i; + goto out_err; if (debug > 1) printk(KERN_DEBUG "%s: w89c840_open() irq %d.\n", dev->name, dev->irq); - if((i=alloc_ring(dev))) - return i; + if((i=alloc_ringdesc(dev))) + goto out_err; + spin_lock_irq(&np->lock); + netif_device_attach(dev); init_registers(dev); + spin_unlock_irq(&np->lock); netif_start_queue(dev); if (debug > 2) @@ -692,33 +708,119 @@ /* Set the timer to check for link beat. */ init_timer(&np->timer); - np->timer.expires = jiffies + 3*HZ; + np->timer.expires = jiffies + 1*HZ; np->timer.data = (unsigned long)dev; np->timer.function = &netdev_timer; /* timer handler */ add_timer(&np->timer); - return 0; +out_err: + netif_device_attach(dev); + return i; } -static void check_duplex(struct net_device *dev) +#define MII_DAVICOM_DM9101 0x0181b800 + +static int update_link(struct net_device *dev) { struct netdev_private *np = dev->priv; - int mii_reg5 = mdio_read(dev, np->phys[0], 5); - int negotiated = mii_reg5 & np->advertising; - int duplex; + int duplex, fasteth, result, mii_reg; - if (np->duplex_lock || mii_reg5 == 0xffff) - return; - duplex = (negotiated & 0x0100) || (negotiated & 0x01C0) == 0x0040; - if (np->full_duplex != duplex) { - np->full_duplex = duplex; + /* BSMR */ + mii_reg = mdio_read(dev, np->phys[0], 1); + + if (mii_reg == 0xffff) + return np->csr6; + /* reread: the link status bit is sticky */ + mii_reg = mdio_read(dev, np->phys[0], 1); + if (!(mii_reg & 0x4)) { + if (netif_carrier_ok(dev)) { + if (debug) + printk(KERN_INFO "%s: MII #%d reports no link. Disabling watchdog.\n", + dev->name, np->phys[0]); + netif_carrier_off(dev); + } + return np->csr6; + } + if (!netif_carrier_ok(dev)) { if (debug) - printk(KERN_INFO "%s: Setting %s-duplex based on MII #%d " - "negotiated capability %4.4x.\n", dev->name, - duplex ? "full" : "half", np->phys[0], negotiated); - np->csr6 &= ~0x200; - np->csr6 |= duplex ? 0x200 : 0; + printk(KERN_INFO "%s: MII #%d link is back. Enabling watchdog.\n", + dev->name, np->phys[0]); + netif_carrier_on(dev); } + + if ((np->mii & ~0xf) == MII_DAVICOM_DM9101) { + /* If the link partner doesn't support autonegotiation + * the MII detects it's abilities with the "parallel detection". + * Some MIIs update the LPA register to the result of the parallel + * detection, some don't. + * The Davicom PHY [at least 0181b800] doesn't. + * Instead bit 9 and 13 of the BMCR are updated to the result + * of the negotiation.. + */ + mii_reg = mdio_read(dev, np->phys[0], 0); + duplex = mii_reg & 0x100; + fasteth = mii_reg & 0x2000; + } else { + int negotiated; + mii_reg = mdio_read(dev, np->phys[0], 5); + negotiated = mii_reg & np->advertising; + + duplex = (negotiated & 0x0100) || ((negotiated & 0x02C0) == 0x0040); + fasteth = negotiated & 0x380; + } + duplex |= np->duplex_lock; + /* remove fastether and fullduplex */ + result = np->csr6 & ~0x20000200; + if (duplex) + result |= 0x200; + if (fasteth) + result |= 0x20000000; + if (result != np->csr6 && debug) + printk(KERN_INFO "%s: Setting %dMBit-%s-duplex based on MII#%d\n", + dev->name, fasteth ? 100 : 10, + duplex ? "full" : "half", np->phys[0]); + return result; +} + +#define RXTX_TIMEOUT 2000 +static inline void update_csr6(struct net_device *dev, int new) +{ + struct netdev_private *np = dev->priv; + long ioaddr = dev->base_addr; + int limit = RXTX_TIMEOUT; + + if (!netif_device_present(dev)) + new = 0; + if (new==np->csr6) + return; + /* stop both Tx and Rx processes */ + writel(np->csr6 & ~0x2002, ioaddr + NetworkConfig); + /* wait until they have really stopped */ + for (;;) { + int csr5 = readl(ioaddr + IntrStatus); + int t; + + t = (csr5 >> 17) & 0x07; + if (t==0||t==1) { + /* rx stopped */ + t = (csr5 >> 20) & 0x07; + if (t==0||t==1) + break; + } + + limit--; + if(!limit) { + printk(KERN_INFO "%s: couldn't stop rxtx, IntrStatus %xh.\n", + dev->name, csr5); + break; + } + udelay(1); + } + np->csr6 = new; + /* and restart them with the new configuration */ + writel(np->csr6, ioaddr + NetworkConfig); + if (new & 0x200) + np->full_duplex = 1; } static void netdev_timer(unsigned long data) @@ -726,8 +828,6 @@ struct net_device *dev = (struct net_device *)data; struct netdev_private *np = dev->priv; long ioaddr = dev->base_addr; - int next_tick = 10*HZ; - int old_csr6 = np->csr6; if (debug > 2) printk(KERN_DEBUG "%s: Media selection timer tick, status %8.8x " @@ -735,13 +835,9 @@ dev->name, (int)readl(ioaddr + IntrStatus), (int)readl(ioaddr + NetworkConfig)); spin_lock_irq(&np->lock); - check_duplex(dev); - if (np->csr6 != old_csr6) { - writel(np->csr6 & ~0x0002, ioaddr + NetworkConfig); - writel(np->csr6 | 0x2002, ioaddr + NetworkConfig); - } + update_csr6(dev, update_link(dev)); spin_unlock_irq(&np->lock); - np->timer.expires = jiffies + next_tick; + np->timer.expires = jiffies + 10*HZ; add_timer(&np->timer); } @@ -755,12 +851,12 @@ /* Initial all Rx descriptors. */ for (i = 0; i < RX_RING_SIZE; i++) { - np->rx_ring[i].length = cpu_to_le32(np->rx_buf_sz); + np->rx_ring[i].length = np->rx_buf_sz; np->rx_ring[i].status = 0; np->rx_skbuff[i] = 0; } /* Mark the last entry as wrapping the ring. */ - np->rx_ring[i-1].length |= cpu_to_le32(DescEndRing); + np->rx_ring[i-1].length |= DescEndRing; /* Fill in the Rx buffers. Handle allocation failure gracefully. */ for (i = 0; i < RX_RING_SIZE; i++) { @@ -772,8 +868,8 @@ np->rx_addr[i] = pci_map_single(np->pci_dev,skb->tail, skb->len,PCI_DMA_FROMDEVICE); - np->rx_ring[i].buffer1 = cpu_to_le32(np->rx_addr[i]); - np->rx_ring[i].status = cpu_to_le32(DescOwn); + np->rx_ring[i].buffer1 = np->rx_addr[i]; + np->rx_ring[i].status = DescOwn; } np->cur_rx = 0; @@ -830,6 +926,14 @@ writeb(dev->dev_addr[i], ioaddr + StationAddr + i); /* Initialize other registers. */ +#ifdef __BIG_ENDIAN + i = (1<<20); /* Big-endian descriptors */ +#else + i = 0; +#endif + i |= (0x04<<2); /* skip length 4 u32 */ + i |= 0x02; /* give Rx priority */ + /* Configure the PCI bus bursts and FIFO thresholds. 486: Set 8 longword cache alignment, 8 longword burst. 586: Set 16 longword cache alignment, no burst limit. @@ -837,44 +941,37 @@ 0000 <not allowed> 0000 align to cache 0800 8 longwords 4000 8 longwords 0100 1 longword 1000 16 longwords 8000 16 longwords 0200 2 longwords 2000 32 longwords - C000 32 longwords 0400 4 longwords - Wait the specified 50 PCI cycles after a reset by initializing - Tx and Rx queues and the address filter list. */ -#if defined(__powerpc__) || defined(__sparc__) /* Big-endian */ - writel(0x00100080 | 0xE010, ioaddr + PCIBusCfg); -#elif defined(__alpha__) - writel(0xE010, ioaddr + PCIBusCfg); -#elif defined(__i386__) -#if defined(MODULE) - writel(0xE010, ioaddr + PCIBusCfg); -#else + C000 32 longwords 0400 4 longwords */ + +#if defined (__i386__) && !defined(MODULE) /* When not a module we can work around broken '486 PCI boards. */ -#define x86 boot_cpu_data.x86 - writel((x86 <= 4 ? 0x4810 : 0xE010), ioaddr + PCIBusCfg); - if (x86 <= 4) + if (boot_cpu_data.x86 <= 4) { + i |= 0x4800; printk(KERN_INFO "%s: This is a 386/486 PCI system, setting cache " - "alignment to %x.\n", dev->name, - (x86 <= 4 ? 0x4810 : 0xE010)); -#endif + "alignment to 8 longwords.\n", dev->name); + } else { + i |= 0xE000; + } +#elif defined(__powerpc__) || defined(__i386__) || defined(__alpha) || defined(__ia64__) + i |= 0xE000; +#elif defined(__sparc__) + i |= 0x4800; #else - writel(0xE010, ioaddr + PCIBusCfg); -#warning Processor architecture undefined! +#warning Processor architecture undefined + i |= 0x4800; #endif + writel(i, ioaddr + PCIBusCfg); - if (dev->if_port == 0) - dev->if_port = np->default_port; - - /* Fast Ethernet; 128 byte Tx threshold; + np->csr6 = 0; + /* 128 byte Tx threshold; Transmit on; Receive on; */ - np->csr6 = 0x20022002; - check_duplex(dev); - set_rx_mode(dev); - writel(0, ioaddr + RxStartDemand); + update_csr6(dev, 0x00022002 | update_link(dev) | __set_rx_mode(dev)); /* Clear and Enable interrupts by setting the interrupt mask. */ writel(0x1A0F5, ioaddr + IntrStatus); writel(0x1A0F5, ioaddr + IntrEnable); + writel(0, ioaddr + RxStartDemand); } static void tx_timeout(struct net_device *dev) @@ -896,9 +993,10 @@ printk("\n"); } printk(KERN_DEBUG "Tx cur %d Tx dirty %d Tx Full %d, q bytes %d.\n", - np->cur_tx, np->dirty_tx, np->tx_full,np->tx_q_bytes); + np->cur_tx, np->dirty_tx, np->tx_full, np->tx_q_bytes); printk(KERN_DEBUG "Tx Descriptor addr %xh.\n",readl(ioaddr+0x4C)); + disable_irq(dev->irq); spin_lock_irq(&np->lock); /* * Under high load dirty_tx and the internal tx descriptor pointer @@ -912,9 +1010,8 @@ free_rxtx_rings(np); init_rxtx_rings(dev); init_registers(dev); - set_rx_mode(dev); - spin_unlock_irq(&np->lock); + enable_irq(dev->irq); netif_wake_queue(dev); dev->trans_start = jiffies; @@ -923,7 +1020,7 @@ } /* Initialize the Rx and Tx rings, along with various 'dev' bits. */ -static int alloc_ring(struct net_device *dev) +static int alloc_ringdesc(struct net_device *dev) { struct netdev_private *np = dev->priv; @@ -939,12 +1036,19 @@ return 0; } +static void free_ringdesc(struct netdev_private *np) +{ + pci_free_consistent(np->pci_dev, + sizeof(struct w840_rx_desc)*RX_RING_SIZE + + sizeof(struct w840_tx_desc)*TX_RING_SIZE, + np->rx_ring, np->ring_dma_addr); + +} static int start_tx(struct sk_buff *skb, struct net_device *dev) { struct netdev_private *np = dev->priv; unsigned entry; - int len1, len2; /* Caution: the write order is important here, set the field with the "ownership" bits last. */ @@ -952,48 +1056,51 @@ /* Calculate the next Tx descriptor entry. */ entry = np->cur_tx % TX_RING_SIZE; - np->tx_skbuff[entry] = skb; np->tx_addr[entry] = pci_map_single(np->pci_dev, skb->data,skb->len, PCI_DMA_TODEVICE); - np->tx_ring[entry].buffer1 = cpu_to_le32(np->tx_addr[entry]); - len2 = 0; - len1 = skb->len; - if(len1 > TX_BUFLIMIT) { - len1 = TX_BUFLIMIT; - len2 = skb->len-len1; - np->tx_ring[entry].buffer2 = cpu_to_le32(np->tx_addr[entry]+TX_BUFLIMIT); - } - np->tx_ring[entry].length = cpu_to_le32(DescWholePkt | (len2 << 11) | len1); - if (entry >= TX_RING_SIZE-1) /* Wrap ring */ - np->tx_ring[entry].length |= cpu_to_le32(DescIntr | DescEndRing); - np->cur_tx++; + np->tx_skbuff[entry] = skb; + + np->tx_ring[entry].buffer1 = np->tx_addr[entry]; + if (skb->len < TX_BUFLIMIT) { + np->tx_ring[entry].length = DescWholePkt | skb->len; + } else { + int len = skb->len - TX_BUFLIMIT; + + np->tx_ring[entry].buffer2 = np->tx_addr[entry]+TX_BUFLIMIT; + np->tx_ring[entry].length = DescWholePkt | (len << 11) | TX_BUFLIMIT; + } + if(entry == TX_RING_SIZE-1) + np->tx_ring[entry].length |= DescEndRing; - /* The spinlock protects against 2 races: - * - tx_q_bytes is updated by this function and intr_handler - * - our hardware is extremely fast and finishes the packet between - * our check for "queue full" and netif_stop_queue. - * Thus setting DescOwn and netif_stop_queue must be atomic. + /* Now acquire the irq spinlock. + * The difficult race is the the ordering between + * increasing np->cur_tx and setting DescOwn: + * - if np->cur_tx is increased first the interrupt + * handler could consider the packet as transmitted + * since DescOwn is cleared. + * - If DescOwn is set first the NIC could report the + * packet as sent, but the interrupt handler would ignore it + * since the np->cur_tx was not yet increased. */ spin_lock_irq(&np->lock); + np->cur_tx++; wmb(); /* flush length, buffer1, buffer2 */ - np->tx_ring[entry].status = cpu_to_le32(DescOwn); + np->tx_ring[entry].status = DescOwn; wmb(); /* flush status and kick the hardware */ writel(0, dev->base_addr + TxStartDemand); - np->tx_q_bytes += skb->len; /* Work around horrible bug in the chip by marking the queue as full when we do not have FIFO room for a maximum sized packet. */ - if (np->cur_tx - np->dirty_tx > TX_QUEUE_LEN) - np->tx_full = 1; - else if ((np->drv_flags & HasBrokenTx) - && np->tx_q_bytes > TX_BUG_FIFO_LIMIT) - np->tx_full = 1; - if (np->tx_full) + if (np->cur_tx - np->dirty_tx > TX_QUEUE_LEN || + ((np->drv_flags & HasBrokenTx) && np->tx_q_bytes > TX_BUG_FIFO_LIMIT)) { netif_stop_queue(dev); + wmb(); + np->tx_full = 1; + } + spin_unlock_irq(&np->lock); dev->trans_start = jiffies; - spin_unlock_irq(&np->lock); if (debug > 4) { printk(KERN_DEBUG "%s: Transmit frame #%d queued in slot %d.\n", @@ -1002,6 +1109,62 @@ return 0; } +static void netdev_tx_done(struct net_device *dev) +{ + struct netdev_private *np = dev->priv; + for (; np->cur_tx - np->dirty_tx > 0; np->dirty_tx++) { + int entry = np->dirty_tx % TX_RING_SIZE; + int tx_status = np->tx_ring[entry].status; + + if (tx_status < 0) + break; + if (tx_status & 0x8000) { /* There was an error, log it. */ +#ifndef final_version + if (debug > 1) + printk(KERN_DEBUG "%s: Transmit error, Tx status %8.8x.\n", + dev->name, tx_status); +#endif + np->stats.tx_errors++; + if (tx_status & 0x0104) np->stats.tx_aborted_errors++; + if (tx_status & 0x0C80) np->stats.tx_carrier_errors++; + if (tx_status & 0x0200) np->stats.tx_window_errors++; + if (tx_status & 0x0002) np->stats.tx_fifo_errors++; + if ((tx_status & 0x0080) && np->full_duplex == 0) + np->stats.tx_heartbeat_errors++; +#ifdef ETHER_STATS + if (tx_status & 0x0100) np->stats.collisions16++; +#endif + } else { +#ifdef ETHER_STATS + if (tx_status & 0x0001) np->stats.tx_deferred++; +#endif +#ifndef final_version + if (debug > 3) + printk(KERN_DEBUG "%s: Transmit slot %d ok, Tx status %8.8x.\n", + dev->name, entry, tx_status); +#endif + np->stats.tx_bytes += np->tx_skbuff[entry]->len; + np->stats.collisions += (tx_status >> 3) & 15; + np->stats.tx_packets++; + } + /* Free the original skb. */ + pci_unmap_single(np->pci_dev,np->tx_addr[entry], + np->tx_skbuff[entry]->len, + PCI_DMA_TODEVICE); + np->tx_q_bytes -= np->tx_skbuff[entry]->len; + dev_kfree_skb_irq(np->tx_skbuff[entry]); + np->tx_skbuff[entry] = 0; + } + if (np->tx_full && + np->cur_tx - np->dirty_tx < TX_QUEUE_LEN_RESTART && + np->tx_q_bytes < TX_BUG_FIFO_LIMIT) { + /* The ring is no longer full, clear tbusy. */ + np->tx_full = 0; + wmb(); + netif_wake_queue(dev); + } +} + /* The interrupt handler does all of the Rx thread work and cleans up after the Tx thread. */ static void intr_handler(int irq, void *dev_instance, struct pt_regs *rgs) @@ -1011,8 +1174,8 @@ long ioaddr = dev->base_addr; int work_limit = max_interrupt_work; - spin_lock(&np->lock); - + if (!netif_device_present(dev)) + return; do { u32 intr_status = readl(ioaddr + IntrStatus); @@ -1028,51 +1191,14 @@ if (intr_status & (IntrRxDone | RxNoBuf)) netdev_rx(dev); + if (intr_status & RxNoBuf) + writel(0, ioaddr + RxStartDemand); - for (; np->cur_tx - np->dirty_tx > 0; np->dirty_tx++) { - int entry = np->dirty_tx % TX_RING_SIZE; - int tx_status = le32_to_cpu(np->tx_ring[entry].status); - - if (tx_status < 0) - break; - if (tx_status & 0x8000) { /* There was an error, log it. */ -#ifndef final_version - if (debug > 1) - printk(KERN_DEBUG "%s: Transmit error, Tx status %8.8x.\n", - dev->name, tx_status); -#endif - np->stats.tx_errors++; - if (tx_status & 0x0104) np->stats.tx_aborted_errors++; - if (tx_status & 0x0C80) np->stats.tx_carrier_errors++; - if (tx_status & 0x0200) np->stats.tx_window_errors++; - if (tx_status & 0x0002) np->stats.tx_fifo_errors++; - if ((tx_status & 0x0080) && np->full_duplex == 0) - np->stats.tx_heartbeat_errors++; -#ifdef ETHER_STATS - if (tx_status & 0x0100) np->stats.collisions16++; -#endif - } else { -#ifdef ETHER_STATS - if (tx_status & 0x0001) np->stats.tx_deferred++; -#endif - np->stats.tx_bytes += np->tx_skbuff[entry]->len; - np->stats.collisions += (tx_status >> 3) & 15; - np->stats.tx_packets++; - } - /* Free the original skb. */ - pci_unmap_single(np->pci_dev,np->tx_addr[entry], - np->tx_skbuff[entry]->len, - PCI_DMA_TODEVICE); - np->tx_q_bytes -= np->tx_skbuff[entry]->len; - dev_kfree_skb_irq(np->tx_skbuff[entry]); - np->tx_skbuff[entry] = 0; - } - if (np->tx_full && - np->cur_tx - np->dirty_tx < TX_QUEUE_LEN - 4 - && np->tx_q_bytes < TX_BUG_FIFO_LIMIT) { - /* The ring is no longer full, clear tbusy. */ - np->tx_full = 0; - netif_wake_queue(dev); + if (intr_status & (TxIdle | IntrTxDone) && + np->cur_tx != np->dirty_tx) { + spin_lock(&np->lock); + netdev_tx_done(dev); + spin_unlock(&np->lock); } /* Abnormal error summary/uncommon events handlers. */ @@ -1085,8 +1211,12 @@ "status=0x%4.4x.\n", dev->name, intr_status); /* Set the timer to re-enable the other interrupts after 10*82usec ticks. */ - writel(AbnormalIntr | TimerInt, ioaddr + IntrEnable); - writel(10, ioaddr + GPTimer); + spin_lock(&np->lock); + if (netif_device_present(dev)) { + writel(AbnormalIntr | TimerInt, ioaddr + IntrEnable); + writel(10, ioaddr + GPTimer); + } + spin_unlock(&np->lock); break; } } while (1); @@ -1094,8 +1224,6 @@ if (debug > 3) printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x.\n", dev->name, (int)readl(ioaddr + IntrStatus)); - - spin_unlock(&np->lock); } /* This routine is logically part of the interrupt handler, but separated @@ -1114,7 +1242,7 @@ /* If EOP is set on the next entry, it's a new packet. Send it up. */ while (--work_limit >= 0) { struct w840_rx_desc *desc = np->rx_head_desc; - s32 status = le32_to_cpu(desc->status); + s32 status = desc->status; if (debug > 4) printk(KERN_DEBUG " netdev_rx() status was %8.8x.\n", @@ -1210,10 +1338,10 @@ np->rx_addr[entry] = pci_map_single(np->pci_dev, skb->tail, skb->len, PCI_DMA_FROMDEVICE); - np->rx_ring[entry].buffer1 = cpu_to_le32(np->rx_addr[entry]); + np->rx_ring[entry].buffer1 = np->rx_addr[entry]; } wmb(); - np->rx_ring[entry].status = cpu_to_le32(DescOwn); + np->rx_ring[entry].status = DescOwn; } return 0; @@ -1229,35 +1357,38 @@ dev->name, intr_status); if (intr_status == 0xffffffff) return; + spin_lock(&np->lock); if (intr_status & TxFIFOUnderflow) { + int new; /* Bump up the Tx threshold */ #if 0 /* This causes lots of dropped packets, * and under high load even tx_timeouts */ - np->csr6 += 0x4000; + new = np->csr6 + 0x4000; #else - int cur = (np->csr6 >> 14)&0x7f; - if (cur < 64) - cur *= 2; + new = (np->csr6 >> 14)&0x7f; + if (new < 64) + new *= 2; else - cur = 0; /* load full packet before starting */ - np->csr6 &= ~(0x7F << 14); - np->csr6 |= cur<<14; + new = 127; /* load full packet before starting */ + new = (np->csr6 & ~(0x7F << 14)) | (new<<14); #endif - printk(KERN_DEBUG "%s: Tx underflow, increasing threshold to %8.8x.\n", - dev->name, np->csr6); - writel(np->csr6, ioaddr + NetworkConfig); + printk(KERN_DEBUG "%s: Tx underflow, new csr6 %8.8x.\n", + dev->name, new); + update_csr6(dev, new); } if (intr_status & IntrRxDied) { /* Missed a Rx frame. */ np->stats.rx_errors++; } if (intr_status & TimerInt) { /* Re-enable other interrupts. */ - writel(0x1A0F5, ioaddr + IntrEnable); + if (netif_device_present(dev)) + writel(0x1A0F5, ioaddr + IntrEnable); } np->stats.rx_missed_errors += readl(ioaddr + RxMissed) & 0xffff; writel(0, ioaddr + RxStartDemand); + spin_unlock(&np->lock); } static struct net_device_stats *get_stats(struct net_device *dev) @@ -1266,8 +1397,10 @@ struct netdev_private *np = dev->priv; /* The chip only need report frame silently dropped. */ - if (netif_running(dev)) + spin_lock_irq(&np->lock); + if (netif_running(dev) && netif_device_present(dev)) np->stats.rx_missed_errors += readl(ioaddr + RxMissed) & 0xffff; + spin_unlock_irq(&np->lock); return &np->stats; } @@ -1288,9 +1421,8 @@ return crc; } -static void set_rx_mode(struct net_device *dev) +static u32 __set_rx_mode(struct net_device *dev) { - struct netdev_private *np = dev->priv; long ioaddr = dev->base_addr; u32 mc_filter[2]; /* Multicast hash filter */ u32 rx_mode; @@ -1319,9 +1451,16 @@ } writel(mc_filter[0], ioaddr + MulticastFilter0); writel(mc_filter[1], ioaddr + MulticastFilter1); - np->csr6 &= ~0x00F8; - np->csr6 |= rx_mode; - writel(np->csr6, ioaddr + NetworkConfig); + return rx_mode; +} + +static void set_rx_mode(struct net_device *dev) +{ + struct netdev_private *np = dev->priv; + u32 rx_mode = __set_rx_mode(dev); + spin_lock_irq(&np->lock); + update_csr6(dev, (np->csr6 & ~0x00F8) | rx_mode); + spin_unlock_irq(&np->lock); } static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr) @@ -1351,6 +1490,7 @@ static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { struct mii_ioctl_data *data = (struct mii_ioctl_data *)&rq->ifr_data; + struct netdev_private *np = dev->priv; switch(cmd) { case SIOCETHTOOL: @@ -1362,14 +1502,18 @@ case SIOCGMIIREG: /* Read MII PHY register. */ case SIOCDEVPRIVATE+1: /* for binary compat, remove in 2.5 */ + spin_lock_irq(&np->lock); data->val_out = mdio_read(dev, data->phy_id & 0x1f, data->reg_num & 0x1f); + spin_unlock_irq(&np->lock); return 0; case SIOCSMIIREG: /* Write MII PHY register. */ case SIOCDEVPRIVATE+2: /* for binary compat, remove in 2.5 */ if (!capable(CAP_NET_ADMIN)) return -EPERM; + spin_lock_irq(&np->lock); mdio_write(dev, data->phy_id & 0x1f, data->reg_num & 0x1f, data->val_in); + spin_unlock_irq(&np->lock); return 0; default: return -EOPNOTSUPP; @@ -1391,11 +1535,16 @@ dev->name, np->cur_tx, np->dirty_tx, np->cur_rx, np->dirty_rx); } - /* Disable interrupts by clearing the interrupt mask. */ + /* Stop the chip's Tx and Rx processes. */ + spin_lock_irq(&np->lock); + netif_device_detach(dev); + update_csr6(dev, 0); writel(0x0000, ioaddr + IntrEnable); + spin_unlock_irq(&np->lock); - /* Stop the chip's Tx and Rx processes. */ - writel(np->csr6 &= ~0x20FA, ioaddr + NetworkConfig); + free_irq(dev->irq, dev); + wmb(); + netif_device_attach(dev); if (readl(ioaddr + NetworkConfig) != 0xffffffff) np->stats.rx_missed_errors += readl(ioaddr + RxMissed) & 0xffff; @@ -1420,11 +1569,10 @@ } #endif /* __i386__ debugging only */ - free_irq(dev->irq, dev); - del_timer_sync(&np->timer); free_rxtx_rings(np); + free_ringdesc(np); return 0; } @@ -1446,11 +1594,112 @@ pci_set_drvdata(pdev, NULL); } +#ifdef CONFIG_PM + +/* + * suspend/resume synchronization: + * - open, close, do_ioctl: + * rtnl_lock, & netif_device_detach after the rtnl_unlock. + * - get_stats: + * spin_lock_irq(np->lock), doesn't touch hw if not present + * - hard_start_xmit: + * netif_stop_queue + spin_unlock_wait(&dev->xmit_lock); + * - tx_timeout: + * netif_device_detach + spin_unlock_wait(&dev->xmit_lock); + * - set_multicast_list + * netif_device_detach + spin_unlock_wait(&dev->xmit_lock); + * - interrupt handler + * doesn't touch hw if not present, synchronize_irq waits for + * running instances of the interrupt handler. + * + * Disabling hw requires clearing csr6 & IntrEnable. + * update_csr6 & all function that write IntrEnable check netif_device_present + * before settings any bits. + * + * Detach must occur under spin_unlock_irq(), interrupts from a detached + * device would cause an irq storm. + */ +static int w840_suspend (struct pci_dev *pdev, u32 state) +{ + struct net_device *dev = pci_get_drvdata (pdev); + struct netdev_private *np = dev->priv; + long ioaddr = dev->base_addr; + + rtnl_lock(); + if (netif_running (dev)) { + del_timer_sync(&np->timer); + + spin_lock_irq(&np->lock); + netif_device_detach(dev); + update_csr6(dev, 0); + writel(0, ioaddr + IntrEnable); + netif_stop_queue(dev); + spin_unlock_irq(&np->lock); + + spin_unlock_wait(&dev->xmit_lock); + synchronize_irq(); + + np->stats.rx_missed_errors += readl(ioaddr + RxMissed) & 0xffff; + + /* no more hardware accesses behind this line. */ + + if (np->csr6) BUG(); + if (readl(ioaddr + IntrEnable)) BUG(); + + /* pci_power_off(pdev, -1); */ + + free_rxtx_rings(np); + } else { + netif_device_detach(dev); + } + rtnl_unlock(); + return 0; +} + + +static int w840_resume (struct pci_dev *pdev) +{ + struct net_device *dev = pci_get_drvdata (pdev); + struct netdev_private *np = dev->priv; + + rtnl_lock(); + if (netif_device_present(dev)) + goto out; /* device not suspended */ + if (netif_running(dev)) { + pci_enable_device(pdev); + /* pci_power_on(pdev); */ + + spin_lock_irq(&np->lock); + writel(1, dev->base_addr+PCIBusCfg); + readl(dev->base_addr+PCIBusCfg); + udelay(1); + netif_device_attach(dev); + init_rxtx_rings(dev); + init_registers(dev); + spin_unlock_irq(&np->lock); + + netif_wake_queue(dev); + + np->timer.expires = jiffies + 1*HZ; + add_timer(&np->timer); + } else { + netif_device_attach(dev); + } +out: + rtnl_unlock(); + return 0; +} +#endif + static struct pci_driver w840_driver = { name: DRV_NAME, id_table: w840_pci_tbl, probe: w840_probe1, remove: w840_remove1, +#ifdef CONFIG_PM + suspend: w840_suspend, + resume: w840_resume, +#endif }; static int __init w840_init(void) diff -u --recursive --new-file v2.4.6/linux/drivers/net/wireless/airo.c linux/drivers/net/wireless/airo.c --- v2.4.6/linux/drivers/net/wireless/airo.c Tue Jul 3 17:08:20 2001 +++ linux/drivers/net/wireless/airo.c Tue Jul 17 18:53:55 2001 @@ -333,7 +333,8 @@ #define EV_LINK 0x80 #define EV_AWAKE 0x100 #define EV_UNKNOWN 0x800 -#define STATUS_INTS ( EV_AWAKE | EV_LINK | EV_TXEXC | EV_TX | EV_RX | EV_UNKNOWN) +#define STATUS_INTS ( EV_AWAKE | EV_LINK | EV_TXEXC | EV_TX | EV_RX) +#define IGNORE_INTS ( EV_CMD | EV_UNKNOWN) /* The RIDs */ #define RID_CAPABILITIES 0xFF00 @@ -656,7 +657,6 @@ // A few details needed for WEP (Wireless Equivalent Privacy) #define MAX_KEY_SIZE 13 // 128 (?) bits #define MIN_KEY_SIZE 5 // 40 bits RC4 - WEP -#define MAX_KEYS 4 // 4 different keys typedef struct wep_key_t { u16 len; u8 key[16]; /* 40-bit and 104-bit keys */ @@ -724,11 +724,12 @@ spinlock_t aux_lock; spinlock_t cmd_lock; int flags; -#define FLAG_PROMISC 0x01 +#define FLAG_PROMISC IFF_PROMISC #define FLAG_RADIO_OFF 0x02 int (*bap_read)(struct airo_info*, u16 *pu16Dst, int bytelen, int whichbap); int (*header_parse)(struct sk_buff*, unsigned char *); + unsigned short *flash; #ifdef WIRELESS_EXT int need_commit; // Need to set config struct iw_statistics wstats; // wireless stats @@ -949,10 +950,17 @@ Cmd cmd; Resp rsp; - memset(&cmd, 0, sizeof(cmd)); - cmd.cmd=CMD_SETMODE; - cmd.parm0=(dev->flags&IFF_PROMISC) ? PROMISC : NOPROMISC; - issuecommand(ai, &cmd, &rsp); + /* For some reason this command takes a lot of time (~20 ms) and it's + * run in an interrupt handler, so we'd better be sure we needed it + * before executing it. + */ + if ((dev->flags ^ ai->flags) & IFF_PROMISC) { + memset(&cmd, 0, sizeof(cmd)); + cmd.cmd=CMD_SETMODE; + cmd.parm0=(dev->flags&IFF_PROMISC) ? PROMISC : NOPROMISC; + issuecommand(ai, &cmd, &rsp); + ai->flags^=IFF_PROMISC; + } if ((dev->flags&IFF_ALLMULTI)||dev->mc_count>0) { /* Turn on multicast. (Should be already setup...) */ @@ -994,6 +1002,8 @@ void stop_airo_card( struct net_device *dev, int freeres ) { struct airo_info *ai = (struct airo_info*)dev->priv; + if (ai->flash) + kfree(ai->flash); takedown_proc_entry( dev, ai ); if (ai->registered) { unregister_netdev( dev ); @@ -1113,11 +1123,10 @@ } int reset_airo_card( struct net_device *dev ) { - int i, flags; + int i; struct airo_info *ai = (struct airo_info*)dev->priv; disable_MAC(ai); - spin_lock_irqsave(&ai->cmd_lock, flags); waitbusy (ai); OUT4500(ai,COMMAND,CMD_SOFTRESET); set_current_state (TASK_UNINTERRUPTIBLE); @@ -1125,7 +1134,6 @@ waitbusy (ai); set_current_state (TASK_UNINTERRUPTIBLE); schedule_timeout (HZ/5); - spin_unlock_irqrestore(&ai->cmd_lock, flags); if ( setup_card(ai, dev->dev_addr, &(ai)->config) != SUCCESS ) { printk( KERN_ERR "airo: MAC could not be enabled\n" ); return -1; @@ -1359,10 +1367,10 @@ apriv->stats.tx_errors++; } } - if ( status & ~STATUS_INTS ) + if ( status & ~STATUS_INTS & ~IGNORE_INTS ) printk( KERN_WARNING "airo: Got weird status %x\n", - status & ~STATUS_INTS ); + status & ~STATUS_INTS & ~IGNORE_INTS ); OUT4500( apriv, EVACK, status & STATUS_INTS ); OUT4500( apriv, EVINTEN, savedInterrupts ); @@ -1446,6 +1454,10 @@ int rc; memset( &mySsid, 0, sizeof( mySsid ) ); + if (ai->flash) { + kfree (ai->flash); + ai->flash = NULL; + } /* The NOP is the first step in getting the card going */ cmd.cmd = NOP; @@ -1562,6 +1574,10 @@ // PC4500 didn't notice command, try again OUT4500(ai, COMMAND, pCmd->cmd); } + if (!(max_tries & 255) && !in_interrupt()) { + set_current_state(TASK_RUNNING); + schedule(); + } } if ( max_tries == -1 ) { printk( KERN_ERR @@ -3134,9 +3150,12 @@ /* Set the SSID */ memset(essid, 0, sizeof(essid)); - copy_from_user(essid, + if (copy_from_user(essid, wrq->u.data.pointer, - wrq->u.data.length); + wrq->u.data.length)) { + rc = -EFAULT; + break; + } memcpy(SSID_rid.ssids[index].ssid, essid, sizeof(essid) - 1); SSID_rid.ssids[index].len = wrq->u.data.length - 1; @@ -3199,7 +3218,11 @@ break; } memset(name, 0, sizeof(name)); - copy_from_user(name, wrq->u.data.pointer, wrq->u.data.length); + if (copy_from_user(name, wrq->u.data.pointer, + wrq->u.data.length)) { + rc = -EFAULT; + break; + } memcpy(config.nodeName, name, 16); local->need_commit = 1; } @@ -3395,7 +3418,7 @@ break; } /* Check the index (none -> use current) */ - if ((index < 0) || (index >= MAX_KEYS)) + if ((index < 0) || (index>=(cap_rid.softCap&0x80)?4:1)) index = current_index; /* Set the length */ if (wrq->u.encoding.length > MIN_KEY_SIZE) @@ -3433,7 +3456,7 @@ } else { /* Do we want to just set the transmit key index ? */ int index = (wrq->u.encoding.flags & IW_ENCODE_INDEX) - 1; - if ((index >= 0) && (index < MAX_KEYS)) { + if ((index>=0) && (index<(cap_rid.softCap&0x80)?4:1)) { set_wep_key(local, index, 0, 0, 1); } else /* Don't complain if only change the mode */ @@ -3490,7 +3513,7 @@ } /* Which key do we want ? -1 -> tx index */ - if((index < 0) || (index >= MAX_KEYS)) + if((index < 0) || (index >= (cap_rid.softCap&0x80)?4:1)) index = get_wep_key(local, 0xffff); wrq->u.encoding.flags |= index + 1; /* Copy the key to the user buffer */ @@ -3614,7 +3637,7 @@ range.num_encoding_sizes = 2; } else range.num_encoding_sizes = 1; - range.max_encoding_tokens = 4; // 4 keys + range.max_encoding_tokens = (cap_rid.softCap & 0x80) ? 4 : 1; } else { range.num_encoding_sizes = 0; range.max_encoding_tokens = 0; @@ -3785,8 +3808,14 @@ memcpy(address[i].sa_data, local->spy_address[i], 6); address[i].sa_family = AF_UNIX; } - copy_to_user(wrq->u.data.pointer, address, sizeof(struct sockaddr) * local->spy_number); - copy_to_user(wrq->u.data.pointer + (sizeof(struct sockaddr)*local->spy_number), local->spy_stat, sizeof(struct iw_quality) * local->spy_number); + if (copy_to_user(wrq->u.data.pointer, address, sizeof(struct sockaddr) * local->spy_number)) { + rc = -EFAULT; + break; + } + if (copy_to_user(wrq->u.data.pointer + (sizeof(struct sockaddr)*local->spy_number), local->spy_stat, sizeof(struct iw_quality) * local->spy_number)) { + rc = -EFAULT; + break; + } for (i=0; i<local->spy_number; i++) local->spy_stat[i].updated = 0; } @@ -3833,7 +3862,10 @@ */ { aironet_ioctl com; - copy_from_user(&com,rq->ifr_data,sizeof(com)); + if (copy_from_user(&com,rq->ifr_data,sizeof(com))) { + rc = -EFAULT; + break; + } /* Seperate R/W functions bracket legality here */ @@ -4035,7 +4067,8 @@ if(comp->len > sizeof(iobuf)) return -EINVAL; - copy_from_user(iobuf,comp->data,comp->len); + if (copy_from_user(iobuf,comp->data,comp->len)) + return -EFAULT; if((*writer)((struct airo_info *)dev->priv, ridcode, iobuf,comp->len)) return -EIO; return 0; @@ -4056,9 +4089,8 @@ int setflashmode(struct airo_info *); int flashgchar(struct airo_info *,int,int); int flashpchar(struct airo_info *,int,int); - int flashputbuf(struct airo_info *, unsigned short *); + int flashputbuf(struct airo_info *); int flashrestart(struct airo_info *,struct net_device *); - unsigned short * flashbuffer; /* Only super-user can modify flash */ if (!capable(CAP_NET_ADMIN)) @@ -4070,32 +4102,34 @@ return cmdreset((struct airo_info *)dev->priv); case AIROFLSHSTFL: + if (!((struct airo_info *)dev->priv)->flash && + (((struct airo_info *)dev->priv)->flash = kmalloc (FLASHSIZE, GFP_KERNEL)) == NULL) + return -ENOMEM; return setflashmode((struct airo_info *)dev->priv); case AIROFLSHGCHR: /* Get char from aux */ if(comp->len != sizeof(int)) return -EINVAL; - copy_from_user(&z,comp->data,comp->len); + if (copy_from_user(&z,comp->data,comp->len)) + return -EFAULT; return flashgchar((struct airo_info *)dev->priv,z,8000); case AIROFLSHPCHR: /* Send char to card. */ if(comp->len != sizeof(int)) return -EINVAL; - copy_from_user(&z,comp->data,comp->len); + if (copy_from_user(&z,comp->data,comp->len)) + return -EFAULT; return flashpchar((struct airo_info *)dev->priv,z,8000); case AIROFLPUTBUF: /* Send 32k to card */ - if(comp->len > FLASHSIZE) - return -EINVAL; - if ((flashbuffer = kmalloc (FLASHSIZE, GFP_KERNEL)) == NULL) + if (!((struct airo_info *)dev->priv)->flash) return -ENOMEM; - if(copy_from_user(flashbuffer,comp->data,comp->len)) { - kfree (flashbuffer); + if(comp->len > FLASHSIZE) return -EINVAL; - } + if(copy_from_user(((struct airo_info *)dev->priv)->flash,comp->data,comp->len)) + return -EFAULT; - flashputbuf((struct airo_info *)dev->priv,flashbuffer); - kfree (flashbuffer); + flashputbuf((struct airo_info *)dev->priv); return 0; case AIRORESTART: @@ -4115,11 +4149,8 @@ */ int cmdreset(struct airo_info *ai) { - int flags; - disable_MAC(ai); - spin_lock_irqsave(&ai->cmd_lock, flags); if(!waitbusy (ai)){ printk(KERN_INFO "Waitbusy hang before RESET\n"); return -EBUSY; @@ -4134,7 +4165,6 @@ printk(KERN_INFO "Waitbusy hang AFTER RESET\n"); return -EBUSY; } - spin_unlock_irqrestore(&ai->cmd_lock, flags); return 0; } @@ -4144,16 +4174,12 @@ */ int setflashmode (struct airo_info *ai) { - int flags; - - spin_lock_irqsave(&ai->cmd_lock, flags); OUT4500(ai, SWS0, FLASH_COMMAND); OUT4500(ai, SWS1, FLASH_COMMAND); OUT4500(ai, SWS0, FLASH_COMMAND); OUT4500(ai, COMMAND,0x10); set_current_state (TASK_UNINTERRUPTIBLE); schedule_timeout (HZ/2); /* 500ms delay */ - spin_unlock_irqrestore(&ai->cmd_lock, flags); if(!waitbusy(ai)) { printk(KERN_INFO "Waitbusy hang after setflash mode\n"); @@ -4237,7 +4263,7 @@ * send to the card */ -int flashputbuf(struct airo_info *ai, unsigned short *bufp){ +int flashputbuf(struct airo_info *ai){ int nwords; /* Write stuff */ @@ -4245,7 +4271,7 @@ OUT4500(ai,AUXOFF,0); for(nwords=0;nwords != FLASHSIZE / 2;nwords++){ - OUT4500(ai,AUXDATA,bufp[nwords] & 0xffff); + OUT4500(ai,AUXDATA,ai->flash[nwords] & 0xffff); } OUT4500(ai,SWS0,0x8000); diff -u --recursive --new-file v2.4.6/linux/drivers/net/yellowfin.c linux/drivers/net/yellowfin.c --- v2.4.6/linux/drivers/net/yellowfin.c Tue Jul 3 17:08:20 2001 +++ linux/drivers/net/yellowfin.c Tue Jul 17 18:53:55 2001 @@ -86,6 +86,9 @@ #define TX_RING_SIZE 16 #define TX_QUEUE_SIZE 12 /* Must be > 4 && <= TX_RING_SIZE */ #define RX_RING_SIZE 64 +#define STATUS_TOTAL_SIZE TX_RING_SIZE*sizeof(struct tx_status_words) +#define TX_TOTAL_SIZE 2*TX_RING_SIZE*sizeof(struct yellowfin_desc) +#define RX_TOTAL_SIZE RX_RING_SIZE*sizeof(struct yellowfin_desc) /* Operational parameters that usually are not changed. */ /* Time in jiffies before concluding the transmitter is hung. */ @@ -127,10 +130,6 @@ KERN_INFO " http://www.scyld.com/network/yellowfin.html\n" KERN_INFO " (unofficial 2.4.x port, " DRV_VERSION ", " DRV_RELDATE ")\n"; -/* Condensed operations for readability. */ -#define virt_to_le32desc(addr) cpu_to_le32(virt_to_bus(addr)) -#define le32desc_to_virt(addr) bus_to_virt(le32_to_cpu(addr)) - #ifndef USE_IO_OPS #undef inb #undef inw @@ -351,19 +350,21 @@ struct yellowfin_private { /* Descriptor rings first for alignment. Tx requires a second descriptor for status. */ - struct yellowfin_desc rx_ring[RX_RING_SIZE]; - struct yellowfin_desc tx_ring[TX_RING_SIZE*2]; - /* The addresses of receive-in-place skbuffs. */ + struct yellowfin_desc *rx_ring; + struct yellowfin_desc *tx_ring; struct sk_buff* rx_skbuff[RX_RING_SIZE]; - /* The saved address of a sent-in-place packet/buffer, for later free(). */ struct sk_buff* tx_skbuff[TX_RING_SIZE]; - struct tx_status_words tx_status[TX_RING_SIZE]; + dma_addr_t rx_ring_dma; + dma_addr_t tx_ring_dma; + + struct tx_status_words *tx_status; + dma_addr_t tx_status_dma; + struct timer_list timer; /* Media selection timer. */ struct net_device_stats stats; /* Frequently used and paired value: keep adjacent for cache effect. */ int chip_id, drv_flags; struct pci_dev *pci_dev; - struct yellowfin_desc *rx_head_desc; unsigned int cur_rx, dirty_rx; /* Producer/consumer ring indices */ unsigned int rx_buf_sz; /* Based on MTU+slack. */ struct tx_status_words *tx_tail_desc; @@ -409,6 +410,8 @@ long ioaddr, real_ioaddr; int i, option = find_cnt < MAX_UNITS ? options[find_cnt] : 0; int drv_flags = pci_id_tbl[chip_idx].drv_flags; + void *ring_space; + dma_addr_t ring_dma; /* when built into the kernel, we only print version if device is found */ #ifndef MODULE @@ -460,12 +463,30 @@ dev->irq = irq; pci_set_drvdata(pdev, dev); - np->lock = SPIN_LOCK_UNLOCKED; + spin_lock_init(&np->lock); np->pci_dev = pdev; np->chip_id = chip_idx; np->drv_flags = drv_flags; + ring_space = pci_alloc_consistent(pdev, TX_TOTAL_SIZE, &ring_dma); + if (!ring_space) + goto err_out_cleardev; + np->tx_ring = (struct yellowfin_desc *)ring_space; + np->tx_ring_dma = ring_dma; + + ring_space = pci_alloc_consistent(pdev, RX_TOTAL_SIZE, &ring_dma); + if (!ring_space) + goto err_out_unmap_tx; + np->rx_ring = (struct yellowfin_desc *)ring_space; + np->rx_ring_dma = ring_dma; + + ring_space = pci_alloc_consistent(pdev, STATUS_TOTAL_SIZE, &ring_dma); + if (!ring_space) + goto err_out_unmap_rx; + np->tx_status = (struct tx_status_words *)ring_space; + np->tx_status_dma = ring_dma; + if (dev->mem_start) option = dev->mem_start; @@ -498,7 +519,7 @@ i = register_netdev(dev); if (i) - goto err_out_cleardev; + goto err_out_unmap_status; printk(KERN_INFO "%s: %s type %8x at 0x%lx, ", dev->name, pci_id_tbl[chip_idx].name, inl(ioaddr + ChipRev), ioaddr); @@ -525,6 +546,13 @@ return 0; +err_out_unmap_status: + pci_free_consistent(pdev, STATUS_TOTAL_SIZE, np->tx_status, + np->tx_status_dma); +err_out_unmap_rx: + pci_free_consistent(pdev, RX_TOTAL_SIZE, np->rx_ring, np->rx_ring_dma); +err_out_unmap_tx: + pci_free_consistent(pdev, TX_TOTAL_SIZE, np->tx_ring, np->tx_ring_dma); err_out_cleardev: pci_set_drvdata(pdev, NULL); #ifndef USE_IO_OPS @@ -597,8 +625,8 @@ yellowfin_init_ring(dev); - outl(virt_to_bus(yp->rx_ring), ioaddr + RxPtr); - outl(virt_to_bus(yp->tx_ring), ioaddr + TxPtr); + outl(yp->rx_ring_dma, ioaddr + RxPtr); + outl(yp->tx_ring_dma, ioaddr + TxPtr); for (i = 0; i < 6; i++) outb(dev->dev_addr[i], ioaddr + StnAddr + i); @@ -742,24 +770,23 @@ yp->dirty_tx = 0; yp->rx_buf_sz = (dev->mtu <= 1500 ? PKT_BUF_SZ : dev->mtu + 32); - yp->rx_head_desc = &yp->rx_ring[0]; for (i = 0; i < RX_RING_SIZE; i++) { yp->rx_ring[i].dbdma_cmd = cpu_to_le32(CMD_RX_BUF | INTR_ALWAYS | yp->rx_buf_sz); - yp->rx_ring[i].branch_addr = virt_to_le32desc(&yp->rx_ring[i+1]); + yp->rx_ring[i].branch_addr = cpu_to_le32(yp->rx_ring_dma + + ((i+1)%RX_RING_SIZE)*sizeof(struct yellowfin_desc)); } - /* Mark the last entry as wrapping the ring. */ - yp->rx_ring[i-1].branch_addr = virt_to_le32desc(&yp->rx_ring[0]); for (i = 0; i < RX_RING_SIZE; i++) { struct sk_buff *skb = dev_alloc_skb(yp->rx_buf_sz); yp->rx_skbuff[i] = skb; if (skb == NULL) break; - skb->dev = dev; /* Mark as being used by this device. */ + skb->dev = dev; /* Mark as being used by this device. */ skb_reserve(skb, 2); /* 16 byte align the IP header. */ - yp->rx_ring[i].addr = virt_to_le32desc(skb->tail); + yp->rx_ring[i].addr = pci_map_single(yp->pci_dev, skb->tail, + yp->rx_buf_sz, PCI_DMA_FROMDEVICE); } yp->rx_ring[i-1].dbdma_cmd = cpu_to_le32(CMD_STOP); yp->dirty_rx = (unsigned int)(i - RX_RING_SIZE); @@ -770,35 +797,47 @@ for (i = 0; i < TX_RING_SIZE; i++) { yp->tx_skbuff[i] = 0; yp->tx_ring[i].dbdma_cmd = cpu_to_le32(CMD_STOP); - yp->tx_ring[i].branch_addr = virt_to_le32desc(&yp->tx_ring[i+1]); + yp->tx_ring[i].branch_addr = cpu_to_le32(yp->tx_ring_dma + + ((i+1)%TX_RING_SIZE)*sizeof(struct yellowfin_desc)); } /* Wrap ring */ yp->tx_ring[--i].dbdma_cmd = cpu_to_le32(CMD_STOP | BRANCH_ALWAYS); - yp->tx_ring[i].branch_addr = virt_to_le32desc(&yp->tx_ring[0]); #else +{ + int j; + /* Tx ring needs a pair of descriptors, the second for the status. */ - for (i = 0; i < TX_RING_SIZE*2; i++) { - yp->tx_skbuff[i/2] = 0; + for (i = 0; i < TX_RING_SIZE; i++) { + j = 2*i; + yp->tx_skbuff[i] = 0; /* Branch on Tx error. */ - yp->tx_ring[i].dbdma_cmd = cpu_to_le32(CMD_STOP); - yp->tx_ring[i].branch_addr = virt_to_le32desc(&yp->tx_ring[i+1]); - i++; + yp->tx_ring[j].dbdma_cmd = cpu_to_le32(CMD_STOP); + yp->tx_ring[j].branch_addr = cpu_to_le32(yp->tx_ring_dma + + (j+1)*sizeof(struct yellowfin_desc); + j++; if (yp->flags & FullTxStatus) { - yp->tx_ring[i].dbdma_cmd = - cpu_to_le32(CMD_TXSTATUS | sizeof(yp->tx_status[i])); - yp->tx_ring[i].request_cnt = sizeof(yp->tx_status[i]); - yp->tx_ring[i].addr = virt_to_le32desc(&yp->tx_status[i/2]); - } else { /* Symbios chips write only tx_errs word. */ - yp->tx_ring[i].dbdma_cmd = + yp->tx_ring[j].dbdma_cmd = + cpu_to_le32(CMD_TXSTATUS | sizeof(*yp->tx_status)); + yp->tx_ring[j].request_cnt = sizeof(*yp->tx_status); + yp->tx_ring[j].addr = cpu_to_le32(yp->tx_status_dma + + i*sizeof(struct tx_status_words); + } else { + /* Symbios chips write only tx_errs word. */ + yp->tx_ring[j].dbdma_cmd = cpu_to_le32(CMD_TXSTATUS | INTR_ALWAYS | 2); - yp->tx_ring[i].request_cnt = 2; - yp->tx_ring[i].addr = virt_to_le32desc(&yp->tx_status[i/2].tx_errs); + yp->tx_ring[j].request_cnt = 2; + /* Om pade ummmmm... */ + yp->tx_ring[j].addr = cpu_to_le32(yp->tx_status_dma + + i*sizeof(struct tx_status_words) + + &(yp->tx_status[0].tx_errs) - + &(yp->tx_status[0])); } - yp->tx_ring[i].branch_addr = virt_to_le32desc(&yp->tx_ring[i+1]); + yp->tx_ring[j].branch_addr = cpu_to_le32(yp->tx_ring_dma + + ((j+1)%(2*TX_RING_SIZE))*sizeof(struct yellowfin_desc)); } /* Wrap ring */ - yp->tx_ring[--i].dbdma_cmd |= cpu_to_le32(BRANCH_ALWAYS | INTR_ALWAYS); - yp->tx_ring[i].branch_addr = virt_to_le32desc(&yp->tx_ring[0]); + yp->tx_ring[++j].dbdma_cmd |= cpu_to_le32(BRANCH_ALWAYS | INTR_ALWAYS); +} #endif yp->tx_tail_desc = &yp->tx_status[0]; return; @@ -819,14 +858,15 @@ yp->tx_skbuff[entry] = skb; - if (gx_fix) { /* Note: only works for paddable protocols e.g. IP. */ - int cacheline_end = (virt_to_bus(skb->data) + skb->len) % 32; + if (gx_fix) { /* Note: only works for paddable protocols e.g. IP. */ + int cacheline_end = ((unsigned long)skb->data + skb->len) % 32; /* Fix GX chipset errata. */ if (cacheline_end > 24 || cacheline_end == 0) skb->len += 32 - cacheline_end + 1; } #ifdef NO_TXSTATS - yp->tx_ring[entry].addr = virt_to_le32desc(skb->data); + yp->tx_ring[entry].addr = cpu_to_le32(pci_map_single(yp->pci_dev, + skb->data, skb->len, PCI_DMA_TODEVICE)); yp->tx_ring[entry].result_status = 0; if (entry >= TX_RING_SIZE-1) { /* New stop command. */ @@ -841,9 +881,10 @@ yp->cur_tx++; #else yp->tx_ring[entry<<1].request_cnt = skb->len; - yp->tx_ring[entry<<1].addr = virt_to_le32desc(skb->data); - /* The input_last (status-write) command is constant, but we must rewrite - the subsequent 'stop' command. */ + yp->tx_ring[entry<<1].addr = cpu_to_le32(pci_map_single(yp->pci_dev, + skb->data, skb->len, PCI_DMA_TODEVICE)); + /* The input_last (status-write) command is constant, but we must + rewrite the subsequent 'stop' command. */ yp->cur_tx++; { @@ -914,12 +955,17 @@ #ifdef NO_TXSTATS for (; yp->cur_tx - yp->dirty_tx > 0; yp->dirty_tx++) { int entry = yp->dirty_tx % TX_RING_SIZE; + struct sk_buff *skb; + if (yp->tx_ring[entry].result_status == 0) break; + skb = yp->tx_skbuff[entry]; yp->stats.tx_packets++; - yp->stats.tx_bytes += yp->tx_skbuff[entry]->len; + yp->stats.tx_bytes += skb->len; /* Free the original skb. */ - dev_kfree_skb_irq(yp->tx_skbuff[entry]); + pci_unmap_single(yp->pci_dev, yp->tx_ring[entry].addr, + skb->len, PCI_DMA_TODEVICE); + dev_kfree_skb_irq(skb); yp->tx_skbuff[entry] = 0; } if (yp->tx_full @@ -929,8 +975,7 @@ netif_wake_queue(dev); } #else - if (intr_status & IntrTxDone - || yp->tx_tail_desc->tx_errs) { + if ((intr_status & IntrTxDone) || (yp->tx_tail_desc->tx_errs)) { unsigned dirty_tx = yp->dirty_tx; for (dirty_tx = yp->dirty_tx; yp->cur_tx - dirty_tx > 0; @@ -938,6 +983,7 @@ /* Todo: optimize this. */ int entry = dirty_tx % TX_RING_SIZE; u16 tx_errs = yp->tx_status[entry].tx_errs; + struct sk_buff *skb; #ifndef final_version if (yellowfin_debug > 5) @@ -950,7 +996,8 @@ yp->tx_status[entry].paused); #endif if (tx_errs == 0) - break; /* It still hasn't been Txed */ + break; /* It still hasn't been Txed */ + skb = yp->tx_skbuff[entry]; if (tx_errs & 0xF810) { /* There was an major error, log it. */ #ifndef final_version @@ -975,12 +1022,15 @@ #ifdef ETHER_STATS if (tx_errs & 0x0400) yp->stats.tx_deferred++; #endif - yp->stats.tx_bytes += yp->tx_skbuff[entry]->len; + yp->stats.tx_bytes += skb->len; yp->stats.collisions += tx_errs & 15; yp->stats.tx_packets++; } /* Free the original skb. */ - dev_kfree_skb_irq(yp->tx_skbuff[entry]); + pci_unmap_single(yp->pci_dev, + yp->tx_ring[entry<<1].addr, skb->len, + PCI_DMA_TODEVICE); + dev_kfree_skb_irq(skb); yp->tx_skbuff[entry] = 0; /* Mark status as empty. */ yp->tx_status[entry].tx_errs = 0; @@ -1043,15 +1093,23 @@ } /* If EOP is set on the next entry, it's a new packet. Send it up. */ - while (yp->rx_head_desc->result_status) { - struct yellowfin_desc *desc = yp->rx_head_desc; - u16 desc_status = le32_to_cpu(desc->result_status) >> 16; - int data_size = - (le32_to_cpu(desc->dbdma_cmd) - le32_to_cpu(desc->result_status)) - & 0xffff; - u8 *buf_addr = le32desc_to_virt(desc->addr); - s16 frame_status = get_unaligned((s16*)&(buf_addr[data_size - 2])); + while (1) { + struct yellowfin_desc *desc = &yp->rx_ring[entry]; + struct sk_buff *rx_skb = yp->rx_skbuff[entry]; + s16 frame_status; + u16 desc_status; + int data_size; + u8 *buf_addr; + if(!desc->result_status) + break; + pci_dma_sync_single(yp->pci_dev, desc->addr, + yp->rx_buf_sz, PCI_DMA_FROMDEVICE); + desc_status = le32_to_cpu(desc->result_status) >> 16; + buf_addr = rx_skb->tail; + data_size = (le32_to_cpu(desc->dbdma_cmd) - + le32_to_cpu(desc->result_status)) & 0xffff; + frame_status = get_unaligned((s16*)&(buf_addr[data_size - 2])); if (yellowfin_debug > 4) printk(KERN_DEBUG " yellowfin_rx() status was %4.4x.\n", frame_status); @@ -1080,12 +1138,14 @@ if (status2 & 0x03) yp->stats.rx_frame_errors++; if (status2 & 0x04) yp->stats.rx_crc_errors++; if (status2 & 0x80) yp->stats.rx_dropped++; -#ifdef YF_PROTOTYPE /* Support for prototype hardware errata. */ +#ifdef YF_PROTOTYPE /* Support for prototype hardware errata. */ } else if ((yp->flags & HasMACAddrBug) && - memcmp(le32desc_to_virt(yp->rx_ring[entry].addr), - dev->dev_addr, 6) != 0 - && memcmp(le32desc_to_virt(yp->rx_ring[entry].addr), - "\377\377\377\377\377\377", 6) != 0) { + memcmp(le32_to_cpu(yp->rx_ring_dma + + entry*sizeof(struct yellowfin_desc)), + dev->dev_addr, 6) != 0 && + memcmp(le32_to_cpu(yp->rx_ring_dma + + entry*sizeof(struct yellowfin_desc)), + "\377\377\377\377\377\377", 6) != 0) { if (bogus_rx++ == 0) printk(KERN_WARNING "%s: Bad frame to %2.2x:%2.2x:%2.2x:%2.2x:" "%2.2x:%2.2x.\n", @@ -1107,16 +1167,12 @@ /* Check if the packet is long enough to just pass up the skbuff without copying to a properly sized skbuff. */ if (pkt_len > rx_copybreak) { - char *temp = skb_put(skb = yp->rx_skbuff[entry], pkt_len); + skb_put(skb = rx_skb, pkt_len); + pci_unmap_single(yp->pci_dev, + yp->rx_ring[entry].addr, + yp->rx_buf_sz, + PCI_DMA_FROMDEVICE); yp->rx_skbuff[entry] = NULL; -#ifndef final_version /* Remove after testing. */ - if (le32desc_to_virt(yp->rx_ring[entry].addr) != temp) - printk(KERN_ERR "%s: Internal fault: The skbuff addresses " - "do not match in yellowfin_rx: %p vs. %p / %p.\n", - dev->name, - le32desc_to_virt(yp->rx_ring[entry].addr), - skb->head, temp); -#endif } else { skb = dev_alloc_skb(pkt_len + 2); if (skb == NULL) @@ -1124,11 +1180,11 @@ skb->dev = dev; skb_reserve(skb, 2); /* 16 byte align the IP header */ #if HAS_IP_COPYSUM - eth_copy_and_sum(skb, yp->rx_skbuff[entry]->tail, pkt_len, 0); + eth_copy_and_sum(skb, rx_skb->tail, pkt_len, 0); skb_put(skb, pkt_len); #else - memcpy(skb_put(skb, pkt_len), yp->rx_skbuff[entry]->tail, - pkt_len); + memcpy(skb_put(skb, pkt_len), + rx_skb->tail, pkt_len); #endif } skb->protocol = eth_type_trans(skb, dev); @@ -1138,7 +1194,6 @@ yp->stats.rx_bytes += pkt_len; } entry = (++yp->cur_rx) % RX_RING_SIZE; - yp->rx_head_desc = &yp->rx_ring[entry]; } /* Refill the Rx ring buffers. */ @@ -1146,12 +1201,13 @@ entry = yp->dirty_rx % RX_RING_SIZE; if (yp->rx_skbuff[entry] == NULL) { struct sk_buff *skb = dev_alloc_skb(yp->rx_buf_sz); - yp->rx_skbuff[entry] = skb; if (skb == NULL) break; /* Better luck next round. */ - skb->dev = dev; /* Mark as being used by this device. */ + yp->rx_skbuff[entry] = skb; + skb->dev = dev; /* Mark as being used by this device. */ skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ - yp->rx_ring[entry].addr = virt_to_le32desc(skb->tail); + yp->rx_ring[entry].addr = pci_map_single(yp->pci_dev, + skb->tail, yp->rx_buf_sz, PCI_DMA_FROMDEVICE); } yp->rx_ring[entry].dbdma_cmd = cpu_to_le32(CMD_STOP); yp->rx_ring[entry].result_status = 0; /* Clear complete bit. */ @@ -1208,8 +1264,7 @@ #if defined(__i386__) if (yellowfin_debug > 2) { - printk("\n"KERN_DEBUG" Tx ring at %8.8x:\n", - (int)virt_to_bus(yp->tx_ring)); + printk("\n"KERN_DEBUG" Tx ring at %8.8x:\n", yp->tx_ring_dma); for (i = 0; i < TX_RING_SIZE*2; i++) printk(" %c #%d desc. %8.8x %8.8x %8.8x %8.8x.\n", inl(ioaddr + TxPtr) == (long)&yp->tx_ring[i] ? '>' : ' ', @@ -1221,8 +1276,7 @@ i, yp->tx_status[i].tx_cnt, yp->tx_status[i].tx_errs, yp->tx_status[i].total_tx_cnt, yp->tx_status[i].paused); - printk("\n"KERN_DEBUG " Rx ring %8.8x:\n", - (int)virt_to_bus(yp->rx_ring)); + printk("\n"KERN_DEBUG " Rx ring %8.8x:\n", yp->rx_ring_dma); for (i = 0; i < RX_RING_SIZE; i++) { printk(KERN_DEBUG " %c #%d desc. %8.8x %8.8x %8.8x\n", inl(ioaddr + RxPtr) == (long)&yp->rx_ring[i] ? '>' : ' ', @@ -1422,6 +1476,10 @@ BUG(); np = dev->priv; + pci_free_consistent(pdev, STATUS_TOTAL_SIZE, np->tx_status, + np->tx_status_dma); + pci_free_consistent(pdev, RX_TOTAL_SIZE, np->rx_ring, np->rx_ring_dma); + pci_free_consistent(pdev, TX_TOTAL_SIZE, np->tx_ring, np->tx_ring_dma); unregister_netdev (dev); pci_release_regions (pdev); diff -u --recursive --new-file v2.4.6/linux/drivers/net/znet.c linux/drivers/net/znet.c --- v2.4.6/linux/drivers/net/znet.c Thu Apr 19 09:34:52 2001 +++ linux/drivers/net/znet.c Tue Jul 17 18:53:55 2001 @@ -5,7 +5,7 @@ /* Written by Donald Becker. - The author may be reached as becker@cesdis.gsfc.nasa.gov. + The author may be reached as becker@scyld.com. This driver is based on the Linux skeleton driver. The copyright of the skeleton driver is held by the United States Government, as represented by DIRNSA, and it is released under the GPL. diff -u --recursive --new-file v2.4.6/linux/drivers/parport/ChangeLog linux/drivers/parport/ChangeLog --- v2.4.6/linux/drivers/parport/ChangeLog Tue Jul 3 17:08:20 2001 +++ linux/drivers/parport/ChangeLog Tue Jul 10 16:07:46 2001 @@ -1,3 +1,11 @@ +2001-06-20 Tim Waugh <twaugh@redhat.com> + + * parport_pc.c: Make 'io_hi=0' work. + +2001-05-31 Tim Waugh <twaugh@redhat.com> + + * parport_serial.c: New file. + 2001-06-05 Tim Waugh <twaugh@redhat.com> * parport_pc.c (parport_pc_unregister_port): New exported function. diff -u --recursive --new-file v2.4.6/linux/drivers/parport/Config.in linux/drivers/parport/Config.in --- v2.4.6/linux/drivers/parport/Config.in Sat Feb 3 12:43:52 2001 +++ linux/drivers/parport/Config.in Tue Jul 10 16:07:46 2001 @@ -11,6 +11,14 @@ tristate 'Parallel port support' CONFIG_PARPORT if [ "$CONFIG_PARPORT" != "n" ]; then dep_tristate ' PC-style hardware' CONFIG_PARPORT_PC $CONFIG_PARPORT + if [ "$CONFIG_PARPORT_PC" != "n" -a "$CONFIG_SERIAL" != "n" ]; then + if [ "$CONFIG_SERIAL" = "m" ]; then + define_tristate CONFIG_PARPORT_PC_CML1 m + else + define_tristate CONFIG_PARPORT_PC_CML1 $CONFIG_PARPORT_PC + fi + dep_tristate ' Multi-IO cards (parallel and serial)' CONFIG_PARPORT_SERIAL $CONFIG_PARPORT_PC_CML1 + fi if [ "$CONFIG_PARPORT_PC" != "n" ]; then if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then bool ' Use FIFO/DMA if available (EXPERIMENTAL)' CONFIG_PARPORT_PC_FIFO diff -u --recursive --new-file v2.4.6/linux/drivers/parport/Makefile linux/drivers/parport/Makefile --- v2.4.6/linux/drivers/parport/Makefile Fri Dec 29 14:07:22 2000 +++ linux/drivers/parport/Makefile Tue Jul 10 16:07:46 2001 @@ -22,6 +22,7 @@ obj-$(CONFIG_PARPORT) += parport.o obj-$(CONFIG_PARPORT_PC) += parport_pc.o +obj-$(CONFIG_PARPORT_SERIAL) += parport_serial.o obj-$(CONFIG_PARPORT_AMIGA) += parport_amiga.o obj-$(CONFIG_PARPORT_MFC3) += parport_mfc3.o obj-$(CONFIG_PARPORT_ATARI) += parport_atari.o diff -u --recursive --new-file v2.4.6/linux/drivers/parport/init.c linux/drivers/parport/init.c --- v2.4.6/linux/drivers/parport/init.c Wed May 16 10:25:39 2001 +++ linux/drivers/parport/init.c Tue Jul 10 16:07:46 2001 @@ -21,7 +21,8 @@ #ifndef MODULE static int io[PARPORT_MAX+1] __initdata = { [0 ... PARPORT_MAX] = 0 }; #ifdef CONFIG_PARPORT_PC -static int io_hi[PARPORT_MAX+1] __initdata = { [0 ... PARPORT_MAX] = 0 }; +static int io_hi[PARPORT_MAX+1] __initdata = + { [0 ... PARPORT_MAX] = PARPORT_IOHI_AUTO }; #endif static int irq[PARPORT_MAX] __initdata = { [0 ... PARPORT_MAX-1] = PARPORT_IRQ_PROBEONLY }; static int dma[PARPORT_MAX] __initdata = { [0 ... PARPORT_MAX-1] = PARPORT_DMA_NONE }; diff -u --recursive --new-file v2.4.6/linux/drivers/parport/parport_pc.c linux/drivers/parport/parport_pc.c --- v2.4.6/linux/drivers/parport/parport_pc.c Tue Jul 3 17:08:20 2001 +++ linux/drivers/parport/parport_pc.c Tue Jul 10 16:07:46 2001 @@ -2824,7 +2824,8 @@ /* Only probe the ports we were given. */ user_specified = 1; do { - if (!*io_hi) *io_hi = 0x400 + *io; + if ((*io_hi) == PARPORT_IOHI_AUTO) + *io_hi = 0x400 + *io; if (parport_pc_probe_port(*(io++), *(io_hi++), *(irq++), *(dma++), NULL)) count++; @@ -2842,7 +2843,8 @@ #ifdef MODULE static int io[PARPORT_PC_MAX_PORTS+1] = { [0 ... PARPORT_PC_MAX_PORTS] = 0 }; -static int io_hi[PARPORT_PC_MAX_PORTS+1] = { [0 ... PARPORT_PC_MAX_PORTS] = 0 }; +static int io_hi[PARPORT_PC_MAX_PORTS+1] = + { [0 ... PARPORT_PC_MAX_PORTS] = PARPORT_IOHI_AUTO }; static int dmaval[PARPORT_PC_MAX_PORTS] = { [0 ... PARPORT_PC_MAX_PORTS-1] = PARPORT_DMA_AUTO }; static int irqval[PARPORT_PC_MAX_PORTS] = { [0 ... PARPORT_PC_MAX_PORTS-1] = PARPORT_IRQ_PROBEONLY }; static const char *irq[PARPORT_PC_MAX_PORTS] = { NULL, }; diff -u --recursive --new-file v2.4.6/linux/drivers/parport/parport_serial.c linux/drivers/parport/parport_serial.c --- v2.4.6/linux/drivers/parport/parport_serial.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/parport/parport_serial.c Tue Jul 10 16:07:46 2001 @@ -0,0 +1,353 @@ +/* + * Support for common PCI multi-I/O cards (which is most of them) + * + * Copyright (C) 2001 Tim Waugh <twaugh@redhat.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * + * Multi-function PCI cards are supposed to present separate logical + * devices on the bus. A common thing to do seems to be to just use + * one logical device with lots of base address registers for both + * parallel ports and serial ports. This driver is for dealing with + * that. + * + */ + +#include <linux/types.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/pci.h> +#include <linux/parport.h> +#include <linux/parport_pc.h> +#include <linux/serial.h> +#include <linux/serialP.h> +#include <linux/list.h> + +#include <asm/serial.h> + +enum parport_pc_pci_cards { + titan_110l = 0, + titan_210l, + netmos_9735, + netmos_9835, + avlab_1s1p, + avlab_1s1p_650, + avlab_1s1p_850, + avlab_1s2p, + avlab_1s2p_650, + avlab_1s2p_850, + avlab_2s1p, + avlab_2s1p_650, + avlab_2s1p_850, +}; + + +/* each element directly indexed from enum list, above */ +static struct parport_pc_pci { + int numports; + struct { /* BAR (base address registers) numbers in the config + space header */ + int lo; + int hi; /* -1 if not there, >6 for offset-method (max + BAR is 6) */ + } addr[4]; +} cards[] __devinitdata = { + /* titan_110l */ { 1, { { 3, -1 }, } }, + /* titan_210l */ { 1, { { 3, -1 }, } }, + /* netmos_9735 (not tested) */ { 1, { { 2, 3 }, } }, + /* netmos_9835 (not tested) */ { 1, { { 2, 3 }, } }, + /* avlab_1s1p */ { 1, { { 1, 2}, } }, + /* avlab_1s1p_650 */ { 1, { { 1, 2}, } }, + /* avlab_1s1p_850 */ { 1, { { 1, 2}, } }, + /* avlab_1s2p */ { 2, { { 1, 2}, { 3, 4 },} }, + /* avlab_1s2p_650 */ { 2, { { 1, 2}, { 3, 4 },} }, + /* avlab_1s2p_850 */ { 2, { { 1, 2}, { 3, 4 },} }, + /* avlab_2s1p */ { 1, { { 2, 3}, } }, + /* avlab_2s1p_650 */ { 1, { { 2, 3}, } }, + /* avlab_2s1p_850 */ { 1, { { 2, 3}, } }, +}; + +static struct pci_device_id parport_serial_pci_tbl[] __devinitdata = { + /* PCI cards */ + { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_110L, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, titan_110l }, + { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_210L, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, titan_210l }, + { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9735, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9735 }, + { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9835, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9835 }, + /* PCI_VENDOR_ID_AVLAB/Intek21 has another bunch of cards ...*/ + { 0x14db, 0x2110, PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_1s1p}, + { 0x14db, 0x2111, PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_1s1p_650}, + { 0x14db, 0x2112, PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_1s1p_850}, + { 0x14db, 0x2140, PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_1s2p}, + { 0x14db, 0x2141, PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_1s2p_650}, + { 0x14db, 0x2142, PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_1s2p_850}, + { 0x14db, 0x2160, PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_2s1p}, + { 0x14db, 0x2161, PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_2s1p_650}, + { 0x14db, 0x2162, PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_2s1p_850}, + { 0, } /* terminate list */ +}; +MODULE_DEVICE_TABLE(pci,parport_serial_pci_tbl); + +struct pci_board_no_ids { + int flags; + int num_ports; + int base_baud; + int uart_offset; + int reg_shift; + int (*init_fn)(struct pci_dev *dev, struct pci_board_no_ids *board, + int enable); + int first_uart_offset; +}; + +static struct pci_board_no_ids pci_boards[] __devinitdata = { + /* + * PCI Flags, Number of Ports, Base (Maximum) Baud Rate, + * Offset to get to next UART's registers, + * Register shift to use for memory-mapped I/O, + * Initialization function, first UART offset + */ + +// Cards not tested are marked n/t +// If you have one of these cards and it works for you, please tell me.. + +/* titan_110l */ { SPCI_FL_BASE1 | SPCI_FL_BASE_TABLE, 1, 921600 }, +/* titan_210l */ { SPCI_FL_BASE1 | SPCI_FL_BASE_TABLE, 2, 921600 }, +/* netmos_9735 (n/t)*/ { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 115200 }, +/* netmos_9835 (n/t)*/ { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 115200 }, +/* avlab_1s1p (n/t) */ { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 1, 115200 }, +/* avlab_1s1p_650 (nt)*/{ SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 1, 115200 }, +/* avlab_1s1p_850 (nt)*/{ SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 1, 115200 }, +/* avlab_1s2p (n/t) */ { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 1, 115200 }, +/* avlab_1s2p_650 (nt)*/{ SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 1, 115200 }, +/* avlab_1s2p_850 (nt)*/{ SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 1, 115200 }, +/* avlab_2s1p (n/t) */ { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 115200 }, +/* avlab_2s1p_650 (nt)*/{ SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 115200 }, +/* avlab_2s1p_850 (nt)*/{ SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 115200 }, +}; + +struct parport_serial_private { + int num_ser; + int line[20]; + struct pci_board_no_ids ser; + int num_par; + struct parport *port[PARPORT_MAX]; +}; + +static int __devinit get_pci_port (struct pci_dev *dev, + struct pci_board_no_ids *board, + struct serial_struct *req, + int idx) +{ + unsigned long port; + int base_idx; + int max_port; + int offset; + + base_idx = SPCI_FL_GET_BASE(board->flags); + if (board->flags & SPCI_FL_BASE_TABLE) + base_idx += idx; + + if (board->flags & SPCI_FL_REGION_SZ_CAP) { + max_port = pci_resource_len(dev, base_idx) / 8; + if (idx >= max_port) + return 1; + } + + offset = board->first_uart_offset; + + /* Timedia/SUNIX uses a mixture of BARs and offsets */ + /* Ugh, this is ugly as all hell --- TYT */ + if(dev->vendor == PCI_VENDOR_ID_TIMEDIA ) /* 0x1409 */ + switch(idx) { + case 0: base_idx=0; + break; + case 1: base_idx=0; offset=8; + break; + case 2: base_idx=1; + break; + case 3: base_idx=1; offset=8; + break; + case 4: /* BAR 2*/ + case 5: /* BAR 3 */ + case 6: /* BAR 4*/ + case 7: base_idx=idx-2; /* BAR 5*/ + } + + port = pci_resource_start(dev, base_idx) + offset; + + if ((board->flags & SPCI_FL_BASE_TABLE) == 0) + port += idx * (board->uart_offset ? board->uart_offset : 8); + + if (pci_resource_flags (dev, base_idx) & IORESOURCE_IO) { + int high_bits_offset = ((sizeof(long)-sizeof(int))*8); + req->port = port; + if (high_bits_offset) + req->port_high = port >> high_bits_offset; + else + req->port_high = 0; + return 0; + } + req->io_type = SERIAL_IO_MEM; + req->iomem_base = ioremap(port, board->uart_offset); + req->iomem_reg_shift = board->reg_shift; + req->port = 0; + return req->iomem_base ? 0 : 1; +} + +/* Register the serial port(s) of a PCI card. */ +static int __devinit serial_register (struct pci_dev *dev, + const struct pci_device_id *id) +{ + struct pci_board_no_ids *board = &pci_boards[id->driver_data]; + struct parport_serial_private *priv = pci_get_drvdata (dev); + struct serial_struct serial_req; + int base_baud; + int k; + int success = 0; + + priv->ser = *board; + if (board->init_fn && ((board->init_fn) (dev, board, 1) != 0)) + return 1; + + base_baud = board->base_baud; + if (!base_baud) + base_baud = BASE_BAUD; + memset (&serial_req, 0, sizeof (serial_req)); + + for (k = 0; k < board->num_ports; k++) { + int line; + serial_req.irq = dev->irq; + if (get_pci_port (dev, board, &serial_req, k)) + break; + serial_req.flags = ASYNC_SKIP_TEST | ASYNC_AUTOPROBE; + line = register_serial (&serial_req); + if (line < 0) { + printk (KERN_DEBUG + "parport_serial: register_serial failed\n"); + continue; + } + priv->line[priv->num_ser++] = line; + success = 1; + } + + return success ? 0 : 1; +} + +/* Register the parallel port(s) of a PCI card. */ +static int __devinit parport_register (struct pci_dev *dev, + const struct pci_device_id *id) +{ + struct parport_serial_private *priv = pci_get_drvdata (dev); + int i = id->driver_data, n; + int success = 0; + + for (n = 0; n < cards[i].numports; n++) { + struct parport *port; + int lo = cards[i].addr[n].lo; + int hi = cards[i].addr[n].hi; + unsigned long io_lo, io_hi; + io_lo = pci_resource_start (dev, lo); + io_hi = 0; + if ((hi >= 0) && (hi <= 6)) + io_hi = pci_resource_start (dev, hi); + else if (hi > 6) + io_lo += hi; /* Reinterpret the meaning of + "hi" as an offset (see SYBA + def.) */ + /* TODO: test if sharing interrupts works */ + printk (KERN_DEBUG "PCI parallel port detected: %04x:%04x, " + "I/O at %#lx(%#lx)\n", + parport_serial_pci_tbl[i].vendor, + parport_serial_pci_tbl[i].device, io_lo, io_hi); + port = parport_pc_probe_port (io_lo, io_hi, PARPORT_IRQ_NONE, + PARPORT_DMA_NONE, dev); + if (port) { + priv->port[priv->num_par++] = port; + success = 1; + } + } + + return success ? 0 : 1; +} + +static int __devinit parport_serial_pci_probe (struct pci_dev *dev, + const struct pci_device_id *id) +{ + struct parport_serial_private *priv; + int err; + + priv = kmalloc (sizeof *priv, GFP_KERNEL); + if (!priv) + return -ENOMEM; + priv->num_ser = priv->num_par = 0; + pci_set_drvdata (dev, priv); + + err = pci_enable_device (dev); + if (err) { + pci_set_drvdata (dev, NULL); + kfree (priv); + return err; + } + + if (serial_register (dev, id) + parport_register (dev, id)) { + pci_set_drvdata (dev, NULL); + kfree (priv); + return -ENODEV; + } + + return 0; +} + +static void __devexit parport_serial_pci_remove (struct pci_dev *dev) +{ + struct parport_serial_private *priv = pci_get_drvdata (dev); + int i; + + // Serial ports + for (i = 0; i < priv->num_ser; i++) { + unregister_serial (priv->line[i]); + + if (priv->ser.init_fn) + (priv->ser.init_fn) (dev, &priv->ser, 0); + } + pci_set_drvdata (dev, NULL); + + // Parallel ports + for (i = 0; i < priv->num_par; i++) + parport_pc_unregister_port (priv->port[i]); + + kfree (priv); + return; +} + +static struct pci_driver parport_serial_pci_driver = { + name: "parport_serial", + id_table: parport_serial_pci_tbl, + probe: parport_serial_pci_probe, + remove: parport_serial_pci_remove, +}; + + +static int __init parport_serial_init (void) +{ + return pci_module_init (&parport_serial_pci_driver); +} + +static void __exit parport_serial_exit (void) +{ + pci_unregister_driver (&parport_serial_pci_driver); + return; +} + +MODULE_AUTHOR("Tim Waugh <twaugh@redhat.com>"); +MODULE_DESCRIPTION("Driver for common parallel+serial multi-I/O PCI cards"); + +module_init(parport_serial_init); +module_exit(parport_serial_exit); diff -u --recursive --new-file v2.4.6/linux/drivers/pci/pci.c linux/drivers/pci/pci.c --- v2.4.6/linux/drivers/pci/pci.c Tue Jul 3 17:08:20 2001 +++ linux/drivers/pci/pci.c Wed Jul 4 09:41:34 2001 @@ -279,7 +279,7 @@ * This doesn't affect PME_Status, disables PME_En, and * sets PowerState to 0. */ - if (dev->current_state == 3) + if (dev->current_state >= 3) pmcsr = 0; else { pci_read_config_word(dev, pm + PCI_PM_CTRL, &pmcsr); @@ -1175,6 +1175,9 @@ class >>= 8; DBG("Found %02x:%02x [%04x/%04x] %06x %02x\n", dev->bus->number, dev->devfn, dev->vendor, dev->device, class, dev->hdr_type); + + /* "Unknown power state" */ + dev->current_state = 4; switch (dev->hdr_type) { /* header type */ case PCI_HEADER_TYPE_NORMAL: /* standard header */ diff -u --recursive --new-file v2.4.6/linux/drivers/pcmcia/hd64465_ss.c linux/drivers/pcmcia/hd64465_ss.c --- v2.4.6/linux/drivers/pcmcia/hd64465_ss.c Thu Apr 12 12:16:35 2001 +++ linux/drivers/pcmcia/hd64465_ss.c Tue Jul 10 20:16:30 2001 @@ -681,7 +681,7 @@ hd64465_port_map( io->start, io->stop - io->start + 1, - vaddrbase + io->start); + vaddrbase + io->start,0); } else { hd64465_port_unmap( sio->start, diff -u --recursive --new-file v2.4.6/linux/drivers/pcmcia/rsrc_mgr.c linux/drivers/pcmcia/rsrc_mgr.c --- v2.4.6/linux/drivers/pcmcia/rsrc_mgr.c Tue Mar 6 19:28:32 2001 +++ linux/drivers/pcmcia/rsrc_mgr.c Sun Jul 15 16:22:23 2001 @@ -189,6 +189,10 @@ /* First, what does a floating port look like? */ b = kmalloc(256, GFP_KERNEL); + if (!b) { + printk(KERN_ERR "do_io_probe: unable to kmalloc 256 bytes"); + return; + } memset(b, 0, 256); for (i = base, most = 0; i < base+num; i += 8) { if (check_io_resource(i, 8)) diff -u --recursive --new-file v2.4.6/linux/drivers/pcmcia/yenta.c linux/drivers/pcmcia/yenta.c --- v2.4.6/linux/drivers/pcmcia/yenta.c Tue Jul 3 17:08:20 2001 +++ linux/drivers/pcmcia/yenta.c Wed Jul 4 14:41:33 2001 @@ -795,6 +795,8 @@ { PD(TI,1251B), &ti_ops }, { PD(TI,1410), &ti_ops }, { PD(TI,1420), &ti_ops }, + { PD(TI,4410), &ti_ops }, + { PD(TI,4451), &ti_ops }, { PD(RICOH,RL5C465), &ricoh_ops }, { PD(RICOH,RL5C466), &ricoh_ops }, diff -u --recursive --new-file v2.4.6/linux/drivers/pnp/isapnp.c linux/drivers/pnp/isapnp.c --- v2.4.6/linux/drivers/pnp/isapnp.c Wed Apr 18 11:49:11 2001 +++ linux/drivers/pnp/isapnp.c Wed Jul 4 14:41:33 2001 @@ -22,6 +22,9 @@ * Peter Denison <peterd@pnd-pc.demon.co.uk> * 2000-06-14 Added isapnp_probe_devs() and isapnp_activate_dev() * Christoph Hellwig <hch@caldera.de> + * 2001-06-03 Added release_region calls to correspond with + * request_region calls when a failure occurs. Also + * added KERN_* constants to printk() calls. */ #include <linux/config.h> @@ -407,7 +410,7 @@ *size = tag & 0x07; } #if 0 - printk("tag = 0x%x, type = 0x%x, size = %i\n", tag, *type, *size); + printk(KERN_DEBUG "tag = 0x%x, type = 0x%x, size = %i\n", tag, *type, *size); #endif if (type == 0) /* wrong type */ return -1; @@ -887,7 +890,7 @@ isapnp_skip_bytes(size); return 1; default: - printk("isapnp: unexpected or unknown tag type 0x%x for logical device %i (device %i), ignored\n", type, dev->devfn, card->number); + printk(KERN_ERR "isapnp: unexpected or unknown tag type 0x%x for logical device %i (device %i), ignored\n", type, dev->devfn, card->number); } __skip: if (size > 0) @@ -941,7 +944,7 @@ isapnp_skip_bytes(size); return; default: - printk("isapnp: unexpected or unknown tag type 0x%x for device %i, ignored\n", type, card->number); + printk(KERN_ERR "isapnp: unexpected or unknown tag type 0x%x for device %i, ignored\n", type, card->number); } __skip: if (size > 0) @@ -988,10 +991,10 @@ isapnp_peek(header, 9); checksum = isapnp_checksum(header); #if 0 - printk("vendor: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", + printk(KERN_DEBUG "vendor: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", header[0], header[1], header[2], header[3], header[4], header[5], header[6], header[7], header[8]); - printk("checksum = 0x%x\n", checksum); + printk(KERN_DEBUG "checksum = 0x%x\n", checksum); #endif /* Don't be strict on the checksum, here ! e.g. 'SCM SwapBox Plug and Play' has header[8]==0 (should be: b7)*/ @@ -1011,7 +1014,7 @@ INIT_LIST_HEAD(&card->devices); isapnp_parse_resource_map(card); if (isapnp_checksum_value != 0x00) - printk("isapnp: checksum for device %i is not valid (0x%x)\n", csn, isapnp_checksum_value); + printk(KERN_ERR "isapnp: checksum for device %i is not valid (0x%x)\n", csn, isapnp_checksum_value); card->checksum = isapnp_checksum_value; list_add_tail(&card->node, &isapnp_cards); @@ -2181,19 +2184,22 @@ if (isapnp_disable) { isapnp_detected = 0; - printk("isapnp: ISA Plug & Play support disabled\n"); + printk(KERN_INFO "isapnp: ISA Plug & Play support disabled\n"); return 0; } #ifdef ISAPNP_REGION_OK pidxr_res=request_region(_PIDXR, 1, "isapnp index"); if(!pidxr_res) { - printk("isapnp: Index Register 0x%x already used\n", _PIDXR); + printk(KERN_ERR "isapnp: Index Register 0x%x already used\n", _PIDXR); return -EBUSY; } #endif pnpwrp_res=request_region(_PNPWRP, 1, "isapnp write"); if(!pnpwrp_res) { - printk("isapnp: Write Data Register 0x%x already used\n", _PNPWRP); + printk(KERN_ERR "isapnp: Write Data Register 0x%x already used\n", _PNPWRP); +#ifdef ISAPNP_REGION_OK + release_region(_PIDXR, 1); +#endif return -EBUSY; } @@ -2202,12 +2208,16 @@ * so let the user know where. */ - printk("isapnp: Scanning for PnP cards...\n"); + printk(KERN_INFO "isapnp: Scanning for PnP cards...\n"); if (isapnp_rdp >= 0x203 && isapnp_rdp <= 0x3ff) { isapnp_rdp |= 3; isapnp_rdp_res=request_region(isapnp_rdp, 1, "isapnp read"); if(!isapnp_rdp_res) { - printk("isapnp: Read Data Register 0x%x already used\n", isapnp_rdp); + printk(KERN_ERR "isapnp: Read Data Register 0x%x already used\n", isapnp_rdp); +#ifdef ISAPNP_REGION_OK + release_region(_PIDXR, 1); +#endif + release_region(isapnp_rdp, 1); return -EBUSY; } isapnp_set_rdp(); @@ -2219,7 +2229,7 @@ (isapnp_rdp < 0x203 || isapnp_rdp > 0x3ff)) { isapnp_free_all_resources(); isapnp_detected = 0; - printk("isapnp: No Plug & Play device found\n"); + printk(KERN_INFO "isapnp: No Plug & Play device found\n"); return 0; } isapnp_rdp_res=request_region(isapnp_rdp, 1, "isapnp read"); @@ -2231,19 +2241,19 @@ cards++; if (isapnp_verbose) { struct list_head *devlist; - printk( "isapnp: Card '%s'\n", card->name[0]?card->name:"Unknown"); + printk(KERN_INFO "isapnp: Card '%s'\n", card->name[0]?card->name:"Unknown"); if (isapnp_verbose < 2) continue; for (devlist = card->devices.next; devlist != &card->devices; devlist = devlist->next) { struct pci_dev *dev = pci_dev_b(devlist); - printk("isapnp: Device '%s'\n", dev->name[0]?card->name:"Unknown"); + printk(KERN_INFO "isapnp: Device '%s'\n", dev->name[0]?card->name:"Unknown"); } } } if (cards) { - printk("isapnp: %i Plug & Play card%s detected total\n", cards, cards>1?"s":""); + printk(KERN_INFO "isapnp: %i Plug & Play card%s detected total\n", cards, cards>1?"s":""); } else { - printk("isapnp: No Plug & Play card found\n"); + printk(KERN_INFO "isapnp: No Plug & Play card found\n"); } #ifdef CONFIG_PROC_FS isapnp_proc_init(); diff -u --recursive --new-file v2.4.6/linux/drivers/s390/s390io.c linux/drivers/s390/s390io.c --- v2.4.6/linux/drivers/s390/s390io.c Wed Apr 11 19:02:29 2001 +++ linux/drivers/s390/s390io.c Wed Jul 4 11:50:39 2001 @@ -2157,6 +2157,7 @@ * Get interrupt info from lowcore */ volatile tpi_info_t *tpi_info = (tpi_info_t*)(__LC_SUBCHANNEL_ID); + int cpu = smp_processor_id(); /* * take fast exit if CPU is in sync. I/O state @@ -2182,7 +2183,9 @@ if ( tpi_info->adapter_IO == 1 && tpi_info->int_type == IO_INTERRUPT_TYPE ) { + irq_enter(cpu, -1); do_adapter_IO( tpi_info->intparm ); + irq_exit(cpu, -1); } else { @@ -2200,9 +2203,11 @@ return; /* this keeps the device boxed ... */ } + irq_enter(cpu, irq); s390irq_spin_lock( irq ); s390_process_IRQ( irq ); s390irq_spin_unlock( irq ); + irq_exit(cpu, irq); } #ifdef CONFIG_FAST_IRQ @@ -3166,8 +3171,11 @@ } /* endif */ - if ( rc ) // can only happen if stsch/msch fails + if ( rc ) /* can only happen if stsch/msch fails */ + { sync_isc_cnt = 0; + atomic_set( &sync_isc, -1); + } } else { @@ -4276,12 +4284,7 @@ { ret = enable_cpu_sync_isc( irq ); - if ( ret ) - { - free_irq( irq, &devstat ); - return; // fixme ! fast exit ... grr - } - else + if ( !ret ) { ioinfo[irq]->ui.flags.unknown = 0; @@ -5270,24 +5273,28 @@ } /* endif */ } - else if ( ret ) + else if ( ret == -EIO ) { - #ifdef CONFIG_DEBUG_IO - printk( "PathVerification(%04X) " - "- Device %04X doesn't " - " support path grouping\n", - irq, - ioinfo[irq]->schib.pmcw.dev); - + printk("PathVerification(%04X) - I/O error " + "on device %04X\n", irq, + ioinfo[irq]->schib.pmcw.dev); #endif - ioinfo[irq]->ui.flags.pgid_supp = 0; - + + } else { +#ifdef CONFIG_DEBUG_IO + printk( "PathVerification(%04X) " + "- Unexpected error on device %04X\n", + irq, + ioinfo[irq]->schib.pmcw.dev); +#endif + ioinfo[irq]->ui.flags.pgid_supp = 0; + } /* endif */ } /* endif */ - + } /* endfor */ } /* endif */ @@ -5442,9 +5449,9 @@ } /* endif */ } -#ifdef CONFIG_DEBUG_IO else { +#ifdef CONFIG_DEBUG_IO printk( "SPID - device %04X," " unit check," " retry %d, cnt %02d," @@ -5462,8 +5469,10 @@ pdevstat->ii.sense.data[6], pdevstat->ii.sense.data[7]); - } /* endif */ #endif + retry--; + + } /* endif */ } else if ( pdevstat->flag & DEVSTAT_NOT_OPER ) { @@ -5474,6 +5483,7 @@ irq); retry = 0; + irq_ret = -EIO; } /* endif */ } @@ -5489,6 +5499,12 @@ } while ( retry > 0 ); + if ( retry == 0 ) + { + irq_ret = -EIO; + + } /* endif */ + if ( init_IRQ_complete ) { kfree( spid_ccw ); @@ -5693,6 +5709,12 @@ } while ( retry > 0 ); + if ( retry == 0 ) + { + irq_ret = -EIO; + + } /* endif */ + if ( init_IRQ_complete ) { kfree( snid_ccw ); @@ -5936,7 +5958,10 @@ } } - do_reipl( 0x10000 | sch ); + if (MACHINE_IS_VM) + cpcmd("IPL", NULL, 0); + else + do_reipl( 0x10000 | sch ); } /* Display info on subchannels in /proc/subchannels. * diff -u --recursive --new-file v2.4.6/linux/drivers/sbus/char/aurora.c linux/drivers/sbus/char/aurora.c --- v2.4.6/linux/drivers/sbus/char/aurora.c Wed May 16 10:31:27 2001 +++ linux/drivers/sbus/char/aurora.c Fri Jul 6 16:46:22 2001 @@ -1,4 +1,4 @@ -/* $Id: aurora.c,v 1.13 2001/05/10 01:45:38 davem Exp $ +/* $Id: aurora.c,v 1.14 2001/06/29 23:07:37 davem Exp $ * linux/drivers/sbus/char/aurora.c -- Aurora multiport driver * * Copyright (c) 1999 by Oliver Aldulea (oli@bv.ro) @@ -1851,7 +1851,6 @@ static int aurora_set_modem_info(struct Aurora_port * port, unsigned int cmd, unsigned int *value) { - int error; unsigned int arg; unsigned long flags; struct Aurora_board *bp = port_Board(port); @@ -1860,9 +1859,8 @@ #ifdef AURORA_DEBUG printk("aurora_set_modem_info: start\n"); #endif - error = get_user(arg, value); - if (error) - return error; + if (get_user(arg, value)) + return -EFAULT; chip = AURORA_CD180(port_No(port)); switch (cmd) { case TIOCMBIS: @@ -1940,16 +1938,12 @@ struct Aurora_board *bp = port_Board(port); int change_speed; unsigned long flags; - int error; #ifdef AURORA_DEBUG printk("aurora_set_serial_info: start\n"); #endif - error = verify_area(VERIFY_READ, (void *) newinfo, sizeof(tmp)); - if (error) - return error; - copy_from_user(&tmp, newinfo, sizeof(tmp)); - + if (copy_from_user(&tmp, newinfo, sizeof(tmp))) + return -EFAULT; #if 0 if ((tmp.irq != bp->irq) || (tmp.port != bp->base) || @@ -2025,7 +2019,6 @@ { struct Aurora_port *port = (struct Aurora_port *) tty->driver_data; - int error; int retval; #ifdef AURORA_DEBUG @@ -2051,25 +2044,19 @@ aurora_send_break(port, arg ? arg*(HZ/10) : HZ/4); return 0; case TIOCGSOFTCAR: - error = verify_area(VERIFY_WRITE, (void *) arg, sizeof(long)); - if (error) - return error; - put_user(C_CLOCAL(tty) ? 1 : 0, - (unsigned long *) arg); - return 0; + return put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned long *)arg); case TIOCSSOFTCAR: - retval = get_user(arg,(unsigned long *) arg); - if (retval) - return retval; + if (get_user(arg,(unsigned long *)arg)) + return -EFAULT; tty->termios->c_cflag = ((tty->termios->c_cflag & ~CLOCAL) | (arg ? CLOCAL : 0)); return 0; case TIOCMGET: - error = verify_area(VERIFY_WRITE, (void *) arg, + retval = verify_area(VERIFY_WRITE, (void *) arg, sizeof(unsigned int)); - if (error) - return error; + if (retval) + return retval; return aurora_get_modem_info(port, (unsigned int *) arg); case TIOCMBIS: case TIOCMBIC: diff -u --recursive --new-file v2.4.6/linux/drivers/sbus/char/sunkbd.c linux/drivers/sbus/char/sunkbd.c --- v2.4.6/linux/drivers/sbus/char/sunkbd.c Mon Jan 22 13:30:20 2001 +++ linux/drivers/sbus/char/sunkbd.c Thu Jul 19 18:11:13 2001 @@ -115,12 +115,12 @@ * return the value. I chose the former way. */ #ifndef CONFIG_PCI -/*static*/ int shift_state; +int shift_state; +struct kbd_struct kbd_table[MAX_NR_CONSOLES]; #endif static int npadch = -1; /* -1 or number assembled on pad */ static unsigned char diacr; static char rep; /* flag telling character repeat */ -struct kbd_struct kbd_table[MAX_NR_CONSOLES]; static struct tty_struct **ttytab; static struct kbd_struct * kbd = kbd_table; static struct tty_struct * tty; @@ -789,7 +789,12 @@ set_leds(); } +#ifdef CONFIG_PCI +extern int spawnpid, spawnsig; +#else int spawnpid, spawnsig; +#endif + static void spawn_console(void) { diff -u --recursive --new-file v2.4.6/linux/drivers/scsi/BusLogic.c linux/drivers/scsi/BusLogic.c --- v2.4.6/linux/drivers/scsi/BusLogic.c Sat Nov 11 19:01:11 2000 +++ linux/drivers/scsi/BusLogic.c Thu Jul 5 11:28:16 2001 @@ -770,15 +770,19 @@ BusLogic_ModifyIOAddressRequest_T ModifyIOAddressRequest; unsigned char Bus = PCI_Device->bus->number; unsigned char Device = PCI_Device->devfn >> 3; - unsigned int IRQ_Channel = PCI_Device->irq; - unsigned long BaseAddress0 = pci_resource_start(PCI_Device, 0); - unsigned long BaseAddress1 = pci_resource_start(PCI_Device, 1); - BusLogic_IO_Address_T IO_Address = BaseAddress0; - BusLogic_PCI_Address_T PCI_Address = BaseAddress1; + unsigned int IRQ_Channel; + unsigned long BaseAddress0; + unsigned long BaseAddress1; + BusLogic_IO_Address_T IO_Address; + BusLogic_PCI_Address_T PCI_Address; if (pci_enable_device(PCI_Device)) continue; + IRQ_Channel = PCI_Device->irq; + IO_Address = BaseAddress0 = pci_resource_start(PCI_Device, 0); + PCI_Address = BaseAddress1 = pci_resource_start(PCI_Device, 1); + if (pci_resource_flags(PCI_Device, 0) & IORESOURCE_MEM) { BusLogic_Error("BusLogic: Base Address0 0x%X not I/O for " @@ -2547,7 +2551,7 @@ int SynchronousTransferRate = 0; if (BusLogic_FlashPointHostAdapterP(HostAdapter)) { - boolean WideTransfersActive; + unsigned char WideTransfersActive; FlashPoint_InquireTargetInfo( HostAdapter->CardHandle, TargetID, &HostAdapter->SynchronousPeriod[TargetID], diff -u --recursive --new-file v2.4.6/linux/drivers/scsi/BusLogic.h linux/drivers/scsi/BusLogic.h --- v2.4.6/linux/drivers/scsi/BusLogic.h Mon Dec 11 13:18:58 2000 +++ linux/drivers/scsi/BusLogic.h Thu Jul 19 21:07:57 2001 @@ -78,6 +78,7 @@ reset: BusLogic_ResetCommand, /* Reset Command Function */ \ bios_param: BusLogic_BIOSDiskParameters, /* BIOS Disk Parameters */ \ unchecked_isa_dma: 1, /* Default Initial Value */ \ + max_sectors: 128, /* I/O queue len limit */ \ use_clustering: ENABLE_CLUSTERING } /* Enable Clustering */ diff -u --recursive --new-file v2.4.6/linux/drivers/scsi/ChangeLog.ncr53c8xx linux/drivers/scsi/ChangeLog.ncr53c8xx --- v2.4.6/linux/drivers/scsi/ChangeLog.ncr53c8xx Tue Mar 6 19:34:25 2001 +++ linux/drivers/scsi/ChangeLog.ncr53c8xx Thu Jul 5 11:28:17 2001 @@ -1,3 +1,9 @@ +Sat May 12 12:00 2001 Gerard Roudier (groudier@club-internet.fr) + * version ncr53c8xx-3.4.3b + - Ensure LEDC bit in GPCNTL is cleared when reading the NVRAM. + Fix sent by Stig Telfer <stig@api-networks.com>. + - Define scsi_set_pci_device() as nil for kernel < 2.4.4. + Mon Feb 12 22:30 2001 Gerard Roudier (groudier@club-internet.fr) * version ncr53c8xx-3.4.3 - Call pci_enable_device() as AC wants this to be done. @@ -238,7 +244,7 @@ - Changes from Eddie Dost for Sparc and Alpha: ioremap/iounmap support for Sparc. pcivtophys changed to bus_dvma_to_phys. - - Add the 53c876 description to the chip table. This is only usefull + - Add the 53c876 description to the chip table. This is only useful for printing the right name of the controller. - DEL-441 Item 2 work-around for the 53c876 rev <= 5 (0x15). - Add additionnal checking of INQUIRY data: @@ -304,7 +310,7 @@ Sat Jun 20 20:00 1998 Gerard Roudier (groudier@club-internet.fr) * revision 3.0c - Add a boot setup option that allows to set up device queue depths - at boot-up. This option is very usefull since Linux does not + at boot-up. This option is very useful since Linux does not allow to change scsi device queue depth once the system has been booted up. @@ -333,7 +339,7 @@ kernel version >= 2.1.105. - Replace all printf(s) by printk(s). After all, the ncr53c8xx is a driver for Linux. - - Perform auto-sense on COMMAND TERMINATED. Not sure it is usefull. + - Perform auto-sense on COMMAND TERMINATED. Not sure it is useful. - Some other minor changes. Tue Jun 4 23:00 1998 Gerard Roudier (groudier@club-internet.fr) @@ -341,7 +347,7 @@ - Code cleanup and simplification: Remove kernel 1.2.X and 1.3.X support. Remove the _old_ target capabilities table. - Remove the error recovery code that have'nt been really usefull. + Remove the error recovery code that have'nt been really useful. Use a single alignment boundary (CACHE_LINE_SIZE) for data structures. - Several aggressive SCRIPTS optimizations and changes: diff -u --recursive --new-file v2.4.6/linux/drivers/scsi/ChangeLog.sym53c8xx linux/drivers/scsi/ChangeLog.sym53c8xx --- v2.4.6/linux/drivers/scsi/ChangeLog.sym53c8xx Tue Mar 6 19:34:25 2001 +++ linux/drivers/scsi/ChangeLog.sym53c8xx Thu Jul 5 11:28:16 2001 @@ -1,3 +1,24 @@ +Sat May 12 12:00 2001 Gerard Roudier (groudier@club-internet.fr) + * version sym53c8xx-1.7.3c + - Ensure LEDC bit in GPCNTL is cleared when reading the NVRAM. + Fix sent by Stig Telfer <stig@api-networks.com>. + - Backport from SYM-2 the work-around that allows to support + hardwares that fail PCI parity checking. + - Check that we received at least 8 bytes of INQUIRY response + for byte 7, that contains device capabilities, to be valid. + - Define scsi_set_pci_device() as nil for kernel < 2.4.4. + - + A couple of minor changes. + +Sat Apr 7 19:30 2001 Gerard Roudier (groudier@club-internet.fr) + * version sym53c8xx-1.7.3b + - Fix an unaligned LOAD from scripts (was used as dummy read). + - In ncr_soft_reset(), only try to ABORT the current operation + for chips that support SRUN bit in ISTAT1 and if SCRIPTS are + currently running, as 896 and 1010 manuals suggest. + - In the CCB abort path, donnot assume that the CCB is currently + queued to SCRIPTS. This is not always true, notably after a + QUEUE FULL status or when using untagged commands. + Sun Mar 4 18:30 2001 Gerard Roudier (groudier@club-internet.fr) * version sym53c8xx-1.7.3a - Fix an issue in the ncr_int_udc() (unexpected disconnect) @@ -338,7 +359,7 @@ Tue Apr 15 10:00 1999 Gerard Roudier (groudier@club-internet.fr) * version sym53c8xx-1.3e - Support for any number of LUNs (64) (SPI2-compliant). - (Btw, this may only be ever usefull under linux-2.2 ;-)) + (Btw, this may only be ever useful under linux-2.2 ;-)) Sun Apr 11 10:00 1999 Gerard Roudier (groudier@club-internet.fr) * version sym53c8xx-1.3d diff -u --recursive --new-file v2.4.6/linux/drivers/scsi/Config.in linux/drivers/scsi/Config.in --- v2.4.6/linux/drivers/scsi/Config.in Sun Mar 4 14:30:18 2001 +++ linux/drivers/scsi/Config.in Thu Jul 5 11:28:16 2001 @@ -101,7 +101,7 @@ fi fi if [ "$CONFIG_X86" = "y" ]; then - dep_tristate 'IBM ServeRAID support' CONFIG_SCSI_IPS $CONFIG_SCSI + dep_tristate 'IBM ServeRAID support' CONFIG_SCSI_IPS $CONFIG_SCSI $CONFIG_PCI fi dep_tristate 'Initio 9100U(W) support' CONFIG_SCSI_INITIO $CONFIG_SCSI $CONFIG_PCI dep_tristate 'Initio INI-A100U2W support' CONFIG_SCSI_INIA100 $CONFIG_SCSI $CONFIG_PCI @@ -196,6 +196,30 @@ fi if [ "$CONFIG_MIPS_JAZZ" = "y" ]; then bool 'MIPS JAZZ FAS216 SCSI support' CONFIG_JAZZ_ESP +fi + +if [ "$CONFIG_AMIGA" = "y" ]; then + dep_tristate 'A3000 WD33C93A support' CONFIG_A3000_SCSI $CONFIG_SCSI + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + bool 'A4000T SCSI support (EXPERIMENTAL)' CONFIG_A4000T_SCSI + fi +fi +if [ "$CONFIG_ZORRO" = "y" ]; then + dep_tristate 'A2091/A590 WD33C93A support' CONFIG_A2091_SCSI $CONFIG_SCSI + dep_tristate 'GVP Series II WD33C93A support' CONFIG_GVP11_SCSI $CONFIG_SCSI + dep_tristate 'CyberStorm SCSI support' CONFIG_CYBERSTORM_SCSI $CONFIG_SCSI + dep_tristate 'CyberStorm Mk II SCSI support' CONFIG_CYBERSTORMII_SCSI $CONFIG_SCSI + dep_tristate 'Blizzard 2060 SCSI support' CONFIG_BLZ2060_SCSI $CONFIG_SCSI + dep_tristate 'Blizzard 1230IV/1260 SCSI support' CONFIG_BLZ1230_SCSI $CONFIG_SCSI + dep_tristate 'Fastlane SCSI support' CONFIG_FASTLANE_SCSI $CONFIG_SCSI + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + bool 'A4091 SCSI support (EXPERIMENTAL)' CONFIG_A4091_SCSI + bool 'WarpEngine SCSI support (EXPERIMENTAL)' CONFIG_WARPENGINE_SCSI + bool 'Blizzard PowerUP 603e+ SCSI (EXPERIMENTAL)' CONFIG_BLZ603EPLUS_SCSI + dep_tristate 'BSC Oktagon SCSI support (EXPERIMENTAL)' CONFIG_OKTAGON_SCSI $CONFIG_SCSI +# bool 'Cyberstorm Mk III SCSI support (EXPERIMENTAL)' CONFIG_CYBERSTORMIII_SCSI +# bool 'GVP Turbo 040/060 SCSI support (EXPERIMENTAL)' CONFIG_GVP_TURBO_SCSI + fi fi endmenu diff -u --recursive --new-file v2.4.6/linux/drivers/scsi/FlashPoint.c linux/drivers/scsi/FlashPoint.c --- v2.4.6/linux/drivers/scsi/FlashPoint.c Mon Aug 17 01:01:01 1998 +++ linux/drivers/scsi/FlashPoint.c Thu Jul 5 11:28:16 2001 @@ -629,7 +629,7 @@ #if (FW_TYPE==_UCB_MGR_) #define HBA_AUTO_SENSE_FAIL 0x1B #define HBA_TQ_REJECTED 0x1C - #define HBA_UNSUPORTED_MSG 0x1D + #define HBA_UNSUPPORTED_MSG 0x1D #define HBA_HW_ERROR 0x20 #define HBA_ATN_NOT_RESPONDED 0x21 #define HBA_SCSI_RESET_BY_ADAPTER 0x22 diff -u --recursive --new-file v2.4.6/linux/drivers/scsi/README.aic7xxx linux/drivers/scsi/README.aic7xxx --- v2.4.6/linux/drivers/scsi/README.aic7xxx Wed Dec 31 16:00:00 1969 +++ linux/drivers/scsi/README.aic7xxx Thu Jul 5 11:28:17 2001 @@ -0,0 +1,477 @@ + AIC7xxx Driver for Linux + +Introduction +---------------------------- +The AIC7xxx SCSI driver adds support for Adaptec (http://www.adaptec.com) +SCSI controllers and chipsets. Major portions of the driver and driver +development are shared between both Linux and FreeBSD. Support for the +AIC-7xxx chipsets have been in the default Linux kernel since approximately +linux-1.1.x and fairly stable since linux-1.2.x, and are also in FreeBSD +2.1.0 or later. + + Supported cards/chipsets + ---------------------------- + Adaptec Cards + ---------------------------- + AHA-274x + AHA-274xT + AHA-274xW + AHA-284x + AHA-284xW + All PCI based cards using any of the chipsets listed under motherboard + chipsets. In general, this means *all* of the Adaptec SCSI controllers + except the ones specifically excluded later on in this document. + + Motherboard Chipsets + ---------------------------- + AIC-777x + AIC-785x + AIC-786x + AIC-787x + AIC-788x + AIC-789x + AIC-3860 + + Bus Types + ---------------------------- + W - Wide SCSI, SCSI-3, 16bit bus, 68pin connector, will also support + SCSI-1/SCSI-2 50pin devices, transfer rates up to 20MB/s. + U - Ultra SCSI, transfer rates up to 40MB/s. + U2- Ultra 2 SCSI, transfer rates up to 80MB/s. + U3- Ultra 3 SCSI, transfer rates up to 160MB/s. + D - Differential SCSI. + T - Twin Channel SCSI. Up to 14 SCSI devices. + + AHA-274x - EISA SCSI controller + AHA-284x - VLB SCSI controller + AHA-29xx - PCI SCSI controller + AHA-39xx - PCI controllers with multiple separate SCSI channels on-board. + + Not Supported Devices + ------------------------------ + Adaptec Cards + ---------------------------- + AHA-2920 (Only the cards that use the Future Domain chipset are not + supported, any 2920 cards based on Adaptec AIC chipsets, + such as the 2920C, are supported) + AAA-13x Raid Adapters + AAA-113x Raid Port Card + + Motherboard Chipsets + ---------------------------- + AIC-781x + + Bus Types + ---------------------------- + R - Raid Port busses are not supported. + + The hardware RAID devices sold by Adaptec are *NOT* supported by this + driver (and will people please stop emailing me about them, they are + a totally separate beast from the bare SCSI controllers and this driver + can not be retrofitted in any sane manner to support the hardware RAID + features on those cards - Doug Ledford). + + + People + ------------------------------ + Justin T Gibbs gibbs@plutotech.com + (BSD Driver Author) + Dan Eischen deischen@iworks.InterWorks.org + (Original Linux Driver Co-maintainer) + Dean Gehnert deang@teleport.com + (Original Linux FTP/patch maintainer) + Jess Johnson jester@frenzy.com + (AIC7xxx FAQ author) + Doug Ledford dledford@redhat.com + (Current Linux aic7xxx-5.x.x Driver/Patch/FTP maintainer) + + Special thanks go to John Aycock (aycock@cpsc.ucalgary.ca), the original + author of the driver. John has since retired from the project. Thanks + again for all his work! + + Mailing list + ------------------------------ + There is a mailing list available for users who want to track development + and converse with other users and developers. This list is for both + FreeBSD and Linux support of the AIC7xxx chipsets. + + To subscribe to the AIC7xxx mailing list send mail to the list server, + with "subscribe AIC7xxx" in the body (no Subject: required): + To: majordomo@FreeBSD.ORG + --- + subscribe AIC7xxx + + To unsubscribe from the list, send mail to the list server with: + To: majordomo@FreeBSD.ORG + --- + unsubscribe AIC7xxx + + Send regular messages and replies to: AIC7xxx@FreeBSD.ORG + + Boot Command line options + ------------------------------ + "aic7xxx=no_reset" - Eliminate the SCSI bus reset during startup. + Some SCSI devices need the initial reset that this option disables + in order to work. If you have problems at bootup, please make sure + you aren't using this option. + + "aic7xxx=reverse_scan" - Certain PCI motherboards scan for devices at + bootup by scanning from the highest numbered PCI device to the + lowest numbered PCI device, others do just the opposite and scan + from lowest to highest numbered PCI device. There is no reliable + way to autodetect this ordering. So, we default to the most common + order, which is lowest to highest. Then, in case your motherboard + scans from highest to lowest, we have this option. If your BIOS + finds the drives on controller A before controller B but the linux + kernel finds your drives on controller B before A, then you should + use this option. + + "aic7xxx=extended" - Force the driver to detect extended drive translation + on your controller. This helps those people who have cards without + a SEEPROM make sure that linux and all other operating systems think + the same way about your hard drives. + + "aic7xxx=scbram" - Some cards have external SCB RAM that can be used to + give the card more hardware SCB slots. This allows the driver to use + that SCB RAM. Without this option, the driver won't touch the SCB + RAM because it is known to cause problems on a few cards out there + (such as 3985 class cards). + + "aic7xxx=irq_trigger:x" - Replace x with either 0 or 1 to force the kernel + to use the correct IRQ type for your card. This only applies to EISA + based controllers. On these controllers, 0 is for Edge triggered + interrupts, and 1 is for Level triggered interrupts. If you aren't + sure or don't know which IRQ trigger type your EISA card uses, then + let the kernel autodetect the trigger type. + + "aic7xxx=verbose" - This option can be used in one of two ways. If you + simply specify aic7xxx=verbose, then the kernel will automatically + pick the default set of verbose messages for you to see. + Alternatively, you can specify the command as + "aic7xxx=verbose:0xXXXX" where the X entries are replaced with + hexadecimal digits. This option is a bit field type option. For + a full listing of the available options, search for the + #define VERBOSE_xxxxxx lines in the aic7xxx.c file. If you want + verbose messages, then it is recommended that you simply use the + aic7xxx=verbose variant of this command. + + "aic7xxx=pci_parity:x" - This option controls whether or not the driver + enables PCI parity error checking on the PCI bus. By default, this + checking is disabled. To enable the checks, simply specify pci_parity + with no value afterwords. To reverse the parity from even to odd, + supply any number other than 0 or 255. In short: + pci_parity - Even parity checking (even is the normal PCI parity) + pci_parity:x - Where x > 0, Odd parity checking + pci_parity:0 - No check (default) + NOTE: In order to get Even PCI parity checking, you must use the + version of the option that does not include the : and a number at + the end (unless you want to enter exactly 2^32 - 1 as the number). + + "aic7xxx=no_probe" - This option will disable the probing for any VLB + based 2842 controllers and any EISA based controllers. This is + needed on certain newer motherboards where the normal EISA I/O ranges + have been claimed by other PCI devices. Probing on those machines + will often result in the machine crashing or spontaneously rebooting + during startup. Examples of machines that need this are the + Dell PowerEdge 6300 machines. + + "aic7xxx=seltime:2" - This option controls how long the card waits + during a device selection sequence for the device to respond. + The original SCSI spec says that this "should be" 256ms. This + is generally not required with modern devices. However, some + very old SCSI I devices need the full 256ms. Most modern devices + can run fine with only 64ms. The default for this option is + 64ms. If you need to change this option, then use the following + table to set the proper value in the example above: + 0 - 256ms + 1 - 128ms + 2 - 64ms + 3 - 32ms + + "aic7xxx=panic_on_abort" - This option is for debugging and will cause + the driver to panic the linux kernel and freeze the system the first + time the drivers abort or reset routines are called. This is most + helpful when some problem causes infinite reset loops that scroll too + fast to see. By using this option, you can write down what the errors + actually are and send that information to me so it can be fixed. + + "aic7xxx=dump_card" - This option will print out the *entire* set of + configuration registers on the card during the init sequence. This + is a debugging aid used to see exactly what state the card is in + when we finally finish our initialization routines. If you don't + have documentation on the chipsets, this will do you absolutely + no good unless you are simply trying to write all the information + down in order to send it to me. + + "aic7xxx=dump_sequencer" - This is the same as the above options except + that instead of dumping the register contents on the card, this + option dumps the contents of the sequencer program RAM. This gives + the ability to verify that the instructions downloaded to the + card's sequencer are indeed what they are suppossed to be. Again, + unless you have documentation to tell you how to interpret these + numbers, then it is totally useless. + + "aic7xxx=override_term:0xffffffff" - This option is used to force the + termination on your SCSI controllers to a particular setting. This + is a bit mask variable that applies for up to 8 aic7xxx SCSI channels. + Each channel gets 4 bits, divided as follows: + bit 3 2 1 0 + | | | Enable/Disable Single Ended Low Byte Termination + | | En/Disable Single Ended High Byte Termination + | En/Disable Low Byte LVD Termination + En/Disable High Byte LVD Termination + + The upper 2 bits that deal with LVD termination only apply to Ultra2 + controllers. Futhermore, due to the current Ultra2 controller + designs, these bits are tied together such that setting either bit + enables both low and high byte LVD termination. It is not possible + to only set high or low byte LVD termination in this manner. This is + an artifact of the BIOS definition on Ultra2 controllers. For other + controllers, the only important bits are the two lowest bits. Setting + the higher bits on non-Ultra2 controllers has no effect. A few + examples of how to use this option: + + Enable low and high byte termination on a non-ultra2 controller that + is the first aic7xxx controller (the correct bits are 0011), + aic7xxx=override_term:0x3 + + Enable all termination on the third aic7xxx controller, high byte + termination on the second aic7xxx controller, and low and high byte + SE termination on the first aic7xxx controller + (bits are 1111 0010 0011), + aic7xxx=override_term:0xf23 + + No attempt has been made to make this option non-cryptic. It really + shouldn't be used except in dire circumstances, and if that happens, + I'm probably going to be telling you what to set this to anyway :) + + "aic7xxx=stpwlev:0xffffffff" - This option is used to control the STPWLEV + bit in the DEVCONFIG PCI register. Currently, this is one of the + very few registers that we have absolutely *no* way of detecting + what the variable should be. It depends entirely on how the chipset + and external terminators were coupled by the card/motherboard maker. + Further, a chip reset (at power up) always sets this bit to 0. If + there is no BIOS to run on the chipset/card (such as with a 2910C + or a motherboard controller with the BIOS totally disabled) then + the variable may not get set properly. Of course, if the proper + setting was 0, then that's what it would be after the reset, but if + the proper setting is actually 1.....you get the picture. Now, since + we can't detect this at all, I've added this option to force the + setting. If you have a BIOS on your controller then you should never + need to use this option. However, if you are having lots of SCSI + reset problems and can't seem to get them knocked out, this may help. + + Here's a test to know for certain if you need this option. Make + a boot floppy that you can use to boot your computer up and that + will detect the aic7xxx controller. Next, power down your computer. + While it's down, unplug all SCSI cables from your Adaptec SCSI + controller. Boot the system back up to the Adaptec EZ-SCSI BIOS + and then make sure that termination is enabled on your adapter (if + you have an Adaptec BIOS of course). Next, boot up the floppy you + made and wait for it to detect the aic7xxx controller. If the kernel + finds the controller fine, says scsi : x hosts and then tries to + detect your devices like normal, up to the point where it fails to + mount your root file system and panics, then you're fine. If, on + the other hand, the system goes into an infinite reset loop, then + you need to use this option and/or the previous option to force the + proper termination settings on your controller. If this happens, + then you next need to figure out what your settings should be. + + To find the correct settings, power your machine back down, connect + back up the SCSI cables, and boot back into your machine like normal. + However, boot with the aic7xxx=verbose:0x39 option. Record the + initial DEVCONFIG values for each of your aic7xxx controllers as + they are listed, and also record what the machine is detecting as + the proper termination on your controllers. NOTE: the order in + which the initial DEVCONFIG values are printed out is not gauranteed + to be the same order as the SCSI controllers are registered. The + above option and this option both work on the order of the SCSI + controllers as they are registered, so make sure you match the right + DEVCONFIG values with the right controllers if you have more than + one aic7xxx controller. + + Once you have the detected termination settings and the initial + DEVCONFIG values for each controller, then figure out what the + termination on each of the controllers *should* be. Hopefully, that + part is correct, but it could possibly be wrong if there is + bogus cable detection logic on your controller or something similar. + If all the controllers have the correct termination settings, then + don't set the aic7xxx=override_term variable at all, leave it alone. + Next, on any controllers that go into an infinite reset loop when + you unplug all the SCSI cables, get the starting DEVCONFIG value. + If the initial DEVCONFIG value is divisible by 2, then the correct + setting for that controller is 0. If it's an odd number, then + the correct setting for that controller is 1. For any other + controllers that didn't have an infinite reset problem, then reverse + the above options. If DEVCONFIG was even, then the correct setting + is 1, if not then the correct setting is 0. + + Now that you know what the correct setting was for each controller, + we need to encode that into the aic7xxx=stpwlev:0x... variable. + This variable is a bit field encoded variable. Bit 0 is for the first + aic7xxx controller, bit 1 for the next, etc. Put all these bits + together and you get a number. For example, if the third aic7xxx + needed a 1, but the second and first both needed a 0, then the bits + would be 100 in binary. This then translates to 0x04. You would + therefore set aic7xxx=stpwlev:0x04. This is fairly standard binary + to hexadecimal conversions here. If you aren't up to speed on the + binary->hex conversion then send an email to the aic7xxx mailing + list and someone can help you out. + + "aic7xxx=tag_info:{{8,8..},{8,8..},..}" - This option is used to disable + or enable Tagged Command Queueing (TCQ) on specific devices. As of + driver version 5.1.11, TCQ is now either on or off by default + according to the setting you choose during the make config process. + In order to en/disable TCQ for certian devices at boot time, a user + may use this boot param. The driver will then parse this message out + and en/disable the specific device entries that are present based upon + the value given. The param line is parsed in the following manner: + + { - first instance indicates the start of this parameter values + second instance is the start of entries for a particular + device entry + } - end the entries for a particular host adapter, or end the entire + set of parameter entries + , - move to next entry. Inside of a set of device entries, this + moves us to the next device on the list. Outside of device + entries, this moves us to the next host adapter + . - Same effect as , but is safe to use with insmod. + x - the number to enter into the array at this position. + 0 = Enable tagged queueing on this device and use the default + queue depth + 1-254 = Enable tagged queueing on this device and use this + number as the queue depth + 255 = Disable tagged queueing on this device. + Note: anything above 32 for an actual queue depth is wasteful + and not recommended. + + A few examples of how this can be used: + + tag_info:{{8,12,,0,,255,4}} + This line will only effect the first aic7xxx card registered. It + will set scsi id 0 to a queue depth of 8, id 1 to 12, leave id 2 + at the default, set id 3 to tagged queueing enabled and use the + default queue depth, id 4 default, id 5 disabled, and id 6 to 4. + Any not specified entries stay at the default value, repeated + commas with no value specified will simply increment to the next id + without changing anything for the missing values. + + tag_info:{,,,{,,,255}} + First, second, and third adapters at default values. Fourth + adapter, id 3 is disabled. Notice that leading commas simply + increment what the first number effects, and there are no need + for trailing commas. When you close out an adapter, or the + entire entry, anything not explicitly set stays at the default + value. + + A final note on this option. The scanner I used for this isn't + perfect or highly robust. If you mess the line up, the worst that + should happen is that the line will get ignored. If you don't + close out the entire entry with the final bracket, then any other + aic7xxx options after this will get ignored. So, in general, be + sure of what you are entering, and after you have it right, just + add it to the lilo.conf file so there won't be any mistakes. As + a means of checking this parser, the entire tag_info array for + each card is now printed out in the /proc/scsi/aic7xxx/x file. You + can use that to verify that your options were parsed correctly. + + Boot command line options may be combined to form the proper set of options + a user might need. For example, the following is valid: + + aic7xxx=verbose,extended,irq_trigger:1 + + The only requirement is that individual options be separated by a comma or + a period on the command line. + + Module Loading command options + ------------------------------ + When loading the aic7xxx driver as a module, the exact same options are + available to the user. However, the syntax to specify the options changes + slightly. For insmod, you need to wrap the aic7xxx= argument in quotes + and replace all ',' with '.'. So, for example, a valid insmod line + would be: + + insmod aic7xxx aic7xxx='verbose.irq_trigger:1.extended' + + This line should result in the *exact* same behaviour as if you typed + it in at the lilo prompt and the driver was compiled into the kernel + instead of being a module. The reason for the single quote is so that + the shell won't try to interpret anything in the line, such as {. + Insmod assumes any options starting with a letter instead of a number + is a character string (which is what we want) and by switching all of + the commas to periods, insmod won't interpret this as more than one + string and write junk into our binary image. I consider it a bug in + the insmod program that even if you wrap your string in quotes (quotes + that pass the shell mind you and that insmod sees) it still treates + a comma inside of those quotes as starting a new variable, resulting + in memory scribbles if you don't switch the commas to periods. + + + Kernel Compile options + ------------------------------ + The various kernel compile time options for this driver are now fairly + well documented in the file Documentation/Configure.help. In order to + see this documentation, you need to use one of the advanced configuration + programs (menuconfig and xconfig). If you are using the "make menuconfig" + method of configuring your kernel, then you would simply highlight the + option in question and hit the ? key. If you are using the "make xconfig" + method of configuring your kernel, then simply click on the help button + next to the option you have questions about. The help information from + the Configure.help file will then get automatically displayed. + + /proc support + ------------------------------ + The /proc support for the AIC7xxx can be found in the /proc/scsi/aic7xxx/ + directory. That directory contains a file for each SCSI controller in + the system. Each file presents the current configuration and transfer + statistics (enabled with #define in aic7xxx.c) for each controller. + + Thanks to Michael Neuffer for his upper-level SCSI help, and + Matthew Jacob for statistics support. + + Debugging the driver + ------------------------------ + Should you have problems with this driver, and would like some help in + getting them solved, there are a couple debugging items built into + the driver to facilitate getting the needed information from the system. + In general, I need a complete description of the problem, with as many + logs as possible concerning what happens. To help with this, there is + a command option aic7xxx=panic_on_abort. This option, when set, forces + the driver to panic the kernel on the first SCSI abort issued by the + mid level SCSI code. If your system is going to reset loops and you + can't read the screen, then this is what you need. Not only will it + stop the system, but it also prints out a large amount of state + information in the process. Second, if you specify the option + "aic7xxx=verbose:0x1ffff", the system will print out *SOOOO* much + information as it runs that you won't be able to see anything. + However, this can actually be very useful if your machine simply + locks up when trying to boot, since it will pin-point what was last + happening (in regards to the aic7xxx driver) immediately prior to + the lockup. This is really only useful if your machine simply can + not boot up successfully. If you can get your machine to run, then + this will produce far too much information. + + FTP sites + ------------------------------ + ftp://ftp.redhat.com/pub/aic/ + - Out of date. I used to keep stuff here, but too many people + complained about having a hard time getting into Red Hat's ftp + server. So use the web site below instead. + ftp://ftp.pcnet.com/users/eischen/Linux/ + - Dan Eischen's driver distribution area + ftp://ekf2.vsb.cz/pub/linux/kernel/aic7xxx/ftp.teleport.com/ + - European Linux mirror of Teleport site + + Web sites + ------------------------------ + http://people.redhat.com/dledford/ + - My web site, also the primary aic7xxx site with several related + pages. + +Dean W. Gehnert +deang@teleport.com + +$Revision: 3.0 $ + +Modified by Doug Ledford 1998-2000 + diff -u --recursive --new-file v2.4.6/linux/drivers/scsi/README.ncr53c8xx linux/drivers/scsi/README.ncr53c8xx --- v2.4.6/linux/drivers/scsi/README.ncr53c8xx Mon Jun 19 17:59:41 2000 +++ linux/drivers/scsi/README.ncr53c8xx Thu Jul 5 11:28:17 2001 @@ -508,7 +508,7 @@ clearprof The profile counters are automatically cleared when the amount of - data transfered reaches 1000 GB in order to avoid overflow. + data transferred reaches 1000 GB in order to avoid overflow. The "clearprof" command allows you to clear these counters at any time. @@ -1042,7 +1042,7 @@ The use of IARB needs the SCSI_NCR_IARB_SUPPORT option to have been defined at compile time and the 'iarb' boot option to have been set to a non zero -value at boot time. It is not that usefull for real work, but can be used +value at boot time. It is not that useful for real work, but can be used to stress SCSI devices or for some applications that can gain advantage of it. By the way, if you experience badnesses like 'unexpected disconnections', 'bad reselections', etc... when using IARB on heavy IO load, you should not @@ -1350,7 +1350,7 @@ Bit 0x04 : UDC Undexpected Disconnection Indicates that the device released the SCSI BUS when the chip was not expecting this to happen. A device may behave so to - indicate the SCSI initiator that an error condition not reportable using the SCSI protocol has occured. + indicate the SCSI initiator that an error condition not reportable using the SCSI protocol has occurred. Bit 0x02 : RST SCSI BUS Reset Generally SCSI targets donnot reset the SCSI BUS, although any device on the BUS can reset it at any time. diff -u --recursive --new-file v2.4.6/linux/drivers/scsi/aha152x.c linux/drivers/scsi/aha152x.c --- v2.4.6/linux/drivers/scsi/aha152x.c Tue Jul 3 17:08:20 2001 +++ linux/drivers/scsi/aha152x.c Sun Jul 15 16:22:23 2001 @@ -238,6 +238,7 @@ #include <linux/interrupt.h> #include <linux/init.h> #include <linux/kernel.h> +#include <linux/isapnp.h> #include <asm/semaphore.h> #include <linux/spinlock.h> @@ -385,6 +386,16 @@ MODULE_PARM_DESC(aha152x1, "parameters for second controller"); static int aha152x1[] = {0, 11, 7, 1, 1, 1, DELAY_DEFAULT, 0, DEBUG_DEFAULT}; #endif /* !defined(AHA152X_DEBUG) */ + +#ifdef __ISAPNP__ + +static struct isapnp_device_id id_table[] __devinitdata = { + { ISAPNP_DEVICE_SINGLE('A','D','P',0x1505, 'A','D','P',0x1505), }, + { ISAPNP_DEVICE_SINGLE_END, } +}; +MODULE_DEVICE_TABLE(isapnp, id_table); + +#endif /* ISAPNP */ #endif /* MODULE */ /* set by aha152x_setup according to the command line */ @@ -940,12 +951,18 @@ SETPORT(DMACNTRL0, INTEN); } - +#ifdef __ISAPNP__ +static struct pci_dev *pnpdev[2]; +static int num_pnpdevs; +#endif int aha152x_detect(Scsi_Host_Template * tpnt) { int i, j, ok; #if defined(AUTOCONF) aha152x_config conf; +#ifdef __ISAPNP__ + struct pci_dev *dev = NULL; +#endif #endif tpnt->proc_name = "aha152x"; @@ -962,6 +979,29 @@ } printk("ok\n"); } +#ifdef __ISAPNP__ + while (setup_count <= 2 && + (dev = isapnp_find_dev (NULL, ISAPNP_VENDOR('A','D','P'), + ISAPNP_FUNCTION(0x1505), dev))) { + if (dev->prepare(dev) < 0) + continue; + if (dev->active) + continue; + if (!(dev->resource[0].flags & IORESOURCE_IO)) + continue; + dev->resource[0].flags |= IORESOURCE_AUTO; + if (dev->activate(dev) < 0) + continue; + setup[setup_count].io_port = dev->resource[0].start; + setup[setup_count].irq = dev->irq_resource[0].start; + pnpdev[num_pnpdevs++] = dev; + printk (KERN_INFO + "aha152x: found ISAPnP AVA-1505A at address 0x%03X, IRQ %d\n", + setup[setup_count].io_port, setup[setup_count].irq); + setup_count++; + } +#endif + #if defined(SETUP0) if (setup_count < 2) { struct aha152x_setup override = SETUP0; @@ -1349,6 +1389,10 @@ if (shpnt->io_port) release_region(shpnt->io_port, IO_RANGE); +#ifdef __ISAPNP__ + while (num_pnpdevs--) + pnpdev[num_pnpdevs]->deactivate(pnpdev[num_pnpdevs]); +#endif scsi_unregister(shpnt); return 0; diff -u --recursive --new-file v2.4.6/linux/drivers/scsi/aic7xxx/aic7xxx_linux_pci.c linux/drivers/scsi/aic7xxx/aic7xxx_linux_pci.c --- v2.4.6/linux/drivers/scsi/aic7xxx/aic7xxx_linux_pci.c Fri May 4 15:16:28 2001 +++ linux/drivers/scsi/aic7xxx/aic7xxx_linux_pci.c Thu Jul 5 11:28:16 2001 @@ -42,9 +42,13 @@ static int ahc_linux_pci_dev_probe(struct pci_dev *pdev, const struct pci_device_id *ent); #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) +#include <linux/module.h> + static void ahc_linux_pci_dev_remove(struct pci_dev *pdev); -/* We do our own ID filtering. So, grab all SCSI storage class devices. */ +/* We do our own ID filtering. So we grab all Adaptec SCSI storage class + * devices here. + */ static struct pci_device_id ahc_linux_pci_id_table[] = { { 0x9004, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, @@ -56,6 +60,7 @@ }, { 0 } }; +MODULE_DEVICE_TABLE(pci,ahc_linux_pci_id_table); struct pci_driver aic7xxx_pci_driver = { name: "aic7xxx", diff -u --recursive --new-file v2.4.6/linux/drivers/scsi/aic7xxx_old/README.aic7xxx linux/drivers/scsi/aic7xxx_old/README.aic7xxx --- v2.4.6/linux/drivers/scsi/aic7xxx_old/README.aic7xxx Sun Mar 4 14:30:18 2001 +++ linux/drivers/scsi/aic7xxx_old/README.aic7xxx Thu Jul 5 11:28:16 2001 @@ -478,10 +478,10 @@ information in the process. Second, if you specify the option "aic7xxx=verbose:0x1ffff", the system will print out *SOOOO* much information as it runs that you won't be able to see anything. - However, this can actually be very usefull if your machine simply + However, this can actually be very useful if your machine simply locks up when trying to boot, since it will pin-point what was last happening (in regards to the aic7xxx driver) immediately prior to - the lockup. This is really only usefull if your machine simply can + the lockup. This is really only useful if your machine simply can not boot up successfully. If you can get your machine to run, then this will produce far too much information. diff -u --recursive --new-file v2.4.6/linux/drivers/scsi/aic7xxx_old/aic7xxx.reg linux/drivers/scsi/aic7xxx_old/aic7xxx.reg --- v2.4.6/linux/drivers/scsi/aic7xxx_old/aic7xxx.reg Fri Apr 6 10:51:19 2001 +++ linux/drivers/scsi/aic7xxx_old/aic7xxx.reg Thu Jul 5 11:28:17 2001 @@ -703,7 +703,12 @@ * it that it can fill the * message buffer. */ - mask TRACEPOINT 0xb0|SEQINT + mask SEQ_SG_FIXUP 0xb0|SEQINT /* need help with fixing up + * the sg array pointer after + * a phasemis with no valid + * sg elements in the shadow + * pipeline. + */ mask TRACEPOINT2 0xc0|SEQINT mask MSGIN_PHASEMIS 0xd0|SEQINT /* * Target changed phase on us diff -u --recursive --new-file v2.4.6/linux/drivers/scsi/aic7xxx_old/aic7xxx.seq linux/drivers/scsi/aic7xxx_old/aic7xxx.seq --- v2.4.6/linux/drivers/scsi/aic7xxx_old/aic7xxx.seq Fri Apr 6 10:51:19 2001 +++ linux/drivers/scsi/aic7xxx_old/aic7xxx.seq Thu Jul 5 11:28:17 2001 @@ -332,12 +332,15 @@ /* clear target specific flags */ clr SEQ_FLAGS ret; + +data_phase_reinit: /* * If we re-enter the data phase after going through another phase, the * STCNT may have been cleared, so restore it from the residual field. + * On Ultra2, we have to put it into the HCNT field because we have to + * drop the data down into the shadow layer via the preload ability. */ -data_phase_reinit: - if ((p->features & AHC_ULTRA2) != 0) { + if ((p->features & AHC_ULTRA2) != 0) { bmov HADDR, SHADDR, 4; bmov HCNT, SCB_RESID_DCNT, 3; } @@ -349,27 +352,24 @@ mvi SCB_RESID_DCNT call bcopy_3; } jmp data_phase_loop; - p_data: - if ((p->features & AHC_ULTRA2) != 0) { + if ((p->features & AHC_ULTRA2) != 0) { mvi DMAPARAMS, PRELOADEN|SCSIEN|HDMAEN; } else { mvi DMAPARAMS, WIDEODD|SCSIEN|SDMAEN|HDMAEN|FIFORESET; } test LASTPHASE, IOI jnz . + 2; or DMAPARAMS, DIRECTION; - call assert; /* - * Ensure entering a data - * phase is okay - seen identify, etc. - */ + call assert; /* + * Ensure entering a data + * phase is okay - seen identify, etc. + */ if ((p->features & AHC_CMD_CHAN) != 0) { mvi CCSGADDR, CCSGADDR_MAX; } - test SEQ_FLAGS, DPHASE jnz data_phase_reinit; - - /* We have seen a data phase */ - or SEQ_FLAGS, DPHASE; + test SEQ_FLAGS, DPHASE jnz data_phase_reinit; + or SEQ_FLAGS, DPHASE; /* we've seen a data phase */ /* * Initialize the DMA address and counter from the SCB. * Also set SG_COUNT and SG_NEXT in memory since we cannot @@ -378,8 +378,10 @@ */ if ((p->features & AHC_CMD_CHAN) != 0) { bmov HADDR, SCB_DATAPTR, 7; - bmov STCNT, HCNT, 3; bmov SG_COUNT, SCB_SGCOUNT, 5; + if ((p->features & AHC_ULTRA2) == 0) { + bmov STCNT, HCNT, 3; + } } else { mvi DINDEX, HADDR; mvi SCB_DATAPTR call bcopy_7; @@ -387,9 +389,8 @@ mvi DINDEX, SG_COUNT; mvi SCB_SGCOUNT call bcopy_5; } - data_phase_loop: -/* Guard against overruns */ + /* Guard against overruns */ test SG_COUNT, 0xff jnz data_phase_inbounds; /* * Turn on 'Bit Bucket' mode, set the transfer count to @@ -399,66 +400,62 @@ */ or SXFRCTL1,BITBUCKET; and DMAPARAMS, ~(HDMAEN|SDMAEN); - if ((p->features & AHC_CMD_CHAN) != 0) { - if ((p->features & AHC_ULTRA2) != 0) { - bmov HCNT, ALLONES, 3; - } + if ((p->features & AHC_ULTRA2) != 0) { + bmov HCNT, ALLONES, 3; + } + if ((p->chip & AHC_CHIPID_MASK) == AHC_AIC7895) { bmov STCNT, ALLONES, 3; - } else { + } + if ((p->features & AHC_CMD_CHAN) == 0) { mvi STCNT[0], 0xFF; mvi STCNT[1], 0xFF; mvi STCNT[2], 0xFF; } + data_phase_inbounds: /* If we are the last SG block, tell the hardware. */ - cmp SG_COUNT,0x01 jne data_phase_wideodd; - if ((p->features & AHC_ULTRA2) == 0) { - and DMAPARAMS, ~WIDEODD; + if ((p->features & AHC_ULTRA2) != 0) { + shl A, 2, SG_COUNT; + cmp SG_COUNT,0x01 jne data_phase_wideodd; + or A, LAST_SEG; } else { - mvi SG_CACHEPTR, LAST_SEG; + cmp SG_COUNT,0x01 jne data_phase_wideodd; + and DMAPARAMS, ~WIDEODD; } data_phase_wideodd: - if ((p->features & AHC_ULTRA2) != 0) { - mov SINDEX, ALLONES; - mov DFCNTRL, DMAPARAMS; - test SSTAT0, SDONE jnz .; -data_phase_dma_loop: - test SSTAT0, SDONE jnz data_phase_dma_done; - test SSTAT1,PHASEMIS jz data_phase_dma_loop; /* ie. underrun */ -data_phase_dma_phasemis: - test SSTAT0,SDONE jnz data_phase_dma_done; - clr SINDEX; /* Remember the phasemiss */ + if ((p->features & AHC_ULTRA2) != 0) { + mov SG_CACHEPTR, A; + mov DFCNTRL, DMAPARAMS; /* start the operation */ + test SXFRCTL1, BITBUCKET jnz data_phase_overrun; +u2_preload_wait: + test SSTAT1, PHASEMIS jnz u2_phasemis; + test DFSTATUS, PRELOAD_AVAIL jz u2_preload_wait; } else { mov DMAPARAMS call dma; - } - data_phase_dma_done: /* Go tell the host about any overruns */ - test SXFRCTL1,BITBUCKET jnz data_phase_overrun; + test SXFRCTL1,BITBUCKET jnz data_phase_overrun; /* Exit if we had an underrun. dma clears SINDEX in this case. */ - test SINDEX,0xff jz data_phase_finish; - + test SINDEX,0xff jz data_phase_finish; + } /* - * Advance the scatter-gather pointers if needed + * Advance the scatter-gather pointers */ sg_advance: - dec SG_COUNT; /* one less segment to go */ + if ((p->features & AHC_ULTRA2) != 0) { + cmp SG_COUNT, 0x01 je u2_data_phase_finish; + } else { + dec SG_COUNT; + test SG_COUNT, 0xff jz data_phase_finish; + } - test SG_COUNT, 0xff jz data_phase_finish; /* Are we done? */ -/* - * Load a struct scatter and set up the data address and length. - * If the working value of the SG count is nonzero, then - * we need to load a new set of values. - * - * This, like all DMA's, assumes little-endian host data storage. - */ -sg_load: if ((p->features & AHC_CMD_CHAN) != 0) { + /* * Do we have any prefetch left??? */ - cmp CCSGADDR, CCSGADDR_MAX jne prefetched_segs_avail; + cmp CCSGADDR, CCSGADDR_MAX jne prefetch_avail; /* * Fetch MIN(CCSGADDR_MAX, (SG_COUNT * 8)) bytes. @@ -474,10 +471,12 @@ and CCSGCTL, ~CCSGEN; test CCSGCTL, CCSGEN jnz .; mvi CCSGCTL, CCSGRESET; -prefetched_segs_avail: +prefetch_avail: bmov HADDR, CCSGRAM, 8; if ((p->features & AHC_ULTRA2) == 0) { bmov STCNT, HCNT, 3; + } else { + dec SG_COUNT; } } else { mvi DINDEX, HADDR; @@ -491,30 +490,63 @@ call dma_finish; - /* - * Copy data from FIFO into SCB data pointer and data count. - * This assumes that the SG segments are of the form: - * struct ahc_dma_seg { - * u_int32_t addr; four bytes, little-endian order - * u_int32_t len; four bytes, little endian order - * }; - */ - mvi HADDR call dfdat_in_7; +/* + * Copy data from FIFO into SCB data pointer and data count. + * This assumes that the SG segments are of the form: + * struct ahc_dma_seg { + * u_int32_t addr; four bytes, little-endian order + * u_int32_t len; four bytes, little endian order + * }; + */ + mvi DINDEX, HADDR; + call dfdat_in_7; call set_stcnt_from_hcnt; } - /* Advance the SG pointer */ - clr A; /* add sizeof(struct scatter) */ + clr A; /* add sizeof(struct scatter) */ add SG_NEXT[0],SG_SIZEOF; adc SG_NEXT[1],A; - test SSTAT1, REQINIT jz .; - test SSTAT1,PHASEMIS jz data_phase_loop; + if ((p->features & AHC_ULTRA2) != 0) { + jmp data_phase_loop; + } else { + test SSTAT1, REQINIT jz .; + test SSTAT1,PHASEMIS jz data_phase_loop; + } + -/* This drops the last SG segment down to the shadow layer for us */ +/* + * We've loaded all of our segments into the preload layer. Now, we simply + * have to wait for it to finish or for us to get a phasemis. And, since + * we'll get a phasemis if we do finish, all we really need to do is wait + * for a phasemis then check if we did actually complete all the segments. + */ if ((p->features & AHC_ULTRA2) != 0) { - mov DFCNTRL, DMAPARAMS; - test SSTAT0, SDONE jnz .; +u2_data_phase_finish: + test SSTAT1, PHASEMIS jnz u2_phasemis; + test SG_CACHEPTR, LAST_SEG_DONE jz u2_data_phase_finish; + clr SG_COUNT; + test SSTAT1, REQINIT jz .; + test SSTAT1, PHASEMIS jz data_phase_loop; +u2_phasemis: + call ultra2_dmafinish; + test SG_CACHEPTR, LAST_SEG_DONE jnz data_phase_finish; + test SSTAT2, SHVALID jnz u2_fixup_residual; + mvi INTSTAT, SEQ_SG_FIXUP; + jmp data_phase_finish; +u2_fixup_residual: + shr ARG_1, 2, SG_CACHEPTR; +u2_phasemis_loop: + and A, 0x3f, SG_COUNT; + cmp ARG_1, A je data_phase_finish; +/* + * Subtract SG_SIZEOF from the SG_NEXT pointer and add 1 to the SG_COUNT + */ + clr A; + add SG_NEXT[0], -SG_SIZEOF; + adc SG_NEXT[1], 0xff; + inc SG_COUNT; + jmp u2_phasemis_loop; } data_phase_finish: @@ -523,64 +555,83 @@ * We use STCNT instead of HCNT, since it's a reflection of how many bytes * were transferred on the SCSI (as opposed to the host) bus. */ - if ((p->features & AHC_ULTRA2) != 0) { - call ultra2_dmafinish; - } - if ((p->features & AHC_ULTRA2) == 0) { - if ((p->features & AHC_CMD_CHAN) != 0) { - bmov SCB_RESID_DCNT, STCNT, 3; - mov SCB_RESID_SGCNT, SG_COUNT; - } else { - mov SCB_RESID_DCNT[0],STCNT[0]; - mov SCB_RESID_DCNT[1],STCNT[1]; - mov SCB_RESID_DCNT[2],STCNT[2]; - mov SCB_RESID_SGCNT, SG_COUNT; + if ((p->features & AHC_CMD_CHAN) != 0) { + bmov SCB_RESID_DCNT, STCNT, 3; + mov SCB_RESID_SGCNT, SG_COUNT; + if ((p->features & AHC_ULTRA2) != 0) { + or SXFRCTL0, CLRSTCNT|CLRCHN; } + } else { + mov SCB_RESID_DCNT[0],STCNT[0]; + mov SCB_RESID_DCNT[1],STCNT[1]; + mov SCB_RESID_DCNT[2],STCNT[2]; + mov SCB_RESID_SGCNT, SG_COUNT; } jmp ITloop; data_phase_overrun: - if ((p->features & AHC_ULTRA2) != 0) { - call ultra2_dmafinish; - } /* * Turn off BITBUCKET mode and notify the host */ + if ((p->features & AHC_ULTRA2) != 0) { +/* + * Wait for the target to quit transferring data on the SCSI bus + */ + test SSTAT1, PHASEMIS jz .; + call ultra2_dmafinish; + } and SXFRCTL1, ~BITBUCKET; mvi INTSTAT,DATA_OVERRUN; jmp ITloop; -ultra2_dmafinish: + + + +/* + * Actually turn off the DMA hardware, save our current position into the + * proper residual variables, wait for the next REQ signal, then jump to + * the ITloop. Jumping to the ITloop ensures that if we happen to get + * brought into the data phase again (or are still in it after our last + * segment) that we will properly signal an overrun to the kernel. + */ if ((p->features & AHC_ULTRA2) != 0) { +ultra2_dmafinish: test DFCNTRL, DIRECTION jnz ultra2_dmahalt; and DFCNTRL, ~SCSIEN; test DFCNTRL, SCSIEN jnz .; + if ((p->bugs & AHC_BUG_AUTOFLUSH) != 0) { + or DFCNTRL, FIFOFLUSH; + } ultra2_dmafifoflush: - or DFCNTRL, FIFOFLUSH; - test DFSTATUS, FIFOEMP jz . - 1; - /* - * hardware bug alert! This needless set of jumps is to - * protect against a FIFOEMP status bit glitch in the - * silicon. - */ - test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush; - test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush; - test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush; - test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush; + if ((p->bugs & AHC_BUG_AUTOFLUSH) != 0) { + /* + * hardware bug alert! This needless set of jumps + * works around a glitch in the silicon. When the + * PCI DMA fifo goes empty, but there is still SCSI + * data to be flushed into the PCI DMA fifo (and from + * there on into main memory), the FIFOEMP bit will + * come on between the time when the PCI DMA buffer + * went empty and the next bit of data is copied from + * the SCSI fifo into the PCI fifo. It should only + * come on when both FIFOs (meaning the entire FIFO + * chain) are emtpy. Since it can take up to 4 cycles + * for new data to be copied from the SCSI fifo into + * the PCI fifo, testing for FIFOEMP status for 4 + * extra times gives the needed time for any + * remaining SCSI fifo data to be put in the PCI fifo + * before we declare it *truly* empty. + */ + test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush; + test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush; + test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush; + test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush; + } test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush; test DFSTATUS, MREQPEND jnz .; ultra2_dmahalt: - test SCSIOFFSET, 0x7f jnz ultra2_shutdown; -ultra2_await_nreq: - test SCSISIGI, REQI jz ultra2_shutdown; - test SSTAT1, (PHASEMIS|REQINIT) jz ultra2_await_nreq; -ultra2_shutdown: and DFCNTRL, ~(HDMAEN|SCSIEN); test DFCNTRL, (HDMAEN|SCSIEN) jnz .; - bmov SCB_RESID_DCNT, STCNT, 3; - mov SCB_RESID_SGCNT, SG_COUNT; - or SXFRCTL0, CLRSTCNT|CLRCHN; ret; } @@ -1021,6 +1072,7 @@ inb_last: mov NONE,SCSIDATL ret; /*dummy read from latch to ACK*/ + mesgin_phasemis: /* * We expected to receive another byte, but the target changed phase @@ -1080,7 +1132,9 @@ * to drain the data fifo until there is space for the input * latch to drain and HDMAEN de-asserts. */ - mov NONE, DFDAT; + if ((p->bugs & AHC_BUG_PCI_2_1_RETRY) != 0) { + mov NONE, DFDAT; + } test DFCNTRL, (SCSIEN|SDMAEN|HDMAEN) jnz dma_halt; } return: @@ -1306,20 +1360,30 @@ cmp CCSCBCTL, CCSCBDONE|ARRDONE|CCARREN|CCSCBEN|CCSCBDIR jne .; jmp dma_scb_finish; dma_scb_tohost: - if ((p->chip & AHC_CHIPID_MASK) == AHC_AIC7895) { + if ((p->features & AHC_ULTRA2) == 0) { mvi CCSCBCTL, CCSCBRESET; bmov CCSCBRAM, SCB_CONTROL, 32; or CCSCBCTL, CCSCBEN|CCSCBRESET; test CCSCBCTL, CCSCBDONE jz .; - } else { - mvi CCSCBCTL, CCARREN|CCSCBEN|CCSCBRESET; - cmp CCSCBCTL, CCSCBDONE|ARRDONE|CCARREN|CCSCBEN jne .; + } + if ((p->features & AHC_ULTRA2) != 0) { + if ((p->bugs & AHC_BUG_SCBCHAN_UPLOAD) != 0) { + mvi CCSCBCTL, CCARREN|CCSCBRESET; + cmp CCSCBCTL, ARRDONE|CCARREN jne .; + mvi CCHCNT, 32; + mvi CCSCBCTL, CCSCBEN|CCSCBRESET; + cmp CCSCBCTL, CCSCBDONE|CCSCBEN jne .; + } else { + mvi CCSCBCTL, CCARREN|CCSCBEN|CCSCBRESET; + cmp CCSCBCTL, CCSCBDONE|ARRDONE|CCARREN|CCSCBEN jne .; + } } dma_scb_finish: clr CCSCBCTL; test CCSCBCTL, CCARREN|CCSCBEN jnz .; ret; - } else { + } + if ((p->features & AHC_CMD_CHAN) == 0) { mvi DINDEX, HADDR; mvi HSCB_ADDR call set_32byte_addr; mvi HCNT[0], 32; @@ -1342,17 +1406,81 @@ mov DFDAT,SINDIR; cmp SINDEX, A jne copy_scb_tofifo_loop; or DFCNTRL, HDMAEN|FIFOFLUSH; + jmp dma_finish; dma_scb_fromhost: - call dma_finish; - /* If we were putting the SCB, we are done */ - test DMAPARAMS, DIRECTION jz return; - mvi SCB_CONTROL call dfdat_in_7; - call dfdat_in_7_continued; - call dfdat_in_7_continued; - jmp dfdat_in_7_continued; + mvi DINDEX, SCB_CONTROL; + if ((p->bugs & AHC_BUG_PCI_2_1_RETRY) != 0) { + /* + * Set the A to -24. It it hits 0, then we let + * our code fall through to dfdat_in_8 to complete + * the last of the copy. + * + * Also, things happen 8 bytes at a time in this + * case, so we may need to drain the fifo at most + * 3 times to keep things flowing + */ + mvi A, -24; +dma_scb_hang_fifo: + /* Wait for the first bit of data to hit the fifo */ + test DFSTATUS, FIFOEMP jnz .; +dma_scb_hang_wait: + /* OK, now they've started to transfer into the fifo, + * so wait for them to stop trying to transfer any + * more data. + */ + test DFSTATUS, MREQPEND jnz .; + /* + * OK, they started, then they stopped, now see if they + * managed to complete the job before stopping. Try + * it multiple times to give the chip a few cycles to + * set the flag if it did complete. + */ + test DFSTATUS, HDONE jnz dma_scb_hang_dma_done; + test DFSTATUS, HDONE jnz dma_scb_hang_dma_done; + test DFSTATUS, HDONE jnz dma_scb_hang_dma_done; + /* + * Too bad, the chip didn't complete the DMA, but there + * aren't any more memory requests pending, so that + * means it stopped part way through and hung. That's + * our bug, so now we drain what data there is in the + * fifo in order to get things going again. + */ +dma_scb_hang_empty_fifo: + call dfdat_in_8; + add A, 8; + add SINDEX, A, HCNT; + /* + * If there are another 8 bytes of data waiting in the + * fifo, then the carry bit will be set as a result + * of the above add command (unless A is non-negative, + * in which case the carry bit won't be set). + */ + jc dma_scb_hang_empty_fifo; + /* + * We've emptied the fifo now, but we wouldn't have got + * here if the memory transfer hadn't stopped part way + * through, so go back up to the beginning of the + * loop and start over. When it succeeds in getting + * all the data down, HDONE will be set and we'll + * jump to the code just below here. + */ + jmp dma_scb_hang_fifo; +dma_scb_hang_dma_done: + and DFCNTRL, ~HDMAEN; + test DFCNTRL, HDMAEN jnz .; + call dfdat_in_8; + add A, 8; + cmp A, 8 jne . - 2; + ret; + } else { + call dma_finish; + call dfdat_in_8; + call dfdat_in_8; + call dfdat_in_8; + } +dfdat_in_8: + mov DINDIR,DFDAT; dfdat_in_7: - mov DINDEX,SINDEX; -dfdat_in_7_continued: mov DINDIR,DFDAT; mov DINDIR,DFDAT; mov DINDIR,DFDAT; diff -u --recursive --new-file v2.4.6/linux/drivers/scsi/aic7xxx_old/aic7xxx_proc.c linux/drivers/scsi/aic7xxx_old/aic7xxx_proc.c --- v2.4.6/linux/drivers/scsi/aic7xxx_old/aic7xxx_proc.c Sun Mar 4 14:30:19 2001 +++ linux/drivers/scsi/aic7xxx_old/aic7xxx_proc.c Thu Jul 5 11:28:17 2001 @@ -162,7 +162,7 @@ size += sprintf(BLS, "%s", AIC7XXX_H_VERSION); size += sprintf(BLS, "\n"); size += sprintf(BLS, "Compile Options:\n"); -#ifdef CONFIG_AIC7XXX_OLD_TCQ_ON_BY_DEFAULT +#ifdef CONFIG_AIC7XXX_TCQ_ON_BY_DEFAULT size += sprintf(BLS, " TCQ Enabled By Default : Enabled\n"); #else size += sprintf(BLS, " TCQ Enabled By Default : Disabled\n"); diff -u --recursive --new-file v2.4.6/linux/drivers/scsi/aic7xxx_old/aic7xxx_reg.h linux/drivers/scsi/aic7xxx_old/aic7xxx_reg.h --- v2.4.6/linux/drivers/scsi/aic7xxx_old/aic7xxx_reg.h Sun Mar 4 14:30:19 2001 +++ linux/drivers/scsi/aic7xxx_old/aic7xxx_reg.h Thu Jul 5 11:28:17 2001 @@ -188,8 +188,8 @@ #define BRDRW 0x04 #define BRDRW_ULTRA2 0x02 #define BRDCTL1 0x02 -#define BRDCTL0 0x01 #define BRDSTB_ULTRA2 0x01 +#define BRDCTL0 0x01 #define SEECTL 0x1e #define EXTARBACK 0x80 @@ -397,7 +397,7 @@ #define DATA_OVERRUN 0xe1 #define MSGIN_PHASEMIS 0xd1 #define TRACEPOINT2 0xc1 -#define TRACEPOINT 0xb1 +#define SEQ_SG_FIXUP 0xb1 #define AWAITING_MSG 0xa1 #define RESIDUAL 0x81 #define BAD_STATUS 0x71 @@ -465,8 +465,6 @@ #define TARGCRCENDEN 0x08 #define TARGCRCCNTEN 0x04 -#define QOUTCNT 0x9e - #define SCSIPHASE 0x9e #define SP_STATUS 0x20 #define SP_COMMAND 0x10 @@ -475,6 +473,8 @@ #define SP_DATA_IN 0x02 #define SP_DATA_OUT 0x01 +#define QOUTCNT 0x9e + #define SFUNCT 0x9f #define ALT_MODE 0x80 @@ -595,8 +595,8 @@ #define RD_DFTHRSH_63 0x03 #define RD_DFTHRSH_50 0x02 #define RD_DFTHRSH_25 0x01 -#define RD_DFTHRSH_MIN 0x00 #define WR_DFTHRSH_MIN 0x00 +#define RD_DFTHRSH_MIN 0x00 #define SG_CACHEPTR 0xfc #define SG_USER_DATA 0xfc @@ -604,18 +604,18 @@ #define LAST_SEG_DONE 0x01 -#define CMD_GROUP_CODE_SHIFT 0x05 -#define BUS_8_BIT 0x00 -#define QOUTFIFO_OFFSET 0x01 -#define CCSGRAM_MAXSEGS 0x10 #define CMD_GROUP2_BYTE_DELTA 0xfa #define MAX_OFFSET_8BIT 0x0f #define BUS_16_BIT 0x01 #define QINFIFO_OFFSET 0x02 #define CMD_GROUP5_BYTE_DELTA 0x0b +#define CMD_GROUP_CODE_SHIFT 0x05 #define MAX_OFFSET_ULTRA2 0x7f #define MAX_OFFSET_16BIT 0x08 +#define BUS_8_BIT 0x00 +#define QOUTFIFO_OFFSET 0x01 #define UNTAGGEDSCB_OFFSET 0x00 +#define CCSGRAM_MAXSEGS 0x10 #define SCB_LIST_NULL 0xff #define SG_SIZEOF 0x08 #define CMD_GROUP4_BYTE_DELTA 0x04 diff -u --recursive --new-file v2.4.6/linux/drivers/scsi/aic7xxx_old/aic7xxx_seq.c linux/drivers/scsi/aic7xxx_old/aic7xxx_seq.c --- v2.4.6/linux/drivers/scsi/aic7xxx_old/aic7xxx_seq.c Sun Mar 4 14:30:19 2001 +++ linux/drivers/scsi/aic7xxx_old/aic7xxx_seq.c Thu Jul 5 11:28:17 2001 @@ -25,12 +25,12 @@ 0x00, 0x4d, 0x10, 0x70, 0x01, 0x4e, 0x9c, 0x18, 0xbf, 0x60, 0xc0, 0x08, - 0x00, 0x6a, 0x3e, 0x5c, + 0x00, 0x6a, 0x86, 0x5c, 0xff, 0x4e, 0xc8, 0x18, - 0x02, 0x6a, 0x54, 0x5b, + 0x02, 0x6a, 0x70, 0x5b, 0xff, 0x52, 0x20, 0x09, 0x0d, 0x6a, 0x6a, 0x00, - 0x00, 0x52, 0xca, 0x5b, + 0x00, 0x52, 0xe6, 0x5b, 0x03, 0xb0, 0x52, 0x31, 0xff, 0xb0, 0x52, 0x09, 0xff, 0xb1, 0x54, 0x09, @@ -87,13 +87,13 @@ 0x08, 0x6a, 0x66, 0x58, 0x80, 0x6a, 0x68, 0x00, 0x80, 0x36, 0x6c, 0x00, - 0x00, 0x65, 0x9e, 0x5b, + 0x00, 0x65, 0xba, 0x5b, 0xff, 0x3d, 0xc8, 0x08, 0xbf, 0x64, 0xe2, 0x78, - 0x80, 0x64, 0xac, 0x71, - 0xa0, 0x64, 0xdc, 0x71, - 0xc0, 0x64, 0xd4, 0x71, - 0xe0, 0x64, 0x1c, 0x72, + 0x80, 0x64, 0xc8, 0x71, + 0xa0, 0x64, 0xf8, 0x71, + 0xc0, 0x64, 0xf0, 0x71, + 0xe0, 0x64, 0x38, 0x72, 0x01, 0x6a, 0x22, 0x01, 0x00, 0x65, 0xaa, 0x40, 0xf7, 0x11, 0x22, 0x08, @@ -113,24 +113,24 @@ 0x03, 0xa9, 0x18, 0x31, 0x03, 0xa9, 0x10, 0x30, 0x08, 0x6a, 0xcc, 0x00, - 0xa9, 0x6a, 0xb4, 0x5b, + 0xa9, 0x6a, 0xd0, 0x5b, 0x00, 0x65, 0x02, 0x41, 0xa8, 0x6a, 0x6a, 0x00, 0x79, 0x6a, 0x6a, 0x00, 0x40, 0x3d, 0xea, 0x68, 0x04, 0x35, 0x6a, 0x00, - 0x00, 0x65, 0x0e, 0x5b, + 0x00, 0x65, 0x2a, 0x5b, 0x80, 0x6a, 0xd4, 0x01, 0x10, 0x36, 0xd6, 0x68, 0x10, 0x36, 0x6c, 0x00, 0x07, 0xac, 0x10, 0x31, - 0x03, 0x8c, 0x10, 0x30, 0x05, 0xa3, 0x70, 0x30, + 0x03, 0x8c, 0x10, 0x30, 0x88, 0x6a, 0xcc, 0x00, - 0xac, 0x6a, 0xac, 0x5b, - 0x00, 0x65, 0xa6, 0x5b, + 0xac, 0x6a, 0xc8, 0x5b, + 0x00, 0x65, 0xc2, 0x5b, 0x38, 0x6a, 0xcc, 0x00, - 0xa3, 0x6a, 0xb0, 0x5b, + 0xa3, 0x6a, 0xcc, 0x5b, 0xff, 0x38, 0x12, 0x69, 0x80, 0x02, 0x04, 0x00, 0xe7, 0x35, 0x6a, 0x08, @@ -139,334 +139,348 @@ 0xff, 0x6a, 0x10, 0x00, 0xff, 0x6a, 0x12, 0x00, 0xff, 0x6a, 0x14, 0x00, - 0x01, 0x38, 0x18, 0x61, + 0x22, 0x38, 0xc8, 0x28, + 0x01, 0x38, 0x1c, 0x61, + 0x02, 0x64, 0xc8, 0x00, + 0x01, 0x38, 0x1c, 0x61, 0xbf, 0x35, 0x6a, 0x08, - 0x02, 0x6a, 0xf8, 0x01, - 0xff, 0x69, 0xca, 0x08, + 0xff, 0x64, 0xf8, 0x09, 0xff, 0x35, 0x26, 0x09, - 0x04, 0x0b, 0x1c, 0x69, - 0x04, 0x0b, 0x28, 0x69, - 0x10, 0x0c, 0x1e, 0x79, - 0x04, 0x0b, 0x28, 0x69, - 0xff, 0x6a, 0xca, 0x08, - 0x00, 0x35, 0xee, 0x5a, - 0x80, 0x02, 0x7c, 0x69, - 0xff, 0x65, 0x6c, 0x79, + 0x80, 0x02, 0xa4, 0x69, + 0x10, 0x0c, 0x7a, 0x69, + 0x80, 0x94, 0x22, 0x79, + 0x00, 0x35, 0x0a, 0x5b, + 0x80, 0x02, 0xa4, 0x69, + 0xff, 0x65, 0x94, 0x79, + 0x01, 0x38, 0x70, 0x71, 0xff, 0x38, 0x70, 0x18, - 0xff, 0x38, 0x6c, 0x79, - 0x80, 0xea, 0x48, 0x61, + 0xff, 0x38, 0x94, 0x79, + 0x80, 0xea, 0x4a, 0x61, 0xef, 0x38, 0xc8, 0x18, 0x80, 0x6a, 0xc8, 0x00, - 0x00, 0x65, 0x3a, 0x49, + 0x00, 0x65, 0x3c, 0x49, 0x33, 0x38, 0xc8, 0x28, 0xff, 0x64, 0xd0, 0x09, 0x04, 0x39, 0xc0, 0x31, 0x09, 0x6a, 0xd6, 0x01, - 0x80, 0xeb, 0x40, 0x79, + 0x80, 0xeb, 0x42, 0x79, 0xf7, 0xeb, 0xd6, 0x09, - 0x08, 0xeb, 0x44, 0x69, + 0x08, 0xeb, 0x46, 0x69, 0x01, 0x6a, 0xd6, 0x01, 0x08, 0xe9, 0x10, 0x31, 0x03, 0x8c, 0x10, 0x30, + 0xff, 0x38, 0x70, 0x18, 0x88, 0x6a, 0xcc, 0x00, - 0x39, 0x6a, 0xb2, 0x5b, + 0x39, 0x6a, 0xce, 0x5b, 0x08, 0x6a, 0x18, 0x01, 0xff, 0x6a, 0x1a, 0x09, 0xff, 0x6a, 0x1c, 0x09, 0x0d, 0x93, 0x26, 0x01, - 0x00, 0x65, 0x30, 0x5c, - 0x88, 0x6a, 0x20, 0x5c, - 0x00, 0x65, 0xa6, 0x5b, + 0x00, 0x65, 0x78, 0x5c, + 0x88, 0x6a, 0xcc, 0x00, + 0x00, 0x65, 0x6a, 0x5c, + 0x00, 0x65, 0xc2, 0x5b, 0xff, 0x6a, 0xc8, 0x08, 0x08, 0x39, 0x72, 0x18, 0x00, 0x3a, 0x74, 0x20, - 0x01, 0x0c, 0x64, 0x79, + 0x00, 0x65, 0x02, 0x41, + 0x01, 0x0c, 0x6c, 0x79, 0x10, 0x0c, 0x02, 0x79, - 0xff, 0x35, 0x26, 0x09, - 0x04, 0x0b, 0x6a, 0x69, - 0x00, 0x65, 0x84, 0x59, + 0x10, 0x0c, 0x7a, 0x69, + 0x01, 0xfc, 0x70, 0x79, + 0xff, 0x6a, 0x70, 0x08, + 0x01, 0x0c, 0x76, 0x79, + 0x10, 0x0c, 0x02, 0x79, + 0x00, 0x65, 0xae, 0x59, + 0x01, 0xfc, 0x94, 0x69, + 0x40, 0x0d, 0x84, 0x69, + 0xb1, 0x6a, 0x22, 0x01, + 0x00, 0x65, 0x94, 0x41, + 0x2e, 0xfc, 0xa2, 0x28, + 0x3f, 0x38, 0xc8, 0x08, + 0x00, 0x51, 0x94, 0x71, + 0xff, 0x6a, 0xc8, 0x08, + 0xf8, 0x39, 0x72, 0x18, + 0xff, 0x3a, 0x74, 0x20, + 0x01, 0x38, 0x70, 0x18, + 0x00, 0x65, 0x86, 0x41, 0x03, 0x08, 0x52, 0x31, 0xff, 0x38, 0x50, 0x09, + 0x12, 0x01, 0x02, 0x00, 0xff, 0x08, 0x52, 0x09, 0xff, 0x09, 0x54, 0x09, 0xff, 0x0a, 0x56, 0x09, 0xff, 0x38, 0x50, 0x09, 0x00, 0x65, 0xaa, 0x40, - 0x00, 0x65, 0x84, 0x59, + 0x10, 0x0c, 0xa4, 0x79, + 0x00, 0x65, 0xae, 0x59, 0x7f, 0x02, 0x04, 0x08, 0xe1, 0x6a, 0x22, 0x01, 0x00, 0x65, 0xaa, 0x40, - 0x04, 0x93, 0x9a, 0x69, + 0x04, 0x93, 0xc2, 0x69, 0xdf, 0x93, 0x26, 0x09, - 0x20, 0x93, 0x88, 0x69, + 0x20, 0x93, 0xb2, 0x69, 0x02, 0x93, 0x26, 0x01, - 0x01, 0x94, 0x8a, 0x79, - 0x01, 0x94, 0x8a, 0x79, - 0x01, 0x94, 0x8a, 0x79, - 0x01, 0x94, 0x8a, 0x79, - 0x01, 0x94, 0x8a, 0x79, - 0x01, 0x94, 0x8a, 0x79, - 0x10, 0x94, 0x98, 0x69, - 0x7f, 0x05, 0xa0, 0x69, - 0x02, 0x03, 0xa0, 0x79, - 0x11, 0x0c, 0x9c, 0x79, + 0x01, 0x94, 0xb6, 0x79, + 0x01, 0x94, 0xb6, 0x79, + 0x01, 0x94, 0xb6, 0x79, + 0x01, 0x94, 0xb6, 0x79, + 0x01, 0x94, 0xb6, 0x79, + 0x10, 0x94, 0xc0, 0x69, 0xd7, 0x93, 0x26, 0x09, - 0x28, 0x93, 0xa2, 0x69, - 0x03, 0x08, 0x52, 0x31, - 0xff, 0x38, 0x50, 0x09, - 0x12, 0x01, 0x02, 0x00, + 0x28, 0x93, 0xc4, 0x69, 0xff, 0x6a, 0xd4, 0x0c, - 0x00, 0x65, 0x0e, 0x5b, + 0x00, 0x65, 0x2a, 0x5b, 0x05, 0xb4, 0x10, 0x31, 0x02, 0x6a, 0x1a, 0x31, 0x03, 0x8c, 0x10, 0x30, 0x88, 0x6a, 0xcc, 0x00, - 0xb4, 0x6a, 0xb0, 0x5b, + 0xb4, 0x6a, 0xcc, 0x5b, 0xff, 0x6a, 0x1a, 0x09, 0xff, 0x6a, 0x1c, 0x09, - 0x00, 0x65, 0xa6, 0x5b, - 0x3d, 0x6a, 0xee, 0x5a, + 0x00, 0x65, 0xc2, 0x5b, + 0x3d, 0x6a, 0x0a, 0x5b, 0xac, 0x6a, 0x26, 0x01, - 0x04, 0x0b, 0xc2, 0x69, - 0x04, 0x0b, 0xc8, 0x69, - 0x10, 0x0c, 0xc4, 0x79, - 0x02, 0x03, 0xcc, 0x79, - 0x11, 0x0c, 0xc8, 0x79, + 0x04, 0x0b, 0xde, 0x69, + 0x04, 0x0b, 0xe4, 0x69, + 0x10, 0x0c, 0xe0, 0x79, + 0x02, 0x03, 0xe8, 0x79, + 0x11, 0x0c, 0xe4, 0x79, 0xd7, 0x93, 0x26, 0x09, - 0x28, 0x93, 0xce, 0x69, + 0x28, 0x93, 0xea, 0x69, 0x12, 0x01, 0x02, 0x00, 0x00, 0x65, 0xaa, 0x40, - 0x00, 0x65, 0x0e, 0x5b, + 0x00, 0x65, 0x2a, 0x5b, 0xff, 0x06, 0x44, 0x09, 0x00, 0x65, 0xaa, 0x40, 0x10, 0x3d, 0x06, 0x00, 0xff, 0x34, 0xca, 0x08, - 0x80, 0x65, 0x00, 0x62, + 0x80, 0x65, 0x1c, 0x62, 0x0f, 0xa1, 0xca, 0x08, 0x07, 0xa1, 0xca, 0x08, 0x40, 0xa0, 0xc8, 0x08, 0x00, 0x65, 0xca, 0x00, 0x80, 0x65, 0xca, 0x00, - 0x80, 0xa0, 0xf0, 0x79, + 0x80, 0xa0, 0x0c, 0x7a, 0xff, 0x65, 0x0c, 0x08, - 0x00, 0x65, 0x02, 0x42, - 0x20, 0xa0, 0x08, 0x7a, + 0x00, 0x65, 0x1e, 0x42, + 0x20, 0xa0, 0x24, 0x7a, 0xff, 0x65, 0x0c, 0x08, - 0x00, 0x65, 0x9e, 0x5b, - 0xa0, 0x3d, 0x10, 0x62, + 0x00, 0x65, 0xba, 0x5b, + 0xa0, 0x3d, 0x2c, 0x62, 0x23, 0xa0, 0x0c, 0x08, - 0x00, 0x65, 0x9e, 0x5b, - 0xa0, 0x3d, 0x10, 0x62, - 0x00, 0xb9, 0x08, 0x42, - 0xff, 0x65, 0x08, 0x62, + 0x00, 0x65, 0xba, 0x5b, + 0xa0, 0x3d, 0x2c, 0x62, + 0x00, 0xb9, 0x24, 0x42, + 0xff, 0x65, 0x24, 0x62, 0xa1, 0x6a, 0x22, 0x01, 0xff, 0x6a, 0xd4, 0x08, - 0x10, 0x51, 0x10, 0x72, + 0x10, 0x51, 0x2c, 0x72, 0x40, 0x6a, 0x18, 0x00, 0xff, 0x65, 0x0c, 0x08, - 0x00, 0x65, 0x9e, 0x5b, - 0xa0, 0x3d, 0xda, 0x71, + 0x00, 0x65, 0xba, 0x5b, + 0xa0, 0x3d, 0xf6, 0x71, 0x40, 0x6a, 0x18, 0x00, 0xff, 0x34, 0xa6, 0x08, - 0x80, 0x34, 0x18, 0x62, + 0x80, 0x34, 0x34, 0x62, 0x7f, 0xa0, 0x40, 0x09, 0x08, 0x6a, 0x68, 0x00, 0x00, 0x65, 0xaa, 0x40, - 0x64, 0x6a, 0xe4, 0x5a, - 0x80, 0x64, 0x8e, 0x6a, - 0x04, 0x64, 0x70, 0x72, - 0x02, 0x64, 0x76, 0x72, - 0x00, 0x6a, 0x38, 0x72, - 0x03, 0x64, 0x8a, 0x72, - 0x01, 0x64, 0x6c, 0x72, - 0x07, 0x64, 0xcc, 0x72, - 0x08, 0x64, 0x34, 0x72, - 0x23, 0x64, 0xd0, 0x72, + 0x64, 0x6a, 0x00, 0x5b, + 0x80, 0x64, 0xaa, 0x6a, + 0x04, 0x64, 0x8c, 0x72, + 0x02, 0x64, 0x92, 0x72, + 0x00, 0x6a, 0x54, 0x72, + 0x03, 0x64, 0xa6, 0x72, + 0x01, 0x64, 0x88, 0x72, + 0x07, 0x64, 0xe8, 0x72, + 0x08, 0x64, 0x50, 0x72, + 0x23, 0x64, 0xec, 0x72, 0x11, 0x6a, 0x22, 0x01, - 0x07, 0x6a, 0xd6, 0x5a, + 0x07, 0x6a, 0xf2, 0x5a, 0xff, 0x06, 0xd4, 0x08, 0x00, 0x65, 0xaa, 0x40, - 0xff, 0xa8, 0x3c, 0x6a, - 0xff, 0xa2, 0x54, 0x7a, + 0xff, 0xa8, 0x58, 0x6a, + 0xff, 0xa2, 0x70, 0x7a, 0x01, 0x6a, 0x6a, 0x00, - 0x00, 0xb9, 0xca, 0x5b, - 0xff, 0xa2, 0x54, 0x7a, + 0x00, 0xb9, 0xe6, 0x5b, + 0xff, 0xa2, 0x70, 0x7a, 0x71, 0x6a, 0x22, 0x01, 0xff, 0x6a, 0xd4, 0x08, - 0x40, 0x51, 0x54, 0x62, + 0x40, 0x51, 0x70, 0x62, 0x0d, 0x6a, 0x6a, 0x00, - 0x00, 0xb9, 0xca, 0x5b, + 0x00, 0xb9, 0xe6, 0x5b, 0xff, 0x3e, 0x74, 0x09, 0xff, 0x90, 0x7c, 0x08, 0x00, 0x65, 0x4e, 0x58, 0x00, 0x65, 0xbc, 0x40, - 0x20, 0xa0, 0x5c, 0x6a, + 0x20, 0xa0, 0x78, 0x6a, 0xff, 0x37, 0xc8, 0x08, - 0x00, 0x6a, 0x74, 0x5b, - 0xff, 0x6a, 0x8a, 0x5b, + 0x00, 0x6a, 0x90, 0x5b, + 0xff, 0x6a, 0xa6, 0x5b, 0xff, 0xf8, 0xc8, 0x08, 0xff, 0x4f, 0xc8, 0x08, - 0x01, 0x6a, 0x74, 0x5b, - 0x00, 0xb9, 0x8a, 0x5b, + 0x01, 0x6a, 0x90, 0x5b, + 0x00, 0xb9, 0xa6, 0x5b, 0x01, 0x4f, 0x9e, 0x18, 0x02, 0x6a, 0x22, 0x01, - 0x00, 0x65, 0x38, 0x5c, + 0x00, 0x65, 0x80, 0x5c, 0x00, 0x65, 0xbc, 0x40, 0x41, 0x6a, 0x22, 0x01, 0x00, 0x65, 0xaa, 0x40, 0x04, 0xa0, 0x40, 0x01, - 0x00, 0x65, 0x50, 0x5c, + 0x00, 0x65, 0x98, 0x5c, 0x00, 0x65, 0xbc, 0x40, - 0x10, 0x36, 0x34, 0x7a, + 0x10, 0x36, 0x50, 0x7a, 0x05, 0x38, 0x46, 0x31, 0x04, 0x14, 0x58, 0x31, 0x03, 0xa9, 0x60, 0x31, 0xa3, 0x6a, 0xcc, 0x00, - 0x38, 0x6a, 0xb0, 0x5b, + 0x38, 0x6a, 0xcc, 0x5b, 0xac, 0x6a, 0xcc, 0x00, - 0x14, 0x6a, 0xb2, 0x5b, - 0xa9, 0x6a, 0xb4, 0x5b, - 0x00, 0x65, 0x34, 0x42, + 0x14, 0x6a, 0xce, 0x5b, + 0xa9, 0x6a, 0xd0, 0x5b, + 0x00, 0x65, 0x50, 0x42, 0xef, 0x36, 0x6c, 0x08, - 0x00, 0x65, 0x34, 0x42, + 0x00, 0x65, 0x50, 0x42, 0x0f, 0x64, 0xc8, 0x08, 0x07, 0x64, 0xc8, 0x08, 0x00, 0x37, 0x6e, 0x00, 0xff, 0x6a, 0xa4, 0x00, - 0x00, 0x65, 0x44, 0x5b, - 0xff, 0x51, 0xa0, 0x72, - 0x20, 0x36, 0xaa, 0x7a, - 0x00, 0x90, 0x32, 0x5b, - 0x00, 0x65, 0xac, 0x42, + 0x00, 0x65, 0x60, 0x5b, + 0xff, 0x51, 0xbc, 0x72, + 0x20, 0x36, 0xc6, 0x7a, + 0x00, 0x90, 0x4e, 0x5b, + 0x00, 0x65, 0xc8, 0x42, 0xff, 0x06, 0xd4, 0x08, - 0x00, 0x65, 0x9e, 0x5b, - 0xe0, 0x3d, 0xc6, 0x62, - 0x20, 0x12, 0xc6, 0x62, - 0x51, 0x6a, 0xda, 0x5a, - 0x00, 0x65, 0x2c, 0x5b, + 0x00, 0x65, 0xba, 0x5b, + 0xe0, 0x3d, 0xe2, 0x62, + 0x20, 0x12, 0xe2, 0x62, + 0x51, 0x6a, 0xf6, 0x5a, + 0x00, 0x65, 0x48, 0x5b, 0xff, 0x37, 0xc8, 0x08, - 0x00, 0xa1, 0xbe, 0x62, - 0x04, 0xa0, 0xbe, 0x7a, + 0x00, 0xa1, 0xda, 0x62, + 0x04, 0xa0, 0xda, 0x7a, 0xfb, 0xa0, 0x40, 0x09, 0x80, 0x36, 0x6c, 0x00, - 0x80, 0xa0, 0x34, 0x7a, + 0x80, 0xa0, 0x50, 0x7a, 0x7f, 0xa0, 0x40, 0x09, - 0xff, 0x6a, 0xd6, 0x5a, - 0x00, 0x65, 0x34, 0x42, - 0x04, 0xa0, 0xc4, 0x7a, - 0x00, 0x65, 0x50, 0x5c, - 0x00, 0x65, 0xc6, 0x42, - 0x00, 0x65, 0x38, 0x5c, + 0xff, 0x6a, 0xf2, 0x5a, + 0x00, 0x65, 0x50, 0x42, + 0x04, 0xa0, 0xe0, 0x7a, + 0x00, 0x65, 0x98, 0x5c, + 0x00, 0x65, 0xe2, 0x42, + 0x00, 0x65, 0x80, 0x5c, 0x31, 0x6a, 0x22, 0x01, - 0x0c, 0x6a, 0xd6, 0x5a, - 0x00, 0x65, 0x34, 0x42, + 0x0c, 0x6a, 0xf2, 0x5a, + 0x00, 0x65, 0x50, 0x42, 0x61, 0x6a, 0x22, 0x01, - 0x00, 0x65, 0x34, 0x42, - 0x51, 0x6a, 0xda, 0x5a, + 0x00, 0x65, 0x50, 0x42, + 0x51, 0x6a, 0xf6, 0x5a, 0x51, 0x6a, 0x22, 0x01, - 0x00, 0x65, 0x34, 0x42, + 0x00, 0x65, 0x50, 0x42, 0x10, 0x3d, 0x06, 0x00, 0xff, 0x65, 0x68, 0x0c, 0xff, 0x06, 0xd4, 0x08, - 0x01, 0x0c, 0xdc, 0x7a, - 0x04, 0x0c, 0xde, 0x6a, + 0x01, 0x0c, 0xf8, 0x7a, + 0x04, 0x0c, 0xfa, 0x6a, 0xe0, 0x03, 0x7a, 0x08, - 0xe0, 0x3d, 0xea, 0x62, + 0xe0, 0x3d, 0x06, 0x63, 0xff, 0x65, 0xcc, 0x08, 0xff, 0x12, 0xda, 0x0c, 0xff, 0x06, 0xd4, 0x0c, 0xd1, 0x6a, 0x22, 0x01, 0x00, 0x65, 0xaa, 0x40, 0xff, 0x65, 0x26, 0x09, - 0x01, 0x0b, 0xfe, 0x6a, - 0x10, 0x0c, 0xf0, 0x7a, - 0x04, 0x0b, 0xf8, 0x6a, + 0x01, 0x0b, 0x1a, 0x6b, + 0x10, 0x0c, 0x0c, 0x7b, + 0x04, 0x0b, 0x14, 0x6b, 0xff, 0x6a, 0xca, 0x08, - 0x04, 0x93, 0xfc, 0x6a, - 0x01, 0x94, 0xfa, 0x7a, - 0x10, 0x94, 0xfc, 0x6a, - 0x80, 0x3d, 0x02, 0x73, - 0x0f, 0x04, 0x06, 0x6b, - 0x02, 0x03, 0x06, 0x7b, - 0x11, 0x0c, 0x02, 0x7b, + 0x04, 0x93, 0x18, 0x6b, + 0x01, 0x94, 0x16, 0x7b, + 0x10, 0x94, 0x18, 0x6b, + 0x80, 0x3d, 0x1e, 0x73, + 0x0f, 0x04, 0x22, 0x6b, + 0x02, 0x03, 0x22, 0x7b, + 0x11, 0x0c, 0x1e, 0x7b, 0xc7, 0x93, 0x26, 0x09, 0xff, 0x99, 0xd4, 0x08, - 0x38, 0x93, 0x08, 0x6b, + 0x38, 0x93, 0x24, 0x6b, 0xff, 0x6a, 0xd4, 0x0c, - 0x80, 0x36, 0x0c, 0x6b, + 0x80, 0x36, 0x28, 0x6b, 0x21, 0x6a, 0x22, 0x05, 0xff, 0x65, 0x20, 0x09, - 0xff, 0x51, 0x1a, 0x63, + 0xff, 0x51, 0x36, 0x63, 0xff, 0x37, 0xc8, 0x08, - 0xa1, 0x6a, 0x26, 0x43, + 0xa1, 0x6a, 0x42, 0x43, 0xff, 0x51, 0xc8, 0x08, - 0xb9, 0x6a, 0x26, 0x43, + 0xb9, 0x6a, 0x42, 0x43, 0xff, 0x90, 0xa4, 0x08, - 0xff, 0xba, 0x2a, 0x73, + 0xff, 0xba, 0x46, 0x73, 0xff, 0xba, 0x20, 0x09, 0xff, 0x65, 0xca, 0x18, - 0x00, 0x6c, 0x1e, 0x63, + 0x00, 0x6c, 0x3a, 0x63, 0xff, 0x90, 0xca, 0x0c, 0xff, 0x6a, 0xca, 0x04, - 0x20, 0x36, 0x3e, 0x7b, - 0x00, 0x90, 0x12, 0x5b, - 0xff, 0x65, 0x3e, 0x73, - 0xff, 0x52, 0x3c, 0x73, + 0x20, 0x36, 0x5a, 0x7b, + 0x00, 0x90, 0x2e, 0x5b, + 0xff, 0x65, 0x5a, 0x73, + 0xff, 0x52, 0x58, 0x73, 0xff, 0xba, 0xcc, 0x08, 0xff, 0x52, 0x20, 0x09, 0xff, 0x66, 0x74, 0x09, 0xff, 0x65, 0x20, 0x0d, 0xff, 0xba, 0x7e, 0x0c, - 0x00, 0x6a, 0x3e, 0x5c, + 0x00, 0x6a, 0x86, 0x5c, 0x0d, 0x6a, 0x6a, 0x00, - 0x00, 0x51, 0xca, 0x43, - 0xff, 0x3f, 0x98, 0x73, + 0x00, 0x51, 0xe6, 0x43, + 0xff, 0x3f, 0xb4, 0x73, 0xff, 0x6a, 0xa2, 0x00, - 0x00, 0x3f, 0x12, 0x5b, - 0xff, 0x65, 0x98, 0x73, + 0x00, 0x3f, 0x2e, 0x5b, + 0xff, 0x65, 0xb4, 0x73, 0x20, 0x36, 0x6c, 0x00, - 0x20, 0xa0, 0x52, 0x6b, + 0x20, 0xa0, 0x6e, 0x6b, 0xff, 0xb9, 0xa2, 0x0c, 0xff, 0x6a, 0xa2, 0x04, 0xff, 0x65, 0xa4, 0x08, 0xe0, 0x6a, 0xcc, 0x00, - 0x45, 0x6a, 0xbe, 0x5b, + 0x45, 0x6a, 0xda, 0x5b, 0x01, 0x6a, 0xd0, 0x01, 0x09, 0x6a, 0xd6, 0x01, - 0x80, 0xeb, 0x5e, 0x7b, + 0x80, 0xeb, 0x7a, 0x7b, 0x01, 0x6a, 0xd6, 0x01, 0x01, 0xe9, 0xa4, 0x34, 0x88, 0x6a, 0xcc, 0x00, - 0x45, 0x6a, 0xbe, 0x5b, + 0x45, 0x6a, 0xda, 0x5b, 0x01, 0x6a, 0x18, 0x01, 0xff, 0x6a, 0x1a, 0x09, 0xff, 0x6a, 0x1c, 0x09, 0x0d, 0x6a, 0x26, 0x01, - 0x00, 0x65, 0x30, 0x5c, + 0x00, 0x65, 0x78, 0x5c, 0xff, 0x99, 0xa4, 0x0c, 0xff, 0x65, 0xa4, 0x08, 0xe0, 0x6a, 0xcc, 0x00, - 0x45, 0x6a, 0xbe, 0x5b, + 0x45, 0x6a, 0xda, 0x5b, 0x01, 0x6a, 0xd0, 0x01, 0x01, 0x6a, 0xdc, 0x05, 0x88, 0x6a, 0xcc, 0x00, - 0x45, 0x6a, 0xbe, 0x5b, + 0x45, 0x6a, 0xda, 0x5b, 0x01, 0x6a, 0x18, 0x01, 0xff, 0x6a, 0x1a, 0x09, 0xff, 0x6a, 0x1c, 0x09, 0x01, 0x6a, 0x26, 0x05, 0x01, 0x65, 0xd8, 0x31, 0x09, 0xee, 0xdc, 0x01, - 0x80, 0xee, 0x8e, 0x7b, + 0x80, 0xee, 0xaa, 0x7b, 0xff, 0x6a, 0xdc, 0x0d, 0xff, 0x65, 0x32, 0x09, 0x0a, 0x93, 0x26, 0x01, - 0x00, 0x65, 0x30, 0x44, + 0x00, 0x65, 0x78, 0x44, 0xff, 0x37, 0xc8, 0x08, - 0x00, 0x6a, 0x54, 0x5b, + 0x00, 0x6a, 0x70, 0x5b, 0xff, 0x52, 0xa2, 0x0c, - 0x01, 0x0c, 0x9e, 0x7b, - 0x04, 0x0c, 0x9e, 0x6b, + 0x01, 0x0c, 0xba, 0x7b, + 0x04, 0x0c, 0xba, 0x6b, 0xe0, 0x03, 0x06, 0x08, 0xe0, 0x03, 0x7a, 0x0c, 0xff, 0x8c, 0x10, 0x08, @@ -489,29 +503,34 @@ 0x00, 0x6c, 0xda, 0x24, 0xff, 0x65, 0xc8, 0x08, 0xe0, 0x6a, 0xcc, 0x00, - 0x41, 0x6a, 0xba, 0x5b, + 0x41, 0x6a, 0xd6, 0x5b, 0xff, 0x90, 0xe2, 0x09, 0x20, 0x6a, 0xd0, 0x01, - 0x04, 0x35, 0xdc, 0x7b, + 0x04, 0x35, 0xf8, 0x7b, 0x1d, 0x6a, 0xdc, 0x01, - 0xdc, 0xee, 0xd8, 0x63, - 0x00, 0x65, 0xe8, 0x43, + 0xdc, 0xee, 0xf4, 0x63, + 0x00, 0x65, 0x0e, 0x44, 0x01, 0x6a, 0xdc, 0x01, 0x20, 0xa0, 0xd8, 0x31, 0x09, 0xee, 0xdc, 0x01, - 0x80, 0xee, 0xe2, 0x7b, + 0x80, 0xee, 0xfe, 0x7b, + 0x11, 0x6a, 0xdc, 0x01, + 0x50, 0xee, 0x02, 0x64, + 0x20, 0x6a, 0xd0, 0x01, + 0x09, 0x6a, 0xdc, 0x01, + 0x88, 0xee, 0x08, 0x64, 0x19, 0x6a, 0xdc, 0x01, - 0xd8, 0xee, 0xe6, 0x63, + 0xd8, 0xee, 0x0c, 0x64, 0xff, 0x6a, 0xdc, 0x09, - 0x18, 0xee, 0xea, 0x6b, + 0x18, 0xee, 0x10, 0x6c, 0xff, 0x6a, 0xd4, 0x0c, 0x88, 0x6a, 0xcc, 0x00, - 0x41, 0x6a, 0xba, 0x5b, + 0x41, 0x6a, 0xd6, 0x5b, 0x20, 0x6a, 0x18, 0x01, 0xff, 0x6a, 0x1a, 0x09, 0xff, 0x6a, 0x1c, 0x09, 0xff, 0x35, 0x26, 0x09, - 0x04, 0x35, 0x14, 0x6c, + 0x04, 0x35, 0x3c, 0x6c, 0xa0, 0x6a, 0xca, 0x00, 0x20, 0x65, 0xc8, 0x18, 0xff, 0x6c, 0x32, 0x09, @@ -522,15 +541,32 @@ 0xff, 0x6c, 0x32, 0x09, 0xff, 0x6c, 0x32, 0x09, 0xff, 0x6c, 0x32, 0x09, - 0x00, 0x65, 0x00, 0x64, + 0x00, 0x65, 0x26, 0x64, 0x0a, 0x93, 0x26, 0x01, - 0x00, 0x65, 0x30, 0x5c, - 0x04, 0x35, 0x0c, 0x7b, - 0xa0, 0x6a, 0x20, 0x5c, - 0x00, 0x65, 0x22, 0x5c, - 0x00, 0x65, 0x22, 0x5c, - 0x00, 0x65, 0x22, 0x44, - 0xff, 0x65, 0xcc, 0x08, + 0x00, 0x65, 0x78, 0x44, + 0xa0, 0x6a, 0xcc, 0x00, + 0xe8, 0x6a, 0xc8, 0x00, + 0x01, 0x94, 0x40, 0x6c, + 0x10, 0x94, 0x42, 0x6c, + 0x08, 0x94, 0x54, 0x6c, + 0x08, 0x94, 0x54, 0x6c, + 0x08, 0x94, 0x54, 0x6c, + 0x00, 0x65, 0x68, 0x5c, + 0x08, 0x64, 0xc8, 0x18, + 0x00, 0x8c, 0xca, 0x18, + 0x00, 0x65, 0x4a, 0x4c, + 0x00, 0x65, 0x40, 0x44, + 0xf7, 0x93, 0x26, 0x09, + 0x08, 0x93, 0x56, 0x6c, + 0x00, 0x65, 0x68, 0x5c, + 0x08, 0x64, 0xc8, 0x18, + 0x08, 0x64, 0x58, 0x64, + 0xff, 0x6a, 0xd4, 0x0c, + 0x00, 0x65, 0x78, 0x5c, + 0x00, 0x65, 0x68, 0x5c, + 0x00, 0x65, 0x68, 0x5c, + 0x00, 0x65, 0x68, 0x5c, + 0xff, 0x99, 0xda, 0x08, 0xff, 0x99, 0xda, 0x08, 0xff, 0x99, 0xda, 0x08, 0xff, 0x99, 0xda, 0x08, @@ -538,19 +574,19 @@ 0xff, 0x99, 0xda, 0x08, 0xff, 0x99, 0xda, 0x08, 0xff, 0x99, 0xda, 0x0c, - 0x08, 0x94, 0x30, 0x7c, + 0x08, 0x94, 0x78, 0x7c, 0xf7, 0x93, 0x26, 0x09, - 0x08, 0x93, 0x34, 0x6c, + 0x08, 0x93, 0x7c, 0x6c, 0xff, 0x6a, 0xd4, 0x0c, 0xff, 0x40, 0x74, 0x09, 0xff, 0x90, 0x80, 0x08, 0xff, 0x6a, 0x72, 0x05, - 0xff, 0x40, 0x4c, 0x64, - 0xff, 0x3f, 0x44, 0x64, + 0xff, 0x40, 0x94, 0x64, + 0xff, 0x3f, 0x8c, 0x64, 0xff, 0x6a, 0xca, 0x04, 0xff, 0x3f, 0x20, 0x09, 0x01, 0x6a, 0x6a, 0x00, - 0x00, 0xb9, 0xca, 0x5b, + 0x00, 0xb9, 0xe6, 0x5b, 0xff, 0xba, 0x7e, 0x0c, 0xff, 0x40, 0x20, 0x09, 0xff, 0xba, 0x80, 0x0c, @@ -558,12 +594,36 @@ 0xff, 0x90, 0x7e, 0x0c, }; +static int aic7xxx_patch15_func(struct aic7xxx_host *p); + +static int +aic7xxx_patch15_func(struct aic7xxx_host *p) +{ + return ((p->bugs & AHC_BUG_SCBCHAN_UPLOAD) != 0); +} + +static int aic7xxx_patch14_func(struct aic7xxx_host *p); + +static int +aic7xxx_patch14_func(struct aic7xxx_host *p) +{ + return ((p->bugs & AHC_BUG_PCI_2_1_RETRY) != 0); +} + +static int aic7xxx_patch13_func(struct aic7xxx_host *p); + +static int +aic7xxx_patch13_func(struct aic7xxx_host *p) +{ + return ((p->features & AHC_WIDE) != 0); +} + static int aic7xxx_patch12_func(struct aic7xxx_host *p); static int aic7xxx_patch12_func(struct aic7xxx_host *p) { - return ((p->features & AHC_WIDE) != 0); + return ((p->bugs & AHC_BUG_AUTOFLUSH) != 0); } static int aic7xxx_patch11_func(struct aic7xxx_host *p); @@ -692,54 +752,66 @@ { aic7xxx_patch7_func, 113, 1, 2 }, { aic7xxx_patch0_func, 114, 1, 1 }, { aic7xxx_patch1_func, 118, 1, 1 }, - { aic7xxx_patch1_func, 121, 3, 2 }, + { aic7xxx_patch1_func, 121, 3, 3 }, + { aic7xxx_patch11_func, 123, 1, 1 }, { aic7xxx_patch0_func, 124, 5, 1 }, - { aic7xxx_patch1_func, 132, 2, 3 }, { aic7xxx_patch7_func, 132, 1, 1 }, - { aic7xxx_patch0_func, 134, 3, 1 }, - { aic7xxx_patch11_func, 138, 1, 2 }, - { aic7xxx_patch0_func, 139, 1, 1 }, - { aic7xxx_patch7_func, 140, 7, 2 }, - { aic7xxx_patch0_func, 147, 1, 1 }, - { aic7xxx_patch1_func, 152, 14, 3 }, - { aic7xxx_patch11_func, 165, 1, 1 }, - { aic7xxx_patch0_func, 166, 9, 1 }, - { aic7xxx_patch7_func, 180, 2, 1 }, - { aic7xxx_patch7_func, 182, 1, 1 }, - { aic7xxx_patch11_func, 183, 6, 3 }, - { aic7xxx_patch1_func, 183, 2, 2 }, - { aic7xxx_patch0_func, 185, 4, 1 }, - { aic7xxx_patch7_func, 190, 1, 1 }, - { aic7xxx_patch7_func, 194, 20, 1 }, - { aic7xxx_patch1_func, 215, 3, 3 }, - { aic7xxx_patch11_func, 217, 1, 1 }, - { aic7xxx_patch0_func, 218, 5, 1 }, - { aic7xxx_patch11_func, 223, 1, 2 }, - { aic7xxx_patch0_func, 224, 9, 1 }, - { aic7xxx_patch12_func, 240, 1, 2 }, - { aic7xxx_patch0_func, 241, 1, 1 }, - { aic7xxx_patch4_func, 302, 1, 2 }, - { aic7xxx_patch0_func, 303, 1, 1 }, - { aic7xxx_patch2_func, 306, 1, 1 }, - { aic7xxx_patch1_func, 316, 3, 2 }, - { aic7xxx_patch0_func, 319, 5, 1 }, - { aic7xxx_patch12_func, 327, 1, 2 }, - { aic7xxx_patch0_func, 328, 1, 1 }, - { aic7xxx_patch5_func, 333, 1, 1 }, - { aic7xxx_patch11_func, 375, 15, 1 }, - { aic7xxx_patch1_func, 427, 7, 2 }, - { aic7xxx_patch0_func, 434, 8, 1 }, - { aic7xxx_patch1_func, 443, 4, 2 }, - { aic7xxx_patch0_func, 447, 6, 1 }, - { aic7xxx_patch1_func, 453, 4, 2 }, - { aic7xxx_patch0_func, 457, 3, 1 }, - { aic7xxx_patch10_func, 467, 10, 1 }, - { aic7xxx_patch1_func, 486, 17, 4 }, - { aic7xxx_patch9_func, 494, 4, 2 }, - { aic7xxx_patch0_func, 498, 2, 1 }, - { aic7xxx_patch0_func, 503, 33, 1 }, - { aic7xxx_patch10_func, 536, 4, 1 }, - { aic7xxx_patch5_func, 540, 2, 1 }, - { aic7xxx_patch5_func, 543, 9, 1 }, + { aic7xxx_patch9_func, 133, 1, 1 }, + { aic7xxx_patch10_func, 134, 3, 1 }, + { aic7xxx_patch7_func, 137, 3, 2 }, + { aic7xxx_patch0_func, 140, 2, 1 }, + { aic7xxx_patch7_func, 142, 5, 2 }, + { aic7xxx_patch0_func, 147, 3, 1 }, + { aic7xxx_patch7_func, 150, 1, 2 }, + { aic7xxx_patch0_func, 151, 2, 1 }, + { aic7xxx_patch1_func, 153, 15, 4 }, + { aic7xxx_patch11_func, 166, 1, 2 }, + { aic7xxx_patch0_func, 167, 1, 1 }, + { aic7xxx_patch0_func, 168, 10, 1 }, + { aic7xxx_patch7_func, 181, 1, 2 }, + { aic7xxx_patch0_func, 182, 2, 1 }, + { aic7xxx_patch7_func, 184, 18, 1 }, + { aic7xxx_patch1_func, 202, 3, 3 }, + { aic7xxx_patch7_func, 204, 1, 1 }, + { aic7xxx_patch0_func, 205, 4, 1 }, + { aic7xxx_patch7_func, 210, 2, 1 }, + { aic7xxx_patch7_func, 215, 13, 3 }, + { aic7xxx_patch12_func, 218, 1, 1 }, + { aic7xxx_patch12_func, 219, 4, 1 }, + { aic7xxx_patch1_func, 229, 3, 3 }, + { aic7xxx_patch11_func, 231, 1, 1 }, + { aic7xxx_patch0_func, 232, 5, 1 }, + { aic7xxx_patch11_func, 237, 1, 2 }, + { aic7xxx_patch0_func, 238, 9, 1 }, + { aic7xxx_patch13_func, 254, 1, 2 }, + { aic7xxx_patch0_func, 255, 1, 1 }, + { aic7xxx_patch4_func, 316, 1, 2 }, + { aic7xxx_patch0_func, 317, 1, 1 }, + { aic7xxx_patch2_func, 320, 1, 1 }, + { aic7xxx_patch1_func, 330, 3, 2 }, + { aic7xxx_patch0_func, 333, 5, 1 }, + { aic7xxx_patch13_func, 341, 1, 2 }, + { aic7xxx_patch0_func, 342, 1, 1 }, + { aic7xxx_patch5_func, 347, 1, 1 }, + { aic7xxx_patch11_func, 389, 15, 2 }, + { aic7xxx_patch14_func, 402, 1, 1 }, + { aic7xxx_patch1_func, 441, 7, 2 }, + { aic7xxx_patch0_func, 448, 8, 1 }, + { aic7xxx_patch1_func, 457, 4, 2 }, + { aic7xxx_patch0_func, 461, 6, 1 }, + { aic7xxx_patch1_func, 467, 4, 2 }, + { aic7xxx_patch0_func, 471, 3, 1 }, + { aic7xxx_patch10_func, 481, 10, 1 }, + { aic7xxx_patch1_func, 500, 22, 5 }, + { aic7xxx_patch11_func, 508, 4, 1 }, + { aic7xxx_patch7_func, 512, 7, 3 }, + { aic7xxx_patch15_func, 512, 5, 2 }, + { aic7xxx_patch0_func, 517, 2, 1 }, + { aic7xxx_patch10_func, 522, 50, 3 }, + { aic7xxx_patch14_func, 543, 17, 2 }, + { aic7xxx_patch0_func, 560, 4, 1 }, + { aic7xxx_patch10_func, 572, 4, 1 }, + { aic7xxx_patch5_func, 576, 2, 1 }, + { aic7xxx_patch5_func, 579, 9, 1 }, }; diff -u --recursive --new-file v2.4.6/linux/drivers/scsi/aic7xxx_old.c linux/drivers/scsi/aic7xxx_old.c --- v2.4.6/linux/drivers/scsi/aic7xxx_old.c Tue Jul 3 17:08:20 2001 +++ linux/drivers/scsi/aic7xxx_old.c Tue Jul 10 16:11:43 2001 @@ -256,7 +256,7 @@ #include <scsi/scsicam.h> #include <linux/stat.h> -#include <linux/malloc.h> /* for kmalloc() */ +#include <linux/slab.h> /* for kmalloc() */ #include <linux/config.h> /* for CONFIG_PCI */ @@ -266,7 +266,7 @@ */ #define VIRT_TO_BUS(a) (unsigned int)virt_to_bus((void *)(a)) -#define AIC7XXX_C_VERSION "5.2.1" +#define AIC7XXX_C_VERSION "5.2.4" #define NUMBER(arr) (sizeof(arr) / sizeof(arr[0])) #define MIN(a,b) (((a) < (b)) ? (a) : (b)) @@ -311,8 +311,8 @@ * You can try raising me if tagged queueing is enabled, or lowering * me if you only have 4 SCBs. */ -#ifdef CONFIG_AIC7XXX_OLD_CMDS_PER_DEVICE -#define AIC7XXX_CMDS_PER_DEVICE CONFIG_AIC7XXX_OLD_CMDS_PER_DEVICE +#ifdef CONFIG_AIC7XXX_CMDS_PER_DEVICE +#define AIC7XXX_CMDS_PER_DEVICE CONFIG_AIC7XXX_CMDS_PER_DEVICE #else #define AIC7XXX_CMDS_PER_DEVICE 8 #endif @@ -323,7 +323,7 @@ * NOTE: Do NOT enable this when running on kernels version 1.2.x and below. * NOTE: This does affect performance since it has to maintain statistics. */ -#ifdef CONFIG_AIC7XXX_OLD_PROC_STATS +#ifdef CONFIG_AIC7XXX_PROC_STATS #define AIC7XXX_PROC_STATS #endif @@ -347,7 +347,7 @@ * Make a define that will tell the driver not to use tagged queueing * by default. */ -#ifdef CONFIG_AIC7XXX_OLD_TCQ_ON_BY_DEFAULT +#ifdef CONFIG_AIC7XXX_TCQ_ON_BY_DEFAULT #define DEFAULT_TAG_COMMANDS {0, 0, 0, 0, 0, 0, 0, 0,\ 0, 0, 0, 0, 0, 0, 0, 0} #else @@ -706,13 +706,14 @@ /*28*/ unsigned int pad; /* * Unused by the kernel, but we require * the padding so that the array of - * hardware SCBs is alligned on 32 byte + * hardware SCBs is aligned on 32 byte * boundaries so the sequencer can index */ }; typedef enum { SCB_FREE = 0x0000, + SCB_DTR_SCB = 0x0001, SCB_WAITINGQ = 0x0002, SCB_ACTIVE = 0x0004, SCB_SENSE = 0x0008, @@ -830,6 +831,17 @@ unsigned int dma_len; /* DMA length */ }; +typedef enum { + AHC_BUG_NONE = 0x0000, + AHC_BUG_TMODE_WIDEODD = 0x0001, + AHC_BUG_AUTOFLUSH = 0x0002, + AHC_BUG_CACHETHEN = 0x0004, + AHC_BUG_CACHETHEN_DIS = 0x0008, + AHC_BUG_PCI_2_1_RETRY = 0x0010, + AHC_BUG_PCI_MWI = 0x0020, + AHC_BUG_SCBCHAN_UPLOAD = 0x0040, +} ahc_bugs; + struct aic7xxx_scb { struct aic7xxx_hwscb *hscb; /* corresponding hardware scb */ Scsi_Cmnd *cmd; /* Scsi_Cmnd for this scb */ @@ -942,7 +954,6 @@ unsigned long isr_count; /* Interrupt count */ unsigned long spurious_int; scb_data_type *scb_data; - volatile unsigned short needdv; volatile unsigned short needppr; volatile unsigned short needsdtr; volatile unsigned short needwdtr; @@ -973,10 +984,9 @@ #define BUS_DEVICE_RESET_PENDING 0x02 #define DEVICE_RESET_DELAY 0x04 #define DEVICE_PRINT_DTR 0x08 -#define DEVICE_PARITY_ERROR 0x10 -#define DEVICE_WAS_BUSY 0x20 -#define DEVICE_SCSI_3 0x40 -#define DEVICE_SCANNED 0x80 +#define DEVICE_WAS_BUSY 0x10 +#define DEVICE_SCSI_3 0x20 +#define DEVICE_DTR_SCANNED 0x40 volatile unsigned char dev_flags[MAX_TARGETS]; volatile unsigned char dev_active_cmds[MAX_TARGETS]; volatile unsigned char dev_temp_queue_depth[MAX_TARGETS]; @@ -989,10 +999,6 @@ spinlock_t spin_lock; volatile unsigned char cpu_lock_count[NR_CPUS]; - Scsi_Cmnd *dev_dtr_cmnd[MAX_TARGETS]; - - unsigned int dev_checksum[MAX_TARGETS]; - unsigned char dev_last_queue_full[MAX_TARGETS]; unsigned char dev_last_queue_full_count[MAX_TARGETS]; unsigned char dev_max_queue_depth[MAX_TARGETS]; @@ -1040,6 +1046,7 @@ int host_no; /* SCSI host number */ unsigned long mbase; /* I/O memory address */ ahc_chip chip; /* chip type */ + ahc_bugs bugs; dma_addr_t fifo_dma; /* DMA handle for fifo arrays */ /* @@ -2821,138 +2828,98 @@ { p->flags &= ~AHC_ABORT_PENDING; } - if (scb->flags & SCB_RESET) + if (scb->flags & (SCB_RESET|SCB_ABORT)) { - cmd->result = (DID_RESET << 16) | (cmd->result & 0xffff); + cmd->result |= (DID_RESET << 16); } - else if (scb->flags & SCB_ABORT) - { - cmd->result = (DID_RESET << 16) | (cmd->result & 0xffff); - } - else if (!(p->dev_flags[tindex] & DEVICE_SCANNED)) + + if (!(p->dev_flags[tindex] & DEVICE_PRESENT)) { if ( (cmd->cmnd[0] == INQUIRY) && (cmd->result == DID_OK) ) { - char *buffer; - + p->dev_flags[tindex] |= DEVICE_PRESENT; - if(cmd->use_sg) - { - struct scatterlist *sg; - - sg = (struct scatterlist *)cmd->request_buffer; - buffer = (char *)sg[0].address; - } - else - { - buffer = (char *)cmd->request_buffer; - } #define WIDE_INQUIRY_BITS 0x60 #define SYNC_INQUIRY_BITS 0x10 #define SCSI_VERSION_BITS 0x07 #define SCSI_DT_BIT 0x04 - if ( (buffer[7] & WIDE_INQUIRY_BITS) && - (p->features & AHC_WIDE) ) - { - p->needwdtr |= (1<<tindex); - p->needwdtr_copy |= (1<<tindex); - p->transinfo[tindex].goal_width = p->transinfo[tindex].user_width; - } - else - { - p->needwdtr &= ~(1<<tindex); - p->needwdtr_copy &= ~(1<<tindex); - pause_sequencer(p); - aic7xxx_set_width(p, cmd->target, cmd->channel, cmd->lun, - MSG_EXT_WDTR_BUS_8_BIT, (AHC_TRANS_ACTIVE | - AHC_TRANS_GOAL | - AHC_TRANS_CUR) ); - unpause_sequencer(p, FALSE); - } - if ( (buffer[7] & SYNC_INQUIRY_BITS) && - p->transinfo[tindex].user_offset ) - { - p->transinfo[tindex].goal_period = p->transinfo[tindex].user_period; - p->transinfo[tindex].goal_options = p->transinfo[tindex].user_options; - if (p->features & AHC_ULTRA2) - p->transinfo[tindex].goal_offset = MAX_OFFSET_ULTRA2; - else if (p->transinfo[tindex].goal_width == MSG_EXT_WDTR_BUS_16_BIT) - p->transinfo[tindex].goal_offset = MAX_OFFSET_16BIT; + if(!(p->dev_flags[tindex] & DEVICE_DTR_SCANNED)) { + char *buffer; + + if(cmd->use_sg) + { + struct scatterlist *sg; + + sg = (struct scatterlist *)cmd->request_buffer; + buffer = (char *)sg[0].address; + } + else + { + buffer = (char *)cmd->request_buffer; + } + + + if ( (buffer[7] & WIDE_INQUIRY_BITS) && + (p->features & AHC_WIDE) ) + { + p->needwdtr |= (1<<tindex); + p->needwdtr_copy |= (1<<tindex); + p->transinfo[tindex].goal_width = p->transinfo[tindex].user_width; + } else - p->transinfo[tindex].goal_offset = MAX_OFFSET_8BIT; - if ( (((buffer[2] & SCSI_VERSION_BITS) == 3) || - (buffer[56] & SCSI_DT_BIT) || - (p->dev_flags[tindex] & DEVICE_SCSI_3) ) && - (p->transinfo[tindex].user_period <= 9) && - (p->transinfo[tindex].user_options) ) { - p->needppr |= (1<<tindex); - p->needppr_copy |= (1<<tindex); - p->needsdtr &= ~(1<<tindex); - p->needsdtr_copy &= ~(1<<tindex); p->needwdtr &= ~(1<<tindex); p->needwdtr_copy &= ~(1<<tindex); - p->dev_flags[tindex] |= DEVICE_SCSI_3; + pause_sequencer(p); + aic7xxx_set_width(p, cmd->target, cmd->channel, cmd->lun, + MSG_EXT_WDTR_BUS_8_BIT, (AHC_TRANS_ACTIVE | + AHC_TRANS_GOAL | + AHC_TRANS_CUR) ); + unpause_sequencer(p, FALSE); } - else + if ( (buffer[7] & SYNC_INQUIRY_BITS) && + p->transinfo[tindex].user_offset ) { - p->needsdtr |= (1<<tindex); - p->needsdtr_copy |= (1<<tindex); - p->transinfo[tindex].goal_period = - MAX(10, p->transinfo[tindex].goal_period); - p->transinfo[tindex].goal_options = 0; + p->transinfo[tindex].goal_period = p->transinfo[tindex].user_period; + p->transinfo[tindex].goal_options = p->transinfo[tindex].user_options; + if (p->features & AHC_ULTRA2) + p->transinfo[tindex].goal_offset = MAX_OFFSET_ULTRA2; + else if (p->transinfo[tindex].goal_width == MSG_EXT_WDTR_BUS_16_BIT) + p->transinfo[tindex].goal_offset = MAX_OFFSET_16BIT; + else + p->transinfo[tindex].goal_offset = MAX_OFFSET_8BIT; + if ( (((buffer[2] & SCSI_VERSION_BITS) >= 3) || + (buffer[56] & SCSI_DT_BIT) || + (p->dev_flags[tindex] & DEVICE_SCSI_3) ) && + (p->transinfo[tindex].user_period <= 9) && + (p->transinfo[tindex].user_options) ) + { + p->needppr |= (1<<tindex); + p->needppr_copy |= (1<<tindex); + p->needsdtr &= ~(1<<tindex); + p->needsdtr_copy &= ~(1<<tindex); + p->needwdtr &= ~(1<<tindex); + p->needwdtr_copy &= ~(1<<tindex); + p->dev_flags[tindex] |= DEVICE_SCSI_3; + } + else + { + p->needsdtr |= (1<<tindex); + p->needsdtr_copy |= (1<<tindex); + p->transinfo[tindex].goal_period = + MAX(10, p->transinfo[tindex].goal_period); + p->transinfo[tindex].goal_options = 0; + } } - } - else - { - p->needsdtr &= ~(1<<tindex); - p->needsdtr_copy &= ~(1<<tindex); - p->transinfo[tindex].goal_period = 255; - p->transinfo[tindex].goal_offset = 0; - p->transinfo[tindex].goal_options = 0; - } - /* - * This is needed to work around a sequencer bug for now. Regardless - * of the controller in use, if we have a Quantum drive, we need to - * limit the speed to 80MByte/sec. As soon as I get a fixed version - * of the sequencer, this code will get yanked. - */ - if(!strncmp(buffer + 8, "QUANTUM", 7) && - p->transinfo[tindex].goal_options ) - { - p->transinfo[tindex].goal_period = - MAX(p->transinfo[tindex].goal_period, 10); - p->transinfo[tindex].goal_options = 0; - p->needppr &= ~(1<<tindex); - p->needppr_copy &= ~(1<<tindex); - p->needsdtr |= (1<<tindex); - p->needsdtr_copy |= (1<<tindex); - p->needwdtr |= (1<<tindex); - p->needwdtr_copy |= (1<<tindex); - } - /* - * Get the INQUIRY checksum. We use this on Ultra 160/m - * and older devices both. It allows us to drop speed on any bus type - * while at the same time giving us the needed domain validation for - * Ultra 160/m - * - * Note: We only get the checksum and set the SCANNED bit if this is - * one of our dtr commands. If we don't do this, then we end up - * getting bad checksum results on the mid-level SCSI code's INQUIRY - * commands. - */ - if(p->dev_dtr_cmnd[tindex] == cmd) { - unsigned int checksum = 0; - int *ibuffer; - int i=0; - - ibuffer = (int *)buffer; - for( i = 0; i < (cmd->request_bufflen >> 2); i++) + else { - checksum += ibuffer[i]; + p->needsdtr &= ~(1<<tindex); + p->needsdtr_copy &= ~(1<<tindex); + p->transinfo[tindex].goal_period = 255; + p->transinfo[tindex].goal_offset = 0; + p->transinfo[tindex].goal_options = 0; } - p->dev_checksum[tindex] = checksum; - p->dev_flags[tindex] |= DEVICE_SCANNED; + p->dev_flags[tindex] |= DEVICE_DTR_SCANNED; p->dev_flags[tindex] |= DEVICE_PRINT_DTR; } #undef WIDE_INQUIRY_BITS @@ -2961,7 +2928,8 @@ #undef SCSI_DT_BIT } } - else if ((scb->flags & SCB_MSGOUT_BITS) != 0) + + if ((scb->flags & SCB_MSGOUT_BITS) != 0) { unsigned short mask; int message_error = FALSE; @@ -2981,7 +2949,6 @@ if (scb->flags & SCB_MSGOUT_WDTR) { - p->dtr_pending &= ~mask; if (message_error) { if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION2) && @@ -3000,7 +2967,6 @@ } if (scb->flags & SCB_MSGOUT_SDTR) { - p->dtr_pending &= ~mask; if (message_error) { if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION2) && @@ -3020,7 +2986,6 @@ } if (scb->flags & SCB_MSGOUT_PPR) { - p->dtr_pending &= ~mask; if(message_error) { if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION2) && @@ -3045,6 +3010,7 @@ } } } + queue_depth = p->dev_temp_queue_depth[tindex]; if (queue_depth >= p->dev_active_cmds[tindex]) { @@ -3078,9 +3044,18 @@ } } } - if ( !(scb->tag_action) && (p->tagenable & (1<<tindex)) ) + if (!(scb->tag_action)) + { + aic7xxx_index_busy_target(p, scb->hscb->target_channel_lun, + /* unbusy */ TRUE); + if (p->tagenable & (1<<tindex)) + { + p->dev_temp_queue_depth[tindex] = p->dev_max_queue_depth[tindex]; + } + } + if(scb->flags & SCB_DTR_SCB) { - p->dev_temp_queue_depth[tindex] = p->dev_max_queue_depth[tindex]; + p->dtr_pending &= ~(1 << tindex); } p->dev_active_cmds[tindex]--; p->activescbs--; @@ -3189,6 +3164,14 @@ printk(INFO_LEAD "Aborting scb %d\n", p->host_no, CTL_OF_SCB(scb), scb->hscb->tag); found++; + /* + * Clear any residual information since the normal aic7xxx_done() path + * doesn't touch the residuals. + */ + scb->hscb->residual_SG_segment_count = 0; + scb->hscb->residual_data_count[0] = 0; + scb->hscb->residual_data_count[1] = 0; + scb->hscb->residual_data_count[2] = 0; aic7xxx_done(p, scb); } } @@ -3401,8 +3384,22 @@ active_scb = aic_inb(p, SCBPTR); if (aic7xxx_verbose & (VERBOSE_RESET_PROCESS | VERBOSE_ABORT_PROCESS)) + { printk(INFO_LEAD "Reset device, active_scb %d\n", p->host_no, channel, target, lun, active_scb); + printk(INFO_LEAD "Current scb_tag %d, SEQADDR 0x%x, LASTPHASE " + "0x%x\n", + p->host_no, channel, target, lun, aic_inb(p, SCB_TAG), + aic_inb(p, SEQADDR0) | (aic_inb(p, SEQADDR1) << 8), + aic_inb(p, LASTPHASE)); + printk(INFO_LEAD "SG_CACHEPTR 0x%x, SG_COUNT %d, SCSISIGI 0x%x\n", + p->host_no, channel, target, lun, + (p->features & AHC_ULTRA2) ? aic_inb(p, SG_CACHEPTR) : 0, + aic_inb(p, SG_COUNT), aic_inb(p, SCSISIGI)); + printk(INFO_LEAD "SSTAT0 0x%x, SSTAT1 0x%x, SSTAT2 0x%x\n", + p->host_no, channel, target, lun, aic_inb(p, SSTAT0), + aic_inb(p, SSTAT1), aic_inb(p, SSTAT2)); + } /* * Deal with the busy target and linked next issues. */ @@ -3446,11 +3443,11 @@ if (aic7xxx_verbose & (VERBOSE_ABORT_PROCESS | VERBOSE_RESET_PROCESS)) printk(INFO_LEAD "Cleaning up status information " "and delayed_scbs.\n", p->host_no, channel, i, lun); - p->dev_flags[i] &= ~(BUS_DEVICE_RESET_PENDING | DEVICE_PARITY_ERROR); + p->dev_flags[i] &= ~BUS_DEVICE_RESET_PENDING; if ( tag == SCB_LIST_NULL ) { p->dev_flags[i] |= DEVICE_PRINT_DTR | DEVICE_RESET_DELAY; - p->dev_expires[i] = jiffies + (4 * HZ); + p->dev_expires[i] = jiffies + (1 * HZ); p->dev_timer_active |= (0x01 << i); p->dev_last_queue_full_count[i] = 0; p->dev_last_queue_full[i] = 0; @@ -3495,7 +3492,7 @@ prev_scbp->flags |= SCB_RESET | SCB_QUEUED_FOR_DONE; } } - if ( j > (p->scb_data->maxscbs + 1) ) + if ( j > (p->scb_data->numscbs + 1) ) { if (aic7xxx_verbose & (VERBOSE_ABORT | VERBOSE_RESET)) printk(WARN_LEAD "Yikes!! There's a loop in the " @@ -3554,7 +3551,7 @@ prev_scbp->flags |= SCB_RESET | SCB_QUEUED_FOR_DONE; } } - if ( j > (p->scb_data->maxscbs + 1) ) + if ( j > (p->scb_data->numscbs + 1) ) { if (aic7xxx_verbose & (VERBOSE_ABORT | VERBOSE_RESET)) printk(WARN_LEAD "Yikes!! There's a loop in the " @@ -4300,11 +4297,25 @@ if (actual < cmd->underflow) { if (aic7xxx_verbose & VERBOSE_MINOR_ERROR) + { printk(INFO_LEAD "Underflow - Wanted %u, %s %u, residual SG " "count %d.\n", p->host_no, CTL_OF_SCB(scb), cmd->underflow, (cmd->request.cmd == WRITE) ? "wrote" : "read", actual, hscb->residual_SG_segment_count); + printk(INFO_LEAD "status 0x%x.\n", p->host_no, CTL_OF_SCB(scb), + hscb->target_status); + } + /* + * In 2.4, only send back the residual information, don't flag this + * as an error. Before 2.4 we had to flag this as an error because + * the mid layer didn't check residual data counts to see if the + * command needs retried. + */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + cmd->resid = scb->sg_length - actual; +#else aic7xxx_error(cmd) = DID_RETRY_COMMAND; +#endif aic7xxx_status(cmd) = hscb->target_status; } } @@ -4623,7 +4634,6 @@ */ p->needwdtr &= ~target_mask; p->needwdtr_copy &= ~target_mask; - p->dtr_pending &= ~target_mask; scb->flags &= ~SCB_MSGOUT_BITS; aic7xxx_set_width(p, target, channel, lun, MSG_EXT_WDTR_BUS_8_BIT, (AHC_TRANS_ACTIVE|AHC_TRANS_GOAL|AHC_TRANS_CUR)); @@ -4643,8 +4653,7 @@ */ p->needsdtr &= ~target_mask; p->needsdtr_copy &= ~target_mask; - p->dtr_pending &= ~target_mask; - scb->flags &= ~SCB_MSGOUT_SDTR; + scb->flags &= ~SCB_MSGOUT_BITS; aic7xxx_set_syncrate(p, NULL, target, channel, 0, 0, 0, (AHC_TRANS_CUR|AHC_TRANS_ACTIVE|AHC_TRANS_GOAL)); if(aic7xxx_verbose & VERBOSE_NEGOTIATION2) @@ -4778,6 +4787,8 @@ aic7xxx_error(cmd) = DID_OK; break; } /* first time sense, no errors */ + printk(INFO_LEAD "CHECK_CONDITION on REQUEST_SENSE, returning " + "an error.\n", p->host_no, CTL_OF_SCB(scb)); aic7xxx_error(cmd) = DID_ERROR; scb->flags &= ~SCB_SENSE; break; @@ -5136,12 +5147,21 @@ printk(KERN_WARNING " %s seen Data Phase. Length=%d, NumSGs=%d.\n", (aic_inb(p, SEQ_FLAGS) & DPHASE) ? "Have" : "Haven't", scb->sg_length, scb->sg_count); - for (i = 0; i < scb->sg_count; i++) + printk(KERN_WARNING " Raw SCSI Command: 0x"); + for (i = 0; i < scb->hscb->SCSI_cmd_length; i++) + { + printk("%02x ", scb->cmd->cmnd[i]); + } + printk("\n"); + if(aic7xxx_verbose > 0xffff) { - printk(KERN_WARNING " sg[%d] - Addr 0x%x : Length %d\n", + for (i = 0; i < scb->sg_count; i++) + { + printk(KERN_WARNING " sg[%d] - Addr 0x%x : Length %d\n", i, le32_to_cpu(scb->sg_list[i].address), le32_to_cpu(scb->sg_list[i].length) ); + } } aic7xxx_error(scb->cmd) = DID_ERROR; } @@ -5156,7 +5176,7 @@ unsigned char resid_sgcnt, index; unsigned char scb_index = aic_inb(p, SCB_TAG); unsigned int cur_addr, resid_dcnt; - unsigned int native_addr, native_length; + unsigned int native_addr, native_length, sg_addr; int i; if(scb_index > p->scb_data->numscbs) @@ -5176,6 +5196,9 @@ scb->flags, (unsigned long)scb->cmd); break; } + if(aic7xxx_verbose & VERBOSE_MINOR_ERROR) + printk(INFO_LEAD "Got WIDE_RESIDUE message, patching up data " + "pointer.\n", p->host_no, CTL_OF_SCB(scb)); /* * We have a valid scb to use on this WIDE_RESIDUE message, so @@ -5188,132 +5211,87 @@ */ cur_addr = aic_inb(p, SHADDR) | (aic_inb(p, SHADDR + 1) << 8) | (aic_inb(p, SHADDR + 2) << 16) | (aic_inb(p, SHADDR + 3) << 24); + sg_addr = aic_inb(p, SG_COUNT + 1) | (aic_inb(p, SG_COUNT + 2) << 8) | + (aic_inb(p, SG_COUNT + 3) << 16) | (aic_inb(p, SG_COUNT + 4) << 24); resid_sgcnt = aic_inb(p, SCB_RESID_SGCNT); resid_dcnt = aic_inb(p, SCB_RESID_DCNT) | (aic_inb(p, SCB_RESID_DCNT + 1) << 8) | (aic_inb(p, SCB_RESID_DCNT + 2) << 16); - index = scb->sg_count - (resid_sgcnt + 1); + index = scb->sg_count - ((resid_sgcnt) ? resid_sgcnt : 1); native_addr = le32_to_cpu(scb->sg_list[index].address); native_length = le32_to_cpu(scb->sg_list[index].length); /* - * Make sure this is a valid sg_seg for the given pointer + * If resid_dcnt == native_length, then we just loaded this SG + * segment and we need to back it up one... */ - if(cur_addr < native_addr || - cur_addr > (native_addr + native_length + 1)) - { - printk(WARN_LEAD "invalid cur_addr:0x%x during WIDE_RESIDUE\n", - p->host_no, CTL_OF_SCB(scb), cur_addr); - if(index > 0) - printk(WARN_LEAD " sg_address[-1]:0x%x sg_length[-1]:%d\n", - p->host_no, CTL_OF_SCB(scb), - le32_to_cpu(scb->sg_list[index - 1].address), - le32_to_cpu(scb->sg_list[index - 1].length)); - printk(WARN_LEAD " sg_address:0x%x sg_length:%d\n", - p->host_no, CTL_OF_SCB(scb), - native_addr, native_length); - if(resid_sgcnt > 1) - printk(WARN_LEAD " sg_address[1]:0x%x sg_length[1]:%d\n", - p->host_no, CTL_OF_SCB(scb), - le32_to_cpu(scb->sg_list[index + 1].address), - le32_to_cpu(scb->sg_list[index + 1].length)); - printk(WARN_LEAD " cur_address:0x%x resid_dcnt:0x%06x\n", - p->host_no, CTL_OF_SCB(scb), - cur_addr, resid_dcnt); - break; - } - - if( (resid_sgcnt == 0) && - ((resid_dcnt == 0) || (resid_dcnt == 0xffffff))) - { - /* - * We are at the end of the transfer and this is about a byte - * we ignored already (because the sequencer knew this was - * the last segment and set the adapter to ignore any wide - * residue bytes that might come through, which is only done - * on the last scatter gather segment of transfers). - */ - break; - } - else if(cur_addr == native_addr) + if(resid_dcnt == native_length) { - /* - * If our current address matches the sg_seg->address then we - * have to back up the sg array to the previous segment and set - * it up to have only one byte of transfer left to go. - */ if(index == 0) { - printk(WARN_LEAD "bogus WIDE_RESIDUE message, no data has been " - "transferred.\n", p->host_no, CTL_OF_SCB(scb)); + /* + * Oops, this isn't right, we can't back up to before the + * beginning. This must be a bogus message, ignore it. + */ break; } - resid_sgcnt++; - index--; - cur_addr = le32_to_cpu(scb->sg_list[index].address) + - le32_to_cpu(scb->sg_list[index].length) - 1; - native_addr = aic_inb(p, SG_NEXT) | (aic_inb(p, SG_NEXT + 1) << 8) - | (aic_inb(p, SG_NEXT + 2) << 16) | (aic_inb(p, SG_NEXT + 3) << 24); - native_addr -= SG_SIZEOF; - aic_outb(p, resid_sgcnt, SG_COUNT); - aic_outb(p, resid_sgcnt, SCB_RESID_SGCNT); - aic_outb(p, native_addr & 0xff, SG_NEXT); - aic_outb(p, (native_addr >> 8) & 0xff, SG_NEXT + 1); - aic_outb(p, (native_addr >> 16) & 0xff, SG_NEXT + 2); - aic_outb(p, (native_addr >> 24) & 0xff, SG_NEXT + 3); - aic_outb(p, 1, SCB_RESID_DCNT); - aic_outb(p, 0, SCB_RESID_DCNT + 1); - aic_outb(p, 0, SCB_RESID_DCNT + 2); - aic_outb(p, 1, HCNT); - aic_outb(p, 0, HCNT + 1); - aic_outb(p, 0, HCNT + 2); - aic_outb(p, cur_addr & 0xff, HADDR); - aic_outb(p, (cur_addr >> 8) & 0xff, HADDR + 1); - aic_outb(p, (cur_addr >> 16) & 0xff, HADDR + 2); - aic_outb(p, (cur_addr >> 24) & 0xff, HADDR + 3); + resid_dcnt = 1; + resid_sgcnt += 1; + native_addr = le32_to_cpu(scb->sg_list[index - 1].address); + native_length = le32_to_cpu(scb->sg_list[index - 1].length); + cur_addr = native_addr + (native_length - 1); + sg_addr -= sizeof(struct hw_scatterlist); } else { /* - * Back the data pointer up by one and add one to the remaining - * byte count. Then store that in the HCNT and HADDR registers. + * resid_dcnt != native_length, so we are in the middle of a SG + * element. Back it up one byte and leave the rest alone. */ - cur_addr--; - resid_dcnt++; - aic_outb(p, resid_dcnt & 0xff, SCB_RESID_DCNT); - aic_outb(p, (resid_dcnt >> 8) & 0xff, SCB_RESID_DCNT + 1); - aic_outb(p, (resid_dcnt >> 16) & 0xff, SCB_RESID_DCNT + 2); - aic_outb(p, resid_dcnt & 0xff, HCNT); - aic_outb(p, (resid_dcnt >> 8) & 0xff, HCNT + 1); - aic_outb(p, (resid_dcnt >> 16) & 0xff, HCNT + 2); - aic_outb(p, cur_addr & 0xff, HADDR); - aic_outb(p, (cur_addr >> 8) & 0xff, HADDR + 1); - aic_outb(p, (cur_addr >> 16) & 0xff, HADDR + 2); - aic_outb(p, (cur_addr >> 24) & 0xff, HADDR + 3); + resid_dcnt += 1; + cur_addr -= 1; } + + /* + * Output the new addresses and counts to the right places on the + * card. + */ + aic_outb(p, resid_sgcnt, SG_COUNT); + aic_outb(p, resid_sgcnt, SCB_RESID_SGCNT); + aic_outb(p, sg_addr & 0xff, SG_COUNT + 1); + aic_outb(p, (sg_addr >> 8) & 0xff, SG_COUNT + 2); + aic_outb(p, (sg_addr >> 16) & 0xff, SG_COUNT + 3); + aic_outb(p, (sg_addr >> 24) & 0xff, SG_COUNT + 4); + aic_outb(p, resid_dcnt & 0xff, SCB_RESID_DCNT); + aic_outb(p, (resid_dcnt >> 8) & 0xff, SCB_RESID_DCNT + 1); + aic_outb(p, (resid_dcnt >> 16) & 0xff, SCB_RESID_DCNT + 2); + /* - * The sequencer actually wants to find the new address and byte - * count in the SHCNT and SHADDR register sets. These registers - * are a shadow of the regular HCNT and HADDR registers. On the - * Ultra2 controllers, these registers are read only and the way - * we have to set their values is to put the values we want into - * the HCNT and HADDR registers and then output PRELOADEN into - * the DFCNTRL register which causes the card to latch the current - * values in the HADDR and HCNT registers and drop it through to - * the shadow registers. On older cards we copy them directly - * across by hand. + * The sequencer actually wants to find the new address + * in the SHADDR register set. On the Ultra2 and later controllers + * this register set is readonly. In order to get the right number + * into the register, you actually have to enter it in HADDR and then + * use the PRELOADEN bit of DFCNTRL to drop it through from the + * HADDR register to the SHADDR register. On non-Ultra2 controllers, + * we simply write it direct. */ if(p->features & AHC_ULTRA2) { - aic_outb(p, aic_inb(p, DMAPARAMS), DFCNTRL); - i=0; + /* + * We might as well be accurate and drop both the resid_dcnt and + * cur_addr into HCNT and HADDR and have both of them drop + * through to the shadow layer together. + */ + aic_outb(p, resid_dcnt & 0xff, HCNT); + aic_outb(p, (resid_dcnt >> 8) & 0xff, HCNT + 1); + aic_outb(p, (resid_dcnt >> 16) & 0xff, HCNT + 2); + aic_outb(p, cur_addr & 0xff, HADDR); + aic_outb(p, (cur_addr >> 8) & 0xff, HADDR + 1); + aic_outb(p, (cur_addr >> 16) & 0xff, HADDR + 2); + aic_outb(p, (cur_addr >> 24) & 0xff, HADDR + 3); + aic_outb(p, aic_inb(p, DMAPARAMS) | PRELOADEN, DFCNTRL); udelay(1); - while(((aic_inb(p, SSTAT0) & SDONE) != 0) && (i++ < 1000)) - { - udelay(1); - } aic_outb(p, aic_inb(p, DMAPARAMS) & ~(SCSIEN|HDMAEN), DFCNTRL); i=0; - udelay(1); while(((aic_inb(p, DFCNTRL) & (SCSIEN|HDMAEN)) != 0) && (i++ < 1000)) { udelay(1); @@ -5321,9 +5299,6 @@ } else { - aic_outb(p, resid_dcnt & 0xff, STCNT); - aic_outb(p, (resid_dcnt >> 8) & 0xff, STCNT + 1); - aic_outb(p, (resid_dcnt >> 16) & 0xff, STCNT + 2); aic_outb(p, cur_addr & 0xff, SHADDR); aic_outb(p, (cur_addr >> 8) & 0xff, SHADDR + 1); aic_outb(p, (cur_addr >> 16) & 0xff, SHADDR + 2); @@ -5332,15 +5307,82 @@ } break; - -#if AIC7XXX_NOT_YET - case TRACEPOINT: + case SEQ_SG_FIXUP: + { + unsigned char scb_index, tmp; + int sg_addr, sg_length; + + scb_index = aic_inb(p, SCB_TAG); + + if(scb_index > p->scb_data->numscbs) { - printk(INFO_LEAD "Tracepoint #1 reached.\n", p->host_no, - channel, target, lun); + printk(WARN_LEAD "invalid scb_index during SEQ_SG_FIXUP.\n", + p->host_no, -1, -1, -1); + printk(INFO_LEAD "SCSISIGI 0x%x, SEQADDR 0x%x, SSTAT0 0x%x, SSTAT1 " + "0x%x\n", p->host_no, -1, -1, -1, + aic_inb(p, SCSISIGI), + aic_inb(p, SEQADDR0) | (aic_inb(p, SEQADDR1) << 8), + aic_inb(p, SSTAT0), aic_inb(p, SSTAT1)); + printk(INFO_LEAD "SG_CACHEPTR 0x%x, SSTAT2 0x%x, STCNT 0x%x\n", + p->host_no, -1, -1, -1, aic_inb(p, SG_CACHEPTR), + aic_inb(p, SSTAT2), aic_inb(p, STCNT + 2) << 16 | + aic_inb(p, STCNT + 1) << 8 | aic_inb(p, STCNT)); + /* + * XXX: Add error handling here + */ + break; } - break; + scb = p->scb_data->scb_array[scb_index]; + if(!(scb->flags & SCB_ACTIVE) || (scb->cmd == NULL)) + { + printk(WARN_LEAD "invalid scb during SEQ_SG_FIXUP flags:0x%x " + "scb->cmd:0x%p\n", p->host_no, CTL_OF_SCB(scb), + scb->flags, scb->cmd); + printk(INFO_LEAD "SCSISIGI 0x%x, SEQADDR 0x%x, SSTAT0 0x%x, SSTAT1 " + "0x%x\n", p->host_no, CTL_OF_SCB(scb), + aic_inb(p, SCSISIGI), + aic_inb(p, SEQADDR0) | (aic_inb(p, SEQADDR1) << 8), + aic_inb(p, SSTAT0), aic_inb(p, SSTAT1)); + printk(INFO_LEAD "SG_CACHEPTR 0x%x, SSTAT2 0x%x, STCNT 0x%x\n", + p->host_no, CTL_OF_SCB(scb), aic_inb(p, SG_CACHEPTR), + aic_inb(p, SSTAT2), aic_inb(p, STCNT + 2) << 16 | + aic_inb(p, STCNT + 1) << 8 | aic_inb(p, STCNT)); + break; + } + if(aic7xxx_verbose & VERBOSE_MINOR_ERROR) + printk(INFO_LEAD "Fixing up SG address for sequencer.\n", p->host_no, + CTL_OF_SCB(scb)); + /* + * Advance the SG pointer to the next element in the list + */ + tmp = aic_inb(p, SG_NEXT); + tmp += SG_SIZEOF; + aic_outb(p, tmp, SG_NEXT); + if( tmp < SG_SIZEOF ) + aic_outb(p, aic_inb(p, SG_NEXT + 1) + 1, SG_NEXT + 1); + tmp = aic_inb(p, SG_COUNT) - 1; + aic_outb(p, tmp, SG_COUNT); + sg_addr = le32_to_cpu(scb->sg_list[scb->sg_count - tmp].address); + sg_length = le32_to_cpu(scb->sg_list[scb->sg_count - tmp].length); + /* + * Now stuff the element we just advanced past down onto the + * card so it can be stored in the residual area. + */ + aic_outb(p, sg_addr & 0xff, HADDR); + aic_outb(p, (sg_addr >> 8) & 0xff, HADDR + 1); + aic_outb(p, (sg_addr >> 16) & 0xff, HADDR + 2); + aic_outb(p, (sg_addr >> 24) & 0xff, HADDR + 3); + aic_outb(p, sg_length & 0xff, HCNT); + aic_outb(p, (sg_length >> 8) & 0xff, HCNT + 1); + aic_outb(p, (sg_length >> 16) & 0xff, HCNT + 2); + aic_outb(p, (tmp << 2) | ((tmp == 1) ? LAST_SEG : 0), SG_CACHEPTR); + aic_outb(p, aic_inb(p, DMAPARAMS), DFCNTRL); + while(aic_inb(p, SSTAT0) & SDONE) udelay(1); + while(aic_inb(p, DFCNTRL) & (HDMAEN|SCSIEN)) aic_outb(p, 0, DFCNTRL); + } + break; +#if AIC7XXX_NOT_YET case TRACEPOINT2: { printk(INFO_LEAD "Tracepoint #2 reached.\n", p->host_no, @@ -5385,6 +5427,10 @@ unsigned char target_scsirate, tindex; unsigned short target_mask; unsigned char target, channel, lun; + unsigned char bus_width, new_bus_width; + unsigned char trans_options, new_trans_options; + unsigned int period, new_period, offset, new_offset, maxsync; + struct aic7xxx_syncrate *syncrate; target = scb->cmd->target; channel = scb->cmd->channel; @@ -5408,6 +5454,35 @@ } /* + * Even if we are an Ultra3 card, don't allow Ultra3 sync rates when + * using the SDTR messages. We need the PPR messages to enable the + * higher speeds that include things like Dual Edge clocking. + */ + if (p->features & AHC_ULTRA2) + { + if ( (aic_inb(p, SBLKCTL) & ENAB40) && + !(aic_inb(p, SSTAT2) & EXP_ACTIVE) ) + { + if (p->features & AHC_ULTRA3) + maxsync = AHC_SYNCRATE_ULTRA3; + else + maxsync = AHC_SYNCRATE_ULTRA2; + } + else + { + maxsync = AHC_SYNCRATE_ULTRA; + } + } + else if (p->features & AHC_ULTRA) + { + maxsync = AHC_SYNCRATE_ULTRA; + } + else + { + maxsync = AHC_SYNCRATE_FAST; + } + + /* * Just accept the length byte outright and perform * more checking once we know the message type. */ @@ -5418,9 +5493,6 @@ { case MSG_EXT_SDTR: { - unsigned int period, offset; - unsigned char maxsync, saved_offset, options; - struct aic7xxx_syncrate *syncrate; if (p->msg_buf[1] != MSG_EXT_SDTR_LEN) { @@ -5433,35 +5505,18 @@ break; } - period = p->msg_buf[3]; - saved_offset = offset = p->msg_buf[4]; - options = 0; + period = new_period = p->msg_buf[3]; + offset = new_offset = p->msg_buf[4]; + trans_options = new_trans_options = 0; + bus_width = new_bus_width = target_scsirate & WIDEXFER; /* - * Even if we are an Ultra3 card, don't allow Ultra3 sync rates when - * using the SDTR messages. We need the PPR messages to enable the - * higher speeds that include things like Dual Edge clocking. + * If our current max syncrate is in the Ultra3 range, bump it back + * down to Ultra2 since we can't negotiate DT transfers using SDTR */ - if (p->features & AHC_ULTRA2) - { - if ( (aic_inb(p, SBLKCTL) & ENAB40) && - !(aic_inb(p, SSTAT2) & EXP_ACTIVE) ) - { - maxsync = AHC_SYNCRATE_ULTRA2; - } - else - { - maxsync = AHC_SYNCRATE_ULTRA; - } - } - else if (p->features & AHC_ULTRA) - { - maxsync = AHC_SYNCRATE_ULTRA; - } - else - { - maxsync = AHC_SYNCRATE_FAST; - } + if(maxsync == AHC_SYNCRATE_ULTRA3) + maxsync = AHC_SYNCRATE_ULTRA2; + /* * We might have a device that is starting negotiation with us * before we can start up negotiation with it....be prepared to @@ -5471,88 +5526,116 @@ if ( (scb->flags & (SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR)) != (SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR) ) { - if (!(p->dev_flags[tindex] & DEVICE_SCANNED) && - !(p->needsdtr_copy & target_mask) && - (p->transinfo[tindex].user_offset) ) + if (!(p->dev_flags[tindex] & DEVICE_DTR_SCANNED)) { /* - * Not only is the device starting this up, but it also hasn't - * been scanned yet, so this would likely be our TUR or our - * INQUIRY command at scan time, so we need to use the - * settings from the SEEPROM if they existed. Of course, even - * if we didn't find a SEEPROM, we stuffed default values into - * the user settings anyway, so use those in all cases. + * We shouldn't get here unless this is a narrow drive, wide + * devices should trigger this same section of code in the WDTR + * handler first instead. */ - p->transinfo[tindex].goal_period = - p->transinfo[tindex].user_period; - if(p->features & AHC_ULTRA2) - { - p->transinfo[tindex].goal_offset = MAX_OFFSET_ULTRA2; - } - else if (p->transinfo[tindex].cur_width) + p->transinfo[tindex].goal_width = MSG_EXT_WDTR_BUS_8_BIT; + p->transinfo[tindex].goal_options = 0; + if(p->transinfo[tindex].user_offset) { - p->transinfo[tindex].goal_offset = MAX_OFFSET_16BIT; + p->needsdtr_copy |= target_mask; + p->transinfo[tindex].goal_period = + MAX(10,p->transinfo[tindex].user_period); + if(p->features & AHC_ULTRA2) + { + p->transinfo[tindex].goal_offset = MAX_OFFSET_ULTRA2; + } + else + { + p->transinfo[tindex].goal_offset = MAX_OFFSET_8BIT; + } } else { - p->transinfo[tindex].goal_offset = MAX_OFFSET_8BIT; + p->needsdtr_copy &= ~target_mask; + p->transinfo[tindex].goal_period = 255; + p->transinfo[tindex].goal_offset = 0; } - p->needsdtr_copy |= target_mask; + p->dev_flags[tindex] |= DEVICE_DTR_SCANNED | DEVICE_PRINT_DTR; + } + else if ((p->needsdtr_copy & target_mask) == 0) + { + /* + * This is a preemptive message from the target, we've already + * scanned this target and set our options for it, and we + * don't need a WDTR with this target (for whatever reason), + * so reject this incoming WDTR + */ + reject = TRUE; + break; } + + /* The device is sending this message first and we have to reply */ + reply = TRUE; + if (aic7xxx_verbose & VERBOSE_NEGOTIATION2) { printk(INFO_LEAD "Received pre-emptive SDTR message from " "target.\n", p->host_no, CTL_OF_SCB(scb)); } - if ( !p->transinfo[tindex].goal_offset ) - period = 255; - if ( p->transinfo[tindex].goal_period > period ) - period = p->transinfo[tindex].goal_period; + /* + * Validate the values the device passed to us against our SEEPROM + * settings. We don't have to do this if we aren't replying since + * the device isn't allowed to send values greater than the ones + * we first sent to it. + */ + new_period = MAX(period, p->transinfo[tindex].goal_period); + new_offset = MIN(offset, p->transinfo[tindex].goal_offset); } - - syncrate = aic7xxx_find_syncrate(p, &period, maxsync, &options); - aic7xxx_validate_offset(p, syncrate, &offset, - target_scsirate & WIDEXFER); - aic7xxx_set_syncrate(p, syncrate, target, channel, period, - offset, options, AHC_TRANS_ACTIVE|AHC_TRANS_CUR); + + /* + * Use our new_period, new_offset, bus_width, and card options + * to determine the actual syncrate settings + */ + syncrate = aic7xxx_find_syncrate(p, &new_period, maxsync, + &trans_options); + aic7xxx_validate_offset(p, syncrate, &new_offset, bus_width); /* - * Did we drop to async? Or are we sending a reply? If we are, - * then we have to make sure that the reply value reflects the proper - * settings so we need to set the goal values according to what - * we need to send. + * Did we drop to async? If so, send a reply regardless of whether + * or not we initiated this negotiation. */ - if ( (offset != saved_offset) || - ((scb->flags & (SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR)) != - (SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR) ) ) + if ((new_offset == 0) && (new_offset != offset)) { - aic7xxx_set_syncrate(p, syncrate, target, channel, period, offset, - options, AHC_TRANS_GOAL|AHC_TRANS_QUITE); + p->needsdtr_copy &= ~target_mask; + reply = TRUE; } /* - * Did we start this, if not, or if we went to low and had to + * Did we start this, if not, or if we went too low and had to * go async, then send an SDTR back to the target */ - p->needsdtr &= ~target_mask; - p->dtr_pending &= ~target_mask; - if ( ((scb->flags & (SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR)) != - (SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR)) || - (offset != saved_offset) ) + if(reply) { - reply = TRUE; - p->dtr_pending |= target_mask; + /* when sending a reply, make sure that the goal settings are + * updated along with current and active since the code that + * will actually build the message for the sequencer uses the + * goal settings as its guidelines. + */ + aic7xxx_set_syncrate(p, syncrate, target, channel, new_period, + new_offset, trans_options, + AHC_TRANS_GOAL|AHC_TRANS_ACTIVE|AHC_TRANS_CUR); scb->flags &= ~SCB_MSGOUT_BITS; scb->flags |= SCB_MSGOUT_SDTR; aic_outb(p, HOST_MSG, MSG_OUT); aic_outb(p, aic_inb(p, SCSISIGO) | ATNO, SCSISIGO); } + else + { + aic7xxx_set_syncrate(p, syncrate, target, channel, new_period, + new_offset, trans_options, + AHC_TRANS_ACTIVE|AHC_TRANS_CUR); + p->needsdtr &= ~target_mask; + } done = TRUE; break; } case MSG_EXT_WDTR: { - unsigned char bus_width; if (p->msg_buf[1] != MSG_EXT_WDTR_LEN) { @@ -5565,7 +5648,8 @@ break; } - bus_width = p->msg_buf[3]; + bus_width = new_bus_width = p->msg_buf[3]; + if ( (scb->flags & (SCB_MSGOUT_SENT|SCB_MSGOUT_WDTR)) == (SCB_MSGOUT_SENT|SCB_MSGOUT_WDTR) ) { @@ -5584,7 +5668,7 @@ } /* We fall through on purpose */ case MSG_EXT_WDTR_BUS_8_BIT: { - bus_width = MSG_EXT_WDTR_BUS_8_BIT; + p->transinfo[tindex].goal_width = MSG_EXT_WDTR_BUS_8_BIT; p->needwdtr_copy &= ~target_mask; break; } @@ -5593,29 +5677,40 @@ break; } } - p->dtr_pending &= ~target_mask; p->needwdtr &= ~target_mask; + aic7xxx_set_width(p, target, channel, lun, new_bus_width, + AHC_TRANS_ACTIVE|AHC_TRANS_CUR); } else { - if ( !(p->dev_flags[tindex] & DEVICE_SCANNED) ) + if ( !(p->dev_flags[tindex] & DEVICE_DTR_SCANNED) ) { /* * Well, we now know the WDTR and SYNC caps of this device since * it contacted us first, mark it as such and copy the user stuff * over to the goal stuff. */ - p->transinfo[tindex].goal_period = - p->transinfo[tindex].user_period; + if( (p->features & AHC_WIDE) && p->transinfo[tindex].user_width ) + { + p->transinfo[tindex].goal_width = MSG_EXT_WDTR_BUS_16_BIT; + p->needwdtr_copy |= target_mask; + } + + /* + * Devices that support DT transfers don't start WDTR requests + */ + p->transinfo[tindex].goal_options = 0; + if(p->transinfo[tindex].user_offset) { + p->needsdtr_copy |= target_mask; + p->transinfo[tindex].goal_period = + MAX(10,p->transinfo[tindex].user_period); if(p->features & AHC_ULTRA2) { p->transinfo[tindex].goal_offset = MAX_OFFSET_ULTRA2; } - else if( p->transinfo[tindex].user_width && - (bus_width == MSG_EXT_WDTR_BUS_16_BIT) && - p->features & AHC_WIDE ) + else if( p->transinfo[tindex].goal_width ) { p->transinfo[tindex].goal_offset = MAX_OFFSET_16BIT; } @@ -5623,48 +5718,76 @@ { p->transinfo[tindex].goal_offset = MAX_OFFSET_8BIT; } + } else { + p->needsdtr_copy &= ~target_mask; + p->transinfo[tindex].goal_period = 255; + p->transinfo[tindex].goal_offset = 0; } - p->transinfo[tindex].goal_width = - p->transinfo[tindex].user_width; - p->needwdtr_copy |= target_mask; - p->needsdtr_copy |= target_mask; + + p->dev_flags[tindex] |= DEVICE_DTR_SCANNED | DEVICE_PRINT_DTR; } - if (aic7xxx_verbose & VERBOSE_NEGOTIATION2) + else if ((p->needwdtr_copy & target_mask) == 0) { - printk(INFO_LEAD "Received pre-emptive WDTR message from " - "target.\n", p->host_no, CTL_OF_SCB(scb)); - } - switch(bus_width) + /* + * This is a preemptive message from the target, we've already + * scanned this target and set our options for it, and we + * don't need a WDTR with this target (for whatever reason), + * so reject this incoming WDTR + */ + reject = TRUE; + break; + } + + /* The device is sending this message first and we have to reply */ + reply = TRUE; + + if (aic7xxx_verbose & VERBOSE_NEGOTIATION2) { - default: + printk(INFO_LEAD "Received pre-emptive WDTR message from " + "target.\n", p->host_no, CTL_OF_SCB(scb)); + } + switch(bus_width) + { + case MSG_EXT_WDTR_BUS_16_BIT: { if ( (p->features & AHC_WIDE) && (p->transinfo[tindex].goal_width == MSG_EXT_WDTR_BUS_16_BIT) ) { - bus_width = MSG_EXT_WDTR_BUS_16_BIT; + new_bus_width = MSG_EXT_WDTR_BUS_16_BIT; break; } } /* Fall through if we aren't a wide card */ + default: case MSG_EXT_WDTR_BUS_8_BIT: { p->needwdtr_copy &= ~target_mask; - bus_width = MSG_EXT_WDTR_BUS_8_BIT; - aic7xxx_set_width(p, target, channel, lun, bus_width, - AHC_TRANS_GOAL|AHC_TRANS_QUITE); + new_bus_width = MSG_EXT_WDTR_BUS_8_BIT; break; } } - reply = TRUE; scb->flags &= ~SCB_MSGOUT_BITS; scb->flags |= SCB_MSGOUT_WDTR; p->needwdtr &= ~target_mask; - p->dtr_pending |= target_mask; + if((p->dtr_pending & target_mask) == 0) + { + /* there is no other command with SCB_DTR_SCB already set that will + * trigger the release of the dtr_pending bit. Both set the bit + * and set scb->flags |= SCB_DTR_SCB + */ + p->dtr_pending |= target_mask; + scb->flags |= SCB_DTR_SCB; + } aic_outb(p, HOST_MSG, MSG_OUT); aic_outb(p, aic_inb(p, SCSISIGO) | ATNO, SCSISIGO); + /* when sending a reply, make sure that the goal settings are + * updated along with current and active since the code that + * will actually build the message for the sequencer uses the + * goal settings as its guidelines. + */ + aic7xxx_set_width(p, target, channel, lun, new_bus_width, + AHC_TRANS_GOAL|AHC_TRANS_ACTIVE|AHC_TRANS_CUR); } - aic7xxx_set_width(p, target, channel, lun, bus_width, - AHC_TRANS_ACTIVE|AHC_TRANS_CUR); /* * By virtue of the SCSI spec, a WDTR message negates any existing @@ -5681,10 +5804,6 @@ } case MSG_EXT_PPR: { - unsigned char bus_width, trans_options, new_trans_options; - unsigned int period, offset; - unsigned char maxsync, saved_offset; - struct aic7xxx_syncrate *syncrate; if (p->msg_buf[1] != MSG_EXT_PPR_LEN) { @@ -5697,9 +5816,9 @@ break; } - period = p->msg_buf[3]; - offset = saved_offset = p->msg_buf[5]; - bus_width = p->msg_buf[6]; + period = new_period = p->msg_buf[3]; + offset = new_offset = p->msg_buf[5]; + bus_width = new_bus_width = p->msg_buf[6]; trans_options = new_trans_options = p->msg_buf[7] & 0xf; if(aic7xxx_verbose & VERBOSE_NEGOTIATION2) @@ -5709,22 +5828,6 @@ trans_options); } - if ( (aic_inb(p, SBLKCTL) & ENAB40) && - !(aic_inb(p, SSTAT2) & EXP_ACTIVE) ) - { - if(p->features & AHC_ULTRA3) - { - maxsync = AHC_SYNCRATE_ULTRA3; - } - else - { - maxsync = AHC_SYNCRATE_ULTRA2; - } - } - else - { - maxsync = AHC_SYNCRATE_ULTRA; - } /* * We might have a device that is starting negotiation with us * before we can start up negotiation with it....be prepared to @@ -5733,13 +5836,22 @@ */ if ( (scb->flags & (SCB_MSGOUT_SENT|SCB_MSGOUT_PPR)) != (SCB_MSGOUT_SENT|SCB_MSGOUT_PPR) ) - { - reply = TRUE; - scb->flags &= ~SCB_MSGOUT_BITS; - scb->flags |= SCB_MSGOUT_PPR; - p->dev_flags[tindex] |= DEVICE_SCSI_3; - if (!(p->dev_flags[tindex] & DEVICE_SCANNED)) - { + { + /* Have we scanned the device yet? */ + if (!(p->dev_flags[tindex] & DEVICE_DTR_SCANNED)) + { + /* The device is electing to use PPR messages, so we will too until + * we know better */ + p->needppr |= target_mask; + p->needppr_copy |= target_mask; + p->needsdtr &= ~target_mask; + p->needsdtr_copy &= ~target_mask; + p->needwdtr &= ~target_mask; + p->needwdtr_copy &= ~target_mask; + + /* We know the device is SCSI-3 compliant due to PPR */ + p->dev_flags[tindex] |= DEVICE_SCSI_3; + /* * Not only is the device starting this up, but it also hasn't * been scanned yet, so this would likely be our TUR or our @@ -5748,15 +5860,19 @@ * if we didn't find a SEEPROM, we stuffed default values into * the user settings anyway, so use those in all cases. */ - p->transinfo[tindex].goal_period = - p->transinfo[tindex].user_period; + p->transinfo[tindex].goal_width = + p->transinfo[tindex].user_width; if(p->transinfo[tindex].user_offset) { + p->transinfo[tindex].goal_period = + p->transinfo[tindex].user_period; + p->transinfo[tindex].goal_options = + p->transinfo[tindex].user_options; if(p->features & AHC_ULTRA2) { p->transinfo[tindex].goal_offset = MAX_OFFSET_ULTRA2; } - else if( p->transinfo[tindex].user_width && + else if( p->transinfo[tindex].goal_width && (bus_width == MSG_EXT_WDTR_BUS_16_BIT) && p->features & AHC_WIDE ) { @@ -5767,117 +5883,142 @@ p->transinfo[tindex].goal_offset = MAX_OFFSET_8BIT; } } - p->transinfo[tindex].goal_width = - p->transinfo[tindex].user_width; - p->transinfo[tindex].goal_options = - p->transinfo[tindex].user_options; + else + { + p->transinfo[tindex].goal_period = 255; + p->transinfo[tindex].goal_offset = 0; + p->transinfo[tindex].goal_options = 0; + } + p->dev_flags[tindex] |= DEVICE_DTR_SCANNED | DEVICE_PRINT_DTR; } + else if ((p->needppr_copy & target_mask) == 0) + { + /* + * This is a preemptive message from the target, we've already + * scanned this target and set our options for it, and we + * don't need a PPR with this target (for whatever reason), + * so reject this incoming PPR + */ + reject = TRUE; + break; + } + + /* The device is sending this message first and we have to reply */ + reply = TRUE; + if (aic7xxx_verbose & VERBOSE_NEGOTIATION2) { printk(INFO_LEAD "Received pre-emptive PPR message from " "target.\n", p->host_no, CTL_OF_SCB(scb)); } - if ( !p->transinfo[tindex].goal_offset ) - period = 255; - if ( p->transinfo[tindex].goal_period > period ) - period = p->transinfo[tindex].goal_period; - if ( p->transinfo[tindex].goal_options == 0 ) - new_trans_options = 0; - switch(bus_width) + + } + + switch(bus_width) + { + case MSG_EXT_WDTR_BUS_16_BIT: { - default: + if ( (p->transinfo[tindex].goal_width == + MSG_EXT_WDTR_BUS_16_BIT) && p->features & AHC_WIDE) { - if ( (p->features & AHC_WIDE) && - (p->transinfo[tindex].goal_width == - MSG_EXT_WDTR_BUS_16_BIT) ) - { - bus_width = MSG_EXT_WDTR_BUS_16_BIT; - break; - } - } /* Fall through if we aren't a wide card */ - case MSG_EXT_WDTR_BUS_8_BIT: - { - p->needwdtr_copy &= ~target_mask; - bus_width = MSG_EXT_WDTR_BUS_8_BIT; - aic7xxx_set_width(p, target, channel, lun, bus_width, - AHC_TRANS_GOAL|AHC_TRANS_QUITE); break; } } - if ( (p->transinfo[tindex].goal_period > 9) || - (p->transinfo[tindex].goal_options == 0) ) + default: { - scb->flags &= ~SCB_MSGOUT_BITS; - reject = TRUE; - reply = FALSE; - p->needppr &= ~(1 << tindex); - p->needppr_copy &= ~(1 << tindex); - if ( p->transinfo[tindex].goal_offset ) + if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION2) && + ((p->dev_flags[tindex] & DEVICE_PRINT_DTR) || + (aic7xxx_verbose > 0xffff)) ) { - p->needsdtr |= (1 << tindex); - p->needsdtr_copy |= (1 << tindex); - } - if ( p->transinfo[tindex].goal_width ) - { - p->needwdtr |= (1 << tindex); - p->needwdtr_copy |= (1 << tindex); + reply = TRUE; + printk(INFO_LEAD "Requesting %d bit transfers, rejecting.\n", + p->host_no, CTL_OF_SCB(scb), 8 * (0x01 << bus_width)); } + } /* We fall through on purpose */ + case MSG_EXT_WDTR_BUS_8_BIT: + { + /* + * According to the spec, if we aren't wide, we also can't be + * Dual Edge so clear the options byte + */ + new_trans_options = 0; + new_bus_width = MSG_EXT_WDTR_BUS_8_BIT; + break; } } + + if(reply) + { + /* when sending a reply, make sure that the goal settings are + * updated along with current and active since the code that + * will actually build the message for the sequencer uses the + * goal settings as its guidelines. + */ + aic7xxx_set_width(p, target, channel, lun, new_bus_width, + AHC_TRANS_GOAL|AHC_TRANS_ACTIVE|AHC_TRANS_CUR); + syncrate = aic7xxx_find_syncrate(p, &new_period, maxsync, + &new_trans_options); + aic7xxx_validate_offset(p, syncrate, &new_offset, new_bus_width); + aic7xxx_set_syncrate(p, syncrate, target, channel, new_period, + new_offset, new_trans_options, + AHC_TRANS_GOAL|AHC_TRANS_ACTIVE|AHC_TRANS_CUR); + } else { - switch(bus_width) + aic7xxx_set_width(p, target, channel, lun, new_bus_width, + AHC_TRANS_ACTIVE|AHC_TRANS_CUR); + syncrate = aic7xxx_find_syncrate(p, &new_period, maxsync, + &new_trans_options); + aic7xxx_validate_offset(p, syncrate, &new_offset, new_bus_width); + aic7xxx_set_syncrate(p, syncrate, target, channel, new_period, + new_offset, new_trans_options, + AHC_TRANS_ACTIVE|AHC_TRANS_CUR); + } + + /* + * As it turns out, if we don't *have* to have PPR messages, then + * configure ourselves not to use them since that makes some + * external drive chassis work (those chassis can't parse PPR + * messages and they mangle the SCSI bus until you send a WDTR + * and SDTR that they can understand). + */ + if(new_trans_options == 0) + { + p->needppr &= ~target_mask; + p->needppr_copy &= ~target_mask; + if(new_offset) { - default: - { - reject = TRUE; - if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION2) && - ((p->dev_flags[tindex] & DEVICE_PRINT_DTR) || - (aic7xxx_verbose > 0xffff)) ) - { - printk(INFO_LEAD "Requesting %d bit transfers, rejecting.\n", - p->host_no, CTL_OF_SCB(scb), 8 * (0x01 << bus_width)); - } - } /* We fall through on purpose */ - case MSG_EXT_WDTR_BUS_8_BIT: - { - /* - * According to the spec, if we aren't wide, we also can't be - * Dual Edge so clear the options byte - */ - new_trans_options = 0; - bus_width = MSG_EXT_WDTR_BUS_8_BIT; - break; - } - case MSG_EXT_WDTR_BUS_16_BIT: - { - break; - } + p->needsdtr |= target_mask; + p->needsdtr_copy |= target_mask; + } + if (new_bus_width) + { + p->needwdtr |= target_mask; + p->needwdtr_copy |= target_mask; } } - if ( !reject ) + if((new_offset == 0) && (offset != 0)) { - aic7xxx_set_width(p, target, channel, lun, bus_width, - AHC_TRANS_ACTIVE|AHC_TRANS_CUR); - syncrate = aic7xxx_find_syncrate(p, &period, maxsync, - &new_trans_options); - aic7xxx_validate_offset(p, syncrate, &offset, bus_width); - aic7xxx_set_syncrate(p, syncrate, target, channel, period, - offset, new_trans_options, - AHC_TRANS_ACTIVE|AHC_TRANS_CUR); + /* + * Oops, the syncrate went to low for this card and we fell off + * to async (should never happen with a device that uses PPR + * messages, but have to be complete) + */ + reply = TRUE; } - p->dtr_pending &= ~target_mask; - p->needppr &= ~target_mask; if(reply) { - p->dtr_pending |= target_mask; scb->flags &= ~SCB_MSGOUT_BITS; scb->flags |= SCB_MSGOUT_PPR; aic_outb(p, HOST_MSG, MSG_OUT); aic_outb(p, aic_inb(p, SCSISIGO) | ATNO, SCSISIGO); } + else + { + p->needppr &= ~target_mask; + } done = TRUE; break; } @@ -6115,16 +6256,14 @@ printerror = 0; } } - if ( (scb != NULL) && - (scb->cmd == p->dev_dtr_cmnd[TARGET_INDEX(scb->cmd)]) ) + if ( (scb != NULL) && (scb->flags & SCB_DTR_SCB) ) { /* - * This might be a SCSI-3 device that is dropping the bus due to - * errors and signalling that we should reduce the transfer speed. - * All we have to do is complete this command (since it's a negotiation - * command already) and the checksum routine should flag an error and - * reduce the speed setting and renegotiate. We call the reset routing - * just to clean out the hardware from this scb. + * Hmmm...error during a negotiation command. Either we have a + * borken bus, or the device doesn't like our negotiation message. + * Since we check the INQUIRY data of a device before sending it + * negotiation messages, assume the bus is borken for whatever + * reason. Complete the command. */ printerror = 0; aic7xxx_reset_device(p, target, channel, ALL_LUNS, scb->hscb->tag); @@ -6256,19 +6395,6 @@ cmd->result = 0; scb = NULL; } - else if (scb->cmd == p->dev_dtr_cmnd[TARGET_INDEX(scb->cmd)]) - { - /* - * Turn off the needsdtr, needwdtr, and needppr bits since this device - * doesn't seem to exist. - */ - p->needppr &= ~(0x01 << TARGET_INDEX(scb->cmd)); - p->needppr_copy &= ~(0x01 << TARGET_INDEX(scb->cmd)); - p->needsdtr &= ~(0x01 << TARGET_INDEX(scb->cmd)); - p->needsdtr_copy &= ~(0x01 << TARGET_INDEX(scb->cmd)); - p->needwdtr &= ~(0x01 << TARGET_INDEX(scb->cmd)); - p->needwdtr_copy &= ~(0x01 << TARGET_INDEX(scb->cmd)); - } } /* * Keep the sequencer from trying to restart any selections @@ -6391,7 +6517,6 @@ } } else if( (lastphase == P_MESGOUT) && - (cmd == p->dev_dtr_cmnd[tindex]) && (scb->flags & SCB_MSGOUT_PPR) ) { /* @@ -6410,7 +6535,6 @@ aic7xxx_set_syncrate(p, NULL, scb->cmd->target, scb->cmd->channel, 0, 0, 0, AHC_TRANS_ACTIVE|AHC_TRANS_CUR|AHC_TRANS_QUITE); p->transinfo[tindex].goal_options = 0; - p->dtr_pending &= ~(1 << tindex); scb->flags &= ~SCB_MSGOUT_BITS; if(aic7xxx_verbose & VERBOSE_NEGOTIATION2) { @@ -6433,87 +6557,6 @@ } scb = NULL; } - else if(p->dev_flags[tindex] & DEVICE_PARITY_ERROR) - { - struct aic7xxx_syncrate *syncrate; - unsigned int period = p->transinfo[tindex].cur_period; - unsigned char options = p->transinfo[tindex].cur_options; - /* - * oops, we had a failure, lower the transfer rate and try again. It's - * worth noting here that it might be wise to also check for typical - * wide setting on narrow cable type problems and try disabling wide - * instead of slowing down if those exist. That's hard to do with simple - * checksums though. - */ - printk(WARN_LEAD "Parity error during %s phase.\n", - p->host_no, CTL_OF_SCB(scb), phase); - if((syncrate = aic7xxx_find_syncrate(p, &period, 0, &options)) != NULL) - { - syncrate++; - if( (syncrate->rate[0] != NULL) && - (!(p->features & AHC_ULTRA2) || (syncrate->sxfr_ultra2 == 0)) ) - { - p->transinfo[tindex].goal_period = syncrate->period; - if( p->transinfo[tindex].goal_period > 9 ) - { - p->transinfo[tindex].goal_options = 0; - p->needppr &= ~(1<<tindex); - p->needsdtr |= (1<<tindex); - p->needppr_copy &= ~(1<<tindex); - p->needsdtr_copy |= (1<<tindex); - if (p->transinfo[tindex].goal_width) - { - p->needwdtr |= (1<<tindex); - p->needwdtr_copy |= (1<<tindex); - } - } - } - else if (p->transinfo[tindex].goal_width) - { - p->transinfo[tindex].goal_width = 0; - p->needwdtr &= ~(1<<tindex); - p->needwdtr_copy &= ~(1<<tindex); - p->transinfo[tindex].goal_offset = - p->transinfo[tindex].user_offset; - p->transinfo[tindex].goal_period = - p->transinfo[tindex].user_period; - p->transinfo[tindex].goal_options = - p->transinfo[tindex].user_options; - if( p->transinfo[tindex].goal_period <= 9 ) - { - p->needppr |= (1<<tindex); - p->needsdtr &= ~(1<<tindex); - p->needppr_copy |= (1<<tindex); - p->needsdtr_copy &= ~(1<<tindex); - } - else - { - p->needppr &= ~(1<<tindex); - p->needsdtr |= (1<<tindex); - p->needppr_copy &= ~(1<<tindex); - p->needsdtr_copy |= (1<<tindex); - } - } - else - { - p->transinfo[tindex].goal_offset = 0; - p->transinfo[tindex].goal_period = 255; - p->transinfo[tindex].goal_options = 0; - p->transinfo[tindex].goal_width = 0; - p->needppr &= ~(1<<tindex); - p->needsdtr &= ~(1<<tindex); - p->needwdtr &= ~(1<<tindex); - p->needppr_copy &= ~(1<<tindex); - p->needsdtr_copy &= ~(1<<tindex); - p->needwdtr_copy &= ~(1<<tindex); - } - } - p->dev_flags[tindex] &= ~DEVICE_PARITY_ERROR; - } - else - { - p->dev_flags[tindex] |= DEVICE_PARITY_ERROR; - } /* * We've set the hardware to assert ATN if we get a parity @@ -6782,34 +6825,11 @@ else if (scb->flags & SCB_SENSE) { char *buffer = &scb->cmd->sense_buffer[0]; - if (scb->cmd == p->dev_dtr_cmnd[tindex]) - { - struct aic7xxx_scb *old_scb; - /* - * We have valid sense data, send it back immediately. - */ - old_scb = p->scb_data->scb_array[scb->cmd->next->tag]; - *old_scb->cmd->sense_buffer = *scb->cmd->sense_buffer; - old_scb->hscb->target_status = scb->hscb->target_status; - old_scb->cmd->result = scb->hscb->target_status; - old_scb->cmd->result |= (DID_ERROR << 16); - aic7xxx_status(old_scb->cmd) = scb->hscb->target_status; - scbq_remove(&p->waiting_scbs, old_scb); - scbq_remove(&p->delayed_scbs[tindex], old_scb); - scb->cmd->next = NULL; - aic7xxx_done(p, scb); - aic7xxx_done(p, old_scb); - continue; - } - else if (buffer[12] == 0x47 || buffer[12] == 0x54) + + if (buffer[12] == 0x47 || buffer[12] == 0x54) { /* - * SCSI errors, run domain validation and re-run negotiation - */ - p->needdv |= (1<<tindex); - /* - * Signal that we need to re-negotiate things, this also gets us our - * INQUIRY command to re-checksum off of. + * Signal that we need to re-negotiate things. */ p->needppr |= (p->needppr_copy & (1<<tindex)); p->needsdtr |= (p->needsdtr_copy & (1<<tindex)); @@ -6822,7 +6842,18 @@ case BUSY: scb->hscb->target_status = 0; scb->cmd->result = 0; + scb->hscb->residual_SG_segment_count = 0; + scb->hscb->residual_data_count[0] = 0; + scb->hscb->residual_data_count[1] = 0; + scb->hscb->residual_data_count[2] = 0; aic7xxx_error(scb->cmd) = DID_OK; + aic7xxx_status(scb->cmd) = 0; + /* + * The QUEUE_FULL/BUSY handler in aic7xxx_seqint takes care of putting + * this command on a timer and allowing us to retry it. Here, we + * just 0 out a few values so that they don't carry through to when + * the command finally does complete. + */ break; default: cmd = scb->cmd; @@ -6987,18 +7018,14 @@ if(!p) return; spin_lock_irqsave(&io_request_lock, cpu_flags); - if(test_and_set_bit(AHC_IN_ISR_BIT, (void *)&p->flags)) - { - spin_unlock_irqrestore(&io_request_lock, cpu_flags); - return; - } + p->flags |= AHC_IN_ISR; do { aic7xxx_isr(irq, dev_id, regs); } while ( (aic_inb(p, INTSTAT) & INT_PEND) ); aic7xxx_done_cmds_complete(p); aic7xxx_run_waiting_queues(p); - clear_bit(AHC_IN_ISR_BIT, (void *)&p->flags); + p->flags &= ~AHC_IN_ISR; spin_unlock_irqrestore(&io_request_lock, cpu_flags); } @@ -8779,7 +8806,7 @@ /* * In the future, we may call this function as a last resort for - * error handling. Let's be nice and not do any unecessary delays. + * error handling. Let's be nice and not do any unnecessary delays. */ wait = 1000; /* 1 msec (1000 * 1 msec) */ while (--wait && !(aic_inb(p, HCNTRL) & CHIPRSTACK)) @@ -8923,22 +8950,6 @@ kfree(p->scb_data); } - /* - * Free any alloced Scsi_Cmnd structures that might be around for - * negotiation purposes.... - */ - for (i = 0; i < MAX_TARGETS; i++) - { - if(p->dev_dtr_cmnd[i]) - { - if(p->dev_dtr_cmnd[i]->request_buffer) - { - kfree(p->dev_dtr_cmnd[i]->request_buffer); - } - kfree(p->dev_dtr_cmnd[i]); - } - } - pci_free_consistent(p->pdev, 3*256, (void *)p->untagged_scbs, p->fifo_dma); } @@ -9325,7 +9336,7 @@ } aic_outb(p, ~(p->discenable & 0xFF), DISC_DSB); aic_outb(p, ~((p->discenable >> 8) & 0xFF), DISC_DSB + 1); - p->needppr = p->needppr_copy = p->needdv = 0; + p->needppr = p->needppr_copy = 0; p->needwdtr = p->needwdtr_copy; p->needsdtr = p->needsdtr_copy; p->dtr_pending = 0; @@ -9383,6 +9394,81 @@ /*+F************************************************************************* * Function: + * aic7xxx_configure_bugs + * + * Description: + * Take the card passed in and set the appropriate bug flags based upon + * the card model. Also make any changes needed to device registers or + * PCI registers while we are here. + *-F*************************************************************************/ +static void +aic7xxx_configure_bugs(struct aic7xxx_host *p) +{ + unsigned short tmp_word; + + switch(p->chip & AHC_CHIPID_MASK) + { + case AHC_AIC7860: + p->bugs |= AHC_BUG_PCI_2_1_RETRY; + /* fall through */ + case AHC_AIC7850: + case AHC_AIC7870: + p->bugs |= AHC_BUG_TMODE_WIDEODD | AHC_BUG_CACHETHEN | AHC_BUG_PCI_MWI; + break; + case AHC_AIC7880: + p->bugs |= AHC_BUG_TMODE_WIDEODD | AHC_BUG_PCI_2_1_RETRY | + AHC_BUG_CACHETHEN | AHC_BUG_PCI_MWI; + break; + case AHC_AIC7890: + p->bugs |= AHC_BUG_AUTOFLUSH | AHC_BUG_CACHETHEN; + break; + case AHC_AIC7892: + p->bugs |= AHC_BUG_SCBCHAN_UPLOAD; + break; + case AHC_AIC7895: + p->bugs |= AHC_BUG_TMODE_WIDEODD | AHC_BUG_PCI_2_1_RETRY | + AHC_BUG_CACHETHEN | AHC_BUG_PCI_MWI; + break; + case AHC_AIC7896: + p->bugs |= AHC_BUG_CACHETHEN_DIS; + break; + case AHC_AIC7899: + p->bugs |= AHC_BUG_SCBCHAN_UPLOAD; + break; + default: + /* Nothing to do */ + break; + } + + /* + * Now handle the bugs that require PCI register or card register tweaks + */ + pci_read_config_word(p->pdev, PCI_COMMAND, &tmp_word); + if(p->bugs & AHC_BUG_PCI_MWI) + { + tmp_word &= ~PCI_COMMAND_INVALIDATE; + } + else + { + tmp_word |= PCI_COMMAND_INVALIDATE; + } + pci_write_config_word(p->pdev, PCI_COMMAND, tmp_word); + + if(p->bugs & AHC_BUG_CACHETHEN) + { + aic_outb(p, aic_inb(p, DSCOMMAND0) & ~CACHETHEN, DSCOMMAND0); + } + else if (p->bugs & AHC_BUG_CACHETHEN_DIS) + { + aic_outb(p, aic_inb(p, DSCOMMAND0) | CACHETHEN, DSCOMMAND0); + } + + return; +} + + +/*+F************************************************************************* + * Function: * aic7xxx_detect * * Description: @@ -10076,6 +10162,14 @@ aic_outb(temp_p, DFTHRSH_100, DSPCISTATUS); } + /* + * Call our function to fixup any bugs that exist on this chipset. + * This may muck with PCI settings and other device settings, so + * make sure it's after all the other PCI and device register + * tweaks so it can back out bad settings on specific broken cards. + */ + aic7xxx_configure_bugs(temp_p); + if ( list_p == NULL ) { list_p = current_p = temp_p; @@ -10319,6 +10413,11 @@ } /* + * All the 7770 based chipsets have this bug + */ + temp_p->bugs |= AHC_BUG_TMODE_WIDEODD; + + /* * Set the FIFO threshold and the bus off time. */ hostconf = aic_inb(temp_p, HOSTCONF); @@ -10537,308 +10636,16 @@ return (found); } -static void aic7xxx_build_negotiation_cmnd(struct aic7xxx_host *p, - Scsi_Cmnd *old_cmd, int tindex); - +#ifdef AIC7XXX_VERBOSE_DEBUGGING /*+F************************************************************************* * Function: - * aic7xxx_allocate_negotiation_command + * aic7xxx_print_scb * * Description: - * allocate the actual command struct and fill in the gaps... + * Dump the byte codes for an about to be sent SCB. *-F*************************************************************************/ -static Scsi_Cmnd * -aic7xxx_allocate_negotiation_command(struct aic7xxx_host *p, - Scsi_Cmnd *old_cmd, int tindex) -{ - Scsi_Cmnd *cmd; - char *buffer; - - if (!(p->dev_dtr_cmnd[tindex] = kmalloc(sizeof(Scsi_Cmnd), GFP_ATOMIC)) ) - { - return(NULL); - } - if (!(buffer = kmalloc(256, GFP_ATOMIC))) - { - kfree(p->dev_dtr_cmnd[tindex]); - p->dev_dtr_cmnd[tindex] = NULL; - return(NULL); - } - cmd = p->dev_dtr_cmnd[tindex]; - memset(cmd, 0, sizeof(Scsi_Cmnd)); - memcpy(cmd, old_cmd, sizeof(Scsi_Cmnd)); - memset(&cmd->cmnd[0], 0, sizeof(cmd->cmnd)); - memset(&cmd->data_cmnd[0], 0, sizeof(cmd->data_cmnd)); - cmd->lun = 0; - cmd->request_bufflen = 255; - cmd->request_buffer = buffer; - cmd->sc_data_direction = SCSI_DATA_READ; - cmd->use_sg = cmd->old_use_sg = cmd->sglist_len = 0; - cmd->bufflen = 0; - cmd->buffer = NULL; - cmd->underflow = 0; - cmd->cmd_len = 6; - cmd->cmnd[0] = cmd->data_cmnd[0] = INQUIRY; - cmd->cmnd[1] = cmd->data_cmnd[1] = 0; - cmd->cmnd[2] = cmd->data_cmnd[2] = 0; - cmd->cmnd[3] = cmd->data_cmnd[3] = 0; - cmd->cmnd[4] = cmd->data_cmnd[4] = 255; /* match what scsi.c does here */ - cmd->cmnd[5] = cmd->data_cmnd[5] = 0; - return(cmd); -} - -/*+F************************************************************************* - * Function: - * aic7xxx_negotiation_complete - * - * Description: - * Handle completion events for our Negotiation commands. Clear out the - * struct and get it ready for its next use. - *-F*************************************************************************/ -static void -aic7xxx_negotiation_complete(Scsi_Cmnd *cmd) -{ - unsigned int checksum; - int i; - int *ibuffer; - struct aic7xxx_host *p = (struct aic7xxx_host *)cmd->host->hostdata; - int tindex = TARGET_INDEX(cmd); - struct aic7xxx_syncrate *syncrate; - - /* - * perform our minimalistic domain validation - */ - if(p->dev_flags[tindex] & DEVICE_SCANNED) - { - ibuffer = (int *)cmd->request_buffer; - checksum = 0; - for(i = 0; i < (cmd->request_bufflen >> 2); i++) - { - checksum += ibuffer[i]; - } - if( (checksum != p->dev_checksum[tindex]) && - (p->transinfo[tindex].cur_offset != 0) ) - { - unsigned int period = p->transinfo[tindex].cur_period; - unsigned char options = p->transinfo[tindex].cur_options; - - if (p->needdv & (1<<tindex)) - { - /* - * oops, we had a failure, lower the transfer rate and try again. It's - * worth noting here that it might be wise to also check for typical - * wide setting on narrow cable type problems and try disabling wide - * instead of slowing down if those exist. That's hard to do with simple - * checksums though. - */ - if(aic7xxx_verbose & VERBOSE_NEGOTIATION2) - { - printk(INFO_LEAD "reducing SCSI transfer speed due to Domain " - "validation failure.\n", p->host_no, CTL_OF_CMD(cmd)); - } - if((syncrate = aic7xxx_find_syncrate(p, &period, 0, &options)) != NULL) - { - syncrate++; - if( (syncrate->rate[0] != NULL) && - (!(p->features & AHC_ULTRA2) || (syncrate->sxfr_ultra2 == 0)) ) - { - p->transinfo[tindex].goal_period = syncrate->period; - if( p->transinfo[tindex].goal_period > 9 ) - { - p->transinfo[tindex].goal_options = 0; - p->needppr &= ~(1<<tindex); - p->needsdtr |= (1<<tindex); - p->needppr_copy &= ~(1<<tindex); - p->needsdtr_copy |= (1<<tindex); - if (p->transinfo[tindex].goal_width) - { - p->needwdtr |= (1<<tindex); - p->needwdtr_copy |= (1<<tindex); - } - } - } - else if (p->transinfo[tindex].goal_width) - { - p->transinfo[tindex].goal_width = 0; - p->needwdtr &= ~(1<<tindex); - p->needwdtr_copy &= ~(1<<tindex); - p->transinfo[tindex].goal_offset = - p->transinfo[tindex].user_offset; - p->transinfo[tindex].goal_period = - p->transinfo[tindex].user_period; - p->transinfo[tindex].goal_options = - p->transinfo[tindex].user_options; - if( p->transinfo[tindex].goal_period <= 9 ) - { - p->needppr |= (1<<tindex); - p->needsdtr &= ~(1<<tindex); - p->needppr_copy |= (1<<tindex); - p->needsdtr_copy &= ~(1<<tindex); - } - else - { - p->needppr &= ~(1<<tindex); - p->needsdtr |= (1<<tindex); - p->needppr_copy &= ~(1<<tindex); - p->needsdtr_copy |= (1<<tindex); - } - } - else - { - p->transinfo[tindex].goal_offset = 0; - p->transinfo[tindex].goal_period = 255; - p->transinfo[tindex].goal_options = 0; - p->transinfo[tindex].goal_width = 0; - p->needppr &= ~(1<<tindex); - p->needsdtr &= ~(1<<tindex); - p->needwdtr &= ~(1<<tindex); - p->needppr_copy &= ~(1<<tindex); - p->needsdtr_copy &= ~(1<<tindex); - p->needwdtr_copy &= ~(1<<tindex); - } - } - p->needdv &= ~(1<<tindex); - } - else - { - if(aic7xxx_verbose & VERBOSE_NEGOTIATION2) - { - printk(INFO_LEAD "Performing Domain validation.\n", - p->host_no, CTL_OF_CMD(cmd)); - } - /* - * Update the checksum in case the INQUIRY data has changed, maybe - * in relation to a change in the mode pages, or whatever. - */ - p->dev_checksum[tindex] = checksum; - /* - * Signal that we are trying out the domain validation - */ - p->needdv |= (1<<tindex); - /* - * Signal that we need to re-negotiate things, this also gets us our - * INQUIRY command to re-checksum off of. - */ - p->needppr |= (p->needppr_copy & (1<<tindex)); - p->needsdtr |= (p->needsdtr_copy & (1<<tindex)); - p->needwdtr |= (p->needwdtr_copy & (1<<tindex)); - } - } - else - { - if( (aic7xxx_verbose & VERBOSE_NEGOTIATION2) && - (p->needdv & (1<<tindex)) ) - { - printk(INFO_LEAD "Successfully completed Domain validation.\n", - p->host_no, CTL_OF_CMD(cmd)); - } - /* - * We successfully did our checksum, so don't leave the needdv flag set - * in case we might have set it last time through. - */ - p->needdv &= ~(1<<tindex); - } - } - - p->dtr_pending &= ~(0x01 << tindex); - /* - * This looks recursive in the extreme, but if this was a WDTR negotiation - * and we didn't follow up with SDTR yet, then this will get it started. - * For all other cases, this should work out to be a no-op, unless we are - * doing domain validation and happen to need a new negotiation command. - * - * In case we don't want this to go any further, the cmdcmplt interrupt - * handler will NULL out the cmd->next entry so that the real SCSI command - * can be sent back to the mid layer code with SENSE data intact. We'll - * finish things up when the cmd gets sent back down to us, so no worries. - */ - if(cmd->next) - { - aic7xxx_build_negotiation_cmnd(p, cmd->next, tindex); - } - return; -} - -/*+F************************************************************************* - * Function: - * aic7xxx_build_negotiation_command - * - * Description: - * Build a Scsi_Cmnd structure to perform negotiation with or else send - * a pre-built command specifically for this purpose. - *-F*************************************************************************/ -static void -aic7xxx_build_negotiation_cmnd(struct aic7xxx_host *p, Scsi_Cmnd *old_cmd, - int tindex) -{ - - if ( !(p->dtr_pending & (1<<tindex)) && - ( (p->needppr & (1<<tindex)) || - (p->needwdtr & (1<<tindex)) || - (p->needsdtr & (1<<tindex)) ) ) - { - if ( (p->dev_dtr_cmnd[tindex] == NULL) && - (aic7xxx_allocate_negotiation_command(p, old_cmd, tindex) == NULL) ) - { - return; - } - /* - * Before sending this thing out, we also make the cmd->next pointer - * point to the real command so we can stuff any possible SENSE data - * into the real command instead of this fake command. This has to be - * done each time the command is built, not just the first time, hence - * it's outside of the above if()... - */ - p->dev_dtr_cmnd[tindex]->next = old_cmd; - /* - * Clear the buffer so checksums come out right.... - */ - memset(p->dev_dtr_cmnd[tindex]->request_buffer, 0, - p->dev_dtr_cmnd[tindex]->request_bufflen); - /* - * Remove any commands for this particular device that might be on the - * waiting_scbs queue or qinfifo so that this command goes out first. - * This is vital for our implementation of domain validation. - */ - pause_sequencer(p); - aic7xxx_search_qinfifo(p, old_cmd->target, old_cmd->channel, ALL_LUNS, - SCB_LIST_NULL, 0, TRUE, &p->delayed_scbs[tindex]); - unpause_sequencer(p, FALSE); - { - struct aic7xxx_scb *scb, *next; - - scb = p->waiting_scbs.head; - while(scb != NULL) - { - if( aic7xxx_match_scb(p, scb, old_cmd->target, old_cmd->channel, - ALL_LUNS, SCB_LIST_NULL) ) - { - next = scb->q_next; - scbq_remove(&p->waiting_scbs, scb); - scbq_insert_tail(&p->delayed_scbs[tindex], scb); - scb = next; - } - else - { - scb = scb->q_next; - } - } - } - aic7xxx_queue(p->dev_dtr_cmnd[tindex], - aic7xxx_negotiation_complete); - } -} - -#ifdef AIC7XXX_VERBOSE_DEBUGGING -/*+F************************************************************************* - * Function: - * aic7xxx_print_scb - * - * Description: - * Dump the byte codes for an about to be sent SCB. - *-F*************************************************************************/ -static void -aic7xxx_print_scb(struct aic7xxx_host *p, struct aic7xxx_scb *scb) +static void +aic7xxx_print_scb(struct aic7xxx_host *p, struct aic7xxx_scb *scb) { int i; unsigned char *x; @@ -10877,7 +10684,7 @@ */ hscb->control = 0; scb->tag_action = 0; - cmd->tag = hscb->tag; + if (p->discenable & mask) { hscb->control |= DISCENB; @@ -10906,34 +10713,29 @@ } } } - if ( cmd == p->dev_dtr_cmnd[tindex] ) + if ( !(p->dtr_pending & mask) && + ( (p->needppr & mask) || + (p->needwdtr & mask) || + (p->needsdtr & mask) ) && + (p->dev_flags[tindex] & DEVICE_DTR_SCANNED) ) { p->dtr_pending |= mask; scb->tag_action = 0; - if (p->dev_flags[tindex] & DEVICE_SCANNED) + hscb->control &= DISCENB; + hscb->control |= MK_MESSAGE; + if(p->needppr & mask) { - hscb->control &= DISCENB; - hscb->control |= MK_MESSAGE; - if(p->needppr & mask) - { - scb->flags |= SCB_MSGOUT_PPR; - } - else if(p->needwdtr & mask) - { - scb->flags |= SCB_MSGOUT_WDTR; - } - else if(p->needsdtr & mask) - { - scb->flags |= SCB_MSGOUT_SDTR; - } + scb->flags |= SCB_MSGOUT_PPR; } - } - if ( !(p->dtr_pending & mask) && - ( (p->needppr & mask) || - (p->needwdtr & mask) || - (p->needsdtr & mask) ) ) - { - aic7xxx_build_negotiation_cmnd(p, cmd, tindex); + else if(p->needwdtr & mask) + { + scb->flags |= SCB_MSGOUT_WDTR; + } + else if(p->needsdtr & mask) + { + scb->flags |= SCB_MSGOUT_SDTR; + } + scb->flags |= SCB_DTR_SCB; } hscb->target_channel_lun = ((cmd->target << 4) & 0xF0) | ((cmd->channel & 0x01) << 3) | (cmd->lun & 0x07); @@ -11079,50 +10881,58 @@ aic7xxx_allocate_scb(p); DRIVER_UNLOCK scb = scbq_remove_head(&p->scb_data->free_scbs); - } - if (scb == NULL) - { - printk(WARN_LEAD "Couldn't get a free SCB.\n", p->host_no, - CTL_OF_CMD(cmd)); - cmd->result = (DID_BUS_BUSY << 16); + if(scb == NULL) + printk(WARN_LEAD "Couldn't get a free SCB.\n", p->host_no, + CTL_OF_CMD(cmd)); + } + while (scb == NULL) + { + /* + * Well, all SCBs are currently active on the bus. So, we spin here + * running the interrupt handler until one completes and becomes free. + * We can do this safely because we either A) hold the driver lock (in + * 2.0 kernels) or we have the io_request_lock held (in 2.2 and later + * kernels) and so either way, we won't take any other interrupts and + * the queue path will block until we release it. Also, we would worry + * about running the completion queues, but obviously there are plenty + * of commands outstanding to trigger a later interrupt that will do + * that for us, so skip it here. + */ DRIVER_LOCK - aic7xxx_queue_cmd_complete(p, cmd); + aic7xxx_isr(p->irq, p, NULL); DRIVER_UNLOCK - return 0; + scb = scbq_remove_head(&p->scb_data->free_scbs); } - else - { - scb->cmd = cmd; - aic7xxx_position(cmd) = scb->hscb->tag; + scb->cmd = cmd; + aic7xxx_position(cmd) = scb->hscb->tag; - /* - * Construct the SCB beforehand, so the sequencer is - * paused a minimal amount of time. - */ - aic7xxx_buildscb(p, cmd, scb); + /* + * Make sure the Scsi_Cmnd pointer is saved, the struct it points to + * is set up properly, and the parity error flag is reset, then send + * the SCB to the sequencer and watch the fun begin. + */ + cmd->scsi_done = fn; + cmd->result = DID_OK; + memset(cmd->sense_buffer, 0, sizeof(cmd->sense_buffer)); + aic7xxx_error(cmd) = DID_OK; + aic7xxx_status(cmd) = 0; + cmd->host_scribble = NULL; - /* - * Make sure the Scsi_Cmnd pointer is saved, the struct it points to - * is set up properly, and the parity error flag is reset, then send - * the SCB to the sequencer and watch the fun begin. - */ - cmd->scsi_done = fn; - cmd->result = DID_OK; - memset(cmd->sense_buffer, 0, sizeof(cmd->sense_buffer)); - aic7xxx_error(cmd) = DID_OK; - aic7xxx_status(cmd) = 0; - cmd->host_scribble = NULL; + /* + * Construct the SCB beforehand, so the sequencer is + * paused a minimal amount of time. + */ + aic7xxx_buildscb(p, cmd, scb); - scb->flags |= SCB_ACTIVE | SCB_WAITINGQ; + scb->flags |= SCB_ACTIVE | SCB_WAITINGQ; - DRIVER_LOCK - scbq_insert_tail(&p->waiting_scbs, scb); - if ( (p->flags & (AHC_IN_ISR | AHC_IN_ABORT | AHC_IN_RESET)) == 0) - { - aic7xxx_run_waiting_queues(p); - } - DRIVER_UNLOCK + DRIVER_LOCK + scbq_insert_tail(&p->waiting_scbs, scb); + if ( (p->flags & (AHC_IN_ISR | AHC_IN_ABORT | AHC_IN_RESET)) == 0) + { + aic7xxx_run_waiting_queues(p); } + DRIVER_UNLOCK return (0); } @@ -11188,6 +10998,12 @@ aic_inb(p, SCSISIGI), aic_inb(p, SEQADDR0) | (aic_inb(p, SEQADDR1) << 8), aic_inb(p, SSTAT0), aic_inb(p, SSTAT1)); + printk(INFO_LEAD "SG_CACHEPTR 0x%x, SSTAT2 0x%x, STCNT 0x%x\n", p->host_no, + CTL_OF_SCB(scb), + (p->features & AHC_ULTRA2) ? aic_inb(p, SG_CACHEPTR) : 0, + aic_inb(p, SSTAT2), + aic_inb(p, STCNT + 2) << 16 | aic_inb(p, STCNT + 1) << 8 | + aic_inb(p, STCNT)); } channel = cmd->channel; @@ -11358,7 +11174,6 @@ #if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95) unsigned long cpu_flags = 0; #endif - Scsi_Cmnd *cmd_next, *cmd_prev; p = (struct aic7xxx_host *) cmd->host->hostdata; scb = (p->scb_data->scb_array[aic7xxx_position(cmd)]); @@ -11367,7 +11182,7 @@ * I added a new config option to the driver: "panic_on_abort" that will * cause the driver to panic and the machine to stop on the first abort * or reset call into the driver. At that point, it prints out a lot of - * usefull information for me which I can then use to try and debug the + * useful information for me which I can then use to try and debug the * problem. Simply enable the boot time prompt in order to activate this * code. */ @@ -11388,13 +11203,11 @@ { aic7xxx_isr(p->irq, p, (void *)NULL); pause_sequencer(p); - aic7xxx_done_cmds_complete(p); } + aic7xxx_done_cmds_complete(p); - if ((scb == NULL) || (cmd->serial_number != cmd->serial_number_at_timeout)) - /* Totally bogus cmd since it points beyond our */ - { /* valid SCB range or doesn't even match it's own*/ - /* timeout serial number. */ + if (scb == NULL) + { if (aic7xxx_verbose & VERBOSE_ABORT_MID) printk(INFO_LEAD "Abort called with bogus Scsi_Cmnd " "pointer.\n", p->host_no, CTL_OF_CMD(cmd)); @@ -11413,28 +11226,6 @@ /* finish successfully, or to indicate that we */ /* don't have this cmd any more and the mid level */ /* code needs to find it. */ - cmd_next = p->completeq.head; - cmd_prev = NULL; - while (cmd_next != NULL) - { - if (cmd_next == cmd) - { - if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS) - printk(INFO_LEAD "Abort called for command " - "on completeq, completing.\n", p->host_no, CTL_OF_CMD(cmd)); - if ( cmd_prev == NULL ) - p->completeq.head = (Scsi_Cmnd *)cmd_next->host_scribble; - else - cmd_prev->host_scribble = cmd_next->host_scribble; - cmd_next->scsi_done(cmd_next); - unpause_sequencer(p, FALSE); - DRIVER_UNLOCK - return(SCSI_ABORT_NOT_RUNNING); /* It's already back as a successful - * completion */ - } - cmd_prev = cmd_next; - cmd_next = (Scsi_Cmnd *)cmd_next->host_scribble; - } if (aic7xxx_verbose & VERBOSE_ABORT_MID) printk(INFO_LEAD "Abort called for already completed" " command.\n", p->host_no, CTL_OF_CMD(cmd)); @@ -11492,8 +11283,20 @@ found = 0; p->flags |= AHC_IN_ABORT; if (aic7xxx_verbose & VERBOSE_ABORT) - printk(INFO_LEAD "Aborting scb %d, flags 0x%x\n", - p->host_no, CTL_OF_SCB(scb), scb->hscb->tag, scb->flags); + { + printk(INFO_LEAD "Aborting scb %d, flags 0x%x, SEQADDR 0x%x, LASTPHASE " + "0x%x\n", + p->host_no, CTL_OF_SCB(scb), scb->hscb->tag, scb->flags, + aic_inb(p, SEQADDR0) | (aic_inb(p, SEQADDR1) << 8), + aic_inb(p, LASTPHASE)); + printk(INFO_LEAD "SG_CACHEPTR 0x%x, SG_COUNT %d, SCSISIGI 0x%x\n", + p->host_no, CTL_OF_SCB(scb), (p->features & AHC_ULTRA2) ? + aic_inb(p, SG_CACHEPTR) : 0, aic_inb(p, SG_COUNT), + aic_inb(p, SCSISIGI)); + printk(INFO_LEAD "SSTAT0 0x%x, SSTAT1 0x%x, SSTAT2 0x%x\n", + p->host_no, CTL_OF_SCB(scb), aic_inb(p, SSTAT0), + aic_inb(p, SSTAT1), aic_inb(p, SSTAT2)); + } /* * First, let's check to see if the currently running command is our target @@ -11521,6 +11324,16 @@ if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS) printk(INFO_LEAD "SCB is currently active. " "Waiting on completion.\n", p->host_no, CTL_OF_SCB(scb)); + printk(INFO_LEAD "SCSISIGI 0x%x, SEQADDR 0x%x, SSTAT0 0x%x, SSTAT1 " + "0x%x\n", p->host_no, CTL_OF_SCB(scb), + aic_inb(p, SCSISIGI), + aic_inb(p, SEQADDR0) | (aic_inb(p, SEQADDR1) << 8), + aic_inb(p, SSTAT0), aic_inb(p, SSTAT1)); + printk(INFO_LEAD "SG_CACHEPTR 0x%x, SSTAT2 0x%x, STCNT 0x%x\n", + p->host_no, CTL_OF_SCB(scb), + (p->features & AHC_ULTRA2) ? aic_inb(p, SG_CACHEPTR) : 0, + aic_inb(p, SSTAT2), aic_inb(p, STCNT + 2) << 16 | + aic_inb(p, STCNT + 1) << 8 | aic_inb(p, STCNT)); unpause_sequencer(p, FALSE); p->flags &= ~AHC_IN_ABORT; scb->flags |= SCB_RECOVERY_SCB; /* Note the fact that we've been */ @@ -11536,35 +11349,7 @@ if ((found == 0) && (scb->flags & SCB_WAITINGQ)) { int tindex = TARGET_INDEX(cmd); - unsigned short mask; - - mask = (1 << tindex); - if (p->dtr_pending & mask) - { - if (p->dev_dtr_cmnd[tindex]->next != cmd) - found = 1; - else - found = 0; - } - else - { - found = 1; - } - if (found == 0) - { - /* - * OK..this means the command we are currently getting an abort - * for has an outstanding negotiation command in front of it. - * We don't really have a way to tie back into the negotiation - * commands, so we just send this back as pending, then it - * will get reset in 2 seconds. - */ - unpause_sequencer(p, TRUE); - scb->flags |= SCB_ABORT; - DRIVER_UNLOCK - return(SCSI_ABORT_PENDING); - } if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS) printk(INFO_LEAD "SCB found on waiting list and " "aborted.\n", p->host_no, CTL_OF_SCB(scb)); @@ -11721,10 +11506,8 @@ #define DEVICE_RESET 0x01 #define BUS_RESET 0x02 #define HOST_RESET 0x04 -#define FAIL 0x08 -#define RESET_DELAY 0x10 +#define RESET_DELAY 0x08 int action; - Scsi_Cmnd *cmd_prev, *cmd_next; if ( cmd == NULL ) @@ -11742,7 +11525,7 @@ * I added a new config option to the driver: "panic_on_abort" that will * cause the driver to panic and the machine to stop on the first abort * or reset call into the driver. At that point, it prints out a lot of - * usefull information for me which I can then use to try and debug the + * useful information for me which I can then use to try and debug the * problem. Simply enable the boot time prompt in order to activate this * code. */ @@ -11752,86 +11535,32 @@ DRIVER_LOCK pause_sequencer(p); - while ( (aic_inb(p, INTSTAT) & INT_PEND) && !(p->flags & AHC_IN_ISR)) - { - aic7xxx_isr(p->irq, p, (void *)NULL ); - pause_sequencer(p); - aic7xxx_done_cmds_complete(p); - } - if (scb == NULL) + if(flags & SCSI_RESET_SYNCHRONOUS) { if (aic7xxx_verbose & VERBOSE_RESET_MID) - printk(INFO_LEAD "Reset called with bogus Scsi_Cmnd" - "->SCB mapping, improvising.\n", p->host_no, CTL_OF_CMD(cmd)); - if ( flags & SCSI_RESET_SUGGEST_HOST_RESET ) - { - action = HOST_RESET; - } - else - { - action = BUS_RESET; - } + printk(INFO_LEAD "Reset called for a SYNCHRONOUS reset, flags 0x%x, " + "cmd->result 0x%x.\n", p->host_no, CTL_OF_CMD(cmd), flags, + cmd->result); + scb = NULL; + action = HOST_RESET; } - else if (scb->cmd != cmd) + else if ((scb == NULL) || (scb->cmd != cmd)) { if (aic7xxx_verbose & VERBOSE_RESET_MID) - printk(INFO_LEAD "Reset called with recycled SCB " - "for cmd.\n", p->host_no, CTL_OF_CMD(cmd)); - cmd_prev = NULL; - cmd_next = p->completeq.head; - while ( cmd_next != NULL ) - { - if (cmd_next == cmd) - { - if (aic7xxx_verbose & VERBOSE_RESET_RETURN) - printk(INFO_LEAD "Reset, found cmd on completeq" - ", completing.\n", p->host_no, CTL_OF_CMD(cmd)); - unpause_sequencer(p, FALSE); - DRIVER_UNLOCK - return(SCSI_RESET_NOT_RUNNING); - } - cmd_prev = cmd_next; - cmd_next = (Scsi_Cmnd *)cmd_next->host_scribble; - } - if ( !(flags & SCSI_RESET_SYNCHRONOUS) ) - { - if (aic7xxx_verbose & VERBOSE_RESET_RETURN) - printk(INFO_LEAD "Reset, cmd not found," - " failing.\n", p->host_no, CTL_OF_CMD(cmd)); - unpause_sequencer(p, FALSE); - DRIVER_UNLOCK - return(SCSI_RESET_NOT_RUNNING); - } - else - { - if (aic7xxx_verbose & VERBOSE_RESET_MID) - printk(INFO_LEAD "Reset called, no scb, " - "flags 0x%x\n", p->host_no, CTL_OF_CMD(cmd), flags); - scb = NULL; - action = HOST_RESET; - } + printk(INFO_LEAD "Reset called with bogus Scsi_Cmnd" + "->SCB mapping, failing.\n", p->host_no, CTL_OF_CMD(cmd)); + aic7xxx_done_cmds_complete(p); + aic7xxx_run_waiting_queues(p); + unpause_sequencer(p, FALSE); + DRIVER_UNLOCK + return(SCSI_RESET_NOT_RUNNING); } else { if (aic7xxx_verbose & VERBOSE_RESET_MID) printk(INFO_LEAD "Reset called, scb %d, flags " "0x%x\n", p->host_no, CTL_OF_SCB(scb), scb->hscb->tag, scb->flags); - if ( aic7xxx_scb_on_qoutfifo(p, scb) ) - { - if(aic7xxx_verbose & VERBOSE_RESET_RETURN) - printk(INFO_LEAD "SCB on qoutfifo, completing.\n", p->host_no, - CTL_OF_SCB(scb)); - if ((aic_inb(p,INTSTAT) & CMDCMPLT) == 0) - printk(INFO_LEAD "missed CMDCMPLT interrupt!\n", p->host_no, - CTL_OF_SCB(scb)); - aic7xxx_handle_command_completion_intr(p); - aic7xxx_done_cmds_complete(p); - aic7xxx_run_waiting_queues(p); - unpause_sequencer(p, FALSE); - DRIVER_UNLOCK - return(SCSI_RESET_SUCCESS); - } if ( flags & SCSI_RESET_SUGGEST_HOST_RESET ) { action = HOST_RESET; @@ -11845,6 +11574,26 @@ action = DEVICE_RESET; } } + + while((aic_inb(p, INTSTAT) & INT_PEND) && !(p->flags & AHC_IN_ISR)) + { + aic7xxx_isr(p->irq, p, (void *)NULL ); + pause_sequencer(p); + } + aic7xxx_done_cmds_complete(p); + + if(scb && (scb->cmd == NULL)) + { + /* + * We just completed the command when we ran the isr stuff, so we no + * longer have it. + */ + aic7xxx_run_waiting_queues(p); + unpause_sequencer(p, FALSE); + DRIVER_UNLOCK + return(SCSI_RESET_SUCCESS); + } + if ( (action & DEVICE_RESET) && (p->dev_flags[tindex] & BUS_DEVICE_RESET_PENDING) ) { @@ -11904,14 +11653,13 @@ switch (action) { case RESET_DELAY: + aic7xxx_run_waiting_queues(p); unpause_sequencer(p, FALSE); DRIVER_UNLOCK - return(SCSI_RESET_PENDING); - break; - case FAIL: - unpause_sequencer(p, FALSE); - DRIVER_UNLOCK - return(SCSI_RESET_ERROR); + if(scb == NULL) + return(SCSI_RESET_PUNT); + else + return(SCSI_RESET_PENDING); break; case DEVICE_RESET: p->flags |= AHC_IN_RESET; @@ -11929,7 +11677,7 @@ case HOST_RESET: default: p->flags |= AHC_IN_RESET | AHC_RESET_DELAY; - p->dev_expires[p->scsi_id] = jiffies + (3 * HZ); + p->dev_expires[p->scsi_id] = jiffies + (1 * HZ); p->dev_timer_active |= (0x01 << p->scsi_id); if ( !(p->dev_timer_active & (0x01 << MAX_TARGETS)) || time_after_eq(p->dev_timer.expires, p->dev_expires[p->scsi_id]) ) @@ -11956,21 +11704,14 @@ p->msg_index = 0; p->msg_len = 0; } - aic7xxx_run_done_queue(p, TRUE); - /* - * If this a SCSI_RESET_SYNCHRONOUS then the command we were given is - * in need of being re-started, so send it on through to aic7xxx_queue - * and let it set until the delay is over. This keeps it from dying - * entirely and avoids getting a bogus dead command back through the - * mid-level code due to too many retries. - */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,132) - if ( flags & SCSI_RESET_SYNCHRONOUS ) +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95) + if(flags & SCSI_RESET_SYNCHRONOUS) { - cmd->result = DID_BUS_BUSY << 16; + cmd->result = DID_RESET << 16; cmd->done(cmd); } #endif + aic7xxx_run_done_queue(p, TRUE); p->flags &= ~AHC_IN_RESET; /* * We can't rely on run_waiting_queues to unpause the sequencer for @@ -11981,7 +11722,10 @@ aic7xxx_run_waiting_queues(p); unpause_sequencer(p, FALSE); DRIVER_UNLOCK - return(result); + if(scb == NULL) + return(SCSI_RESET_SUCCESS|SCSI_RESET_HOST_RESET); + else + return(result); break; } } diff -u --recursive --new-file v2.4.6/linux/drivers/scsi/atp870u.c linux/drivers/scsi/atp870u.c --- v2.4.6/linux/drivers/scsi/atp870u.c Fri Apr 27 13:59:18 2001 +++ linux/drivers/scsi/atp870u.c Sun Jul 15 16:22:23 2001 @@ -10,6 +10,8 @@ * support atp876 chip * enable 32 bit fifo transfer * support cdrom & remove device run ultra speed + * fix disconnect bug 2000/12/21 + * support atp880 chip lvd u160 2001/05/15 */ #include <linux/module.h> @@ -63,6 +65,7 @@ unsigned short wide_idu; unsigned short active_idu; unsigned short ultra_map; + unsigned short deviceid; unsigned char ata_cdbu[16]; Scsi_Cmnd *querequ[qcnt]; struct atp_id @@ -137,14 +140,6 @@ tmport -= 0x08; i = inb(tmport); - if ((j & 0x40) == 0) - { - if ((dev->last_cmd & 0x40) == 0) - { - dev->last_cmd = 0xff; - } - } - else dev->last_cmd |= 0x40; tmport -= 0x02; target_id = inb(tmport); @@ -160,8 +155,21 @@ target_id &= 0x07; } + if ((j & 0x40) != 0) + { + if (dev->last_cmd == 0xff) + { + dev->last_cmd = target_id; + } + dev->last_cmd |= 0x40; + } + if (i == 0x85) { + if ((dev->last_cmd & 0xf0) != 0x40) + { + dev->last_cmd = 0xff; + } /* * Flip wide */ @@ -188,8 +196,20 @@ dev->in_int = 0; return; } + + if (i == 0x40) + { + dev->last_cmd |= 0x40; + dev->in_int = 0; + return; + } + if (i == 0x21) { + if ((dev->last_cmd & 0xf0) != 0x40) + { + dev->last_cmd = 0xff; + } tmport -= 0x05; adrcntu = 0; ((unsigned char *) &adrcntu)[2] = inb(tmport++); @@ -215,6 +235,10 @@ tmport += 0x0d; lun = inb(tmport) & 0x07; } else { + if ((dev->last_cmd & 0xf0) != 0x40) + { + dev->last_cmd = 0xff; + } if (j == 0x41) { tmport += 0x02; @@ -245,6 +269,10 @@ return; } } + if (dev->last_cmd != 0xff) + { + dev->last_cmd |= 0x40; + } tmport = workportu + 0x10; outb(0x45, tmport); tmport += 0x06; @@ -279,15 +307,31 @@ outb(0x80, tmport); /* enable 32 bit fifo transfer */ - tmport = workportu + 0x3a; - if ((dev->ata_cdbu[0] == 0x08) || (dev->ata_cdbu[0] == 0x28) || - (dev->ata_cdbu[0] == 0x0a) || (dev->ata_cdbu[0] == 0x2a)) + if (dev->deviceid != 0x8081) { - outb((unsigned char)((inb(tmport) & 0xf3) | 0x08),tmport); + tmport = workportu + 0x3a; + if ((dev->ata_cdbu[0] == 0x08) || (dev->ata_cdbu[0] == 0x28) || + (dev->ata_cdbu[0] == 0x0a) || (dev->ata_cdbu[0] == 0x2a)) + { + outb((unsigned char)((inb(tmport) & 0xf3) | 0x08),tmport); + } + else + { + outb((unsigned char)(inb(tmport) & 0xf3),tmport); + } } else { - outb((unsigned char)(inb(tmport) & 0xf3),tmport); + tmport = workportu - 0x05; + if ((dev->ata_cdbu[0] == 0x08) || (dev->ata_cdbu[0] == 0x28) || + (dev->ata_cdbu[0] == 0x0a) || (dev->ata_cdbu[0] == 0x2a)) + { + outb((unsigned char)((inb(tmport) & 0x3f) | 0xc0),tmport); + } + else + { + outb((unsigned char)(inb(tmport) & 0x3f),tmport); + } } tmport = workportu + 0x1b; @@ -303,7 +347,7 @@ outb(j, tmport); while ((inb(tmport) & 0x01) != j) { - outb(j,tmport); + outb(j,tmport); } if (dev->id[target_id].last_lenu == 0) { @@ -365,12 +409,20 @@ workrequ = dev->id[target_id].curr_req; if (i == 0x42) { + if ((dev->last_cmd & 0xf0) != 0x40) + { + dev->last_cmd = 0xff; + } errstus = 0x02; workrequ->result = errstus; goto go_42; } if (i == 0x16) { + if ((dev->last_cmd & 0xf0) != 0x40) + { + dev->last_cmd = 0xff; + } errstus = 0; tmport -= 0x08; errstus = inb(tmport); @@ -381,13 +433,13 @@ */ spin_lock_irqsave(&io_request_lock, flags); (*workrequ->scsi_done) (workrequ); - spin_unlock_irqrestore(&io_request_lock, flags); /* * Clear it off the queue */ dev->id[target_id].curr_req = 0; dev->working--; + spin_unlock_irqrestore(&io_request_lock, flags); /* * Take it back wide */ @@ -396,7 +448,7 @@ outb(0x01,tmport); while ((inb(tmport) & 0x01) != 0x01) { - outb(0x01,tmport); + outb(0x01,tmport); } } /* @@ -405,11 +457,15 @@ if (((dev->last_cmd != 0xff) || (dev->quhdu != dev->quendu)) && (dev->in_snd == 0)) { - send_s870(h); + send_s870(h); } dev->in_int = 0; return; } + if ((dev->last_cmd & 0xf0) != 0x40) + { + dev->last_cmd = 0xff; + } if (i == 0x4f) { i = 0x89; } @@ -474,7 +530,7 @@ int atp870u_queuecommand(Scsi_Cmnd * req_p, void (*done) (Scsi_Cmnd *)) { - unsigned char i, h; + unsigned char h; unsigned long flags; unsigned short int m; unsigned int tmport; @@ -516,6 +572,8 @@ /* * Count new command */ + save_flags(flags); + cli(); dev->quendu++; if (dev->quendu >= qcnt) { dev->quendu = 0; @@ -523,18 +581,17 @@ /* * Check queue state */ -wait_que_empty: if (dev->quhdu == dev->quendu) { - goto wait_que_empty; + if (dev->quendu == 0) { + dev->quendu = qcnt; + } + dev->quendu--; + req_p->result = 0x00020000; + done(req_p); + restore_flags(flags); + return 0; } - save_flags(flags); - cli(); dev->querequ[dev->quendu] = req_p; - if (dev->quendu == 0) { - i = qcnt - 1; - } else { - i = dev->quendu - 1; - } tmport = dev->ioport + 0x1c; restore_flags(flags); if ((inb(tmport) == 0) && (dev->in_int == 0) && (dev->in_snd == 0)) { @@ -582,11 +639,17 @@ dev->last_cmd = 0xff; if (dev->quhdu == dev->quendu) { - dev->in_snd = 0; - restore_flags(flags); - return ; + dev->in_snd = 0; + restore_flags(flags); + return ; } } + if ((dev->last_cmd != 0xff) && (dev->working != 0)) + { + dev->in_snd = 0; + restore_flags(flags); + return ; + } dev->working++; j = dev->quhdu; dev->quhdu++; @@ -629,15 +692,6 @@ if (dev->ata_cdbu[0] == 0x00) { workrequ->request_bufflen = 0; } - /* - * Why limit this ???? - */ - if (dev->ata_cdbu[0] == INQUIRY) { - if (workrequ->request_bufflen > 0x24) { - workrequ->request_bufflen = 0x24; - dev->ata_cdbu[4] = 0x24; - } - } tmport = workportu + 0x1b; j = 0; @@ -654,7 +708,7 @@ outb(j, tmport); while ((inb(tmport) & 0x01) != j) { - outb(j,tmport); + outb(j,tmport); } /* @@ -780,15 +834,31 @@ outb(0x00, tmpcip); tmpcip = tmpcip - 2; - tmport = workportu + 0x3a; - if ((dev->ata_cdbu[0] == 0x08) || (dev->ata_cdbu[0] == 0x28) || - (dev->ata_cdbu[0] == 0x0a) || (dev->ata_cdbu[0] == 0x2a)) + if (dev->deviceid != 0x8081) { - outb((unsigned char)((inb(tmport) & 0xf3) | 0x08),tmport); + tmport = workportu + 0x3a; + if ((dev->ata_cdbu[0] == 0x08) || (dev->ata_cdbu[0] == 0x28) || + (dev->ata_cdbu[0] == 0x0a) || (dev->ata_cdbu[0] == 0x2a)) + { + outb((unsigned char)((inb(tmport) & 0xf3) | 0x08),tmport); + } + else + { + outb((unsigned char)(inb(tmport) & 0xf3),tmport); + } } else { - outb((unsigned char)(inb(tmport) & 0xf3),tmport); + tmport = workportu - 0x05; + if ((dev->ata_cdbu[0] == 0x08) || (dev->ata_cdbu[0] == 0x28) || + (dev->ata_cdbu[0] == 0x0a) || (dev->ata_cdbu[0] == 0x2a)) + { + outb((unsigned char)((inb(tmport) & 0x3f) | 0xc0),tmport); + } + else + { + outb((unsigned char)(inb(tmport) & 0x3f),tmport); + } } tmport = workportu + 0x1c; @@ -1152,11 +1222,11 @@ } tmport = wkport + 0x1b; if (dev->chip_veru == 4) { - outb(0x01, tmport); + outb(0x01, tmport); } else { - outb(0x00, tmport); + outb(0x00, tmport); } tmport = wkport + 1; outb(0x08, tmport++); @@ -1615,182 +1685,909 @@ outb((unsigned char) (inb(tmport) & 0xef), tmport); } -/* return non-zero on detection */ -int atp870u_detect(Scsi_Host_Template * tpnt) +void is880(unsigned long host, unsigned int wkport) { - unsigned char irq, h, k; - unsigned long flags; - unsigned int base_io, error, tmport; - unsigned short index = 0; - struct pci_dev *pdev[3]; - unsigned char chip_ver[3], host_id; - struct Scsi_Host *shpnt = NULL; - int tmpcnt = 0; - int count = 0; - - static unsigned short devid[8] = { - 0x8002, 0x8010, 0x8020, 0x8030, 0x8040, 0x8050, 0x8060, 0 - }; + unsigned int tmport; + unsigned char i, j, k, rmb, n, lvdmode; + unsigned short int m; + static unsigned char mbuf[512]; + static unsigned char satn[9] = {0, 0, 0, 0, 0, 0, 0, 6, 6}; + static unsigned char inqd[9] = {0x12, 0, 0, 0, 0x24, 0, 0, 0x24, 6}; + static unsigned char synn[6] = {0x80, 1, 3, 1, 0x19, 0x0e}; + static unsigned char synu[6] = {0x80, 1, 3, 1, 0x0a, 0x0e}; + static unsigned char synw[6] = {0x80, 1, 3, 1, 0x0a, 0x0e}; + static unsigned char wide[6] = {0x80, 1, 2, 3, 1, 0}; + static unsigned char u3[9] = { 0x80,1,6,4,0x09,00,0x0e,0x01,0x02 }; + struct atp_unit *dev = &atp_unit[host]; - printk(KERN_INFO "aec671x_detect: \n"); - if (!pci_present()) { - printk(KERN_INFO" NO PCI SUPPORT.\n"); - return count; - } - tpnt->proc_name = "atp870u"; + sync_idu = 0; + lvdmode=inb(wkport + 0x3f) & 0x40; - for (h = 0; h < 2; h++) { - struct atp_unit *dev = &atp_unit[h]; - for(k=0;k<16;k++) - { - dev->id[k].prd_tableu = kmalloc(1024, GFP_KERNEL); - dev->id[k].devspu=0x20; - dev->id[k].devtypeu = 0; - dev->id[k].curr_req = NULL; - } - dev->active_idu = 0; - dev->wide_idu = 0; - dev->host_idu = 0x07; - dev->quhdu = 0; - dev->quendu = 0; - pdev[h]=NULL; - pdev[2]=NULL; - dev->chip_veru = 0; - dev->last_cmd = 0xff; - dev->in_snd = 0; - dev->in_int = 0; - for (k = 0; k < qcnt; k++) { - dev->querequ[k] = 0; - } - for (k = 0; k < 16; k++) { - dev->id[k].curr_req = 0; - } - } - h = 0; - while (devid[h] != 0) { - pdev[2] = pci_find_device(0x1191, devid[h], pdev[2]); - if (pdev[2] == NULL || pci_enable_device(pdev[2])) { - h++; - index = 0; + for (i = 0; i < 16; i++) { + m = 1; + m = m << i; + if ((m & dev->active_idu) != 0) { continue; } - chip_ver[2] = 0; - - if (devid[h] == 0x8002) { - error = pci_read_config_byte(pdev[2], 0x08, &chip_ver[2]); - if (chip_ver[2] < 2) { - goto nxt_devfn; - } - } - if (devid[h] == 0x8010 || devid[h] == 0x8050) { - chip_ver[2] = 0x04; - } - pdev[tmpcnt] = pdev[2]; - chip_ver[tmpcnt] = chip_ver[2]; - tmpcnt++; - nxt_devfn: - index++; - if (index > 3) { - index = 0; - h++; + if (i == dev->host_idu) { + printk(KERN_INFO " ID: %2d Host Adapter\n", dev->host_idu); + continue; } - if(tmpcnt>1) - break; - } - for (h = 0; h < 2; h++) { - struct atp_unit *dev=&atp_unit[h]; - if (pdev[h]==NULL) { - return count; + tmport = wkport + 0x5b; + outb(0x01, tmport); + tmport = wkport + 0x41; + outb(0x08, tmport++); + outb(0x7f, tmport++); + outb(satn[0], tmport++); + outb(satn[1], tmport++); + outb(satn[2], tmport++); + outb(satn[3], tmport++); + outb(satn[4], tmport++); + outb(satn[5], tmport++); + tmport += 0x06; + outb(0, tmport); + tmport += 0x02; + outb(dev->id[i].devspu, tmport++); + outb(0, tmport++); + outb(satn[6], tmport++); + outb(satn[7], tmport++); + j = i; + if ((j & 0x08) != 0) { + j = (j & 0x07) | 0x40; } + outb(j, tmport); + tmport += 0x03; + outb(satn[8], tmport); + tmport += 0x07; - /* Found an atp870u/w. */ - base_io = pci_resource_start(pdev[h], 0); - irq = pdev[h]->irq; - error = pci_read_config_byte(pdev[h],0x49,&host_id); + while ((inb(tmport) & 0x80) == 0x00); + tmport -= 0x08; + if ((inb(tmport) != 0x11) && (inb(tmport) != 0x8e)) { + continue; + } + while (inb(tmport) != 0x8e); + dev->active_idu |= m; - base_io &= 0xfffffff8; + tmport = wkport + 0x50; + outb(0x30, tmport); + tmport = wkport + 0x54; + outb(0x00, tmport); - if (check_region(base_io,0x40) != 0) - { - return 0; +phase_cmd: + tmport = wkport + 0x58; + outb(0x08, tmport); + tmport += 0x07; + while ((inb(tmport) & 0x80) == 0x00); + tmport -= 0x08; + j = inb(tmport); + if (j != 0x16) { + tmport = wkport + 0x50; + outb(0x41, tmport); + goto phase_cmd; + } +sel_ok: + tmport = wkport + 0x43; + outb(inqd[0], tmport++); + outb(inqd[1], tmport++); + outb(inqd[2], tmport++); + outb(inqd[3], tmport++); + outb(inqd[4], tmport++); + outb(inqd[5], tmport); + tmport += 0x07; + outb(0, tmport); + tmport += 0x02; + outb(dev->id[i].devspu, tmport++); + outb(0, tmport++); + outb(inqd[6], tmport++); + outb(inqd[7], tmport++); + tmport += 0x03; + outb(inqd[8], tmport); + tmport += 0x07; + while ((inb(tmport) & 0x80) == 0x00); + tmport -= 0x08; + if ((inb(tmport) != 0x11) && (inb(tmport) != 0x8e)) { + continue; } - printk(KERN_INFO " ACARD AEC-671X PCI Ultra/W SCSI-3 Host Adapter: %d IO:%x, IRQ:%d.\n" - ,h, base_io, irq); - dev->ioport = base_io; - dev->pciport = base_io + 0x20; - irqnumu[h] = irq; - host_id &= 0x07; - dev->host_idu = host_id; - dev->chip_veru = chip_ver[h]; - - tmport = base_io + 0x22; - dev->scam_on = inb(tmport); - tmport += 0x0b; - dev->global_map = inb(tmport++); - dev->ultra_map = inw(tmport); - if (dev->ultra_map == 0) { - dev->scam_on = 0x00; - dev->global_map = 0x20; - dev->ultra_map = 0xffff; + while (inb(tmport) != 0x8e); + tmport = wkport + 0x5b; + outb(0x00, tmport); + tmport = wkport + 0x58; + outb(0x08, tmport); + tmport += 0x07; + j = 0; +rd_inq_data: + k = inb(tmport); + if ((k & 0x01) != 0) { + tmport -= 0x06; + mbuf[j++] = inb(tmport); + tmport += 0x06; + goto rd_inq_data; } - shpnt = scsi_register(tpnt, 4); - if(shpnt==NULL) - return count; - - save_flags(flags); - cli(); - if (request_irq(irq, atp870u_intr_handle, SA_SHIRQ, "atp870u", dev)) { - printk(KERN_ERR "Unable to allocate IRQ for Acard controller.\n"); - goto unregister; + if ((k & 0x80) == 0) { + goto rd_inq_data; } - - if (chip_ver[h] > 0x07) /* check if atp876 chip */ - { /* then enable terminator */ - tmport = base_io + 0x3e; - outb(0x30, tmport); + tmport -= 0x08; + j = inb(tmport); + if (j == 0x16) { + goto inq_ok; } - - tmport = base_io + 0x3a; - k = (inb(tmport) & 0xf3) | 0x10; - outb(k, tmport); - outb((k & 0xdf), tmport); - mydlyu(0x8000); - outb(k, tmport); - mydlyu(0x8000); - tmport = base_io; - outb((host_id | 0x08), tmport); - tmport += 0x18; - outb(0, tmport); + tmport = wkport + 0x50; + outb(0x46, tmport); + tmport += 0x02; + outb(0, tmport++); + outb(0, tmport++); + outb(0, tmport++); + tmport += 0x03; + outb(0x08, tmport); tmport += 0x07; - while ((inb(tmport) & 0x80) == 0); + while ((inb(tmport) & 0x80) == 0x00); tmport -= 0x08; - inb(tmport); - tmport = base_io + 1; - outb(8, tmport++); - outb(0x7f, tmport); - tmport = base_io + 0x11; - outb(0x20, tmport); - - tscam(h); - is870(h, base_io); - tmport = base_io + 0x3a; - outb((inb(tmport) & 0xef), tmport); - tmport++; - outb((inb(tmport) | 0x20),tmport); - - atp_host[h] = shpnt; - if (dev->chip_veru == 4) { - shpnt->max_id = 16; + if (inb(tmport) != 0x16) { + goto sel_ok; } - shpnt->this_id = host_id; - shpnt->unique_id = base_io; - shpnt->io_port = base_io; - shpnt->n_io_port = 0x40; /* Number of bytes of I/O space used */ - shpnt->irq = irq; - scsi_set_pci_device(shpnt, pdev[h]); - restore_flags(flags); - request_region(base_io, 0x40, "atp870u"); /* Register the IO ports that we use */ - count++; +inq_ok: + mbuf[36] = 0; + printk(KERN_INFO " ID: %2d %s\n", i, &mbuf[8]); + dev->id[i].devtypeu = mbuf[0]; + rmb = mbuf[1]; + n = mbuf[7]; + if ((mbuf[7] & 0x60) == 0) { + goto not_wide; + } + if ((dev->global_map & 0x20) == 0) { + goto not_wide; + } + if (lvdmode == 0) + { + goto chg_wide; + } + if ((mbuf[2] & 0x07) < 0x03) // force u2 + { + goto chg_wide; + } + tmport = wkport + 0x5b; + outb(0x01, tmport); + tmport = wkport + 0x43; + outb(satn[0], tmport++); + outb(satn[1], tmport++); + outb(satn[2], tmport++); + outb(satn[3], tmport++); + outb(satn[4], tmport++); + outb(satn[5], tmport++); + tmport += 0x06; + outb(0, tmport); + tmport += 0x02; + outb(dev->id[i].devspu, tmport++); + outb(0, tmport++); + outb(satn[6], tmport++); + outb(satn[7], tmport++); + tmport += 0x03; + outb(satn[8], tmport); + tmport += 0x07; + + while ((inb(tmport) & 0x80) == 0x00); + tmport -= 0x08; + if ((inb(tmport) != 0x11) && (inb(tmport) != 0x8e)) { + continue; + } + while (inb(tmport) != 0x8e); +try_u3: + j = 0; + tmport = wkport + 0x54; + outb(0x09, tmport); + tmport += 0x04; + outb(0x20, tmport); + tmport += 0x07; + + while ((inb(tmport) & 0x80) == 0) { + if ((inb(tmport) & 0x01) != 0) { + tmport -= 0x06; + outb(u3[j++], tmport); + tmport += 0x06; + } + } + tmport -= 0x08; + while ((inb(tmport) & 0x80) == 0x00); + j = inb(tmport) & 0x0f; + if (j == 0x0f) { + goto u3p_in; + } + if (j == 0x0a) { + goto u3p_cmd; + } + if (j == 0x0e) { + goto try_u3; + } + continue; +u3p_out: + tmport = wkport + 0x58; + outb(0x20, tmport); + tmport += 0x07; + while ((inb(tmport) & 0x80) == 0) { + if ((inb(tmport) & 0x01) != 0) { + tmport -= 0x06; + outb(0, tmport); + tmport += 0x06; + } + } + tmport -= 0x08; + j = inb(tmport) & 0x0f; + if (j == 0x0f) { + goto u3p_in; + } + if (j == 0x0a) { + goto u3p_cmd; + } + if (j == 0x0e) { + goto u3p_out; + } + continue; +u3p_in: + tmport = wkport + 0x54; + outb(0x09, tmport); + tmport += 0x04; + outb(0x20, tmport); + tmport += 0x07; + k = 0; +u3p_in1: + j = inb(tmport); + if ((j & 0x01) != 0) { + tmport -= 0x06; + mbuf[k++] = inb(tmport); + tmport += 0x06; + goto u3p_in1; + } + if ((j & 0x80) == 0x00) { + goto u3p_in1; + } + tmport -= 0x08; + j = inb(tmport) & 0x0f; + if (j == 0x0f) { + goto u3p_in; + } + if (j == 0x0a) { + goto u3p_cmd; + } + if (j == 0x0e) { + goto u3p_out; + } + continue; +u3p_cmd: + tmport = wkport + 0x50; + outb(0x30, tmport); + tmport = wkport + 0x54; + outb(0x00, tmport); + tmport += 0x04; + outb(0x08, tmport); + tmport += 0x07; + while ((inb(tmport) & 0x80) == 0x00); + tmport -= 0x08; + j = inb(tmport); + if (j != 0x16) { + if (j == 0x4e) { + goto u3p_out; + } + continue; + } + if (mbuf[0] != 0x01) { + goto chg_wide; + } + if (mbuf[1] != 0x06) { + goto chg_wide; + } + if (mbuf[2] != 0x04) { + goto chg_wide; + } + if (mbuf[3] == 0x09) { + m = 1; + m = m << i; + dev->wide_idu |= m; + dev->id[i].devspu = 0xce; + continue; + } +chg_wide: + tmport = wkport + 0x5b; + outb(0x01, tmport); + tmport = wkport + 0x43; + outb(satn[0], tmport++); + outb(satn[1], tmport++); + outb(satn[2], tmport++); + outb(satn[3], tmport++); + outb(satn[4], tmport++); + outb(satn[5], tmport++); + tmport += 0x06; + outb(0, tmport); + tmport += 0x02; + outb(dev->id[i].devspu, tmport++); + outb(0, tmport++); + outb(satn[6], tmport++); + outb(satn[7], tmport++); + tmport += 0x03; + outb(satn[8], tmport); + tmport += 0x07; + + while ((inb(tmport) & 0x80) == 0x00); + tmport -= 0x08; + if ((inb(tmport) != 0x11) && (inb(tmport) != 0x8e)) { + continue; + } + while (inb(tmport) != 0x8e); +try_wide: + j = 0; + tmport = wkport + 0x54; + outb(0x05, tmport); + tmport += 0x04; + outb(0x20, tmport); + tmport += 0x07; + + while ((inb(tmport) & 0x80) == 0) { + if ((inb(tmport) & 0x01) != 0) { + tmport -= 0x06; + outb(wide[j++], tmport); + tmport += 0x06; + } + } + tmport -= 0x08; + while ((inb(tmport) & 0x80) == 0x00); + j = inb(tmport) & 0x0f; + if (j == 0x0f) { + goto widep_in; + } + if (j == 0x0a) { + goto widep_cmd; + } + if (j == 0x0e) { + goto try_wide; + } + continue; +widep_out: + tmport = wkport + 0x58; + outb(0x20, tmport); + tmport += 0x07; + while ((inb(tmport) & 0x80) == 0) { + if ((inb(tmport) & 0x01) != 0) { + tmport -= 0x06; + outb(0, tmport); + tmport += 0x06; + } + } + tmport -= 0x08; + j = inb(tmport) & 0x0f; + if (j == 0x0f) { + goto widep_in; + } + if (j == 0x0a) { + goto widep_cmd; + } + if (j == 0x0e) { + goto widep_out; + } + continue; +widep_in: + tmport = wkport + 0x54; + outb(0xff, tmport); + tmport += 0x04; + outb(0x20, tmport); + tmport += 0x07; + k = 0; +widep_in1: + j = inb(tmport); + if ((j & 0x01) != 0) { + tmport -= 0x06; + mbuf[k++] = inb(tmport); + tmport += 0x06; + goto widep_in1; + } + if ((j & 0x80) == 0x00) { + goto widep_in1; + } + tmport -= 0x08; + j = inb(tmport) & 0x0f; + if (j == 0x0f) { + goto widep_in; + } + if (j == 0x0a) { + goto widep_cmd; + } + if (j == 0x0e) { + goto widep_out; + } + continue; +widep_cmd: + tmport = wkport + 0x50; + outb(0x30, tmport); + tmport = wkport + 0x54; + outb(0x00, tmport); + tmport += 0x04; + outb(0x08, tmport); + tmport += 0x07; + while ((inb(tmport) & 0x80) == 0x00); + tmport -= 0x08; + j = inb(tmport); + if (j != 0x16) { + if (j == 0x4e) { + goto widep_out; + } + continue; + } + if (mbuf[0] != 0x01) { + goto not_wide; + } + if (mbuf[1] != 0x02) { + goto not_wide; + } + if (mbuf[2] != 0x03) { + goto not_wide; + } + if (mbuf[3] != 0x01) { + goto not_wide; + } + m = 1; + m = m << i; + dev->wide_idu |= m; +not_wide: + if ((dev->id[i].devtypeu == 0x00) || (dev->id[i].devtypeu == 0x07) || + ((dev->id[i].devtypeu == 0x05) && ((n & 0x10) != 0))) + { + goto set_sync; + } + continue; +set_sync: + tmport = wkport + 0x5b; + j = 0; + if ((m & dev->wide_idu) != 0) { + j |= 0x01; + } + outb(j, tmport); + tmport = wkport + 0x43; + outb(satn[0], tmport++); + outb(satn[1], tmport++); + outb(satn[2], tmport++); + outb(satn[3], tmport++); + outb(satn[4], tmport++); + outb(satn[5], tmport++); + tmport += 0x06; + outb(0, tmport); + tmport += 0x02; + outb(dev->id[i].devspu, tmport++); + outb(0, tmport++); + outb(satn[6], tmport++); + outb(satn[7], tmport++); + tmport += 0x03; + outb(satn[8], tmport); + tmport += 0x07; + + while ((inb(tmport) & 0x80) == 0x00); + tmport -= 0x08; + if ((inb(tmport) != 0x11) && (inb(tmport) != 0x8e)) { + continue; + } + while (inb(tmport) != 0x8e); +try_sync: + j = 0; + tmport = wkport + 0x54; + outb(0x06, tmport); + tmport += 0x04; + outb(0x20, tmport); + tmport += 0x07; + + while ((inb(tmport) & 0x80) == 0) { + if ((inb(tmport) & 0x01) != 0) { + tmport -= 0x06; + if ((m & dev->wide_idu) != 0) { + outb(synw[j++], tmport); + } else { + if ((m & dev->ultra_map) != 0) { + outb(synu[j++], tmport); + } else { + outb(synn[j++], tmport); + } + } + tmport += 0x06; + } + } + tmport -= 0x08; + while ((inb(tmport) & 0x80) == 0x00); + j = inb(tmport) & 0x0f; + if (j == 0x0f) { + goto phase_ins; + } + if (j == 0x0a) { + goto phase_cmds; + } + if (j == 0x0e) { + goto try_sync; + } + continue; +phase_outs: + tmport = wkport + 0x58; + outb(0x20, tmport); + tmport += 0x07; + while ((inb(tmport) & 0x80) == 0x00) { + if ((inb(tmport) & 0x01) != 0x00) { + tmport -= 0x06; + outb(0x00, tmport); + tmport += 0x06; + } + } + tmport -= 0x08; + j = inb(tmport); + if (j == 0x85) { + goto tar_dcons; + } + j &= 0x0f; + if (j == 0x0f) { + goto phase_ins; + } + if (j == 0x0a) { + goto phase_cmds; + } + if (j == 0x0e) { + goto phase_outs; + } + continue; +phase_ins: + tmport = wkport + 0x54; + outb(0x06, tmport); + tmport += 0x04; + outb(0x20, tmport); + tmport += 0x07; + k = 0; +phase_ins1: + j = inb(tmport); + if ((j & 0x01) != 0x00) { + tmport -= 0x06; + mbuf[k++] = inb(tmport); + tmport += 0x06; + goto phase_ins1; + } + if ((j & 0x80) == 0x00) { + goto phase_ins1; + } + tmport -= 0x08; + while ((inb(tmport) & 0x80) == 0x00); + j = inb(tmport); + if (j == 0x85) { + goto tar_dcons; + } + j &= 0x0f; + if (j == 0x0f) { + goto phase_ins; + } + if (j == 0x0a) { + goto phase_cmds; + } + if (j == 0x0e) { + goto phase_outs; + } + continue; +phase_cmds: + tmport = wkport + 0x50; + outb(0x30, tmport); +tar_dcons: + tmport = wkport + 0x54; + outb(0x00, tmport); + tmport += 0x04; + outb(0x08, tmport); + tmport += 0x07; + while ((inb(tmport) & 0x80) == 0x00); + tmport -= 0x08; + j = inb(tmport); + if (j != 0x16) { + continue; + } + if (mbuf[0] != 0x01) { + continue; + } + if (mbuf[1] != 0x03) { + continue; + } + if (mbuf[4] == 0x00) { + continue; + } + if (mbuf[3] > 0x64) { + continue; + } + if (mbuf[4] > 0x0e) { + mbuf[4] = 0x0e; + } + dev->id[i].devspu = mbuf[4]; + if (mbuf[3] < 0x0c){ + j = 0xb0; + goto set_syn_ok; + } + if ((mbuf[3] < 0x0d) && (rmb == 0)) { + j = 0xa0; + goto set_syn_ok; + } + if (mbuf[3] < 0x1a) { + j = 0x20; + goto set_syn_ok; + } + if (mbuf[3] < 0x33) { + j = 0x40; + goto set_syn_ok; + } + if (mbuf[3] < 0x4c) { + j = 0x50; + goto set_syn_ok; + } + j = 0x60; + set_syn_ok: + dev->id[i].devspu = (dev->id[i].devspu & 0x0f) | j; + } +} + +/* return non-zero on detection */ +int atp870u_detect(Scsi_Host_Template * tpnt) +{ + unsigned char irq, h, k; + unsigned long flags; + unsigned int base_io, error, tmport; + unsigned short index = 0; + struct pci_dev *pdev[3]; + unsigned char chip_ver[3], host_id; + unsigned short dev_id[3]; + struct Scsi_Host *shpnt = NULL; + int tmpcnt = 0; + int count = 0; + + static unsigned short devid[9] = { + 0x8081, 0x8002, 0x8010, 0x8020, 0x8030, 0x8040, 0x8050, 0x8060, 0 + }; + + printk(KERN_INFO "aec671x_detect: \n"); + if (!pci_present()) { + printk(KERN_INFO" NO PCI SUPPORT.\n"); + return count; + } + tpnt->proc_name = "atp870u"; + + for (h = 0; h < 2; h++) { + struct atp_unit *dev = &atp_unit[h]; + for(k=0;k<16;k++) + { + dev->id[k].prd_tableu = kmalloc(1024, GFP_KERNEL); + dev->id[k].devspu=0x20; + dev->id[k].devtypeu = 0; + dev->id[k].curr_req = NULL; + } + dev->active_idu = 0; + dev->wide_idu = 0; + dev->host_idu = 0x07; + dev->quhdu = 0; + dev->quendu = 0; + pdev[h]=NULL; + pdev[2]=NULL; + dev->chip_veru = 0; + dev->last_cmd = 0xff; + dev->in_snd = 0; + dev->in_int = 0; + for (k = 0; k < qcnt; k++) { + dev->querequ[k] = 0; + } + for (k = 0; k < 16; k++) { + dev->id[k].curr_req = 0; + } + } + h = 0; + while (devid[h] != 0) { + pdev[2] = pci_find_device(0x1191, devid[h], pdev[2]); + if (pdev[2] == NULL || pci_enable_device(pdev[2])) { + h++; + index = 0; + continue; + } + chip_ver[2] = 0; + dev_id[2] = devid[h]; + + if (devid[h] == 0x8002) { + error = pci_read_config_byte(pdev[2], 0x08, &chip_ver[2]); + if (chip_ver[2] < 2) { + goto nxt_devfn; + } + } + if (devid[h] == 0x8010 || devid[h] == 0x8081 || devid[h] == 0x8050) + { + chip_ver[2] = 0x04; + } + pdev[tmpcnt] = pdev[2]; + chip_ver[tmpcnt] = chip_ver[2]; + dev_id[tmpcnt] = dev_id[2]; + tmpcnt++; + nxt_devfn: + index++; + if (index > 3) { + index = 0; + h++; + } + if(tmpcnt>1) + break; + } + for (h = 0; h < 2; h++) { + struct atp_unit *dev=&atp_unit[h]; + if (pdev[h]==NULL) { + return count; + } + + /* Found an atp870u/w. */ + base_io = pci_resource_start(pdev[h], 0); + irq = pdev[h]->irq; + + if (dev_id[h] != 0x8081) + { + error = pci_read_config_byte(pdev[h],0x49,&host_id); + + base_io &= 0xfffffff8; + + if (check_region(base_io,0x40) != 0) + { + return 0; + } + printk(KERN_INFO " ACARD AEC-671X PCI Ultra/W SCSI-3 Host Adapter: %d IO:%x, IRQ:%d.\n" + ,h, base_io, irq); + dev->ioport = base_io; + dev->pciport = base_io + 0x20; + dev->deviceid = dev_id[h]; + irqnumu[h] = irq; + host_id &= 0x07; + dev->host_idu = host_id; + dev->chip_veru = chip_ver[h]; + + tmport = base_io + 0x22; + dev->scam_on = inb(tmport); + tmport += 0x0b; + dev->global_map = inb(tmport++); + dev->ultra_map = inw(tmport); + if (dev->ultra_map == 0) { + dev->scam_on = 0x00; + dev->global_map = 0x20; + dev->ultra_map = 0xffff; + } + shpnt = scsi_register(tpnt, 4); + if(shpnt==NULL) + return count; + + save_flags(flags); + cli(); + if (request_irq(irq, atp870u_intr_handle, SA_SHIRQ, "atp870u", dev)) { + printk(KERN_ERR "Unable to allocate IRQ for Acard controller.\n"); + goto unregister; + } + + if (chip_ver[h] > 0x07) /* check if atp876 chip */ + { /* then enable terminator */ + tmport = base_io + 0x3e; + outb(0x00, tmport); + } + + tmport = base_io + 0x3a; + k = (inb(tmport) & 0xf3) | 0x10; + outb(k, tmport); + outb((k & 0xdf), tmport); + mydlyu(0x8000); + outb(k, tmport); + mydlyu(0x8000); + tmport = base_io; + outb((host_id | 0x08), tmport); + tmport += 0x18; + outb(0, tmport); + tmport += 0x07; + while ((inb(tmport) & 0x80) == 0); + tmport -= 0x08; + inb(tmport); + tmport = base_io + 1; + outb(8, tmport++); + outb(0x7f, tmport); + tmport = base_io + 0x11; + outb(0x20, tmport); + + tscam(h); + is870(h, base_io); + tmport = base_io + 0x3a; + outb((inb(tmport) & 0xef), tmport); + tmport++; + outb((inb(tmport) | 0x20),tmport); + } + else + { + base_io &= 0xfffffff8; + + if (check_region(base_io,0x60) != 0) + { + return 0; + } + host_id = inb(base_io + 0x39); + host_id >>= 0x04; + + printk(KERN_INFO " ACARD AEC-67160 PCI Ultra3 LVD Host Adapter: %d IO:%x, IRQ:%d.\n" + ,h, base_io, irq); + dev->ioport = base_io + 0x40; + dev->pciport = base_io + 0x28; + dev->deviceid = dev_id[h]; + irqnumu[h] = irq; + dev->host_idu = host_id; + dev->chip_veru = chip_ver[h]; + + tmport = base_io + 0x22; + dev->scam_on = inb(tmport); + tmport += 0x13; + dev->global_map = inb(tmport); + tmport += 0x07; + dev->ultra_map = inw(tmport); + if (dev->ultra_map == 0) { + dev->scam_on = 0x00; + dev->global_map = 0x20; + dev->ultra_map = 0xffff; + } + shpnt = scsi_register(tpnt, 4); + if(shpnt==NULL) + return count; + + save_flags(flags); + cli(); + if (request_irq(irq, atp870u_intr_handle, SA_SHIRQ, "atp870u", dev)) { + printk(KERN_ERR "Unable to allocate IRQ for Acard controller.\n"); + goto unregister; + } + + tmport = base_io + 0x38; + k = inb(tmport) & 0x80; + outb(k, tmport); + tmport += 0x03; + outb(0x20, tmport); + mydlyu(0x8000); + outb(0, tmport); + mydlyu(0x8000); + tmport = base_io + 0x5b; + inb(tmport); + tmport -= 0x04; + inb(tmport); + tmport = base_io + 0x40; + outb((host_id | 0x08), tmport); + tmport += 0x18; + outb(0, tmport); + tmport += 0x07; + while ((inb(tmport) & 0x80) == 0); + tmport -= 0x08; + inb(tmport); + tmport = base_io + 0x41; + outb(8, tmport++); + outb(0x7f, tmport); + tmport = base_io + 0x51; + outb(0x20, tmport); + + is880(h, base_io); + tmport = base_io + 0x38; + outb(0xb0, tmport); + } + + atp_host[h] = shpnt; + if (dev->chip_veru == 4) { + shpnt->max_id = 16; + } + shpnt->this_id = host_id; + shpnt->unique_id = base_io; + shpnt->io_port = base_io; + if (dev_id[h] == 0x8081) + { + shpnt->n_io_port = 0x60; /* Number of bytes of I/O space used */ + } + else + { + shpnt->n_io_port = 0x40; /* Number of bytes of I/O space used */ + } + shpnt->irq = irq; + restore_flags(flags); + if (dev_id[h] == 0x8081) + { + request_region(base_io, 0x60, "atp870u"); /* Register the IO ports that we use */ + } + else + { + request_region(base_io, 0x40, "atp870u"); /* Register the IO ports that we use */ + } + count++; index++; continue; unregister: @@ -1809,7 +2606,8 @@ int atp870u_abort(Scsi_Cmnd * SCpnt) { - unsigned char h, j; + unsigned char h, j, k; + Scsi_Cmnd *workrequ; unsigned int tmport; struct atp_unit *dev; for (h = 0; h <= admaxu; h++) { @@ -1830,18 +2628,34 @@ printk(" r1c=%2x", inb(tmport)); tmport += 0x03; printk(" r1f=%2x in_snd=%2x ", inb(tmport), dev->in_snd); - tmport++; + tmport= dev->pciport; printk(" r20=%2x", inb(tmport)); tmport += 0x02; printk(" r22=%2x", inb(tmport)); - tmport += 0x18; + tmport = dev->ioport + 0x3a; printk(" r3a=%2x \n",inb(tmport)); + tmport = dev->ioport + 0x3b; + printk(" r3b=%2x \n",inb(tmport)); + for(j=0;j<16;j++) + { + if (dev->id[j].curr_req != NULL) + { + workrequ = dev->id[j].curr_req; + printk("\n que cdb= "); + for (k=0; k < workrequ->cmd_len; k++) + { + printk(" %2x ",workrequ->cmnd[k]); + } + printk(" last_lenu= %x ",dev->id[j].last_lenu); + } + } return (SCSI_ABORT_SNOOZE); } int atp870u_reset(Scsi_Cmnd * SCpnt, unsigned int reset_flags) { unsigned char h; + struct atp_unit *dev; /* * See if a bus reset was suggested. */ @@ -1852,6 +2666,7 @@ } panic("Reset bus host not found !"); find_host: + dev=&atp_unit[h]; /* SCpnt->result = 0x00080000; SCpnt->scsi_done(SCpnt); dev->working=0; @@ -1865,7 +2680,7 @@ { static char buffer[128]; - strcpy(buffer, "ACARD AEC-6710/6712 PCI Ultra/W SCSI-3 Adapter Driver V2.1+ac "); + strcpy(buffer, "ACARD AEC-6710/6712/67160 PCI Ultra/W/LVD SCSI-3 Adapter Driver V2.4+ac "); return buffer; } @@ -1910,7 +2725,7 @@ if (offset == 0) { memset(buff, 0, sizeof(buff)); } - size += sprintf(BLS, "ACARD AEC-671X Driver Version: 2.1+ac\n"); + size += sprintf(BLS, "ACARD AEC-671X Driver Version: 2.4+ac\n"); len += size; pos = begin + len; size = 0; @@ -1976,3 +2791,4 @@ static Scsi_Host_Template driver_template = ATP870U; #include "scsi_module.c" + diff -u --recursive --new-file v2.4.6/linux/drivers/scsi/cpqfcTSinit.c linux/drivers/scsi/cpqfcTSinit.c --- v2.4.6/linux/drivers/scsi/cpqfcTSinit.c Tue Jul 3 17:08:20 2001 +++ linux/drivers/scsi/cpqfcTSinit.c Thu Jul 19 21:09:34 2001 @@ -41,6 +41,7 @@ #include <linux/timer.h> #include <linux/ioport.h> // request_region() prototype #include <linux/vmalloc.h> // ioremap() +#include <linux/completion.h> #ifdef __alpha__ #define __KERNEL_SYSCALLS__ #endif @@ -435,8 +436,8 @@ req = &SCpnt->request; req->rq_status = RQ_SCSI_DONE; /* Busy, but indicate request done */ - if (req->sem != NULL) { - up(req->sem); + if (req->waiting != NULL) { + complete(req->waiting); } } @@ -560,8 +561,8 @@ spin_lock_irqsave(&io_request_lock, flags); { - DECLARE_MUTEX_LOCKED(sem); - ScsiPassThruCmnd->request.sem = &sem; + DECLARE_COMPLETION(wait); + ScsiPassThruCmnd->request.waiting = &wait; // eventually gets us to our own _quecommand routine scsi_do_cmd( ScsiPassThruCmnd, &vendor_cmd->cdb[0], buf, @@ -571,9 +572,9 @@ spin_unlock_irqrestore(&io_request_lock, flags); // Other I/Os can now resume; we wait for our ioctl // command to complete - down(&sem); + wait_for_completion(&wait); spin_lock_irqsave(&io_request_lock, flags); - ScsiPassThruCmnd->request.sem = NULL; + ScsiPassThruCmnd->request.waiting = NULL; } result = ScsiPassThruCmnd->result; diff -u --recursive --new-file v2.4.6/linux/drivers/scsi/dec_esp.c linux/drivers/scsi/dec_esp.c --- v2.4.6/linux/drivers/scsi/dec_esp.c Fri Feb 9 11:30:23 2001 +++ linux/drivers/scsi/dec_esp.c Thu Jul 5 11:28:16 2001 @@ -87,7 +87,7 @@ unsigned char scsi_pmaz_dma_buff_used[ESP_NCMD]; unsigned char scsi_cur_buff = 1; /* Leave space for command buffer */ __u32 esp_virt_buffer; -int scsi_current_length = 0; +int scsi_current_length; volatile unsigned char cmd_buffer[16]; volatile unsigned char pmaz_cmd_buffer[16]; @@ -181,10 +181,13 @@ esp->esp_command_dvma = (__u32) KSEG1ADDR((volatile unsigned char *) cmd_buffer); esp->irq = SCSI_INT; - request_irq(esp->irq, esp_intr, SA_INTERRUPT, "NCR 53C94 SCSI", - NULL); - request_irq(SCSI_DMA_INT, scsi_dma_int, SA_INTERRUPT, "JUNKIO SCSI DMA", - NULL); + if (request_irq(esp->irq, esp_intr, SA_INTERRUPT, + "NCR 53C94 SCSI", NULL)) + goto err_dealloc; + if (request_irq(SCSI_DMA_INT, scsi_dma_int, SA_INTERRUPT, + "JUNKIO SCSI DMA", NULL)) + goto err_free_irq; + esp->scsi_id = 7; @@ -257,7 +260,12 @@ esp->dma_mmu_release_scsi_sgl = 0; esp->dma_advance_sg = 0; - request_irq(esp->irq, esp_intr, SA_INTERRUPT, "PMAZ_AA", NULL); + if (request_irq(esp->irq, esp_intr, SA_INTERRUPT, + "PMAZ_AA", NULL)) { + esp_deallocate(esp); + release_tc_card(slot); + continue; + } esp->scsi_id = 7; esp->diff = 0; esp_initialize(esp); @@ -267,10 +275,16 @@ if(nesps) { printk("ESP: Total of %d ESP hosts found, %d actually in use.\n", nesps, esps_in_use); - esps_running = esps_in_use; - return esps_in_use; - } else - return 0; + esps_running = esps_in_use; + return esps_in_use; + } + return 0; + + err_free_irq: + free_irq(esp->irq, esp_intr); + err_dealloc: + esp_deallocate(esp); + return 0; } /************************************************************* DMA Functions */ @@ -524,4 +538,4 @@ (char *) KSEG0ADDR((sp->request_buffer)); } -#endif \ No newline at end of file +#endif diff -u --recursive --new-file v2.4.6/linux/drivers/scsi/fdomain.c linux/drivers/scsi/fdomain.c --- v2.4.6/linux/drivers/scsi/fdomain.c Fri May 4 15:11:42 2001 +++ linux/drivers/scsi/fdomain.c Sun Jul 15 16:22:23 2001 @@ -3,6 +3,7 @@ * Revised: Mon Dec 28 21:59:02 1998 by faith@acm.org * Author: Rickard E. Faith, faith@cs.unc.edu * Copyright 1992-1996, 1998 Rickard E. Faith (faith@acm.org) + * Shared IRQ supported added 7/7/2001 Alan Cox <alan@redhat.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 @@ -982,7 +983,7 @@ /* Register the IRQ with the kernel */ retcode = request_irq( interrupt_level, - do_fdomain_16x0_intr, 0, "fdomain", NULL); + do_fdomain_16x0_intr, pdev?SA_SHIRQ:0, "fdomain", NULL); if (retcode < 0) { if (retcode == -EINVAL) { @@ -1229,8 +1230,11 @@ interruptions while this routine is running. */ - /* sti(); Yes, we really want sti() here if we want to lock up our machine */ - + /* Check for other IRQ sources */ + if((inb(TMC_Status_port)&0x01)==0) + return; + + /* It is our IRQ */ outb( 0x00, Interrupt_Cntl_port ); /* We usually have one spurious interrupt after each command. Ignore it. */ diff -u --recursive --new-file v2.4.6/linux/drivers/scsi/gdth_proc.c linux/drivers/scsi/gdth_proc.c --- v2.4.6/linux/drivers/scsi/gdth_proc.c Sat May 19 17:43:06 2001 +++ linux/drivers/scsi/gdth_proc.c Thu Jul 19 21:11:02 2001 @@ -3,6 +3,7 @@ */ #include "gdth_ioctl.h" +#include <linux/completion.h> int gdth_proc_info(char *buffer,char **start,off_t offset,int length, int hostno,int inout) @@ -1229,11 +1230,7 @@ char *cmnd, int timeout) { unsigned bufflen; -#if LINUX_VERSION_CODE >= 0x020322 - DECLARE_MUTEX_LOCKED(sem); -#else - struct semaphore sem = MUTEX_LOCKED; -#endif + DECLARE_COMPLETION(wait); TRACE2(("gdth_do_cmd()\n")); if (gdtcmd != NULL) { @@ -1244,7 +1241,7 @@ bufflen = 0; } scp->request.rq_status = RQ_SCSI_BUSY; - scp->request.sem = &sem; + scp->request.waiting = &wait; #if LINUX_VERSION_CODE >= 0x020322 scsi_do_cmd(scp, cmnd, gdtcmd, bufflen, gdth_scsi_done, timeout*HZ, 1); #else @@ -1252,7 +1249,7 @@ scsi_do_cmd(scp, cmnd, gdtcmd, bufflen, gdth_scsi_done, timeout*HZ, 1); GDTH_UNLOCK_SCSI_DOCMD(); #endif - down(&sem); + wait_for_completion(&wait); } void gdth_scsi_done(Scsi_Cmnd *scp) @@ -1261,8 +1258,8 @@ scp->request.rq_status = RQ_SCSI_DONE; - if (scp->request.sem != NULL) - up(scp->request.sem); + if (scp->request.waiting != NULL) + complete(scp->request.waiting); } static int gdth_ioctl_alloc(int hanum, ushort size) diff -u --recursive --new-file v2.4.6/linux/drivers/scsi/hosts.c linux/drivers/scsi/hosts.c --- v2.4.6/linux/drivers/scsi/hosts.c Tue Jul 3 17:08:20 2001 +++ linux/drivers/scsi/hosts.c Thu Jul 5 11:28:17 2001 @@ -69,7 +69,7 @@ * idiocy. */ -Scsi_Host_Template * scsi_hosts = NULL; +Scsi_Host_Template * scsi_hosts; /* @@ -77,12 +77,12 @@ * MAX_SCSI_HOSTS here. */ -Scsi_Host_Name * scsi_host_no_list = NULL; -struct Scsi_Host * scsi_hostlist = NULL; -struct Scsi_Device_Template * scsi_devicelist = NULL; +Scsi_Host_Name * scsi_host_no_list; +struct Scsi_Host * scsi_hostlist; +struct Scsi_Device_Template * scsi_devicelist; -int max_scsi_hosts = 0; -int next_scsi_host = 0; +int max_scsi_hosts; +int next_scsi_host; void scsi_unregister(struct Scsi_Host * sh){ @@ -237,6 +237,7 @@ retval->use_clustering = tpnt->use_clustering; retval->select_queue_depths = tpnt->select_queue_depths; + retval->max_sectors = tpnt->max_sectors; if(!scsi_hostlist) scsi_hostlist = retval; diff -u --recursive --new-file v2.4.6/linux/drivers/scsi/hosts.h linux/drivers/scsi/hosts.h --- v2.4.6/linux/drivers/scsi/hosts.h Fri May 25 18:02:21 2001 +++ linux/drivers/scsi/hosts.h Fri Jul 20 12:55:46 2001 @@ -243,6 +243,11 @@ short unsigned int sg_tablesize; /* + * if the host adapter has limitations beside segment count + */ + short unsigned int max_sectors; + + /* * True if this host adapter can make good use of linked commands. * This will allow more than one command to be queued to a given * unit on a given host. Set this to the maximum number of command @@ -380,6 +385,7 @@ int can_queue; short cmd_per_lun; short unsigned int sg_tablesize; + short unsigned int max_sectors; unsigned in_recovery:1; unsigned unchecked_isa_dma:1; @@ -523,7 +529,7 @@ /* These are used by loadable modules */ extern int scsi_register_module(int, void *); -extern void scsi_unregister_module(int, void *); +extern int scsi_unregister_module(int, void *); /* The different types of modules that we can load and unload */ #define MODULE_SCSI_HA 1 diff -u --recursive --new-file v2.4.6/linux/drivers/scsi/megaraid.c linux/drivers/scsi/megaraid.c --- v2.4.6/linux/drivers/scsi/megaraid.c Fri Apr 27 13:59:18 2001 +++ linux/drivers/scsi/megaraid.c Wed Jul 4 11:50:39 2001 @@ -9,7 +9,7 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * - * Version : v1.14g (Feb 5, 2001) + * Version : v1.15d(May 30, 2001) * * Description: Linux device driver for AMI MegaRAID controller * @@ -296,6 +296,63 @@ * Version 1.14g-ac2 - 22/03/01 * Fixed a non obvious dereference after free in the driver unload path * + * Version 1.14i + * changes for making 32bit application run on IA64 + * + * Version 1.14j + * Tue Mar 13 14:27:54 EST 2001 - AM + * Changes made in the driver to be able to run applications if the + * system has memory >4GB. + * + * + * Version 1.14k + * Thu Mar 15 18:38:11 EST 2001 - AM + * + * Firmware version check removed if subsysid==0x1111 and + * subsysvid==0x1111, since its not yet initialized. + * + * changes made to correctly calculate the base in mega_findCard. + * + * Driver informational messages now appear on the console as well as + * with dmesg + * + * Older ioctl interface is returned failure on newer(2.4.xx) kernels. + * + * Inclusion of "modversions.h" is still a debatable question. It is + * included anyway with this release. + * + * Version 1.14l + * Mon Mar 19 17:39:46 EST 2001 - AM + * + * Assorted changes to remove compilation error in 1.14k when compiled + * with kernel < 2.4.0 + * + * Version 1.15 + * Thu Apr 19 09:38:38 EDT 2001 - AM + * + * 1.14l rollover to 1.15 + * + * Version 1.15b + * Wed May 16 20:10:01 EDT 2001 - AM + * + * "modeversions.h" is no longer included in the code. + * 2.4.xx style mutex initialization used for older kernels also + * Brought in-sync with Alan's changes in 2.4.4 + * Note: 1.15a is on OBDR brabch(main trunk), and is not merged with yet. + * + * Version 1.15c + * Mon May 21 23:10:42 EDT 2001 - AM + * + * ioctl interface uses 2.4.x conforming pci dma calls + * similar calls used for older kernels + * + * Version 1.15d + * Wed May 30 17:30:41 EDT 2001 - AM + * + * NULL is not a valid first argument for pci_alloc_consistent() on + * IA64(2.4.3-2.10.1). Code shuffling done in ioctl interface to get + * "pci_dev" before making calls to pci interface routines. + * BUGS: * Some older 2.1 kernels (eg. 2.1.90) have a bug in pci.c that * fails to detect the controller as a pci device on the system. @@ -399,7 +456,11 @@ #define cpuid smp_processor_id() #endif -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) /* 0x020100 */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,4) +#define scsi_set_pci_device(x,y) +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) /* 0x020400 */ /* * Linux 2.4 and higher @@ -447,10 +508,12 @@ #define IO_UNLOCK spin_unlock_irqrestore(&io_request_lock,io_flags); #define pci_free_consistent(a,b,c,d) -#define pci_unmap_single(a,b,c,d,e) +#define pci_unmap_single(a,b,c,d) + +#define init_MUTEX_LOCKED(x) (*(x)=MUTEX_LOCKED) +#define init_MUTEX(x) (*(x)=MUTEX) -#define init_MUTEX_LOCKED(x) ((x)=MUTEX_LOCKED) -#define init_MUTEX(x) ((x)=MUTEX) +#define pci_enable_device(x) (0) #define queue_task_irq(a,b) queue_task(a,b) #define queue_task_irq_off(a,b) queue_task(a,b) @@ -480,10 +543,12 @@ #define cpu_to_le32(x) (x) #define pci_free_consistent(a,b,c,d) -#define pci_unmap_single(a,b,c,d,e) +#define pci_unmap_single(a,b,c,d) + +#define init_MUTEX_LOCKED(x) (*(x)=MUTEX_LOCKED) +#define init_MUTEX(x) (*(x)=MUTEX) -#define init_MUTEX_LOCKED(x) ((x)=MUTEX_LOCKED) -#define init_MUTEX(x) ((x)=MUTEX) +#define pci_enable_device(x) (0) /* * 2.0 lacks spinlocks, iounmap/ioremap @@ -508,6 +573,16 @@ #endif +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) /* 0x020400 */ +#define dma_alloc_consistent pci_alloc_consistent +#define dma_free_consistent pci_free_consistent +#else +typedef unsigned long dma_addr_t; +void *dma_alloc_consistent(void *, size_t, dma_addr_t *); +void dma_free_consistent(void *, size_t, void *, dma_addr_t); +int mega_get_order(int); +int pow_2(int); +#endif /* set SERDEBUG to 1 to enable serial debugging */ #define SERDEBUG 0 @@ -973,10 +1048,16 @@ if ((SCpnt->cmnd[0] == MEGADEVIOC)) return megadev_doioctl (megaCfg, SCpnt); -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0) if ((SCpnt->cmnd[0] == M_RD_IOCTL_CMD) - || (SCpnt->cmnd[0] == M_RD_IOCTL_CMD_NEW)) + || (SCpnt->cmnd[0] == M_RD_IOCTL_CMD_NEW)) +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0) return mega_ioctl (megaCfg, SCpnt); /* Handle IOCTL command */ +#else + { + printk(KERN_WARNING "megaraid ioctl: older interface - " + "not supported.\n"); + return NULL; + } #endif islogical = (SCpnt->channel == megaCfg->host->max_channel); @@ -1407,7 +1488,7 @@ * cmnd[4..7] = external user buffer * * cmnd[8..11] = length of buffer * * */ - char *user_area = *((char **) &SCpnt->cmnd[4]); + char *user_area = (char *)*((u32*)&SCpnt->cmnd[4]); u32 xfer_size = *((u32 *) & SCpnt->cmnd[8]); switch (data[0]) { case FW_FIRE_WRITE: @@ -1598,8 +1679,8 @@ mbox->xferaddr = virt_to_bus (pScb->sgList); mbox->numsgelements = idx; } +#endif -#endif /* KERNEL_VERSION(2,3,0) */ #if DEBUG static unsigned int cum_time = 0; @@ -2348,7 +2429,7 @@ megaCfg->biosVer[4] = 0; #endif - printk (KERN_INFO "megaraid: [%s:%s] detected %d logical drives" M_RD_CRLFSTR, + printk (KERN_NOTICE "megaraid: [%s:%s] detected %d logical drives" M_RD_CRLFSTR, megaCfg->fwVer, megaCfg->biosVer, megaCfg->numldrv); /* * I hope that I can unmap here, reason DMA transaction is not required any more @@ -2368,7 +2449,7 @@ * Returns data to be displayed in /proc/scsi/megaraid/X *----------------------------------------------------------*/ -static int megaraid_proc_info (char *buffer, char **start, off_t offset, +int megaraid_proc_info (char *buffer, char **start, off_t offset, int length, int host_no, int inout) { *start = buffer; @@ -2411,7 +2492,7 @@ #endif while ((pdev = pci_find_device (pciVendor, pciDev, pdev))) { - if (pci_enable_device (pdev)) + if(pci_enable_device (pdev)) continue; pciBus = pdev->bus->number; pciDevFun = pdev->devfn; @@ -2425,11 +2506,16 @@ continue; /* not an AMI board */ } #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) +#if 0 +/* + * This leads to corruption on some HP boards so disable it + */ pcibios_read_config_dword (pciBus, pciDevFun, PCI_CONF_AMISIG64, &magic64); if (magic64 == AMI_64BIT_SIGNATURE) flag |= BOARD_64BIT; +#endif #endif } @@ -2451,9 +2537,7 @@ pci_read_config_word (pdev, PCI_SUBSYSTEM_ID, &subsysid); #endif - if ((subsysid == 0x1111) && (subsysvid == 0x1111) && - (!strcmp (megaCfg->fwVer, "3.00") - || !strcmp (megaCfg->fwVer, "3.01"))) { + if ((subsysid == 0x1111) && (subsysvid == 0x1111)) { printk (KERN_WARNING "megaraid: Your card is a Dell PERC 2/SC RAID controller with firmware\n" "megaraid: 3.00 or 3.01. This driver is known to have corruption issues\n" @@ -2476,7 +2560,7 @@ continue; } - printk (KERN_INFO + printk (KERN_NOTICE "megaraid: found 0x%4.04x:0x%4.04x:idx %d:bus %d:slot %d:func %d\n", pciVendor, pciDev, pciIdx, pciBus, PCI_SLOT (pciDevFun), PCI_FUNC (pciDevFun)); @@ -2499,11 +2583,14 @@ pciIdx++; if (flag & BOARD_QUARTZ) { + megaBase &= PCI_BASE_ADDRESS_MEM_MASK; megaBase = (long) ioremap (megaBase, 128); if (!megaBase) continue; - } else + } else { + megaBase &= PCI_BASE_ADDRESS_IO_MASK; megaBase += 0x10; + } /* Initialize SCSI Host structure */ host = scsi_register (pHostTmpl, sizeof (mega_host_config)); @@ -2514,11 +2601,11 @@ megaCfg = (mega_host_config *) host->hostdata; memset (megaCfg, 0, sizeof (mega_host_config)); - printk (KERN_INFO "scsi%d : Found a MegaRAID controller at 0x%x, IRQ: %d" + printk (KERN_NOTICE "scsi%d : Found a MegaRAID controller at 0x%x, IRQ: %d" M_RD_CRLFSTR, host->host_no, (u_int) megaBase, megaIrq); if (flag & BOARD_64BIT) - printk (KERN_INFO "scsi%d : Enabling 64 bit support\n", + printk (KERN_NOTICE "scsi%d : Enabling 64 bit support\n", host->host_no); /* Copy resource info into structure */ @@ -2549,10 +2636,11 @@ if (!(flag & BOARD_QUARTZ)) { /* Request our IO Range */ - if (!request_region(megaBase, 16, "megaraid")) { - printk (KERN_WARNING "megaraid: Couldn't register I/O range!" M_RD_CRLFSTR); + if (check_region (megaBase, 16)) { + printk(KERN_WARNING "megaraid: Couldn't register I/O range!\n"); goto err_unregister; } + request_region(megaBase, 16, "megaraid"); } /* Request our IRQ */ @@ -2678,7 +2766,7 @@ skip_id = (skip_id > 15) ? -1 : skip_id; } - printk (KERN_INFO "megaraid: " MEGARAID_VERSION M_RD_CRLFSTR); + printk (KERN_NOTICE "megaraid: " MEGARAID_VERSION M_RD_CRLFSTR); memset (mega_hbas, 0, sizeof (mega_hbas)); @@ -2736,7 +2824,7 @@ /*--------------------------------------------------------------------- * Release the controller's resources *---------------------------------------------------------------------*/ -static int megaraid_release (struct Scsi_Host *pSHost) +int megaraid_release (struct Scsi_Host *pSHost) { mega_host_config *megaCfg; mega_mailbox *mbox; @@ -3022,7 +3110,7 @@ /*---------------------------------------------- * Get information about the card/driver *----------------------------------------------*/ -static const char *megaraid_info (struct Scsi_Host *pSHost) +const char *megaraid_info (struct Scsi_Host *pSHost) { static char buffer[512]; mega_host_config *megaCfg; @@ -3052,7 +3140,7 @@ * 10 01 numstatus byte * 11 01 status byte *-----------------------------------------------------------------*/ -static int megaraid_queue (Scsi_Cmnd * SCpnt, void (*pktComp) (Scsi_Cmnd *)) +int megaraid_queue (Scsi_Cmnd * SCpnt, void (*pktComp) (Scsi_Cmnd *)) { DRIVER_LOCK_T mega_host_config * megaCfg; mega_scb *pScb; @@ -3063,11 +3151,11 @@ if (!(megaCfg->flag & (1L << SCpnt->channel))) { if (SCpnt->channel < SCpnt->host->max_channel) - printk ( /*KERN_INFO */ + printk ( KERN_NOTICE "scsi%d: scanning channel %c for devices.\n", megaCfg->host->host_no, SCpnt->channel + '1'); else - printk ( /*KERN_INFO */ + printk ( KERN_NOTICE "scsi%d: scanning virtual channel for logical drives.\n", megaCfg->host->host_no); @@ -3136,7 +3224,7 @@ init_MUTEX_LOCKED (&pScb->ioctl_sem); spin_unlock_irq (&io_request_lock); down (&pScb->ioctl_sem); - user_area = *((char **) &pScb->SCpnt->cmnd[4]); + user_area = (char *)*((u32*)&pScb->SCpnt->cmnd[4]); if (copy_to_user (user_area, pScb->buff_ptr, pScb->iDataSize)) { printk @@ -3178,7 +3266,7 @@ /* shouldn't be used, but included for completeness */ -static int megaraid_command (Scsi_Cmnd * SCpnt) +int megaraid_command (Scsi_Cmnd * SCpnt) { internal_done_flag = 0; @@ -3195,7 +3283,7 @@ /*--------------------------------------------------------------------- * Abort a previous SCSI request *---------------------------------------------------------------------*/ -static int megaraid_abort (Scsi_Cmnd * SCpnt) +int megaraid_abort (Scsi_Cmnd * SCpnt) { mega_host_config *megaCfg; int rc; /*, idx; */ @@ -3293,7 +3381,7 @@ * Reset a previous SCSI request *---------------------------------------------------------------------*/ -static int megaraid_reset (Scsi_Cmnd * SCpnt, unsigned int rstflags) +int megaraid_reset (Scsi_Cmnd * SCpnt, unsigned int rstflags) { mega_host_config *megaCfg; int idx; @@ -3404,7 +3492,7 @@ *start = page; proc_printf (megaCfg, "Statistical Information for this controller\n"); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) /* 0x020100 */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) /* 0x020400 */ proc_printf (megaCfg, "Interrupts Collected = %Lu\n", megaCfg->nInterrupts); #else @@ -3574,7 +3662,7 @@ * geom[1] = sectors * geom[2] = cylinders *-------------------------------------------------------------*/ -static int megaraid_biosparam (Disk * disk, kdev_t dev, int *geom) +int megaraid_biosparam (Disk * disk, kdev_t dev, int *geom) { int heads, sectors, cylinders; mega_host_config *megaCfg; @@ -3788,11 +3876,9 @@ kdev_t dev; u32 inlen; struct uioctl_t ioc; - char *kphysaddr = NULL; + char *kvaddr = NULL; int nadap = numCtlrs; - int npages; u8 opcode; - int order = 0; u32 outlen; int ret; u8 subopcode; @@ -3800,6 +3886,15 @@ struct Scsi_Host *shpnt; char *uaddr; struct uioctl_t *uioc; + dma_addr_t dma_addr; + u32 length; + mega_host_config *megacfg; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) /* 0x020400 */ + struct pci_dev pdev; + struct pci_dev *pdevp = &pdev; +#else + char *pdevp = NULL; +#endif IO_LOCK_T; if (!inode || !(dev = inode->i_rdev)) @@ -3809,12 +3904,6 @@ return (-EINVAL); /* - * We do not transfer more than IOCTL_MAX_DATALEN (see megaraid.h) with - * this interface.If the user needs to transfer more than this,he should - * use 0x81 command op-code. - */ - - /* * Get the user ioctl structure */ ret = verify_area (VERIFY_WRITE, (char *) arg, sizeof (struct uioctl_t)); @@ -3826,10 +3915,10 @@ return -EFAULT; /* - * The first call the applications should make is to find out the number - * of controllers in the system. The next logical call should be for - * getting the list of controllers in the system as detected by the - * driver. + * The first call the applications should make is to find out the + * number of controllers in the system. The next logical call should + * be for getting the list of controllers in the system as detected + * by the driver. */ /* @@ -3892,173 +3981,135 @@ adapno = ioc.ui.fcs.adapno; /* See comment above: MEGAIOC_QADAPINFO */ - adapno = GETADAP (adapno); + adapno = GETADAP(adapno); if (adapno >= numCtlrs) - return (-ENODEV); + return(-ENODEV); - /* Check for zero length buffer. */ - if (!ioc.ui.fcs.length) + length = ioc.ui.fcs.length; + + /* Check for zero length buffer or very large buffers */ + if( !length || length > 32*1024 ) return -EINVAL; /* save the user address */ uaddr = ioc.ui.fcs.buffer; -/* -* For M_RD_IOCTL_CMD_NEW commands, the fields outlen and inlen of uioctl_t -* structure are treated as flags. If outlen is 1, the data is -* transferred from the device and if inlen is 1, the data is -* transferred to the device. -*/ + /* + * For M_RD_IOCTL_CMD_NEW commands, the fields outlen and inlen of + * uioctl_t structure are treated as flags. If outlen is 1, the + * data is transferred from the device and if inlen is 1, the data + * is transferred to the device. + */ outlen = ioc.outlen; inlen = ioc.inlen; -#if 0 - if (inlen && outlen) - return -EINVAL; -#endif - if (outlen) { - ret = verify_area (VERIFY_WRITE, - (char *) ioc.ui.fcs.buffer, - ioc.ui.fcs.length); - if (ret) - return ret; - } else if (inlen) { - ret = verify_area (VERIFY_READ, - (char *) ioc.ui.fcs.buffer, - ioc.ui.fcs.length); - if (ret) - return ret; + if(outlen) { + ret = verify_area(VERIFY_WRITE, (char *)ioc.ui.fcs.buffer, length); + if (ret) return ret; + } + if(inlen) { + ret = verify_area(VERIFY_READ, (char *) ioc.ui.fcs.buffer, length); + if (ret) return ret; } - /* How many pages required of size PAGE_SIZE */ - npages = ioc.ui.fcs.length / PAGE_SIZE; - /* Do we need one more? */ - - if (ioc.ui.fcs.length % PAGE_SIZE) - npages++; - - /* ioctl does not support data xfer > 32KB */ - if (npages == 1) - order = 0; - else if (npages == 2) - order = 1; - else if (npages <= 4) - order = 2; - else if (npages <= 8) - order = 3; - else - return -EINVAL; - - if (outlen || inlen) { - /* - * Allocate kernel space for npages. - * - * Since we need the memory for DMA, it needs to be physically - * contiguous. __get_free_pags() return consecutive free pages - * in kernel space. - * Note: We don't do __get_dma_pages(), since for PCI devices, - * the DMA memory is not restriceted to 16M, which is ensured - * by __get_dma_pages() - */ - - if ((kphysaddr = (char *) __get_free_pages (GFP_KERNEL, - order)) == - 0) { - printk (KERN_INFO - "megaraid:allocation failed\n"); - return -ENOMEM; - } - - memset (kphysaddr, 0, npages * PAGE_SIZE); - ioc.ui.fcs.buffer = kphysaddr; - - if (inlen) { - /* copyin the user data */ - copy_from_user (kphysaddr, - (char *) uaddr, - ioc.ui.fcs.length); + /* + * Find this host + */ + for( shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next ) { + if( shpnt->hostdata == (unsigned long *)megaCtlrs[adapno] ) { + megacfg = (mega_host_config *)shpnt->hostdata; + break; } } + if(shpnt == NULL) return -ENODEV; + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) - scsicmd = (Scsi_Cmnd *) kmalloc (sizeof (Scsi_Cmnd), - GFP_KERNEL | GFP_DMA); - memset (scsicmd, 0, sizeof (Scsi_Cmnd)); + scsicmd = (Scsi_Cmnd *)kmalloc(sizeof(Scsi_Cmnd), GFP_KERNEL|GFP_DMA); #else - scsicmd = (Scsi_Cmnd *) scsi_init_malloc (sizeof (Scsi_Cmnd), + scsicmd = (Scsi_Cmnd *)scsi_init_malloc(sizeof(Scsi_Cmnd), GFP_ATOMIC | GFP_DMA); #endif - if (!scsicmd) { - if (kphysaddr) - free_pages ((unsigned long) kphysaddr, order); - return -ENOMEM; - } + if(scsicmd == NULL) return -ENOMEM; - scsicmd->host = NULL; + memset(scsicmd, 0, sizeof(Scsi_Cmnd)); + scsicmd->host = shpnt; - /* - * Find this host - */ - for (shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) { - if (shpnt->hostdata == - (unsigned long *) megaCtlrs[adapno]) - scsicmd->host = shpnt; - } - - if (scsicmd->host == NULL) { + if( outlen || inlen ) { #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) - kfree (scsicmd); + pdevp = &pdev; + memcpy(pdevp, megacfg->dev, sizeof(struct pci_dev)); + pdevp->dma_mask = 0xffffffff; +#else + pdevp = NULL; +#endif + kvaddr = dma_alloc_consistent(pdevp, length, &dma_addr); + + if( kvaddr == NULL ) { + printk(KERN_WARNING "megaraid:allocation failed\n"); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) /*0x20400 */ + kfree(scsicmd); #else - scsi_init_free ((char *) scsicmd, sizeof (Scsi_Cmnd)); + scsi_init_free((char *)scsicmd, sizeof(Scsi_Cmnd)); #endif - if (kphysaddr) - free_pages ((unsigned long) kphysaddr, order); - return -ENODEV; + return -ENOMEM; + } + + ioc.ui.fcs.buffer = kvaddr; + + if (inlen) { + /* copyin the user data */ + copy_from_user(kvaddr, (char *)uaddr, length ); + } } scsicmd->cmnd[0] = MEGADEVIOC; - scsicmd->request_buffer = (void *) &ioc; + scsicmd->request_buffer = (void *)&ioc; - init_MUTEX_LOCKED (&mimd_ioctl_sem); + init_MUTEX_LOCKED(&mimd_ioctl_sem); IO_LOCK; - megaraid_queue (scsicmd, megadev_ioctl_done); + megaraid_queue(scsicmd, megadev_ioctl_done); IO_UNLOCK; - down (&mimd_ioctl_sem); + down(&mimd_ioctl_sem); - if (!scsicmd->result && outlen) { - copy_to_user (uaddr, kphysaddr, ioc.ui.fcs.length); + if( !scsicmd->result && outlen ) { + copy_to_user(uaddr, kvaddr, length); } /* * copyout the result */ - uioc = (struct uioctl_t *) arg; + uioc = (struct uioctl_t *)arg; - if (ioc.mbox[0] == MEGA_MBOXCMD_PASSTHRU) { - put_user (scsicmd->result, &uioc->pthru.scsistatus); + if( ioc.mbox[0] == MEGA_MBOXCMD_PASSTHRU ) { + put_user( scsicmd->result, &uioc->pthru.scsistatus ); } else { - put_user (1, &uioc->mbox[16]); /* numstatus */ + put_user(1, &uioc->mbox[16]); /* numstatus */ /* status */ put_user (scsicmd->result, &uioc->mbox[17]); } - if (kphysaddr) { - free_pages ((ulong) kphysaddr, order); + if (kvaddr) { + dma_free_consistent(pdevp, length, kvaddr, dma_addr); } #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) /*0x20400 */ kfree (scsicmd); #else - scsi_init_free ((char *) scsicmd, sizeof (Scsi_Cmnd)); + scsi_init_free((char *)scsicmd, sizeof(Scsi_Cmnd)); #endif + /* restore the user address */ + ioc.ui.fcs.buffer = uaddr; + return ret; case M_RD_IOCTL_CMD: /* which adapter? */ adapno = ioc.ui.fcs.adapno; + /* See comment above: MEGAIOC_QADAPINFO */ adapno = GETADAP (adapno); @@ -4070,85 +4121,74 @@ outlen = ioc.outlen; inlen = ioc.inlen; - if ((outlen >= IOCTL_MAX_DATALEN) - || (inlen >= IOCTL_MAX_DATALEN)) + if ((outlen >= IOCTL_MAX_DATALEN) || (inlen >= IOCTL_MAX_DATALEN)) return (-EINVAL); if (outlen) { ret = verify_area (VERIFY_WRITE, ioc.data, outlen); - if (ret) - return ret; - } else if (inlen) { + if (ret) return ret; + } + if (inlen) { ret = verify_area (VERIFY_READ, ioc.data, inlen); + if (ret) return ret; + } - if (ret) - return ret; + /* + * Find this host + */ + for( shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next ) { + if( shpnt->hostdata == (unsigned long *)megaCtlrs[adapno] ) { + megacfg = (mega_host_config *)shpnt->hostdata; + break; + } } + if(shpnt == NULL) return -ENODEV; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + scsicmd = (Scsi_Cmnd *)kmalloc(sizeof(Scsi_Cmnd), GFP_KERNEL|GFP_DMA); +#else + scsicmd = (Scsi_Cmnd *)scsi_init_malloc(sizeof(Scsi_Cmnd), + GFP_ATOMIC | GFP_DMA); +#endif + if(scsicmd == NULL) return -ENOMEM; + + memset(scsicmd, 0, sizeof(Scsi_Cmnd)); + scsicmd->host = shpnt; if (outlen || inlen) { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + pdevp = &pdev; + memcpy(pdevp, megacfg->dev, sizeof(struct pci_dev)); + pdevp->dma_mask = 0xffffffff; +#else + pdevp = NULL; +#endif /* * Allocate a page of kernel space. */ - if ((kphysaddr = - (char *) __get_free_pages (GFP_KERNEL, 0)) == 0) { + kvaddr = dma_alloc_consistent(pdevp, PAGE_SIZE, &dma_addr); - printk (KERN_INFO - "megaraid:allocation failed\n"); + if( kvaddr == NULL ) { + printk (KERN_WARNING "megaraid:allocation failed\n"); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) /*0x20400 */ + kfree(scsicmd); +#else + scsi_init_free((char *)scsicmd, sizeof(Scsi_Cmnd)); +#endif return -ENOMEM; } - memset (kphysaddr, 0, PAGE_SIZE); - ioc.data = kphysaddr; + ioc.data = kvaddr; if (inlen) { if (ioc.mbox[0] == MEGA_MBOXCMD_PASSTHRU) { /* copyin the user data */ - copy_from_user (kphysaddr, - uaddr, - ioc.pthru.dataxferlen); + copy_from_user (kvaddr, uaddr, ioc.pthru.dataxferlen); } else { - copy_from_user (kphysaddr, - uaddr, inlen); + copy_from_user (kvaddr, uaddr, inlen); } } } -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) /* 0x020400 */ - scsicmd = (Scsi_Cmnd *) kmalloc (sizeof (Scsi_Cmnd), - GFP_KERNEL | GFP_DMA); - memset (scsicmd, 0, sizeof (Scsi_Cmnd)); -#else - scsicmd = (Scsi_Cmnd *) scsi_init_malloc (sizeof (Scsi_Cmnd), - GFP_ATOMIC | GFP_DMA); -#endif - - if (!scsicmd) { - if (kphysaddr) - free_pages ((unsigned long) kphysaddr, 0); - return -ENOMEM; - } - - scsicmd->host = NULL; - - /* - * Find this host in the hostlist - */ - for (shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) { - if (shpnt->hostdata == - (unsigned long *) megaCtlrs[adapno]) - scsicmd->host = shpnt; - } - - if (scsicmd->host == NULL) { -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) - kfree (scsicmd); -#else - scsi_init_free ((char *) scsicmd, sizeof (Scsi_Cmnd)); -#endif - if (kphysaddr) - free_pages ((unsigned long) kphysaddr, 0); - - return -ENODEV; - } scsicmd->cmnd[0] = MEGADEVIOC; scsicmd->request_buffer = (void *) &ioc; @@ -4163,10 +4203,9 @@ if (!scsicmd->result && outlen) { if (ioc.mbox[0] == MEGA_MBOXCMD_PASSTHRU) { - copy_to_user (uaddr, - kphysaddr, ioc.pthru.dataxferlen); + copy_to_user (uaddr, kvaddr, ioc.pthru.dataxferlen); } else { - copy_to_user (uaddr, kphysaddr, outlen); + copy_to_user (uaddr, kvaddr, outlen); } } @@ -4183,26 +4222,31 @@ put_user (scsicmd->result, &uioc->mbox[17]); } - if (kphysaddr) - free_pages ((unsigned long) kphysaddr, 0); + if (kvaddr) { + dma_free_consistent(pdevp, PAGE_SIZE, kvaddr, dma_addr ); + } #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) kfree (scsicmd); #else - scsi_init_free ((char *) scsicmd, sizeof (Scsi_Cmnd)); + scsi_init_free((char *)scsicmd, sizeof(Scsi_Cmnd)); #endif + + /* restore user pointer */ + ioc.data = uaddr; + return ret; default: return (-EINVAL); - } /* Outer switch */ + }/* Outer switch */ return 0; } static void -megadev_ioctl_done (Scsi_Cmnd * sc) +megadev_ioctl_done(Scsi_Cmnd *sc) { up (&mimd_ioctl_sem); } @@ -4309,6 +4353,94 @@ #endif return 0; } + + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0) +void * +dma_alloc_consistent(void *dev, size_t size, dma_addr_t *dma_addr) +{ + void *_tv; + int npages; + int order = 0; + + /* + * How many pages application needs + */ + npages = size / PAGE_SIZE; + + /* Do we need one more page */ + if(size % PAGE_SIZE) + npages++; + + order = mega_get_order(npages); + + _tv = (void *)__get_free_pages(GFP_DMA, order); + + if( _tv != NULL ) { + memset(_tv, 0, size); + *(dma_addr) = virt_to_bus(_tv); + } + + return _tv; +} + +/* + * int mega_get_order(int) + * + * returns the order to be used as 2nd argument to __get_free_pages() - which + * return pages equal to pow(2, order) - AM + */ +int +mega_get_order(int n) +{ + int i = 0; + + while( pow_2(i++) < n ) + ; /* null statement */ + + return i-1; +} + +/* + * int pow_2(int) + * + * calculates pow(2, i) + */ +int +pow_2(int i) +{ + unsigned int v = 1; + + while(i--) + v <<= 1; + + return v; +} + +void +dma_free_consistent(void *dev, size_t size, void *vaddr, dma_addr_t dma_addr) +{ + int npages; + int order = 0; + + npages = size / PAGE_SIZE; + + if(size % PAGE_SIZE) + npages++; + + if (npages == 1) + order = 0; + else if (npages == 2) + order = 1; + else if (npages <= 4) + order = 2; + else + order = 3; + + free_pages((unsigned long)vaddr, order); + +} +#endif #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) static diff -u --recursive --new-file v2.4.6/linux/drivers/scsi/megaraid.h linux/drivers/scsi/megaraid.h --- v2.4.6/linux/drivers/scsi/megaraid.h Fri Apr 13 20:26:07 2001 +++ linux/drivers/scsi/megaraid.h Thu Jul 19 21:08:54 2001 @@ -27,7 +27,8 @@ #define M_RD_IOCTL_CMD_NEW 0x81 #define M_RD_DRIVER_IOCTL_INTERFACE 0x82 -#define MEGARAID_VERSION "v1.14g-ac2 (Release Date: Mar 22, 2001; 19:34:02)" +#define MEGARAID_VERSION "v1.15d (Release Date: Wed May 30 17:30:41 EDT 2001)" + #define MEGARAID_IOCTL_VERSION 114 /* Methods */ @@ -115,6 +116,23 @@ #define ENABLE_INTR(base) WRITE_PORT(base,I_TOGGLE_PORT,ENABLE_INTR_BYTE) #define DISABLE_INTR(base) WRITE_PORT(base,I_TOGGLE_PORT,DISABLE_INTR_BYTE) +/* Define AMI's PCI codes */ +#ifndef PCI_VENDOR_ID_AMI +#define PCI_VENDOR_ID_AMI 0x101E +#endif + +#ifndef PCI_DEVICE_ID_AMI_MEGARAID +#define PCI_DEVICE_ID_AMI_MEGARAID 0x9010 +#endif + +#ifndef PCI_DEVICE_ID_AMI_MEGARAID2 +#define PCI_DEVICE_ID_AMI_MEGARAID2 0x9060 +#endif + +#ifndef PCI_DEVICE_ID_AMI_MEGARAID3 +#define PCI_DEVICE_ID_AMI_MEGARAID3 0x1960 +#endif + /* Special Adapter Commands */ #define FW_FIRE_WRITE 0x2C #define FW_FIRE_FLASH 0x2D @@ -829,15 +847,15 @@ * *================================================================ */ -static const char *megaraid_info (struct Scsi_Host *); +const char *megaraid_info (struct Scsi_Host *); int megaraid_detect (Scsi_Host_Template *); -static int megaraid_release (struct Scsi_Host *); -static int megaraid_command (Scsi_Cmnd *); -static int megaraid_abort (Scsi_Cmnd *); -static int megaraid_reset (Scsi_Cmnd *, unsigned int); -static int megaraid_queue (Scsi_Cmnd *, void (*done) (Scsi_Cmnd *)); -static int megaraid_biosparam (Disk *, kdev_t, int *); -static int megaraid_proc_info (char *buffer, char **start, off_t offset, +int megaraid_release (struct Scsi_Host *); +int megaraid_command (Scsi_Cmnd *); +int megaraid_abort (Scsi_Cmnd *); +int megaraid_reset (Scsi_Cmnd *, unsigned int); +int megaraid_queue (Scsi_Cmnd *, void (*done) (Scsi_Cmnd *)); +int megaraid_biosparam (Disk *, kdev_t, int *); +int megaraid_proc_info (char *buffer, char **start, off_t offset, int length, int hostno, int inout); static int megaIssueCmd (mega_host_config * megaCfg, u_char * mboxData, @@ -855,7 +873,7 @@ static int megaraid_reboot_notify (struct notifier_block *, unsigned long, void *); -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0) +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0) static mega_scb *mega_ioctl (mega_host_config * megaCfg, Scsi_Cmnd * SCpnt); static void mega_build_kernel_sg (char *barea, ulong xfersize, mega_scb * pScb, mega_ioctl_mbox * mbox); diff -u --recursive --new-file v2.4.6/linux/drivers/scsi/ncr53c8xx.c linux/drivers/scsi/ncr53c8xx.c --- v2.4.6/linux/drivers/scsi/ncr53c8xx.c Fri Apr 27 13:59:19 2001 +++ linux/drivers/scsi/ncr53c8xx.c Thu Jul 5 11:28:17 2001 @@ -103,7 +103,7 @@ /* ** Name and version of the driver */ -#define SCSI_NCR_DRIVER_NAME "ncr53c8xx-3.4.3-20010212" +#define SCSI_NCR_DRIVER_NAME "ncr53c8xx-3.4.3b-20010512" #define SCSI_NCR_DEBUG_FLAGS (0) @@ -3082,7 +3082,7 @@ }; /* -** Print something which allows to retrieve the controler type, unit, +** Print something which allows to retrieve the controller type, unit, ** target, lun concerned by a kernel message. */ @@ -4302,7 +4302,7 @@ ** **---------------------------------------------------- */ -#if 0 /* This stuff was only usefull for linux-1.2.13 */ +#if 0 /* This stuff was only useful for linux-1.2.13 */ if (lp && !lp->numtags && cmd->device && cmd->device->tagged_queue) { lp->numtags = tp->usrtags; ncr_setup_tags (np, cmd->target, cmd->lun); @@ -5701,7 +5701,7 @@ */ fak = (kpc - 1) / div_10M[div] + 1; -#if 0 /* This optimization does not seem very usefull */ +#if 0 /* This optimization does not seem very useful */ per = (fak * div_10M[div]) / clk; @@ -6647,7 +6647,7 @@ delta=(INB (nc_dfifo) - rest) & 0x7f; /* - ** The data in the dma fifo has not been transfered to + ** The data in the dma fifo has not been transferred to ** the target -> add the amount to the rest ** and clear the data. ** Check the sstat2 register in case of wide transfer. @@ -7153,7 +7153,7 @@ ** Was Sie schon immer ueber transfermode negotiation wissen wollten ... ** ** We try to negotiate sync and wide transfer only after -** a successfull inquire command. We look at byte 7 of the +** a successful inquire command. We look at byte 7 of the ** inquire data to determine the capabilities of the target. ** ** When we try to negotiate, we append the negotiation message @@ -7550,7 +7550,7 @@ /*========================================================== ** ** -** Aquire a control block +** Acquire a control block ** ** **========================================================== diff -u --recursive --new-file v2.4.6/linux/drivers/scsi/osst.c linux/drivers/scsi/osst.c --- v2.4.6/linux/drivers/scsi/osst.c Tue Jul 3 17:08:20 2001 +++ linux/drivers/scsi/osst.c Thu Jul 19 21:18:15 2001 @@ -290,7 +290,7 @@ #if DEBUG STp->write_pending = 0; #endif - up(SCpnt->request.sem); + complete(SCpnt->request.waiting); } #if DEBUG else if (debugging) @@ -321,8 +321,9 @@ } } - cmd[1] |= (SRpnt->sr_device->lun << 5) & 0xe0; - init_MUTEX_LOCKED(&STp->sem); + if (SRpnt->sr_device->scsi_level <= SCSI_2) + cmd[1] |= (SRpnt->sr_device->lun << 5) & 0xe0; + init_completion(&STp->wait); SRpnt->sr_use_sg = (bytes > (STp->buffer)->sg[0].length) ? (STp->buffer)->use_sg : 0; if (SRpnt->sr_use_sg) { @@ -334,15 +335,15 @@ bp = (STp->buffer)->b_data; SRpnt->sr_data_direction = direction; SRpnt->sr_cmd_len = 0; - SRpnt->sr_request.sem = &(STp->sem); + SRpnt->sr_request.waiting = &(STp->wait); SRpnt->sr_request.rq_status = RQ_SCSI_BUSY; SRpnt->sr_request.rq_dev = STp->devt; scsi_do_req(SRpnt, (void *)cmd, bp, bytes, osst_sleep_done, timeout, retries); if (do_wait) { - down(SRpnt->sr_request.sem); - SRpnt->sr_request.sem = NULL; + wait_for_completion(SRpnt->sr_request.waiting); + SRpnt->sr_request.waiting = NULL; STp->buffer->syscall_result = osst_chk_result(STp, SRpnt); #ifdef OSST_INJECT_ERRORS if (STp->buffer->syscall_result == 0 && @@ -374,8 +375,8 @@ else STp->nbr_finished++; #endif - down(&(STp->sem)); - (STp->buffer)->last_SRpnt->sr_request.sem = NULL; + wait_for_completion(&(STp->wait)); + (STp->buffer)->last_SRpnt->sr_request.waiting = NULL; STp->buffer->syscall_result = osst_chk_result(STp, STp->buffer->last_SRpnt); @@ -712,7 +713,7 @@ result = osst_get_frame_position (STp, aSRpnt); if (result == -EIO) if ((result = osst_write_error_recovery(STp, aSRpnt, 0)) == 0) - return 0; /* successfull recovery leaves drive ready for frame */ + return 0; /* successful recovery leaves drive ready for frame */ if (result < 0) break; if (STp->first_frame_position == curr && ((minlast < 0 && @@ -1379,7 +1380,7 @@ unsigned char cmd[MAX_COMMAND_SIZE]; Scsi_Request * SRpnt; int dev = TAPE_NR(STp->devt); - int expected = 0; + int expected __attribute__ ((__unused__)); int attempts = 1000 / skip; int flag = 1; long startwait = jiffies; diff -u --recursive --new-file v2.4.6/linux/drivers/scsi/osst.h linux/drivers/scsi/osst.h --- v2.4.6/linux/drivers/scsi/osst.h Tue Jul 3 17:08:20 2001 +++ linux/drivers/scsi/osst.h Thu Jul 19 21:18:00 2001 @@ -4,6 +4,7 @@ #include <asm/byteorder.h> #include <linux/config.h> +#include <linux/completion.h> #ifdef CONFIG_DEVFS_FS #include <linux/devfs_fs_kernel.h> #endif @@ -535,7 +536,7 @@ unsigned capacity; Scsi_Device* device; struct semaphore lock; /* for serialization */ - struct semaphore sem; /* for SCSI commands */ + struct completion wait; /* for SCSI commands */ OSST_buffer * buffer; /* Drive characteristics */ @@ -595,7 +596,7 @@ * has been read into STp->buffer and is valid */ int frame_seq_number; /* logical frame number */ int logical_blk_num; /* logical block number */ - unsigned first_frame_position; /* physical frame to be transfered to/from host */ + unsigned first_frame_position; /* physical frame to be transferred to/from host */ unsigned last_frame_position; /* physical frame to be transferd to/from tape */ int cur_frames; /* current number of frames in internal buffer */ int max_frames; /* max number of frames in internal buffer */ diff -u --recursive --new-file v2.4.6/linux/drivers/scsi/pcmcia/Config.in linux/drivers/scsi/pcmcia/Config.in --- v2.4.6/linux/drivers/scsi/pcmcia/Config.in Sun Mar 4 14:30:19 2001 +++ linux/drivers/scsi/pcmcia/Config.in Wed Jul 4 11:50:38 2001 @@ -8,12 +8,13 @@ bool 'PCMCIA SCSI adapter support' CONFIG_SCSI_PCMCIA if [ "$CONFIG_SCSI_PCMCIA" = "y" ]; then dep_tristate ' Adaptec AHA152X PCMCIA support' CONFIG_PCMCIA_AHA152X m - dep_tristate ' Qlogic PCMCIA support' CONFIG_PCMCIA_QLOGIC m dep_tristate ' Future Domain PCMCIA support' CONFIG_PCMCIA_FDOMAIN m + dep_tristate ' NinjaSCSI-3 / NinjaSCSI-32Bi (16bit) PCMCIA support' CONFIG_PCMCIA_NINJA_SCSI m + dep_tristate ' Qlogic PCMCIA support' CONFIG_PCMCIA_QLOGIC m fi if [ "$CONFIG_PCMCIA_QLOGIC" = "y" -o "$CONFIG_PCMCIA_AHA152X" = "y" -o \ - "$CONFIG_PCMCIA_FDOMAIN" = "y" ]; then + "$CONFIG_PCMCIA_FDOMAIN" = "y" -o "$CONFIG_PCMCIA_NINJA_SCSI" = "y" ]; then define_bool CONFIG_PCMCIA_SCSICARD y fi diff -u --recursive --new-file v2.4.6/linux/drivers/scsi/pcmcia/Makefile linux/drivers/scsi/pcmcia/Makefile --- v2.4.6/linux/drivers/scsi/pcmcia/Makefile Mon Mar 26 15:36:30 2001 +++ linux/drivers/scsi/pcmcia/Makefile Wed Jul 4 11:50:38 2001 @@ -19,6 +19,7 @@ obj-$(CONFIG_PCMCIA_QLOGIC) += qlogic_cs.o obj-$(CONFIG_PCMCIA_FDOMAIN) += fdomain_cs.o obj-$(CONFIG_PCMCIA_AHA152X) += aha152x_cs.o +obj-$(CONFIG_PCMCIA_NINJA_SCSI) += nsp_cs.o list-multi := qlogic_cs.o fdomain_cs.o aha152x_cs.o aha152x_cs-objs := aha152x_stub.o aha152x.o diff -u --recursive --new-file v2.4.6/linux/drivers/scsi/pcmcia/nsp_cs.c linux/drivers/scsi/pcmcia/nsp_cs.c --- v2.4.6/linux/drivers/scsi/pcmcia/nsp_cs.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/scsi/pcmcia/nsp_cs.c Wed Jul 4 11:50:38 2001 @@ -0,0 +1,1714 @@ +/*====================================================================== + + NinjaSCSI-3 / NinjaSCSI-32Bi PCMCIA SCSI hostadapter card driver + By: YOKOTA Hiroshi <yokota@netlab.is.tsukuba.ac.jp> + + Ver.2.0 Support 32bit PIO mode + Ver.1.1.2 Fix for scatter list buffer exceeds + Ver.1.1 Support scatter list + Ver.0.1 Initial version + + This software may be used and distributed according to the terms of + the GNU General Public License. + +======================================================================*/ + +/*********************************************************************** + This driver is for these PCcards. + + I-O DATA PCSC-F (Workbit NinjaSCSI-3) + "WBT", "NinjaSCSI-3", "R1.0" + I-O DATA CBSC-II (Workbit NinjaSCSI-32Bi in 16bit mode) + "IO DATA", "CBSC16 ", "1" + +***********************************************************************/ + +/* $Id: nsp_cs.c,v 1.28 2001/02/15 02:56:32 elca Exp $ */ + +#ifdef NSP_KERNEL_2_2 +#include <pcmcia/config.h> +#include <pcmcia/k_compat.h> +#endif + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/sched.h> +#include <linux/slab.h> +#include <linux/string.h> +#include <linux/timer.h> +#include <linux/ioport.h> +#include <linux/delay.h> +#include <linux/tqueue.h> +#include <linux/interrupt.h> +#include <linux/major.h> +#include <linux/blk.h> +#include <linux/stat.h> + +#include <asm/io.h> +#include <asm/irq.h> + +#include <../drivers/scsi/scsi.h> +#include <../drivers/scsi/hosts.h> +#include <../drivers/scsi/sd.h> + +#include <scsi/scsi.h> +#include <scsi/scsi_ioctl.h> + +#include <pcmcia/version.h> +#include <pcmcia/cs_types.h> +#include <pcmcia/cs.h> +#include <pcmcia/cistpl.h> +#include <pcmcia/ds.h> + +#include "nsp_cs.h" + +MODULE_AUTHOR("YOKOTA Hiroshi <yokota@netlab.is.tsukuba.ac.jp>"); +MODULE_DESCRIPTION("WorkBit NinjaSCSI-3 / NinjaSCSI-32Bi(16bit) PCMCIA SCSI host adapter module"); +MODULE_SUPPORTED_DEVICE("sd,sr,sg,st"); + +#ifdef PCMCIA_DEBUG +static int pc_debug = PCMCIA_DEBUG; +MODULE_PARM(pc_debug, "i"); +MODULE_PARM_DESC(pc_debug, "set debug level"); +static char *version = "$Id: nsp_cs.c,v 1.28 2001/02/15 02:56:32 elca Exp $"; +#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) +#else +#define DEBUG(n, args...) /* */ +#endif + +#include "nsp_io.h" + +/*====================================================================*/ + +typedef struct scsi_info_t { + dev_link_t link; + struct Scsi_Host *host; + int ndev; + dev_node_t node[8]; + int stop; + struct bus_operations *bus; +} scsi_info_t; + +static void nsp_release(u_long arg); +static int nsp_event(event_t event, int priority, + event_callback_args_t *args); +static dev_link_t *nsp_attach(void); +static void nsp_detach(dev_link_t *); +static int nsp_detect(Scsi_Host_Template * ); +static const char * nsp_info(struct Scsi_Host *); +static int nsp_queuecommand(Scsi_Cmnd *, void (* done)(Scsi_Cmnd *)); +static int nsp_abort(Scsi_Cmnd *); +static int nsp_reset(Scsi_Cmnd *, unsigned int); + + +/*----------------------------------------------------------------*/ + +#if (KERNEL_VERSION(2,4,0) > LINUX_VERSION_CODE) +#define PROC_SCSI_NSP PROC_SCSI_IBMMCA /* bad hack... */ +static struct proc_dir_entry proc_scsi_nsp = { + PROC_SCSI_NSP, 6, "nsp_cs", + S_IFDIR | S_IRUGO | S_IXUGO, 2 +}; +#endif + +/*====================================================================*/ +/* Parameters that can be set with 'insmod' */ + +static unsigned int irq_mask = 0xffff; +MODULE_PARM(irq_mask, "i"); +MODULE_PARM_DESC(irq_mask, "IRQ mask bits"); + +static int irq_list[4] = { -1 }; +MODULE_PARM(irq_list, "1-4i"); +MODULE_PARM_DESC(irq_list, "IRQ number list"); + +/*----------------------------------------------------------------*/ +/* driver state info, local to driver */ +static char nspinfo[100]; /* description */ + +/* /usr/src/linux/drivers/scsi/hosts.h */ +static Scsi_Host_Template driver_template = { +/* next: NULL,*/ +/* proc_dir: NULL,*/ +/* proc_info: NULL,*/ + name: "WorkBit NinjaSCSI-3/32Bi", + detect: nsp_detect, +/* release: NULL,*/ + info: nsp_info, +/* command: NULL,*/ + queuecommand: nsp_queuecommand, +/* eh_strategy_handler: nsp_eh_strategy,*/ +/* eh_abort_handler: nsp_eh_abort,*/ +/* eh_device_reset_handler: nsp_eh_device_reset,*/ + eh_bus_reset_handler: nsp_eh_bus_reset, +/* eh_host_reset_handler: nsp_eh_host_reset,*/ + abort: nsp_abort, + reset: nsp_reset, +/* slave_attach: NULL,*/ +/* bios_param: nsp_biosparam,*/ + can_queue: 1, + this_id: -1, + sg_tablesize: SG_ALL, + cmd_per_lun: 1, +/* present: 0,*/ +/* unchecked_isa_dma: 0,*/ + use_clustering: DISABLE_CLUSTERING, + use_new_eh_code: 0, +/* emulated: 0,*/ +}; + +static dev_link_t *dev_list = NULL; +static dev_info_t dev_info = {"nsp_cs"}; + +static nsp_hw_data nsp_data; + +/***********************************************************/ + +static int nsp_queuecommand(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) +{ +#ifdef PCMCIA_DEBUG + //unsigned int host_id = SCpnt->host->this_id; + //unsigned int base = SCpnt->host->io_port; + unsigned char target = SCpnt->target; +#endif + + DEBUG(0, __FUNCTION__ "() SCpnt=0x%p target=%d lun=%d buff=0x%p bufflen=%d use_sg=%d\n", + SCpnt, target, SCpnt->lun, SCpnt->request_buffer, SCpnt->request_bufflen, SCpnt->use_sg); + //DEBUG(0, " before CurrentSC=0x%p\n", nsp_data.CurrentSC); + + if(nsp_data.CurrentSC != NULL) { + printk(KERN_DEBUG " " __FUNCTION__ "() CurrentSC!=NULL this can't be happen\n"); + nsp_data.CurrentSC = NULL; + SCpnt->result = DID_BAD_TARGET << 16; + done(SCpnt); + return FAILED; + } + +#ifdef PCMCIA_DEBUG + show_command(SCpnt); +#endif + + SCpnt->scsi_done = done; + nsp_data.CurrentSC = SCpnt; + RESID = SCpnt->request_bufflen; + + SCpnt->SCp.Status = -1; + SCpnt->SCp.Message = -1; + SCpnt->SCp.have_data_in = IO_UNKNOWN; + SCpnt->SCp.sent_command = 0; + SCpnt->SCp.phase = PH_UNDETERMINED; + + /* setup scratch area + SCp.ptr : buffer pointer + SCp.this_residual : buffer length + SCp.buffer : next buffer + SCp.buffers_residual : left buffers in list + SCp.phase : current state of the command */ + if (SCpnt->use_sg) { + SCpnt->SCp.buffer = (struct scatterlist *) SCpnt->request_buffer; + SCpnt->SCp.ptr = SCpnt->SCp.buffer->address; + SCpnt->SCp.this_residual = SCpnt->SCp.buffer->length; + SCpnt->SCp.buffers_residual = SCpnt->use_sg - 1; + } else { + SCpnt->SCp.ptr = (char *) SCpnt->request_buffer; + SCpnt->SCp.this_residual = SCpnt->request_bufflen; + SCpnt->SCp.buffer = NULL; + SCpnt->SCp.buffers_residual = 0; + } + + if(nsphw_start_selection(SCpnt) == FALSE) { + DEBUG(0, " selection fail\n"); + nsp_data.CurrentSC = NULL; + SCpnt->result = DID_NO_CONNECT << 16; + done(SCpnt); + return FAILED; + } + + + //DEBUG(0, __FUNCTION__ "() out\n"); + return SUCCESS; +} + +/* + * setup PIO FIFO transfer mode and enable/disable to data out + */ +static void nsp_setup_fifo(unsigned int base, int enabled) +{ + unsigned char transfer_mode; + + //DEBUG(0, __FUNCTION__ "() enabled=%d\n", enabled); + + if (enabled != FALSE) { + transfer_mode = TRANSFER_GO | BRAIND; + } else { + transfer_mode = 0; + } + + transfer_mode |= nsp_data.TransferMode; + + nsp_index_write(base, TRANSFERMODE, transfer_mode); +} + +/* + * Initialize Ninja hardware + */ +static int nsphw_init(void) +{ + unsigned int base = nsp_data.BaseAddress; + int i, j; + sync_data tmp_sync = { SyncNegotiation: SYNC_NOT_YET, + SyncPeriod: 0, + SyncOffset: 0 + }; + + //DEBUG(0, __FUNCTION__ "() in\n"); + + nsp_data.ScsiClockDiv = CLOCK_40M; + nsp_data.CurrentSC = NULL; + nsp_data.FifoCount = 0; + nsp_data.TransferMode = MODE_IO8; + + /* setup sync data */ + for ( i = 0; i < N_TARGET; i++ ) { + for ( j = 0; j < N_LUN; j++ ) { + nsp_data.Sync[i][j] = tmp_sync; + } + } + + /* block all interrupts */ + nsp_write(base, IRQCONTROL, IRQCONTROL_ALLMASK); + + /* setup SCSI interface */ + nsp_write(base, IFSELECT, IF_IFSEL); + + nsp_index_write(base, SCSIIRQMODE, 0); + + nsp_index_write(base, TRANSFERMODE, MODE_IO8); + nsp_index_write(base, CLOCKDIV, nsp_data.ScsiClockDiv); + + nsp_index_write(base, PARITYCTRL, 0); + nsp_index_write(base, POINTERCLR, POINTER_CLEAR | + ACK_COUNTER_CLEAR | + REQ_COUNTER_CLEAR | + HOST_COUNTER_CLEAR); + + /* setup fifo asic */ + nsp_write(base, IFSELECT, IF_REGSEL); + nsp_index_write(base, TERMPWRCTRL, 0); + if ((nsp_index_read(base, OTHERCONTROL) & TPWR_SENSE) == 0) { + printk(KERN_INFO "nsp_cs: terminator power on\n"); + nsp_index_write(base, TERMPWRCTRL, POWER_ON); + } + + nsp_index_write(base, TIMERCOUNT, 0); + nsp_index_write(base, TIMERCOUNT, 0); /* requires 2 times!! */ + + nsp_index_write(base, SYNCREG, 0); + nsp_index_write(base, ACKWIDTH, 0); + + /* enable interrupts and ack them */ + nsp_index_write(base, SCSIIRQMODE, SCSI_PHASE_CHANGE_EI | + RESELECT_EI | + SCSI_RESET_IRQ_EI ); + nsp_write(base, IRQCONTROL, IRQCONTROL_ALLCLEAR); + + nsp_setup_fifo(base, FALSE); + + return TRUE; +} + +/* + * Start selection phase + */ +static unsigned int nsphw_start_selection(Scsi_Cmnd *SCpnt) +{ + unsigned int host_id = SCpnt->host->this_id; + unsigned int base = SCpnt->host->io_port; + unsigned char target = SCpnt->target; + int wait_count; + unsigned char phase, arbit; + + //DEBUG(0, __FUNCTION__ "()in\n"); + + + phase = nsp_index_read(base, SCSIBUSMON); + if(phase != BUSMON_BUS_FREE) { + //DEBUG(0, " bus busy\n"); + return FALSE; + } + + /* start arbitration */ + //DEBUG(0, " start arbit\n"); + SCpnt->SCp.phase = PH_ARBSTART; + nsp_index_write(base, SETARBIT, ARBIT_GO); + + wait_count = jiffies + 10 * HZ; + do { + /* XXX: what a stupid chip! */ + arbit = nsp_index_read(base, ARBITSTATUS); + //DEBUG(0, " arbit=%d, wait_count=%d\n", arbit, wait_count); + udelay(1); /* hold 1.2us */ + } while((arbit & (ARBIT_WIN | ARBIT_FAIL)) == 0 && + time_before(jiffies, wait_count)); + + if((arbit & ARBIT_WIN) == 0) { + //DEBUG(0, " arbit fail\n"); + nsp_index_write(base, SETARBIT, ARBIT_FLAG_CLEAR); + return FALSE; + } + + /* assert select line */ + //DEBUG(0, " assert SEL line\n"); + SCpnt->SCp.phase = PH_SELSTART; + udelay(3); + nsp_index_write(base, SCSIDATALATCH, (1 << host_id) | (1 << target)); + nsp_index_write(base, SCSIBUSCTRL, SCSI_SEL | SCSI_BSY | SCSI_ATN); + udelay(3); + nsp_index_write(base, SCSIBUSCTRL, SCSI_SEL | SCSI_BSY | SCSI_DATAOUT_ENB | SCSI_ATN); + nsp_index_write(base, SETARBIT, ARBIT_FLAG_CLEAR); + udelay(3); + nsp_index_write(base, SCSIBUSCTRL, SCSI_SEL | SCSI_DATAOUT_ENB | SCSI_ATN); + + /* check selection timeout */ + nsp_start_timer(SCpnt, 1000/51); + nsp_data.SelectionTimeOut = 1; + + return TRUE; +} + +struct nsp_sync_table { + unsigned int min_period; + unsigned int max_period; + unsigned int chip_period; + unsigned int ack_width; +}; + +static struct nsp_sync_table nsp_sync_table_40M[] = { + {0x0c,0x0c,0x1,0}, /* 20MB 50ns*/ + {0x19,0x19,0x3,1}, /* 10MB 100ns*/ + {0x1a,0x25,0x5,2}, /* 7.5MB 150ns*/ + {0x26,0x32,0x7,3}, /* 5MB 200ns*/ + {0x0, 0, 0, 0} +}; + +static struct nsp_sync_table nsp_sync_table_20M[] = { + {0x19,0x19,0x1,0}, /* 10MB 100ns*/ + {0x1a,0x25,0x2,0}, /* 7.5MB 150ns*/ + {0x26,0x32,0x3,1}, /* 5MB 200ns*/ + {0x0, 0, 0, 0} +}; + +/* + * setup synchronous data transfer mode + */ +static int nsp_msg(Scsi_Cmnd *SCpnt) +{ + unsigned char target = SCpnt->target; + unsigned char lun = SCpnt->lun; + sync_data *sync = &(nsp_data.Sync[target][lun]); + struct nsp_sync_table *sync_table; + unsigned int period, offset; + int i; + + + DEBUG(0, __FUNCTION__ "()\n"); + +/**!**/ + + period = sync->SyncPeriod; + offset = sync->SyncOffset; + + DEBUG(0, " period=0x%x, offset=0x%x\n", period, offset); + + if (nsp_data.ScsiClockDiv == CLOCK_20M) { + sync_table = &nsp_sync_table_20M[0]; + } else { + sync_table = &nsp_sync_table_40M[0]; + } + + for ( i = 0; sync_table->max_period != 0; i++, sync_table++) { + if ( period >= sync_table->min_period && + period <= sync_table->max_period ) { + break; + } + } + + if (period != 0 && sync_table->max_period == 0) { + /* + * No proper period/offset found + */ + DEBUG(0, " no proper period/offset\n"); + + sync->SyncPeriod = 0; + sync->SyncOffset = 0; + sync->SyncRegister = 0; + sync->AckWidth = 0; + + return FALSE; + } + + sync->SyncRegister = (sync_table->chip_period << SYNCREG_PERIOD_SHIFT) | + (offset & SYNCREG_OFFSET_MASK); + sync->AckWidth = sync_table->ack_width; + + DEBUG(0, " sync_reg=0x%x, ack_width=0x%x\n", sync->SyncRegister, sync->AckWidth); + + return TRUE; +} + + +/* + * start ninja hardware timer + */ +static void nsp_start_timer(Scsi_Cmnd *SCpnt, int time) +{ + unsigned int base = SCpnt->host->io_port; + + //DEBUG(0, __FUNCTION__ "() in SCpnt=0x%p, time=%d\n", SCpnt, time); + nsp_data.TimerCount = time; + nsp_index_write(base, TIMERCOUNT, time); +} + +/* + * wait for bus phase change + */ +static int nsp_negate_signal(Scsi_Cmnd *SCpnt, unsigned char mask, char *str) +{ + unsigned int base = SCpnt->host->io_port; + unsigned char reg; + int count, i = TRUE; + + //DEBUG(0, __FUNCTION__ "()\n"); + + count = jiffies + HZ; + + do { + reg = nsp_index_read(base, SCSIBUSMON); + if (reg == 0xff) { + break; + } + } while ((i = time_before(jiffies, count)) && (reg & mask) != 0); + + if (!i) { + printk(KERN_DEBUG __FUNCTION__ " %s signal off timeut\n", str); + } + + return 0; +} + +/* + * expect Ninja Irq + */ +static int nsp_expect_signal(Scsi_Cmnd *SCpnt, + unsigned char current_phase, + unsigned char mask) +{ + unsigned int base = SCpnt->host->io_port; + int wait_count; + unsigned char phase, i_src; + + //DEBUG(0, __FUNCTION__ "() current_phase=0x%x, mask=0x%x\n", current_phase, mask); + + wait_count = jiffies + HZ; + do { + phase = nsp_index_read(base, SCSIBUSMON); + if (phase == 0xff) { + //DEBUG(0, " ret -1\n"); + return -1; + } + i_src = nsp_read(base, IRQSTATUS); + if (i_src & IRQSTATUS_SCSI) { + //DEBUG(0, " ret 0 found scsi signal\n"); + return 0; + } + if ((phase & mask) != 0 && (phase & BUSMON_PHASE_MASK) == current_phase) { + //DEBUG(0, " ret 1 phase=0x%x\n", phase); + return 1; + } + } while(time_before(jiffies, wait_count)); + + //DEBUG(0, __FUNCTION__ " : " __FUNCTION__ " timeout\n"); + return -1; +} + +/* + * transfer SCSI message + */ +static int nsp_xfer(Scsi_Cmnd *SCpnt, int phase) +{ + unsigned int base = SCpnt->host->io_port; + char *buf = nsp_data.MsgBuffer; + int len = MIN(MSGBUF_SIZE, nsp_data.MsgLen); + int ptr; + int ret; + + //DEBUG(0, __FUNCTION__ "()\n"); +/**!**/ + for (ptr = 0; len > 0; len --, ptr ++) { + + ret = nsp_expect_signal(SCpnt, phase, BUSMON_REQ); + if (ret <= 0) { + DEBUG(0, " xfer quit\n"); + return 0; + } + + /* if last byte, negate ATN */ + if (len == 1) { + nsp_index_write(base, SCSIBUSCTRL, AUTODIRECTION | ACKENB); + } + + /* read & write message */ + if (phase & BUSMON_IO) { + //DEBUG(0, " read msg\n"); + buf[ptr] = nsp_index_read(base, SCSIDATAWITHACK); + } else { + //DEBUG(0, " write msg\n"); + nsp_index_write(base, SCSIDATAWITHACK, buf[ptr]); + } + nsp_negate_signal(SCpnt, BUSMON_ACK, "xfer<ack>"); + + } + return len; +} + +/* + * get extra SCSI data from fifo + */ +static int nsp_dataphase_bypass(Scsi_Cmnd *SCpnt) +{ + unsigned int base = SCpnt->host->io_port; + unsigned int count; + + //DEBUG(0, __FUNCTION__ "()\n"); + + if (SCpnt->SCp.have_data_in != IO_IN) { + return 0; + } + + count = nsp_fifo_count(SCpnt); + if (nsp_data.FifoCount == count) { + //DEBUG(0, " not use bypass quirk\n"); + return 0; + } + + /* + * XXX: NSP_QUIRK + * data phase skip only occures in case of SCSI_LOW_READ + */ + SCpnt->SCp.phase = PH_DATA; + nsp_pio_read(SCpnt); + nsp_setup_fifo(base, FALSE); + + DEBUG(0, " use bypass quirk\n"); + return 0; +} + +/* + * accept reselection + */ +static int nsp_reselected(Scsi_Cmnd *SCpnt) +{ + unsigned int base = SCpnt->host->io_port; + unsigned char reg; + + //DEBUG(0, __FUNCTION__ "()\n"); + + nsp_negate_signal(SCpnt, BUSMON_SEL, "reselect<SEL>"); + + nsp_nexus(SCpnt); + reg = nsp_index_read(base, SCSIBUSCTRL) & ~(SCSI_BSY | SCSI_ATN); + nsp_index_write(base, SCSIBUSCTRL, reg); + nsp_index_write(base, SCSIBUSCTRL, reg | AUTODIRECTION | ACKENB); + + return TRUE; +} + +/* + * count how many data transferd + */ +static int nsp_fifo_count(Scsi_Cmnd *SCpnt) +{ + unsigned int base = SCpnt->host->io_port; + unsigned int count; + unsigned int l, m, h; + + nsp_index_write(base, POINTERCLR, POINTER_CLEAR); + + l = (unsigned int)nsp_read(base, DATAREG); + m = (unsigned int)nsp_read(base, DATAREG); + h = (unsigned int)nsp_read(base, DATAREG); + + count = (h << 16) | (m << 8) | (l << 0); + + //DEBUG(0, __FUNCTION__ "() =0x%x\n", count); + + return count; +} + +/* fifo size */ +#define RFIFO_CRIT 64 +#define WFIFO_CRIT 64 + +/* + * read data in DATA IN phase + */ +static void nsp_pio_read(Scsi_Cmnd *SCpnt) +{ + unsigned int base = SCpnt->host->io_port; + int time_out, i; + int ocount, res; + unsigned char stat, fifo_stat; + + ocount = nsp_data.FifoCount; + + DEBUG(0, __FUNCTION__ "() in SCpnt=0x%p resid=%d ocount=%d ptr=0x%p this_residual=%d buffers=0x%p nbuf=%d\n", SCpnt, RESID, ocount, SCpnt->SCp.ptr, SCpnt->SCp.this_residual, SCpnt->SCp.buffer, SCpnt->SCp.buffers_residual); + + time_out = jiffies + 10 * HZ; + + while ((i = time_before(jiffies,time_out)) && + (SCpnt->SCp.this_residual > 0 || SCpnt->SCp.buffers_residual > 0 ) ) { + + stat = nsp_index_read(base, SCSIBUSMON); + stat &= BUSMON_PHASE_MASK; + + res = nsp_fifo_count(SCpnt) - ocount; + + //DEBUG(0, " ptr=0x%p this=0x%x ocount=0x%x res=0x%x\n", SCpnt->SCp.ptr, SCpnt->SCp.this_residual, ocount, res); + if (res == 0) { /* if some data avilable ? */ + if (stat == BUSPHASE_DATA_IN) { /* phase changed? */ + //DEBUG(0, " wait for data this=%d\n", SCpnt->SCp.this_residual); + continue; + } else { + DEBUG(0, " phase changed stat=0x%x\n", stat); + break; + } + } + + fifo_stat = nsp_read(base, FIFOSTATUS); + if ((fifo_stat & FIFOSTATUS_FULL_EMPTY) == 0 && + stat == BUSPHASE_DATA_IN) { + continue; + } + + res = MIN(res, SCpnt->SCp.this_residual); + + switch (nsp_data.TransferMode) { + case MODE_IO32: + res &= ~(BIT(1)|BIT(0)); /* align 4 */ + nsp_fifo32_read(base, SCpnt->SCp.ptr, res >> 2); + break; + case MODE_IO8: + nsp_fifo8_read (base, SCpnt->SCp.ptr, res ); + break; + default: + DEBUG(0, "unknown read mode\n"); + break; + } + + RESID -= res; + SCpnt->SCp.ptr += res; + SCpnt->SCp.this_residual -= res; + ocount += res; + //DEBUG(0, " ptr=0x%p this_residual=0x%x ocount=0x%x\n", SCpnt->SCp.ptr, SCpnt->SCp.this_residual, ocount); + + /* go to next scatter list if availavle */ + if (SCpnt->SCp.this_residual == 0 && + SCpnt->SCp.buffers_residual != 0 ) { + //DEBUG(0, " scatterlist next timeout=%d\n", time_out); + SCpnt->SCp.buffers_residual--; + SCpnt->SCp.buffer++; + SCpnt->SCp.ptr = SCpnt->SCp.buffer->address; + SCpnt->SCp.this_residual = SCpnt->SCp.buffer->length; + } + + time_out = jiffies + 10 * HZ; + } + + nsp_data.FifoCount = ocount; + + if (!i) { + printk(KERN_DEBUG __FUNCTION__ "() pio read timeout resid=%d this_residual=%d buffers_residual=%d\n", RESID, SCpnt->SCp.this_residual, SCpnt->SCp.buffers_residual); + } + DEBUG(0, " read ocount=0x%x\n", ocount); +} + +/* + * write data in DATA OUT phase + */ +static void nsp_pio_write(Scsi_Cmnd *SCpnt) +{ + unsigned int base = SCpnt->host->io_port; + int time_out, i; + unsigned int ocount, res; + unsigned char stat; + + ocount = nsp_data.FifoCount; + + DEBUG(0, __FUNCTION__ "() in fifocount=%d ptr=0x%p this_residual=%d buffers=0x%p nbuf=%d resid=0x%x\n", nsp_data.FifoCount, SCpnt->SCp.ptr, SCpnt->SCp.this_residual, SCpnt->SCp.buffer, SCpnt->SCp.buffers_residual, SCpnt->resid); + + time_out = jiffies + 10 * HZ; + + while ((i = time_before(jiffies, time_out)) && + (SCpnt->SCp.this_residual > 0 || SCpnt->SCp.buffers_residual > 0)) { + stat = nsp_index_read(base, SCSIBUSMON); + stat &= BUSMON_PHASE_MASK; + if (stat != BUSPHASE_DATA_OUT) { + DEBUG(0, " phase changed stat=0x%x\n", stat); + break; + } + + res = ocount - nsp_fifo_count(SCpnt); + if (res > 0) { /* write all data? */ + DEBUG(0, " wait for all data out. ocount=0x%x res=%d\n", ocount, res); + continue; + } + + res = MIN(SCpnt->SCp.this_residual, WFIFO_CRIT); + + //DEBUG(0, " ptr=0x%p this=0x%x res=0x%x\n", SCpnt->SCp.ptr, SCpnt->SCp.this_residual, res); + switch (nsp_data.TransferMode) { + case MODE_IO32: + res &= ~(BIT(1)|BIT(0)); /* align 4 */ + nsp_fifo32_write(base, SCpnt->SCp.ptr, res >> 2); + break; + case MODE_IO8: + nsp_fifo8_write (base, SCpnt->SCp.ptr, res ); + break; + default: + DEBUG(0, "unknown write mode\n"); + break; + } + + RESID -= res; + SCpnt->SCp.ptr += res; + SCpnt->SCp.this_residual -= res; + ocount += res; + + /* go to next scatter list if availavle */ + if (SCpnt->SCp.this_residual == 0 && + SCpnt->SCp.buffers_residual != 0 ) { + //DEBUG(0, " scatterlist next\n"); + SCpnt->SCp.buffers_residual--; + SCpnt->SCp.buffer++; + SCpnt->SCp.ptr = SCpnt->SCp.buffer->address; + SCpnt->SCp.this_residual = SCpnt->SCp.buffer->length; + } + + time_out = jiffies + 10 * HZ; + } + + nsp_data.FifoCount = ocount; + + if (!i) { + printk(KERN_DEBUG __FUNCTION__ "() pio write timeout resid=%d\n", RESID); + } + //DEBUG(0, " write ocount=%d\n", ocount); +} + +#undef RFIFO_CRIT +#undef WFIFO_CRIT + +/* + * setup synchronous/asynchronous data transfer mode + */ +static int nsp_nexus(Scsi_Cmnd *SCpnt) +{ + unsigned int base = SCpnt->host->io_port; + unsigned char target = SCpnt->target; + unsigned char lun = SCpnt->lun; + sync_data *sync = &(nsp_data.Sync[target][lun]); + + //DEBUG(0, __FUNCTION__ "() in SCpnt=0x%p\n", SCpnt); + + /* setup synch transfer registers */ + nsp_index_write(base, SYNCREG, sync->SyncRegister); + nsp_index_write(base, ACKWIDTH, sync->AckWidth); + + if (RESID % 4 != 0 || + RESID <= 256 ) { + nsp_data.TransferMode = MODE_IO8; + } else { + nsp_data.TransferMode = MODE_IO32; + } + + /* setup pdma fifo */ + nsp_setup_fifo(base, TRUE); + + /* clear ack counter */ + nsp_data.FifoCount = 0; + nsp_index_write(base, POINTERCLR, POINTER_CLEAR | + ACK_COUNTER_CLEAR | + REQ_COUNTER_CLEAR | + HOST_COUNTER_CLEAR); + + return 0; +} + +/* + * interrupt handler + */ +static void nspintr(int irq, void *dev_id, struct pt_regs *regs) +{ + unsigned int base; + unsigned char i_src, irq_phase, phase; + Scsi_Cmnd *tmpSC; + int ret, len; + unsigned char data_reg, control_reg; + + + //DEBUG(0, __FUNCTION__ "(%d) CurrentSC=0x%p\n", irq, nsp_data.CurrentSC); + + base = nsp_data.BaseAddress; + //DEBUG(0, " base=0x%x\n", base); + + /* + * interrupt check + */ + nsp_write(base, IRQCONTROL, IRQCONTROL_IRQDISABLE); + i_src = nsp_read(base, IRQSTATUS); + if (i_src == 0xff || (i_src & IRQSTATUS_MASK) == 0) { + nsp_write(base, IRQCONTROL, 0); + //DEBUG(0, " no irq\n"); + return; + } + + //DEBUG(0, " i_src=0x%x\n", i_src); + + /* XXX: IMPORTANT + * Do not read an irq_phase register if no scsi phase interrupt. + * Unless, you should lose a scsi phase interrupt. + */ + phase = nsp_index_read(base, SCSIBUSMON); + if((i_src & IRQSTATUS_SCSI) != 0) { + irq_phase = nsp_index_read(base, IRQPHASESENCE); + } else { + irq_phase = 0; + } + + //DEBUG(0, " irq_phase=0x%x\n", irq_phase); + + /* + * timer interrupt handler (scsi vs timer interrupts) + */ + //DEBUG(0, " timercount=%d\n", nsp_data.TimerCount); + if (nsp_data.TimerCount != 0) { + //DEBUG(0, " stop timer\n"); + nsp_index_write(base, TIMERCOUNT, 0); + nsp_index_write(base, TIMERCOUNT, 0); + nsp_data.TimerCount = 0; + } + + if ((i_src & IRQSTATUS_MASK) == IRQSTATUS_TIMER && + nsp_data.SelectionTimeOut == 0) { + //DEBUG(0, " timer start\n"); + nsp_write(base, IRQCONTROL, IRQCONTROL_TIMER_CLEAR); + return; + } + + nsp_write(base, IRQCONTROL, IRQCONTROL_TIMER_CLEAR | IRQCONTROL_FIFO_CLEAR); + + if (nsp_data.CurrentSC == NULL) { + printk(KERN_DEBUG __FUNCTION__ " CurrentSC==NULL irq_status=0x%x phase=0x%x irq_phase=0x%x this can't be happen\n", i_src, phase, irq_phase); + return; + } else { + tmpSC = nsp_data.CurrentSC; + } + + /* + * parse hardware SCSI irq reasons register + */ + if ((i_src & IRQSTATUS_SCSI) != 0) { + if ((irq_phase & SCSI_RESET_IRQ) != 0) { + printk(KERN_DEBUG " " __FUNCTION__ "() bus reset (power off?)\n"); + + nsp_data.CurrentSC = NULL; + tmpSC->result = DID_RESET << 16; + tmpSC->scsi_done(tmpSC); + return; + } + + if ((irq_phase & RESELECT_IRQ) != 0) { + DEBUG(0, " reselect\n"); + nsp_write(base, IRQCONTROL, IRQCONTROL_RESELECT_CLEAR); + if (nsp_reselected(tmpSC) != FALSE) { + return; + } + } + + if ((irq_phase & (PHASE_CHANGE_IRQ | LATCHED_BUS_FREE)) == 0) { + return; + } + } + + //show_phase(tmpSC); + + switch(tmpSC->SCp.phase) { + case PH_SELSTART: + if ((phase & BUSMON_BSY) == 0) { + //DEBUG(0, " selection count=%d\n", nsp_data.SelectionTimeOut); + if (nsp_data.SelectionTimeOut >= NSP_SELTIMEOUT) { + DEBUG(0, " selection time out\n"); + nsp_data.SelectionTimeOut = 0; + nsp_index_write(base, SCSIBUSCTRL, 0); + + nsp_data.CurrentSC = NULL; + tmpSC->result = DID_NO_CONNECT << 16; + tmpSC->scsi_done(tmpSC); + + return; + } + nsp_data.SelectionTimeOut += 1; + nsp_start_timer(tmpSC, 1000/51); + return; + } + + /* attention assert */ + //DEBUG(0, " attention assert\n"); + nsp_data.SelectionTimeOut = 0; + tmpSC->SCp.phase = PH_SELECTED; + nsp_index_write(base, SCSIBUSCTRL, SCSI_ATN); + udelay(1); + nsp_index_write(base, SCSIBUSCTRL, SCSI_ATN | AUTODIRECTION | ACKENB); + return; + + break; + + case PH_RESELECT: + //DEBUG(0, " phase reselect\n"); + if ((phase & BUSMON_PHASE_MASK) != BUSPHASE_MESSAGE_IN) { + + nsp_data.CurrentSC = NULL; + tmpSC->result = DID_ABORT << 16; + tmpSC->scsi_done(tmpSC); + return; + } + /* fall thru */ + default: + if (( i_src & (IRQSTATUS_SCSI | IRQSTATUS_FIFO)) == 0) { + return; + } + break; + } + + /* + * SCSI sequencer + */ + //DEBUG(0, " start scsi seq\n"); + + /* normal disconnect */ + if ((irq_phase & LATCHED_BUS_FREE) != 0) { + //DEBUG(0, " normal disconnect i_src=0x%x, phase=0x%x, irq_phase=0x%x\n", i_src, phase, irq_phase); + if ((tmpSC->SCp.Message == 0)) { /* all command complete and return status */ + nsp_data.CurrentSC = NULL; + tmpSC->result = (DID_OK << 16) | + (tmpSC->SCp.Message << 8) | + (tmpSC->SCp.Status << 0); + DEBUG(0, " command complete result=0x%x\n", tmpSC->result); + tmpSC->scsi_done(tmpSC); + return; + } + + return; + } + + + /* check unexpected bus free state */ + if (phase == 0) { + printk(KERN_DEBUG " " __FUNCTION__ " unexpected bus free. i_src=0x%x, phase=0x%x, irq_phase=0x%x\n", i_src, phase, irq_phase); + + nsp_data.CurrentSC = NULL; + tmpSC->result = DID_ERROR << 16; + tmpSC->scsi_done(tmpSC); + return; + } + + switch (phase & BUSMON_PHASE_MASK) { + case BUSPHASE_COMMAND: + DEBUG(0, " BUSPHASE_COMMAND\n"); + if ((phase & BUSMON_REQ) == 0) { + DEBUG(0, " REQ == 0\n"); + return; + } + + tmpSC->SCp.phase = PH_COMMAND; + + nsp_nexus(tmpSC); + + /* write scsi command */ + nsp_index_write(base, COMMANDCTRL, CLEAR_COMMAND_POINTER); + for (len = 0; len < COMMAND_SIZE(tmpSC->cmnd[0]); len++) { + nsp_index_write(base, COMMANDDATA, tmpSC->cmnd[len]); + } + nsp_index_write(base, COMMANDCTRL, CLEAR_COMMAND_POINTER | AUTO_COMMAND_GO); + break; + + case BUSPHASE_DATA_OUT: + DEBUG(0, " BUSPHASE_DATA_OUT\n"); + + tmpSC->SCp.phase = PH_DATA; + tmpSC->SCp.have_data_in = IO_OUT; + + nsp_pio_write(tmpSC); + + break; + + case BUSPHASE_DATA_IN: + DEBUG(0, " BUSPHASE_DATA_IN\n"); + + tmpSC->SCp.phase = PH_DATA; + tmpSC->SCp.have_data_in = IO_IN; + + nsp_pio_read(tmpSC); + + break; + + case BUSPHASE_STATUS: + nsp_dataphase_bypass(tmpSC); + DEBUG(0, " BUSPHASE_STATUS\n"); + + tmpSC->SCp.phase = PH_STATUS; + + tmpSC->SCp.Status = nsp_index_read(base, SCSIDATAWITHACK); + //DEBUG(0, " message=0x%x status=0x%x\n", tmpSC->SCp.Message, tmpSC->SCp.Status); + + break; + + case BUSPHASE_MESSAGE_OUT: + DEBUG(0, " BUSPHASE_MESSAGE_OUT\n"); + if ((phase & BUSMON_REQ) == 0) { + goto timer_out; + } + + tmpSC->SCp.phase = PH_MSG_OUT; + + /* + * XXX: NSP QUIRK + * NSP invoke interrupts only in the case of scsi phase changes, + * therefore we should poll the scsi phase here to catch + * the next "msg out" if exists (no scsi phase changes). + */ + ret = 16; + len = 0; + + nsp_msg(tmpSC); + + nsp_data.MsgBuffer[len] = IDENTIFY(TRUE, tmpSC->lun); len++; + nsp_data.MsgLen = len; + + do { + DEBUG(0, " msgout loop\n"); + + if (nsp_xfer(tmpSC, BUSPHASE_MESSAGE_OUT)) { + printk(KERN_DEBUG " " __FUNCTION__ " msgout: xfer short\n"); + } + + /* catch a next signal */ + ret = nsp_expect_signal(tmpSC, BUSPHASE_MESSAGE_OUT, BUSMON_REQ); + } while (ret > 0 && len-- > 0); + + break; + + case BUSPHASE_MESSAGE_IN: + nsp_dataphase_bypass(tmpSC); + DEBUG(0, " BUSPHASE_MESSAGE_IN\n"); + if ((phase & BUSMON_REQ) == 0) { + goto timer_out; + } + + tmpSC->SCp.phase = PH_MSG_IN; + + /* + * XXX: NSP QUIRK + * NSP invoke interrupts only in the case of scsi phase changes, + * therefore we should poll the scsi phase here to catch + * the next "msg in" if exists (no scsi phase changes). + */ + ret = 16; + len = 0; + + do { + //DEBUG(0, " msgin loop\n"); + /* read data */ + data_reg = nsp_index_read(base, SCSIDATAIN); + + /* assert ACK */ + control_reg = nsp_index_read(base, SCSIBUSCTRL); + control_reg |= SCSI_ACK; + nsp_index_write(base, SCSIBUSCTRL, control_reg); + nsp_negate_signal(tmpSC, BUSMON_REQ, "msgin<REQ>"); + + nsp_data.MsgBuffer[len] = data_reg; len++; + DEBUG(0, " msg=0x%x\n", data_reg); + + /* deassert ACK */ + control_reg = nsp_index_read(base, SCSIBUSCTRL); + control_reg &= ~SCSI_ACK; + nsp_index_write(base, SCSIBUSCTRL, control_reg); + + /* catch a next signal */ + ret = nsp_expect_signal(tmpSC, BUSPHASE_MESSAGE_IN, BUSMON_REQ); + } while (ret > 0 && MSGBUF_SIZE > len); + + nsp_data.MsgLen = len; + tmpSC->SCp.Message = nsp_data.MsgBuffer[len-1]; + + //DEBUG(0, " message=0x%x len=%d\n", tmpSC->SCp.Message, nsp_data.MsgLen); + break; + + case BUSPHASE_SELECT: + default: + DEBUG(0, " BUSPHASE other\n"); + + break; + } + + //DEBUG(0, __FUNCTION__ "() out\n"); + return; + +timer_out: + nsp_start_timer(tmpSC, 1000/102); + return; +} + +#ifdef DBG_SHOWCOMMAND +#include "nsp_debug.c" +#endif /* DBG_SHOWCOMMAND */ + +/*====================================================================*/ +static void cs_error(client_handle_t handle, int func, int ret) +{ + error_info_t err = { func, ret }; + CardServices(ReportError, handle, &err); +} + +/*====================================================================== + nsp_attach() creates an "instance" of the driver, allocating + local data structures for one device. The device is registered + with Card Services. + + The dev_link structure is initialized, but we don't actually + configure the card at this point -- we wait until we receive a + card insertion event. +======================================================================*/ +static dev_link_t *nsp_attach(void) +{ + scsi_info_t *info; + client_reg_t client_reg; + dev_link_t *link; + int ret, i; + + DEBUG(0, __FUNCTION__ "()\n"); + + /* Create new SCSI device */ + info = kmalloc(sizeof(*info), GFP_KERNEL); + if (!info) return NULL; + memset(info, 0, sizeof(*info)); + link = &info->link; + link->priv = info; + + /* Initialize the dev_link_t structure */ + link->release.function = &nsp_release; + link->release.data = (u_long)link; + + /* The io structure describes IO port mapping */ + link->io.NumPorts1 = 0x10; + link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; + link->io.IOAddrLines = 10; /* not used */ + + /* Interrupt setup */ + link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT; + link->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_LEVEL_ID; + if (irq_list[0] == -1) { + link->irq.IRQInfo2 = irq_mask; + } else { + for (i = 0; i < 4; i++) { + link->irq.IRQInfo2 |= 1 << irq_list[i]; + } + } + link->irq.Handler = &nspintr; + + /* General socket configuration */ + link->conf.Attributes = CONF_ENABLE_IRQ; + link->conf.Vcc = 50; + link->conf.IntType = INT_MEMORY_AND_IO; + link->conf.Present = PRESENT_OPTION; + + + /* Register with Card Services */ + link->next = dev_list; + dev_list = link; + client_reg.dev_info = &dev_info; + client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; + client_reg.EventMask = + CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | + CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | + CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME ; + client_reg.event_handler = &nsp_event; + client_reg.Version = 0x0210; + client_reg.event_callback_args.client_data = link; + ret = CardServices(RegisterClient, &link->handle, &client_reg); + if (ret != CS_SUCCESS) { + cs_error(link->handle, RegisterClient, ret); + nsp_detach(link); + return NULL; + } + + return link; +} /* nsp_attach */ + + +/*====================================================================== + This deletes a driver "instance". The device is de-registered + with Card Services. If it has been released, all local data + structures are freed. Otherwise, the structures will be freed + when the device is released. +======================================================================*/ +static void nsp_detach(dev_link_t *link) +{ + dev_link_t **linkp; + + DEBUG(0, __FUNCTION__ "(0x%p)\n", link); + + /* Locate device structure */ + for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) { + if (*linkp == link) { + break; + } + } + if (*linkp == NULL) { + return; + } + + del_timer(&link->release); + if (link->state & DEV_CONFIG) { + nsp_release((u_long)link); + if (link->state & DEV_STALE_CONFIG) { + link->state |= DEV_STALE_LINK; + return; + } + } + + /* Break the link with Card Services */ + if (link->handle) { + CardServices(DeregisterClient, link->handle); + } + + /* Unlink device structure, free bits */ + *linkp = link->next; + kfree(link->priv); + +} /* nsp_detach */ + + +/*====================================================================== + nsp_config() is scheduled to run after a CARD_INSERTION event + is received, to configure the PCMCIA socket, and to make the + ethernet device available to the system. +======================================================================*/ +#define CS_CHECK(fn, args...) \ +while ((last_ret=CardServices(last_fn=(fn),args))!=0) goto cs_failed +#define CFG_CHECK(fn, args...) \ +if (CardServices(fn, args) != 0) goto next_entry +/*====================================================================*/ + +static void nsp_config(dev_link_t *link) +{ + client_handle_t handle = link->handle; + scsi_info_t *info = link->priv; + tuple_t tuple; + cisparse_t parse; + int i, last_ret, last_fn; + u_char tuple_data[64]; + config_info_t conf; + Scsi_Device *dev; + dev_node_t **tail, *node; + struct Scsi_Host *host; + + DEBUG(0, __FUNCTION__ "() in\n"); + + tuple.DesiredTuple = CISTPL_CONFIG; + tuple.Attributes = 0; + tuple.TupleData = tuple_data; + tuple.TupleDataMax = sizeof(tuple_data); + tuple.TupleOffset = 0; + CS_CHECK(GetFirstTuple, handle, &tuple); + CS_CHECK(GetTupleData, handle, &tuple); + CS_CHECK(ParseTuple, handle, &tuple, &parse); + link->conf.ConfigBase = parse.config.base; + link->conf.Present = parse.config.rmask[0]; + + /* Configure card */ + driver_template.module = &__this_module; + link->state |= DEV_CONFIG; + + /* Look up the current Vcc */ + CS_CHECK(GetConfigurationInfo, handle, &conf); + link->conf.Vcc = conf.Vcc; + + tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; + CS_CHECK(GetFirstTuple, handle, &tuple); + while (1) { + CFG_CHECK(GetTupleData, handle, &tuple); + CFG_CHECK(ParseTuple, handle, &tuple, &parse); + link->conf.ConfigIndex = parse.cftable_entry.index; + link->io.BasePort1 = parse.cftable_entry.io.win[0].base; + i = CardServices(RequestIO, handle, &link->io); + if (i == CS_SUCCESS) { + break; + } + next_entry: + DEBUG(0, __FUNCTION__ " next\n"); + CS_CHECK(GetNextTuple, handle, &tuple); + } + + CS_CHECK(RequestIRQ, handle, &link->irq); + CS_CHECK(RequestConfiguration, handle, &link->conf); + + /* A bad hack... */ + release_region(link->io.BasePort1, link->io.NumPorts1); + + /* Set port and IRQ */ + nsp_data.BaseAddress = link->io.BasePort1; + nsp_data.NumAddress = link->io.NumPorts1; + nsp_data.IrqNumber = link->irq.AssignedIRQ; + + DEBUG(0, __FUNCTION__ " I/O[0x%x+0x%x] IRQ %d\n", + nsp_data.BaseAddress, nsp_data.NumAddress, nsp_data.IrqNumber); + + if(nsphw_init() == FALSE) { + goto cs_failed; + } + + scsi_register_module(MODULE_SCSI_HA, &driver_template); + + DEBUG(0, "GET_SCSI_INFO\n"); + tail = &link->dev; + info->ndev = 0; + for (host = scsi_hostlist; host != NULL; host = host->next) { + if (host->hostt == &driver_template) { + for (dev = host->host_queue; dev != NULL; dev = dev->next) { + u_long arg[2], id; + kernel_scsi_ioctl(dev, SCSI_IOCTL_GET_IDLUN, arg); + id = (arg[0]&0x0f) + ((arg[0]>>4)&0xf0) + + ((arg[0]>>8)&0xf00) + ((arg[0]>>12)&0xf000); + node = &info->node[info->ndev]; + node->minor = 0; + switch (dev->type) { + case TYPE_TAPE: + node->major = SCSI_TAPE_MAJOR; + sprintf(node->dev_name, "st#%04lx", id); + break; + case TYPE_DISK: + case TYPE_MOD: + node->major = SCSI_DISK0_MAJOR; + sprintf(node->dev_name, "sd#%04lx", id); + break; + case TYPE_ROM: + case TYPE_WORM: + node->major = SCSI_CDROM_MAJOR; + sprintf(node->dev_name, "sr#%04lx", id); + break; + default: + node->major = SCSI_GENERIC_MAJOR; + sprintf(node->dev_name, "sg#%04lx", id); + break; + } + *tail = node; tail = &node->next; + info->ndev++; + info->host = dev->host; + } + } + } + *tail = NULL; + if (info->ndev == 0) { + printk(KERN_INFO "nsp_cs: no SCSI devices found\n"); + } + + /* Finally, report what we've done */ + printk(KERN_INFO "nsp_cs: index 0x%02x: Vcc %d.%d", + link->conf.ConfigIndex, + link->conf.Vcc/10, link->conf.Vcc%10); + if (link->conf.Vpp1) { + printk(", Vpp %d.%d", link->conf.Vpp1/10, link->conf.Vpp1%10); + } + if (link->conf.Attributes & CONF_ENABLE_IRQ) { + printk(", irq %d", link->irq.AssignedIRQ); + } + if (link->io.NumPorts1) { + printk(", io 0x%04x-0x%04x", link->io.BasePort1, + link->io.BasePort1+link->io.NumPorts1-1); + } + printk("\n"); + + link->state &= ~DEV_CONFIG_PENDING; + return; + +cs_failed: + cs_error(link->handle, last_fn, last_ret); + nsp_release((u_long)link); + return; + +} /* nsp_config */ +#undef CS_CHECK +#undef CFG_CHECK + +/*====================================================================== + After a card is removed, nsp_release() will unregister the net + device, and release the PCMCIA configuration. If the device is + still open, this will be postponed until it is closed. +======================================================================*/ +static void nsp_release(u_long arg) +{ + dev_link_t *link = (dev_link_t *)arg; + + DEBUG(0, __FUNCTION__ "(0x%p)\n", link); + + /* + * If the device is currently in use, we won't release until it + * is actually closed. + */ + if (link->open) { + DEBUG(1, "nsp_cs: release postponed, '%s' still open\n", + link->dev->dev_name); + link->state |= DEV_STALE_CONFIG; + return; + } + + /* Unlink the device chain */ + scsi_unregister_module(MODULE_SCSI_HA, &driver_template); + link->dev = NULL; + + if (link->win) { + CardServices(ReleaseWindow, link->win); + } + CardServices(ReleaseConfiguration, link->handle); + if (link->io.NumPorts1) { + CardServices(ReleaseIO, link->handle, &link->io); + } + if (link->irq.AssignedIRQ) { + CardServices(ReleaseIRQ, link->handle, &link->irq); + } + link->state &= ~DEV_CONFIG; + + if (link->state & DEV_STALE_LINK) { + nsp_detach(link); + } +} /* nsp_release */ + +/*====================================================================== + + The card status event handler. Mostly, this schedules other + stuff to run after an event is received. A CARD_REMOVAL event + also sets some flags to discourage the net drivers from trying + to talk to the card any more. + + When a CARD_REMOVAL event is received, we immediately set a flag + to block future accesses to this device. All the functions that + actually access the device should check this flag to make sure + the card is still present. + +======================================================================*/ +static int nsp_event(event_t event, + int priority, + event_callback_args_t *args) +{ + dev_link_t *link = args->client_data; + scsi_info_t *info = link->priv; + + DEBUG(1, __FUNCTION__ "(0x%06x)\n", event); + + switch (event) { + case CS_EVENT_CARD_REMOVAL: + DEBUG(0, " event: remove\n"); + link->state &= ~DEV_PRESENT; + if (link->state & DEV_CONFIG) { + ((scsi_info_t *)link->priv)->stop = 1; + mod_timer(&link->release, jiffies + HZ/20); + } + break; + + case CS_EVENT_CARD_INSERTION: + DEBUG(0, " event: insert\n"); + link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; + info->bus = args->bus; + nsp_config(link); + break; + + case CS_EVENT_PM_SUSPEND: + link->state |= DEV_SUSPEND; + /* Fall through... */ + case CS_EVENT_RESET_PHYSICAL: + /* Mark the device as stopped, to block IO until later */ + info->stop = 1; + if (link->state & DEV_CONFIG) { + CardServices(ReleaseConfiguration, link->handle); + } + break; + + case CS_EVENT_PM_RESUME: + link->state &= ~DEV_SUSPEND; + /* Fall through... */ + case CS_EVENT_CARD_RESET: + DEBUG(0, " event: reset\n"); + if (link->state & DEV_CONFIG) { + Scsi_Cmnd tmp; + + CardServices(RequestConfiguration, link->handle, &link->conf); + tmp.host = info->host; + nsp_reset(&tmp, 0); + } + info->stop = 0; + /* restart IO */ + nsphw_init(); + break; + + default: + DEBUG(0, " event: unknown\n"); + break; + } + DEBUG(0, __FUNCTION__ " end\n"); + return 0; +} /* nsp_event */ + +/*----------------------------------------------------------------*/ +/* look for ninja3 card and init if found */ +/*----------------------------------------------------------------*/ +static int nsp_detect(Scsi_Host_Template *sht) +{ + struct Scsi_Host *host; /* registered host structure */ + + DEBUG(0, __FUNCTION__ " this_id=%d\n", sht->this_id); + +#if (KERNEL_VERSION(2,3,99) > LINUX_VERSION_CODE) + sht->proc_dir = &proc_scsi_nsp; /* kernel 2.2 */ +#else + sht->proc_name = "nsp_cs"; /* kernel 2.4 */ +#endif + + sht->this_id = SCSI_INITIATOR_ID; + + request_region(nsp_data.BaseAddress, nsp_data.NumAddress,"nsp_cs"); + host = scsi_register(sht, 0); + host->io_port = nsp_data.BaseAddress; + host->unique_id = nsp_data.BaseAddress; + host->n_io_port = nsp_data.NumAddress; + host->irq = nsp_data.IrqNumber; + host->dma_channel = -1; + + sprintf(nspinfo, +/* Buffer size is 100 bytes */ +/* 0 1 2 3 4 5 6 7 8 9 0*/ +/* 01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890*/ + "NinjaSCSI-3/32Bi Driver version 2.0, I/O 0x%04lx-0x%04lx IRQ %2d", + host->io_port, host->io_port + host->n_io_port, + host->irq); + sht->name = nspinfo; + + DEBUG(0, __FUNCTION__ " end\n"); + + return 1; /* detect done. */ +} + + +/*----------------------------------------------------------------*/ +/* return info string */ +/*----------------------------------------------------------------*/ +static const char *nsp_info(struct Scsi_Host *host) +{ + return nspinfo; +} + +static int nsp_reset(Scsi_Cmnd *SCpnt, unsigned int why) +{ + DEBUG(0, __FUNCTION__ "() SCpnt=0x%p why=%d\n", SCpnt, why); + + return nsp_eh_bus_reset(SCpnt); +} + +static int nsp_abort(Scsi_Cmnd *SCpnt) +{ + DEBUG(0, __FUNCTION__ "() SCpnt=0x%p\n", SCpnt); + return FAILED; +} + +/*static int nsp_eh_strategy(struct Scsi_Host *Shost) +{ +} +static int nsp_eh_abort(Scsi_Cmnd * cmd) +{ + DEBUG(0, __FUNCTION__"() SCpnt\n"); +} + +static nsp_eh_device_reset(Scsi_Cmnd *) +{ +} +*/ +static int nsp_eh_bus_reset(Scsi_Cmnd *SCpnt) +{ + unsigned int base = SCpnt->host->io_port; + int i; + + DEBUG(0, __FUNCTION__ "() SCpnt=0x%p\n", SCpnt); + + nsp_write(base, IRQCONTROL, IRQCONTROL_ALLMASK); + + nsp_index_write(base, SCSIBUSCTRL, SCSI_RST); + mdelay(100); /* 100ms */ + nsp_index_write(base, SCSIBUSCTRL, 0); + for(i = 0; i < 5; i++) { + (void) nsp_index_read(base, IRQPHASESENCE); /* dummy read */ + } + + nsp_write(base, IRQCONTROL, IRQCONTROL_ALLCLEAR); + + return 0; +} +/* +static nsp_eh_host_reset(Scsi_Cmnd *) +{ +}*/ + +/*======================================================================* + * module entry point + *====================================================================*/ +static int __init nsp_init(void) +{ + servinfo_t serv; + + DEBUG(0, __FUNCTION__ "() in\n"); + DEBUG(0, "%s\n", version); + CardServices(GetCardServicesInfo, &serv); + if (serv.Revision != CS_RELEASE_CODE) { + printk(KERN_DEBUG "nsp_cs: Card Services release " + "does not match!\n"); + return -1; + } + register_pcmcia_driver(&dev_info, &nsp_attach, &nsp_detach); + + DEBUG(0, __FUNCTION__ "() out\n"); + return 0; +} + + +static void __exit nsp_cleanup(void) +{ + DEBUG(0, "nsp_cs: unloading\n"); + unregister_pcmcia_driver(&dev_info); + while (dev_list != NULL) { + if (dev_list->state & DEV_CONFIG) { + nsp_release((u_long)dev_list); + } + nsp_detach(dev_list); + } +} + +module_init(nsp_init); +module_exit(nsp_cleanup); + +/* + * + * + */ + +/* end */ diff -u --recursive --new-file v2.4.6/linux/drivers/scsi/pcmcia/nsp_cs.h linux/drivers/scsi/pcmcia/nsp_cs.h --- v2.4.6/linux/drivers/scsi/pcmcia/nsp_cs.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/scsi/pcmcia/nsp_cs.h Wed Jul 4 11:50:38 2001 @@ -0,0 +1,302 @@ +/*=======================================================/ + Header file for nsp_cs.c + By: YOKOTA Hiroshi <yokota@netlab.is.tsukuba.ac.jp> + + Ver.1.0 : Cut unused lines. + Ver 0.1 : Initial version. + + This software may be used and distributed according to the terms of + the GNU General Public License. + +=========================================================*/ + +/* $Id: nsp_cs.h,v 1.18 2001/02/09 04:42:19 elca Exp $ */ + +#ifndef __nsp_cs__ +#define __nsp_cs__ + +/* for debugging */ +/* +#define DBG +#define DBG_PRINT +#define DBG_SHOWCOMMAND +#define PCMCIA_DEBUG 9 +*/ + +/* +#define static +#define inline +*/ + +/************************************ + * Some useful macros... + */ +#define Number(arr) ((int) (sizeof(arr) / sizeof(arr[0]))) +#define BIT(x) (1<<(x)) +#define MIN(a,b) ((a) > (b) ? (b) : (a)) + +/* SCSI initiator must be 7 */ +#define SCSI_INITIATOR_ID 7 + +/* base register */ +#define IRQCONTROL 0x00 +# define IRQCONTROL_RESELECT_CLEAR BIT(0) +# define IRQCONTROL_PHASE_CHANGE_CLEAR BIT(1) +# define IRQCONTROL_TIMER_CLEAR BIT(2) +# define IRQCONTROL_FIFO_CLEAR BIT(3) +# define IRQCONTROL_ALLMASK 0xff +# define IRQCONTROL_ALLCLEAR 0x0f +# define IRQCONTROL_IRQDISABLE 0xf0 + +#define IRQSTATUS 0x00 +# define IRQSTATUS_SCSI BIT(0) +# define IRQSTATUS_TIMER BIT(2) +# define IRQSTATUS_FIFO BIT(3) +# define IRQSTATUS_MASK 0x0f + +#define IFSELECT 0x01 +# define IF_IFSEL BIT(0) +# define IF_REGSEL BIT(2) + +#define FIFOSTATUS 0x01 +# define FIFOSTATUS_CHIP_REVISION 0x0f +# define FIFOSTATUS_CHIP_ID 0x70 +# define FIFOSTATUS_FULL_EMPTY 0x80 + +#define INDEXREG 0x02 +#define DATAREG 0x03 +#define FIFODATA 0x04 +#define FIFODATA1 0x05 +#define FIFODATA2 0x06 +#define FIFODATA3 0x07 + +/* indexed register */ +#define EXTBUSCTRL 0x10 + +#define CLOCKDIV 0x11 +# define CLOCK_40M 0x02 +# define CLOCK_20M 0x01 + +#define TERMPWRCTRL 0x13 +# define POWER_ON BIT(0) + +#define SCSIIRQMODE 0x15 +# define SCSI_PHASE_CHANGE_EI BIT(0) +# define RESELECT_EI BIT(4) +# define FIFO_IRQ_EI BIT(5) +# define SCSI_RESET_IRQ_EI BIT(6) + +#define IRQPHASESENCE 0x16 +# define LATCHED_MSG BIT(0) +# define LATCHED_IO BIT(1) +# define LATCHED_CD BIT(2) +# define LATCHED_BUS_FREE BIT(3) +# define PHASE_CHANGE_IRQ BIT(4) +# define RESELECT_IRQ BIT(5) +# define FIFO_IRQ BIT(6) +# define SCSI_RESET_IRQ BIT(7) + +#define TIMERCOUNT 0x17 + +#define SCSIBUSCTRL 0x18 +# define SCSI_SEL BIT(0) +# define SCSI_RST BIT(1) +# define SCSI_DATAOUT_ENB BIT(2) +# define SCSI_ATN BIT(3) +# define SCSI_ACK BIT(4) +# define SCSI_BSY BIT(5) +# define AUTODIRECTION BIT(6) +# define ACKENB BIT(7) + +#define SCSIBUSMON 0x19 + +#define SETARBIT 0x1A +# define ARBIT_GO BIT(0) +# define ARBIT_FLAG_CLEAR BIT(1) + +#define ARBITSTATUS 0x1A +/*# define ARBIT_GO BIT(0)*/ +# define ARBIT_WIN BIT(1) +# define ARBIT_FAIL BIT(2) +# define RESELECT_FLAG BIT(3) + +#define PARITYCTRL 0x1B /* W */ +#define PARITYSTATUS 0x1B /* R */ + +#define COMMANDCTRL 0x1C /* W */ +# define CLEAR_COMMAND_POINTER BIT(0) +# define AUTO_COMMAND_GO BIT(1) + +#define RESELECTID 0x1C /* R */ +#define COMMANDDATA 0x1D + +#define POINTERCLR 0x1E /* W */ +# define POINTER_CLEAR BIT(0) +# define ACK_COUNTER_CLEAR BIT(1) +# define REQ_COUNTER_CLEAR BIT(2) +# define HOST_COUNTER_CLEAR BIT(3) +# define READ_SOURCE 0x30 + +#define TRANSFERCOUNT 0x1E /* R */ + +#define TRANSFERMODE 0x20 +# define MODE_MEM8 BIT(0) +# define MODE_MEM32 BIT(1) +# define MODE_ADR24 BIT(2) +# define MODE_ADR32 BIT(3) +# define MODE_IO8 BIT(4) +# define MODE_IO32 BIT(5) +# define TRANSFER_GO BIT(6) +# define BRAIND BIT(7) + +#define SYNCREG 0x21 +# define SYNCREG_OFFSET_MASK 0x0f +# define SYNCREG_PERIOD_MASK 0xf0 +# define SYNCREG_PERIOD_SHIFT 4 + +#define SCSIDATALATCH 0x22 +#define SCSIDATAIN 0x22 +#define SCSIDATAWITHACK 0x23 +#define SCAMCONTROL 0x24 +#define SCAMSTATUS 0x24 +#define SCAMDATA 0x25 + +#define OTHERCONTROL 0x26 +# define TPL_ROM_WRITE_EN BIT(0) +# define TPWR_OUT BIT(1) +# define TPWR_SENSE BIT(2) +# define RA8_CONTROL BIT(3) + +#define ACKWIDTH 0x27 +#define CLRTESTPNT 0x28 +#define ACKCNTLD 0x29 +#define REQCNTLD 0x2A +#define HSTCNTLD 0x2B +#define CHECKSUM 0x2C + +/* + * Input status bit definitions. + */ +#define S_ATN 0x80 /**/ +#define S_SELECT 0x40 /**/ +#define S_REQUEST 0x20 /* Request line from SCSI bus*/ +#define S_ACK 0x10 /* Acknowlege line from SCSI bus*/ +#define S_BUSY 0x08 /* Busy line from SCSI bus*/ +#define S_CD 0x04 /* Command/Data line from SCSI bus*/ +#define S_IO 0x02 /* Input/Output line from SCSI bus*/ +#define S_MESSAGE 0x01 /* Message line from SCSI bus*/ + +/* + * Useful Bus Monitor status combinations. + */ +#define BUSMON_SEL S_SELECT +#define BUSMON_BSY S_BUSY +#define BUSMON_REQ S_REQUEST +#define BUSMON_IO S_IO +#define BUSMON_ACK S_ACK +#define BUSMON_BUS_FREE 0 +#define BUSMON_COMMAND ( S_BUSY | S_CD | S_REQUEST ) +#define BUSMON_MESSAGE_IN ( S_BUSY | S_MESSAGE | S_IO | S_CD | S_REQUEST ) +#define BUSMON_MESSAGE_OUT ( S_BUSY | S_MESSAGE | S_CD | S_REQUEST ) +#define BUSMON_DATA_IN ( S_BUSY | S_IO | S_REQUEST ) +#define BUSMON_DATA_OUT ( S_BUSY | S_REQUEST ) +#define BUSMON_STATUS ( S_BUSY | S_IO | S_CD | S_REQUEST ) +#define BUSMON_RESELECT ( S_SELECT | S_IO ) +#define BUSMON_PHASE_MASK ( S_SELECT | S_CD | S_MESSAGE | S_IO ) + +#define BUSPHASE_COMMAND ( BUSMON_COMMAND & BUSMON_PHASE_MASK ) +#define BUSPHASE_MESSAGE_IN ( BUSMON_MESSAGE_IN & BUSMON_PHASE_MASK ) +#define BUSPHASE_MESSAGE_OUT ( BUSMON_MESSAGE_OUT & BUSMON_PHASE_MASK ) +#define BUSPHASE_DATA_IN ( BUSMON_DATA_IN & BUSMON_PHASE_MASK ) +#define BUSPHASE_DATA_OUT ( BUSMON_DATA_OUT & BUSMON_PHASE_MASK ) +#define BUSPHASE_STATUS ( BUSMON_STATUS & BUSMON_PHASE_MASK ) +#define BUSPHASE_SELECT ( S_SELECT | S_IO ) + +/* synchronous transfer negotiation data */ +typedef struct _sync_data { + unsigned int SyncNegotiation; +#define SYNC_NOT_YET 0 +#define SYNC_OK 1 +#define SYNC_NG 2 + + unsigned int SyncPeriod; + unsigned int SyncOffset; + unsigned char SyncRegister; + unsigned char AckWidth; +} sync_data; + +typedef struct _nsp_data { + unsigned int BaseAddress; + unsigned int NumAddress; + unsigned int IrqNumber; + + unsigned char ScsiClockDiv; + + unsigned char TransferMode; + + int TimerCount; + int SelectionTimeOut; + Scsi_Cmnd *CurrentSC; + + int FifoCount; +#if (KERNEL_VERSION(2,4,0) > LINUX_VERSION_CODE) + int Residual; +#define RESID nsp_data.Residual +#else +#define RESID SCpnt->resid +#endif + +#define MSGBUF_SIZE 20 + unsigned char MsgBuffer[MSGBUF_SIZE]; + int MsgLen; + +#define N_TARGET 8 +#define N_LUN 8 + sync_data Sync[N_TARGET][N_LUN]; +} nsp_hw_data; + + +static unsigned int nsphw_start_selection(Scsi_Cmnd *SCpnt); +static void nsp_start_timer(Scsi_Cmnd *SCpnt, int time); + +static int nsp_eh_bus_reset(Scsi_Cmnd *SCpnt); + +static int nsp_fifo_count(Scsi_Cmnd *SCpnt); +static void nsp_pio_read(Scsi_Cmnd *SCpnt); +static int nsp_nexus(Scsi_Cmnd *SCpnt); + +#ifdef PCMCIA_DEBUG +# ifdef DBG_SHOWCOMMAND +static void show_command(Scsi_Cmnd *ptr); +static void show_phase(Scsi_Cmnd *SCpnt); +static void show_busphase(unsigned char stat); +# endif /* DBG_SHOWCOMMAND */ +#endif + +/* + * SCSI phase + */ +enum _scsi_phase { + PH_UNDETERMINED, + PH_ARBSTART, + PH_SELSTART, + PH_SELECTED, + PH_COMMAND, + PH_DATA, + PH_STATUS, + PH_MSG_IN, + PH_MSG_OUT, + PH_DISCONNECT, + PH_RESELECT +}; + +enum _data_in_out { + IO_UNKNOWN, + IO_IN, + IO_OUT +}; + + +#define NSP_SELTIMEOUT 200 + +#endif /*__nsp_cs__*/ diff -u --recursive --new-file v2.4.6/linux/drivers/scsi/pcmcia/nsp_debug.c linux/drivers/scsi/pcmcia/nsp_debug.c --- v2.4.6/linux/drivers/scsi/pcmcia/nsp_debug.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/scsi/pcmcia/nsp_debug.c Wed Jul 4 11:50:38 2001 @@ -0,0 +1,195 @@ +/*======================================================================== + Debug routines for nsp_cs + By: YOKOTA Hiroshi <yokota@netlab.is.tsukuba.ac.jp> + + This software may be used and distributed according to the terms of + the GNU General Public License. +=========================================================================*/ + +/* $Id: nsp_debug.c,v 1.5 2001/02/08 08:08:58 elca Exp $ */ + +/* + * Show the command data of a command + */ +static const char unknown[] = "UNKNOWN"; + +static const char * group_0_commands[] = { +/* 00-03 */ "Test Unit Ready", "Rezero Unit", unknown, "Request Sense", +/* 04-07 */ "Format Unit", "Read Block Limits", unknown, "Reasssign Blocks", +/* 08-0d */ "Read (6)", unknown, "Write (6)", "Seek (6)", unknown, unknown, +/* 0e-12 */ unknown, "Read Reverse", "Write Filemarks", "Space", "Inquiry", +/* 13-16 */ unknown, "Recover Buffered Data", "Mode Select", "Reserve", +/* 17-1b */ "Release", "Copy", "Erase", "Mode Sense", "Start/Stop Unit", +/* 1c-1d */ "Receive Diagnostic", "Send Diagnostic", +/* 1e-1f */ "Prevent/Allow Medium Removal", unknown, +}; + + +static const char *group_1_commands[] = { +/* 20-22 */ unknown, unknown, unknown, +/* 23-28 */ unknown, unknown, "Read Capacity", unknown, unknown, "Read (10)", +/* 29-2d */ unknown, "Write (10)", "Seek (10)", unknown, unknown, +/* 2e-31 */ "Write Verify","Verify", "Search High", "Search Equal", +/* 32-34 */ "Search Low", "Set Limits", "Prefetch or Read Position", +/* 35-37 */ "Synchronize Cache","Lock/Unlock Cache", "Read Defect Data", +/* 38-3c */ "Medium Scan", "Compare","Copy Verify", "Write Buffer", "Read Buffer", +/* 3d-3f */ "Update Block", "Read Long", "Write Long", +}; + + +static const char *group_2_commands[] = { +/* 40-41 */ "Change Definition", "Write Same", +/* 42-48 */ "Read Sub-Ch(cd)", "Read TOC", "Read Header(cd)", "Play Audio(cd)", unknown, "Play Audio MSF(cd)", "Play Audio Track/Index(cd)", +/* 49-4f */ "Play Track Relative(10)(cd)", unknown, "Pause/Resume(cd)", "Log Select", "Log Sense", unknown, unknown, +/* 50-55 */ unknown, unknown, unknown, unknown, unknown, "Mode Select (10)", +/* 56-5b */ unknown, unknown, unknown, unknown, "Mode Sense (10)", unknown, +/* 5c-5f */ unknown, unknown, unknown, +}; + +#define group(opcode) (((opcode) >> 5) & 7) + +#define RESERVED_GROUP 0 +#define VENDOR_GROUP 1 +#define NOTEXT_GROUP 2 + +static const char **commands[] = { + group_0_commands, group_1_commands, group_2_commands, + (const char **) RESERVED_GROUP, (const char **) RESERVED_GROUP, + (const char **) NOTEXT_GROUP, (const char **) VENDOR_GROUP, + (const char **) VENDOR_GROUP +}; + +static const char reserved[] = "RESERVED"; +static const char vendor[] = "VENDOR SPECIFIC"; + +static void print_opcodek(unsigned char opcode) +{ + const char **table = commands[ group(opcode) ]; + + switch ((unsigned long) table) { + case RESERVED_GROUP: + printk("%s[%02x] ", reserved, opcode); + break; + case NOTEXT_GROUP: + printk("%s(notext)[%02x] ", unknown, opcode); + break; + case VENDOR_GROUP: + printk("%s[%02x] ", vendor, opcode); + break; + default: + if (table[opcode & 0x1f] != unknown) + printk("%s[%02x] ", table[opcode & 0x1f], opcode); + else + printk("%s[%02x] ", unknown, opcode); + break; + } +} + +void print_commandk (unsigned char *command) +{ + int i,s; + printk(KERN_DEBUG); + print_opcodek(command[0]); + /*printk(KERN_DEBUG __FUNCTION__ " ");*/ + for ( i = 1, s = COMMAND_SIZE(command[0]); i < s; ++i) { + printk("%02x ", command[i]); + } + switch (COMMAND_SIZE(command[0])) { + case 6: + printk("LBA=%d len=%d", + (((unsigned int)command[1] & 0x0f) << 16) | + ( (unsigned int)command[2] << 8) | + ( (unsigned int)command[3] ), + (unsigned int)command[4] + ); + break; + case 10: + printk("LBA=%d len=%d", + ((unsigned int)command[2] << 24) | + ((unsigned int)command[3] << 16) | + ((unsigned int)command[4] << 8) | + ((unsigned int)command[5] ), + ((unsigned int)command[7] << 8) | + ((unsigned int)command[8] ) + ); + break; + case 12: + printk("LBA=%d len=%d", + ((unsigned int)command[2] << 24) | + ((unsigned int)command[3] << 16) | + ((unsigned int)command[4] << 8) | + ((unsigned int)command[5] ), + ((unsigned int)command[6] << 24) | + ((unsigned int)command[7] << 16) | + ((unsigned int)command[8] << 8) | + ((unsigned int)command[9] ) + ); + break; + default: + break; + } + printk("\n"); +} + +static void show_command(Scsi_Cmnd *ptr) +{ + print_commandk(ptr->cmnd); +} + +static void show_phase(Scsi_Cmnd *SCpnt) +{ + int i = SCpnt->SCp.phase; + + char *ph[] = { + "PH_UNDETERMINED", + "PH_ARBSTART", + "PH_SELSTART", + "PH_SELECTED", + "PH_COMMAND", + "PH_DATA", + "PH_STATUS", + "PH_MSG_IN", + "PH_MSG_OUT", + "PH_DISCONNECT", + "PH_RESELECT" + }; + + if ( i < PH_UNDETERMINED || i > PH_RESELECT ) { + printk(KERN_DEBUG "scsi phase: unknown(%d)\n", i); + return; + } + + printk(KERN_DEBUG "scsi phase: %s\n", ph[i]); + + return; +} + +static void show_busphase(unsigned char stat) +{ + switch(stat) { + case BUSPHASE_COMMAND: + printk(KERN_DEBUG "BUSPHASE_COMMAND\n"); + break; + case BUSPHASE_MESSAGE_IN: + printk(KERN_DEBUG "BUSPHASE_MESSAGE_IN\n"); + break; + case BUSPHASE_MESSAGE_OUT: + printk(KERN_DEBUG "BUSPHASE_MESSAGE_OUT\n"); + break; + case BUSPHASE_DATA_IN: + printk(KERN_DEBUG "BUSPHASE_DATA_IN\n"); + break; + case BUSPHASE_DATA_OUT: + printk(KERN_DEBUG "BUSPHASE_DATA_OUT\n"); + break; + case BUSPHASE_STATUS: + printk(KERN_DEBUG "BUSPHASE_STATUS\n"); + break; + case BUSPHASE_SELECT: + printk(KERN_DEBUG "BUSPHASE_SELECT\n"); + break; + default: + printk(KERN_DEBUG "BUSPHASE_other\n"); + break; + } +} diff -u --recursive --new-file v2.4.6/linux/drivers/scsi/pcmcia/nsp_io.h linux/drivers/scsi/pcmcia/nsp_io.h --- v2.4.6/linux/drivers/scsi/pcmcia/nsp_io.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/scsi/pcmcia/nsp_io.h Wed Jul 4 11:50:38 2001 @@ -0,0 +1,176 @@ +/* + NinjaSCSI I/O funtions + By: YOKOTA Hiroshi <yokota@netlab.is.tsukuba.ac.jp> + + This software may be used and distributed according to the terms of + the GNU General Public License. + + */ + +/* $Id: nsp_io.h,v 1.8 2001/01/30 05:16:02 elca Exp $ */ + +#ifndef __NSP_IO_H__ +#define __NSP_IO_H__ + +static inline void nsp_write(unsigned int base, + unsigned int index, + unsigned char val); +static inline unsigned char nsp_read(unsigned int base, + unsigned int index); +static inline void nsp_index_write(unsigned int BaseAddr, + unsigned int Register, + unsigned char Value); +static inline unsigned char nsp_index_read(unsigned int BaseAddr, + unsigned int Register); + +/******************************************************************* + * Basic IO + */ + +static inline void nsp_write(unsigned int base, + unsigned int index, + unsigned char val) +{ + outb(val, (base + index)); +} + +static inline unsigned char nsp_read(unsigned int base, + unsigned int index) +{ + return inb(base + index); +} + + +/********************************************************************** + * Indexed IO + */ +static inline unsigned char nsp_index_read(unsigned int BaseAddr, + unsigned int Register) +{ + outb(Register, BaseAddr + INDEXREG); + return inb(BaseAddr + DATAREG); +} + +static inline void nsp_index_write(unsigned int BaseAddr, + unsigned int Register, + unsigned char Value) +{ + outb(Register, BaseAddr + INDEXREG); + outb(Value, BaseAddr + DATAREG); +} + +/********************************************************************* + * fifo func + */ + +/* read 8 bit FIFO */ +static inline void nsp_multi_read_1(unsigned int BaseAddr, + unsigned int Register, + void *buf, + unsigned long count) +{ + insb(BaseAddr + Register, buf, count); +} + +static inline void nsp_fifo8_read(unsigned int base, + void *buf, + unsigned long count) +{ + //DEBUG(0, __FUNCTION__ "() buf=0x%p, count=0x%lx\n", buf, count); + nsp_multi_read_1(base, FIFODATA, buf, count); +} + +/*--------------------------------------------------------------*/ + +/* read 16 bit FIFO */ +static inline void nsp_multi_read_2(unsigned int BaseAddr, + unsigned int Register, + void *buf, + unsigned long count) +{ + insw(BaseAddr + Register, buf, count); +} + +static inline void nsp_fifo16_read(unsigned int base, + void *buf, + unsigned long count) +{ + //DEBUG(0, __FUNCTION__ "() buf=0x%p, count=0x%lx*2\n", buf, count); + nsp_multi_read_2(base, FIFODATA, buf, count); +} + +/*--------------------------------------------------------------*/ + +/* read 32bit FIFO */ +static inline void nsp_multi_read_4(unsigned int BaseAddr, + unsigned int Register, + void *buf, + unsigned long count) +{ + insl(BaseAddr + Register, buf, count); +} + +static inline void nsp_fifo32_read(unsigned int base, + void *buf, + unsigned long count) +{ + //DEBUG(0, __FUNCTION__ "() buf=0x%p, count=0x%lx*4\n", buf, count); + nsp_multi_read_4(base, FIFODATA, buf, count); +} + +/*----------------------------------------------------------*/ + +/* write 8bit FIFO */ +static inline void nsp_multi_write_1(unsigned int BaseAddr, + unsigned int Register, + void *buf, + unsigned long count) +{ + outsb(BaseAddr + Register, buf, count); +} + +static inline void nsp_fifo8_write(unsigned int base, + void *buf, + unsigned long count) +{ + nsp_multi_write_1(base, FIFODATA, buf, count); +} + +/*---------------------------------------------------------*/ + +/* write 16bit FIFO */ +static inline void nsp_multi_write_2(unsigned int BaseAddr, + unsigned int Register, + void *buf, + unsigned long count) +{ + outsw(BaseAddr + Register, buf, count); +} + +static inline void nsp_fifo16_write(unsigned int base, + void *buf, + unsigned long count) +{ + nsp_multi_write_2(base, FIFODATA, buf, count); +} + +/*---------------------------------------------------------*/ + +/* write 32bit FIFO */ +static inline void nsp_multi_write_4(unsigned int BaseAddr, + unsigned int Register, + void *buf, + unsigned long count) +{ + outsl(BaseAddr + Register, buf, count); +} + +static inline void nsp_fifo32_write(unsigned int base, + void *buf, + unsigned long count) +{ + nsp_multi_write_4(base, FIFODATA, buf, count); +} + +#endif +/* end */ diff -u --recursive --new-file v2.4.6/linux/drivers/scsi/qlogicisp.c linux/drivers/scsi/qlogicisp.c --- v2.4.6/linux/drivers/scsi/qlogicisp.c Tue Jul 3 17:08:20 2001 +++ linux/drivers/scsi/qlogicisp.c Thu Jul 5 11:28:17 2001 @@ -704,6 +704,7 @@ } host->this_id = hostdata->host_param.initiator_scsi_id; + host->max_sectors = 64; if (request_irq(host->irq, do_isp1020_intr_handler, SA_INTERRUPT | SA_SHIRQ, "qlogicisp", host)) diff -u --recursive --new-file v2.4.6/linux/drivers/scsi/qlogicpti.c linux/drivers/scsi/qlogicpti.c --- v2.4.6/linux/drivers/scsi/qlogicpti.c Tue Jul 3 17:08:20 2001 +++ linux/drivers/scsi/qlogicpti.c Thu Jul 5 11:28:17 2001 @@ -737,6 +737,7 @@ prom_getintdefault(qpti->sdev->bus->prom_node, "scsi-initiator-id", 7); qpti->qhost->this_id = qpti->scsi_id; + qpti->qhost->max_sectors = 64; printk("SCSI ID %d ", qpti->scsi_id); } diff -u --recursive --new-file v2.4.6/linux/drivers/scsi/scsi.c linux/drivers/scsi/scsi.c --- v2.4.6/linux/drivers/scsi/scsi.c Tue Jul 3 17:08:20 2001 +++ linux/drivers/scsi/scsi.c Thu Jul 19 21:07:04 2001 @@ -53,6 +53,8 @@ #include <linux/interrupt.h> #include <linux/delay.h> #include <linux/init.h> +#include <linux/smp_lock.h> +#include <linux/completion.h> #define __KERNEL_SYSCALLS__ @@ -217,8 +219,8 @@ req = &SCpnt->request; req->rq_status = RQ_SCSI_DONE; /* Busy, but indicate request done */ - if (req->sem != NULL) { - up(req->sem); + if (req->waiting != NULL) { + complete(req->waiting); } } @@ -464,7 +466,7 @@ } SCpnt->request.rq_status = RQ_SCSI_BUSY; - SCpnt->request.sem = NULL; /* And no one is waiting for this + SCpnt->request.waiting = NULL; /* And no one is waiting for this * to complete */ atomic_inc(&SCpnt->host->host_active); atomic_inc(&SCpnt->device->device_active); @@ -729,14 +731,14 @@ void *buffer, unsigned bufflen, int timeout, int retries) { - DECLARE_MUTEX_LOCKED(sem); + DECLARE_COMPLETION(wait); - SRpnt->sr_request.sem = &sem; + SRpnt->sr_request.waiting = &wait; SRpnt->sr_request.rq_status = RQ_SCSI_BUSY; scsi_do_req (SRpnt, (void *) cmnd, buffer, bufflen, scsi_wait_done, timeout, retries); - down (&sem); - SRpnt->sr_request.sem = NULL; + wait_for_completion(&wait); + SRpnt->sr_request.waiting = NULL; if( SRpnt->sr_command != NULL ) { scsi_release_command(SRpnt->sr_command); @@ -1098,7 +1100,7 @@ * the response. We treat it as if the command never finished. * * Since serial_number is now 0, the error handler cound detect this - * situation and avoid to call the the low level driver abort routine. + * situation and avoid to call the low level driver abort routine. * (DB) * * FIXME(eric) - I believe that this test is now redundant, due to @@ -1373,7 +1375,7 @@ } static int scsi_register_host(Scsi_Host_Template *); -static void scsi_unregister_host(Scsi_Host_Template *); +static int scsi_unregister_host(Scsi_Host_Template *); /* * Function: scsi_release_commandblocks() @@ -1569,12 +1571,17 @@ if (!(buffer = (char *) __get_free_page(GFP_KERNEL))) return -ENOMEM; - copy_from_user(buffer, buf, length); + if(copy_from_user(buffer, buf, length)) + { + err =-EFAULT; + goto out; + } err = -EINVAL; + if (length < PAGE_SIZE) - buffer[length] ='\0'; - else if (buffer[length]) + buffer[length] = '\0'; + else if (buffer[PAGE_SIZE-1]) goto out; if (length < 11 || strncmp("scsi", buffer, 4)) @@ -1821,6 +1828,11 @@ return 1; /* Must be already loaded, or * no detect routine available */ + + /* If max_sectors isn't set, default to max */ + if (!tpnt->max_sectors) + tpnt->max_sectors = MAX_SECTORS; + pcount = next_scsi_host; /* The detect routine must carefully spinunlock/spinlock if @@ -1965,14 +1977,8 @@ /* * Similarly, this entry point should be called by a loadable module if it * is trying to remove a low level scsi driver from the system. - * - * Note - there is a fatal flaw in the deregister module function. - * There is no way to return a code that says 'I cannot be unloaded now'. - * The system relies entirely upon usage counts that are maintained, - * and the assumption is that if the usage count is 0, then the module - * can be unloaded. */ -static void scsi_unregister_host(Scsi_Host_Template * tpnt) +static int scsi_unregister_host(Scsi_Host_Template * tpnt) { int online_status; int pcount0, pcount; @@ -1984,6 +1990,9 @@ struct Scsi_Host *shpnt; char name[10]; /* host_no>=10^9? I don't think so. */ + /* get the big kernel lock, so we don't race with open() */ + lock_kernel(); + /* * First verify that this host adapter is completely free with no pending * commands @@ -1994,7 +2003,7 @@ if (SDpnt->host->hostt == tpnt && SDpnt->host->hostt->module && GET_USE_COUNT(SDpnt->host->hostt->module)) - return; + goto err_out; /* * FIXME(eric) - We need to find a way to notify the * low level driver that we are shutting down - via the @@ -2046,7 +2055,7 @@ } SDpnt->online = online_status; printk(KERN_ERR "Device busy???\n"); - return; + goto err_out; } /* * No, this device is really free. Mark it as such, and @@ -2072,7 +2081,7 @@ /* If something still attached, punt */ if (SDpnt->attached) { printk(KERN_ERR "Attached usage count = %d\n", SDpnt->attached); - return; + goto err_out; } devfs_unregister (SDpnt->de); } @@ -2180,6 +2189,13 @@ } } MOD_DEC_USE_COUNT; + + unlock_kernel(); + return 0; + +err_out: + unlock_kernel(); + return -1; } static int scsi_unregister_device(struct Scsi_Device_Template *tpnt); @@ -2261,12 +2277,13 @@ struct Scsi_Host *shpnt; struct Scsi_Device_Template *spnt; struct Scsi_Device_Template *prev_spnt; - + + lock_kernel(); /* * If we are busy, this is not going to fly. */ if (GET_USE_COUNT(tpnt->module) != 0) - return 0; + goto error_out; /* * Next, detach the devices from the driver. @@ -2303,11 +2320,15 @@ prev_spnt->next = spnt->next; MOD_DEC_USE_COUNT; + unlock_kernel(); /* * Final cleanup for the driver is done in the driver sources in the * cleanup function. */ return 0; +error_out: + unlock_kernel(); + return -1; } @@ -2344,22 +2365,24 @@ /* Reverse the actions taken above */ -void scsi_unregister_module(int module_type, void *ptr) +int scsi_unregister_module(int module_type, void *ptr) { + int retval = 0; + switch (module_type) { case MODULE_SCSI_HA: - scsi_unregister_host((Scsi_Host_Template *) ptr); + retval = scsi_unregister_host((Scsi_Host_Template *) ptr); break; case MODULE_SCSI_DEV: - scsi_unregister_device((struct Scsi_Device_Template *) ptr); - break; + retval = scsi_unregister_device((struct Scsi_Device_Template *)ptr); + break; /* The rest of these are not yet implemented. */ case MODULE_SCSI_CONST: case MODULE_SCSI_IOCTL: - default: break; + default:; } - return; + return retval; } #ifdef CONFIG_PROC_FS diff -u --recursive --new-file v2.4.6/linux/drivers/scsi/scsi.h linux/drivers/scsi/scsi.h --- v2.4.6/linux/drivers/scsi/scsi.h Fri May 25 18:02:21 2001 +++ linux/drivers/scsi/scsi.h Fri Jul 20 12:55:46 2001 @@ -617,6 +617,9 @@ unsigned remap:1; /* support remapping */ unsigned starved:1; /* unable to process commands because host busy */ + + // Flag to allow revalidate to succeed in sd_open + int allow_revalidate; }; @@ -668,7 +671,7 @@ unsigned short sr_use_sg; /* Number of pieces of scatter-gather */ unsigned short sr_sglist_len; /* size of malloc'd scatter-gather list */ unsigned sr_underflow; /* Return error if less than - this amount is transfered */ + this amount is transferred */ }; /* @@ -756,7 +759,7 @@ void *buffer; /* Data buffer */ unsigned underflow; /* Return error if less than - this amount is transfered */ + this amount is transferred */ unsigned old_underflow; /* save underflow here when reusing the * command for error handling */ diff -u --recursive --new-file v2.4.6/linux/drivers/scsi/scsi_error.c linux/drivers/scsi/scsi_error.c --- v2.4.6/linux/drivers/scsi/scsi_error.c Sun Mar 4 14:30:27 2001 +++ linux/drivers/scsi/scsi_error.c Thu Jul 5 11:28:17 2001 @@ -427,7 +427,8 @@ memcpy((void *) SCpnt->cmnd, (void *) generic_sense, sizeof(generic_sense)); - SCpnt->cmnd[1] = SCpnt->lun << 5; + if (SCpnt->device->scsi_level <= SCSI_2) + SCpnt->cmnd[1] = SCpnt->lun << 5; scsi_result = (!SCpnt->host->hostt->unchecked_isa_dma) ? &scsi_result0[0] : kmalloc(512, GFP_ATOMIC | GFP_DMA); @@ -496,7 +497,8 @@ memcpy((void *) SCpnt->cmnd, (void *) tur_command, sizeof(tur_command)); - SCpnt->cmnd[1] = SCpnt->lun << 5; + if (SCpnt->device->scsi_level <= SCSI_2) + SCpnt->cmnd[1] = SCpnt->lun << 5; /* * Zero the sense buffer. The SCSI spec mandates that any @@ -1175,6 +1177,14 @@ */ if (SCpnt->device->expecting_cc_ua) { SCpnt->device->expecting_cc_ua = 0; + return NEEDS_RETRY; + } + /* + * If the device is in the process of becoming ready, we + * should retry. + */ + if ((SCpnt->sense_buffer[12] == 0x04) && + (SCpnt->sense_buffer[13] == 0x01)) { return NEEDS_RETRY; } return SUCCESS; diff -u --recursive --new-file v2.4.6/linux/drivers/scsi/scsi_ioctl.c linux/drivers/scsi/scsi_ioctl.c --- v2.4.6/linux/drivers/scsi/scsi_ioctl.c Tue Jul 3 17:08:20 2001 +++ linux/drivers/scsi/scsi_ioctl.c Thu Jul 5 11:28:17 2001 @@ -79,7 +79,7 @@ * * *(char *) ((int *) arg)[2] the actual command byte. * - * Note that if more than MAX_BUF bytes are requested to be transfered, + * Note that if more than MAX_BUF bytes are requested to be transferred, * the ioctl will fail with error EINVAL. MAX_BUF can be increased in * the future by increasing the size that scsi_malloc will accept. * @@ -196,8 +196,8 @@ Scsi_Request *SRpnt; Scsi_Device *SDpnt; unsigned char opcode; - int inlen, outlen, cmdlen; - int needed, buf_needed; + unsigned int inlen, outlen, cmdlen; + unsigned int needed, buf_needed; int timeout, retries, result; int data_direction; @@ -209,8 +209,11 @@ if (verify_area(VERIFY_READ, sic, sizeof(Scsi_Ioctl_Command))) return -EFAULT; - __get_user(inlen, &sic->inlen); - __get_user(outlen, &sic->outlen); + if(__get_user(inlen, &sic->inlen)) + return -EFAULT; + + if(__get_user(outlen, &sic->outlen)) + return -EFAULT; /* * We do not transfer more than MAX_BUF with this interface. @@ -223,7 +226,8 @@ return -EINVAL; cmd_in = sic->data; - __get_user(opcode, cmd_in); + if(get_user(opcode, cmd_in)) + return -EFAULT; needed = buf_needed = (inlen > outlen ? inlen : outlen); if (buf_needed) { @@ -254,21 +258,27 @@ * Obtain the command from the user's address space. */ cmdlen = COMMAND_SIZE(opcode); + + result = -EFAULT; if (verify_area(VERIFY_READ, cmd_in, cmdlen + inlen)) - return -EFAULT; + goto error; - __copy_from_user(cmd, cmd_in, cmdlen); + if(__copy_from_user(cmd, cmd_in, cmdlen)) + goto error; /* * Obtain the data to be sent to the device (if any). */ - __copy_from_user(buf, cmd_in + cmdlen, inlen); + + if(copy_from_user(buf, cmd_in + cmdlen, inlen)) + goto error; /* * Set the lun field to the correct value. */ - cmd[1] = (cmd[1] & 0x1f) | (dev->lun << 5); + if (dev->scsi_level <= SCSI_2) + cmd[1] = (cmd[1] & 0x1f) | (dev->lun << 5); switch (opcode) { case FORMAT_UNIT: @@ -303,7 +313,8 @@ SRpnt = scsi_allocate_request(dev); if( SRpnt == NULL ) { - return -EINTR; + result = -EINTR; + goto error; } SRpnt->sr_data_direction = data_direction; @@ -312,7 +323,9 @@ /* * If there was an error condition, pass the info back to the user. */ + result = SRpnt->sr_result; + if (SRpnt->sr_result) { int sb_len = sizeof(SRpnt->sr_sense_buffer); @@ -322,12 +335,13 @@ } else { if (copy_to_user(cmd_in, buf, outlen)) result = -EFAULT; - } + } SDpnt = SRpnt->sr_device; scsi_release_request(SRpnt); SRpnt = NULL; +error: if (buf) scsi_free(buf, buf_needed); @@ -379,6 +393,7 @@ int scsi_ioctl(Scsi_Device * dev, int cmd, void *arg) { char scsi_cmd[MAX_COMMAND_SIZE]; + char cmd_byte1; /* No idea how this happens.... */ if (!dev) @@ -393,14 +408,16 @@ if (!scsi_block_when_processing_errors(dev)) { return -ENODEV; } + cmd_byte1 = (dev->scsi_level <= SCSI_2) ? (dev->lun << 5) : 0; + switch (cmd) { case SCSI_IOCTL_GET_IDLUN: if (verify_area(VERIFY_WRITE, arg, sizeof(Scsi_Idlun))) return -EFAULT; - __put_user(dev->id - + (dev->lun << 8) - + (dev->channel << 16) + __put_user((dev->id & 0xff) + + ((dev->lun & 0xff) << 8) + + ((dev->channel & 0xff) << 16) + ((dev->host->host_no & 0xff) << 24), &((Scsi_Idlun *) arg)->dev_id); __put_user(dev->host->unique_id, &((Scsi_Idlun *) arg)->host_unique_id); @@ -434,7 +451,7 @@ if (!dev->removable || !dev->lockable) return 0; scsi_cmd[0] = ALLOW_MEDIUM_REMOVAL; - scsi_cmd[1] = dev->lun << 5; + scsi_cmd[1] = cmd_byte1; scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0; scsi_cmd[4] = SCSI_REMOVAL_PREVENT; return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd, @@ -444,14 +461,14 @@ if (!dev->removable || !dev->lockable) return 0; scsi_cmd[0] = ALLOW_MEDIUM_REMOVAL; - scsi_cmd[1] = dev->lun << 5; + scsi_cmd[1] = cmd_byte1; scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0; scsi_cmd[4] = SCSI_REMOVAL_ALLOW; return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd, IOCTL_NORMAL_TIMEOUT, NORMAL_RETRIES); case SCSI_IOCTL_TEST_UNIT_READY: scsi_cmd[0] = TEST_UNIT_READY; - scsi_cmd[1] = dev->lun << 5; + scsi_cmd[1] = cmd_byte1; scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0; scsi_cmd[4] = 0; return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd, @@ -459,7 +476,7 @@ break; case SCSI_IOCTL_START_UNIT: scsi_cmd[0] = START_STOP; - scsi_cmd[1] = dev->lun << 5; + scsi_cmd[1] = cmd_byte1; scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0; scsi_cmd[4] = 1; return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd, @@ -467,7 +484,7 @@ break; case SCSI_IOCTL_STOP_UNIT: scsi_cmd[0] = START_STOP; - scsi_cmd[1] = dev->lun << 5; + scsi_cmd[1] = cmd_byte1; scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0; scsi_cmd[4] = 0; return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd, diff -u --recursive --new-file v2.4.6/linux/drivers/scsi/scsi_lib.c linux/drivers/scsi/scsi_lib.c --- v2.4.6/linux/drivers/scsi/scsi_lib.c Fri May 4 15:16:28 2001 +++ linux/drivers/scsi/scsi_lib.c Thu Jul 19 20:48:04 2001 @@ -31,6 +31,7 @@ #include <linux/interrupt.h> #include <linux/delay.h> #include <linux/smp_lock.h> +#include <linux/completion.h> #define __KERNEL_SYSCALLS__ @@ -377,12 +378,15 @@ nsect = bh->b_size >> 9; blk_finished_io(nsect); req->bh = bh->b_reqnext; - req->nr_sectors -= nsect; - req->sector += nsect; bh->b_reqnext = NULL; sectors -= nsect; bh->b_end_io(bh, uptodate); if ((bh = req->bh) != NULL) { + req->hard_sector += nsect; + req->hard_nr_sectors -= nsect; + req->sector += nsect; + req->nr_sectors -= nsect; + req->current_nr_sectors = bh->b_size >> 9; if (req->nr_sectors < req->current_nr_sectors) { req->nr_sectors = req->current_nr_sectors; @@ -419,8 +423,8 @@ * request, wake them up. Typically used to wake up processes trying * to swap a page into memory. */ - if (req->sem != NULL) { - up(req->sem); + if (req->waiting != NULL) { + complete(req->waiting); } add_blkdev_randomness(MAJOR(req->rq_dev)); diff -u --recursive --new-file v2.4.6/linux/drivers/scsi/scsi_merge.c linux/drivers/scsi/scsi_merge.c --- v2.4.6/linux/drivers/scsi/scsi_merge.c Fri Feb 9 11:30:23 2001 +++ linux/drivers/scsi/scsi_merge.c Thu Jul 5 11:28:17 2001 @@ -417,6 +417,9 @@ max_segments = 64; #endif + if ((req->nr_sectors + (bh->b_size >> 9)) > SHpnt->max_sectors) + return 0; + if (use_clustering) { /* * See if we can do this without creating another @@ -473,6 +476,9 @@ max_segments = 64; #endif + if ((req->nr_sectors + (bh->b_size >> 9)) > SHpnt->max_sectors) + return 0; + if (use_clustering) { /* * See if we can do this without creating another @@ -597,6 +603,13 @@ Scsi_Device *SDpnt; struct Scsi_Host *SHpnt; + /* + * First check if the either of the requests are re-queued + * requests. Can't merge them if they are. + */ + if (req->special || next->special) + return 0; + SDpnt = (Scsi_Device *) q->queuedata; SHpnt = SDpnt->host; @@ -624,6 +637,10 @@ return 0; } #endif + + if ((req->nr_sectors + next->nr_sectors) > SHpnt->max_sectors) + return 0; + /* * The main question is whether the two segments at the boundaries * would be considered one or two. diff -u --recursive --new-file v2.4.6/linux/drivers/scsi/scsi_obsolete.c linux/drivers/scsi/scsi_obsolete.c --- v2.4.6/linux/drivers/scsi/scsi_obsolete.c Fri Feb 9 11:30:23 2001 +++ linux/drivers/scsi/scsi_obsolete.c Thu Jul 5 11:28:17 2001 @@ -223,7 +223,8 @@ memset((void *) SCpnt->sense_buffer, 0, sizeof(SCpnt->sense_buffer)); - SCpnt->cmnd[1] = SCpnt->lun << 5; + if (SCpnt->device->scsi_level <= SCSI_2) + SCpnt->cmnd[1] = SCpnt->lun << 5; SCpnt->cmnd[4] = sizeof(SCpnt->sense_buffer); SCpnt->request_buffer = &SCpnt->sense_buffer; diff -u --recursive --new-file v2.4.6/linux/drivers/scsi/scsi_scan.c linux/drivers/scsi/scsi_scan.c --- v2.4.6/linux/drivers/scsi/scsi_scan.c Tue Jul 3 17:08:20 2001 +++ linux/drivers/scsi/scsi_scan.c Thu Jul 5 11:28:17 2001 @@ -40,9 +40,13 @@ #define BLIST_ISROM 0x200 static void print_inquiry(unsigned char *data); -static int scan_scsis_single(int channel, int dev, int lun, int *max_scsi_dev, - int *sparse_lun, Scsi_Device ** SDpnt, - struct Scsi_Host *shpnt, char *scsi_result); +static int scan_scsis_single(unsigned int channel, unsigned int dev, + unsigned int lun, int lun0_scsi_level, + unsigned int *max_scsi_dev, unsigned int *sparse_lun, + Scsi_Device ** SDpnt, struct Scsi_Host *shpnt, + char *scsi_result); +static int find_lun0_scsi_level(unsigned int channel, unsigned int dev, + struct Scsi_Host *shpnt); struct dev_info { const char *vendor; @@ -135,6 +139,7 @@ {"nCipher", "Fastness Crypto", "*", BLIST_FORCELUN}, {"DEC","HSG80","*", BLIST_FORCELUN}, {"COMPAQ","LOGICAL VOLUME","*", BLIST_FORCELUN}, + {"COMPAQ","CR3500","*", BLIST_FORCELUN}, {"NEC", "PD-1 ODX654P", "*", BLIST_FORCELUN | BLIST_SINGLELUN}, {"MATSHITA", "PD-1", "*", BLIST_FORCELUN | BLIST_SINGLELUN}, {"iomega", "jaz 1GB", "J.86", BLIST_NOTQ | BLIST_NOLUN}, @@ -143,7 +148,11 @@ {"MegaRAID", "LD", "*", BLIST_FORCELUN}, {"DGC", "RAID", "*", BLIST_SPARSELUN}, // Dell PV 650F (tgt @ LUN 0) {"DGC", "DISK", "*", BLIST_SPARSELUN}, // Dell PV 650F (no tgt @ LUN 0) + {"DELL", "PV660F", "*", BLIST_SPARSELUN}, + {"DELL", "PV660F PSEUDO", "*", BLIST_SPARSELUN}, + {"DELL", "PSEUDO DEVICE .", "*", BLIST_SPARSELUN}, // Dell PV 530F {"DELL", "PV530F", "*", BLIST_SPARSELUN}, // Dell PV 530F + {"EMC", "SYMMETRIX", "*", BLIST_SPARSELUN}, {"SONY", "TSL", "*", BLIST_FORCELUN}, // DDS3 & DDS4 autoloaders {"DELL", "PERCRAID", "*", BLIST_FORCELUN}, {"HP", "NetRAID-4M", "*", BLIST_FORCELUN}, @@ -154,29 +163,31 @@ {NULL, NULL, NULL} }; +#define MAX_SCSI_LUNS 0xFFFFFFFF + #ifdef CONFIG_SCSI_MULTI_LUN -static int max_scsi_luns = 8; +static unsigned int max_scsi_luns = MAX_SCSI_LUNS; #else -static int max_scsi_luns = 1; +static unsigned int max_scsi_luns = 1; #endif #ifdef MODULE MODULE_PARM(max_scsi_luns, "i"); -MODULE_PARM_DESC(max_scsi_luns, "last scsi LUN (should be between 1 and 8)"); +MODULE_PARM_DESC(max_scsi_luns, "last scsi LUN (should be between 1 and 2^32-1)"); #else static int __init scsi_luns_setup(char *str) { - int tmp; + unsigned int tmp; if (get_option(&str, &tmp) == 1) { max_scsi_luns = tmp; return 1; } else { printk("scsi_luns_setup : usage max_scsi_luns=n " - "(n should be between 1 and 8)\n"); + "(n should be between 1 and 2^32-1)\n"); return 0; } } @@ -264,14 +275,15 @@ uint hlun) { uint channel; - int dev; - int lun; - int max_dev_lun; + unsigned int dev; + unsigned int lun; + unsigned int max_dev_lun; unsigned char *scsi_result; unsigned char scsi_result0[256]; Scsi_Device *SDpnt; Scsi_Device *SDtail; - int sparse_lun; + unsigned int sparse_lun; + int lun0_sl; scsi_result = NULL; @@ -343,8 +355,12 @@ lun = hlun; if (lun >= shpnt->max_lun) goto leave; - scan_scsis_single(channel, dev, lun, &max_dev_lun, &sparse_lun, - &SDpnt, shpnt, scsi_result); + if ((0 == lun) || (lun > 7)) + lun0_sl = SCSI_3; /* actually don't care for 0 == lun */ + else + lun0_sl = find_lun0_scsi_level(channel, dev, shpnt); + scan_scsis_single(channel, dev, lun, lun0_sl, &max_dev_lun, + &sparse_lun, &SDpnt, shpnt, scsi_result); if (SDpnt != oldSDpnt) { /* it could happen the blockdevice hasn't yet been inited */ @@ -400,12 +416,14 @@ max_dev_lun = (max_scsi_luns < shpnt->max_lun ? max_scsi_luns : shpnt->max_lun); sparse_lun = 0; - for (lun = 0; lun < max_dev_lun; ++lun) { - if (!scan_scsis_single(channel, order_dev, lun, &max_dev_lun, - &sparse_lun, &SDpnt, shpnt, - scsi_result) + for (lun = 0, lun0_sl = SCSI_2; lun < max_dev_lun; ++lun) { + if (!scan_scsis_single(channel, order_dev, lun, lun0_sl, + &max_dev_lun, &sparse_lun, &SDpnt, shpnt, + scsi_result) && !sparse_lun) break; /* break means don't probe further for luns!=0 */ + if (SDpnt && (0 == lun)) + lun0_sl = SDpnt->scsi_level; } /* for lun ends */ } /* if this_id != id ends */ } /* for dev ends */ @@ -461,9 +479,11 @@ * Returning 0 means Please don't ask further for lun!=0, 1 means OK go on. * Global variables used : scsi_devices(linked list) */ -static int scan_scsis_single(int channel, int dev, int lun, int *max_dev_lun, - int *sparse_lun, Scsi_Device ** SDpnt2, - struct Scsi_Host *shpnt, char *scsi_result) +static int scan_scsis_single(unsigned int channel, unsigned int dev, + unsigned int lun, int lun0_scsi_level, + unsigned int *max_dev_lun, unsigned int *sparse_lun, + Scsi_Device ** SDpnt2, struct Scsi_Host *shpnt, + char *scsi_result) { char devname[64]; unsigned char scsi_cmd[MAX_COMMAND_SIZE]; @@ -509,7 +529,10 @@ * Build an INQUIRY command block. */ scsi_cmd[0] = INQUIRY; - scsi_cmd[1] = (lun << 5) & 0xe0; + if ((lun > 0) && (lun0_scsi_level <= SCSI_2)) + scsi_cmd[1] = (lun << 5) & 0xe0; + else + scsi_cmd[1] = 0; /* SCSI_3 and higher, don't touch */ scsi_cmd[2] = 0; scsi_cmd[3] = 0; scsi_cmd[4] = 255; @@ -677,7 +700,9 @@ printk("Unlocked floptical drive.\n"); SDpnt->lockable = 0; scsi_cmd[0] = MODE_SENSE; - scsi_cmd[1] = (lun << 5) & 0xe0; + if (shpnt->max_lun <= 8) + scsi_cmd[1] = (lun << 5) & 0xe0; + else scsi_cmd[1] = 0; /* any other idea? */ scsi_cmd[2] = 0x2e; scsi_cmd[3] = 0; scsi_cmd[4] = 0x2a; @@ -760,7 +785,19 @@ * other settings, and scan all of them. */ if (bflags & BLIST_SPARSELUN) { - *max_dev_lun = 8; + /* + * Scanning MAX_SCSI_LUNS units would be a bad idea. + * Any better idea? + * I think we need REPORT LUNS in future to avoid scanning + * of unused LUNs. But, that is another item. + * + * FIXME(eric) - perhaps this should be a kernel configurable? + */ + if (*max_dev_lun < shpnt->max_lun) + *max_dev_lun = shpnt->max_lun; + else if ((max_scsi_luns >> 1) >= *max_dev_lun) + *max_dev_lun += shpnt->max_lun; + else *max_dev_lun = max_scsi_luns; *sparse_lun = 1; return 1; } @@ -769,7 +806,17 @@ * settings, and scan all of them. */ if (bflags & BLIST_FORCELUN) { - *max_dev_lun = 8; + /* + * Scanning MAX_SCSI_LUNS units would be a bad idea. + * Any better idea? + * I think we need REPORT LUNS in future to avoid scanning + * of unused LUNs. But, that is another item. + */ + if (*max_dev_lun < shpnt->max_lun) + *max_dev_lun = shpnt->max_lun; + else if ((max_scsi_luns >> 1) >= *max_dev_lun) + *max_dev_lun += shpnt->max_lun; + else *max_dev_lun = max_scsi_luns; return 1; } /* @@ -793,3 +840,23 @@ return 1; } +/* + * The worker for scan_scsis. + * Returns the scsi_level of lun0 on this host, channel and dev (if already + * known), otherwise returns SCSI_2. + */ +static int find_lun0_scsi_level(unsigned int channel, unsigned int dev, + struct Scsi_Host *shpnt) +{ + int res = SCSI_2; + Scsi_Device *SDpnt; + + for (SDpnt = shpnt->host_queue; SDpnt; SDpnt = SDpnt->next) + { + if ((0 == SDpnt->lun) && (dev == SDpnt->id) && + (channel == SDpnt->channel)) + return (int)SDpnt->scsi_level; + } + /* haven't found lun0, should send INQUIRY but take easy route */ + return res; +} diff -u --recursive --new-file v2.4.6/linux/drivers/scsi/sd.c linux/drivers/scsi/sd.c --- v2.4.6/linux/drivers/scsi/sd.c Tue Jul 3 17:08:20 2001 +++ linux/drivers/scsi/sd.c Thu Jul 5 11:28:17 2001 @@ -22,6 +22,12 @@ * * Modified by Torben Mathiasen tmm@image.dk * Resource allocation fixes in sd_init and cleanups. + * + * Modified by Alex Davis <letmein@erols.com> + * Fix problem where partition info not being read in sd_open. + * + * Modified by Alex Davis <letmein@erols.com> + * Fix problem where removable media could be ejected after sd_open. */ #include <linux/config.h> @@ -372,7 +378,8 @@ (SCpnt->request.cmd == WRITE) ? "writing" : "reading", this_count, SCpnt->request.nr_sectors)); - SCpnt->cmnd[1] = (SCpnt->lun << 5) & 0xe0; + SCpnt->cmnd[1] = (SCpnt->device->scsi_level <= SCSI_2) ? + ((SCpnt->lun << 5) & 0xe0) : 0; if (((this_count > 0xff) || (block > 0x1fffff)) || SCpnt->device->ten) { if (this_count > 0xffff) @@ -424,7 +431,7 @@ static int sd_open(struct inode *inode, struct file *filp) { - int target; + int target, retval = -ENXIO; Scsi_Device * SDev; target = DEVICE_NR(inode->i_rdev); @@ -448,24 +455,40 @@ while (rscsi_disks[target].device->busy) barrier(); + /* + * The following code can sleep. + * Module unloading must be prevented + */ + SDev = rscsi_disks[target].device; + if (SDev->host->hostt->module) + __MOD_INC_USE_COUNT(SDev->host->hostt->module); + if (sd_template.module) + __MOD_INC_USE_COUNT(sd_template.module); + SDev->access_count++; + if (rscsi_disks[target].device->removable) { + SDev->allow_revalidate = 1; check_disk_change(inode->i_rdev); + SDev->allow_revalidate = 0; /* * If the drive is empty, just let the open fail. */ - if (!rscsi_disks[target].ready) - return -ENXIO; + if ((!rscsi_disks[target].ready) && !(filp->f_flags & O_NDELAY)) { + retval = -ENOMEDIUM; + goto error_out; + } /* * Similarly, if the device has the write protect tab set, * have the open fail if the user expects to be able to write * to the thing. */ - if ((rscsi_disks[target].write_prot) && (filp->f_mode & 2)) - return -EROFS; + if ((rscsi_disks[target].write_prot) && (filp->f_mode & 2)) { + retval = -EROFS; + goto error_out; + } } - SDev = rscsi_disks[target].device; /* * It is possible that the disk changing stuff resulted in the device * being taken offline. If this is the case, report this to the user, @@ -473,26 +496,31 @@ * the open actually succeeded. */ if (!SDev->online) { - return -ENXIO; + goto error_out; } /* * See if we are requesting a non-existent partition. Do this * after checking for disk change. */ - if (sd_sizes[SD_PARTITION(inode->i_rdev)] == 0) - return -ENXIO; + if (sd_sizes[SD_PARTITION(inode->i_rdev)] == 0) { + goto error_out; + } if (SDev->removable) - if (!SDev->access_count) + if (SDev->access_count==1) if (scsi_block_when_processing_errors(SDev)) scsi_ioctl(SDev, SCSI_IOCTL_DOORLOCK, NULL); - SDev->access_count++; + + return 0; + +error_out: + SDev->access_count--; if (SDev->host->hostt->module) - __MOD_INC_USE_COUNT(SDev->host->hostt->module); + __MOD_DEC_USE_COUNT(SDev->host->hostt->module); if (sd_template.module) - __MOD_INC_USE_COUNT(sd_template.module); - return 0; + __MOD_DEC_USE_COUNT(sd_template.module); + return retval; } static int sd_release(struct inode *inode, struct file *file) @@ -746,7 +774,8 @@ while (retries < 3) { cmd[0] = TEST_UNIT_READY; - cmd[1] = (rscsi_disks[i].device->lun << 5) & 0xe0; + cmd[1] = (rscsi_disks[i].device->scsi_level <= SCSI_2) ? + ((rscsi_disks[i].device->lun << 5) & 0xe0) : 0; memset((void *) &cmd[2], 0, 8); SRpnt->sr_cmd_len = 0; SRpnt->sr_sense_buffer[0] = 0; @@ -787,7 +816,8 @@ if (!spintime) { printk("%s: Spinning up disk...", nbuff); cmd[0] = START_STOP; - cmd[1] = (rscsi_disks[i].device->lun << 5) & 0xe0; + cmd[1] = (rscsi_disks[i].device->scsi_level <= SCSI_2) ? + ((rscsi_disks[i].device->lun << 5) & 0xe0) : 0; cmd[1] |= 1; /* Return immediately */ memset((void *) &cmd[2], 0, 8); cmd[4] = 1; /* Start spin cycle */ @@ -820,7 +850,8 @@ retries = 3; do { cmd[0] = READ_CAPACITY; - cmd[1] = (rscsi_disks[i].device->lun << 5) & 0xe0; + cmd[1] = (rscsi_disks[i].device->scsi_level <= SCSI_2) ? + ((rscsi_disks[i].device->lun << 5) & 0xe0) : 0; memset((void *) &cmd[2], 0, 8); memset((void *) buffer, 0, 8); SRpnt->sr_cmd_len = 0; @@ -977,7 +1008,8 @@ memset((void *) &cmd[0], 0, 8); cmd[0] = MODE_SENSE; - cmd[1] = (rscsi_disks[i].device->lun << 5) & 0xe0; + cmd[1] = (rscsi_disks[i].device->scsi_level <= SCSI_2) ? + ((rscsi_disks[i].device->lun << 5) & 0xe0) : 0; cmd[2] = 0x3f; /* Get all pages */ cmd[4] = 8; /* But we only want the 8 byte header */ SRpnt->sr_cmd_len = 0; @@ -1183,16 +1215,9 @@ static int sd_detect(Scsi_Device * SDp) { - char nbuff[6]; if (SDp->type != TYPE_DISK && SDp->type != TYPE_MOD) return 0; - - sd_devname(sd_template.dev_noticed++, nbuff); - printk("Detected scsi %sdisk %s at scsi%d, channel %d, id %d, lun %d\n", - SDp->removable ? "removable " : "", - nbuff, - SDp->host->host_no, SDp->channel, SDp->id, SDp->lun); - + sd_template.dev_noticed++; return 1; } @@ -1201,6 +1226,7 @@ unsigned int devnum; Scsi_Disk *dpnt; int i; + char nbuff[6]; if (SDp->type != TYPE_DISK && SDp->type != TYPE_MOD) return 0; @@ -1224,10 +1250,15 @@ SD_GENDISK(i).de_arr[devnum] = SDp->de; if (SDp->removable) SD_GENDISK(i).flags[devnum] |= GENHD_FL_REMOVABLE; + sd_devname(i, nbuff); + printk("Attached scsi %sdisk %s at scsi%d, channel %d, id %d, lun %d\n", + SDp->removable ? "removable " : "", + nbuff, SDp->host->host_no, SDp->channel, SDp->id, SDp->lun); return 0; } #define DEVICE_BUSY rscsi_disks[target].device->busy +#define ALLOW_REVALIDATE rscsi_disks[target].device->allow_revalidate #define USAGE rscsi_disks[target].device->access_count #define CAPACITY rscsi_disks[target].capacity #define MAYBE_REINIT sd_init_onedisk(target) @@ -1248,7 +1279,7 @@ target = DEVICE_NR(dev); - if (DEVICE_BUSY || USAGE > maxusage) { + if (DEVICE_BUSY || (ALLOW_REVALIDATE == 0 && USAGE > maxusage)) { printk("Device busy for revalidation (usage=%d)\n", USAGE); return -EBUSY; } diff -u --recursive --new-file v2.4.6/linux/drivers/scsi/sg.c linux/drivers/scsi/sg.c --- v2.4.6/linux/drivers/scsi/sg.c Mon Jan 15 13:08:15 2001 +++ linux/drivers/scsi/sg.c Wed Jul 4 15:39:28 2001 @@ -7,7 +7,7 @@ * Original driver (sg.c): * Copyright (C) 1992 Lawrence Foard * Version 2 and 3 extensions to driver: - * Copyright (C) 1998 - 2000 Douglas Gilbert + * Copyright (C) 1998 - 2001 Douglas Gilbert * * Modified 19-JAN-1998 Richard Gooch <rgooch@atnf.csiro.au> Devfs support * @@ -19,9 +19,9 @@ */ #include <linux/config.h> #ifdef CONFIG_PROC_FS - static char * sg_version_str = "Version: 3.1.17 (20001002)"; + static char sg_version_str[] = "Version: 3.1.19 (20010623)"; #endif - static int sg_version_num = 30117; /* 2 digits for each component */ + static int sg_version_num = 30119; /* 2 digits for each component */ /* * D. P. Gilbert (dgilbert@interlog.com, dougg@triode.net.au), notes: * - scsi logging is available via SCSI_LOG_TIMEOUT macros. First @@ -76,8 +76,9 @@ #include <linux/version.h> #endif /* LINUX_VERSION_CODE */ -/* #define SG_ALLOW_DIO */ -#ifdef SG_ALLOW_DIO +#define SG_ALLOW_DIO_DEF 0 +#define SG_ALLOW_DIO_CODE /* compile out be commenting this define */ +#ifdef SG_ALLOW_DIO_CODE #include <linux/iobuf.h> #endif @@ -89,6 +90,7 @@ readable via /proc/sys/kernel/sg-big-buff if the sg driver is built into the kernel (i.e. it is not a module).] */ static int def_reserved_size = -1; /* picks up init parameter */ +static int sg_allow_dio = SG_ALLOW_DIO_DEF; #define SG_SECTOR_SZ 512 #define SG_SECTOR_MSK (SG_SECTOR_SZ - 1) @@ -112,7 +114,7 @@ static int sg_detect(Scsi_Device *); static void sg_detach(Scsi_Device *); -static Scsi_Request * dummy_cmdp = 0; /* only used for sizeof */ +static Scsi_Request * dummy_cmdp; /* only used for sizeof */ static rwlock_t sg_dev_arr_lock = RW_LOCK_UNLOCKED; /* Also used to lock file descriptor list for device */ @@ -157,7 +159,7 @@ char res_used; /* 1 -> using reserve buffer, 0 -> not ... */ char orphan; /* 1 -> drop on sight, 0 -> normal */ char sg_io_owned; /* 1 -> packet belongs to SG_IO */ - char done; /* 0->before bh, 1->before read, 2->read */ + volatile char done; /* 0->before bh, 1->before read, 2->read */ } Sg_request; /* 168 bytes long on i386 */ typedef struct sg_fd /* holds the state of a file descriptor */ @@ -174,12 +176,12 @@ Sg_request req_arr[SG_MAX_QUEUE]; /* used as singly-linked list */ char low_dma; /* as in parent but possibly overridden to 1 */ char force_packid; /* 1 -> pack_id input to read(), 0 -> ignored */ - char closed; /* 1 -> fd closed but request(s) outstanding */ + volatile char closed; /* 1 -> fd closed but request(s) outstanding */ char fd_mem_src; /* heap whereabouts of this Sg_fd object */ char cmd_q; /* 1 -> allow command queuing, 0 -> don't */ char next_cmd_len; /* 0 -> automatic (def), >0 -> use on next write() */ char keep_orphan; /* 0 -> drop orphan (def), 1 -> keep for read() */ -} Sg_fd; /* 2768 bytes long on i386 */ +} Sg_fd; /* 2760 bytes long on i386 */ typedef struct sg_device /* holds the state of each scsi generic device */ { @@ -189,10 +191,10 @@ Sg_fd * headfp; /* first open fd belonging to this device */ devfs_handle_t de; kdev_t i_rdev; /* holds device major+minor number */ - char exclude; /* opened for exclusive access */ + volatile char detached; /* 0->attached, 1->detached pending removal */ + volatile char exclude; /* opened for exclusive access */ char sgdebug; /* 0->off, 1->sense, 9->dump dev, 10-> all devs */ - char detached; /* 0->attached, 1->detached pending removal */ -} Sg_device; /* 44 bytes long on i386 */ +} Sg_device; /* 36 bytes long on i386 */ static int sg_fasync(int fd, struct file * filp, int mode); @@ -225,13 +227,12 @@ static void sg_low_free(char * buff, int size, int mem_src); static Sg_fd * sg_add_sfp(Sg_device * sdp, int dev); static int sg_remove_sfp(Sg_device * sdp, Sg_fd * sfp); +static void __sg_remove_sfp(Sg_device * sdp, Sg_fd * sfp); static Sg_request * sg_get_rq_mark(Sg_fd * sfp, int pack_id); static Sg_request * sg_add_request(Sg_fd * sfp); static int sg_remove_request(Sg_fd * sfp, Sg_request * srp); static int sg_res_in_use(Sg_fd * sfp); -static int sg_dio_in_use(Sg_fd * sfp); static void sg_clr_srpnt(Scsi_Request * SRpnt); -static void sg_shorten_timeout(Scsi_Request * srpnt); static int sg_ms_to_jif(unsigned int msecs); static unsigned sg_jif_to_ms(int jifs); static int sg_allow_access(unsigned char opcode, char dev_type); @@ -244,10 +245,10 @@ static Sg_device ** sg_dev_arr = NULL; -static const int size_sg_header = sizeof(struct sg_header); -static const int size_sg_io_hdr = sizeof(sg_io_hdr_t); -static const int size_sg_iovec = sizeof(sg_iovec_t); -static const int size_sg_req_info = sizeof(sg_req_info_t); +#define SZ_SG_HEADER sizeof(struct sg_header) +#define SZ_SG_IO_HDR sizeof(sg_io_hdr_t) +#define SZ_SG_IOVEC sizeof(sg_iovec_t) +#define SZ_SG_REQ_INFO sizeof(sg_req_info_t) static int sg_open(struct inode * inode, struct file * filp) @@ -257,43 +258,56 @@ Sg_device * sdp; Sg_fd * sfp; int res; + int retval = -EBUSY; + SCSI_LOG_TIMEOUT(3, printk("sg_open: dev=%d, flags=0x%x\n", dev, flags)); sdp = sg_get_dev(dev); - if ((! sdp) || (! sdp->device) || (! sdp->device->host)) - return -ENXIO; - if (sdp->i_rdev != inode->i_rdev) - printk("sg_open: inode maj=%d, min=%d sdp maj=%d, min=%d\n", - MAJOR(inode->i_rdev), MINOR(inode->i_rdev), - MAJOR(sdp->i_rdev), MINOR(sdp->i_rdev)); - /* If we are in the middle of error recovery, don't let anyone - * else try and use this device. Also, if error recovery fails, it - * may try and take the device offline, in which case all further - * access to the device is prohibited. */ - if (! ((flags & O_NONBLOCK) || - scsi_block_when_processing_errors(sdp->device))) + if ((! sdp) || (! sdp->device)) return -ENXIO; + if (sdp->detached) + return -ENODEV; - SCSI_LOG_TIMEOUT(3, printk("sg_open: dev=%d, flags=0x%x\n", dev, flags)); + /* This driver's module count bumped by fops_get in <linux/fs.h> */ + /* Prevent the device driver from vanishing while we sleep */ + if (sdp->device->host->hostt->module) + __MOD_INC_USE_COUNT(sdp->device->host->hostt->module); + + if (! ((flags & O_NONBLOCK) || + scsi_block_when_processing_errors(sdp->device))) { + retval = -ENXIO; + /* we are in error recovery for this device */ + goto error_out; + } if (flags & O_EXCL) { - if (O_RDONLY == (flags & O_ACCMODE)) - return -EACCES; /* Can't lock it with read only access */ - if (sdp->headfp && (flags & O_NONBLOCK)) - return -EBUSY; - res = 0; /* following is a macro that beats race condition */ + if (O_RDONLY == (flags & O_ACCMODE)) { + retval = -EACCES; /* Can't lock it with read only access */ + goto error_out; + } + if (sdp->headfp && (flags & O_NONBLOCK)) + goto error_out; + res = 0; __wait_event_interruptible(sdp->o_excl_wait, ((sdp->headfp || sdp->exclude) ? 0 : (sdp->exclude = 1)), res); - if (res) - return res; /* -ERESTARTSYS because signal hit process */ + if (res) { + retval = res; /* -ERESTARTSYS because signal hit process */ + goto error_out; + } } else if (sdp->exclude) { /* some other fd has an exclusive lock on dev */ if (flags & O_NONBLOCK) - return -EBUSY; - res = 0; /* following is a macro that beats race condition */ + goto error_out; + res = 0; __wait_event_interruptible(sdp->o_excl_wait, (! sdp->exclude), res); - if (res) - return res; /* -ERESTARTSYS because signal hit process */ + if (res) { + retval = res; /* -ERESTARTSYS because signal hit process */ + goto error_out; + } + } + if (sdp->detached) { + retval = -ENODEV; + goto error_out; } if (! sdp->headfp) { /* no existing opens on this device */ sdp->sgdebug = 0; @@ -303,12 +317,15 @@ filp->private_data = sfp; else { if (flags & O_EXCL) sdp->exclude = 0; /* undo if error */ - return -ENOMEM; + retval = -ENOMEM; + goto error_out; } - - if (sdp->device->host->hostt->module) - __MOD_INC_USE_COUNT(sdp->device->host->hostt->module); return 0; + +error_out: + if ((! sdp->detached) && sdp->device->host->hostt->module) + __MOD_DEC_USE_COUNT(sdp->device->host->hostt->module); + return retval; } /* Following function was formerly called 'sg_close' */ @@ -324,14 +341,12 @@ } SCSI_LOG_TIMEOUT(3, printk("sg_release: dev=%d\n", MINOR(sdp->i_rdev))); sg_fasync(-1, filp, 0); /* remove filp from async notification list */ - sg_remove_sfp(sdp, sfp); - if (! sdp->headfp) - filp->private_data = NULL; - - if (sdp->device->host->hostt->module) - __MOD_DEC_USE_COUNT(sdp->device->host->hostt->module); - sdp->exclude = 0; - wake_up_interruptible(&sdp->o_excl_wait); + if (0 == sg_remove_sfp(sdp, sfp)) { /* Returns 1 when sdp gone */ + if ((! sdp->detached) && sdp->device->host->hostt->module) + __MOD_DEC_USE_COUNT(sdp->device->host->hostt->module); + sdp->exclude = 0; + wake_up_interruptible(&sdp->o_excl_wait); + } unlock_kernel(); return 0; } @@ -356,11 +371,11 @@ ; /* FIXME: Hmm. Seek to the right place, or fail? */ if ((k = verify_area(VERIFY_WRITE, buf, count))) return k; - if (sfp->force_packid && (count >= size_sg_header)) { - __copy_from_user(&old_hdr, buf, size_sg_header); + if (sfp->force_packid && (count >= SZ_SG_HEADER)) { + __copy_from_user(&old_hdr, buf, SZ_SG_HEADER); if (old_hdr.reply_len < 0) { - if (count >= size_sg_io_hdr) { - __copy_from_user(&new_hdr, buf, size_sg_io_hdr); + if (count >= SZ_SG_IO_HDR) { + __copy_from_user(&new_hdr, buf, SZ_SG_IO_HDR); req_pack_id = new_hdr.pack_id; } } @@ -369,25 +384,26 @@ } srp = sg_get_rq_mark(sfp, req_pack_id); if (! srp) { /* now wait on packet to arrive */ + if (sdp->detached) + return -ENODEV; if (filp->f_flags & O_NONBLOCK) return -EAGAIN; while (1) { - int dio = sg_dio_in_use(sfp); res = 0; /* following is a macro that beats race condition */ - __wait_event_interruptible(sfp->read_wait, - (srp = sg_get_rq_mark(sfp, req_pack_id)), - res); + __wait_event_interruptible(sfp->read_wait, (sdp->detached || + (srp = sg_get_rq_mark(sfp, req_pack_id))), res); + if (sdp->detached) + return -ENODEV; if (0 == res) break; - else if (! dio) /* only let signal out if no dio */ - return res; /* -ERESTARTSYS because signal hit process */ + return res; /* -ERESTARTSYS because signal hit process */ } } if (srp->header.interface_id != '\0') return sg_new_read(sfp, buf, count, srp); hp = &srp->header; - memset(&old_hdr, 0, size_sg_header); + memset(&old_hdr, 0, SZ_SG_HEADER); old_hdr.reply_len = (int)hp->timeout; old_hdr.pack_len = old_hdr.reply_len; /* very old, strange behaviour */ old_hdr.pack_id = hp->pack_id; @@ -430,13 +446,13 @@ } /* Now copy the result back to the user buffer. */ - if (count >= size_sg_header) { - __copy_to_user(buf, &old_hdr, size_sg_header); - buf += size_sg_header; + if (count >= SZ_SG_HEADER) { + __copy_to_user(buf, &old_hdr, SZ_SG_HEADER); + buf += SZ_SG_HEADER; if (count > old_hdr.reply_len) count = old_hdr.reply_len; - if (count > size_sg_header) - sg_read_oxfer(srp, buf, count - size_sg_header); + if (count > SZ_SG_HEADER) + sg_read_oxfer(srp, buf, count - SZ_SG_HEADER); } else count = (old_hdr.result == 0) ? 0 : -EIO; @@ -447,11 +463,14 @@ static ssize_t sg_new_read(Sg_fd * sfp, char * buf, size_t count, Sg_request * srp) { - sg_io_hdr_t * hp = &srp->header; - int k, len; + sg_io_hdr_t * hp = &srp->header; + int err = 0; + int len; - if (count < size_sg_io_hdr) - return -EINVAL; + if (count < SZ_SG_IO_HDR) { + err = -EINVAL; + goto err_out; + } hp->sb_len_wr = 0; if ((hp->mx_sb_len > 0) && hp->sbp) { if ((CHECK_CONDITION & hp->masked_status) || @@ -460,20 +479,19 @@ sb_len = (hp->mx_sb_len > sb_len) ? sb_len : hp->mx_sb_len; len = 8 + (int)srp->sense_b[7]; /* Additional sense length field */ len = (len > sb_len) ? sb_len : len; - if ((k = verify_area(VERIFY_WRITE, hp->sbp, len))) - return k; + if ((err = verify_area(VERIFY_WRITE, hp->sbp, len))) + goto err_out; __copy_to_user(hp->sbp, srp->sense_b, len); hp->sb_len_wr = len; } } if (hp->masked_status || hp->host_status || hp->driver_status) hp->info |= SG_INFO_CHECK; - copy_to_user(buf, hp, size_sg_io_hdr); - - k = sg_read_xfer(srp); - if (k) return k; /* probably -EFAULT, bad addr in dxferp or iovec list */ + copy_to_user(buf, hp, SZ_SG_IO_HDR); + err = sg_read_xfer(srp); +err_out: sg_finish_rem_req(srp); - return count; + return (0 == err) ? count : err; } @@ -494,7 +512,8 @@ return -ENXIO; SCSI_LOG_TIMEOUT(3, printk("sg_write: dev=%d, count=%d\n", MINOR(sdp->i_rdev), (int)count)); - + if (sdp->detached) + return -ENODEV; if (! ((filp->f_flags & O_NONBLOCK) || scsi_block_when_processing_errors(sdp->device))) return -ENXIO; @@ -503,20 +522,20 @@ if ((k = verify_area(VERIFY_READ, buf, count))) return k; /* protects following copy_from_user()s + get_user()s */ - if (count < size_sg_header) + if (count < SZ_SG_HEADER) return -EIO; - __copy_from_user(&old_hdr, buf, size_sg_header); + __copy_from_user(&old_hdr, buf, SZ_SG_HEADER); blocking = !(filp->f_flags & O_NONBLOCK); if (old_hdr.reply_len < 0) return sg_new_write(sfp, buf, count, blocking, 0, NULL); - if (count < (size_sg_header + 6)) + if (count < (SZ_SG_HEADER + 6)) return -EIO; /* The minimum scsi command length is 6 bytes. */ if (! (srp = sg_add_request(sfp))) { SCSI_LOG_TIMEOUT(1, printk("sg_write: queue full\n")); return -EDOM; } - buf += size_sg_header; + buf += SZ_SG_HEADER; __get_user(opcode, buf); if (sfp->next_cmd_len > 0) { if (sfp->next_cmd_len > MAX_COMMAND_SIZE) { @@ -539,8 +558,8 @@ input_size = count - cmd_size; mxsize = (input_size > old_hdr.reply_len) ? input_size : old_hdr.reply_len; - mxsize -= size_sg_header; - input_size -= size_sg_header; + mxsize -= SZ_SG_HEADER; + input_size -= SZ_SG_HEADER; if (input_size < 0) { sg_remove_request(sfp, srp); return -EIO; /* User did not pass enough bytes for this command. */ @@ -550,16 +569,12 @@ hp->cmd_len = (unsigned char)cmd_size; hp->iovec_count = 0; hp->mx_sb_len = 0; -#if 0 - hp->dxfer_direction = SG_DXFER_UNKNOWN; -#else if (input_size > 0) - hp->dxfer_direction = ((old_hdr.reply_len - size_sg_header) > 0) ? + hp->dxfer_direction = ((old_hdr.reply_len - SZ_SG_HEADER) > 0) ? SG_DXFER_TO_FROM_DEV : SG_DXFER_TO_DEV; else hp->dxfer_direction = (mxsize > 0) ? SG_DXFER_FROM_DEV : SG_DXFER_NONE; -#endif hp->dxfer_len = mxsize; hp->dxferp = (unsigned char *)buf + cmd_size; hp->sbp = NULL; @@ -581,7 +596,7 @@ unsigned char cmnd[sizeof(dummy_cmdp->sr_cmnd)]; int timeout; - if (count < size_sg_io_hdr) + if (count < SZ_SG_IO_HDR) return -EINVAL; if ((k = verify_area(VERIFY_READ, buf, count))) return k; /* protects following copy_from_user()s + get_user()s */ @@ -592,7 +607,7 @@ return -EDOM; } hp = &srp->header; - __copy_from_user(hp, buf, size_sg_io_hdr); + __copy_from_user(hp, buf, SZ_SG_IO_HDR); if (hp->interface_id != 'S') { sg_remove_request(sfp, srp); return -ENOSYS; @@ -648,7 +663,10 @@ sg_finish_rem_req(srp); return k; } -/* SCSI_LOG_TIMEOUT(7, printk("sg_write: allocating device\n")); */ + if (sdp->detached) { + sg_finish_rem_req(srp); + return -ENODEV; + } SRpnt = scsi_allocate_request(sdp->device); if(SRpnt == NULL) { SCSI_LOG_TIMEOUT(1, printk("sg_write: no mem\n")); @@ -656,17 +674,15 @@ return -ENOMEM; } -/* SCSI_LOG_TIMEOUT(7, printk("sg_write: device allocated\n")); */ srp->my_cmdp = SRpnt; SRpnt->sr_request.rq_dev = sdp->i_rdev; SRpnt->sr_request.rq_status = RQ_ACTIVE; SRpnt->sr_sense_buffer[0] = 0; SRpnt->sr_cmd_len = hp->cmd_len; -/* Set the LUN field in the command structure, overriding user input */ - if (! (hp->flags & SG_FLAG_LUN_INHIBIT)) - cmnd[1] = (cmnd[1] & 0x1f) | (sdp->device->lun << 5); - -/* SCSI_LOG_TIMEOUT(7, printk("sg_write: do cmd\n")); */ + if (! (hp->flags & SG_FLAG_LUN_INHIBIT)) { + if (sdp->device->scsi_level <= SCSI_2) + cmnd[1] = (cmnd[1] & 0x1f) | (sdp->device->lun << 5); + } SRpnt->sr_use_sg = srp->data.k_use_sg; SRpnt->sr_sglist_len = srp->data.sglist_len; SRpnt->sr_bufflen = srp->data.bufflen; @@ -719,30 +735,31 @@ { int blocking = 1; /* ignore O_NONBLOCK flag */ + if (sdp->detached) + return -ENODEV; if(! scsi_block_when_processing_errors(sdp->device) ) return -ENXIO; - result = verify_area(VERIFY_WRITE, (void *)arg, size_sg_io_hdr); + result = verify_area(VERIFY_WRITE, (void *)arg, SZ_SG_IO_HDR); if (result) return result; - result = sg_new_write(sfp, (const char *)arg, size_sg_io_hdr, + result = sg_new_write(sfp, (const char *)arg, SZ_SG_IO_HDR, blocking, read_only, &srp); if (result < 0) return result; srp->sg_io_owned = 1; while (1) { - int dio = sg_dio_in_use(sfp); result = 0; /* following macro to beat race condition */ __wait_event_interruptible(sfp->read_wait, - (sfp->closed || srp->done), result); + (sdp->detached || sfp->closed || srp->done), result); + if (sdp->detached) + return -ENODEV; if (sfp->closed) return 0; /* request packet dropped already */ if (0 == result) break; - else if (! dio) { /* only let signal out if no dio */ - srp->orphan = 1; - return result; /* -ERESTARTSYS because signal hit process */ - } + srp->orphan = 1; + return result; /* -ERESTARTSYS because signal hit process */ } srp->done = 2; - result = sg_new_read(sfp, (char *)arg, size_sg_io_hdr, srp); + result = sg_new_read(sfp, (char *)arg, SZ_SG_IO_HDR, srp); return (result < 0) ? result : 0; } case SG_SET_TIMEOUT: @@ -765,8 +782,11 @@ sg_build_reserve(sfp, val); } } - else + else { + if (sdp->detached) + return -ENODEV; sfp->low_dma = sdp->device->host->unchecked_isa_dma; + } return 0; case SG_GET_LOW_DMA: return put_user((int)sfp->low_dma, (int *)arg); @@ -775,6 +795,9 @@ if (result) return result; else { sg_scsi_id_t * sg_idp = (sg_scsi_id_t *)arg; + + if (sdp->detached) + return -ENODEV; __put_user((int)sdp->device->host->host_no, &sg_idp->host_no); __put_user((int)sdp->device->channel, &sg_idp->channel); __put_user((int)sdp->device->id, &sg_idp->scsi_id); @@ -853,7 +876,7 @@ return put_user(sg_version_num, (int *)arg); case SG_GET_REQUEST_TABLE: result = verify_area(VERIFY_WRITE, (void *) arg, - size_sg_req_info * SG_MAX_QUEUE); + SZ_SG_REQ_INFO * SG_MAX_QUEUE); if (result) return result; else { sg_req_info_t rinfo[SG_MAX_QUEUE]; @@ -861,7 +884,7 @@ read_lock_irqsave(&sfp->rq_list_lock, iflags); for (srp = sfp->headrp, val = 0; val < SG_MAX_QUEUE; ++val, srp = srp ? srp->nextrp : srp) { - memset(&rinfo[val], 0, size_sg_req_info); + memset(&rinfo[val], 0, SZ_SG_REQ_INFO); if (srp) { rinfo[val].req_state = srp->done + 1; rinfo[val].problem = srp->header.masked_status & @@ -876,12 +899,16 @@ } } read_unlock_irqrestore(&sfp->rq_list_lock, iflags); - __copy_to_user((void *)arg, rinfo, size_sg_req_info * SG_MAX_QUEUE); + __copy_to_user((void *)arg, rinfo, SZ_SG_REQ_INFO * SG_MAX_QUEUE); return 0; } case SG_EMULATED_HOST: + if (sdp->detached) + return -ENODEV; return put_user(sdp->device->host->hostt->emulated, (int *)arg); case SG_SCSI_RESET: + if (sdp->detached) + return -ENODEV; if (filp->f_flags & O_NONBLOCK) { if (sdp->device->host->in_recovery) return -EBUSY; @@ -907,13 +934,16 @@ default: return -EINVAL; } - if(! capable(CAP_SYS_ADMIN)) return -EACCES; + if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) + return -EACCES; return (scsi_reset_provider(sdp->device, val) == SUCCESS) ? 0 : -EIO; #else SCSI_LOG_TIMEOUT(1, printk("sg_ioctl: SG_RESET_SCSI not supported\n")); result = -EINVAL; #endif case SCSI_IOCTL_SEND_COMMAND: + if (sdp->detached) + return -ENODEV; if (read_only) { unsigned char opcode = WRITE_6; Scsi_Ioctl_Command * siocp = (void *)arg; @@ -932,6 +962,8 @@ case SCSI_IOCTL_GET_BUS_NUMBER: case SCSI_IOCTL_PROBE_HOST: case SG_GET_TRANSFORM: + if (sdp->detached) + return -ENODEV; return scsi_ioctl(sdp->device, cmd_in, (void *)arg); default: if (read_only) @@ -949,7 +981,8 @@ int count = 0; unsigned long iflags; - if ((! (sfp = (Sg_fd *)filp->private_data)) || (! (sdp = sfp->parentdp))) + if ((! (sfp = (Sg_fd *)filp->private_data)) || (! (sdp = sfp->parentdp)) + || sfp->closed) return POLLERR; poll_wait(filp, &sfp->read_wait, wait); read_lock_irqsave(&sfp->rq_list_lock, iflags); @@ -960,7 +993,10 @@ ++count; } read_unlock_irqrestore(&sfp->rq_list_lock, iflags); - if (! sfp->cmd_q) { + + if (sdp->detached) + res |= POLLHUP; + else if (! sfp->cmd_q) { if (0 == count) res |= POLLOUT | POLLWRNORM; } @@ -1001,9 +1037,9 @@ if (dev < sg_template.dev_max) sdp = sg_dev_arr[dev]; } - if (NULL == sdp) { + if ((NULL == sdp) || sdp->detached) { read_unlock(&sg_dev_arr_lock); - SCSI_LOG_TIMEOUT(1, printk("sg...bh: bad args dev=%d\n", dev)); + SCSI_LOG_TIMEOUT(1, printk("sg...bh: dev=%d gone\n", dev)); scsi_release_request(SRpnt); SRpnt = NULL; return; @@ -1020,8 +1056,8 @@ break; sfp = sfp->nextfp; } - read_unlock(&sg_dev_arr_lock); if (! srp) { + read_unlock(&sg_dev_arr_lock); SCSI_LOG_TIMEOUT(1, printk("sg...bh: req missing, dev=%d\n", dev)); scsi_release_request(SRpnt); SRpnt = NULL; @@ -1035,6 +1071,7 @@ sg_clr_srpnt(SRpnt); srp->my_cmdp = NULL; srp->done = 1; + read_unlock(&sg_dev_arr_lock); SCSI_LOG_TIMEOUT(4, printk("sg...bh: dev=%d, pack_id=%d, res=0x%x\n", dev, srp->header.pack_id, (int)SRpnt->sr_result)); @@ -1071,7 +1108,6 @@ if (sfp->closed) { /* whoops this fd already released, cleanup */ SCSI_LOG_TIMEOUT(1, printk("sg...bh: already closed, freeing ...\n")); - /* should check if module is unloaded <<<<<<< */ sg_finish_rem_req(srp); srp = NULL; if (NULL == sfp->headrp) { @@ -1080,6 +1116,10 @@ sg_remove_sfp(sdp, sfp); sfp = NULL; } + if (sg_template.module) + __MOD_DEC_USE_COUNT(sg_template.module); + if (sdp->device->host->hostt->module) + __MOD_DEC_USE_COUNT(sdp->device->host->hostt->module); } else if (srp && srp->orphan) { if (sfp->keep_orphan) @@ -1110,19 +1150,6 @@ static int sg_detect(Scsi_Device * scsidp) { - switch (scsidp->type) { - case TYPE_DISK: - case TYPE_MOD: - case TYPE_ROM: - case TYPE_WORM: - case TYPE_TAPE: break; - default: - printk("Detected scsi generic sg%d at scsi%d," - " channel %d, id %d, lun %d, type %d\n", - sg_template.dev_noticed, - scsidp->host->host_no, scsidp->channel, - scsidp->id, scsidp->lun, scsidp->type); - } sg_template.dev_noticed++; return 1; } @@ -1241,51 +1268,73 @@ sg_template.nr_dev++; sg_dev_arr[k] = sdp; write_unlock_irqrestore(&sg_dev_arr_lock, iflags); + switch (scsidp->type) { + case TYPE_DISK: + case TYPE_MOD: + case TYPE_ROM: + case TYPE_WORM: + case TYPE_TAPE: break; + default: + printk("Attached scsi generic sg%d at scsi%d, channel %d, id %d," + " lun %d, type %d\n", k, scsidp->host->host_no, + scsidp->channel, scsidp->id, scsidp->lun, scsidp->type); + } return 0; } /* Called at 'finish' of init process, after all attaches */ static void sg_finish(void) -{ - SCSI_LOG_TIMEOUT(3, printk("sg_finish: dma_free_sectors=%u\n", - scsi_dma_free_sectors)); -} +{ } static void sg_detach(Scsi_Device * scsidp) { Sg_device * sdp; unsigned long iflags; Sg_fd * sfp; + Sg_fd * tsfp; Sg_request * srp; - int k; + Sg_request * tsrp; + int k, delay; if (NULL == sg_dev_arr) return; + delay = 0; write_lock_irqsave(&sg_dev_arr_lock, iflags); for (k = 0; k < sg_template.dev_max; k++) { sdp = sg_dev_arr[k]; if ((NULL == sdp) || (sdp->device != scsidp)) continue; /* dirty but lowers nesting */ if (sdp->headfp) { - for (sfp = sdp->headfp; sfp; sfp = sfp->nextfp) { - /* no lock on request list here */ - for (srp = sfp->headrp; srp; srp = srp->nextrp) { - if (! srp->done) { - write_unlock_irqrestore(&sg_dev_arr_lock, iflags); - sg_shorten_timeout(srp->my_cmdp); - write_lock_irqsave(&sg_dev_arr_lock, iflags); - } - } + sdp->detached = 1; + for (sfp = sdp->headfp; sfp; sfp = tsfp) { + tsfp = sfp->nextfp; + for (srp = sfp->headrp; srp; srp = tsrp) { + tsrp = srp->nextrp; + if (sfp->closed || (0 == srp->done)) + sg_finish_rem_req(srp); + } + if (sfp->closed) { + if (sg_template.module) + __MOD_DEC_USE_COUNT(sg_template.module); + if (sdp->device->host->hostt->module) + __MOD_DEC_USE_COUNT(sdp->device->host->hostt->module); + __sg_remove_sfp(sdp, sfp); + } + else { + delay = 1; + wake_up_interruptible(&sfp->read_wait); + kill_fasync(&sfp->async_qp, SIGPOLL, POLL_HUP); + } } - write_unlock_irqrestore(&sg_dev_arr_lock, iflags); - SCSI_LOG_TIMEOUT(3, printk("sg_detach: dev=%d, dirty, sleep(3)\n", k)); - scsi_sleep(3); /* sleep 3 jiffies, hoping for timeout to go off */ + SCSI_LOG_TIMEOUT(3, printk("sg_detach: dev=%d, dirty\n", k)); devfs_unregister (sdp->de); sdp->de = NULL; - sdp->detached = 1; - write_lock_irqsave(&sg_dev_arr_lock, iflags); + if (NULL == sdp->headfp) { + kfree((char *)sdp); + sg_dev_arr[k] = NULL; + } } - else { + else { /* nothing active, simple case */ SCSI_LOG_TIMEOUT(3, printk("sg_detach: dev=%d\n", k)); devfs_unregister (sdp->de); kfree((char *)sdp); @@ -1293,13 +1342,12 @@ } scsidp->attached--; sg_template.nr_dev--; -/* avoid associated device /dev/sg? being incremented - * each time module is inserted/removed , <dan@lectra.fr> */ - sg_template.dev_noticed--; + sg_template.dev_noticed--; /* from <dan@lectra.fr> */ break; } write_unlock_irqrestore(&sg_dev_arr_lock, iflags); - return; + if (delay) + scsi_sleep(2); /* dirty detach so delay device destruction */ } MODULE_AUTHOR("Douglas Gilbert"); @@ -1322,8 +1370,6 @@ scsi_unregister_module(MODULE_SCSI_DEV, &sg_template); devfs_unregister_chrdev(SCSI_GENERIC_MAJOR, "sg"); if(sg_dev_arr != NULL) { -/* Really worrying situation of writes still pending and get here */ -/* Strategy: shorten timeout on release + wait on detach ... */ kfree((char *)sg_dev_arr); sg_dev_arr = NULL; } @@ -1331,29 +1377,6 @@ } -#if 0 -extern void scsi_times_out (Scsi_Cmnd * SCpnt); -extern void scsi_old_times_out (Scsi_Cmnd * SCpnt); -#endif - -/* Can't see clean way to abort a command so shorten timeout to 1 jiffy */ -static void sg_shorten_timeout(Scsi_Request * srpnt) -{ -#if 0 /* scsi_syms.c is very miserly about exported functions */ - scsi_delete_timer(scpnt); - if (! scpnt) - return; - scpnt->timeout_per_command = 1; /* try 1 jiffy (perhaps 0 jiffies) */ - if (scpnt->host->hostt->use_new_eh_code) - scsi_add_timer(scpnt, scpnt->timeout_per_command, scsi_times_out); - else - scsi_add_timer(scpnt, scpnt->timeout_per_command, - scsi_old_times_out); -#else - scsi_sleep(HZ); /* just sleep 1 second and hope ... */ -#endif -} - static int sg_start_req(Sg_request * srp) { int res; @@ -1367,9 +1390,8 @@ SCSI_LOG_TIMEOUT(4, printk("sg_start_req: dxfer_len=%d\n", dxfer_len)); if ((dxfer_len <= 0) || (dxfer_dir == SG_DXFER_NONE)) return 0; - if ((hp->flags & SG_FLAG_DIRECT_IO) && - (dxfer_dir != SG_DXFER_UNKNOWN) && - (0 == hp->iovec_count) && + if (sg_allow_dio && (hp->flags & SG_FLAG_DIRECT_IO) && + (dxfer_dir != SG_DXFER_UNKNOWN) && (0 == hp->iovec_count) && (! sfp->parentdp->device->host->unchecked_isa_dma)) { res = sg_build_dir(srp, sfp, dxfer_len); if (res <= 0) /* -ve -> error, 0 -> done, 1 -> try indirect */ @@ -1427,7 +1449,7 @@ static void sg_unmap_and(Sg_scatter_hold * schp, int free_also) { -#ifdef SG_ALLOW_DIO +#ifdef SG_ALLOW_DIO_CODE if (schp && schp->kiobp) { if (schp->mapped) { unmap_kiobuf(schp->kiobp); @@ -1443,7 +1465,7 @@ static int sg_build_dir(Sg_request * srp, Sg_fd * sfp, int dxfer_len) { -#ifdef SG_ALLOW_DIO +#ifdef SG_ALLOW_DIO_CODE int res, k, split, offset, num, mx_sc_elems, rem_sz; struct kiobuf * kp; char * mem_src_arr; @@ -1519,7 +1541,7 @@ return 0; #else return 1; -#endif /* SG_ALLOW_DIO */ +#endif /* SG_ALLOW_DIO_CODE */ } static int sg_build_indi(Sg_scatter_hold * schp, Sg_fd * sfp, int buff_size) @@ -1629,7 +1651,7 @@ if (iovec_count) { onum = iovec_count; if ((k = verify_area(VERIFY_READ, hp->dxferp, - size_sg_iovec * onum))) + SZ_SG_IOVEC * onum))) return k; } else @@ -1707,8 +1729,8 @@ } else { __copy_from_user(&u_iovec, - (unsigned char *)hp->dxferp + (ind * size_sg_iovec), - size_sg_iovec); + (unsigned char *)hp->dxferp + (ind * SZ_SG_IOVEC), + SZ_SG_IOVEC); p = (unsigned char *)u_iovec.iov_base; count = (int)u_iovec.iov_len; } @@ -1778,7 +1800,7 @@ if (iovec_count) { onum = iovec_count; if ((k = verify_area(VERIFY_READ, hp->dxferp, - size_sg_iovec * onum))) + SZ_SG_IOVEC * onum))) return k; } else @@ -2124,6 +2146,34 @@ return sfp; } +static void __sg_remove_sfp(Sg_device * sdp, Sg_fd * sfp) +{ + Sg_fd * fp; + Sg_fd * prev_fp; + + prev_fp = sdp->headfp; + if (sfp == prev_fp) + sdp->headfp = prev_fp->nextfp; + else { + while ((fp = prev_fp->nextfp)) { + if (sfp == fp) { + prev_fp->nextfp = fp->nextfp; + break; + } + prev_fp = fp; + } + } + if (sfp->reserve.bufflen > 0) { + SCSI_LOG_TIMEOUT(6, printk("__sg_remove_sfp: bufflen=%d, k_use_sg=%d\n", + (int)sfp->reserve.bufflen, (int)sfp->reserve.k_use_sg)); + sg_remove_scat(&sfp->reserve); + } + sfp->parentdp = NULL; + SCSI_LOG_TIMEOUT(6, printk("__sg_remove_sfp: sfp=0x%p\n", sfp)); + sg_low_free((char *)sfp, sizeof(Sg_fd), sfp->fd_mem_src); +} + +/* Returns 0 in normal case, 1 when detached and sdp object removed */ static int sg_remove_sfp(Sg_device * sdp, Sg_fd * sfp) { Sg_request * srp; @@ -2131,44 +2181,18 @@ int dirty = 0; int res = 0; - srp = sfp->headrp; - if (srp) { - while (srp) { - tsrp = srp->nextrp; - if (srp->done) - sg_finish_rem_req(srp); - else - ++dirty; - srp = tsrp; - } + for (srp = sfp->headrp; srp; srp = tsrp) { + tsrp = srp->nextrp; + if (srp->done) + sg_finish_rem_req(srp); + else + ++dirty; } if (0 == dirty) { - Sg_fd * fp; - Sg_fd * prev_fp; unsigned long iflags; write_lock_irqsave(&sg_dev_arr_lock, iflags); - prev_fp = sdp->headfp; - if (sfp == prev_fp) - sdp->headfp = prev_fp->nextfp; - else { - while ((fp = prev_fp->nextfp)) { - if (sfp == fp) { - prev_fp->nextfp = fp->nextfp; - break; - } - prev_fp = fp; - } - } - write_unlock_irqrestore(&sg_dev_arr_lock, iflags); - if (sfp->reserve.bufflen > 0) { -SCSI_LOG_TIMEOUT(6, printk("sg_remove_sfp: bufflen=%d, k_use_sg=%d\n", - (int)sfp->reserve.bufflen, (int)sfp->reserve.k_use_sg)); - sg_remove_scat(&sfp->reserve); - } - sfp->parentdp = NULL; - SCSI_LOG_TIMEOUT(6, printk("sg_remove_sfp: sfp=0x%p\n", sfp)); - sg_low_free((char *)sfp, sizeof(Sg_fd), sfp->fd_mem_src); + __sg_remove_sfp(sdp, sfp); if (sdp->detached && (NULL == sdp->headfp)) { int k, maxd; @@ -2180,11 +2204,17 @@ if (k < maxd) sg_dev_arr[k] = NULL; kfree((char *)sdp); + res = 1; } - res = 1; + write_unlock_irqrestore(&sg_dev_arr_lock, iflags); } else { sfp->closed = 1; /* flag dirty state on this fd */ + /* MOD_INC's to inhibit unloading sg and associated adapter driver */ + if (sg_template.module) + __MOD_INC_USE_COUNT(sg_template.module); + if (sdp->device->host->hostt->module) + __MOD_INC_USE_COUNT(sdp->device->host->hostt->module); SCSI_LOG_TIMEOUT(1, printk( "sg_remove_sfp: worrisome, %d writes pending\n", dirty)); } @@ -2203,31 +2233,15 @@ return srp ? 1 : 0; } -static int sg_dio_in_use(Sg_fd * sfp) -{ - const Sg_request * srp; - unsigned long iflags; - - read_lock_irqsave(&sfp->rq_list_lock, iflags); - for (srp = sfp->headrp; srp; srp = srp->nextrp) - if ((! srp->done) && srp->data.kiobp) break; - read_unlock_irqrestore(&sfp->rq_list_lock, iflags); - return srp ? 1 : 0; -} - /* If retSzp==NULL want exact size or fail */ -/* sg_low_malloc() should always be called from a process context allowing - GFP_KERNEL to be used instead of GFP_ATOMIC */ static char * sg_low_malloc(int rqSz, int lowDma, int mem_src, int * retSzp) { char * resp = NULL; - int page_mask = lowDma ? (GFP_KERNEL | GFP_DMA) : GFP_KERNEL; + int page_mask = lowDma ? (GFP_ATOMIC | GFP_DMA) : GFP_ATOMIC; if (rqSz <= 0) return resp; if (SG_HEAP_KMAL == mem_src) { - page_mask = lowDma ? (GFP_ATOMIC | GFP_DMA) : GFP_ATOMIC; - /* Seen kmalloc(..,GFP_KERNEL) hang for 40 secs! */ resp = kmalloc(rqSz, page_mask); if (resp && retSzp) *retSzp = rqSz; return resp; @@ -2355,7 +2369,7 @@ case SG_USER_MEM: break; /* nothing to do */ default: - printk("sg_low_free: bad mem_src=%d, buff=0x%p, rqSz=%df\n", + printk("sg_low_free: bad mem_src=%d, buff=0x%p, rqSz=%d\n", mem_src, buff, size); break; } @@ -2451,11 +2465,17 @@ static struct proc_dir_entry * sg_proc_sgp = NULL; -static const char * sg_proc_sg_dirname = "sg"; -static const char * sg_proc_leaf_names[] = {"def_reserved_size", "debug", - "devices", "device_hdr", "device_strs", - "hosts", "host_hdr", "host_strs", "version"}; +static char sg_proc_sg_dirname[] = "sg"; +static const char * sg_proc_leaf_names[] = {"allow_dio", "def_reserved_size", + "debug", "devices", "device_hdr", "device_strs", + "hosts", "host_hdr", "host_strs", "version"}; +static int sg_proc_adio_read(char * buffer, char ** start, off_t offset, + int size, int * eof, void * data); +static int sg_proc_adio_info(char * buffer, int * len, off_t * begin, + off_t offset, int size); +static int sg_proc_adio_write(struct file * filp, const char * buffer, + unsigned long count, void * data); static int sg_proc_dressz_read(char * buffer, char ** start, off_t offset, int size, int * eof, void * data); static int sg_proc_dressz_info(char * buffer, int * len, off_t * begin, @@ -2495,12 +2515,12 @@ static int sg_proc_version_info(char * buffer, int * len, off_t * begin, off_t offset, int size); static read_proc_t * sg_proc_leaf_reads[] = { - sg_proc_dressz_read, sg_proc_debug_read, + sg_proc_adio_read, sg_proc_dressz_read, sg_proc_debug_read, sg_proc_dev_read, sg_proc_devhdr_read, sg_proc_devstrs_read, sg_proc_host_read, sg_proc_hosthdr_read, sg_proc_hoststrs_read, sg_proc_version_read}; static write_proc_t * sg_proc_leaf_writes[] = { - sg_proc_dressz_write, 0, 0, 0, 0, 0, 0, 0, 0}; + sg_proc_adio_write, sg_proc_dressz_write, 0, 0, 0, 0, 0, 0, 0, 0}; #define PRINT_PROC(fmt,args...) \ do { \ @@ -2562,6 +2582,32 @@ remove_proc_entry(sg_proc_sg_dirname, proc_scsi); } +static int sg_proc_adio_read(char * buffer, char ** start, off_t offset, + int size, int * eof, void * data) +{ SG_PROC_READ_FN(sg_proc_adio_info); } + +static int sg_proc_adio_info(char * buffer, int * len, off_t * begin, + off_t offset, int size) +{ + PRINT_PROC("%d\n", sg_allow_dio); + return 1; +} + +static int sg_proc_adio_write(struct file * filp, const char * buffer, + unsigned long count, void * data) +{ + int num; + char buff[11]; + + if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) + return -EACCES; + num = (count < 10) ? count : 10; + copy_from_user(buff, buffer, num); + buff[num] = '\0'; + sg_allow_dio = simple_strtoul(buff, 0, 10) ? 1 : 0; + return count; +} + static int sg_proc_dressz_read(char * buffer, char ** start, off_t offset, int size, int * eof, void * data) { SG_PROC_READ_FN(sg_proc_dressz_info); } @@ -2580,7 +2626,7 @@ unsigned long k = ULONG_MAX; char buff[11]; - if (! capable(CAP_SYS_ADMIN)) + if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) return -EACCES; num = (count < 10) ? count : 10; copy_from_user(buff, buffer, num); @@ -2620,8 +2666,9 @@ Sg_request * srp; struct scsi_device * scsidp; int dev, k, m, blen, usg; - - if (! (scsidp = sdp->device)) { + + scsidp = sdp->device; + if (NULL == scsidp) { PRINT_PROC("device %d detached ??\n", j); continue; } @@ -2629,10 +2676,14 @@ if (sg_get_nth_sfp(sdp, 0)) { PRINT_PROC(" >>> device=sg%d ", dev); - PRINT_PROC("scsi%d chan=%d id=%d lun=%d em=%d sg_tablesize=%d" - " excl=%d\n", scsidp->host->host_no, scsidp->channel, - scsidp->id, scsidp->lun, scsidp->host->hostt->emulated, - sdp->sg_tablesize, sdp->exclude); + if (sdp->detached) + PRINT_PROC("detached pending close "); + else + PRINT_PROC("scsi%d chan=%d id=%d lun=%d em=%d", + scsidp->host->host_no, scsidp->channel, + scsidp->id, scsidp->lun, scsidp->host->hostt->emulated); + PRINT_PROC(" sg_tablesize=%d excl=%d\n", sdp->sg_tablesize, + sdp->exclude); } for (k = 0; (fp = sg_get_nth_sfp(sdp, k)); ++k) { PRINT_PROC(" FD(%d): timeout=%dms bufflen=%d " @@ -2683,13 +2734,14 @@ max_dev = sg_last_dev(); for (j = 0; j < max_dev; ++j) { sdp = sg_get_dev(j); - if (sdp && (scsidp = sdp->device)) - PRINT_PROC("%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\n", + if (sdp && (scsidp = sdp->device) && (! sdp->detached)) + PRINT_PROC("%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\n", scsidp->host->host_no, scsidp->channel, scsidp->id, scsidp->lun, (int)scsidp->type, (int)scsidp->access_count, - (int)scsidp->queue_depth, (int)scsidp->device_busy); + (int)scsidp->queue_depth, (int)scsidp->device_busy, + (int)scsidp->online); else - PRINT_PROC("-1\t-1\t-1\t-1\t-1\t-1\t-1\t-1\n"); + PRINT_PROC("-1\t-1\t-1\t-1\t-1\t-1\t-1\t-1\t-1\n"); } return 1; } @@ -2701,7 +2753,7 @@ static int sg_proc_devhdr_info(char * buffer, int * len, off_t * begin, off_t offset, int size) { - PRINT_PROC("host\tchan\tid\tlun\ttype\tbopens\tqdepth\tbusy\n"); + PRINT_PROC("host\tchan\tid\tlun\ttype\tbopens\tqdepth\tbusy\tonline\n"); return 1; } @@ -2719,7 +2771,7 @@ max_dev = sg_last_dev(); for (j = 0; j < max_dev; ++j) { sdp = sg_get_dev(j); - if (sdp && (scsidp = sdp->device)) + if (sdp && (scsidp = sdp->device) && (! sdp->detached)) PRINT_PROC("%8.8s\t%16.16s\t%4.4s\n", scsidp->vendor, scsidp->model, scsidp->rev); else diff -u --recursive --new-file v2.4.6/linux/drivers/scsi/sr.c linux/drivers/scsi/sr.c --- v2.4.6/linux/drivers/scsi/sr.c Sat Apr 28 11:28:08 2001 +++ linux/drivers/scsi/sr.c Thu Jul 5 11:28:17 2001 @@ -88,6 +88,7 @@ static int *sr_sizes; static int *sr_blocksizes; +static int *sr_hardsizes; static int sr_open(struct cdrom_device_info *, int); void get_sectorsize(int); @@ -262,7 +263,7 @@ static int sr_scatter_pad(Scsi_Cmnd *SCpnt, int s_size) { struct scatterlist *sg, *old_sg = NULL; - int i, fsize, bsize, sg_ent; + int i, fsize, bsize, sg_ent, sg_count; char *front, *back; back = front = NULL; @@ -290,17 +291,24 @@ /* * extend or allocate new scatter-gather table */ - if (SCpnt->use_sg) + sg_count = SCpnt->use_sg; + if (sg_count) old_sg = (struct scatterlist *) SCpnt->request_buffer; else { - SCpnt->use_sg = 1; + sg_count = 1; sg_ent++; } - SCpnt->sglist_len = ((sg_ent * sizeof(struct scatterlist)) + 511) & ~511; - if ((sg = scsi_malloc(SCpnt->sglist_len)) == NULL) + i = ((sg_ent * sizeof(struct scatterlist)) + 511) & ~511; + if ((sg = scsi_malloc(i)) == NULL) goto no_mem; + /* + * no more failing memory allocs possible, we can safely assign + * SCpnt values now + */ + SCpnt->sglist_len = i; + SCpnt->use_sg = sg_count; memset(sg, 0, SCpnt->sglist_len); i = 0; @@ -343,12 +351,12 @@ static int sr_init_command(Scsi_Cmnd * SCpnt) { - int dev, devm, block, this_count, s_size; + int dev, devm, block=0, this_count, s_size; devm = MINOR(SCpnt->request.rq_dev); dev = DEVICE_NR(SCpnt->request.rq_dev); - SCSI_LOG_HLQUEUE(1, printk("Doing sr request, dev = %d\n", devm)); + SCSI_LOG_HLQUEUE(1, printk("Doing sr request, dev = %d, block = %d\n", devm, block)); if (dev >= sr_template.nr_dev || !scsi_CDs[dev].device || @@ -415,7 +423,8 @@ (SCpnt->request.cmd == WRITE) ? "writing" : "reading", this_count, SCpnt->request.nr_sectors)); - SCpnt->cmnd[1] = (SCpnt->lun << 5) & 0xe0; + SCpnt->cmnd[1] = (SCpnt->device->scsi_level <= SCSI_2) ? + ((SCpnt->lun << 5) & 0xe0) : 0; if (this_count > 0xffff) this_count = 0xffff; @@ -501,11 +510,7 @@ if (SDp->type != TYPE_ROM && SDp->type != TYPE_WORM) return 0; - - printk("Detected scsi CD-ROM sr%d at scsi%d, channel %d, id %d, lun %d\n", - sr_template.dev_noticed++, - SDp->host->host_no, SDp->channel, SDp->id, SDp->lun); - + sr_template.dev_noticed++; return 1; } @@ -534,6 +539,9 @@ sr_template.nr_dev++; if (sr_template.nr_dev > sr_template.dev_max) panic("scsi_devices corrupt (sr)"); + + printk("Attached scsi CD-ROM sr%d at scsi%d, channel %d, id %d, lun %d\n", + i, SDp->host->host_no, SDp->channel, SDp->id, SDp->lun); return 0; } @@ -564,7 +572,8 @@ retries = 3; do { cmd[0] = READ_CAPACITY; - cmd[1] = (scsi_CDs[i].device->lun << 5) & 0xe0; + cmd[1] = (scsi_CDs[i].device->scsi_level <= SCSI_2) ? + ((scsi_CDs[i].device->lun << 5) & 0xe0) : 0; memset((void *) &cmd[2], 0, 8); SRpnt->sr_request.rq_status = RQ_SCSI_BUSY; /* Mark as really busy */ SRpnt->sr_cmd_len = 0; @@ -593,7 +602,7 @@ } else { #if 0 if (cdrom_get_last_written(MKDEV(MAJOR_NR, i), - (long *) &scsi_CDs[i].capacity)) + &scsi_CDs[i].capacity)) #endif scsi_CDs[i].capacity = 1 + ((buffer[0] << 24) | (buffer[1] << 16) | @@ -656,8 +665,14 @@ }; buffer = (unsigned char *) scsi_malloc(512); + if (!buffer) + { + printk(KERN_ERR "sr: out of memory.\n"); + return; + } cmd[0] = MODE_SENSE; - cmd[1] = (scsi_CDs[i].device->lun << 5) & 0xe0; + cmd[1] = (scsi_CDs[i].device->scsi_level <= SCSI_2) ? + ((scsi_CDs[i].device->lun << 5) & 0xe0) : 0; cmd[2] = 0x2a; cmd[4] = 128; cmd[3] = cmd[5] = 0; @@ -734,7 +749,8 @@ Scsi_Device *device = scsi_CDs[MINOR(cdi->dev)].device; /* set the LUN */ - cgc->cmd[1] |= device->lun << 5; + if (device->scsi_level <= SCSI_2) + cgc->cmd[1] |= device->lun << 5; cgc->stat = sr_do_ioctl(MINOR(cdi->dev), cgc->cmd, cgc->buffer, cgc->buflen, cgc->quiet, cgc->data_direction, cgc->sense); @@ -775,16 +791,21 @@ if (!sr_blocksizes) goto cleanup_sizes; + sr_hardsizes = kmalloc(sr_template.dev_max * sizeof(int), GFP_ATOMIC); + if (!sr_hardsizes) + goto cleanup_blocksizes; /* * These are good guesses for the time being. - * Don't set sr_hardsizes here! That will prevent reading anything smaller. */ for (i = 0; i < sr_template.dev_max; i++) { sr_blocksizes[i] = 2048; + sr_hardsizes[i] = 2048; } blksize_size[MAJOR_NR] = sr_blocksizes; + hardsect_size[MAJOR_NR] = sr_hardsizes; return 0; - +cleanup_blocksizes: + kfree(sr_blocksizes); cleanup_sizes: kfree(sr_sizes); cleanup_cds: @@ -830,6 +851,10 @@ scsi_CDs[i].cdi.dev = MKDEV(MAJOR_NR, i); scsi_CDs[i].cdi.mask = 0; scsi_CDs[i].cdi.capacity = 1; + /* + * FIXME: someone needs to handle a get_capabilities + * failure properly ?? + */ get_capabilities(i); sr_vendor_init(i); @@ -903,8 +928,11 @@ kfree(sr_blocksizes); sr_blocksizes = NULL; + kfree(sr_hardsizes); + sr_hardsizes = NULL; } blksize_size[MAJOR_NR] = NULL; + hardsect_size[MAJOR_NR] = NULL; blk_size[MAJOR_NR] = NULL; read_ahead[MAJOR_NR] = 0; diff -u --recursive --new-file v2.4.6/linux/drivers/scsi/sr_ioctl.c linux/drivers/scsi/sr_ioctl.c --- v2.4.6/linux/drivers/scsi/sr_ioctl.c Fri Dec 29 14:07:22 2000 +++ linux/drivers/scsi/sr_ioctl.c Thu Jul 5 11:28:17 2001 @@ -85,6 +85,10 @@ SDev = scsi_CDs[target].device; SRpnt = scsi_allocate_request(scsi_CDs[target].device); + if (!SRpnt) { + printk("Unable to allocate SCSI request in sr_do_ioctl"); + return -ENOMEM; + } SRpnt->sr_data_direction = readwrite; /* use ISA DMA buffer if necessary */ @@ -191,7 +195,8 @@ u_char sr_cmd[10]; sr_cmd[0] = GPCMD_TEST_UNIT_READY; - sr_cmd[1] = ((scsi_CDs[minor].device->lun) << 5); + sr_cmd[1] = (scsi_CDs[minor].device->scsi_level <= SCSI_2) ? + ((scsi_CDs[minor].device->lun) << 5) : 0; sr_cmd[2] = sr_cmd[3] = sr_cmd[4] = sr_cmd[5] = 0; return sr_do_ioctl(minor, sr_cmd, NULL, 0, 1, SCSI_DATA_NONE, NULL); } @@ -201,7 +206,8 @@ u_char sr_cmd[10]; sr_cmd[0] = GPCMD_START_STOP_UNIT; - sr_cmd[1] = ((scsi_CDs[MINOR(cdi->dev)].device->lun) << 5); + sr_cmd[1] = (scsi_CDs[MINOR(cdi->dev)].device->scsi_level <= SCSI_2) ? + ((scsi_CDs[MINOR(cdi->dev)].device->lun) << 5) : 0; sr_cmd[2] = sr_cmd[3] = sr_cmd[5] = 0; sr_cmd[4] = (pos == 0) ? 0x03 /* close */ : 0x02 /* eject */ ; @@ -273,7 +279,8 @@ int result; sr_cmd[0] = GPCMD_READ_SUBCHANNEL; - sr_cmd[1] = ((scsi_CDs[MINOR(cdi->dev)].device->lun) << 5); + sr_cmd[1] = (scsi_CDs[MINOR(cdi->dev)].device->scsi_level <= SCSI_2) ? + ((scsi_CDs[MINOR(cdi->dev)].device->lun) << 5) : 0; sr_cmd[2] = 0x40; /* I do want the subchannel info */ sr_cmd[3] = 0x02; /* Give me medium catalog number info */ sr_cmd[4] = sr_cmd[5] = 0; @@ -307,7 +314,8 @@ memset(sr_cmd, 0, MAX_COMMAND_SIZE); sr_cmd[0] = GPCMD_SET_SPEED; /* SET CD SPEED */ - sr_cmd[1] = (scsi_CDs[MINOR(cdi->dev)].device->lun) << 5; + sr_cmd[1] = (scsi_CDs[MINOR(cdi->dev)].device->scsi_level <= SCSI_2) ? + ((scsi_CDs[MINOR(cdi->dev)].device->lun) << 5) : 0; sr_cmd[2] = (speed >> 8) & 0xff; /* MSB for speed (in kbytes/sec) */ sr_cmd[3] = speed & 0xff; /* LSB */ @@ -336,7 +344,8 @@ struct cdrom_tochdr *tochdr = (struct cdrom_tochdr *) arg; sr_cmd[0] = GPCMD_READ_TOC_PMA_ATIP; - sr_cmd[1] = ((scsi_CDs[target].device->lun) << 5); + sr_cmd[1] = (scsi_CDs[target].device->scsi_level <= SCSI_2) ? + ((scsi_CDs[target].device->lun) << 5) : 0; sr_cmd[2] = sr_cmd[3] = sr_cmd[4] = sr_cmd[5] = 0; sr_cmd[8] = 12; /* LSB of length */ @@ -353,8 +362,9 @@ struct cdrom_tocentry *tocentry = (struct cdrom_tocentry *) arg; sr_cmd[0] = GPCMD_READ_TOC_PMA_ATIP; - sr_cmd[1] = ((scsi_CDs[target].device->lun) << 5) | - (tocentry->cdte_format == CDROM_MSF ? 0x02 : 0); + sr_cmd[1] = (scsi_CDs[target].device->scsi_level <= SCSI_2) ? + ((scsi_CDs[target].device->lun) << 5) : 0; + sr_cmd[1] |= (tocentry->cdte_format == CDROM_MSF) ? 0x02 : 0; sr_cmd[2] = sr_cmd[3] = sr_cmd[4] = sr_cmd[5] = 0; sr_cmd[6] = tocentry->cdte_track; sr_cmd[8] = 12; /* LSB of length */ @@ -379,7 +389,8 @@ struct cdrom_ti* ti = (struct cdrom_ti*)arg; sr_cmd[0] = GPCMD_PLAYAUDIO_TI; - sr_cmd[1] = scsi_CDs[target].device->lun << 5; + sr_cmd[1] = (scsi_CDs[target].device->scsi_level <= SCSI_2) ? + (scsi_CDs[target].device->lun << 5) : 0; sr_cmd[4] = ti->cdti_trk0; sr_cmd[5] = ti->cdti_ind0; sr_cmd[7] = ti->cdti_trk1; @@ -429,7 +440,9 @@ memset(cmd, 0, MAX_COMMAND_SIZE); cmd[0] = GPCMD_READ_CD; /* READ_CD */ - cmd[1] = (scsi_CDs[minor].device->lun << 5) | ((format & 7) << 2); + cmd[1] = (scsi_CDs[minor].device->scsi_level <= SCSI_2) ? + (scsi_CDs[minor].device->lun << 5) : 0; + cmd[1] |= ((format & 7) << 2); cmd[2] = (unsigned char) (lba >> 24) & 0xff; cmd[3] = (unsigned char) (lba >> 16) & 0xff; cmd[4] = (unsigned char) (lba >> 8) & 0xff; @@ -481,7 +494,8 @@ memset(cmd, 0, MAX_COMMAND_SIZE); cmd[0] = GPCMD_READ_10; - cmd[1] = (scsi_CDs[minor].device->lun << 5); + cmd[1] = (scsi_CDs[minor].device->scsi_level <= SCSI_2) ? + (scsi_CDs[minor].device->lun << 5) : 0; cmd[2] = (unsigned char) (lba >> 24) & 0xff; cmd[3] = (unsigned char) (lba >> 16) & 0xff; cmd[4] = (unsigned char) (lba >> 8) & 0xff; @@ -530,6 +544,8 @@ target = MINOR(cdi->dev); switch (cmd) { + case BLKGETSIZE: + return put_user(scsi_CDs[target].capacity >> 1, (long *) arg); case BLKROSET: case BLKROGET: case BLKRASET: diff -u --recursive --new-file v2.4.6/linux/drivers/scsi/sr_vendor.c linux/drivers/scsi/sr_vendor.c --- v2.4.6/linux/drivers/scsi/sr_vendor.c Fri Dec 29 14:07:22 2000 +++ linux/drivers/scsi/sr_vendor.c Thu Jul 5 11:28:17 2001 @@ -124,7 +124,9 @@ #endif memset(cmd, 0, MAX_COMMAND_SIZE); cmd[0] = MODE_SELECT; - cmd[1] = (scsi_CDs[minor].device->lun << 5) | (1 << 4); + cmd[1] = (scsi_CDs[minor].device->scsi_level <= SCSI_2) ? + (scsi_CDs[minor].device->lun << 5) : 0; + cmd[1] |= (1 << 4); cmd[4] = 12; modesel = (struct ccs_modesel_head *) buffer; memset(modesel, 0, sizeof(*modesel)); @@ -173,7 +175,8 @@ case VENDOR_SCSI3: memset(cmd, 0, MAX_COMMAND_SIZE); cmd[0] = READ_TOC; - cmd[1] = (scsi_CDs[minor].device->lun << 5); + cmd[1] = (scsi_CDs[minor].device->scsi_level <= SCSI_2) ? + (scsi_CDs[minor].device->lun << 5) : 0; cmd[8] = 12; cmd[9] = 0x40; rc = sr_do_ioctl(minor, cmd, buffer, 12, 1, SCSI_DATA_READ, NULL); @@ -198,7 +201,9 @@ unsigned long min, sec, frame; memset(cmd, 0, MAX_COMMAND_SIZE); cmd[0] = 0xde; - cmd[1] = (scsi_CDs[minor].device->lun << 5) | 0x03; + cmd[1] = (scsi_CDs[minor].device->scsi_level <= SCSI_2) ? + (scsi_CDs[minor].device->lun << 5) : 0; + cmd[1] |= 0x03; cmd[2] = 0xb0; rc = sr_do_ioctl(minor, cmd, buffer, 0x16, 1, SCSI_DATA_READ, NULL); if (rc != 0) @@ -223,7 +228,9 @@ * where starts the last session ?) */ memset(cmd, 0, MAX_COMMAND_SIZE); cmd[0] = 0xc7; - cmd[1] = (scsi_CDs[minor].device->lun << 5) | 3; + cmd[1] = (scsi_CDs[minor].device->scsi_level <= SCSI_2) ? + (scsi_CDs[minor].device->lun << 5) : 0; + cmd[1] |= 0x03; rc = sr_do_ioctl(minor, cmd, buffer, 4, 1, SCSI_DATA_READ, NULL); if (rc == -EINVAL) { printk(KERN_INFO "sr%d: Hmm, seems the drive " @@ -246,7 +253,8 @@ case VENDOR_WRITER: memset(cmd, 0, MAX_COMMAND_SIZE); cmd[0] = READ_TOC; - cmd[1] = (scsi_CDs[minor].device->lun << 5); + cmd[1] = (scsi_CDs[minor].device->scsi_level <= SCSI_2) ? + (scsi_CDs[minor].device->lun << 5) : 0; cmd[8] = 0x04; cmd[9] = 0x40; rc = sr_do_ioctl(minor, cmd, buffer, 0x04, 1, SCSI_DATA_READ, NULL); @@ -259,7 +267,8 @@ break; } cmd[0] = READ_TOC; /* Read TOC */ - cmd[1] = (scsi_CDs[minor].device->lun << 5); + cmd[1] = (scsi_CDs[minor].device->scsi_level <= SCSI_2) ? + (scsi_CDs[minor].device->lun << 5) : 0; cmd[6] = rc & 0x7f; /* number of last session */ cmd[8] = 0x0c; cmd[9] = 0x40; diff -u --recursive --new-file v2.4.6/linux/drivers/scsi/st.c linux/drivers/scsi/st.c --- v2.4.6/linux/drivers/scsi/st.c Sat Dec 30 11:23:14 2000 +++ linux/drivers/scsi/st.c Thu Jul 19 21:16:32 2001 @@ -328,7 +328,7 @@ (STp->buffer)->last_SRpnt = SCpnt->sc_request; DEB( STp->write_pending = 0; ) - up(SCpnt->request.sem); + complete(SCpnt->request.waiting); } DEB( else if (debugging) @@ -359,8 +359,9 @@ } } - cmd[1] |= (SRpnt->sr_device->lun << 5) & 0xe0; - init_MUTEX_LOCKED(&STp->sem); + if (SRpnt->sr_device->scsi_level <= SCSI_2) + cmd[1] |= (SRpnt->sr_device->lun << 5) & 0xe0; + init_completion(&STp->wait); SRpnt->sr_use_sg = (bytes > (STp->buffer)->sg[0].length) ? (STp->buffer)->use_sg : 0; if (SRpnt->sr_use_sg) { @@ -371,7 +372,7 @@ bp = (STp->buffer)->b_data; SRpnt->sr_data_direction = direction; SRpnt->sr_cmd_len = 0; - SRpnt->sr_request.sem = &(STp->sem); + SRpnt->sr_request.waiting = &(STp->wait); SRpnt->sr_request.rq_status = RQ_SCSI_BUSY; SRpnt->sr_request.rq_dev = STp->devt; @@ -379,8 +380,8 @@ st_sleep_done, timeout, retries); if (do_wait) { - down(SRpnt->sr_request.sem); - SRpnt->sr_request.sem = NULL; + wait_for_completion(SRpnt->sr_request.waiting); + SRpnt->sr_request.waiting = NULL; (STp->buffer)->syscall_result = st_chk_result(STp, SRpnt); } return SRpnt; @@ -402,8 +403,8 @@ STp->nbr_finished++; ) /* end DEB */ - down(&(STp->sem)); - (STp->buffer)->last_SRpnt->sr_request.sem = NULL; + wait_for_completion(&(STp->wait)); + (STp->buffer)->last_SRpnt->sr_request.waiting = NULL; (STp->buffer)->syscall_result = st_chk_result(STp, (STp->buffer)->last_SRpnt); scsi_release_request((STp->buffer)->last_SRpnt); @@ -3495,7 +3496,7 @@ Scsi_Tape *tpnt; ST_mode *STm; ST_partstat *STps; - int i, mode, target_nbr; + int i, mode, target_nbr, dev_num; unsigned long flags = 0; char *stp; @@ -3573,6 +3574,7 @@ } memset(tpnt, 0, sizeof(Scsi_Tape)); scsi_tapes[i] = tpnt; + dev_num = i; for (mode = 0; mode < ST_NBR_MODES; ++mode) { char name[8]; @@ -3653,6 +3655,9 @@ st_template.nr_dev++; write_unlock_irqrestore(&st_dev_arr_lock, flags); + printk(KERN_WARNING + "Attached scsi tape st%d at scsi%d, channel %d, id %d, lun %d\n", + dev_num, SDp->host->host_no, SDp->channel, SDp->id, SDp->lun); /* See if we need to allocate more static buffers */ target_nbr = st_template.nr_dev; @@ -3673,12 +3678,7 @@ { if (SDp->type != TYPE_TAPE || st_incompatible(SDp)) return 0; - - printk(KERN_WARNING - "Detected scsi tape st%d at scsi%d, channel %d, id %d, lun %d\n", - st_template.dev_noticed++, - SDp->host->host_no, SDp->channel, SDp->id, SDp->lun); - + st_template.dev_noticed++; return 1; } diff -u --recursive --new-file v2.4.6/linux/drivers/scsi/st.h linux/drivers/scsi/st.h --- v2.4.6/linux/drivers/scsi/st.h Mon Dec 11 13:19:52 2000 +++ linux/drivers/scsi/st.h Thu Jul 19 21:17:04 2001 @@ -9,6 +9,7 @@ #include "scsi.h" #endif #include <linux/devfs_fs_kernel.h> +#include <linux/completion.h> /* The tape buffer descriptor. */ typedef struct { @@ -67,7 +68,7 @@ kdev_t devt; Scsi_Device *device; struct semaphore lock; /* For serialization */ - struct semaphore sem; /* For SCSI commands */ + struct completion wait; /* For SCSI commands */ ST_buffer *buffer; /* Drive characteristics */ diff -u --recursive --new-file v2.4.6/linux/drivers/scsi/sym53c8xx.c linux/drivers/scsi/sym53c8xx.c --- v2.4.6/linux/drivers/scsi/sym53c8xx.c Tue Jul 3 17:08:21 2001 +++ linux/drivers/scsi/sym53c8xx.c Thu Jul 5 11:28:16 2001 @@ -85,7 +85,7 @@ /* ** Name and version of the driver */ -#define SCSI_NCR_DRIVER_NAME "sym53c8xx-1.7.3a-20010304" +#define SCSI_NCR_DRIVER_NAME "sym53c8xx-1.7.3c-20010512" #define SCSI_NCR_DEBUG_FLAGS (0) @@ -584,6 +584,9 @@ #if LINUX_VERSION_CODE < LinuxVersionCode(2,4,0) #define pci_enable_device(pdev) (0) #endif +#if LINUX_VERSION_CODE < LinuxVersionCode(2,4,4) +#define scsi_set_pci_device(inst, pdev) (0) +#endif /*========================================================== ** @@ -3781,7 +3784,7 @@ SIR_MSG_RECEIVED, }/*-------------------------< MSG_WEIRD_SEEN >------------------*/,{ - SCR_LOAD_REL (scratcha1, 4), /* DUMMY READ */ + SCR_LOAD_REL (scratcha, 4), /* DUMMY READ */ 0, SCR_INT, SIR_MSG_WEIRD, @@ -6591,7 +6594,7 @@ ** **---------------------------------------------------- */ -#if 0 /* This stuff was only usefull for linux-1.2.13 */ +#if 0 /* This stuff was only useful for linux-1.2.13 */ if (lp && !lp->numtags && cmd->device && cmd->device->tagged_queue) { lp->numtags = tp->usrtags; ncr_setup_tags (np, cp->target, cp->lun); @@ -6991,22 +6994,26 @@ u_char istat; int i; + if (!(np->features & FE_ISTAT1) || !(INB (nc_istat1) & SRUN)) + goto do_chip_reset; + OUTB (nc_istat, CABRT); - for (i = 1000000 ; i ; --i) { + for (i = 100000 ; i ; --i) { istat = INB (nc_istat); if (istat & SIP) { INW (nc_sist); - continue; } - if (istat & DIP) { - OUTB (nc_istat, 0); - INB (nc_dstat); - break; + else if (istat & DIP) { + if (INB (nc_dstat) & ABRT); + break; } + UDELAY(5); } + OUTB (nc_istat, 0); if (!i) - printk("%s: unable to abort current chip operation.\n", - ncr_name(np)); + printk("%s: unable to abort current chip operation, " + "ISTAT=0x%02x.\n", ncr_name(np), istat); +do_chip_reset: ncr_chip_reset(np); } @@ -7419,10 +7426,10 @@ /* ** On standard INQUIRY response (EVPD and CmDt ** not set), setup logical unit according to - ** announced capabilities (we need the 1rst 7 bytes). + ** announced capabilities (we need the 1rst 8 bytes). */ if (cmd->cmnd[0] == 0x12 && !(cmd->cmnd[1] & 0x3) && - cmd->cmnd[4] >= 7 && !cmd->use_sg) { + cmd->request_bufflen - cp->resid > 7 && !cmd->use_sg) { sync_scsi_data(np, cmd); /* SYNC the data */ ncr_setup_lcb (np, cp->target, cp->lun, (char *) cmd->request_buffer); @@ -7959,7 +7966,7 @@ */ fak = (kpc - 1) / div_10M[div] + 1; -#if 0 /* This optimization does not seem very usefull */ +#if 0 /* This optimization does not seem very useful */ per = (fak * div_10M[div]) / clk; @@ -8685,7 +8692,7 @@ ** scntl3: (see the manual) ** ** current script command: -** dsp: script adress (relative to start of script). +** dsp: script address (relative to start of script). ** dbc: first word of script command. ** ** First 24 register of the chip: @@ -9535,7 +9542,7 @@ #ifdef SYM_DEBUG_PM_WITH_WSR PRINT_ADDR(cp); - printf ("MA interrupt with WSR set - " + printk ("MA interrupt with WSR set - " "pm->sg.addr=%x - pm->sg.size=%d\n", pm->sg.addr, pm->sg.size); #endif @@ -10167,14 +10174,16 @@ if (i >= MAX_START*2) i = 0; } - assert(k != -1); - if (k != 1) { + /* + ** If job removed, repair the start queue. + */ + if (k != -1) { np->squeue[k] = np->squeue[i]; /* Idle task */ np->squeueput = k; /* Start queue pointer */ - cp->host_status = HS_ABORTED; - cp->scsi_status = S_ILLEGAL; - ncr_complete(np, cp); } + cp->host_status = HS_ABORTED; + cp->scsi_status = S_ILLEGAL; + ncr_complete(np, cp); } break; /* @@ -10730,7 +10739,7 @@ ** Was Sie schon immer ueber transfermode negotiation wissen wollten ... ** ** We try to negotiate sync and wide transfer only after -** a successfull inquire command. We look at byte 7 of the +** a successful inquire command. We look at byte 7 of the ** inquire data to determine the capabilities of the target. ** ** When we try to negotiate, we append the negotiation message @@ -11571,7 +11580,7 @@ /*========================================================== ** ** -** Aquire a control block +** Acquire a control block ** ** **========================================================== @@ -12223,6 +12232,7 @@ static int __init ncr_snooptest (struct ncb* np) { u_int32 ncr_rd, ncr_wr, ncr_bk, host_rd, host_wr, pc; + u_char dstat; int i, err=0; #ifndef SCSI_NCR_IOMAPPED if (np->reg) { @@ -12230,6 +12240,12 @@ if (err) return (err); } #endif +restart_test: + /* + ** Enable Master Parity Checking as we intend + ** to enable it for normal operations. + */ + OUTB (nc_ctest4, (np->rv_ctest4 & MPEE)); /* ** init */ @@ -12252,6 +12268,27 @@ for (i=0; i<NCR_SNOOP_TIMEOUT; i++) if (INB(nc_istat) & (INTF|SIP|DIP)) break; + if (i>=NCR_SNOOP_TIMEOUT) { + printk ("CACHE TEST FAILED: timeout.\n"); + return (0x20); + }; + /* + ** Check for fatal DMA errors. + */ + dstat = INB (nc_dstat); +#if 1 /* Band aiding for broken hardwares that fail PCI parity */ + if ((dstat & MDPE) && (np->rv_ctest4 & MPEE)) { + printk ("%s: PCI DATA PARITY ERROR DETECTED - " + "DISABLING MASTER DATA PARITY CHECKING.\n", + ncr_name(np)); + np->rv_ctest4 &= ~MPEE; + goto restart_test; + } +#endif + if (dstat & (MDPE|BF|IID)) { + printk ("CACHE TEST FAILED: DMA error (dstat=0x%02x).", dstat); + return (0x80); + } /* ** Save termination position. */ @@ -12262,14 +12299,6 @@ host_rd = scr_to_cpu(np->ncr_cache); ncr_rd = INL (nc_scratcha); ncr_bk = INL (nc_temp); - - /* - ** check for timeout - */ - if (i>=NCR_SNOOP_TIMEOUT) { - printk ("CACHE TEST FAILED: timeout.\n"); - return (0x20); - }; /* ** Check termination position. */ @@ -14381,7 +14410,7 @@ /* save current state of GPCNTL and GPREG */ old_gpreg = INB (nc_gpreg); old_gpcntl = INB (nc_gpcntl); - gpcntl = old_gpcntl & 0xfc; + gpcntl = old_gpcntl & 0x1c; /* set up GPREG & GPCNTL to set GPIO0 and GPIO1 in to known state */ OUTB (nc_gpreg, old_gpreg); diff -u --recursive --new-file v2.4.6/linux/drivers/scsi/sym53c8xx_comm.h linux/drivers/scsi/sym53c8xx_comm.h --- v2.4.6/linux/drivers/scsi/sym53c8xx_comm.h Tue Mar 6 19:34:25 2001 +++ linux/drivers/scsi/sym53c8xx_comm.h Thu Jul 5 11:28:16 2001 @@ -403,6 +403,9 @@ #if LINUX_VERSION_CODE < LinuxVersionCode(2,4,0) #define pci_enable_device(pdev) (0) #endif +#if LINUX_VERSION_CODE < LinuxVersionCode(2,4,4) +#define scsi_set_pci_device(inst, pdev) (0) +#endif /*========================================================== ** @@ -1311,7 +1314,7 @@ /* save current state of GPCNTL and GPREG */ old_gpreg = INB (nc_gpreg); old_gpcntl = INB (nc_gpcntl); - gpcntl = old_gpcntl & 0xfc; + gpcntl = old_gpcntl & 0x1c; /* set up GPREG & GPCNTL to set GPIO0 and GPIO1 in to known state */ OUTB (nc_gpreg, old_gpreg); diff -u --recursive --new-file v2.4.6/linux/drivers/scsi/sym53c8xx_defs.h linux/drivers/scsi/sym53c8xx_defs.h --- v2.4.6/linux/drivers/scsi/sym53c8xx_defs.h Fri May 25 18:02:55 2001 +++ linux/drivers/scsi/sym53c8xx_defs.h Fri Jul 20 12:56:01 2001 @@ -168,16 +168,17 @@ #endif /* - * Use normal IO if configured. Forced for alpha and powerpc. - * Powerpc fails copying to on-chip RAM using memcpy_toio(). + * Use normal IO if configured. Forced for alpha. */ #if defined(CONFIG_SCSI_NCR53C8XX_IOMAPPED) #define SCSI_NCR_IOMAPPED #elif defined(__alpha__) #define SCSI_NCR_IOMAPPED #elif defined(__powerpc__) +#if LINUX_VERSION_CODE <= LinuxVersionCode(2,4,3) #define SCSI_NCR_IOMAPPED #define SCSI_NCR_PCI_MEM_NOT_SUPPORTED +#endif #elif defined(__sparc__) #undef SCSI_NCR_IOMAPPED #endif @@ -734,7 +735,7 @@ #define FE_PFEN (1<<12) /* Prefetch enable */ #define FE_LDSTR (1<<13) /* Load/Store supported */ #define FE_RAM (1<<14) /* On chip RAM present */ -#define FE_VARCLK (1<<15) /* SCSI lock may vary */ +#define FE_VARCLK (1<<15) /* SCSI clock may vary */ #define FE_RAM8K (1<<16) /* On chip RAM sized 8Kb */ #define FE_64BIT (1<<17) /* Have a 64-bit PCI interface */ #define FE_IO256 (1<<18) /* Requires full 256 bytes in PCI space */ @@ -744,6 +745,7 @@ #define FE_ULTRA3 (1<<22) /* Ultra-3 80Mtrans/sec */ #define FE_66MHZ (1<<23) /* 66MHz PCI Support */ #define FE_DAC (1<<24) /* Support DAC cycles (64 bit addressing) */ +#define FE_ISTAT1 (1<<25) /* Have ISTAT1, MBOX0, MBOX1 registers */ #define FE_CACHE_SET (FE_ERL|FE_CLSE|FE_WRIE|FE_ERMP) #define FE_SCSI_SET (FE_WIDE|FE_ULTRA|FE_ULTRA2|FE_DBLR|FE_QUAD|F_CLK80) @@ -808,7 +810,7 @@ , \ {PCI_DEVICE_ID_NCR_53C896, 0xff, "896", 6, 31, 7, \ FE_WIDE|FE_ULTRA2|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN| \ - FE_RAM|FE_RAM8K|FE_64BIT|FE_DAC|FE_IO256|FE_NOPM|FE_LEDC} \ + FE_RAM|FE_RAM8K|FE_64BIT|FE_DAC|FE_IO256|FE_NOPM|FE_LEDC|FE_ISTAT1} \ , \ {PCI_DEVICE_ID_NCR_53C895A, 0xff, "895a", 6, 31, 7, \ FE_WIDE|FE_ULTRA2|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN| \ @@ -823,11 +825,11 @@ FE_RAM|FE_IO256} \ , \ {PCI_DEVICE_ID_LSI_53C1010, 0xff, "1010-33", 6, 62, 7, \ - FE_WIDE|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN| \ + FE_WIDE|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|FE_ISTAT1| \ FE_RAM|FE_RAM8K|FE_64BIT|FE_DAC|FE_IO256|FE_NOPM|FE_LEDC|FE_ULTRA3} \ , \ {PCI_DEVICE_ID_LSI_53C1010_66, 0xff, "1010-66", 6, 62, 7, \ - FE_WIDE|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN| \ + FE_WIDE|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|FE_ISTAT1| \ FE_RAM|FE_RAM8K|FE_64BIT|FE_DAC|FE_IO256|FE_NOPM|FE_LEDC|FE_ULTRA3| \ FE_66MHZ} \ } @@ -1179,9 +1181,13 @@ #define SIP 0x02 /* sta: scsi-interrupt */ #define DIP 0x01 /* sta: host/script interrupt */ -/*15*/ u_char nc_istat1; /* 896 only */ -/*16*/ u_char nc_mbox0; /* 896 only */ -/*17*/ u_char nc_mbox1; /* 896 only */ +/*15*/ u_char nc_istat1; /* 896 and later cores only */ + #define FLSH 0x04 /* sta: chip is flushing */ + #define SRUN 0x02 /* sta: scripts are running */ + #define SIRQD 0x01 /* r/w: disable INT pin */ + +/*16*/ u_char nc_mbox0; /* 896 and later cores only */ +/*17*/ u_char nc_mbox1; /* 896 and later cores only */ /*18*/ u_char nc_ctest0; /*19*/ u_char nc_ctest1; diff -u --recursive --new-file v2.4.6/linux/drivers/scsi/ultrastor.c linux/drivers/scsi/ultrastor.c --- v2.4.6/linux/drivers/scsi/ultrastor.c Sat Feb 3 11:32:54 2001 +++ linux/drivers/scsi/ultrastor.c Wed Jul 4 11:50:39 2001 @@ -259,7 +259,7 @@ } config = {0}; /* Set this to 1 to reset the SCSI bus on error. */ -int ultrastor_bus_reset = 0; +int ultrastor_bus_reset; /* Allowed BIOS base addresses (NULL indicates reserved) */ diff -u --recursive --new-file v2.4.6/linux/drivers/sound/Config.in linux/drivers/sound/Config.in --- v2.4.6/linux/drivers/sound/Config.in Tue Jul 3 17:08:21 2001 +++ linux/drivers/sound/Config.in Wed Jul 4 11:50:38 2001 @@ -6,12 +6,27 @@ # Prompt user for primary drivers. -dep_tristate ' C-Media PCI (CMI8338/8378)' CONFIG_SOUND_CMPCI $CONFIG_SOUND $CONFIG_PCI +dep_tristate ' C-Media PCI (CMI8338/8738)' CONFIG_SOUND_CMPCI $CONFIG_SOUND $CONFIG_PCI if [ "$CONFIG_SOUND_CMPCI" = "y" -o "$CONFIG_SOUND_CMPCI" = "m" ]; then - bool ' Enable S/PDIF loop for CMI8738' CONFIG_SOUND_CMPCI_SPDIFLOOP - bool ' Enable 4 channel mode for CMI8738' CONFIG_SOUND_CMPCI_4CH - if [ "$CONFIG_SOUND_CMPCI_4CH" = "y" ]; then - bool ' Separate rear out jack' CONFIG_SOUND_CMPCI_REAR + bool ' Enable legacy FM' CONFIG_SOUND_CMPCI_FM + if [ "$CONFIG_SOUND_CMPCI_FM" = "y" ]; then + define_hex CONFIG_SOUND_CMPCI_FMIO 388 + hex ' FM I/O 388, 3C8, 3E0, 3E8' CONFIG_SOUND_CMPCI_FMIO 388 + fi + bool ' Enable legacy MPU-401' CONFIG_SOUND_CMPCI_MIDI + if [ "$CONFIG_SOUND_CMPCI_MIDI" = "y" ]; then + hex ' MPU-401 I/O 330, 320, 310, 300' CONFIG_SOUND_CMPCI_MPUIO 330 + fi + bool ' Enable joystick' CONFIG_SOUND_CMPCI_JOYSTICK + bool ' Support CMI8738 based audio cards' CONFIG_SOUND_CMPCI_CM8738 + if [ "$CONFIG_SOUND_CMPCI_CM8738" = "y" ]; then + bool ' Inverse S/PDIF in for CMI8738' CONFIG_SOUND_CMPCI_SPDIFINVERSE + bool ' Enable S/PDIF loop for CMI8738' CONFIG_SOUND_CMPCI_SPDIFLOOP + int ' Number of speakers 2, 4, 5, 6' CONFIG_SOUND_CMPCI_SPEAKERS 2 + if [ "$CONFIG_SOUND_CMPCI_SPEAKERS" != "2" ]; then + bool ' Use Line-in as Read-out' CONFIG_SOUND_CMPCI_LINE_REAR + bool ' Use Line-in as Bass' CONFIG_SOUND_CMPCI_LINE_BASS + fi fi fi dep_tristate ' Creative SBLive! (EMU10K1)' CONFIG_SOUND_EMU10K1 $CONFIG_SOUND $CONFIG_PCI diff -u --recursive --new-file v2.4.6/linux/drivers/sound/ac97.c linux/drivers/sound/ac97.c --- v2.4.6/linux/drivers/sound/ac97.c Thu Jan 6 15:01:56 2000 +++ linux/drivers/sound/ac97.c Sun Jul 15 16:22:23 2001 @@ -407,19 +407,19 @@ /* Read or write request. */ ret = -EINVAL; if (_IOC_TYPE (cmd) == 'M') { - int dir = _IOC_DIR (cmd); + int dir = _SIOC_DIR (cmd); int channel = _IOC_NR (cmd); if (channel >= 0 && channel < SOUND_MIXER_NRDEVICES) { ret = 0; - if (dir & _IOC_WRITE) { + if (dir & _SIOC_WRITE) { int val; if (get_user (val, (int *) arg) == 0) ret = ac97_set_mixer (dev, channel, val); else ret = -EFAULT; } - if (ret >= 0 && (dir & _IOC_READ)) { + if (ret >= 0 && (dir & _SIOC_READ)) { if (dev->last_written_OSS_values[channel] == AC97_REGVAL_UNKNOWN) dev->last_written_OSS_values[channel] diff -u --recursive --new-file v2.4.6/linux/drivers/sound/ad1848.c linux/drivers/sound/ad1848.c --- v2.4.6/linux/drivers/sound/ad1848.c Sun Feb 4 10:05:29 2001 +++ linux/drivers/sound/ad1848.c Wed Jul 4 11:50:39 2001 @@ -106,11 +106,11 @@ ad1848_port_info; static struct address_info cfg; -static int nr_ad1848_devs = 0; +static int nr_ad1848_devs; -int deskpro_xl = 0; -int deskpro_m = 0; -int soundpro = 0; +int deskpro_xl; +int deskpro_m; +int soundpro; static volatile signed char irq2dev[17] = { -1, -1, -1, -1, -1, -1, -1, -1, @@ -121,7 +121,7 @@ static int timer_installed = -1; #endif -static int loaded = 0; +static int loaded; static int ad_format_mask[10 /*devc->model */ ] = { diff -u --recursive --new-file v2.4.6/linux/drivers/sound/dev_table.h linux/drivers/sound/dev_table.h --- v2.4.6/linux/drivers/sound/dev_table.h Sun Feb 4 10:05:29 2001 +++ linux/drivers/sound/dev_table.h Wed Jul 4 11:50:39 2001 @@ -350,14 +350,14 @@ }; #ifdef _DEV_TABLE_C_ -struct audio_operations *audio_devs[MAX_AUDIO_DEV] = {NULL}; -int num_audiodevs = 0; -struct mixer_operations *mixer_devs[MAX_MIXER_DEV] = {NULL}; -int num_mixers = 0; -struct synth_operations *synth_devs[MAX_SYNTH_DEV+MAX_MIDI_DEV] = {NULL}; -int num_synths = 0; -struct midi_operations *midi_devs[MAX_MIDI_DEV] = {NULL}; -int num_midis = 0; +struct audio_operations *audio_devs[MAX_AUDIO_DEV]; +int num_audiodevs; +struct mixer_operations *mixer_devs[MAX_MIXER_DEV]; +int num_mixers; +struct synth_operations *synth_devs[MAX_SYNTH_DEV+MAX_MIDI_DEV]; +int num_synths; +struct midi_operations *midi_devs[MAX_MIDI_DEV]; +int num_midis; extern struct sound_timer_operations default_sound_timer; struct sound_timer_operations *sound_timer_devs[MAX_TIMER_DEV] = { diff -u --recursive --new-file v2.4.6/linux/drivers/sound/esssolo1.c linux/drivers/sound/esssolo1.c --- v2.4.6/linux/drivers/sound/esssolo1.c Tue May 22 10:23:16 2001 +++ linux/drivers/sound/esssolo1.c Sun Jul 15 16:22:23 2001 @@ -1,4 +1,4 @@ -/*****************************************************************************/ +/****************************************************************************/ /* * esssolo1.c -- ESS Technology Solo1 (ES1946) audio driver. @@ -79,6 +79,9 @@ * for abs. Bug report by Andrew Morton <andrewm@uow.edu.au> * 15.05.2001 pci_enable_device moved, return values in probe cleaned * up. Marcus Meissner <mm@caldera.de> + * 22.05.2001 0.19 more cleanups, changed PM to PCI 2.4 style, got rid + * of global list of devices, using pci device data. + * Marcus Meissner <mm@caldera.de> */ /*****************************************************************************/ @@ -94,7 +97,6 @@ #include <linux/soundcard.h> #include <linux/pci.h> #include <linux/bitops.h> -#include <linux/pm.h> #include <asm/io.h> #include <asm/dma.h> #include <linux/init.h> @@ -104,25 +106,9 @@ #include <linux/wrapper.h> #include <asm/uaccess.h> #include <asm/hardirq.h> - -#include "dm.h" - -#if defined(CONFIG_INPUT_ANALOG) || defined(CONFIG_INPUT_ANALOG_MODULE) #include <linux/gameport.h> -#else -struct gameport { - int io; - int size; -}; -extern inline void gameport_register_port(struct gameport *gameport) -{ -} - -extern inline void gameport_unregister_port(struct gameport *gameport) -{ -} -#endif +#include "dm.h" /* --------------------------------------------------------------------- */ @@ -147,6 +133,7 @@ #define VCBASE_EXTENT (DDMABASE_EXTENT+DDMABASE_OFFSET) #define MPUBASE_EXTENT 4 #define GPBASE_EXTENT 4 +#define GAMEPORT_EXTENT 4 #define FMSYNTH_EXTENT 4 @@ -161,15 +148,14 @@ #define FMODE_DMFM 0x10 +static struct pci_driver solo1_driver; + /* --------------------------------------------------------------------- */ struct solo1_state { /* magic */ unsigned int magic; - /* list of esssolo1 devices */ - struct list_head devs; - /* the corresponding pci_dev structure */ struct pci_dev *dev; @@ -244,10 +230,6 @@ /* --------------------------------------------------------------------- */ -static LIST_HEAD(devs); - -/* --------------------------------------------------------------------- */ - extern inline void write_seq(struct solo1_state *s, unsigned char data) { int i; @@ -939,16 +921,22 @@ static int solo1_open_mixdev(struct inode *inode, struct file *file) { int minor = MINOR(inode->i_rdev); - struct list_head *list; - struct solo1_state *s; + struct solo1_state *s = NULL; + struct pci_dev *pci_dev; - for (list = devs.next; ; list = list->next) { - if (list == &devs) - return -ENODEV; - s = list_entry(list, struct solo1_state, devs); + pci_for_each_dev(pci_dev) { + struct pci_driver *drvr; + drvr = pci_dev_driver (pci_dev); + if (drvr != &solo1_driver) + continue; + s = (struct solo1_state*)pci_get_drvdata(pci_dev); + if (!s) + continue; if (s->dev_mixer == minor) break; } + if (!s) + return -ENODEV; VALIDATE_STATE(s); file->private_data = s; return 0; @@ -1611,16 +1599,23 @@ { int minor = MINOR(inode->i_rdev); DECLARE_WAITQUEUE(wait, current); - struct list_head *list; - struct solo1_state *s; + struct solo1_state *s = NULL; + struct pci_dev *pci_dev; - for (list = devs.next; ; list = list->next) { - if (list == &devs) - return -ENODEV; - s = list_entry(list, struct solo1_state, devs); + pci_for_each_dev(pci_dev) { + struct pci_driver *drvr; + + drvr = pci_dev_driver(pci_dev); + if (drvr != &solo1_driver) + continue; + s = (struct solo1_state*)pci_get_drvdata(pci_dev); + if (!s) + continue; if (!((s->dev_audio ^ minor) & ~0xf)) break; } + if (!s) + return -ENODEV; VALIDATE_STATE(s); file->private_data = s; /* wait for device to become free */ @@ -1894,16 +1889,23 @@ int minor = MINOR(inode->i_rdev); DECLARE_WAITQUEUE(wait, current); unsigned long flags; - struct list_head *list; - struct solo1_state *s; + struct solo1_state *s = NULL; + struct pci_dev *pci_dev; + + pci_for_each_dev(pci_dev) { + struct pci_driver *drvr; - for (list = devs.next; ; list = list->next) { - if (list == &devs) - return -ENODEV; - s = list_entry(list, struct solo1_state, devs); + drvr = pci_dev_driver(pci_dev); + if (drvr != &solo1_driver) + continue; + s = (struct solo1_state*)pci_get_drvdata(pci_dev); + if (!s) + continue; if (s->dev_midi == minor) break; } + if (!s) + return -ENODEV; VALIDATE_STATE(s); file->private_data = s; /* wait for device to become free */ @@ -2112,16 +2114,23 @@ { int minor = MINOR(inode->i_rdev); DECLARE_WAITQUEUE(wait, current); - struct list_head *list; - struct solo1_state *s; + struct solo1_state *s = NULL; + struct pci_dev *pci_dev; - for (list = devs.next; ; list = list->next) { - if (list == &devs) - return -ENODEV; - s = list_entry(list, struct solo1_state, devs); + pci_for_each_dev(pci_dev) { + struct pci_driver *drvr; + + drvr = pci_dev_driver(pci_dev); + if (drvr != &solo1_driver) + continue; + s = (struct solo1_state*)pci_get_drvdata(pci_dev); + if (!s) + continue; if (s->dev_dmfm == minor) break; } + if (!s) + return -ENODEV; VALIDATE_STATE(s); file->private_data = s; /* wait for device to become free */ @@ -2256,33 +2265,31 @@ return 0; } -static int solo1_pm_callback(struct pm_dev *dev, pm_request_t rqst, void *data) -{ - struct solo1_state *s = (struct solo1_state*) dev->data; - if (s) { - switch(rqst) { - case PM_RESUME: - setup_solo1(s); - break; +static void +solo1_suspend(struct pci_dev *pci_dev) { + struct solo1_state *s = (struct solo1_state*)pci_get_drvdata(pci_dev); + if (!s) + return; + outb(0, s->iobase+6); + /* DMA master clear */ + outb(0, s->ddmabase+0xd); + /* reset sequencer and FIFO */ + outb(3, s->sbbase+6); + /* turn off DDMA controller address space */ + pci_write_config_word(s->dev, 0x60, 0); +} - case PM_SUSPEND: - outb(0, s->iobase+6); - /* DMA master clear */ - outb(0, s->ddmabase+0xd); - /* reset sequencer and FIFO */ - outb(3, s->sbbase+6); - /* turn off DDMA controller address space */ - pci_write_config_word(s->dev, 0x60, 0); - break; - } - } - return 0; +static void +solo1_resume(struct pci_dev *pci_dev) { + struct solo1_state *s = (struct solo1_state*)pci_get_drvdata(pci_dev); + if (!s) + return; + setup_solo1(s); } static int __devinit solo1_probe(struct pci_dev *pcidev, const struct pci_device_id *pciid) { struct solo1_state *s; - struct pm_dev *pmdev; int ret; if ((ret=pci_enable_device(pcidev))) @@ -2324,7 +2331,6 @@ s->ddmabase = s->vcbase + DDMABASE_OFFSET; s->mpubase = pci_resource_start(pcidev, 3); s->gameport.io = pci_resource_start(pcidev, 4); - s->gameport.size = pci_resource_len(pcidev,4); s->irq = pcidev->irq; ret = -EBUSY; if (!request_region(s->iobase, IOBASE_EXTENT, "ESS Solo1")) { @@ -2343,11 +2349,9 @@ printk(KERN_ERR "solo1: io ports in use\n"); goto err_region4; } - if (!s->gameport.size) - s->gameport.io = 0; - if (s->gameport.io && !request_region(s->gameport.io, s->gameport.size, "ESS Solo1")) { + if (s->gameport.io && !request_region(s->gameport.io, GAMEPORT_EXTENT, "ESS Solo1")) { printk(KERN_ERR "solo1: gameport io ports in use\n"); - s->gameport.io = s->gameport.size = 0; + s->gameport.io = 0; } if ((ret=request_irq(s->irq,solo1_interrupt,SA_SHIRQ,"ESS Solo1",s))) { printk(KERN_ERR "solo1: irq %u in use\n", s->irq); @@ -2379,13 +2383,6 @@ gameport_register_port(&s->gameport); /* store it in the driver field */ pci_set_drvdata(pcidev, s); - /* put it into driver list */ - list_add_tail(&s->devs, &devs); - - pmdev = pm_register(PM_PCI_DEV, PM_PCI_ID(pcidev), solo1_pm_callback); - if (pmdev) - pmdev->data = s; - return 0; err: @@ -2401,7 +2398,7 @@ free_irq(s->irq, s); err_irq: if (s->gameport.io) - release_region(s->gameport.io, s->gameport.size); + release_region(s->gameport.io, GAMEPORT_EXTENT); release_region(s->iobase, IOBASE_EXTENT); err_region4: release_region(s->sbbase+FMSYNTH_EXTENT, SBBASE_EXTENT-FMSYNTH_EXTENT); @@ -2420,7 +2417,6 @@ if (!s) return; - list_del(&s->devs); /* stop DMA controller */ outb(0, s->iobase+6); outb(0, s->ddmabase+0xd); /* DMA master clear */ @@ -2430,7 +2426,7 @@ free_irq(s->irq, s); if (s->gameport.io) { gameport_unregister_port(&s->gameport); - release_region(s->gameport.io, s->gameport.size); + release_region(s->gameport.io, GAMEPORT_EXTENT); } release_region(s->iobase, IOBASE_EXTENT); release_region(s->sbbase+FMSYNTH_EXTENT, SBBASE_EXTENT-FMSYNTH_EXTENT); @@ -2455,7 +2451,9 @@ name: "ESS Solo1", id_table: id_table, probe: solo1_probe, - remove: solo1_remove + remove: solo1_remove, + suspend: solo1_suspend, + resume: solo1_resume }; @@ -2463,7 +2461,7 @@ { if (!pci_present()) /* No PCI bus in this machine! */ return -ENODEV; - printk(KERN_INFO "solo1: version v0.18 time " __TIME__ " " __DATE__ "\n"); + printk(KERN_INFO "solo1: version v0.19 time " __TIME__ " " __DATE__ "\n"); if (!pci_register_driver(&solo1_driver)) { pci_unregister_driver(&solo1_driver); return -ENODEV; @@ -2480,7 +2478,6 @@ { printk(KERN_INFO "solo1: unloading\n"); pci_unregister_driver(&solo1_driver); - pm_unregister_all(solo1_pm_callback); } /* --------------------------------------------------------------------- */ diff -u --recursive --new-file v2.4.6/linux/drivers/sound/maestro.c linux/drivers/sound/maestro.c --- v2.4.6/linux/drivers/sound/maestro.c Fri Mar 2 11:12:11 2001 +++ linux/drivers/sound/maestro.c Wed Jul 4 11:50:39 2001 @@ -115,6 +115,12 @@ * themselves, but we'll see. * * History + * v0.15 - May 21 2001 - Marcus Meissner <mm@caldera.de> + * Ported to Linux 2.4 PCI API. Some clean ups, global devs list + * removed (now using pci device driver data). + * PM needs to be polished still. Bumped version. + * (still kind of v0.14) May 13 2001 - Ben Pfaff <pfaffben@msu.edu> + * Add support for 978 docking and basic hardware volume control * (still kind of v0.14) Nov 23 - Alan Cox <alan@redhat.com> * Add clocking= for people with seriously warped hardware * (still v0.14) Nov 10 2000 - Bartlomiej Zolnierkiewicz <bkz@linux-ide.org> @@ -189,7 +195,7 @@ * fix bob frequency * endianness * do smart things with ac97 2.0 bits. - * docking and dual codecs and 978? + * dual codecs * leave 54->61 open * * it also would be fun to have a mode that would not use pci dma at all @@ -204,28 +210,6 @@ #include <linux/sched.h> #include <linux/smp_lock.h> #include <linux/wrapper.h> - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0) - - #define DECLARE_WAITQUEUE(QUEUE,INIT) struct wait_queue QUEUE = {INIT, NULL} - #define wait_queue_head_t struct wait_queue * - #define SILLY_PCI_BASE_ADDRESS(PCIDEV) (PCIDEV->base_address[0] & PCI_BASE_ADDRESS_IO_MASK) - #define SILLY_INIT_SEM(SEM) SEM=MUTEX; - #define init_waitqueue_head init_waitqueue - #define SILLY_MAKE_INIT(FUNC) __initfunc(FUNC) - #define SILLY_OFFSET(VMA) ((VMA)->vm_offset) - - -#else - - #define SILLY_PCI_BASE_ADDRESS(PCIDEV) (PCIDEV->resource[0].start) - #define SILLY_INIT_SEM(SEM) init_MUTEX(&SEM) - #define SILLY_MAKE_INIT(FUNC) __init FUNC - #define SILLY_OFFSET(VMA) ((VMA)->vm_pgoff) - - -#endif - #include <linux/string.h> #include <linux/ctype.h> #include <linux/ioport.h> @@ -249,6 +233,8 @@ #include "maestro.h" +static struct pci_driver maestro_pci_driver; + /* --------------------------------------------------------------------- */ #define M_DEBUG 1 @@ -269,8 +255,17 @@ static int clocking=48000; +MODULE_AUTHOR("Zach Brown <zab@zabbo.net>, Alan Cox <alan@redhat.com>"); +MODULE_DESCRIPTION("ESS Maestro Driver"); +#ifdef M_DEBUG +MODULE_PARM(debug,"i"); +#endif +MODULE_PARM(dsps_order,"i"); +MODULE_PARM(use_pm,"i"); +MODULE_PARM(clocking, "i"); + /* --------------------------------------------------------------------- */ -#define DRIVER_VERSION "0.14" +#define DRIVER_VERSION "0.15" #ifndef PCI_VENDOR_ESS #define PCI_VENDOR_ESS 0x125D @@ -352,6 +347,11 @@ [ACPI_D3] = ACPI_NONE }; +static char version[] __devinitdata = +KERN_INFO "maestro: version " DRIVER_VERSION " time " __TIME__ " " __DATE__ "\n"; + + + static const unsigned sample_size[] = { 1, 2, 2, 4 }; static const unsigned sample_shift[] = { 0, 1, 1, 2 }; @@ -483,8 +483,12 @@ int bob_freq; char dsps_open; + + int dock_mute_vol; }; +static void set_mixer(struct ess_card *card,unsigned int mixer, unsigned int val ); + static unsigned ld2(unsigned int x) { @@ -516,8 +520,6 @@ static void check_suspend(struct ess_card *card); -static struct ess_card *devs = NULL; - /* --------------------------------------------------------------------- */ @@ -983,6 +985,17 @@ outw(inw(ioaddr+0x68) | 0x600, ioaddr + 0x68); outw(0x0209, ioaddr + 0x60); } + + /* Turn on the 978 docking chip. + First frob the "master output enable" bit, + then set most of the playback volume control registers to max. */ + outb(inb(ioaddr+0xc0)|(1<<5), ioaddr+0xc0); + outb(0xff, ioaddr+0xc3); + outb(0xff, ioaddr+0xc4); + outb(0xff, ioaddr+0xc6); + outb(0xff, ioaddr+0xc8); + outb(0x3f, ioaddr+0xcf); + outb(0x3f, ioaddr+0xd0); } /* * Indirect register access. Not all registers are readable so we @@ -1895,19 +1908,52 @@ outw(inw(c->iobase+4)&1, c->iobase+4); /* M_printk("maestro int: %x\n",event);*/ - if(event&(1<<6)) { - /* XXX if we have a hw volume control int enable - all the ints? doesn't make sense.. */ - event = inw(c->iobase+0x18); - outb(0xFF, c->iobase+0x1A); - } - else - { - /* else ack 'em all, i imagine */ - outb(0xFF, c->iobase+0x1A); + int x; + enum {UP_EVT, DOWN_EVT, MUTE_EVT} vol_evt; + int volume; + + /* Figure out which volume control button was pushed, + based on differences from the default register + values. */ + x = inb(c->iobase+0x1c); + if (x&1) vol_evt = MUTE_EVT; + else if (((x>>1)&7) > 4) vol_evt = UP_EVT; + else vol_evt = DOWN_EVT; + + /* Reset the volume control registers. */ + outb(0x88, c->iobase+0x1c); + outb(0x88, c->iobase+0x1d); + outb(0x88, c->iobase+0x1e); + outb(0x88, c->iobase+0x1f); + + /* Deal with the button press in a hammer-handed + manner by adjusting the master mixer volume. */ + volume = c->mix.mixer_state[0] & 0xff; + if (vol_evt == UP_EVT) { + volume += 10; + if (volume > 100) + volume = 100; + } + else if (vol_evt == DOWN_EVT) { + volume -= 10; + if (volume < 0) + volume = 0; + } else { + /* vol_evt == MUTE_EVT */ + if (volume == 0) + volume = c->dock_mute_vol; + else { + c->dock_mute_vol = volume; + volume = 0; + } + } + set_mixer (c, 0, (volume << 8) | volume); } + + /* Ack all the interrupts. */ + outb(0xFF, c->iobase+0x1A); /* * Update the pointers for all APU's we are running. @@ -2083,17 +2129,25 @@ } /* --------------------------------------------------------------------- */ - static int ess_open_mixdev(struct inode *inode, struct file *file) { int minor = MINOR(inode->i_rdev); - struct ess_card *card = devs; - - while (card && card->dev_mixer != minor) - card = card->next; + struct ess_card *card = NULL; + struct pci_dev *pdev; + struct pci_driver *drvr; + + pci_for_each_dev(pdev) { + drvr = pci_dev_driver (pdev); + if (drvr == &maestro_pci_driver) { + card = (struct ess_card*)pci_get_drvdata (pdev); + if (!card) + continue; + if (card->dev_mixer == minor) + break; + } + } if (!card) return -ENODEV; - file->private_data = card; return 0; } @@ -2455,7 +2509,7 @@ #endif goto out; ret = -EINVAL; - if (SILLY_OFFSET(vma) != 0) + if (vma->vm_pgoff != 0) goto out; size = vma->vm_end - vma->vm_start; if (size > (PAGE_SIZE << db->buforder)) @@ -2919,33 +2973,40 @@ ess_open(struct inode *inode, struct file *file) { int minor = MINOR(inode->i_rdev); - struct ess_card *c = devs; - struct ess_state *s = NULL, *sp; - int i; + struct ess_state *s = NULL; unsigned char fmtm = ~0, fmts = 0; - + struct pci_dev *pdev; /* * Scan the cards and find the channel. We only * do this at open time so it is ok */ - - while (c!=NULL) - { - for(i=0;i<NR_DSPS;i++) - { - sp=&c->channels[i]; - if(sp->dev_audio < 0) - continue; - if((sp->dev_audio ^ minor) & ~0xf) + + pci_for_each_dev(pdev) { + struct ess_card *c; + struct pci_driver *drvr; + + drvr = pci_dev_driver (pdev); + if (drvr == &maestro_pci_driver) { + int i; + struct ess_state *sp; + + c = (struct ess_card*)pci_get_drvdata (pdev); + if (!c) continue; - s=sp; + for(i=0;i<NR_DSPS;i++) + { + sp=&c->channels[i]; + if(sp->dev_audio < 0) + continue; + if((sp->dev_audio ^ minor) & ~0xf) + continue; + s=sp; + } } - c=c->next; } - if (!s) return -ENODEV; - + VALIDATE_STATE(s); file->private_data = s; /* wait for device to become free */ @@ -3087,8 +3148,8 @@ /* XXX how do we know which to use? */ w&=~(1<<14); /* External clock */ - w&=~(1<<7); /* HWV off */ - w&=~(1<<6); /* Debounce off */ + w|= (1<<7); /* Hardware volume control on */ + w|= (1<<6); /* Debounce off: easier to push the HWV buttons. */ w&=~(1<<5); /* GPIO 4:5 */ w|= (1<<4); /* Disconnect from the CHI. Enabling this made a dell 7500 work. */ w&=~(1<<2); /* MIDI fix off (undoc) */ @@ -3106,6 +3167,12 @@ pci_write_config_word(pcidev, 0x40, w); + /* Set up 978 docking control chip. */ + pci_read_config_word(pcidev, 0x58, &w); + w|=1<<2; /* Enable 978. */ + w|=1<<3; /* Turn on 978 hardware volume control. */ + w&=~(1<<11); /* Turn on 978 mixer volume control. */ + pci_write_config_word(pcidev, 0x58, w); sound_reset(iobase); @@ -3170,7 +3237,7 @@ outw(w, iobase+0x18); w=inw(iobase+0x18); - w&=~(1<<6); /* Harpo off */ + w&=~(1<<6); /* Hardware volume control interrupt off... for now. */ outw(w, iobase+0x18); w=inw(iobase+0x18); @@ -3193,6 +3260,13 @@ w|=(1<<0); /* SB IRQ on */ outw(w, iobase+0x18); + /* Set hardware volume control registers to midpoints. + We can tell which button was pushed based on how they change. */ + outb(0x88, iobase+0x1c); + outb(0x88, iobase+0x1d); + outb(0x88, iobase+0x1e); + outb(0x88, iobase+0x1f); + /* it appears some maestros (dell 7500) only work if these are set, regardless of wether we use the assp or not. */ @@ -3308,32 +3382,44 @@ } static int __init -maestro_install(struct pci_dev *pcidev, int card_type) +maestro_probe(struct pci_dev *pcidev,const struct pci_device_id *pdid) { + int card_type = pdid->driver_data; u32 n; int iobase; - int i; + int i, ret; struct ess_card *card; struct ess_state *ess; struct pm_dev *pmdev; int num = 0; +/* when built into the kernel, we only print version if device is found */ +#ifndef MODULE + static int printed_version; + if (!printed_version++) + printk(version); +#endif + /* don't pick up weird modem maestros */ if(((pcidev->class >> 8) & 0xffff) != PCI_CLASS_MULTIMEDIA_AUDIO) - return 0; + return -ENODEV; + + + if ((ret=pci_enable_device(pcidev))) + return ret; - iobase = SILLY_PCI_BASE_ADDRESS(pcidev); + iobase = pci_resource_start(pcidev,0); + if (!iobase || !(pci_resource_flags(pcidev, 0 ) & IORESOURCE_IO)) + return -ENODEV; + + if(pcidev->irq == 0) + return -ENODEV; /* stake our claim on the iospace */ if( request_region(iobase, 256, card_names[card_type]) == NULL ) { printk(KERN_WARNING "maestro: can't allocate 256 bytes I/O at 0x%4.4x\n", iobase); - return 0; - } - - /* this was tripping up some machines */ - if(pcidev->irq == 0) { - printk(KERN_WARNING "maestro: pci subsystem reports irq 0, this might not be correct.\n"); + return -EBUSY; } /* just to be sure */ @@ -3343,7 +3429,8 @@ if(card == NULL) { printk(KERN_WARNING "maestro: out of memory\n"); - return 0; + release_region(iobase, 256); + return -ENOMEM; } memset(card, 0, sizeof(*card)); @@ -3354,18 +3441,14 @@ if (pmdev) pmdev->data = card; - if (register_reboot_notifier(&maestro_nb)) { - printk(KERN_WARNING "maestro: reboot notifier registration failed; may not reboot properly.\n"); - } - card->iobase = iobase; card->card_type = card_type; card->irq = pcidev->irq; - card->next = devs; card->magic = ESS_CARD_MAGIC; spin_lock_init(&card->lock); init_waitqueue_head(&card->suspend_queue); - devs = card; + + card->dock_mute_vol = 50; /* init our groups of 6 apus */ for(i=0;i<NR_DSPS;i++) @@ -3379,7 +3462,7 @@ init_waitqueue_head(&s->dma_dac.wait); init_waitqueue_head(&s->open_wait); spin_lock_init(&s->lock); - SILLY_INIT_SEM(s->open_sem); + init_MUTEX(&s->open_sem); s->magic = ESS_STATE_MAGIC; s->apu[0] = 6*i; @@ -3407,19 +3490,6 @@ ess = &card->channels[0]; - if (pci_enable_device(pcidev)) { - printk (KERN_ERR "maestro: pci_enable_device() failed\n"); - for (i = 0; i < NR_DSPS; i++) { - struct ess_state *s = &card->channels[i]; - if (s->dev_audio != -1) - unregister_sound_dsp(s->dev_audio); - } - release_region(card->iobase, 256); - unregister_reboot_notifier(&maestro_nb); - kfree(card); - return 0; - } - /* * Ok card ready. Begin setup proper */ @@ -3469,7 +3539,7 @@ mixer_push_state(card); } - if(request_irq(card->irq, ess_interrupt, SA_SHIRQ, card_names[card_type], card)) + if((ret=request_irq(card->irq, ess_interrupt, SA_SHIRQ, card_names[card_type], card))) { printk(KERN_ERR "maestro: unable to allocate irq %d,\n", card->irq); unregister_sound_mixer(card->dev_mixer); @@ -3482,26 +3552,69 @@ release_region(card->iobase, 256); unregister_reboot_notifier(&maestro_nb); kfree(card); - return 0; + return ret; } + + /* Turn on hardware volume control interrupt. + This has to come after we grab the IRQ above, + or a crash will result on installation if a button has been pressed, + because in that case we'll get an immediate interrupt. */ + n = inw(iobase+0x18); + n|=(1<<6); + outw(n, iobase+0x18); + + pci_set_drvdata(pcidev,card); /* now go to sleep 'till something interesting happens */ maestro_power(card,ACPI_D2); printk(KERN_INFO "maestro: %d channels configured.\n", num); - return 1; + return 0; } -int __init init_maestro(void) -{ - struct pci_dev *pcidev = NULL; - int foundone = 0; - - if (!pci_present()) /* No PCI bus in this machine! */ - return -ENODEV; - printk(KERN_INFO "maestro: version " DRIVER_VERSION " time " __TIME__ " " __DATE__ "\n"); +static void maestro_remove(struct pci_dev *pcidev) { + struct ess_card *card = pci_get_drvdata(pcidev); + int i; + + /* XXX maybe should force stop bob, but should be all + stopped by _release by now */ + free_irq(card->irq, card); + unregister_sound_mixer(card->dev_mixer); + for(i=0;i<NR_DSPS;i++) + { + struct ess_state *ess = &card->channels[i]; + if(ess->dev_audio != -1) + unregister_sound_dsp(ess->dev_audio); + } + /* Goodbye, Mr. Bond. */ + maestro_power(card,ACPI_D3); + release_region(card->iobase, 256); + kfree(card); + pci_set_drvdata(pcidev,NULL); +} + +static struct pci_device_id maestro_pci_tbl[] __devinitdata = { + {PCI_VENDOR_ESS, PCI_DEVICE_ID_ESS_ESS1968, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TYPE_MAESTRO2}, + {PCI_VENDOR_ESS, PCI_DEVICE_ID_ESS_ESS1978, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TYPE_MAESTRO2E}, + {PCI_VENDOR_ESS_OLD, PCI_DEVICE_ID_ESS_ESS0100, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TYPE_MAESTRO}, + {0,} +}; +MODULE_DEVICE_TABLE(pci, maestro_pci_tbl); - pcidev = NULL; +static struct pci_driver maestro_pci_driver = { + name:"maestro", + id_table:maestro_pci_tbl, + probe:maestro_probe, + remove:maestro_remove, +}; +int __init init_maestro(void) +{ + pci_module_init(&maestro_pci_driver); + if (register_reboot_notifier(&maestro_nb)) + printk(KERN_WARNING "maestro: reboot notifier registration failed; may not reboot properly.\n"); +#ifdef MODULE + printk(version); +#endif if (dsps_order < 0) { dsps_order = 1; printk(KERN_WARNING "maestro: clipping dsps_order to %d\n",dsps_order); @@ -3510,97 +3623,29 @@ dsps_order = MAX_DSP_ORDER; printk(KERN_WARNING "maestro: clipping dsps_order to %d\n",dsps_order); } - - /* - * Find the ESS Maestro 2. - */ - - while( (pcidev = pci_find_device(PCI_VENDOR_ESS, PCI_DEVICE_ID_ESS_ESS1968, pcidev))!=NULL ) { - if (maestro_install(pcidev, TYPE_MAESTRO2)) - foundone=1; - } - - /* - * Find the ESS Maestro 2E - */ - - while( (pcidev = pci_find_device(PCI_VENDOR_ESS, PCI_DEVICE_ID_ESS_ESS1978, pcidev))!=NULL) { - if (maestro_install(pcidev, TYPE_MAESTRO2E)) - foundone=1; - } - - /* - * ESS Maestro 1 - */ - - while((pcidev = pci_find_device(PCI_VENDOR_ESS_OLD, PCI_DEVICE_ID_ESS_ESS0100, pcidev))!=NULL) { - if (maestro_install(pcidev, TYPE_MAESTRO)) - foundone=1; - } - if( ! foundone ) { - printk("maestro: no devices found.\n"); - return -ENODEV; - } return 0; } -static void nuke_maestros(void) -{ - struct ess_card *card; - - /* we do these unconditionally, which is probably wrong */ - pm_unregister_all(maestro_pm_callback); - unregister_reboot_notifier(&maestro_nb); - - while ((card = devs)) { - int i; - devs = devs->next; - - /* XXX maybe should force stop bob, but should be all - stopped by _release by now */ - free_irq(card->irq, card); - unregister_sound_mixer(card->dev_mixer); - for(i=0;i<NR_DSPS;i++) - { - struct ess_state *ess = &card->channels[i]; - if(ess->dev_audio != -1) - unregister_sound_dsp(ess->dev_audio); - } - /* Goodbye, Mr. Bond. */ - maestro_power(card,ACPI_D3); - release_region(card->iobase, 256); - kfree(card); - } - devs = NULL; -} - static int maestro_notifier(struct notifier_block *nb, unsigned long event, void *buf) { /* this notifier is called when the kernel is really shut down. */ M_printk("maestro: shutting down\n"); - nuke_maestros(); + /* this will remove all card instances too */ + pci_unregister_driver(&maestro_pci_driver); + /* XXX dunno about power management */ return NOTIFY_OK; } /* --------------------------------------------------------------------- */ -#ifdef MODULE -MODULE_AUTHOR("Zach Brown <zab@zabbo.net>, Alan Cox <alan@redhat.com>"); -MODULE_DESCRIPTION("ESS Maestro Driver"); -#ifdef M_DEBUG -MODULE_PARM(debug,"i"); -#endif -MODULE_PARM(dsps_order,"i"); -MODULE_PARM(use_pm,"i"); -MODULE_PARM(clocking, "i"); -void cleanup_module(void) { +void cleanup_maestro(void) { M_printk("maestro: unloading\n"); - nuke_maestros(); + pci_unregister_driver(&maestro_pci_driver); + pm_unregister_all(maestro_pm_callback); + unregister_reboot_notifier(&maestro_nb); } -#endif - /* --------------------------------------------------------------------- */ void @@ -3759,3 +3804,4 @@ } module_init(init_maestro); +module_exit(cleanup_maestro); diff -u --recursive --new-file v2.4.6/linux/drivers/sound/msnd_pinnacle.c linux/drivers/sound/msnd_pinnacle.c --- v2.4.6/linux/drivers/sound/msnd_pinnacle.c Tue Mar 6 19:44:37 2001 +++ linux/drivers/sound/msnd_pinnacle.c Sun Jul 15 16:22:23 2001 @@ -1570,7 +1570,6 @@ MODULE_PARM (irq, "i"); MODULE_PARM (mem, "i"); MODULE_PARM (write_ndelay, "i"); -MODULE_PARM (major, "i"); MODULE_PARM (fifosize, "i"); MODULE_PARM (calibrate_signal, "i"); #ifndef MSND_CLASSIC diff -u --recursive --new-file v2.4.6/linux/drivers/sound/nm256_audio.c linux/drivers/sound/nm256_audio.c --- v2.4.6/linux/drivers/sound/nm256_audio.c Tue May 1 16:05:00 2001 +++ linux/drivers/sound/nm256_audio.c Wed Jul 4 11:50:39 2001 @@ -29,8 +29,8 @@ #include "nm256.h" #include "nm256_coeff.h" -int nm256_debug = 0; -static int force_load = 0; +int nm256_debug; +static int force_load; /* * The size of the playback reserve. When the playback buffer has less @@ -131,8 +131,8 @@ return NULL; } -static int usecache = 0; -static int buffertop = 0; +static int usecache; +static int buffertop; /* Check to see if we're using the bank of cached coefficients. */ int diff -u --recursive --new-file v2.4.6/linux/drivers/sound/sb_common.c linux/drivers/sound/sb_common.c --- v2.4.6/linux/drivers/sound/sb_common.c Wed Apr 18 11:49:12 2001 +++ linux/drivers/sound/sb_common.c Wed Jul 4 11:50:39 2001 @@ -45,10 +45,10 @@ * global module flag */ -int sb_be_quiet = 0; +int sb_be_quiet; -static sb_devc *detected_devc = NULL; /* For communication from probe to init */ -static sb_devc *last_devc = NULL; /* For MPU401 initialization */ +static sb_devc *detected_devc; /* For communication from probe to init */ +static sb_devc *last_devc; /* For MPU401 initialization */ static unsigned char jazz_irq_bits[] = { 0, 0, 2, 3, 0, 1, 0, 4, 0, 2, 5, 0, 0, 0, 0, 6 @@ -58,14 +58,14 @@ 0, 1, 0, 2, 0, 3, 0, 4 }; -void *smw_free = NULL; +void *smw_free; /* * Jazz16 chipset specific control variables */ -static int jazz16_base = 0; /* Not detected */ -static unsigned char jazz16_bits = 0; /* I/O relocation bits */ +static int jazz16_base; /* Not detected */ +static unsigned char jazz16_bits; /* I/O relocation bits */ static spinlock_t jazz16_lock = SPIN_LOCK_UNLOCKED; /* @@ -75,12 +75,12 @@ #ifdef SMW_MIDI0001_INCLUDED #include "smw-midi0001.h" #else -static unsigned char *smw_ucode = NULL; -static int smw_ucodeLen = 0; +static unsigned char *smw_ucode; +static int smw_ucodeLen; #endif -sb_devc *last_sb = NULL; /* Last sb loaded */ +sb_devc *last_sb; /* Last sb loaded */ int sb_dsp_command(sb_devc * devc, unsigned char val) { diff -u --recursive --new-file v2.4.6/linux/drivers/sound/trident.c linux/drivers/sound/trident.c --- v2.4.6/linux/drivers/sound/trident.c Sat May 19 17:43:10 2001 +++ linux/drivers/sound/trident.c Sun Jul 15 16:22:23 2001 @@ -31,6 +31,17 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * History + * v0.14.8a + * July 7 2001 Alan Cox + * Moved Matt Wu's ac97 register cache into the card structure + * v0.14.8 + * Apr 30 2001 Matt Wu + * Set EBUF1 and EBUF2 to still mode + * Add dc97/ac97 reset function + * Fix power management: ali_restore_regs + * unreleased + * Mar 09 2001 Matt Wu + * Add cache for ac97 access * v0.14.7 * Feb 06 2001 Matt Wu * Fix ac97 initialization @@ -104,6 +115,11 @@ * Mmap support * "Channel Binding" ioctl extension (done) * new pci device driver interface for 2.4 kernel (done) + * + * Lock order (high->low) + * lock - hardware lock + * open_sem - guard opens + * sem - guard dmabuf, write re-entry etc */ #include <linux/config.h> @@ -131,11 +147,15 @@ #include <linux/bitops.h> #include <linux/proc_fs.h> +#if defined CONFIG_ALPHA_NAUTILUS || CONFIG_ALPHA_GENERIC +#include <asm/hwrpb.h> +#endif + #include "trident.h" #include <linux/pm.h> -#define DRIVER_VERSION "0.14.6" +#define DRIVER_VERSION "0.14.8" /* magic numbers to protect our data structures */ #define TRIDENT_CARD_MAGIC 0x5072696E /* "Prin" */ @@ -243,6 +263,9 @@ int multi_channels_adjust_count; unsigned chans_num; unsigned fmt_flag:1; + /* Guard against mmap/write/read races */ + struct semaphore sem; + }; /* hardware channels */ @@ -296,7 +319,7 @@ /* The trident has a certain amount of cross channel interaction so we use a single per card lock */ spinlock_t lock; - + /* PCI device stuff */ struct pci_dev * pci_dev; u16 pci_id; @@ -320,9 +343,11 @@ void (*free_pcm_channel)(struct trident_card *, unsigned int chan); void (*address_interrupt)(struct trident_card *); - /* Add by Matt Wu 01-05-2001 for spdif in */ + /* Added by Matt Wu 01-05-2001 for spdif in */ int multi_channel_use_count; int rec_channel_use_count; + u16 mixer_regs[64][NR_AC97]; /* Made card local by Alan */ + int mixer_regs_ready; }; /* table to map from CHANNELMASK to channel attribute for SiS 7018 */ @@ -338,11 +363,14 @@ DSP_BIND_I2S, DSP_BIND_CENTER_LFE, DSP_BIND_SURR, DSP_BIND_SPDIF }; -/* Add by Matt Wu 01-05-2001 for spdif in */ +/* Added by Matt Wu 01-05-2001 for spdif in */ static int ali_close_multi_channels(void); static void ali_delay(struct trident_card *card,int interval); static void ali_detect_spdif_rate(struct trident_card *card); +static void ali_ac97_write(struct ac97_codec *codec, u8 reg, u16 val); +static u16 ali_ac97_read(struct ac97_codec *codec, u8 reg); + static struct trident_card *devs; static void trident_ac97_set(struct ac97_codec *codec, u8 reg, u16 val); @@ -353,15 +381,16 @@ unsigned long arg); static loff_t trident_llseek(struct file *file, loff_t offset, int origin); -static void ali_ac97_set(struct ac97_codec *codec, u8 reg, u16 val); -static u16 ali_ac97_get(struct ac97_codec *codec, u8 reg); +static void ali_ac97_set(struct trident_card *card, int secondary, u8 reg, u16 val); +static u16 ali_ac97_get(struct trident_card *card, int secondary, u8 reg); static void ali_set_spdif_out_rate(struct trident_card *card, unsigned int rate); static void ali_enable_special_channel(struct trident_state *stat); static struct trident_channel *ali_alloc_rec_pcm_channel(struct trident_card *card); static struct trident_channel *ali_alloc_pcm_channel(struct trident_card *card); -static int ali_pm_callback(struct pm_dev *dev, pm_request_t rqst, void *data); static void ali_restore_regs(struct trident_card *card); static void ali_save_regs(struct trident_card *card); +static int trident_suspend(struct pci_dev *dev, u32 unused); +static int trident_resume(struct pci_dev *dev); static void ali_free_pcm_channel(struct trident_card *card, unsigned int channel); static int ali_setup_multi_channels(struct trident_card *card, int chan_nums); static unsigned int ali_get_spdif_in_rate(struct trident_card *card); @@ -607,6 +636,10 @@ continue; outl(data[i], TRID_REG(card, CHANNEL_START + 4*i)); } + if (card->pci_id == PCI_DEVICE_ID_ALI_5451) { + outl(ALI_EMOD_Still, TRID_REG(card, ALI_EBUF1)); + outl(ALI_EMOD_Still, TRID_REG(card, ALI_EBUF2)); + } return TRUE; } @@ -989,7 +1022,7 @@ static int alloc_dmabuf(struct trident_state *state) { struct dmabuf *dmabuf = &state->dmabuf; - void *rawbuf=NULL; + void *rawbuf = NULL; int order; struct page *page, *pend; @@ -1221,7 +1254,7 @@ return -EBUSY; } - /* No matter how much data left in the buffer, we have to wait untill + /* No matter how much data is left in the buffer, we have to wait until CSO == ESO/2 or CSO == ESO when address engine interrupts */ if (state->card->pci_id == PCI_DEVICE_ID_ALI_5451) { @@ -1234,7 +1267,6 @@ tmo = (dmabuf->dmasize * HZ) / dmabuf->rate; } tmo >>= sample_shift[dmabuf->fmt]; -// printk("trident: diff=%d count= %d/%d total=%d tmo=%d hwptr=%d swptr=%d curptr=%d\n",diff,dmabuf->count,dmabuf->dmasize,dmabuf->total_bytes,tmo,dmabuf->hwptr,dmabuf->swptr,trident_get_dma_addr(state)); if (!schedule_timeout(tmo ? tmo : 1) && tmo){ break; } @@ -1416,7 +1448,7 @@ { struct trident_state *state = (struct trident_state *)file->private_data; struct dmabuf *dmabuf = &state->dmabuf; - ssize_t ret; + ssize_t ret = 0; unsigned long flags; unsigned swptr; int cnt; @@ -1428,13 +1460,15 @@ VALIDATE_STATE(state); if (ppos != &file->f_pos) return -ESPIPE; + if (dmabuf->mapped) return -ENXIO; - if (!dmabuf->ready && (ret = prog_dmabuf(state, 1))) - return ret; if (!access_ok(VERIFY_WRITE, buffer, count)) return -EFAULT; - ret = 0; + + down(&state->sem); + if (!dmabuf->ready && (ret = prog_dmabuf(state, 1))) + goto out; while (count > 0) { spin_lock_irqsave(&state->card->lock, flags); @@ -1459,8 +1493,10 @@ start_adc(state); if (file->f_flags & O_NONBLOCK) { if (!ret) ret = -EAGAIN; - return ret; + goto out; } + + up(&state->sem); /* No matter how much space left in the buffer, we have to wait until CSO == ESO/2 or CSO == ESO when address engine interrupts */ tmo = (dmabuf->dmasize * HZ) / (dmabuf->rate * 2); @@ -1483,15 +1519,22 @@ while loop begin and we REALLY have space to record */ } if (signal_pending(current)) { - ret = ret ? ret : -ERESTARTSYS; - return ret; + if(!ret) ret = -ERESTARTSYS; + goto out; + } + down(&state->sem); + if(dmabuf->mapped) + { + if(!ret) + ret = -ENXIO; + goto out; } continue; } if (copy_to_user(buffer, dmabuf->rawbuf + swptr, cnt)) { if (!ret) ret = -EFAULT; - return ret; + goto out; } swptr = (swptr + cnt) % dmabuf->dmasize; @@ -1506,11 +1549,14 @@ ret += cnt; start_adc(state); } +out: + up(&state->sem); return ret; } /* in this loop, dmabuf.count signifies the amount of data that is waiting to be dma to the soundcard. it is drained by the dma machine and filled by this loop. */ + static ssize_t trident_write(struct file *file, const char *buffer, size_t count, loff_t *ppos) { struct trident_state *state = (struct trident_state *)file->private_data; @@ -1528,12 +1574,27 @@ VALIDATE_STATE(state); if (ppos != &file->f_pos) return -ESPIPE; + + /* + * Guard against an mmap or ioctl while writing + */ + + down(&state->sem); + if (dmabuf->mapped) - return -ENXIO; + { + ret = -ENXIO; + goto out; + } if (!dmabuf->ready && (ret = prog_dmabuf(state, 0))) - return ret; + goto out; + if (!access_ok(VERIFY_READ, buffer, count)) - return -EFAULT; + { + ret= -EFAULT; + goto out; + } + ret = 0; while (count > 0) { @@ -1559,7 +1620,7 @@ start_dac(state); if (file->f_flags & O_NONBLOCK) { if (!ret) ret = -EAGAIN; - return ret; + goto out; } /* No matter how much data left in the buffer, we have to wait until CSO == ESO/2 or CSO == ESO when address engine interrupts */ @@ -1567,6 +1628,8 @@ tmo = (dmabuf->dmasize * HZ) / (dmabuf->rate * 2); tmo >>= sample_shift[dmabuf->fmt]; unlock_set_fmt(state); + up(&state->sem); + /* There are two situations when sleep_on_timeout returns, one is when the interrupt is serviced correctly and the process is waked up by ISR ON TIME. Another is when timeout is expired, which means that @@ -1586,7 +1649,14 @@ } if (signal_pending(current)) { if (!ret) ret = -ERESTARTSYS; - return ret; + goto out; + } + down(&state->sem); + if(dmabuf->mapped) + { + if(!ret) + ret = -ENXIO; + goto out; } continue; } @@ -1606,14 +1676,14 @@ ret += copy_count; if (!ret) ret = -EFAULT; unlock_set_fmt(state); - return ret; + goto out; } } else { if (copy_from_user(dmabuf->rawbuf + swptr, buffer, cnt)) { if (!ret) ret = -EFAULT; unlock_set_fmt(state); - return ret; + goto out; } state_cnt = cnt; } @@ -1632,9 +1702,12 @@ ret += cnt; start_dac(state); } +out: + up(&state->sem); return ret; } + /* No kernel lock - we have our own spinlock */ static unsigned int trident_poll(struct file *file, struct poll_table_struct *wait) { @@ -1645,17 +1718,32 @@ VALIDATE_STATE(state); + /* + * Guard against a parallel poll and write causing multiple + * prog_dmabuf events + */ + + down(&state->sem); + if (file->f_mode & FMODE_WRITE) { if (!dmabuf->ready && prog_dmabuf(state, 0)) + { + up(&state->sem); return 0; + } poll_wait(file, &dmabuf->wait, wait); } if (file->f_mode & FMODE_READ) { if (!dmabuf->ready && prog_dmabuf(state, 1)) + { + up(&state->sem); return 0; + } poll_wait(file, &dmabuf->wait, wait); } + up(&state->sem); + spin_lock_irqsave(&state->card->lock, flags); trident_update_ptr(state); if (file->f_mode & FMODE_READ) { @@ -1685,6 +1773,14 @@ VALIDATE_STATE(state); lock_kernel(); + + /* + * Lock against poll read write or mmap creating buffers. Also lock + * a read or write against an mmap. + */ + + down(&state->sem); + if (vma->vm_flags & VM_WRITE) { if ((ret = prog_dmabuf(state, 0)) != 0) goto out; @@ -1707,6 +1803,7 @@ dmabuf->mapped = 1; ret = 0; out: + up(&state->sem); unlock_kernel(); return ret; } @@ -1718,7 +1815,7 @@ unsigned long flags; audio_buf_info abinfo; count_info cinfo; - int val, mapped, ret; + int val, mapped, ret = 0; struct trident_card *card = state->card; @@ -1733,8 +1830,9 @@ switch (cmd) { case OSS_GETVERSION: - return put_user(SOUND_VERSION, (int *)arg); - + ret = put_user(SOUND_VERSION, (int *)arg); + break; + case SNDCTL_DSP_RESET: /* FIXME: spin_lock ? */ if (file->f_mode & FMODE_WRITE) { @@ -1751,16 +1849,19 @@ dmabuf->swptr = dmabuf->hwptr = 0; dmabuf->count = dmabuf->total_bytes = 0; } - return 0; + break; case SNDCTL_DSP_SYNC: if (file->f_mode & FMODE_WRITE) - return drain_dac(state, file->f_flags & O_NONBLOCK); - return 0; + ret = drain_dac(state, file->f_flags & O_NONBLOCK); + break; case SNDCTL_DSP_SPEED: /* set smaple rate */ if (get_user(val, (int *)arg)) - return -EFAULT; + { + ret = -EFAULT; + break; + } if (val >= 0) { if (file->f_mode & FMODE_WRITE) { stop_dac(state); @@ -1777,11 +1878,15 @@ spin_unlock_irqrestore(&state->card->lock, flags); } } - return put_user(dmabuf->rate, (int *)arg); + ret = put_user(dmabuf->rate, (int *)arg); + break; case SNDCTL_DSP_STEREO: /* set stereo or mono channel */ if (get_user(val, (int *)arg)) - return -EFAULT; + { + ret = -EFAULT; + break; + } lock_set_fmt(state); if (file->f_mode & FMODE_WRITE) { stop_dac(state); @@ -1800,26 +1905,34 @@ dmabuf->fmt &= ~TRIDENT_FMT_STEREO; } unlock_set_fmt(state); - return 0; + break; case SNDCTL_DSP_GETBLKSIZE: if (file->f_mode & FMODE_WRITE) { if ((val = prog_dmabuf(state, 0))) - return val; - return put_user(dmabuf->fragsize, (int *)arg); + ret = val; + else + ret = put_user(dmabuf->fragsize, (int *)arg); + break; } if (file->f_mode & FMODE_READ) { if ((val = prog_dmabuf(state, 1))) - return val; - return put_user(dmabuf->fragsize, (int *)arg); + ret = val; + else + ret = put_user(dmabuf->fragsize, (int *)arg); + break; } case SNDCTL_DSP_GETFMTS: /* Returns a mask of supported sample format*/ - return put_user(AFMT_S16_LE|AFMT_U16_LE|AFMT_S8|AFMT_U8, (int *)arg); + ret = put_user(AFMT_S16_LE|AFMT_U16_LE|AFMT_S8|AFMT_U8, (int *)arg); + break; case SNDCTL_DSP_SETFMT: /* Select sample format */ if (get_user(val, (int *)arg)) - return -EFAULT; + { + ret = -EFAULT; + break; + } lock_set_fmt(state); if (val != AFMT_QUERY) { if (file->f_mode & FMODE_WRITE) { @@ -1840,12 +1953,16 @@ } } unlock_set_fmt(state); - return put_user((dmabuf->fmt & TRIDENT_FMT_16BIT) ? + ret = put_user((dmabuf->fmt & TRIDENT_FMT_16BIT) ? AFMT_S16_LE : AFMT_U8, (int *)arg); + break; case SNDCTL_DSP_CHANNELS: if (get_user(val, (int *)arg)) - return -EFAULT; + { + ret = -EFAULT; + break; + } if (val != 0) { lock_set_fmt(state); if (file->f_mode & FMODE_WRITE) { @@ -1866,21 +1983,22 @@ if( card->rec_channel_use_count > 0 ) { - printk("Err: Record is working on the card!\n"); - return -EBUSY; + printk(KERN_ERR "trident: Record is working on the card!\n"); + ret = -EBUSY; + break; } ret = ali_setup_multi_channels(state->card, 6); if (ret < 0) { unlock_set_fmt(state); - return ret; + break; } down(&state->card->open_sem); ret = ali_allocate_other_states_resources(state, 6); if (ret < 0) { up(&state->card->open_sem); unlock_set_fmt(state); - return ret; + break; } state->card->multi_channel_use_count ++; up(&state->card->open_sem); @@ -1905,25 +2023,38 @@ } unlock_set_fmt(state); } - return put_user(val, (int *)arg); + ret = put_user(val, (int *)arg); + break; case SNDCTL_DSP_POST: - /* FIXME: the same as RESET ?? */ - return 0; + /* Cause the working fragment to be output */ + break; case SNDCTL_DSP_SUBDIVIDE: if (dmabuf->subdivision) - return -EINVAL; + { + ret = -EINVAL; + break; + } if (get_user(val, (int *)arg)) - return -EFAULT; + { + ret = -EFAULT; + break; + } if (val != 1 && val != 2 && val != 4) - return -EINVAL; + { + ret = -EINVAL; + break; + } dmabuf->subdivision = val; - return 0; + break; case SNDCTL_DSP_SETFRAGMENT: if (get_user(val, (int *)arg)) - return -EFAULT; + { + ret = -EFAULT; + break; + } dmabuf->ossfragshift = val & 0xffff; dmabuf->ossmaxfrags = (val >> 16) & 0xffff; @@ -1934,13 +2065,19 @@ if (dmabuf->ossmaxfrags < 4) dmabuf->ossmaxfrags = 4; - return 0; + break; case SNDCTL_DSP_GETOSPACE: if (!(file->f_mode & FMODE_WRITE)) - return -EINVAL; + { + ret = -EINVAL; + break; + } if (!dmabuf->ready && (val = prog_dmabuf(state, 0)) != 0) - return val; + { + ret = val; + break; + } spin_lock_irqsave(&state->card->lock, flags); trident_update_ptr(state); abinfo.fragsize = dmabuf->fragsize; @@ -1948,13 +2085,20 @@ abinfo.fragstotal = dmabuf->numfrag; abinfo.fragments = abinfo.bytes >> dmabuf->fragshift; spin_unlock_irqrestore(&state->card->lock, flags); - return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0; + ret = copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0; + break; case SNDCTL_DSP_GETISPACE: if (!(file->f_mode & FMODE_READ)) - return -EINVAL; + { + ret = -EINVAL; + break; + } if (!dmabuf->ready && (val = prog_dmabuf(state, 1)) != 0) - return val; + { + ret = val; + break; + } spin_lock_irqsave(&state->card->lock, flags); trident_update_ptr(state); abinfo.fragsize = dmabuf->fragsize; @@ -1962,15 +2106,17 @@ abinfo.fragstotal = dmabuf->numfrag; abinfo.fragments = abinfo.bytes >> dmabuf->fragshift; spin_unlock_irqrestore(&state->card->lock, flags); - return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0; + ret = copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0; + break; case SNDCTL_DSP_NONBLOCK: file->f_flags |= O_NONBLOCK; - return 0; + break; case SNDCTL_DSP_GETCAPS: - return put_user(DSP_CAP_REALTIME|DSP_CAP_TRIGGER|DSP_CAP_MMAP|DSP_CAP_BIND, + ret = put_user(DSP_CAP_REALTIME|DSP_CAP_TRIGGER|DSP_CAP_MMAP|DSP_CAP_BIND, (int *)arg); + break; case SNDCTL_DSP_GETTRIGGER: val = 0; @@ -1978,15 +2124,19 @@ val |= PCM_ENABLE_INPUT; if ((file->f_mode & FMODE_WRITE) && dmabuf->enable) val |= PCM_ENABLE_OUTPUT; - return put_user(val, (int *)arg); + ret = put_user(val, (int *)arg); + break; case SNDCTL_DSP_SETTRIGGER: if (get_user(val, (int *)arg)) - return -EFAULT; + { + ret = -EFAULT; + break; + } if (file->f_mode & FMODE_READ) { if (val & PCM_ENABLE_INPUT) { if (!dmabuf->ready && (ret = prog_dmabuf(state, 1))) - return ret; + break; start_adc(state); } else stop_adc(state); @@ -1994,18 +2144,24 @@ if (file->f_mode & FMODE_WRITE) { if (val & PCM_ENABLE_OUTPUT) { if (!dmabuf->ready && (ret = prog_dmabuf(state, 0))) - return ret; + break; start_dac(state); } else stop_dac(state); } - return 0; + break; case SNDCTL_DSP_GETIPTR: if (!(file->f_mode & FMODE_READ)) - return -EINVAL; + { + ret = -EINVAL; + break; + } if (!dmabuf->ready && (val = prog_dmabuf(state, 1)) != 0) - return val; + { + ret = val; + break; + } spin_lock_irqsave(&state->card->lock, flags); trident_update_ptr(state); cinfo.bytes = dmabuf->total_bytes; @@ -2014,13 +2170,21 @@ if (dmabuf->mapped) dmabuf->count &= dmabuf->fragsize-1; spin_unlock_irqrestore(&state->card->lock, flags); - return copy_to_user((void *)arg, &cinfo, sizeof(cinfo)); + ret = copy_to_user((void *)arg, &cinfo, sizeof(cinfo)); + break; case SNDCTL_DSP_GETOPTR: if (!(file->f_mode & FMODE_WRITE)) - return -EINVAL; + { + ret = -EINVAL; + break; + } if (!dmabuf->ready && (val = prog_dmabuf(state, 0)) != 0) - return val; + { + ret = val; + break; + } + spin_lock_irqsave(&state->card->lock, flags); trident_update_ptr(state); cinfo.bytes = dmabuf->total_bytes; @@ -2029,43 +2193,62 @@ if (dmabuf->mapped) dmabuf->count &= dmabuf->fragsize-1; spin_unlock_irqrestore(&state->card->lock, flags); - return copy_to_user((void *)arg, &cinfo, sizeof(cinfo)); + ret = copy_to_user((void *)arg, &cinfo, sizeof(cinfo))?-EFAULT:0; + break; case SNDCTL_DSP_SETDUPLEX: - return -EINVAL; + ret = -EINVAL; + break; case SNDCTL_DSP_GETODELAY: if (!(file->f_mode & FMODE_WRITE)) - return -EINVAL; + { + ret = -EINVAL; + break; + } if (!dmabuf->ready && (val = prog_dmabuf(state, 0)) != 0) - return val; + { + ret = val; + break; + } spin_lock_irqsave(&state->card->lock, flags); trident_update_ptr(state); val = dmabuf->count; spin_unlock_irqrestore(&state->card->lock, flags); - return put_user(val, (int *)arg); + ret = put_user(val, (int *)arg); + break; case SOUND_PCM_READ_RATE: - return put_user(dmabuf->rate, (int *)arg); + ret = put_user(dmabuf->rate, (int *)arg); + break; case SOUND_PCM_READ_CHANNELS: - return put_user((dmabuf->fmt & TRIDENT_FMT_STEREO) ? 2 : 1, + ret = put_user((dmabuf->fmt & TRIDENT_FMT_STEREO) ? 2 : 1, (int *)arg); + break; case SOUND_PCM_READ_BITS: - return put_user((dmabuf->fmt & TRIDENT_FMT_16BIT) ? + ret = put_user((dmabuf->fmt & TRIDENT_FMT_16BIT) ? AFMT_S16_LE : AFMT_U8, (int *)arg); + break; case SNDCTL_DSP_GETCHANNELMASK: - return put_user(DSP_BIND_FRONT|DSP_BIND_SURR|DSP_BIND_CENTER_LFE, + ret = put_user(DSP_BIND_FRONT|DSP_BIND_SURR|DSP_BIND_CENTER_LFE, (int *)arg); + break; case SNDCTL_DSP_BIND_CHANNEL: if (state->card->pci_id != PCI_DEVICE_ID_SI_7018) - return -EINVAL; + { + ret = -EINVAL; + break; + } if (get_user(val, (int *)arg)) - return -EFAULT; + { + ret = -EFAULT; + break; + } if (val == DSP_BIND_QUERY) { val = dmabuf->channel->attribute | 0x3c00; val = attr2mask[val >> 8]; @@ -2077,17 +2260,20 @@ dmabuf->channel->attribute = (CHANNEL_SPC_PB|SRC_ENABLE); dmabuf->channel->attribute |= mask2attr[ffs(val)]; } - return put_user(val, (int *)arg); + ret = put_user(val, (int *)arg); + break; case SNDCTL_DSP_MAPINBUF: case SNDCTL_DSP_MAPOUTBUF: case SNDCTL_DSP_SETSYNCRO: case SOUND_PCM_WRITE_FILTER: case SOUND_PCM_READ_FILTER: - return -EINVAL; + default: + ret = -EINVAL; + break; } - return -EINVAL; + return ret; } static int trident_open(struct inode *inode, struct file *file) @@ -2098,7 +2284,16 @@ struct trident_state *state = NULL; struct dmabuf *dmabuf = NULL; - /* find an avaiable virtual channel (instance of /dev/dsp) */ + /* Added by Matt Wu 01-05-2001 */ + if(file->f_mode & FMODE_READ) + { + if(card->pci_id == PCI_DEVICE_ID_ALI_5451) { + if (card->multi_channel_use_count > 0) + return -EBUSY; + } + } + + /* find an available virtual channel (instance of /dev/dsp) */ while (card != NULL) { down(&card->open_sem); if(file->f_mode & FMODE_READ) @@ -2119,6 +2314,7 @@ return -ENOMEM; } memset(state, 0, sizeof(struct trident_state)); + init_MUTEX(&state->sem); dmabuf = &state->dmabuf; goto found_virt; } @@ -2183,7 +2379,10 @@ (CHANNEL_REC|PCM_LR|MONO_MIX); } trident_set_adc_rate(state, 8000); - card->rec_channel_use_count ++; + + /* Added by Matt Wu 01-05-2001 */ + if(card->pci_id == PCI_DEVICE_ID_ALI_5451) + card->rec_channel_use_count ++; } state->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE); @@ -2225,15 +2424,15 @@ dealloc_dmabuf(state); state->card->free_pcm_channel(state->card, dmabuf->channel->num); - if (state->chans_num > 2) - { - if( card->multi_channel_use_count-- < 0 ) - card->multi_channel_use_count = 0; - - if (card->multi_channel_use_count == 0) - ali_close_multi_channels(); - - ali_free_other_states_resources(state); + /* Added by Matt Wu */ + if (card->pci_id == PCI_DEVICE_ID_ALI_5451) { + if (state->chans_num > 2) { + if (card->multi_channel_use_count-- < 0) + card->multi_channel_use_count = 0; + if (card->multi_channel_use_count == 0) + ali_close_multi_channels(); + ali_free_other_states_resources(state); + } } } if (file->f_mode & FMODE_READ) { @@ -2241,8 +2440,11 @@ dealloc_dmabuf(state); state->card->free_pcm_channel(state->card, dmabuf->channel->num); - if( card->rec_channel_use_count-- < 0 ) - card->rec_channel_use_count = 0; + /* Added by Matt Wu */ + if (card->pci_id == PCI_DEVICE_ID_ALI_5451) { + if( card->rec_channel_use_count-- < 0 ) + card->rec_channel_use_count = 0; + } } card->states[state->virt] = NULL; @@ -2373,9 +2575,8 @@ } /* Write AC97 codec registers for ALi*/ -static void ali_ac97_set(struct ac97_codec *codec, u8 reg, u16 val) +static void ali_ac97_set(struct trident_card *card, int secondary, u8 reg, u16 val) { - struct trident_card *card = (struct trident_card *)codec->private_data; unsigned int address, mask; unsigned int wCount1 = 0xffff; unsigned int wCount2= 0xffff; @@ -2390,7 +2591,7 @@ address = ALI_AC97_WRITE; mask = ALI_AC97_WRITE_ACTION | ALI_AC97_AUDIO_BUSY; - if (codec->id) + if (secondary) mask |= ALI_AC97_SECONDARY; if (card->revision == ALI_5451_V02) mask |= ALI_AC97_WRITE_MIXER_REGISTER; @@ -2421,9 +2622,8 @@ } /* Read AC97 codec registers for ALi*/ -static u16 ali_ac97_get(struct ac97_codec *codec, u8 reg) +static u16 ali_ac97_get(struct trident_card *card, int secondary, u8 reg) { - struct trident_card *card = (struct trident_card *)codec->private_data; unsigned int address, mask; unsigned int wCount1 = 0xffff; unsigned int wCount2= 0xffff; @@ -2431,13 +2631,15 @@ unsigned long flags; u32 data; + if(!card) + BUG(); + address = ALI_AC97_READ; if (card->revision == ALI_5451_V02) { address = ALI_AC97_WRITE; - mask &= ALI_AC97_READ_MIXER_REGISTER; } mask = ALI_AC97_READ_ACTION | ALI_AC97_AUDIO_BUSY; - if (codec->id) + if (secondary) mask |= ALI_AC97_SECONDARY; spin_lock_irqsave(&card->lock, flags); @@ -2480,6 +2682,56 @@ outl(s_channels, TRID_REG(card, ALI_GLOBAL_CONTROL)); } +static u16 ali_ac97_read(struct ac97_codec *codec, u8 reg) +{ + int id; + u16 data; + struct trident_card *card = NULL; + + /* Added by Matt Wu */ + if (!codec) + BUG(); + + card = (struct trident_card *)codec->private_data; + + if(!card->mixer_regs_ready) + return ali_ac97_get(card, codec->id, reg); + + if(codec->id) + id = 1; + else + id = 0; + + data = card->mixer_regs[reg/2][id]; + return data; +} + +static void ali_ac97_write(struct ac97_codec *codec, u8 reg, u16 val) +{ + int id; + struct trident_card *card; + + /* Added by Matt Wu */ + if (!codec) + BUG(); + + card = (struct trident_card *)codec->private_data; + + if (!card->mixer_regs_ready) + { + ali_ac97_set(card, codec->id, reg, val); + return; + } + + if(codec->id) + id = 1; + else + id = 0; + + card->mixer_regs[reg/2][id] = val; + ali_ac97_set(card, codec->id, reg, val); +} + /* flag: ALI_SPDIF_OUT_TO_SPDIF_OUT ALI_PCM_TO_SPDIF_OUT @@ -2493,7 +2745,7 @@ char temp; struct pci_dev *pci_dev = NULL; - pci_dev = pci_find_device(PCI_VENDOR_ID_AL,PCI_DEVICE_ID_AL_M1533, pci_dev); + pci_dev = pci_find_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, pci_dev); if (pci_dev == NULL) return; pci_read_config_byte(pci_dev, 0x61, &temp); @@ -2748,14 +3000,14 @@ mdelay(4); dwValue = inl(TRID_REG(card, ALI_SCTRL)); if (dwValue & 0x2000000) { - ali_ac97_set(card->ac97_codec[0], 0x02, 8080); - ali_ac97_set(card->ac97_codec[0], 0x36, 0); - ali_ac97_set(card->ac97_codec[0], 0x38, 0); - ali_ac97_set(card->ac97_codec[1], 0x36, 0); - ali_ac97_set(card->ac97_codec[1], 0x38, 0); - ali_ac97_set(card->ac97_codec[1], 0x02, 0); - ali_ac97_set(card->ac97_codec[1], 0x18, 0x0808); - ali_ac97_set(card->ac97_codec[1], 0x74, 0x3); + ali_ac97_write(card->ac97_codec[0], 0x02, 8080); + ali_ac97_write(card->ac97_codec[0], 0x36, 0); + ali_ac97_write(card->ac97_codec[0], 0x38, 0); + ali_ac97_write(card->ac97_codec[1], 0x36, 0); + ali_ac97_write(card->ac97_codec[1], 0x38, 0); + ali_ac97_write(card->ac97_codec[1], 0x02, 0x0606); + ali_ac97_write(card->ac97_codec[1], 0x18, 0x0303); + ali_ac97_write(card->ac97_codec[1], 0x74, 0x3); return 1; } } @@ -2853,7 +3105,7 @@ outl(ALI_DISABLE_ALL_IRQ, TRID_REG(card, T4D_MISCINT)); for (i = 1; i < ALI_MIXER_REGS; i++) - ali_registers.mixer_regs[i] = ali_ac97_get (card->ac97_codec[0], i*2); + ali_registers.mixer_regs[i] = ali_ac97_read (card->ac97_codec[0], i*2); for (i = 0; i < ALI_GLOBAL_REGS; i++) { @@ -2884,7 +3136,7 @@ cli(); for (i = 1; i < ALI_MIXER_REGS; i++) - ali_ac97_set(card->ac97_codec[0], i*2, ali_registers.mixer_regs[i]); + ali_ac97_write(card->ac97_codec[0], i*2, ali_registers.mixer_regs[i]); for (i = 0; i < ALI_CHANNELS; i++) { @@ -2908,19 +3160,22 @@ restore_flags(flags); } -static int ali_pm_callback(struct pm_dev *dev, pm_request_t rqst, void *data) +static int trident_suspend(struct pci_dev *dev, u32 unused) { - struct trident_card *card = (struct trident_card *)dev->data; - - if (card) { - switch (rqst) { - case PM_SUSPEND: - ali_save_regs(card); - break; - case PM_RESUME: - ali_restore_regs(card); - break; - } + struct trident_card *card = (struct trident_card *) dev; + + if(card->pci_id == PCI_DEVICE_ID_ALI_5451) { + ali_save_regs(card); + } + return 0; +} + +static int trident_resume(struct pci_dev *dev) +{ + struct trident_card *card = (struct trident_card *) dev; + + if(card->pci_id == PCI_DEVICE_ID_ALI_5451) { + ali_restore_regs(card); } return 0; } @@ -3236,29 +3491,75 @@ open: trident_open_mixdev, }; +static int ali_reset_5451(struct trident_card *card) +{ + struct pci_dev *pci_dev = NULL; + unsigned int dwVal; + unsigned short wCount, wReg; + + pci_dev = pci_find_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, pci_dev); + if (pci_dev == NULL) + return -1; + + pci_read_config_dword(pci_dev, 0x7c, &dwVal); + pci_write_config_dword(pci_dev, 0x7c, dwVal | 0x08000000); + udelay(5000); + pci_read_config_dword(pci_dev, 0x7c, &dwVal); + pci_write_config_dword(pci_dev, 0x7c, dwVal & 0xf7ffffff); + udelay(5000); + + pci_dev = card->pci_dev; + if (pci_dev == NULL) + return -1; + + pci_read_config_dword(pci_dev, 0x44, &dwVal); + pci_write_config_dword(pci_dev, 0x44, dwVal | 0x000c0000); + udelay(500); + pci_read_config_dword(pci_dev, 0x44, &dwVal); + pci_write_config_dword(pci_dev, 0x44, dwVal & 0xfffbffff); + udelay(5000); + + wCount = 200; + while(wCount--) { + wReg = ali_ac97_get(card, 0, AC97_POWER_CONTROL); + if((wReg & 0x000f) == 0x000f) + return 0; + udelay(500); + } + return 0; +} + /* AC97 codec initialisation. */ static int __init trident_ac97_init(struct trident_card *card) { int num_ac97 = 0; unsigned long ready_2nd = 0; struct ac97_codec *codec; + int i = 0; + /* initialize controller side of AC link, and find out if secondary codes really exist */ switch (card->pci_id) { case PCI_DEVICE_ID_ALI_5451: - outl(0x80000000,TRID_REG(card, ALI_GLOBAL_CONTROL)); - outl(0x00000000,TRID_REG(card, 0xa4)); - outl(0xffffffff,TRID_REG(card, 0x98)); - outl(0x00000000,TRID_REG(card, 0xa8)); - outb(0x10, TRID_REG(card, 0x22)); + if (ali_reset_5451(card)) + { + printk(KERN_ERR "trident_ac97_init: error resetting 5451.\n"); + return -1; + } + outl(0x80000001,TRID_REG(card, ALI_GLOBAL_CONTROL)); + outl(0x00000000,TRID_REG(card, T4D_AINTEN_A)); + outl(0xffffffff,TRID_REG(card, T4D_AINT_A)); + outl(0x00000000,TRID_REG(card, T4D_MUSICVOL_WAVEVOL)); + outb(0x10, TRID_REG(card, ALI_MPUR2)); ready_2nd = inl(TRID_REG(card, ALI_SCTRL)); ready_2nd &= 0x3fff; outl(ready_2nd | PCMOUT | 0x8000, TRID_REG(card, ALI_SCTRL)); ready_2nd = inl(TRID_REG(card, ALI_SCTRL)); ready_2nd &= SI_AC97_SECONDARY_READY; -// printk("codec 2 ready flag= %lx\n", ready_2nd); + if (card->revision < ALI_5451_V02) + ready_2nd = 0; break; case PCI_DEVICE_ID_SI_7018: /* disable AC97 GPIO interrupt */ @@ -3295,8 +3596,8 @@ codec->id = num_ac97; if (card->pci_id == PCI_DEVICE_ID_ALI_5451) { - codec->codec_read = ali_ac97_get; - codec->codec_write = ali_ac97_set; + codec->codec_read = ali_ac97_read; + codec->codec_write = ali_ac97_write; } else { codec->codec_read = trident_ac97_get; @@ -3316,10 +3617,18 @@ /* if there is no secondary codec at all, don't probe any more */ if (!ready_2nd) - return num_ac97+1; + break; } - return 1/*num_ac97*/; + if (card->pci_id == PCI_DEVICE_ID_ALI_5451) { + for (num_ac97 = 0; num_ac97 < NR_AC97; num_ac97++) { + if (card->ac97_codec[num_ac97] == NULL) + break; + for (i=0; i<64;i++) + card->mixer_regs[i][num_ac97] = ali_ac97_get(card, num_ac97,i*2); + } + } + return num_ac97+1; } /* install the driver, we do not allocate hardware channel nor DMA buffer now, they are defered @@ -3331,20 +3640,14 @@ dma_addr_t mask; int bits; u8 revision; + int i = 0; if (pci_enable_device(pci_dev)) return -ENODEV; - if (pci_dev->device == PCI_DEVICE_ID_ALI_5451) { - mask = 0xffffffff; - bits = 32; - } else { - mask = TRIDENT_DMA_MASK; - bits = 30; - } - if (pci_set_dma_mask(pci_dev, mask)) { + if (pci_set_dma_mask(pci_dev, TRIDENT_DMA_MASK)) { printk(KERN_ERR "trident: architecture does not support" - " %dbit PCI busmaster DMA\n", bits); + " 30bit PCI busmaster DMA\n"); return -ENODEV; } pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &revision); @@ -3383,14 +3686,6 @@ card_names[pci_id->driver_data], card->iobase, card->irq); if(card->pci_id == PCI_DEVICE_ID_ALI_5451) { - /* ALi Power Management */ - struct pm_dev *pmdev; - - pmdev = pm_register(PM_PCI_DEV, PM_PCI_ID(pci_dev), - ali_pm_callback); - if (pmdev) - pmdev->data = card; - /* ALi channel Management */ card->alloc_pcm_channel = ali_alloc_pcm_channel; card->alloc_rec_pcm_channel = ali_alloc_rec_pcm_channel; @@ -3438,22 +3733,38 @@ kfree(card); return -ENODEV; } + card->mixer_regs_ready = 0; /* initialize AC97 codec and register /dev/mixer */ if (trident_ac97_init(card) <= 0) { + /* unregister audio devices */ + for (i = 0; i < NR_AC97; i++) { + if (card->ac97_codec[i] != NULL) { + unregister_sound_mixer(card->ac97_codec[i]->dev_mixer); + kfree (card->ac97_codec[i]); + } + } unregister_sound_dsp(card->dev_audio); release_region(iobase, 256); free_irq(card->irq, card); kfree(card); return -ENODEV; } + card->mixer_regs_ready = 1; outl(0x00, TRID_REG(card, T4D_MUSICVOL_WAVEVOL)); if (card->pci_id == PCI_DEVICE_ID_ALI_5451) { + if(card->revision == ALI_5451_V02) + ali_close_multi_channels(); /* edited by HMSEO for GT sound */ -#ifdef CONFIG_ALPHA_NAUTILUS +#if defined CONFIG_ALPHA_NAUTILUS || CONFIG_ALPHA_GENERIC u16 ac97_data; - ac97_data = ali_ac97_get (card->ac97_codec[0], AC97_POWER_CONTROL); - ali_ac97_set (card->ac97_codec[0], AC97_POWER_CONTROL, ac97_data | ALI_EAPD_POWER_DOWN); + extern struct hwrpb_struct *hwrpb; + + if ((hwrpb->sys_type) == 201) { + printk(KERN_INFO "trident: Running on Alpha system type Nautilus\n"); + ac97_data = ali_ac97_get(card, 0, AC97_POWER_CONTROL); + ali_ac97_set(card, 0, AC97_POWER_CONTROL, ac97_data | + } #endif /* edited by HMSEO for GT sound*/ } @@ -3479,7 +3790,6 @@ #ifdef CONFIG_PROC_FS remove_proc_entry("ALi5451", NULL); #endif - pm_unregister_all(ali_pm_callback); } /* Kill interrupts, and SP/DIF */ @@ -3512,6 +3822,8 @@ id_table: trident_pci_tbl, probe: trident_probe, remove: trident_remove, + suspend: trident_suspend, + resume: trident_resume }; static int __init trident_init_module (void) diff -u --recursive --new-file v2.4.6/linux/drivers/sound/trident.h linux/drivers/sound/trident.h --- v2.4.6/linux/drivers/sound/trident.h Thu Oct 26 23:07:58 2000 +++ linux/drivers/sound/trident.h Sun Jul 15 16:22:23 2001 @@ -90,7 +90,10 @@ T4D_STOP_B = 0xb8, T4D_CSPF_B = 0xbc, T4D_SBBL_SBCL = 0xc0, T4D_SBCTRL_SBE2R_SBDD = 0xc4, T4D_STIMER = 0xc8, T4D_LFO_B_I2S_DELTA = 0xcc, - T4D_AINT_B = 0xd8, T4D_AINTEN_B = 0xdc + T4D_AINT_B = 0xd8, T4D_AINTEN_B = 0xdc, + ALI_MPUR2 = 0x22, + ALI_EBUF1 = 0xf4, + ALI_EBUF2 = 0xf8 }; enum ali_op_registers { @@ -136,7 +139,13 @@ ALI_CHANNELS = 32, ALI_STOP_ALL_CHANNELS = 0xffffffff, ALI_MULTI_CHANNELS_START_STOP = 0x07800000 +}; +enum ali_EMOD_control_bit { + ALI_EMOD_DEC = 0x00000000, + ALI_EMOD_INC = 0x10000000, + ALI_EMOD_Delay = 0x20000000, + ALI_EMOD_Still = 0x30000000 }; enum ali_pcm_in_channel_num { diff -u --recursive --new-file v2.4.6/linux/drivers/sound/wavfront.c linux/drivers/sound/wavfront.c --- v2.4.6/linux/drivers/sound/wavfront.c Tue Jul 3 17:08:21 2001 +++ linux/drivers/sound/wavfront.c Sun Jul 15 16:22:23 2001 @@ -166,7 +166,7 @@ /*** Module-accessible parameters ***************************************/ -int wf_raw = 0; /* we normally check for "raw state" to firmware +int wf_raw; /* we normally check for "raw state" to firmware loading. if set, then during driver loading, the state of the board is ignored, and we reset the board and load the firmware anyway. @@ -179,7 +179,7 @@ operation, whatever that means. */ -int debug_default = 0; /* you can set this to control debugging +int debug_default; /* you can set this to control debugging during driver loading. it takes any combination of the WF_DEBUG_* flags defined in wavefront.h diff -u --recursive --new-file v2.4.6/linux/drivers/sound/ymfpci.c linux/drivers/sound/ymfpci.c --- v2.4.6/linux/drivers/sound/ymfpci.c Tue Jul 3 17:08:21 2001 +++ linux/drivers/sound/ymfpci.c Wed Jul 4 11:50:39 2001 @@ -23,14 +23,9 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * TODO: - * - Use P44Slot for 44.1 playback. + * - Use P44Slot for 44.1 playback (beware of idle buzzing in P44Slot). * - 96KHz playback for DVD - use pitch of 2.0. - * - uLaw for Sun apps. - * : Alan says firmly "no software format conversion in kernel". * - Retain DMA buffer on close, do not wait the end of frame. - * - Cleanup - * ? underused structure members - * - Remove remaining P3 tags (debug messages). * - Resolve XXX tagged questions. * - Cannot play 5133Hz. * - 2001/01/07 Consider if we can remove voice_lock, like so: @@ -66,14 +61,28 @@ #endif #include "ymfpci.h" -static int ymf_playback_trigger(ymfpci_t *codec, struct ymf_pcm *ypcm, int cmd); +/* + * I do not believe in debug levels as I never can guess what + * part of the code is going to be problematic in the future. + * Don't forget to run your klogd with -c 8. + */ +/* #define YMFDBG(fmt, arg...) do{ printk(KERN_DEBUG fmt, ##arg); }while(0) */ +#define YMFDBGW(fmt, arg...) /* */ +#define YMFDBGI(fmt, arg...) /* */ + +static int ymf_playback_trigger(ymfpci_t *unit, struct ymf_pcm *ypcm, int cmd); static void ymf_capture_trigger(ymfpci_t *unit, struct ymf_pcm *ypcm, int cmd); -static void ymfpci_voice_free(ymfpci_t *codec, ymfpci_voice_t *pvoice); +static void ymfpci_voice_free(ymfpci_t *unit, ymfpci_voice_t *pvoice); static int ymf_capture_alloc(struct ymf_unit *unit, int *pbank); static int ymf_playback_prepare(struct ymf_state *state); static int ymf_capture_prepare(struct ymf_state *state); static struct ymf_state *ymf_state_alloc(ymfpci_t *unit); +static void ymfpci_aclink_reset(struct pci_dev * pci); +static void ymfpci_disable_dsp(ymfpci_t *unit); +static void ymfpci_download_image(ymfpci_t *codec); +static void ymf_memload(ymfpci_t *unit); + static LIST_HEAD(ymf_devs); /* @@ -237,8 +246,7 @@ } /* - * XXX Find if this function exists in the OSS framework. - * XXX Make sure we do no panic when ADPCM is selected. + * We ever allow only a few formats, but let's be generic, for smaller surprise. */ static int ymf_pcm_format_width(int format) { @@ -330,7 +338,7 @@ spin_lock_irqsave(&state->unit->reg_lock, flags); dmabuf->hwptr = dmabuf->swptr = 0; dmabuf->total_bytes = 0; - dmabuf->count = dmabuf->error = 0; + dmabuf->count = 0; spin_unlock_irqrestore(&state->unit->reg_lock, flags); /* allocate DMA buffer if not allocated yet */ @@ -579,9 +587,9 @@ dmabuf = &ypcm->dmabuf; spin_lock(&codec->reg_lock); if (ypcm->running) { -/* P3 */ /** printk("ymfpci: %d, intr bank %d count %d start 0x%x:%x\n", - voice->number, codec->active_bank, dmabuf->count, - voice->bank[0].start, voice->bank[1].start); **/ + YMFDBGI("ymfpci: %d, intr bank %d count %d start 0x%x:%x\n", + voice->number, codec->active_bank, dmabuf->count, + voice->bank[0].start, voice->bank[1].start); silence = (ymf_pcm_format_width(state->format.format) == 16) ? 0 : 0x80; /* We need actual left-hand-side redzone size here. */ @@ -810,8 +818,6 @@ end >>= 1; if (w_16) end >>= 1; -/* P3 */ // printk("ymf_pcm_init_voice: %d: Rate %d Format 0x%08x Delta 0x%x End 0x%x\n", -// voice->number, rate, format, delta, end); for (nbank = 0; nbank < 2; nbank++) { bank = &voice->bank[nbank]; bank->format = format; @@ -907,7 +913,7 @@ if ((err = ymfpci_pcm_voice_alloc(ypcm, state->format.voices)) < 0) { /* Somebody started 32 mpg123's in parallel? */ - /* P3 */ printk("ymfpci%d: cannot allocate voice\n", + printk(KERN_INFO "ymfpci%d: cannot allocate voice\n", state->unit->dev_audio); return err; } @@ -1178,6 +1184,7 @@ { struct ymf_state *state = (struct ymf_state *)file->private_data; struct ymf_dmabuf *dmabuf = &state->rpcm.dmabuf; + struct ymf_unit *unit = state->unit; DECLARE_WAITQUEUE(waita, current); ssize_t ret; unsigned long flags; @@ -1190,18 +1197,26 @@ return -ENXIO; if (!dmabuf->ready && (ret = prog_dmabuf(state, 1))) return ret; - if (!access_ok(VERIFY_WRITE, buffer, count)) - return -EFAULT; ret = 0; add_wait_queue(&dmabuf->wait, &waita); while (count > 0) { - spin_lock_irqsave(&state->unit->reg_lock, flags); + spin_lock_irqsave(&unit->reg_lock, flags); + if (unit->suspended) { + spin_unlock_irqrestore(&unit->reg_lock, flags); + set_current_state(TASK_INTERRUPTIBLE); + schedule(); + if (signal_pending(current)) { + if (!ret) ret = -EAGAIN; + break; + } + continue; + } swptr = dmabuf->swptr; cnt = dmabuf->dmasize - swptr; if (dmabuf->count < cnt) cnt = dmabuf->count; - spin_unlock_irqrestore(&state->unit->reg_lock, flags); + spin_unlock_irqrestore(&unit->reg_lock, flags); if (cnt > count) cnt = count; @@ -1240,7 +1255,7 @@ } spin_unlock_irqrestore(&state->unit->reg_lock, flags); if (signal_pending(current)) { - ret = ret ? ret : -ERESTARTSYS; + if (!ret) ret = -ERESTARTSYS; break; } continue; @@ -1253,19 +1268,24 @@ swptr = (swptr + cnt) % dmabuf->dmasize; - spin_lock_irqsave(&state->unit->reg_lock, flags); + spin_lock_irqsave(&unit->reg_lock, flags); + if (unit->suspended) { + spin_unlock_irqrestore(&unit->reg_lock, flags); + continue; + } + dmabuf->swptr = swptr; dmabuf->count -= cnt; - // spin_unlock_irqrestore(&state->unit->reg_lock, flags); + // spin_unlock_irqrestore(&unit->reg_lock, flags); count -= cnt; buffer += cnt; ret += cnt; - // spin_lock_irqsave(&state->unit->reg_lock, flags); + // spin_lock_irqsave(&unit->reg_lock, flags); if (!state->rpcm.running) { - ymf_capture_trigger(state->unit, &state->rpcm, 1); + ymf_capture_trigger(unit, &state->rpcm, 1); } - spin_unlock_irqrestore(&state->unit->reg_lock, flags); + spin_unlock_irqrestore(&unit->reg_lock, flags); } set_current_state(TASK_RUNNING); remove_wait_queue(&dmabuf->wait, &waita); @@ -1278,6 +1298,7 @@ { struct ymf_state *state = (struct ymf_state *)file->private_data; struct ymf_dmabuf *dmabuf = &state->wpcm.dmabuf; + struct ymf_unit *unit = state->unit; DECLARE_WAITQUEUE(waita, current); ssize_t ret; unsigned long flags; @@ -1286,7 +1307,7 @@ int redzone; int delay; -/* P3 */ /* printk("ymf_write: count %d\n", count); */ + YMFDBGW("ymf_write: count %d\n", count); if (ppos != &file->f_pos) return -ESPIPE; @@ -1294,8 +1315,6 @@ return -ENXIO; if (!dmabuf->ready && (ret = prog_dmabuf(state, 0))) return ret; - if (!access_ok(VERIFY_READ, buffer, count)) - return -EFAULT; ret = 0; /* @@ -1310,7 +1329,17 @@ add_wait_queue(&dmabuf->wait, &waita); while (count > 0) { - spin_lock_irqsave(&state->unit->reg_lock, flags); + spin_lock_irqsave(&unit->reg_lock, flags); + if (unit->suspended) { + spin_unlock_irqrestore(&unit->reg_lock, flags); + set_current_state(TASK_INTERRUPTIBLE); + schedule(); + if (signal_pending(current)) { + if (!ret) ret = -EAGAIN; + break; + } + continue; + } if (dmabuf->count < 0) { printk(KERN_ERR "ymf_write: count %d, was legal in cs46xx\n", @@ -1342,22 +1371,22 @@ cnt = dmabuf->dmasize - swptr; if (dmabuf->count + cnt > dmabuf->dmasize - redzone) cnt = (dmabuf->dmasize - redzone) - dmabuf->count; - spin_unlock_irqrestore(&state->unit->reg_lock, flags); + spin_unlock_irqrestore(&unit->reg_lock, flags); if (cnt > count) cnt = count; if (cnt <= 0) { -/* P3 */ /* printk("ymf_write: full, count %d swptr %d\n", - dmabuf->count, dmabuf->swptr); */ + YMFDBGW("ymf_write: full, count %d swptr %d\n", + dmabuf->count, dmabuf->swptr); /* * buffer is full, start the dma machine and * wait for data to be played */ - spin_lock_irqsave(&state->unit->reg_lock, flags); + spin_lock_irqsave(&unit->reg_lock, flags); if (!state->wpcm.running) { - ymf_playback_trigger(state->unit, &state->wpcm, 1); + ymf_playback_trigger(unit, &state->wpcm, 1); } - spin_unlock_irqrestore(&state->unit->reg_lock, flags); + spin_unlock_irqrestore(&unit->reg_lock, flags); if (file->f_flags & O_NONBLOCK) { if (!ret) ret = -EAGAIN; break; @@ -1379,7 +1408,11 @@ swptr -= dmabuf->dmasize; } - spin_lock_irqsave(&state->unit->reg_lock, flags); + spin_lock_irqsave(&unit->reg_lock, flags); + if (unit->suspended) { + spin_unlock_irqrestore(&unit->reg_lock, flags); + continue; + } dmabuf->swptr = swptr; dmabuf->count += cnt; @@ -1393,10 +1426,10 @@ delay = state->format.rate / 20; /* 50ms */ delay <<= state->format.shift; if (dmabuf->count >= delay && !state->wpcm.running) { - ymf_playback_trigger(state->unit, &state->wpcm, 1); + ymf_playback_trigger(unit, &state->wpcm, 1); } - spin_unlock_irqrestore(&state->unit->reg_lock, flags); + spin_unlock_irqrestore(&unit->reg_lock, flags); count -= cnt; buffer += cnt; @@ -1406,7 +1439,7 @@ set_current_state(TASK_RUNNING); remove_wait_queue(&dmabuf->wait, &waita); -/* P3 */ /* printk("ymf_write: dmabuf.count %d\n", dmabuf->count); */ + YMFDBGW("ymf_write: dmabuf.count %d\n", dmabuf->count); return ret; } @@ -1621,7 +1654,6 @@ case SNDCTL_DSP_CHANNELS: if (get_user(val, (int *)arg)) return -EFAULT; - /* P3 */ /* printk("ymfpci: ioctl SNDCTL_DSP_CHANNELS 0x%x\n", val); */ if (val != 0) { if (file->f_mode & FMODE_WRITE) { ymf_wait_dac(state); @@ -1667,19 +1699,6 @@ spin_unlock_irqrestore(&state->unit->reg_lock, flags); return 0; -#if 0 /* XXX Was dummy implementation anyways. Make sense of this. */ - case SNDCTL_DSP_SUBDIVIDE: - dmabuf = &state->wpcm.dmabuf; - if (dmabuf->subdivision) - return -EINVAL; - if (get_user(val, (int *)arg)) - return -EFAULT; - if (val != 1 && val != 2) - return -EINVAL; - dmabuf->subdivision = val; - return 0; -#endif - case SNDCTL_DSP_SETFRAGMENT: if (get_user(val, (int *)arg)) return -EFAULT; @@ -1729,40 +1748,6 @@ (int *)arg); */ return put_user(0, (int *)arg); -#if 0 /* not implememnted, yet? */ - case SNDCTL_DSP_GETTRIGGER: - val = 0; - dmabuf = &state->wpcm.dmabuf; - if (file->f_mode & FMODE_READ && dmabuf->enable) - val |= PCM_ENABLE_INPUT; - if (file->f_mode & FMODE_WRITE && dmabuf->enable) - val |= PCM_ENABLE_OUTPUT; - return put_user(val, (int *)arg); - - case SNDCTL_DSP_SETTRIGGER: - if (get_user(val, (int *)arg)) - return -EFAULT; - if (file->f_mode & FMODE_READ) { - dmabuf = &state->rpcm.dmabuf; - if (val & PCM_ENABLE_INPUT) { - if (!dmabuf->ready && (ret = prog_dmabuf(state, 1))) - return ret; - start_adc(state); - } else - stop_adc(state); - } - if (file->f_mode & FMODE_WRITE) { - dmabuf = &state->wpcm.dmabuf; - if (val & PCM_ENABLE_OUTPUT) { - if (!dmabuf->ready && (ret = prog_dmabuf(state, 0))) - return ret; - start_dac(state); // sure? - } else - stop_dac(state); - } - return 0; -#endif - case SNDCTL_DSP_GETIPTR: if (!(file->f_mode & FMODE_READ)) return -EINVAL; @@ -1794,18 +1779,6 @@ case SNDCTL_DSP_SETDUPLEX: /* XXX TODO */ return -EINVAL; -#if 0 /* XXX implement when an app found that uses it. */ - case SNDCTL_DSP_GETODELAY: - if (!(file->f_mode & FMODE_WRITE)) - return -EINVAL; - spin_lock_irqsave(&state->unit->reg_lock, flags); - cs_update_ptr(state); - dmabuf = &state->wpcm.dmabuf; - val = dmabuf->count; - spin_unlock_irqrestore(&state->unit->reg_lock, flags); - return put_user(val, (int *)arg); -#endif - case SOUND_PCM_READ_RATE: return put_user(state->format.rate, (int *)arg); @@ -1827,7 +1800,6 @@ * Some programs mix up audio devices and ioctls * or perhaps they expect "universal" ioctls, * for instance we get SNDCTL_TMR_CONTINUE here. - * XXX Is there sound_generic_ioctl() around? */ break; } @@ -2017,6 +1989,79 @@ }; /* + */ + +static int ymf_suspend(struct pci_dev *pcidev, u32 unused) +{ + struct ymf_unit *unit = pci_get_drvdata(pcidev); + unsigned long flags; + struct ymf_dmabuf *dmabuf; + struct list_head *p; + struct ymf_state *state; + + spin_lock_irqsave(&unit->reg_lock, flags); + + unit->suspended = 1; + + list_for_each(p, &unit->states) { + state = list_entry(p, struct ymf_state, chain); + + dmabuf = &state->wpcm.dmabuf; + dmabuf->hwptr = dmabuf->swptr = 0; + dmabuf->total_bytes = 0; + dmabuf->count = 0; + + dmabuf = &state->rpcm.dmabuf; + dmabuf->hwptr = dmabuf->swptr = 0; + dmabuf->total_bytes = 0; + dmabuf->count = 0; + } + + ymfpci_writel(unit, YDSXGR_NATIVEDACOUTVOL, 0); + ymfpci_disable_dsp(unit); + + spin_unlock_irqrestore(&unit->reg_lock, flags); + + return 0; +} + +static int ymf_resume(struct pci_dev *pcidev) +{ + struct ymf_unit *unit = pci_get_drvdata(pcidev); + unsigned long flags; + struct list_head *p; + struct ymf_state *state; + + ymfpci_aclink_reset(unit->pci); + ymfpci_codec_ready(unit, 0, 1); /* prints diag if not ready. */ + +#ifdef CONFIG_SOUND_YMFPCI_LEGACY + /* XXX At this time the legacy registers are probably deprogrammed. */ +#endif + + ymfpci_download_image(unit); + + ymf_memload(unit); + + spin_lock_irqsave(&unit->reg_lock, flags); + + if (unit->start_count) { + ymfpci_writel(unit, YDSXGR_MODE, 3); + unit->active_bank = ymfpci_readl(unit, YDSXGR_CTRLSELECT) & 1; + } + + unit->suspended = 0; + list_for_each(p, &unit->states) { + state = list_entry(p, struct ymf_state, chain); + wake_up(&state->wpcm.dmabuf.wait); + wake_up(&state->rpcm.dmabuf.wait); + } + + spin_unlock_irqrestore(&unit->reg_lock, flags); + return 0; +} + +/* * initialization routines */ @@ -2176,6 +2221,9 @@ } ymfpci_enable_dsp(codec); + + /* 0.02s sounds not too bad, we may do schedule_timeout() later. */ + mdelay(20); /* seems we need some delay after downloading image.. */ } static int ymfpci_memalloc(ymfpci_t *codec) @@ -2239,28 +2287,6 @@ ptr += (codec->bank_size_effect + 0x00ff) & ~0x00ff; codec->work_base = ptr; - ymfpci_writel(codec, YDSXGR_PLAYCTRLBASE, virt_to_bus(codec->bank_base_playback)); - ymfpci_writel(codec, YDSXGR_RECCTRLBASE, virt_to_bus(codec->bank_base_capture)); - ymfpci_writel(codec, YDSXGR_EFFCTRLBASE, virt_to_bus(codec->bank_base_effect)); - ymfpci_writel(codec, YDSXGR_WORKBASE, virt_to_bus(codec->work_base)); - ymfpci_writel(codec, YDSXGR_WORKSIZE, codec->work_size >> 2); - - /* S/PDIF output initialization */ - ymfpci_writew(codec, YDSXGR_SPDIFOUTCTRL, 0); - ymfpci_writew(codec, YDSXGR_SPDIFOUTSTATUS, - SND_PCM_AES0_CON_EMPHASIS_NONE | - (SND_PCM_AES1_CON_ORIGINAL << 8) | - (SND_PCM_AES1_CON_PCM_CODER << 8)); - - /* S/PDIF input initialization */ - ymfpci_writew(codec, YDSXGR_SPDIFINCTRL, 0); - - /* move this volume setup to mixer */ - ymfpci_writel(codec, YDSXGR_NATIVEDACOUTVOL, 0x3fff3fff); - ymfpci_writel(codec, YDSXGR_BUF441OUTVOL, 0); - ymfpci_writel(codec, YDSXGR_NATIVEADCINVOL, 0x3fff3fff); - ymfpci_writel(codec, YDSXGR_NATIVEDACINVOL, 0x3fff3fff); - return 0; } @@ -2274,6 +2300,32 @@ kfree(codec->work_ptr); } +static void ymf_memload(ymfpci_t *unit) +{ + + ymfpci_writel(unit, YDSXGR_PLAYCTRLBASE, virt_to_bus(unit->bank_base_playback)); + ymfpci_writel(unit, YDSXGR_RECCTRLBASE, virt_to_bus(unit->bank_base_capture)); + ymfpci_writel(unit, YDSXGR_EFFCTRLBASE, virt_to_bus(unit->bank_base_effect)); + ymfpci_writel(unit, YDSXGR_WORKBASE, virt_to_bus(unit->work_base)); + ymfpci_writel(unit, YDSXGR_WORKSIZE, unit->work_size >> 2); + + /* S/PDIF output initialization */ + ymfpci_writew(unit, YDSXGR_SPDIFOUTCTRL, 0); + ymfpci_writew(unit, YDSXGR_SPDIFOUTSTATUS, + SND_PCM_AES0_CON_EMPHASIS_NONE | + (SND_PCM_AES1_CON_ORIGINAL << 8) | + (SND_PCM_AES1_CON_PCM_CODER << 8)); + + /* S/PDIF input initialization */ + ymfpci_writew(unit, YDSXGR_SPDIFINCTRL, 0); + + /* move this volume setup to mixer */ + ymfpci_writel(unit, YDSXGR_NATIVEDACOUTVOL, 0x3fff3fff); + ymfpci_writel(unit, YDSXGR_BUF441OUTVOL, 0); + ymfpci_writel(unit, YDSXGR_NATIVEADCINVOL, 0x3fff3fff); + ymfpci_writel(unit, YDSXGR_NATIVEDACINVOL, 0x3fff3fff); +} + static int ymf_ac97_init(ymfpci_t *unit, int num_ac97) { struct ac97_codec *codec; @@ -2380,12 +2432,9 @@ ymfpci_download_image(codec); - udelay(100); /* seems we need some delay after downloading image.. */ - if (ymfpci_memalloc(codec) < 0) goto out_disable_dsp; - - /* ymfpci_proc_init(unit, codec); */ + ymf_memload(codec); if (request_irq(pcidev->irq, ymf_interrupt, SA_SHIRQ, "ymfpci", codec) != 0) { printk(KERN_ERR "ymfpci: unable to request IRQ %d\n", @@ -2481,6 +2530,8 @@ id_table: ymf_id_tbl, probe: ymf_probe_one, remove: ymf_remove_one, + suspend: ymf_suspend, + resume: ymf_resume }; static int __init ymf_init_module(void) diff -u --recursive --new-file v2.4.6/linux/drivers/sound/ymfpci.h linux/drivers/sound/ymfpci.h --- v2.4.6/linux/drivers/sound/ymfpci.h Tue May 15 11:16:26 2001 +++ linux/drivers/sound/ymfpci.h Wed Jul 4 11:50:39 2001 @@ -257,6 +257,7 @@ ymfpci_effect_bank_t *bank_effect[YDSXG_EFFECT_VOICES][2]; int start_count; + int suspended; u32 active_bank; struct ymf_voice voices[64]; @@ -282,8 +283,6 @@ struct list_head ymf_devs; struct list_head states; /* List of states for this unit */ - /* For the moment we do not traverse list of states so it is - * entirely useless. Will be used (PM) or killed. XXX */ }; struct ymf_dmabuf { @@ -300,7 +299,6 @@ int count; /* fill count */ unsigned total_bytes; /* total bytes dmaed by hardware */ - unsigned error; /* number of over/underruns */ wait_queue_head_t wait; /* put process on wait queue when no more space in buffer */ /* redundant, but makes calculations easier */ diff -u --recursive --new-file v2.4.6/linux/drivers/usb/acm.c linux/drivers/usb/acm.c --- v2.4.6/linux/drivers/usb/acm.c Tue Jul 3 17:08:21 2001 +++ linux/drivers/usb/acm.c Wed Jul 4 20:11:17 2001 @@ -1,5 +1,5 @@ /* - * acm.c Version 0.18 + * acm.c Version 0.19 * * Copyright (c) 1999 Armin Fuerst <fuerst@in.tum.de> * Copyright (c) 1999 Pavel Machek <pavel@suse.cz> @@ -21,6 +21,7 @@ * v0.16 - added code for modems with swapped data and control interfaces * v0.17 - added new style probing * v0.18 - fixed new style probing for devices with more configurations + * v0.19 - fixed CLOCAL handling (thanks to Richard Shih-Ping Chan) */ /* @@ -51,6 +52,7 @@ #include <linux/tty_driver.h> #include <linux/tty_flip.h> #include <linux/module.h> +#include <linux/smp_lock.h> #undef DEBUG #include <linux/usb.h> @@ -202,13 +204,10 @@ newctrl = le16_to_cpup((__u16 *) data); -#if 0 - /* Please someone tell me how to do this properly to kill pppd and not kill minicom */ if (acm->tty && !acm->clocal && (acm->ctrlin & ~newctrl & ACM_CTRL_DCD)) { dbg("calling hangup"); tty_hangup(acm->tty); } -#endif acm->ctrlin = newctrl; @@ -305,7 +304,14 @@ MOD_INC_USE_COUNT; - if (acm->used++) return 0; + lock_kernel(); + + if (acm->used++) { + unlock_kernel(); + return 0; + } + + unlock_kernel(); acm->ctrlurb.dev = acm->dev; if (usb_submit_urb(&acm->ctrlurb)) @@ -410,7 +416,7 @@ static int acm_tty_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg) { struct acm *acm = tty->driver_data; - unsigned int retval, mask, newctrl; + unsigned int mask, newctrl; if (!ACM_READY(acm)) return -EINVAL; @@ -429,7 +435,8 @@ case TIOCMBIS: case TIOCMBIC: - if ((retval = get_user(mask, (unsigned long *) arg))) return retval; + if (get_user(mask, (unsigned long *) arg)) + return -EFAULT; newctrl = acm->ctrlout; mask = (mask & TIOCM_DTR ? ACM_CTRL_DTR : 0) | (mask & TIOCM_RTS ? ACM_CTRL_RTS : 0); @@ -475,7 +482,7 @@ (termios->c_cflag & PARODD ? 1 : 2) + (termios->c_cflag & CMSPAR ? 2 : 0) : 0; newline.databits = acm_tty_size[(termios->c_cflag & CSIZE) >> 4]; - acm->clocal = termios->c_cflag & CLOCAL; + acm->clocal = ((termios->c_cflag & CLOCAL) != 0); if (!newline.speed) { newline.speed = acm->line.speed; diff -u --recursive --new-file v2.4.6/linux/drivers/usb/bluetooth.c linux/drivers/usb/bluetooth.c --- v2.4.6/linux/drivers/usb/bluetooth.c Tue Jul 3 17:08:21 2001 +++ linux/drivers/usb/bluetooth.c Thu Jul 12 14:21:05 2001 @@ -1,11 +1,15 @@ /* - * bluetooth.c Version 0.11 + * bluetooth.c Version 0.12 * * Copyright (c) 2000, 2001 Greg Kroah-Hartman <greg@kroah.com> * Copyright (c) 2000 Mark Douglas Corner <mcorner@umich.edu> * * USB Bluetooth driver, based on the Bluetooth Spec version 1.0B * + * (2001/07/09) Version 0.12 gkh + * - removed in_interrupt() call, as it doesn't make sense to do + * that anymore. + * * (2001/06/05) Version 0.11 gkh * - Fixed problem with read urb status saying that we have shutdown, * and that we shouldn't resubmit the urb. Patch from unknown. @@ -114,9 +118,9 @@ /* * Version Information */ -#define DRIVER_VERSION "v0.11" +#define DRIVER_VERSION "v0.12" #define DRIVER_AUTHOR "Greg Kroah-Hartman, Mark Douglas Corner" -#define DRIVER_DESC "USB Bluetooth driver" +#define DRIVER_DESC "USB Bluetooth tty driver" /* define this if you have hardware that is not good */ /*#define BTBUGGYHARDWARE */ @@ -484,12 +488,6 @@ case CMD_PKT: /* dbg(__FUNCTION__ "- Send cmd_pkt len:%d", count);*/ - if (in_interrupt()){ - printk("cmd_pkt from interrupt!\n"); - retval = count; - goto exit; - } - retval = bluetooth_ctrl_msg (bluetooth, 0x00, 0x00, ¤t_buffer[1], count-1); if (retval) { goto exit; @@ -1329,7 +1327,7 @@ return -1; } - info(DRIVER_VERSION ":" DRIVER_DESC); + info(DRIVER_DESC " " DRIVER_VERSION); return 0; } diff -u --recursive --new-file v2.4.6/linux/drivers/usb/devices.c linux/drivers/usb/devices.c --- v2.4.6/linux/drivers/usb/devices.c Mon Sep 25 15:25:29 2000 +++ linux/drivers/usb/devices.c Wed Jul 4 20:11:17 2001 @@ -475,6 +475,7 @@ return -EFAULT; /* enumerate busses */ + read_lock_irq (&usb_bus_list_lock); for (buslist = usb_bus_list.next; buslist != &usb_bus_list; buslist = buslist->next) { /* print devices for this bus */ bus = list_entry(buslist, struct usb_bus, bus_list); @@ -484,6 +485,7 @@ return ret; total_written += ret; } + read_unlock_irq (&usb_bus_list_lock); return total_written; } diff -u --recursive --new-file v2.4.6/linux/drivers/usb/devio.c linux/drivers/usb/devio.c --- v2.4.6/linux/drivers/usb/devio.c Fri Apr 6 15:51:50 2001 +++ linux/drivers/usb/devio.c Thu Jul 12 14:22:29 2001 @@ -429,11 +429,14 @@ } #endif -static int check_ctrlrecip(struct dev_state *ps, unsigned int recip, unsigned int index) +static int check_ctrlrecip(struct dev_state *ps, unsigned int requesttype, unsigned int index) { int ret; - switch (recip & USB_RECIP_MASK) { + if (USB_TYPE_VENDOR == (USB_TYPE_MASK & requesttype)) + return 0; + + switch (requesttype & USB_RECIP_MASK) { case USB_RECIP_ENDPOINT: if ((ret = findintfep(ps->dev, index & 0xff)) < 0) return ret; @@ -760,7 +763,8 @@ if (copy_from_user(&uurb, arg, sizeof(uurb))) return -EFAULT; - if (uurb.flags & ~(USBDEVFS_URB_ISO_ASAP|USBDEVFS_URB_DISABLE_SPD|USBDEVFS_URB_QUEUE_BULK)) + if (uurb.flags & ~(USBDEVFS_URB_ISO_ASAP|USBDEVFS_URB_DISABLE_SPD|USBDEVFS_URB_QUEUE_BULK| + USB_NO_FSBR|USB_ZERO_PACKET)) return -EINVAL; if (!uurb.buffer) return -EINVAL; diff -u --recursive --new-file v2.4.6/linux/drivers/usb/dsbr100.c linux/drivers/usb/dsbr100.c --- v2.4.6/linux/drivers/usb/dsbr100.c Tue Jul 3 17:08:21 2001 +++ linux/drivers/usb/dsbr100.c Sun Jul 15 16:22:23 2001 @@ -85,6 +85,8 @@ static int usb_dsbr100_open(struct video_device *dev, int flags); static void usb_dsbr100_close(struct video_device *dev); +static int radio_nr = -1; +MODULE_PARM(radio_nr, "i"); typedef struct { struct urb readurb,writeurb; @@ -107,7 +109,6 @@ }; static int users = 0; -static int radio_nr = -1; static struct usb_device_id usb_dsbr100_table [] = { { USB_DEVICE(DSB100_VENDOR, DSB100_PRODUCT) }, diff -u --recursive --new-file v2.4.6/linux/drivers/usb/inode.c linux/drivers/usb/inode.c --- v2.4.6/linux/drivers/usb/inode.c Tue May 22 10:25:36 2001 +++ linux/drivers/usb/inode.c Wed Jul 4 20:11:17 2001 @@ -260,11 +260,15 @@ struct list_head *list; struct usb_bus *bus; + read_lock_irq (&usb_bus_list_lock); for (list = usb_bus_list.next; list != &usb_bus_list; list = list->next) { bus = list_entry(list, struct usb_bus, bus_list); - if (bus->busnum == busnr) + if (bus->busnum == busnr) { + read_unlock_irq (&usb_bus_list_lock); return bus; + } } + read_unlock_irq (&usb_bus_list_lock); return NULL; } @@ -412,7 +416,7 @@ if (i < 2+NRSPECIAL) return 0; i -= 2+NRSPECIAL; - lock_kernel(); + read_lock_irq (&usb_bus_list_lock); for (list = usb_bus_list.next; list != &usb_bus_list; list = list->next) { if (i > 0) { i--; @@ -424,7 +428,7 @@ break; filp->f_pos++; } - unlock_kernel(); + read_unlock_irq (&usb_bus_list_lock); return 0; } } @@ -635,13 +639,13 @@ list_add_tail(&inode->u.usbdev_i.slist, &s->u.usbdevfs_sb.ilist); list_add_tail(&inode->u.usbdev_i.dlist, &special[i].inodes); } - lock_kernel(); + read_lock_irq (&usb_bus_list_lock); for (blist = usb_bus_list.next; blist != &usb_bus_list; blist = blist->next) { bus = list_entry(blist, struct usb_bus, bus_list); new_bus_inode(bus, s); recurse_new_dev_inode(bus->root_hub, s); } - unlock_kernel(); + read_unlock_irq (&usb_bus_list_lock); return s; out_no_root: diff -u --recursive --new-file v2.4.6/linux/drivers/usb/mdc800.c linux/drivers/usb/mdc800.c --- v2.4.6/linux/drivers/usb/mdc800.c Tue Jul 3 17:08:21 2001 +++ linux/drivers/usb/mdc800.c Wed Jul 4 15:39:28 2001 @@ -716,6 +716,7 @@ static ssize_t mdc800_device_write (struct file *file, const char *buf, size_t len, loff_t *pos) { int i=0; + char c; spin_lock (&mdc800->io_lock); if (mdc800->state != READY) @@ -738,7 +739,14 @@ } /* check for command start */ - if (buf [i] == (char) 0x55) + + if(get_user(c, buf+i)) + { + spin_unlock (&mdc800->io_lock); + return -EFAULT; + } + + if (c == (char) 0x55) { mdc800->in_count=0; mdc800->out_count=0; @@ -749,7 +757,7 @@ /* save command byte */ if (mdc800->in_count < 8) { - mdc800->in[mdc800->in_count]=buf[i]; + mdc800->in[mdc800->in_count]=c; mdc800->in_count++; } else diff -u --recursive --new-file v2.4.6/linux/drivers/usb/ov511.c linux/drivers/usb/ov511.c --- v2.4.6/linux/drivers/usb/ov511.c Tue Jul 3 17:08:21 2001 +++ linux/drivers/usb/ov511.c Mon Jul 16 15:13:32 2001 @@ -152,6 +152,7 @@ MODULE_PARM_DESC(sensor_gbr, "Make sensor output GBR422 rather than YUV420"); MODULE_PARM(dumppix, "i"); MODULE_PARM_DESC(dumppix, "Dump raw pixel data, in one of 3 formats. See ov511_dumppix() for details"); +MODULE_PARM(video_nr,"i"); MODULE_AUTHOR( DRIVER_AUTHOR ); MODULE_DESCRIPTION( DRIVER_DESC ); @@ -2521,6 +2522,9 @@ PDEBUG(4, "syncing to frame %d, grabstate = %d", frame, ov511->frame[frame].grabstate); + if(frame < 0 || frame >= OV511_NUMFRAMES) + return -EINVAL; + switch (ov511->frame[frame].grabstate) { case FRAME_UNUSED: return -EINVAL; @@ -3146,11 +3150,6 @@ init_waitqueue_head(&ov511->wq); - if (video_register_device(&ov511->vdev, VFL_TYPE_GRABBER, video_nr) < 0) { - err("video_register_device failed"); - return -EBUSY; - } - if (ov511_write_regvals(dev, aRegvalsInit)) goto error; if (ov511_write_regvals(dev, aRegvalsNorm511)) goto error; @@ -3219,7 +3218,6 @@ return 0; error: - video_unregister_device(&ov511->vdev); usb_driver_release_interface(&ov511_driver, &dev->actconfig->interface[ov511->iface]); @@ -3328,6 +3326,11 @@ ov511->buf_state = BUF_NOT_ALLOCATED; } else { err("Failed to configure camera"); + goto error; + } + + if (video_register_device(&ov511->vdev, VFL_TYPE_GRABBER, video_nr) < 0) { + err("video_register_device failed"); goto error; } diff -u --recursive --new-file v2.4.6/linux/drivers/usb/printer.c linux/drivers/usb/printer.c --- v2.4.6/linux/drivers/usb/printer.c Tue Jul 3 17:08:21 2001 +++ linux/drivers/usb/printer.c Fri Jul 6 17:04:29 2001 @@ -19,6 +19,7 @@ * v0.6 - never time out * v0.7 - fixed bulk-IN read and poll (David Paschal, paschal@rcsis.com) * v0.8 - add devfs support + * v0.9 - fix unplug-while-open paths */ /* @@ -88,6 +89,7 @@ struct usblp { struct usb_device *dev; /* USB device */ devfs_handle_t devfs; /* devfs device */ + struct semaphore sem; /* locks this struct, especially "dev" */ struct urb readurb, writeurb; /* The urbs */ wait_queue_head_t wait; /* Zzzzz ... */ int readcount; /* Counter for reads */ @@ -172,9 +174,12 @@ static int usblp_check_status(struct usblp *usblp, int err) { unsigned char status, newerr = 0; + int error; - if (usblp_read_status(usblp, &status)) { - err("usblp%d: failed reading printer status", usblp->minor); + error = usblp_read_status (usblp, &status); + if (error < 0) { + err("usblp%d: error %d reading printer status", + usblp->minor, error); return 0; } @@ -244,24 +249,30 @@ return retval; } +static void usblp_cleanup (struct usblp *usblp) +{ + devfs_unregister (usblp->devfs); + usblp_table [usblp->minor] = NULL; + info ("usblp%d: removed", usblp->minor); + + kfree (usblp->writeurb.transfer_buffer); + kfree (usblp->device_id_string); + kfree (usblp); +} + static int usblp_release(struct inode *inode, struct file *file) { struct usblp *usblp = file->private_data; + down (&usblp->sem); usblp->used = 0; - if (usblp->dev) { if (usblp->bidir) usb_unlink_urb(&usblp->readurb); usb_unlink_urb(&usblp->writeurb); - return 0; - } - - devfs_unregister(usblp->devfs); - usblp_table[usblp->minor] = NULL; - kfree(usblp->device_id_string); - kfree(usblp); - + up(&usblp->sem); + } else /* finish cleanup from disconnect */ + usblp_cleanup (usblp); return 0; } @@ -279,21 +290,31 @@ struct usblp *usblp = file->private_data; int length, err; unsigned char status; + int retval = 0; + + down (&usblp->sem); + if (!usblp->dev) { + retval = -ENODEV; + goto done; + } if (_IOC_TYPE(cmd) == 'P') /* new-style ioctl number */ switch (_IOC_NR(cmd)) { case IOCNR_GET_DEVICE_ID: /* get the DEVICE_ID string */ - if (_IOC_DIR(cmd) != _IOC_READ) - return -EINVAL; + if (_IOC_DIR(cmd) != _IOC_READ) { + retval = -EINVAL; + goto done; + } err = usblp_get_id(usblp, 0, usblp->device_id_string, DEVICE_ID_SIZE - 1); if (err < 0) { dbg ("usblp%d: error = %d reading IEEE-1284 Device ID string", usblp->minor, err); usblp->device_id_string[0] = usblp->device_id_string[1] = '\0'; - return -EIO; + retval = -EIO; + goto done; } length = (usblp->device_id_string[0] << 8) + usblp->device_id_string[1]; /* big-endian */ @@ -307,13 +328,16 @@ if (length > _IOC_SIZE(cmd)) length = _IOC_SIZE(cmd); /* truncate */ - if (copy_to_user((unsigned char *) arg, usblp->device_id_string, (unsigned long) length)) - return -EFAULT; + if (copy_to_user((unsigned char *) arg, + usblp->device_id_string, (unsigned long) length)) { + retval = -EFAULT; + goto done; + } break; default: - return -EINVAL; + retval = -EINVAL; } else /* old-style ioctl value */ switch (cmd) { @@ -321,17 +345,20 @@ case LPGETSTATUS: if (usblp_read_status(usblp, &status)) { err("usblp%d: failed reading printer status", usblp->minor); - return -EIO; + retval = -EIO; + goto done; } if (copy_to_user ((unsigned char *)arg, &status, 1)) - return -EFAULT; + retval = -EFAULT; break; default: - return -EINVAL; + retval = -EINVAL; } - return 0; +done: + up (&usblp->sem); + return retval; } static ssize_t usblp_write(struct file *file, const char *buffer, size_t count, loff_t *ppos) @@ -341,6 +368,8 @@ while (writecount < count) { + // FIXME: only use urb->status inside completion + // callbacks; this way is racey... if (usblp->writeurb.status == -EINPROGRESS) { if (file->f_flags & O_NONBLOCK) @@ -356,28 +385,36 @@ } } - if (!usblp->dev) + down (&usblp->sem); + if (!usblp->dev) { + up (&usblp->sem); return -ENODEV; + } - if (usblp->writeurb.status) { + if (usblp->writeurb.status != 0) { if (usblp->quirks & USBLP_QUIRK_BIDIR) { if (usblp->writeurb.status != -EINPROGRESS) err("usblp%d: error %d writing to printer", usblp->minor, usblp->writeurb.status); err = usblp->writeurb.status; - continue; - } - else { + } else err = usblp_check_status(usblp, err); - continue; - } + up (&usblp->sem); + + /* if the fault was due to disconnect, let khubd's + * call to usblp_disconnect() grab usblp->sem ... + */ + schedule (); + continue; } writecount += usblp->writeurb.transfer_buffer_length; usblp->writeurb.transfer_buffer_length = 0; - if (writecount == count) - continue; + if (writecount == count) { + up (&usblp->sem); + break; + } usblp->writeurb.transfer_buffer_length = (count - writecount) < USBLP_BUF_SIZE ? (count - writecount) : USBLP_BUF_SIZE; @@ -387,6 +424,7 @@ usblp->writeurb.dev = usblp->dev; usb_submit_urb(&usblp->writeurb); + up (&usblp->sem); } return count; @@ -399,20 +437,36 @@ if (!usblp->bidir) return -EINVAL; + down (&usblp->sem); + if (!usblp->dev) { + count = -ENODEV; + goto done; + } + if (usblp->readurb.status == -EINPROGRESS) { - if (file->f_flags & O_NONBLOCK) - return -EAGAIN; + if (file->f_flags & O_NONBLOCK) { + count = -EAGAIN; + goto done; + } + // FIXME: only use urb->status inside completion + // callbacks; this way is racey... while (usblp->readurb.status == -EINPROGRESS) { - if (signal_pending(current)) - return -EINTR; + if (signal_pending(current)) { + count = -EINTR; + goto done; + } + up (&usblp->sem); interruptible_sleep_on(&usblp->wait); + down (&usblp->sem); } } - if (!usblp->dev) - return -ENODEV; + if (!usblp->dev) { + count = -ENODEV; + goto done; + } if (usblp->readurb.status) { err("usblp%d: error %d reading from printer", @@ -420,14 +474,17 @@ usblp->readurb.dev = usblp->dev; usblp->readcount = 0; usb_submit_urb(&usblp->readurb); - return -EIO; + count = -EIO; + goto done; } count = count < usblp->readurb.actual_length - usblp->readcount ? count : usblp->readurb.actual_length - usblp->readcount; - if (copy_to_user(buffer, usblp->readurb.transfer_buffer + usblp->readcount, count)) - return -EFAULT; + if (copy_to_user(buffer, usblp->readurb.transfer_buffer + usblp->readcount, count)) { + count = -EFAULT; + goto done; + } if ((usblp->readcount += count) == usblp->readurb.actual_length) { usblp->readcount = 0; @@ -435,6 +492,8 @@ usb_submit_urb(&usblp->readurb); } +done: + up (&usblp->sem); return count; } @@ -537,6 +596,7 @@ return NULL; } memset(usblp, 0, sizeof(struct usblp)); + init_MUTEX (&usblp->sem); /* lookup quirks for this printer */ quirks = usblp_quirks(dev->descriptor.idVendor, dev->descriptor.idProduct); @@ -599,14 +659,12 @@ sprintf(name, "lp%d", minor); - /* Create with perms=664 */ + /* if we have devfs, create with perms=660 */ usblp->devfs = devfs_register(usb_devfs_handle, name, DEVFS_FL_DEFAULT, USB_MAJOR, USBLP_MINOR_BASE + minor, S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP, &usblp_fops, NULL); - if (usblp->devfs == NULL) - err("usblp%d: device node registration failed", minor); info("usblp%d: USB %sdirectional printer dev %d if %d alt %d", minor, bidir ? "Bi" : "Uni", dev->devnum, ifnum, alts); @@ -619,25 +677,21 @@ struct usblp *usblp = ptr; if (!usblp || !usblp->dev) { - err("disconnect on nonexisting interface"); - return; + err("bogus disconnect"); + BUG (); } + down (&usblp->sem); usblp->dev = NULL; usb_unlink_urb(&usblp->writeurb); if (usblp->bidir) usb_unlink_urb(&usblp->readurb); - kfree(usblp->writeurb.transfer_buffer); - - if (usblp->used) return; - - kfree(usblp->device_id_string); - - devfs_unregister(usblp->devfs); - usblp_table[usblp->minor] = NULL; - kfree(usblp); + if (!usblp->used) + usblp_cleanup (usblp); + else /* cleanup later, on close */ + up (&usblp->sem); } static struct usb_device_id usblp_ids [] = { diff -u --recursive --new-file v2.4.6/linux/drivers/usb/scanner.c linux/drivers/usb/scanner.c --- v2.4.6/linux/drivers/usb/scanner.c Wed Apr 18 11:49:12 2001 +++ linux/drivers/usb/scanner.c Sun Jul 8 13:17:30 2001 @@ -909,7 +909,7 @@ return result; } default: - return -ENOIOCTLCMD; + return -ENOTTY; } return 0; } diff -u --recursive --new-file v2.4.6/linux/drivers/usb/serial/Config.in linux/drivers/usb/serial/Config.in --- v2.4.6/linux/drivers/usb/serial/Config.in Tue Jul 3 17:08:21 2001 +++ linux/drivers/usb/serial/Config.in Sun Jul 15 16:22:23 2001 @@ -4,7 +4,7 @@ mainmenu_option next_comment comment 'USB Serial Converter support' -tristate 'USB Serial Converter support' CONFIG_USB_SERIAL $CONFIG_USB +dep_tristate 'USB Serial Converter support' CONFIG_USB_SERIAL $CONFIG_USB if [ "$CONFIG_USB_SERIAL" != "n" ]; then if [ "$CONFIG_USB_SERIAL" = "y" ]; then bool ' USB Serial Converter verbose debug' CONFIG_USB_SERIAL_DEBUG diff -u --recursive --new-file v2.4.6/linux/drivers/usb/serial/empeg.c linux/drivers/usb/serial/empeg.c --- v2.4.6/linux/drivers/usb/serial/empeg.c Tue Jul 3 17:08:21 2001 +++ linux/drivers/usb/serial/empeg.c Fri Jul 6 17:04:29 2001 @@ -247,7 +247,6 @@ static void empeg_close (struct usb_serial_port *port, struct file * filp) { struct usb_serial *serial; - unsigned char *transfer_buffer; if (port_paranoia_check (port, __FUNCTION__)) return; @@ -263,14 +262,6 @@ --port->open_count; if (port->open_count <= 0) { - transfer_buffer = kmalloc (0x12, GFP_KERNEL); - - if (!transfer_buffer) { - err(__FUNCTION__ " - kmalloc(%d) failed.", 0x12); - } else { - kfree (transfer_buffer); - } - /* shutdown our bulk read */ usb_unlink_urb (port->read_urb); port->active = 0; diff -u --recursive --new-file v2.4.6/linux/drivers/usb/serial/ftdi_sio.c linux/drivers/usb/serial/ftdi_sio.c --- v2.4.6/linux/drivers/usb/serial/ftdi_sio.c Tue Jul 3 17:08:21 2001 +++ linux/drivers/usb/serial/ftdi_sio.c Fri Jul 6 17:04:29 2001 @@ -902,7 +902,8 @@ case TIOCMSET: /* Turns on and off the lines as specified by the mask */ dbg(__FUNCTION__ " TIOCMSET"); - if ((ret = get_user(mask, (unsigned long *) arg))) return ret; + if (get_user(mask, (unsigned long *) arg)) + return -EFAULT; urb_value = ((mask & TIOCM_DTR) ? HIGH : LOW); if (set_dtr(serial->dev, usb_sndctrlpipe(serial->dev, 0),urb_value) < 0){ err("Error from DTR set urb (TIOCMSET)"); @@ -915,7 +916,8 @@ case TIOCMBIS: /* turns on (Sets) the lines as specified by the mask */ dbg(__FUNCTION__ " TIOCMBIS"); - if ((ret = get_user(mask, (unsigned long *) arg))) return ret; + if (get_user(mask, (unsigned long *) arg)) + return -EFAULT; if (mask & TIOCM_DTR){ if ((ret = set_dtr(serial->dev, usb_sndctrlpipe(serial->dev, 0), @@ -936,7 +938,8 @@ case TIOCMBIC: /* turns off (Clears) the lines as specified by the mask */ dbg(__FUNCTION__ " TIOCMBIC"); - if ((ret = get_user(mask, (unsigned long *) arg))) return ret; + if (get_user(mask, (unsigned long *) arg)) + return -EFAULT; if (mask & TIOCM_DTR){ if ((ret = set_dtr(serial->dev, usb_sndctrlpipe(serial->dev, 0), diff -u --recursive --new-file v2.4.6/linux/drivers/usb/serial/io_edgeport.c linux/drivers/usb/serial/io_edgeport.c --- v2.4.6/linux/drivers/usb/serial/io_edgeport.c Tue Jul 3 17:08:21 2001 +++ linux/drivers/usb/serial/io_edgeport.c Thu Jul 12 14:21:05 2001 @@ -25,6 +25,9 @@ * * Version history: * + * 2.1 2001_07_09 greg kroah-hartman + * - added support for TIOCMBIS and TIOCMBIC. + * * (04/08/2001) gb * - Identify version on module load. * @@ -260,7 +263,7 @@ /* * Version Information */ -#define DRIVER_VERSION "v2.0.0" +#define DRIVER_VERSION "v2.1" #define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com> and David Iacovelli" #define DRIVER_DESC "Edgeport USB Serial Driver" @@ -1718,7 +1721,7 @@ return -ENOIOCTLCMD; } -static int set_modem_info(struct edgeport_port *edge_port, unsigned int *value) +static int set_modem_info(struct edgeport_port *edge_port, unsigned int cmd, unsigned int *value) { unsigned int mcr = edge_port->shadowMCR; unsigned int arg; @@ -1726,11 +1729,34 @@ if (copy_from_user(&arg, value, sizeof(int))) return -EFAULT; - // turn off the RTS and DTR - mcr &= ~(MCR_RTS | MCR_DTR); + switch (cmd) { + case TIOCMBIS: + if (arg & TIOCM_RTS) + mcr |= MCR_RTS; + if (arg & TIOCM_DTR) + mcr |= MCR_RTS; + if (arg & TIOCM_LOOP) + mcr |= MCR_LOOPBACK; + break; - mcr |= ((arg & TIOCM_RTS) ? MCR_RTS : 0); - mcr |= ((arg & TIOCM_DTR) ? MCR_DTR : 0); + case TIOCMBIC: + if (arg & TIOCM_RTS) + mcr &= ~MCR_RTS; + if (arg & TIOCM_DTR) + mcr &= ~MCR_RTS; + if (arg & TIOCM_LOOP) + mcr &= ~MCR_LOOPBACK; + break; + + case TIOCMSET: + /* turn off the RTS and DTR and LOOPBACK + * and then only turn on what was asked to */ + mcr &= ~(MCR_RTS | MCR_DTR | MCR_LOOPBACK); + mcr |= ((arg & TIOCM_RTS) ? MCR_RTS : 0); + mcr |= ((arg & TIOCM_DTR) ? MCR_DTR : 0); + mcr |= ((arg & TIOCM_LOOP) ? MCR_LOOPBACK : 0); + break; + } edge_port->shadowMCR = mcr; @@ -1827,9 +1853,11 @@ return get_lsr_info(edge_port, (unsigned int *) arg); return 0; - case TIOCMSET: - dbg(__FUNCTION__" (%d) TIOCMSET", port->number); - return set_modem_info(edge_port, (unsigned int *) arg); + case TIOCMBIS: + case TIOCMBIC: + case TIOCMSET: + dbg(__FUNCTION__" (%d) TIOCMSET/TIOCMBIC/TIOCMSET", port->number); + return set_modem_info(edge_port, cmd, (unsigned int *) arg); case TIOCMGET: dbg(__FUNCTION__" (%d) TIOCMGET", port->number); @@ -3037,7 +3065,7 @@ usb_serial_register (&edgeport_16dual_device); usb_serial_register (&edgeport_compat_id_device); usb_serial_register (&edgeport_8i_device); - info(DRIVER_VERSION ":" DRIVER_DESC); + info(DRIVER_DESC " " DRIVER_VERSION); return 0; } diff -u --recursive --new-file v2.4.6/linux/drivers/usb/serial/usbserial.c linux/drivers/usb/serial/usbserial.c --- v2.4.6/linux/drivers/usb/serial/usbserial.c Tue Jul 3 17:08:21 2001 +++ linux/drivers/usb/serial/usbserial.c Fri Jul 6 17:04:29 2001 @@ -15,6 +15,13 @@ * * See Documentation/usb/usb-serial.txt for more information on using this driver * + * (07/03/2001) gkh + * Fixed module paramater size. Thanks to John Brockmeyer for the pointer. + * Fixed vendor and product getting defined through the MODULE_PARM macro + * if the Generic driver wasn't compiled in. + * Fixed problem with generic_shutdown() not being called for drivers that + * don't have a shutdown() function. + * * (06/06/2001) gkh * added evil hack that is needed for the prolific pl2303 device due to the * crazy way its endpoints are set up. @@ -296,7 +303,7 @@ /* * Version Information */ -#define DRIVER_VERSION "v1.2" +#define DRIVER_VERSION "v1.3" #define DRIVER_AUTHOR "Greg Kroah-Hartman, greg@kroah.com, http://www.kroah.com/linux-usb/" #define DRIVER_DESC "USB Serial Driver core" @@ -347,6 +354,7 @@ static void serial_unthrottle (struct tty_struct * tty); static int serial_ioctl (struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg); static void serial_set_termios (struct tty_struct *tty, struct termios * old); +static void serial_shutdown (struct usb_serial *serial); static void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum, const struct usb_device_id *id); @@ -736,6 +744,16 @@ } +static void serial_shutdown (struct usb_serial *serial) +{ + if (serial->type->shutdown) { + serial->type->shutdown(serial); + } else { + generic_shutdown(serial); + } +} + + /***************************************************************************** * generic devices specific driver functions @@ -1311,8 +1329,7 @@ serial->port[i].tty->driver_data = NULL; } - if (serial->type->shutdown) - serial->type->shutdown(serial); + serial_shutdown (serial); for (i = 0; i < serial->num_ports; ++i) serial->port[i].active = 0; @@ -1426,7 +1443,7 @@ return -1; } - info(DRIVER_VERSION ":" DRIVER_DESC); + info(DRIVER_DESC " " DRIVER_VERSION); return 0; } @@ -1500,9 +1517,11 @@ MODULE_PARM(debug, "i"); MODULE_PARM_DESC(debug, "Debug enabled or not"); -MODULE_PARM(vendor, "i"); +#ifdef CONFIG_USB_SERIAL_GENERIC +MODULE_PARM(vendor, "h"); MODULE_PARM_DESC(vendor, "User specified USB idVendor"); -MODULE_PARM(product, "i"); +MODULE_PARM(product, "h"); MODULE_PARM_DESC(product, "User specified USB idProduct"); +#endif diff -u --recursive --new-file v2.4.6/linux/drivers/usb/storage/freecom.c linux/drivers/usb/storage/freecom.c --- v2.4.6/linux/drivers/usb/storage/freecom.c Tue Nov 28 21:50:07 2000 +++ linux/drivers/usb/storage/freecom.c Wed Jul 4 15:43:05 2001 @@ -96,7 +96,7 @@ #define FCM_PACKET_OUTPUT 0x01 /* Write a value to an ide register. Or the ide register to write after - * munging the addres a bit. */ + * munging the address a bit. */ #define FCM_PACKET_IDE_WRITE 0x40 #define FCM_PACKET_IDE_READ 0xC0 @@ -412,7 +412,7 @@ US_DEBUG(pdump ((void *) fst, partial)); - /* while we haven't recieved the IRQ */ + /* while we haven't received the IRQ */ while (!(fst->Status & 0x2)) { /* send a command to re-fetch the status */ US_DEBUGP("Re-attempting to get status...\n"); diff -u --recursive --new-file v2.4.6/linux/drivers/usb/uhci.c linux/drivers/usb/uhci.c --- v2.4.6/linux/drivers/usb/uhci.c Tue Jul 3 17:08:21 2001 +++ linux/drivers/usb/uhci.c Wed Jul 4 15:43:05 2001 @@ -62,7 +62,7 @@ * Version Information */ #define DRIVER_VERSION "" -#define DRIVER_AUTHOR "Linus Torvalds, Johannes Erdfelt, Randy Dunlap, Georg Acher, Deti Fliegl, Thomas Sailer, Roman Weissgaerber" +#define DRIVER_AUTHOR "Linus 'Frodo Rabbit' Torvalds, Johannes Erdfelt, Randy Dunlap, Georg Acher, Deti Fliegl, Thomas Sailer, Roman Weissgaerber" #define DRIVER_DESC "USB Universal Host Controller Interface driver" @@ -305,8 +305,7 @@ mb(); td->link = UHCI_PTR_TERM; - list_del(&td->fl_list); - INIT_LIST_HEAD(&td->fl_list); + list_del_init(&td->fl_list); td->frame = -1; spin_unlock_irqrestore(&uhci->frame_list_lock, flags); @@ -438,8 +437,7 @@ mb(); qh->element = qh->link = UHCI_PTR_TERM; - list_del(&qh->list); - INIT_LIST_HEAD(&qh->list); + list_del_init(&qh->list); spin_unlock_irqrestore(&uhci->frame_list_lock, flags); @@ -624,8 +622,7 @@ pltd->link = UHCI_PTR_TERM; } - list_del(&urbp->queue_list); - INIT_LIST_HEAD(&urbp->queue_list); + list_del_init(&urbp->queue_list); out: spin_unlock_irqrestore(&uhci->frame_list_lock, flags); @@ -689,8 +686,7 @@ if (list_empty(&td->list)) return; - list_del(&td->list); - INIT_LIST_HEAD(&td->list); + list_del_init(&td->list); td->urb = NULL; } @@ -1665,8 +1661,7 @@ usb_pipetype(urb->pipe), urb); } - list_del(&urb->urb_list); - INIT_LIST_HEAD(&urb->urb_list); + list_del_init(&urb->urb_list); uhci_add_complete(urb); } @@ -1723,8 +1718,7 @@ return 0; spin_lock_irqsave(&uhci->urb_list_lock, flags); - list_del(&urb->urb_list); - INIT_LIST_HEAD(&urb->urb_list); + list_del_init(&urb->urb_list); spin_unlock_irqrestore(&uhci->urb_list_lock, flags); uhci_unlink_generic(uhci, urb); @@ -2206,8 +2200,7 @@ tmp = tmp->next; - list_del(&qh->remove_list); - INIT_LIST_HEAD(&qh->remove_list); + list_del_init(&qh->remove_list); uhci_free_qh(uhci, qh); } @@ -2300,8 +2293,7 @@ tmp = tmp->next; - list_del(&urbp->complete_list); - INIT_LIST_HEAD(&urbp->complete_list); + list_del_init(&urbp->complete_list); uhci_call_completion(urb); } @@ -2322,8 +2314,7 @@ tmp = tmp->next; - list_del(&urb->urb_list); - INIT_LIST_HEAD(&urb->urb_list); + list_del_init(&urb->urb_list); urbp->status = urb->status = -ECONNRESET; uhci_call_completion(urb); diff -u --recursive --new-file v2.4.6/linux/drivers/usb/usb-ohci.c linux/drivers/usb/usb-ohci.c --- v2.4.6/linux/drivers/usb/usb-ohci.c Tue Jul 3 17:08:21 2001 +++ linux/drivers/usb/usb-ohci.c Sun Jul 8 13:17:30 2001 @@ -2749,7 +2749,7 @@ switch (when) { case PBOOK_SLEEP_NOW: - ohci_pci_suspend (ohci->ohci_dev); + ohci_pci_suspend (ohci->ohci_dev, 3); break; case PBOOK_WAKE: ohci_pci_resume (ohci->ohci_dev); diff -u --recursive --new-file v2.4.6/linux/drivers/usb/usb-skeleton.c linux/drivers/usb/usb-skeleton.c --- v2.4.6/linux/drivers/usb/usb-skeleton.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/usb/usb-skeleton.c Wed Jul 4 15:43:05 2001 @@ -0,0 +1,652 @@ +/* + * USB Skeleton driver + * + * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * + * This driver is to be used as a skeleton driver to be able to create a + * USB driver quickly. The design of it is based on the usb-serial and + * dc2xx drivers. + * + * Thanks to Oliver Neukum and David Brownell for their help in debugging + * this driver. + * + * TODO: + * - fix urb->status race condition in write sequence + * - move minor_table to a dynamic list. + * + * History: + * + * 2001_05_29 - 0.3 - more bug fixes based on review from linux-usb-devel + * 2001_05_24 - 0.2 - bug fixes based on review from linux-usb-devel people + * 2001_05_01 - 0.1 - first version + * + */ + +#include <linux/config.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/signal.h> +#include <linux/errno.h> +#include <linux/poll.h> +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/fcntl.h> +#include <linux/module.h> +#include <linux/spinlock.h> +#include <linux/list.h> +#include <linux/smp_lock.h> +#include <linux/devfs_fs_kernel.h> +#include <linux/usb.h> + +#ifdef CONFIG_USB_DEBUG + static int debug = 1; +#else + static int debug; +#endif + +/* Use our own dbg macro */ +#undef dbg +#define dbg(format, arg...) do { if (debug) printk(KERN_DEBUG __FILE__ ": " format "\n" , ## arg); } while (0) + + +/* Version Information */ +#define DRIVER_VERSION "v0.3" +#define DRIVER_AUTHOR "Greg Kroah-Hartman, greg@kroah.com" +#define DRIVER_DESC "USB Skeleton Driver" + +/* Module paramaters */ +MODULE_PARM(debug, "i"); +MODULE_PARM_DESC(debug, "Debug enabled or not"); + + +/* Define these values to match your device */ +#define USB_SKEL_VENDOR_ID 0xfff0 +#define USB_SKEL_PRODUCT_ID 0xfff0 + +/* table of devices that work with this driver */ +static struct usb_device_id skel_table [] = { + { USB_DEVICE(USB_SKEL_VENDOR_ID, USB_SKEL_PRODUCT_ID) }, + { } /* Terminating entry */ +}; + +MODULE_DEVICE_TABLE (usb, skel_table); + + + +/* Get a minor range for your devices from the usb maintainer */ +#define USB_SKEL_MINOR_BASE 200 + +/* we can have up to this number of device plugged in at once */ +#define MAX_DEVICES 16 + +/* Structure to hold all of our device specific stuff */ +struct usb_skel { + struct usb_device * udev; /* save off the usb device pointer */ + struct usb_interface * interface; /* the interface for this device */ + devfs_handle_t devfs; /* devfs device node */ + unsigned char minor; /* the starting minor number for this device */ + unsigned char num_ports; /* the number of ports this device has */ + char num_interrupt_in; /* number of interrupt in endpoints we have */ + char num_bulk_in; /* number of bulk in endpoints we have */ + char num_bulk_out; /* number of bulk out endpoints we have */ + + unsigned char * bulk_in_buffer; /* the buffer to receive data */ + int bulk_in_size; /* the size of the receive buffer */ + __u8 bulk_in_endpointAddr; /* the address of the bulk in endpoint */ + + unsigned char * bulk_out_buffer; /* the buffer to send data */ + int bulk_out_size; /* the size of the send buffer */ + struct urb * write_urb; /* the urb used to send data */ + __u8 bulk_out_endpointAddr; /* the address of the bulk out endpoint */ + + struct tq_struct tqueue; /* task queue for line discipline waking up */ + int open_count; /* number of times this port has been opened */ + struct semaphore sem; /* locks this structure */ +}; + + +/* the global usb devfs handle */ +extern devfs_handle_t usb_devfs_handle; + + +/* local function prototypes */ +static ssize_t skel_read (struct file *file, char *buffer, size_t count, loff_t *ppos); +static ssize_t skel_write (struct file *file, const char *buffer, size_t count, loff_t *ppos); +static int skel_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg); +static int skel_open (struct inode *inode, struct file *file); +static int skel_release (struct inode *inode, struct file *file); + +static void * skel_probe (struct usb_device *dev, unsigned int ifnum, const struct usb_device_id *id); +static void skel_disconnect (struct usb_device *dev, void *ptr); + +static void skel_write_bulk_callback (struct urb *urb); + + +/* array of pointers to our devices that are currently connected */ +static struct usb_skel *minor_table[MAX_DEVICES]; + +/* lock to protect the minor_table structure */ +static DECLARE_MUTEX (minor_table_mutex); + +/* file operations needed when we register this driver */ +static struct file_operations skel_fops = { + owner: THIS_MODULE, + read: skel_read, + write: skel_write, + ioctl: skel_ioctl, + open: skel_open, + release: skel_release, +}; + + +/* usb specific object needed to register this driver with the usb subsystem */ +static struct usb_driver skel_driver = { + name: "skeleton", + probe: skel_probe, + disconnect: skel_disconnect, + fops: &skel_fops, + minor: USB_SKEL_MINOR_BASE, + id_table: skel_table, +}; + + + + + +/** + * usb_skel_debug_data + */ +static inline void usb_skel_debug_data (const char *function, int size, const unsigned char *data) +{ + int i; + + if (!debug) + return; + + printk (KERN_DEBUG __FILE__": %s - length = %d, data = ", + function, size); + for (i = 0; i < size; ++i) { + printk ("%.2x ", data[i]); + } + printk ("\n"); +} + + +/** + * skel_open + */ +static int skel_open (struct inode *inode, struct file *file) +{ + struct usb_skel *dev = NULL; + int subminor; + int retval = 0; + + dbg(__FUNCTION__); + + subminor = MINOR (inode->i_rdev) - USB_SKEL_MINOR_BASE; + if ((subminor < 0) || + (subminor >= MAX_DEVICES)) { + return -ENODEV; + } + + /* increment our usage count for the module */ + MOD_INC_USE_COUNT; + + /* lock our minor table and get our local data for this minor */ + down (&minor_table_mutex); + dev = minor_table[subminor]; + if (dev == NULL) { + up (&minor_table_mutex); + MOD_DEC_USE_COUNT; + return -ENODEV; + } + + /* lock this device */ + down (&dev->sem); + + /* unlock the minor table */ + up (&minor_table_mutex); + + /* increment our usage count for the driver */ + ++dev->open_count; + + /* save our object in the file's private structure */ + file->private_data = dev; + + /* unlock this device */ + up (&dev->sem); + + return retval; +} + + +/** + * skel_release + */ +static int skel_release (struct inode *inode, struct file *file) +{ + struct usb_skel *dev; + int retval = 0; + + dev = (struct usb_skel *)file->private_data; + if (dev == NULL) { + dbg (__FUNCTION__ " - object is NULL"); + return -ENODEV; + } + + dbg(__FUNCTION__ " - minor %d", dev->minor); + + /* lock our minor table */ + down (&minor_table_mutex); + + /* lock our device */ + down (&dev->sem); + + if (dev->open_count <= 0) { + dbg (__FUNCTION__ " - device not opened"); + retval = -ENODEV; + goto exit_not_opened; + } + + if (dev->udev == NULL) { + /* the device was unplugged before the file was released */ + minor_table[dev->minor] = NULL; + if (dev->bulk_in_buffer != NULL) + kfree (dev->bulk_in_buffer); + if (dev->bulk_out_buffer != NULL) + kfree (dev->bulk_out_buffer); + if (dev->write_urb != NULL) + usb_free_urb (dev->write_urb); + kfree (dev); + goto exit; + } + + /* decrement our usage count for the device */ + --dev->open_count; + if (dev->open_count <= 0) { + /* shutdown any bulk writes that might be going on */ + dev->write_urb->transfer_flags |= USB_ASYNC_UNLINK; + usb_unlink_urb (dev->write_urb); + dev->open_count = 0; + } + +exit: + /* decrement our usage count for the module */ + MOD_DEC_USE_COUNT; + +exit_not_opened: + up (&dev->sem); + up (&minor_table_mutex); + + return retval; +} + + +/** + * skel_read + */ +static ssize_t skel_read (struct file *file, char *buffer, size_t count, loff_t *ppos) +{ + struct usb_skel *dev; + int retval = 0; + + dev = (struct usb_skel *)file->private_data; + + dbg(__FUNCTION__ " - minor %d, count = %d", dev->minor, count); + + /* lock this object */ + down (&dev->sem); + + /* verify that the device wasn't unplugged */ + if (dev->udev == NULL) { + up (&dev->sem); + return -ENODEV; + } + + /* do an immediate bulk read to get data from the device */ + retval = usb_bulk_msg (dev->udev, + usb_rcvbulkpipe (dev->udev, + dev->bulk_in_endpointAddr), + dev->bulk_in_buffer, dev->bulk_in_size, + &count, HZ*10); + + /* if the read was successful, copy the data to userspace */ + if (!retval) { + if (copy_to_user (buffer, dev->bulk_in_buffer, count)) + retval = -EFAULT; + else + retval = count; + } + + /* unlock the device */ + up (&dev->sem); + return retval; +} + + +/** + * skel_write + */ +static ssize_t skel_write (struct file *file, const char *buffer, size_t count, loff_t *ppos) +{ + struct usb_skel *dev; + ssize_t bytes_written = 0; + int retval = 0; + + dev = (struct usb_skel *)file->private_data; + + dbg(__FUNCTION__ " - minor %d, count = %d", dev->minor, count); + + /* lock this object */ + down (&dev->sem); + + /* verify that the device wasn't unplugged */ + if (dev->udev == NULL) { + retval = -ENODEV; + goto exit; + } + + /* verify that we actually have some data to write */ + if (count == 0) { + dbg(__FUNCTION__ " - write request of 0 bytes"); + goto exit; + } + + /* see if we are already in the middle of a write */ + if (dev->write_urb->status == -EINPROGRESS) { + dbg (__FUNCTION__ " - already writing"); + goto exit; + } + + /* we can only write as much as 1 urb will hold */ + bytes_written = (count > dev->bulk_out_size) ? + dev->bulk_out_size : count; + + /* copy the data from userspace into our urb */ + if (copy_from_user(dev->write_urb->transfer_buffer, buffer, + bytes_written)) { + retval = -EFAULT; + goto exit; + } + + usb_skel_debug_data (__FUNCTION__, bytes_written, + dev->write_urb->transfer_buffer); + + /* set up our urb */ + FILL_BULK_URB(dev->write_urb, dev->udev, + usb_sndbulkpipe(dev->udev, dev->bulk_out_endpointAddr), + dev->write_urb->transfer_buffer, bytes_written, + skel_write_bulk_callback, dev); + + /* send the data out the bulk port */ + retval = usb_submit_urb(dev->write_urb); + if (retval) { + err(__FUNCTION__ " - failed submitting write urb, error %d", + retval); + } else { + retval = bytes_written; + } + +exit: + /* unlock the device */ + up (&dev->sem); + + return retval; +} + + +/** + * skel_ioctl + */ +static int skel_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) +{ + struct usb_skel *dev; + + dev = (struct usb_skel *)file->private_data; + + /* lock this object */ + down (&dev->sem); + + /* verify that the device wasn't unplugged */ + if (dev->udev == NULL) { + up (&dev->sem); + return -ENODEV; + } + + dbg(__FUNCTION__ " - minor %d, cmd 0x%.4x, arg %ld", + dev->minor, cmd, arg); + + + /* fill in your device specific stuff here */ + + /* unlock the device */ + up (&dev->sem); + + /* return that we did not understand this ioctl call */ + return -ENOTTY; +} + + +/** + * skel_write_bulk_callback + */ +static void skel_write_bulk_callback (struct urb *urb) +{ + struct usb_skel *dev = (struct usb_skel *)urb->context; + + dbg(__FUNCTION__ " - minor %d", dev->minor); + + if ((urb->status != -ENOENT) && + (urb->status != -ECONNRESET)) { + dbg(__FUNCTION__ " - nonzero write bulk status received: %d", + urb->status); + return; + } + + return; +} + + + + + +static void * skel_probe(struct usb_device *udev, unsigned int ifnum, const struct usb_device_id *id) +{ + struct usb_skel *dev = NULL; + struct usb_interface *interface; + struct usb_interface_descriptor *iface_desc; + struct usb_endpoint_descriptor *endpoint; + int minor; + int buffer_size; + int i; + char name[10]; + + + /* See if the device offered us matches what we can accept */ + if ((udev->descriptor.idVendor != USB_SKEL_VENDOR_ID) || + (udev->descriptor.idProduct != USB_SKEL_PRODUCT_ID)) { + return NULL; + } + + /* select a "subminor" number (part of a minor number) */ + down (&minor_table_mutex); + for (minor = 0; minor < MAX_DEVICES; i++) { + if (minor_table[minor] == NULL) + break; + } + if (minor >= MAX_DEVICES) { + info ("Too many devices plugged in, can not handle this device."); + goto exit; + } + + /* allocate memory for our device state and intialize it */ + dev = kmalloc (sizeof(struct usb_skel), GFP_KERNEL); + if (dev == NULL) { + err ("Out of memory"); + goto exit; + } + minor_table[minor] = dev; + + interface = &udev->actconfig->interface[ifnum]; + + init_MUTEX (&dev->sem); + dev->udev = udev; + dev->interface = interface; + dev->minor = minor; + + /* set up the endpoint information */ + /* check out the endpoints */ + iface_desc = &interface->altsetting[0]; + for (i = 0; i < iface_desc->bNumEndpoints; ++i) { + endpoint = &iface_desc->endpoint[i]; + + if ((endpoint->bEndpointAddress & 0x80) && + ((endpoint->bmAttributes & 3) == 0x02)) { + /* we found a bulk in endpoint */ + buffer_size = endpoint->wMaxPacketSize; + dev->bulk_in_size = buffer_size; + dev->bulk_in_endpointAddr = endpoint->bEndpointAddress; + dev->bulk_in_buffer = kmalloc (buffer_size, GFP_KERNEL); + if (!dev->bulk_in_buffer) { + err("Couldn't allocate bulk_in_buffer"); + goto error; + } + } + + if (((endpoint->bEndpointAddress & 0x80) == 0x00) && + ((endpoint->bmAttributes & 3) == 0x02)) { + /* we found a bulk out endpoint */ + dev->write_urb = usb_alloc_urb(0); + if (!dev->write_urb) { + err("No free urbs available"); + goto error; + } + buffer_size = endpoint->wMaxPacketSize; + dev->bulk_out_size = buffer_size; + dev->bulk_out_endpointAddr = endpoint->bEndpointAddress; + dev->bulk_out_buffer = kmalloc (buffer_size, GFP_KERNEL); + if (!dev->bulk_out_buffer) { + err("Couldn't allocate bulk_out_buffer"); + goto error; + } + FILL_BULK_URB(dev->write_urb, udev, + usb_sndbulkpipe(udev, + endpoint->bEndpointAddress), + dev->bulk_out_buffer, buffer_size, + skel_write_bulk_callback, dev); + } + } + + /* initialize the devfs node for this device and register it */ + sprintf(name, "skel%d", dev->minor); + + dev->devfs = devfs_register (usb_devfs_handle, name, + DEVFS_FL_DEFAULT, USB_MAJOR, + USB_SKEL_MINOR_BASE + dev->minor, + S_IFCHR | S_IRUSR | S_IWUSR | + S_IRGRP | S_IWGRP | S_IROTH, + &skel_fops, NULL); + + /* let the user know what node this device is now attached to */ + info ("USB Skeleton device now attached to USBSkel%d", dev->minor); + goto exit; + +error: + minor_table [dev->minor] = NULL; + if (dev->bulk_in_buffer != NULL) + kfree (dev->bulk_in_buffer); + if (dev->bulk_out_buffer != NULL) + kfree (dev->bulk_out_buffer); + if (dev->write_urb != NULL) + usb_free_urb (dev->write_urb); + kfree (dev); + dev = NULL; + +exit: + up (&minor_table_mutex); + return dev; +} + + +/** + * skel_disconnect + */ +static void skel_disconnect(struct usb_device *udev, void *ptr) +{ + struct usb_skel *dev; + int minor; + + dev = (struct usb_skel *)ptr; + + down (&minor_table_mutex); + down (&dev->sem); + + minor = dev->minor; + + /* if the device is not opened, then we clean up right now */ + if (!dev->open_count) { + minor_table[dev->minor] = NULL; + if (dev->bulk_in_buffer != NULL) + kfree (dev->bulk_in_buffer); + if (dev->bulk_out_buffer != NULL) + kfree (dev->bulk_out_buffer); + if (dev->write_urb != NULL) + usb_free_urb (dev->write_urb); + kfree (dev); + } else { + dev->udev = NULL; + up (&dev->sem); + } + + /* remove our devfs node */ + devfs_unregister(dev->devfs); + + info("USB Skeleton #%d now disconnected", minor); + up (&minor_table_mutex); +} + + + +/** + * usb_skel_init + */ +static int __init usb_skel_init(void) +{ + int result; + + /* register this driver with the USB subsystem */ + result = usb_register(&skel_driver); + if (result < 0) { + err("usb_register failed for the "__FILE__" driver. Error number %d", + result); + return -1; + } + + info(DRIVER_VERSION " " DRIVER_AUTHOR); + info(DRIVER_DESC); + return 0; +} + + +/** + * usb_skel_exit + */ +static void __exit usb_skel_exit(void) +{ + /* deregister this driver with the USB subsystem */ + usb_deregister(&skel_driver); +} + + +module_init (usb_skel_init); +module_exit (usb_skel_exit); + +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); + diff -u --recursive --new-file v2.4.6/linux/drivers/usb/usb.c linux/drivers/usb/usb.c --- v2.4.6/linux/drivers/usb/usb.c Tue Jul 3 17:08:21 2001 +++ linux/drivers/usb/usb.c Thu Jul 12 14:21:05 2001 @@ -29,6 +29,7 @@ #include <linux/kmod.h> #include <linux/init.h> #include <linux/devfs_fs_kernel.h> +#include <linux/spinlock.h> #ifdef CONFIG_USB_DEBUG #define DEBUG @@ -59,6 +60,7 @@ */ LIST_HEAD(usb_driver_list); LIST_HEAD(usb_bus_list); +rwlock_t usb_bus_list_lock = RW_LOCK_UNLOCKED; devfs_handle_t usb_devfs_handle; /* /dev/usb dir. */ @@ -110,6 +112,7 @@ { struct list_head *tmp; + read_lock_irq (&usb_bus_list_lock); tmp = usb_bus_list.next; while (tmp != &usb_bus_list) { struct usb_bus *bus = list_entry(tmp,struct usb_bus, bus_list); @@ -117,6 +120,7 @@ tmp = tmp->next; usb_check_support(bus->root_hub); } + read_unlock_irq (&usb_bus_list_lock); } /* @@ -178,6 +182,7 @@ */ list_del(&driver->driver_list); + read_lock_irq (&usb_bus_list_lock); tmp = usb_bus_list.next; while (tmp != &usb_bus_list) { struct usb_bus *bus = list_entry(tmp,struct usb_bus,bus_list); @@ -185,6 +190,7 @@ tmp = tmp->next; usb_drivers_purge(driver, bus->root_hub); } + read_unlock_irq (&usb_bus_list_lock); } struct usb_interface *usb_ifnum_to_if(struct usb_device *dev, unsigned ifnum) @@ -415,6 +421,7 @@ { int busnum; + write_lock_irq (&usb_bus_list_lock); busnum = find_next_zero_bit(busmap.busmap, USB_MAXBUS, 1); if (busnum < USB_MAXBUS) { set_bit(busnum, busmap.busmap); @@ -426,6 +433,7 @@ /* Add it to the list of buses */ list_add(&bus->bus_list, &usb_bus_list); + write_unlock_irq (&usb_bus_list_lock); usbdevfs_add_bus(bus); @@ -447,9 +455,11 @@ * controller code, as well as having it call this when cleaning * itself up */ + write_lock_irq (&usb_bus_list_lock); list_del(&bus->bus_list); + write_unlock_irq (&usb_bus_list_lock); - usbdevfs_remove_bus(bus); + usbdevfs_remove_bus(bus); clear_bit(bus->busnum, busmap.busmap); @@ -688,10 +698,12 @@ return -1; } + down(&dev->serialize); + interface = dev->actconfig->interface + ifnum; if (usb_interface_claimed(interface)) - return -1; + goto out_err; private = NULL; for (tmp = usb_driver_list.next; tmp != &usb_driver_list;) { @@ -699,7 +711,6 @@ driver = list_entry(tmp, struct usb_driver, driver_list); tmp = tmp->next; - down(&driver->serialize); id = driver->id_table; /* new style driver? */ if (id) { @@ -707,7 +718,9 @@ interface->act_altsetting = i; id = usb_match_id(dev, interface, id); if (id) { + down(&driver->serialize); private = driver->probe(dev,ifnum,id); + up(&driver->serialize); if (private != NULL) break; } @@ -717,15 +730,21 @@ interface->act_altsetting = 0; } else /* "old style" driver */ + { + down(&driver->serialize); private = driver->probe(dev, ifnum, NULL); + up(&driver->serialize); + } - up(&driver->serialize); if (private) { usb_driver_claim_interface(driver, interface, private); + up(&dev->serialize); return 0; } } +out_err: + up(&dev->serialize); return -1; } @@ -924,6 +943,8 @@ atomic_set(&dev->refcnt, 1); INIT_LIST_HEAD(&dev->inodes); INIT_LIST_HEAD(&dev->filelist); + + init_MUTEX(&dev->serialize); dev->bus->op->allocate(dev); diff -u --recursive --new-file v2.4.6/linux/drivers/video/Config.in linux/drivers/video/Config.in --- v2.4.6/linux/drivers/video/Config.in Fri Apr 13 20:31:32 2001 +++ linux/drivers/video/Config.in Tue Jul 10 20:16:30 2001 @@ -98,14 +98,13 @@ bool ' CGsix (GX,TurboGX) support' CONFIG_FB_CGSIX fi fi + tristate ' NEC PowerVR 2 display support' CONFIG_FB_PVR2 + dep_bool ' Debug pvr2fb' CONFIG_FB_PVR2_DEBUG $CONFIG_FB_PVR2 bool ' Epson 1355 framebuffer support' CONFIG_FB_E1355 if [ "$CONFIG_FB_E1355" = "y" ]; then hex ' Register Base Address' CONFIG_E1355_REG_BASE a8000000 hex ' Framebuffer Base Address' CONFIG_E1355_FB_BASE a8200000 fi - if [ "$CONFIG_SH_DREAMCAST" = "y" ]; then - tristate ' Dreamcast Frame Buffer support' CONFIG_FB_DC - fi if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then if [ "$CONFIG_PCI" != "n" ]; then tristate ' Matrox acceleration (EXPERIMENTAL)' CONFIG_FB_MATROX @@ -262,7 +261,8 @@ "$CONFIG_FB_PM2" = "y" -o "$CONFIG_FB_SGIVW" = "y" -o \ "$CONFIG_FB_RIVA" = "y" -o "$CONFIG_FB_ATY128" = "y" -o \ "$CONFIG_FB_CYBER2000" = "y" -o "$CONFIG_FB_3DFX" = "y" -o \ - "$CONFIG_FB_SIS" = "y" -o "$CONFIG_FB_SA1100" = "y" ]; then + "$CONFIG_FB_SIS" = "y" -o "$CONFIG_FB_SA1100" = "y" -o \ + "$CONFIG_FB_PVR2" = "y" ]; then define_tristate CONFIG_FBCON_CFB16 y else if [ "$CONFIG_FB_ATARI" = "m" -o "$CONFIG_FB_ATY" = "m" -o \ @@ -276,7 +276,7 @@ "$CONFIG_FB_PM2" = "m" -o "$CONFIG_FB_SGIVW" = "m" -o \ "$CONFIG_FB_RIVA" = "m" -o "$CONFIG_FB_ATY128" = "m" -o \ "$CONFIG_FB_CYBER2000" = "m" -o "$CONFIG_FB_SIS" = "m" -o \ - "$CONFIG_FB_SA1100" = "m" ]; then + "$CONFIG_FB_SA1100" = "m" -o "$CONFIG_FB_PVR2" = "m" ]; then define_tristate CONFIG_FBCON_CFB16 m fi fi @@ -284,14 +284,14 @@ "$CONFIG_FB_CLGEN" = "y" -o "$CONFIG_FB_VESA" = "y" -o \ "$CONFIG_FB_MATROX" = "y" -o "$CONFIG_FB_PM2" = "y" -o \ "$CONFIG_FB_ATY128" = "y" -o \ - "$CONFIG_FB_CYBER2000" = "y" ]; then + "$CONFIG_FB_CYBER2000" = "y" -o "$CONFIG_FB_PVR2" = "y" ]; then define_tristate CONFIG_FBCON_CFB24 y else if [ "$CONFIG_FB_ATY" = "m" -o "$CONFIG_FB_VIRTUAL" = "m" -o \ "$CONFIG_FB_CLGEN" = "m" -o "$CONFIG_FB_VESA" = "m" -o \ "$CONFIG_FB_MATROX" = "m" -o "$CONFIG_FB_PM2" = "m" -o \ "$CONFIG_FB_ATY128" = "m" -o \ - "$CONFIG_FB_CYBER2000" = "m" ]; then + "$CONFIG_FB_CYBER2000" = "m" -o "$CONFIG_FB_PVR2" = "m" ]; then define_tristate CONFIG_FBCON_CFB24 m fi fi @@ -302,7 +302,8 @@ "$CONFIG_FB_MATROX" = "y" -o "$CONFIG_FB_PM2" = "y" -o \ "$CONFIG_FB_RIVA" = "y" -o "$CONFIG_FB_ATY128" = "y" -o \ "$CONFIG_FB_FM2" = "y" -o "$CONFIG_FB_SGIVW" = "y" -o \ - "$CONFIG_FB_3DFX" = "y" -o "$CONFIG_FB_SIS" = "y" ]; then + "$CONFIG_FB_3DFX" = "y" -o "$CONFIG_FB_SIS" = "y" -o \ + "$CONFIG_FB_PVR2" = "y" ]; then define_tristate CONFIG_FBCON_CFB32 y else if [ "$CONFIG_FB_ATARI" = "m" -o "$CONFIG_FB_ATY" = "m" -o \ @@ -312,7 +313,8 @@ "$CONFIG_FB_MATROX" = "m" -o "$CONFIG_FB_PM2" = "m" -o \ "$CONFIG_FB_RIVA" = "m" -o "$CONFIG_FB_ATY128" = "m" -o \ "$CONFIG_FB_3DFX" = "m" -o \ - "$CONFIG_FB_SGIVW" = "m" -o "$CONFIG_FB_SIS" = "m" ]; then + "$CONFIG_FB_SGIVW" = "m" -o "$CONFIG_FB_SIS" = "m" -o \ + "$CONFIG_FB_PVR2" = "m" ]; then define_tristate CONFIG_FBCON_CFB32 m fi fi diff -u --recursive --new-file v2.4.6/linux/drivers/video/Makefile linux/drivers/video/Makefile --- v2.4.6/linux/drivers/video/Makefile Fri Apr 13 20:31:32 2001 +++ linux/drivers/video/Makefile Tue Jul 10 20:16:30 2001 @@ -101,7 +101,7 @@ obj-$(CONFIG_FB_VIRTUAL) += vfb.o obj-$(CONFIG_FB_HIT) += hitfb.o fbgen.o obj-$(CONFIG_FB_E1355) += epson1355fb.o fbgen.o -obj-$(CONFIG_FB_DC) += dcfb.o fbgen.o +obj-$(CONFIG_FB_PVR2) += pvr2fb.o # Generic Low Level Drivers diff -u --recursive --new-file v2.4.6/linux/drivers/video/clgenfb.c linux/drivers/video/clgenfb.c --- v2.4.6/linux/drivers/video/clgenfb.c Tue Mar 6 19:28:33 2001 +++ linux/drivers/video/clgenfb.c Tue Jul 17 18:53:55 2001 @@ -46,7 +46,7 @@ #include <linux/init.h> #include <linux/selection.h> #include <asm/pgtable.h> -#include <asm/io.h> + #ifdef CONFIG_ZORRO #include <linux/zorro.h> #endif @@ -168,15 +168,15 @@ TRUE, TRUE, TRUE, - 0xF0, + 0xF0, 0xF0, 0, /* unused, does not multiplex */ 0xF1, 0, /* unused, does not multiplex */ - 0x20 }, + 0x20 }, { BT_PICCOLO, "CL Piccolo", - 90000, + 90000, TRUE, TRUE, FALSE, @@ -286,22 +286,28 @@ static const struct { clgen_board_t btype; zorro_id id, id2; + unsigned long size; } clgen_zorro_probe_list[] __initdata = { { BT_SD64, ZORRO_PROD_HELFRICH_SD64_RAM, - ZORRO_PROD_HELFRICH_SD64_REG }, + ZORRO_PROD_HELFRICH_SD64_REG, + 0x400000 }, { BT_PICCOLO, ZORRO_PROD_HELFRICH_PICCOLO_RAM, - ZORRO_PROD_HELFRICH_PICCOLO_REG }, + ZORRO_PROD_HELFRICH_PICCOLO_REG, + 0x200000 }, { BT_PICASSO, ZORRO_PROD_VILLAGE_TRONIC_PICASSO_II_II_PLUS_RAM, - ZORRO_PROD_VILLAGE_TRONIC_PICASSO_II_II_PLUS_REG }, + ZORRO_PROD_VILLAGE_TRONIC_PICASSO_II_II_PLUS_REG, + 0x200000 }, { BT_SPECTRUM, ZORRO_PROD_GVP_EGS_28_24_SPECTRUM_RAM, - ZORRO_PROD_GVP_EGS_28_24_SPECTRUM_REG }, + ZORRO_PROD_GVP_EGS_28_24_SPECTRUM_REG, + 0x200000 }, { BT_PICASSO4, ZORRO_PROD_VILLAGE_TRONIC_PICASSO_IV_Z3, - 0 }, + 0, + 0x400000 }, }; #endif /* CONFIG_ZORRO */ @@ -431,7 +437,7 @@ } }, - /* + /* Modeline from XF86Config: Mode "1024x768" 80 1024 1136 1340 1432 768 770 774 805 */ @@ -705,7 +711,7 @@ assert (div != NULL); /* Calculate MCLK, in case VCLK is high enough to require > 50MHz. - * Assume a 64-bit data path for now. The formula is: + * Assume a 64-bit data path for now. The formula is: * ((B * PCLK * 2)/W) * 1.2 * B = bytes per pixel, PCLK = pixclock, W = data width in bytes */ mclk = ((bpp / 8) * freq * 2) / 4; @@ -1211,7 +1217,7 @@ /* 1280x1024 */ vga_wcrt (fb_info->regs, VGA_CRTC_MODE, 0xc7); else - /* mode control: VGA_CRTC_START_HI enable, ROTATE(?), 16bit + /* mode control: VGA_CRTC_START_HI enable, ROTATE(?), 16bit * address wrap, no compat. */ vga_wcrt (fb_info->regs, VGA_CRTC_MODE, 0xc3); @@ -1243,7 +1249,7 @@ * 1 bpp * */ - + /* programming for different color depths */ if (_par->var.bits_per_pixel == 1) { DPRINTK ("clgen: preparing for 1 bit deep display\n"); @@ -1269,7 +1275,7 @@ vga_wseq (fb_info->regs, CL_SEQR7, vga_rseq (fb_info->regs, CL_SEQR7) & ~0x01); break; - + default: printk (KERN_WARNING "clgen: unknown Board\n"); break; @@ -1310,7 +1316,7 @@ DPRINTK (" (for GD54xx)\n"); /* do nothing */ break; - + default: printk (KERN_WARNING "clgen: unknown Board\n"); break; @@ -1325,13 +1331,13 @@ vga_wseq (fb_info->regs, VGA_SEQ_PLANE_WRITE, 0x01); /* plane mask: only write to first plane */ offset = _par->var.xres_virtual / 16; } - + /****************************************************** * * 8 bpp * */ - + else if (_par->var.bits_per_pixel == 8) { DPRINTK ("clgen: preparing for 8 bit deep display\n"); switch (fb_info->btype) { @@ -1353,7 +1359,7 @@ vga_wseq (fb_info->regs, CL_SEQR7, vga_rseq (fb_info->regs, CL_SEQR7) | 0x01); break; - + default: printk (KERN_WARNING "clgen: unknown Board\n"); break; @@ -1395,7 +1401,7 @@ DPRINTK (" (for GD54xx)\n"); /* do nothing */ break; - + default: printk (KERN_WARNING "clgen: unknown Board\n"); break; @@ -1411,13 +1417,13 @@ vga_wseq (fb_info->regs, VGA_SEQ_PLANE_WRITE, 0xff); /* plane mask: enable writing to all 4 planes */ offset = _par->var.xres_virtual / 8; } - + /****************************************************** * * 16 bpp * */ - + else if (_par->var.bits_per_pixel == 16) { DPRINTK ("clgen: preparing for 16 bit deep display\n"); switch (fb_info->btype) { @@ -1469,7 +1475,7 @@ vga_wseq (fb_info->regs, CL_SEQR7, vga_rseq (fb_info->regs, CL_SEQR7) & ~0x01); break; - + default: printk (KERN_WARNING "CLGEN: unknown Board\n"); break; @@ -1479,20 +1485,21 @@ WGen (fb_info, VGA_PEL_MSK, 0xff); /* pixel mask: pass-through all planes */ #ifdef CONFIG_PCI WHDR (fb_info, 0xc0); /* Copy Xbh */ -#elif CONFIG_ZORRO +#elif defined(CONFIG_ZORRO) + /* FIXME: CONFIG_PCI and CONFIG_ZORRO may be defined both */ WHDR (fb_info, 0xa0); /* hidden dac reg: nothing special */ #endif vga_wseq (fb_info->regs, VGA_SEQ_MEMORY_MODE, 0x0a); /* memory mode: chain4, ext. memory */ vga_wseq (fb_info->regs, VGA_SEQ_PLANE_WRITE, 0xff); /* plane mask: enable writing to all 4 planes */ offset = _par->var.xres_virtual / 4; } - + /****************************************************** * * 32 bpp * */ - + else if (_par->var.bits_per_pixel == 32) { DPRINTK ("clgen: preparing for 24/32 bit deep display\n"); switch (fb_info->btype) { @@ -1541,7 +1548,7 @@ vga_wseq (fb_info->regs, CL_SEQR7, vga_rseq (fb_info->regs, CL_SEQR7) & ~0x01); break; - + default: printk (KERN_WARNING "clgen: unknown Board\n"); break; @@ -1554,18 +1561,18 @@ vga_wseq (fb_info->regs, VGA_SEQ_PLANE_WRITE, 0xff); /* plane mask: enable writing to all 4 planes */ offset = _par->var.xres_virtual / 4; } - + /****************************************************** * * unknown/unsupported bpp * */ - + else { printk (KERN_ERR "clgen: What's this?? requested color depth == %d.\n", _par->var.bits_per_pixel); } - + vga_wcrt (fb_info->regs, VGA_CRTC_OFFSET, offset & 0xff); tmp = 0x22; if (offset & 0x100) @@ -1674,7 +1681,7 @@ if (regno >= 16) return 0; - + switch (fb_info->currentmode.var.bits_per_pixel) { #ifdef FBCON_HAS_CFB16 @@ -1871,11 +1878,11 @@ static void __init init_vgachip (struct clgenfb_info *fb_info) { const struct clgen_board_info_rec *bi; - + DPRINTK ("ENTER\n"); assert (fb_info != NULL); - + bi = &clgen_board_info[fb_info->btype]; /* reset board globally */ @@ -1918,16 +1925,7 @@ break; } -#ifdef CLGEN_USE_HARDCODED_RAM_SETTINGS - /* "pre-set" a RAMsize; if the test succeeds, double it */ - if (fb_info->btype == BT_SD64 || - fb_info->btype == BT_PICASSO4) - fb_info->size = 0x400000; - else - fb_info->size = 0x200000; -#else assert (fb_info->size > 0); /* make sure RAM size set by this point */ -#endif /* assume it's a "large memory" board (2/4 MB) */ fb_info->smallboard = FALSE; @@ -2141,7 +2139,7 @@ default: /* do nothing */ break; } } - + DPRINTK ("EXIT\n"); #endif /* CONFIG_ZORRO */ } @@ -2154,10 +2152,10 @@ int accel_text; DPRINTK ("ENTER\n"); - + assert (_par != NULL); assert (fb_info != NULL); - + accel_text = _par->var.accel_flags & FB_ACCELF_TEXT; printk ("Cirrus Logic video mode: "); @@ -2428,19 +2426,19 @@ int i; DPRINTK ("ENTER\n"); - + for (i = 0; i < ARRAY_SIZE(clgen_pci_probe_list); i++) { pdev = NULL; while ((pdev = pci_find_device (PCI_VENDOR_ID_CIRRUS, clgen_pci_probe_list[i].device, pdev)) != NULL) { if (pci_enable_device(pdev) == 0) { - *btype = clgen_pci_probe_list[i - 1].btype; + *btype = clgen_pci_probe_list[i].btype; DPRINTK ("EXIT, returning pdev=%p\n", pdev); return pdev; } } } - + DPRINTK ("EXIT, returning NULL\n"); return NULL; } @@ -2572,7 +2570,7 @@ #ifdef CONFIG_ZORRO static int __init clgen_zorro_find (struct zorro_dev **z_o, struct zorro_dev **z2_o, - clgen_board_t *btype) + clgen_board_t *btype, unsigned long *size) { struct zorro_dev *z = NULL; int i; @@ -2590,14 +2588,16 @@ *z2_o = zorro_find_device(clgen_zorro_probe_list[i].id2, NULL); else *z2_o = NULL; - *btype = clgen_zorro_probe_list[i - 1].btype; - + + *btype = clgen_zorro_probe_list[i].btype; + *size = clgen_zorro_probe_list[i].size; + printk (KERN_INFO "clgen: %s board detected; ", clgen_board_info[*btype].name); - + return 0; } - + printk (KERN_NOTICE "clgen: no supported board found.\n"); return -1; } @@ -2621,20 +2621,21 @@ clgen_board_t *btype) { struct zorro_dev *z = NULL, *z2 = NULL; - unsigned long board_addr, board_size; - + unsigned long board_addr, board_size, size; + assert (info != NULL); assert (btype != NULL); - if (clgen_zorro_find (&z, &z2, btype)) + if (clgen_zorro_find (&z, &z2, btype, &size)) return -1; assert (z > 0); assert (z2 >= 0); assert (*btype != BT_NONE); - + info->board_addr = board_addr = z->resource.start; info->board_size = board_size = z->resource.end-z->resource.start+1; + info->size = size; if (!request_mem_region(board_addr, board_size, "clgenfb")) { printk(KERN_ERR "clgen: cannot reserve region 0x%lx, abort\n", @@ -2675,7 +2676,7 @@ } printk (KERN_INFO "Cirrus Logic chipset on Zorro bus\n"); - + return 0; } #endif /* CONFIG_ZORRO */ @@ -2704,7 +2705,8 @@ return -ENXIO; } -#elif CONFIG_ZORRO +#elif defined(CONFIG_ZORRO) + /* FIXME: CONFIG_PCI and CONFIG_ZORRO may be defined both */ if (clgen_zorro_setup (fb_info, &btype)) { DPRINTK ("EXIT, returning -ENXIO\n"); return -ENXIO; @@ -2808,18 +2810,18 @@ int __init clgenfb_setup(char *options) { char *this_opt, s[32]; int i; - + DPRINTK ("ENTER\n"); - + if (!options || !*options) return 0; - + for (this_opt = strtok (options, ","); this_opt != NULL; this_opt = strtok (NULL, ",")) { if (!*this_opt) continue; - + DPRINTK("clgenfb_setup: option '%s'\n", this_opt); - + for (i = 0; i < NUM_TOTAL_MODES; i++) { sprintf (s, "mode:%s", clgenfb_predefined[i].name); if (strcmp (this_opt, s) == 0) @@ -2915,9 +2917,9 @@ } /*** WHDR() - write into the Hidden DAC register ***/ -/* as the HDR is the only extension register that requires special treatment +/* as the HDR is the only extension register that requires special treatment * (the other extension registers are accessible just like the "ordinary" - * registers of their functional group) here is a specialized routine for + * registers of their functional group) here is a specialized routine for * accessing the HDR */ static void WHDR (const struct clgenfb_info *fb_info, unsigned char val) @@ -2966,7 +2968,7 @@ #ifdef CONFIG_ZORRO assert (fb_info->regs != NULL); fb_info->SFR = val; - writeb (val, fb_info->regs + 0x8000); + z_writeb (val, fb_info->regs + 0x8000); #endif } @@ -2978,7 +2980,7 @@ /* to flip to Amiga display */ assert (fb_info->regs != NULL); fb_info->SFR = val; - writeb (val, fb_info->regs + 0x9000); + z_writeb (val, fb_info->regs + 0x9000); #endif } @@ -3383,7 +3385,7 @@ * * DESCRIPTION: */ - + static void clgen_dump (void) { diff -u --recursive --new-file v2.4.6/linux/drivers/video/cyber2000fb.c linux/drivers/video/cyber2000fb.c --- v2.4.6/linux/drivers/video/cyber2000fb.c Tue Jul 3 17:08:21 2001 +++ linux/drivers/video/cyber2000fb.c Wed Jul 4 11:50:39 2001 @@ -367,6 +367,7 @@ * Other */ u_char palette_ctrl; + u_int vmode; }; static const u_char crtc_idx[] = { @@ -427,6 +428,16 @@ cyber2000_attrw(0x13, 0x00); cyber2000_attrw(0x14, 0x00); + /* woody: set the interlaced bit... */ + /* FIXME: what about doublescan? */ + cyber2000_outb(0x11, 0x3ce); + i = cyber2000_inb(0x3cf); + if (hw->vmode == FB_VMODE_INTERLACED) + i |= 0x20; + else + i &= ~0x20; + cyber2000_outb(i, 0x3cf); + /* PLL registers */ cyber2000_grphw(DCLK_MULT, hw->clock_mult); cyber2000_grphw(DCLK_DIV, hw->clock_div); @@ -711,6 +722,7 @@ hw->width = var->xres_virtual; hw->palette_ctrl = 0x06; + hw->vmode = var->vmode; switch (var->bits_per_pixel) { #ifdef FBCON_HAS_CFB8 @@ -1570,7 +1582,7 @@ /* * Our driver data */ - dev->driver_data = cfb; + pci_set_drvdata(dev, cfb); if (int_cfb_info == NULL) int_cfb_info = cfb; @@ -1586,7 +1598,7 @@ static void __devexit cyberpro_remove(struct pci_dev *dev) { - struct cfb_info *cfb = (struct cfb_info *)dev->driver_data; + struct cfb_info *cfb = pci_get_drvdata(dev); if (cfb) { /* @@ -1606,7 +1618,7 @@ * Ensure that the driver data is no longer * valid. */ - dev->driver_data = NULL; + pci_set_drvdata(dev, NULL); if (cfb == int_cfb_info) int_cfb_info = NULL; } @@ -1622,7 +1634,7 @@ */ static int cyberpro_resume(struct pci_dev *dev) { - struct cfb_info *cfb = (struct cfb_info *)dev->driver_data; + struct cfb_info *cfb = pci_get_drvdata(dev); if (cfb) { cyberpro_init_hw(cfb, 0); diff -u --recursive --new-file v2.4.6/linux/drivers/video/dcfb.c linux/drivers/video/dcfb.c --- v2.4.6/linux/drivers/video/dcfb.c Sun May 20 12:11:39 2001 +++ linux/drivers/video/dcfb.c Wed Dec 31 16:00:00 1969 @@ -1,504 +0,0 @@ -/* - * $Id: dcfb.c,v 1.1 2001/04/01 15:02:51 yaegashi Exp $ - * SEGA Dreamcast framebuffer - */ - -#include <linux/config.h> -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/sched.h> -#include <linux/errno.h> -#include <linux/string.h> -#include <linux/mm.h> -#include <linux/tty.h> -#include <linux/malloc.h> -#include <linux/delay.h> -#include <linux/nubus.h> -#include <linux/init.h> - -#include <asm/uaccess.h> -#include <asm/pgtable.h> -#include <asm/io.h> - -#include <linux/fb.h> - -#include <video/fbcon.h> -#include <video/fbcon-cfb16.h> -#include <video/fbcon-cfb32.h> - -#define BORDERRGB 0xa05f8040 -#define DISPLAYMODE 0xa05f8044 -#define ALPHAMODE 0xa05f8048 -#define DISPLAYALIGN 0xa05f804c -#define BASEOFFSET1 0xa05f8050 -#define BASEOFFSET2 0xa05f8054 -#define DISPLAYSIZE 0xa05f805c -#define SYNCMODE 0xa05f80d0 -#define VERTICALRANGE 0xa05f80dc -#define HORIZPOSITION 0xa05f80ec -#define VERTPOSITION 0xa05f80f0 -#define PALETTEMODE 0xa05f8108 -#define VIDEOOUTPUT 0xa0702c00 - -static unsigned long dc_parm_vga_16bpp[] = { - DISPLAYMODE, 0x00800005, - BASEOFFSET1, 0, - BASEOFFSET2, 640*2, - DISPLAYSIZE, (1<<20)+((480-1)<<10)+(640*2/4-1), - SYNCMODE, 0x100, - VERTPOSITION, 0x00230023, - VERTICALRANGE, 0x00280208, - HORIZPOSITION, 0x00000090, - VIDEOOUTPUT, 0, - 0, 0, -}; - -static unsigned long dc_parm_vga_32bpp[] = { - DISPLAYMODE, 0x0080000d, - BASEOFFSET1, 0, - BASEOFFSET2, 640*4, - DISPLAYSIZE, (1<<20)+((480-1)<<10)+(640*4/4-1), - SYNCMODE, 0x100, - VERTPOSITION, 0x00230023, - VERTICALRANGE, 0x00280208, - HORIZPOSITION, 0x00000090, - VIDEOOUTPUT, 0, - 0, 0, -}; - -static unsigned long *dc_parm_vga[] = { - dc_parm_vga_16bpp, - dc_parm_vga_32bpp, -}; - -static unsigned long dc_parm_composite_16bpp[] = { - DISPLAYMODE, 0x00000005, - BASEOFFSET1, 0, - BASEOFFSET2, 640*2, - DISPLAYSIZE, ((640*2/4+1)<<20)+((240-1)<<10)+(640*2/4-1), - SYNCMODE, 0x150, - VERTPOSITION, 0x00120012, - VERTICALRANGE, 0x00240204, - HORIZPOSITION, 0x000000a4, - VIDEOOUTPUT, 0x300, - 0, 0, -}; - -static unsigned long dc_parm_composite_32bpp[] = { - DISPLAYMODE, 0x0000000d, - BASEOFFSET1, 0, - BASEOFFSET2, 640*4, - DISPLAYSIZE, ((640*4/4+1)<<20)+((240-1)<<10)+(640*4/4-1), - SYNCMODE, 0x150, - VERTPOSITION, 0x00120012, - VERTICALRANGE, 0x00240204, - HORIZPOSITION, 0x000000a4, - VIDEOOUTPUT, 0x300, - 0, 0, -}; - -static unsigned long *dc_parm_composite[] = { - dc_parm_composite_16bpp, - dc_parm_composite_32bpp, -}; - -static unsigned long dc_parm_interlace_16bpp[] = { - DISPLAYMODE, 0x00000005, - BASEOFFSET1, 0, - BASEOFFSET2, 640*2, - DISPLAYSIZE, ((640*2/4+1)<<20)+((240-1)<<10)+(640*2/4-1), - SYNCMODE, 0x150, - VERTPOSITION, 0x00120012, - VERTICALRANGE, 0x00240204, - HORIZPOSITION, 0x000000a4, - VIDEOOUTPUT, 0, - 0, 0, -}; - -static unsigned long dc_parm_interlace_32bpp[] = { - DISPLAYMODE, 0x0000000d, - BASEOFFSET1, 0, - BASEOFFSET2, 640*4, - DISPLAYSIZE, ((640*4/4+1)<<20)+((240-1)<<10)+(640*4/4-1), - SYNCMODE, 0x150, - VERTPOSITION, 0x00120012, - VERTICALRANGE, 0x00240204, - HORIZPOSITION, 0x000000a4, - VIDEOOUTPUT, 0, - 0, 0, -}; - -static unsigned long *dc_parm_interlace[] = { - dc_parm_interlace_16bpp, - dc_parm_interlace_32bpp, -}; - -struct dcfb_info { - struct fb_info_gen gen; -}; - -struct dcfb_par -{ - int x, y; - int bpp; -}; - -static struct dcfb_info fb_info; -static struct dcfb_par current_par; -static int current_par_valid = 0; -static struct display disp; - -static union { -#ifdef FBCON_HAS_CFB16 - u16 cfb16[16]; -#endif -#ifdef FBCON_HAS_CFB32 - u32 cfb32[16]; -#endif -} fbcon_cmap; - -static unsigned long **dc_parms; -static unsigned long dc_videobase, dc_videosize; -static struct fb_var_screeninfo default_var; - -int dcfb_init(void); - -static void dcfb_set_par(struct dcfb_par *par, const struct fb_info *info); -static void dcfb_encode_var(struct fb_var_screeninfo *var, - struct dcfb_par *par, - const struct fb_info *info); - - -/* - * Check cable type. - * 0: VGA, 2: RGB, 3: Composite - */ - -#define PCTRA 0xff80002c -#define PDTRA 0xff800030 - -static int dcfb_cable_check(void) -{ - unsigned long temp = ctrl_inl(PCTRA); - temp &= 0xfff0ffff; - temp |= 0x000a0000; - ctrl_outl(temp, PCTRA); - return (ctrl_inw(PDTRA)>>8)&3; -} - -static void dcfb_detect(void) -{ - struct dcfb_par par; - int cable = dcfb_cable_check(); - unsigned long **parm_list[4] = { - dc_parm_vga, dc_parm_vga, dc_parm_interlace, dc_parm_composite, - }; - char *cable_name[] = { "VGA", "VGA", "Interlace", "Composite", }; - - dc_videobase = 0xa5000000; - dc_videosize = 0x00200000; - - par.x = 640; - par.y = 480; - par.bpp = 32; - dc_parms = parm_list[cable]; - printk(KERN_INFO "Dreamcast video cable detected: %s.\n", cable_name[cable]); - - dcfb_set_par(&par, NULL); - dcfb_encode_var(&default_var, &par, NULL); -} - -static int dcfb_encode_fix(struct fb_fix_screeninfo *fix, - struct dcfb_par *par, - const struct fb_info *info) -{ - memset(fix, 0, sizeof(struct fb_fix_screeninfo)); - - strcpy(fix->id, "SEGA Dreamcast"); - fix->smem_start = dc_videobase; - fix->smem_len = dc_videosize; - fix->type = FB_TYPE_PACKED_PIXELS; - fix->type_aux = 0; - fix->visual = FB_VISUAL_TRUECOLOR; - fix->xpanstep = 0; - fix->ypanstep = 0; - fix->ywrapstep = 0; - - switch(par->bpp) { - default: - case 16: - fix->line_length = par->x*2; - break; - case 32: - fix->line_length = par->x*4; - break; - } - - return 0; -} - - -static int dcfb_decode_var(struct fb_var_screeninfo *var, - struct dcfb_par *par, - const struct fb_info *info) -{ - par->x = var->xres; - par->y = var->yres; - par->bpp = var->bits_per_pixel; - return 0; -} - - -static void dcfb_encode_var(struct fb_var_screeninfo *var, - struct dcfb_par *par, - const struct fb_info *info) -{ - memset(var, 0, sizeof(*var)); - - var->xres = par->x; - var->yres = par->y; - var->xres_virtual = var->xres; - var->yres_virtual = var->yres; - var->xoffset = 0; - var->yoffset = 0; - var->bits_per_pixel = par->bpp; - var->grayscale = 0; - var->transp.offset = 0; - var->transp.length = 0; - var->transp.msb_right = 0; - var->nonstd = 0; - var->activate = 0; - var->height = -1; - var->width = -1; - var->vmode = FB_VMODE_NONINTERLACED; - var->pixclock = 0; - var->sync = 0; - var->left_margin = 0; - var->right_margin = 0; - var->upper_margin = 0; - var->lower_margin = 0; - var->hsync_len = 0; - var->vsync_len = 0; - - switch (var->bits_per_pixel) { - - case 16: /* RGB 565 */ - var->red.offset = 11; - var->red.length = 5; - var->green.offset = 5; - var->green.length = 6; - var->blue.offset = 0; - var->blue.length = 5; - var->transp.offset = 0; - var->transp.length = 0; - break; - - case 32: - var->red.offset = 16; - var->red.length = 8; - var->green.offset = 8; - var->green.length = 8; - var->blue.offset = 0; - var->blue.length = 8; - var->transp.offset = 0; - var->transp.length = 0; - break; - - } - - var->red.msb_right = 0; - var->green.msb_right = 0; - var->blue.msb_right = 0; - var->transp.msb_right = 0; -} - - -static void dcfb_get_par(struct dcfb_par *par, const struct fb_info *info) -{ - *par = current_par; -} - - -static void dcfb_set_par(struct dcfb_par *par, const struct fb_info *info) -{ - unsigned long a, d, *p; - - current_par = *par; - current_par_valid = 1; - - switch(par->bpp) { - default: - case 16: - p = dc_parms[0]; - break; - case 32: - p = dc_parms[1]; - break; - } - - ctrl_outl(0, 0xa05f8008); /* reset? */ - ctrl_outl(0, BORDERRGB); - - while(1) { - a = *p++; d = *p++; - if (!a) break; - ctrl_outl(d, a); - } - -} - -static struct { - u_int red, green, blue; -} palette[256]; - -static int dcfb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue, - u_int *transp, struct fb_info *info) -{ - if (regno > 255) - return 1; - - *red = palette[regno].red; - *green = palette[regno].green; - *blue = palette[regno].blue; - *transp = 0; - - return 0; -} - - -static int dcfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, - u_int transp, struct fb_info *info) -{ - if (regno > 255) - return 1; - - palette[regno].red = red; - palette[regno].green = green; - palette[regno].blue = blue; - - if(regno<16) { - switch(current_par.bpp) { -#ifdef FBCON_HAS_CFB16 - case 16: - fbcon_cmap.cfb16[regno] = - ((red & 0xf800) ) | - ((green & 0xfc00) >> 5) | - ((blue & 0xf800) >> 11); - break; -#endif -#ifdef FBCON_HAS_CFB32 - case 32: - fbcon_cmap.cfb32[regno] = - ((red & 0xff00) << 8) | - ((green & 0xff00) ) | - ((blue & 0xff00) >> 8); - break; -#endif - } - } - - return 0; -} - -static int dcfb_blank(int blank_mode, const struct fb_info *info) -{ - return 0; -} - - -static void dcfb_set_disp(const void *par, struct display *disp, - struct fb_info_gen *info) -{ - disp->screen_base = (void *)dc_videobase; - disp->scrollmode = SCROLL_YREDRAW; - - switch(((struct dcfb_par *)par)->bpp) { -#ifdef FBCON_HAS_CFB16 - case 16: - disp->dispsw = &fbcon_cfb16; - disp->dispsw_data = fbcon_cmap.cfb16; - break; -#endif -#ifdef FBCON_HAS_CFB32 - case 32: - disp->dispsw = &fbcon_cfb32; - disp->dispsw_data = fbcon_cmap.cfb32; - break; -#endif - default: - disp->dispsw = &fbcon_dummy; - } -} - - -struct fbgen_hwswitch dcfb_switch = { - dcfb_detect, - dcfb_encode_fix, - dcfb_decode_var, - dcfb_encode_var, - dcfb_get_par, - dcfb_set_par, - dcfb_getcolreg, - dcfb_setcolreg, - NULL, - dcfb_blank, - dcfb_set_disp -}; - -static struct fb_ops dcfb_ops = { - owner: THIS_MODULE, - fb_get_fix: fbgen_get_fix, - fb_get_var: fbgen_get_var, - fb_set_var: fbgen_set_var, - fb_get_cmap: fbgen_get_cmap, - fb_set_cmap: fbgen_set_cmap, -}; - - -int __init dcfb_init(void) -{ - strcpy(fb_info.gen.info.modename, "SEGA Dreamcast"); - fb_info.gen.info.node = -1; - fb_info.gen.info.flags = FBINFO_FLAG_DEFAULT; - fb_info.gen.info.fbops = &dcfb_ops; - fb_info.gen.info.disp = &disp; - fb_info.gen.info.changevar = NULL; - fb_info.gen.info.switch_con = &fbgen_switch; - fb_info.gen.info.updatevar = &fbgen_update_var; - fb_info.gen.info.blank = &fbgen_blank; - fb_info.gen.parsize = sizeof(struct dcfb_par); - fb_info.gen.fbhw = &dcfb_switch; - fb_info.gen.fbhw->detect(); - - fbgen_get_var(&disp.var, -1, &fb_info.gen.info); - disp.var.activate = FB_ACTIVATE_NOW; - fbgen_do_set_var(&disp.var, 1, &fb_info.gen); - fbgen_set_disp(-1, &fb_info.gen); - fbgen_install_cmap(0, &fb_info.gen); - - if(register_framebuffer(&fb_info.gen.info)<0) return -EINVAL; - - printk(KERN_INFO "fb%d: %s frame buffer device\n", - GET_FB_IDX(fb_info.gen.info.node), fb_info.gen.info.modename); - - return 0; -} - - -void dcfb_cleanup(struct fb_info *info) -{ - unregister_framebuffer(info); -} - - -#ifdef MODULE -int init_module(void) -{ - return dcfb_init(); -} - -void cleanup_module(void) -{ - dcfb_cleanup(void); -} -#endif diff -u --recursive --new-file v2.4.6/linux/drivers/video/fbcon.c linux/drivers/video/fbcon.c --- v2.4.6/linux/drivers/video/fbcon.c Tue Jul 3 17:08:21 2001 +++ linux/drivers/video/fbcon.c Wed Jul 4 22:56:00 2001 @@ -31,6 +31,8 @@ * * Random hacking by Martin Mares <mj@ucw.cz> * + * 2001 - Documented with DocBook + * - Brad Douglas <brad@neruo.com> * * The low level operations for the various display memory organizations are * now in separate source files. @@ -239,6 +241,20 @@ add_timer(&cursor_timer); } + +/** + * PROC_CONSOLE - find the attached tty or visible console + * @info: frame buffer info structure + * + * Finds the tty attached to the process or visible console if + * the process is not directly attached to a tty (e.g. remote + * user) for device @info. + * + * Returns -1 errno on error, or tty/visible console number + * on success. + * + */ + int PROC_CONSOLE(const struct fb_info *info) { int fgc; @@ -261,6 +277,21 @@ return MINOR(current->tty->device) - 1; } + +/** + * set_all_vcs - set all virtual consoles to match + * @fbidx: frame buffer index (e.g. fb0, fb1, ...) + * @fb: frame buffer ops structure + * @var: frame buffer screen structure to set + * @info: frame buffer info structure + * + * Set all virtual consoles to match screen info set in @var + * for device @info. + * + * Returns negative errno on error, or zero on success. + * + */ + int set_all_vcs(int fbidx, struct fb_ops *fb, struct fb_var_screeninfo *var, struct fb_info *info) { @@ -277,6 +308,17 @@ return 0; } + +/** + * set_con2fb_map - map console to frame buffer device + * @unit: virtual console number to map + * @newidx: frame buffer index to map virtual console to + * + * Maps a virtual console @unit to a frame buffer device + * @newidx. + * + */ + void set_con2fb_map(int unit, int newidx) { int oldidx = con2fb_map[unit]; @@ -1124,6 +1166,20 @@ } } +/** + * fbcon_redraw_clear - clear area of the screen + * @conp: stucture pointing to current active virtual console + * @p: display structure + * @sy: starting Y coordinate + * @sx: starting X coordinate + * @height: height of area to clear + * @width: width of area to clear + * + * Clears a specified area of the screen. All dimensions are in + * pixels. + * + */ + void fbcon_redraw_clear(struct vc_data *conp, struct display *p, int sy, int sx, int height, int width) { @@ -1133,7 +1189,25 @@ fbcon_putc(conp, ' ', sy+y, sx+x); } -/* This cannot be used together with ypan or ywrap */ + +/** + * fbcon_redraw_bmove - copy area of screen to another area + * @p: display structure + * @sy: origin Y coordinate + * @sx: origin X coordinate + * @dy: destination Y coordinate + * @dx: destination X coordinate + * @h: height of area to copy + * @w: width of area to copy + * + * Copies an area of the screen to another area of the same screen. + * All dimensions are in pixels. + * + * Note that this function cannot be used together with ypan or + * ywrap. + * + */ + void fbcon_redraw_bmove(struct display *p, int sy, int sx, int dy, int dx, int h, int w) { if (sy != dy) diff -u --recursive --new-file v2.4.6/linux/drivers/video/fbmem.c linux/drivers/video/fbmem.c --- v2.4.6/linux/drivers/video/fbmem.c Wed Apr 25 16:31:16 2001 +++ linux/drivers/video/fbmem.c Tue Jul 10 20:16:30 2001 @@ -122,8 +122,9 @@ extern int radeonfb_setup(char*); extern int e1355fb_init(void); extern int e1355fb_setup(char*); -extern int dcfb_init(void); - +extern int pvr2fb_init(void); +extern int pvr2fb_setup(char*); + static struct { const char *name; int (*init)(void); @@ -270,8 +271,8 @@ #ifdef CONFIG_FB_E1355 { "e1355fb", e1355fb_init, e1355fb_setup }, #endif -#ifdef CONFIG_FB_DC - { "dcfb", dcfb_init, NULL }, +#ifdef CONFIG_FB_PVR2 + { "pvr2", pvr2fb_init, pvr2fb_setup }, #endif /* diff -u --recursive --new-file v2.4.6/linux/drivers/video/hgafb.c linux/drivers/video/hgafb.c --- v2.4.6/linux/drivers/video/hgafb.c Fri Feb 9 11:30:23 2001 +++ linux/drivers/video/hgafb.c Fri Jul 6 16:48:50 2001 @@ -49,7 +49,7 @@ #ifdef MODULE -#define INCLUDE_LINUX_LOGOBW +#define INCLUDE_LINUX_LOGO_DATA #include <linux/linux_logo.h> #endif /* MODULE */ diff -u --recursive --new-file v2.4.6/linux/drivers/video/imsttfb.c linux/drivers/video/imsttfb.c --- v2.4.6/linux/drivers/video/imsttfb.c Tue Jul 3 17:08:21 2001 +++ linux/drivers/video/imsttfb.c Sun Jul 8 13:17:30 2001 @@ -386,7 +386,6 @@ #if defined(CONFIG_PPC) static signed char init_vmode __initdata = -1, init_cmode __initdata = -1; #endif -static struct fb_info_imstt *fb_info_imstt_p[FB_MAX] = { 0, 0, 0, 0, 0, 0, 0, 0 }; static struct imstt_regvals tvp_reg_init_2 = { 512, @@ -444,6 +443,12 @@ { 0x38, 0x38, 0x38 }, { 0xf3, 0xf2, 0xf1 } }; +/* + * PCI driver prototypes + */ +static int imsttfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent); +static void imsttfb_remove(struct pci_dev *pdev); + static __u32 getclkMHz (struct fb_info_imstt *p) { @@ -1273,10 +1278,11 @@ break; #endif #ifdef FBCON_HAS_CFB32 - case 32: - i = (regno << 8) | regno; + case 32: { + int i = (regno << 8) | regno; p->fbcon_cmap.cfb32[regno] = (i << 16) | i; break; + } #endif } @@ -1623,6 +1629,23 @@ } } +static struct pci_device_id imsttfb_pci_tbl[] __devinitdata = { + { PCI_VENDOR_ID_IMS, PCI_DEVICE_ID_IMS_TT128, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, IBM }, + { PCI_VENDOR_ID_IMS, PCI_DEVICE_ID_IMS_TT3D, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, TVP }, + { 0, } +}; + +MODULE_DEVICE_TABLE(pci, imsttfb_pci_tbl); + +static struct pci_driver imsttfb_pci_driver = { + name: "imsttfb", + id_table: imsttfb_pci_tbl, + probe: imsttfb_probe, + remove: imsttfb_remove, +}; + static struct fb_ops imsttfb_ops = { owner: THIS_MODULE, fb_get_fix: imsttfb_get_fix, @@ -1869,7 +1892,6 @@ printk("fb%u: %s frame buffer; %uMB vram; chip version %u\n", i, p->fix.id, p->total_vram >> 20, tmp); - fb_info_imstt_p[i] = p; #ifdef CONFIG_FB_COMPAT_XPMAC strncpy(display_info.name, "IMS,tt128mb", sizeof(display_info.name)); display_info.fb_address = p->frame_buffer_phys; @@ -1881,61 +1903,69 @@ #endif /* CONFIG_FB_COMPAT_XPMAC */ } -int __init -imsttfb_init(void) +static int __devinit +imsttfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { - int i; - struct pci_dev *pdev = NULL; struct fb_info_imstt *p; unsigned long addr, size; - while ((pdev = pci_find_device(PCI_VENDOR_ID_IMS, PCI_ANY_ID, pdev))) { - if ((pdev->class >> 16) != PCI_BASE_CLASS_DISPLAY) - continue; - if (pci_enable_device(pdev)) - continue; - - addr = pci_resource_start (pdev, 0); - size = pci_resource_len (pdev, 0); - if (!addr) - continue; - - p = kmalloc(sizeof(struct fb_info_imstt), GFP_ATOMIC); - if (!p) - continue; - memset(p, 0, sizeof(struct fb_info_imstt)); - - if (!request_mem_region(addr, size, "imsttfb")) { - kfree(p); - continue; - } - printk("imsttfb: device=%04x\n", pdev->device); - - switch (pdev->device) { - case 0x9128: /* IMS,tt128mbA */ - p->ramdac = IBM; - break; - case 0x9135: /* IMS,tt3d */ - default: - p->ramdac = TVP; - break; - } + addr = pci_resource_start (pdev, 0); + size = pci_resource_len (pdev, 0); - p->frame_buffer_phys = addr; - p->board_size = size; - p->frame_buffer = (__u8 *)ioremap(addr, p->ramdac == IBM ? 0x400000 : 0x800000); - p->dc_regs_phys = addr + 0x800000; - p->dc_regs = (__u32 *)ioremap(addr + 0x800000, 0x1000); - p->cmap_regs_phys = addr + 0x840000; - p->cmap_regs = (__u8 *)ioremap(addr + 0x840000, 0x1000); + p = kmalloc(sizeof(struct fb_info_imstt), GFP_KERNEL); - init_imstt(p); + if (!p) { + printk(KERN_ERR "imsttfb: Can't allocate memory\n"); + return -ENOMEM; } - for (i = 0; i < FB_MAX; i++) { - if (fb_info_imstt_p[i]) - return 0; + + memset(p, 0, sizeof(struct fb_info_imstt)); + + if (!request_mem_region(addr, size, "imsttfb")) { + printk(KERN_ERR "imsttfb: Can't reserve memory region\n"); + kfree(p); + return -ENODEV; } - return -ENXIO; + + switch (pdev->device) { + case PCI_DEVICE_ID_IMS_TT128: /* IMS,tt128mbA */ + p->ramdac = IBM; + break; + case PCI_DEVICE_ID_IMS_TT3D: /* IMS,tt3d */ + p->ramdac = TVP; + break; + default: + printk(KERN_INFO "imsttfb: Device 0x%lx unknown, " + "contact maintainer.\n", pdev->device); + return -ENODEV; + } + + p->frame_buffer_phys = addr; + p->board_size = size; + p->frame_buffer = (__u8 *)ioremap(addr, p->ramdac == IBM ? 0x400000 : 0x800000); + p->dc_regs_phys = addr + 0x800000; + p->dc_regs = (__u32 *)ioremap(addr + 0x800000, 0x1000); + p->cmap_regs_phys = addr + 0x840000; + p->cmap_regs = (__u8 *)ioremap(addr + 0x840000, 0x1000); + + init_imstt(p); + + pdev->driver_data = p; + + return 0; +} + +static void __devexit +imsttfb_remove(struct pci_dev *pdev) +{ + struct fb_info_imstt *p = (struct fb_info_imstt *)pdev->driver_data; + + unregister_framebuffer(&p->info); + iounmap(p->cmap_regs); + iounmap(p->dc_regs); + iounmap(p->frame_buffer); + release_mem_region(p->frame_buffer_phys, p->board_size); + kfree(p); } #ifndef MODULE @@ -1996,29 +2026,20 @@ return 0; } -#else /* MODULE */ -static void __exit -imsttfb_exit(void) -{ - struct fb_info_imstt *p; - __u32 i; +#endif /* MODULE */ - for (i = 0; i < FB_MAX; i++) { - p = fb_info_imstt_p[i]; - if (!p) - continue; - unregister_framebuffer(&p->info); - iounmap(p->cmap_regs); - iounmap(p->dc_regs); - iounmap(p->frame_buffer); - release_mem_region(p->frame_buffer_phys, p->board_size); - kfree(p); - } +int __init imsttfb_init(void) +{ + return pci_module_init(&imsttfb_pci_driver); +} + +static void __exit imsttfb_exit(void) +{ + pci_unregister_driver(&imsttfb_pci_driver); } -#include "macmodes.c" - +#ifdef MODULE module_init(imsttfb_init); +#endif module_exit(imsttfb_exit); -#endif /* MODULE */ diff -u --recursive --new-file v2.4.6/linux/drivers/video/maxinefb.c linux/drivers/video/maxinefb.c --- v2.4.6/linux/drivers/video/maxinefb.c Wed Apr 18 11:49:12 2001 +++ linux/drivers/video/maxinefb.c Wed Jul 4 11:50:39 2001 @@ -272,14 +272,6 @@ return 0; } - -static int maxinefb_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg, int con, - struct fb_info *info) -{ - return -EINVAL; -} - static int maxinefb_switch(int con, struct fb_info *info) { maxinefb_do_fb_set_var(&fb_display[con].var, 1); @@ -287,22 +279,6 @@ return 0; } -/* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */ - -static void maxinefb_blank(int blank, struct fb_info *info) -{ - /* Not supported */ -} - -static int maxinefb_open(struct fb_info *info, int user) -{ - /* - * Nothing, only a usage count for the moment - */ - MOD_INC_USE_COUNT; - return (0); -} - static void maxinefb_set_disp(int con) { struct fb_fix_screeninfo fix; @@ -329,31 +305,28 @@ display->dispsw = &fbcon_cfb8; } -static int maxinefb_release(struct fb_info *info, int user) -{ - MOD_DEC_USE_COUNT; - return (0); -} - static struct fb_ops maxinefb_ops = { - owner:THIS_MODULE, - fb_open:maxinefb_open, - fb_release:maxinefb_release, - fb_get_fix:maxinefb_get_fix, - fb_get_var:maxinefb_get_var, - fb_set_var:maxinefb_set_var, - fb_get_cmap:maxinefb_get_cmap, - fb_set_cmap:maxinefb_set_cmap, - fb_ioctl:maxinefb_ioctl, - fb_mmap:0, - fb_rasterimg:0 + owner: THIS_MODULE, + fb_get_fix: maxinefb_get_fix, + fb_get_var: maxinefb_get_var, + fb_set_var: maxinefb_set_var, + fb_get_cmap: maxinefb_get_cmap, + fb_set_cmap: maxinefb_set_cmap, }; -int __init maxinefb_init_one() +int __init maxinefb_init(void) { volatile unsigned char *fboff; int i; + /* Validate we're on the proper machine type */ + if (mips_machtype != MACH_DS5000_XX) { + return -EINVAL; + } + + printk(KERN_INFO "Maxinefb: Personal DECstation detected\n"); + printk(KERN_INFO "Maxinefb: initializing onboard framebuffer\n"); + /* Framebuffer display memory base address */ fb_start = DS5000_xx_ONBOARD_FBMEM_START; @@ -390,7 +363,7 @@ fb_info.disp = &disp; fb_info.switch_con = &maxinefb_switch; fb_info.updatevar = &maxinefb_fb_update_var; - fb_info.blank = &maxinefb_blank; + fb_info.blank = NULL; fb_info.flags = FBINFO_FLAG_DEFAULT; maxinefb_do_fb_set_var(&maxinefb_defined, 1); @@ -403,23 +376,13 @@ return 0; } - -/* Initialise the framebuffer */ - -void __init maxinefb_init() +static void __exit maxinefb_exit(void) { - unsigned int sid; - - if (mips_machtype == MACH_DS5000_XX) { - printk("Maxinefb: Personal DECstation detected\n"); - printk("Maxinefb: initializing onboard framebuffer\n"); - - maxinefb_init_one(); - - } - + unregister_framebuffer(&fb_info); } -void __init maxinefb_setup(char *options, int *ints) -{ -} +#ifdef MODULE +module_init(maxinefb_init); +#endif +module_exit(maxinefb_exit); + diff -u --recursive --new-file v2.4.6/linux/drivers/video/pvr2fb.c linux/drivers/video/pvr2fb.c --- v2.4.6/linux/drivers/video/pvr2fb.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/video/pvr2fb.c Tue Jul 10 20:16:30 2001 @@ -0,0 +1,1171 @@ +/* drivers/video/pvr2fb.c + * + * Frame buffer and fbcon support for the NEC PowerVR2 found within the Sega + * Dreamcast. + * + * Copyright (c) 2001 M. R. Brown <mrbrown@0xd6.org> + * Copyright (c) 2001 Paul Mundt <lethal@chaoticdreams.org> + * + * This file is part of the LinuxDC project (linuxdc.sourceforge.net). + * + */ + +/* + * This driver is mostly based on the excellent amifb and vfb sources. It uses + * an odd scheme for converting hardware values to/from framebuffer values, here are + * some hacked-up formulas: + * + * The Dreamcast has screen offsets from each side of it's four borders and the start + * offsets of the display window. I used these values to calculate 'pseudo' values + * (think of them as placeholders) for the fb video mode, so that when it came time + * to convert these values back into their hardware values, I could just add mode- + * specific offsets to get the correct mode settings: + * + * left_margin = diwstart_h - borderstart_h; + * right_margin = borderstop_h - (diwstart_h + xres); + * upper_margin = diwstart_v - borderstart_v; + * lower_margin = borderstop_v - (diwstart_h + yres); + * + * hsync_len = borderstart_h + (hsync_total - borderstop_h); + * vsync_len = borderstart_v + (vsync_total - borderstop_v); + * + * Then, when it's time to convert back to hardware settings, the only constants + * are the borderstart_* offsets, all other values are derived from the fb video + * mode: + * + * // PAL + * borderstart_h = 116; + * borderstart_v = 44; + * ... + * borderstop_h = borderstart_h + hsync_total - hsync_len; + * ... + * diwstart_v = borderstart_v - upper_margin; + * + * However, in the current implementation, the borderstart values haven't had + * the benefit of being fully researched, so some modes may be broken. + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/string.h> +#include <linux/mm.h> +#include <linux/tty.h> +#include <linux/malloc.h> +#include <linux/delay.h> +#include <linux/config.h> +#include <linux/interrupt.h> +#include <linux/fb.h> +#include <linux/init.h> +#include <linux/console.h> + +#ifdef CONFIG_SH_DREAMCAST +#include <asm/io.h> +#include <asm/machvec.h> +#include <asm/dc_sysasic.h> +#endif + +#ifdef CONFIG_MTRR + #include <asm/mtrr.h> +#endif + +#include <video/fbcon.h> +#include <video/fbcon-cfb16.h> +#include <video/fbcon-cfb24.h> +#include <video/fbcon-cfb32.h> + +#ifdef CONFIG_FB_PVR2_DEBUG +# define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args) +#else +# define DPRINTK(fmt, args...) +#endif + +/* 2D video registers */ +#define DISP_BASE 0xa05f8000 + +#define DISP_BRDRCOLR (DISP_BASE + 0x40) +#define DISP_DIWMODE (DISP_BASE + 0x44) +#define DISP_DIWADDRL (DISP_BASE + 0x50) +#define DISP_DIWADDRS (DISP_BASE + 0x54) +#define DISP_DIWSIZE (DISP_BASE + 0x5c) +#define DISP_SYNCCONF (DISP_BASE + 0xd0) +#define DISP_BRDRHORZ (DISP_BASE + 0xd4) +#define DISP_SYNCSIZE (DISP_BASE + 0xd8) +#define DISP_BRDRVERT (DISP_BASE + 0xdc) +#define DISP_DIWCONF (DISP_BASE + 0xe8) +#define DISP_DIWHSTRT (DISP_BASE + 0xec) +#define DISP_DIWVSTRT (DISP_BASE + 0xf0) + +/* Pixel clocks, one for TV output, doubled for VGA output */ +#define TV_CLK 74239 +#define VGA_CLK 37119 + +/* This is for 60Hz - the VTOTAL is doubled for interlaced modes */ +#define PAL_HTOTAL 863 +#define PAL_VTOTAL 312 +#define NTSC_HTOTAL 857 +#define NTSC_VTOTAL 262 + +enum { CT_VGA, CT_NONE, CT_RGB, CT_COMPOSITE }; + +enum { VO_PAL, VO_NTSC, VO_VGA }; + +struct pvr2_params { u_short val; char *name; }; +static struct pvr2_params cables[] __initdata = { + { CT_VGA, "VGA" }, { CT_RGB, "RGB" }, { CT_COMPOSITE, "COMPOSITE" }, +}; + +static struct pvr2_params outputs[] __initdata = { + { VO_PAL, "PAL" }, { VO_NTSC, "NTSC" }, { VO_VGA, "VGA" }, +}; + +/* + * This describes the current video mode + */ + +static struct pvr2fb_par { + + int xres; + int yres; + int vxres; + int vyres; + int xoffset; + int yoffset; + u_short bpp; + + u_long pixclock; + u_short hsync_total; /* Clocks/line */ + u_short vsync_total; /* Lines/field */ + u_short borderstart_h; + u_short borderstop_h; + u_short borderstart_v; + u_short borderstop_v; + u_short diwstart_h; /* Horizontal offset of the display field */ + u_short diwstart_v; /* Vertical offset of the display field, for + interlaced modes, this is the long field */ + u_long disp_start; /* Address of image within VRAM */ + + u_long next_line; /* Modulo for next line */ + + u_char is_interlaced; /* Is the display interlaced? */ + u_char is_doublescan; /* Are scanlines output twice? (doublescan) */ + u_char is_lowres; /* Is horizontal pixel-doubling enabled? */ + + u_long bordercolor; /* RGB888 format border color */ + + u_long vmode; + +} currentpar; + +static int currcon = 0; +static int currbpp; +static struct display disp; +static struct fb_info fb_info; +static int pvr2fb_inverse = 0; + +static struct { u_short red, green, blue, alpha; } palette[256]; +static union { +#ifdef FBCON_HAS_CFB16 + u16 cfb16[16]; +#endif +#ifdef FBCON_HAS_CFB24 + u32 cfb24[16]; +#endif +#ifdef FBCON_HAS_CFB32 + u32 cfb32[16]; +#endif +} fbcon_cmap; + +static char pvr2fb_name[16] = "NEC PowerVR2"; + +#define VIDEOMEMSIZE (8*1024*1024) +static u_long videomemory = 0xa5000000, videomemorysize = VIDEOMEMSIZE; +static int cable_type = -1; +static int video_output = -1; + +#ifdef CONFIG_MTRR +static int enable_mtrr = 1; +static int mtrr_handle; +#endif + +/* + * We do all updating, blanking, etc. during the vertical retrace period + */ + +static u_short do_vmode_full = 0; /* Change the video mode */ +static u_short do_vmode_pan = 0; /* Update the video mode */ +static short do_blank = 0; /* (Un)Blank the screen */ + +static u_short is_blanked = 0; /* Is the screen blanked? */ + +/* Interface used by the world */ + +int pvr2fb_setup(char*); + +static int pvr2fb_get_fix(struct fb_fix_screeninfo *fix, int con, + struct fb_info *info); +static int pvr2fb_get_var(struct fb_var_screeninfo *var, int con, + struct fb_info *info); +static int pvr2fb_set_var(struct fb_var_screeninfo *var, int con, + struct fb_info *info); +static int pvr2fb_pan_display(struct fb_var_screeninfo *var, int con, + struct fb_info *info); +static int pvr2fb_get_cmap(struct fb_cmap *cmap, int kspc, int con, + struct fb_info *info); +static int pvr2fb_set_cmap(struct fb_cmap *cmap, int kspc, int con, + struct fb_info *info); + + /* + * Interface to the low level console driver + */ + +static int pvr2fbcon_switch(int con, struct fb_info *info); +static int pvr2fbcon_updatevar(int con, struct fb_info *info); +static void pvr2fbcon_blank(int blank, struct fb_info *info); + + /* + * Internal/hardware-specific routines + */ + +static void do_install_cmap(int con, struct fb_info *info); +static u_long get_line_length(int xres_virtual, int bpp); +static void set_color_bitfields(struct fb_var_screeninfo *var); +static int pvr2_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue, + u_int *transp, struct fb_info *info); +static int pvr2_setcolreg(u_int regno, u_int red, u_int green, u_int blue, + u_int transp, struct fb_info *info); + +static int pvr2_encode_fix(struct fb_fix_screeninfo *fix, + struct pvr2fb_par *par); +static int pvr2_decode_var(struct fb_var_screeninfo *var, + struct pvr2fb_par *par); +static int pvr2_encode_var(struct fb_var_screeninfo *var, + struct pvr2fb_par *par); +static void pvr2_get_par(struct pvr2fb_par *par); +static void pvr2_set_var(struct fb_var_screeninfo *var); +static void pvr2_pan_var(struct fb_var_screeninfo *var); +static int pvr2_update_par(void); +static void pvr2_update_display(void); +static void pvr2_init_display(void); +static void pvr2_do_blank(void); +static void pvr2fb_interrupt(int irq, void *dev_id, struct pt_regs *fp); +static int pvr2_init_cable(void); +static int pvr2_get_param(const struct pvr2_params *p, const char *s, + int val, int size); + +static struct fb_ops pvr2fb_ops = { + owner: THIS_MODULE, + fb_get_fix: pvr2fb_get_fix, + fb_get_var: pvr2fb_get_var, + fb_set_var: pvr2fb_set_var, + fb_get_cmap: pvr2fb_get_cmap, + fb_set_cmap: pvr2fb_set_cmap, + fb_pan_display: pvr2fb_pan_display, +}; + +static struct fb_videomode pvr2_modedb[] __initdata = { + + /* + * Broadcast video modes (PAL and NTSC). I'm unfamiliar with + * PAL-M and PAL-N, but from what I've read both modes parallel PAL and + * NTSC, so it shouldn't be a problem (I hope). + */ + + { + /* 640x480 @ 60Hz interlaced (NTSC) */ + "ntsc_640x480i", 60, 640, 480, TV_CLK, 38, 33, 0, 18, 146, 26, + FB_SYNC_BROADCAST, FB_VMODE_INTERLACED | FB_VMODE_YWRAP + }, + + { + /* 640x240 @ 60Hz (NTSC) */ + /* XXX: Broken! Don't use... */ + "ntsc_640x240", 60, 640, 240, TV_CLK, 38, 33, 0, 0, 146, 22, + FB_SYNC_BROADCAST, FB_VMODE_YWRAP + }, + + { + /* 640x480 @ 60hz (VGA) */ + "vga_640x480", 60, 640, 480, 38, 33, 0, 18, 146, 26, + 0, FB_VMODE_YWRAP + }, + +}; + +#define NUM_TOTAL_MODES ARRAY_SIZE(pvr2_modedb) + +#define DEFMODE_NTSC 0 +#define DEFMODE_PAL 0 +#define DEFMODE_VGA 2 + +static int defmode = DEFMODE_NTSC; +static const char *mode_option __initdata = NULL; + +/* Get the fixed part of the display */ + +static int pvr2fb_get_fix(struct fb_fix_screeninfo *fix, int con, + struct fb_info *info) +{ + struct pvr2fb_par par; + + if (con == -1) + pvr2_get_par(&par); + else { + int err; + + if ((err = pvr2_decode_var(&fb_display[con].var, &par))) + return err; + } + return pvr2_encode_fix(fix, &par); +} + +/* Get the user-defined part of the display */ + +static int pvr2fb_get_var(struct fb_var_screeninfo *var, int con, + struct fb_info *info) +{ + int err = 0; + + if (con == -1) { + struct pvr2fb_par par; + + pvr2_get_par(&par); + err = pvr2_encode_var(var, &par); + } else + *var = fb_display[con].var; + + return err; +} + +/* Set the user-defined part of the display */ + +static int pvr2fb_set_var(struct fb_var_screeninfo *var, int con, + struct fb_info *info) +{ + int err, activate = var->activate; + int oldxres, oldyres, oldvxres, oldvyres, oldbpp; + struct pvr2fb_par par; + + struct display *display; + if (con >= 0) + display = &fb_display[con]; + else + display = &disp; /* used during initialization */ + + /* + * FB_VMODE_CONUPDATE and FB_VMODE_SMOOTH_XPAN are equal! + * as FB_VMODE_SMOOTH_XPAN is only used internally + */ + + if (var->vmode & FB_VMODE_CONUPDATE) { + var->vmode |= FB_VMODE_YWRAP; + var->xoffset = display->var.xoffset; + var->yoffset = display->var.yoffset; + } + if ((err = pvr2_decode_var(var, &par))) + return err; + pvr2_encode_var(var, &par); + + /* Do memory check and bitfield set here?? */ + + if ((activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) { + oldxres = display->var.xres; + oldyres = display->var.yres; + oldvxres = display->var.xres_virtual; + oldvyres = display->var.yres_virtual; + oldbpp = display->var.bits_per_pixel; + display->var = *var; + if (oldxres != var->xres || oldyres != var->yres || + oldvxres != var->xres_virtual || oldvyres != var->yres_virtual || + oldbpp != var->bits_per_pixel) { + struct fb_fix_screeninfo fix; + + pvr2_encode_fix(&fix, &par); + display->screen_base = (char *)fix.smem_start; + display->visual = fix.visual; + display->type = fix.type; + display->type_aux = fix.type_aux; + display->ypanstep = fix.ypanstep; + display->ywrapstep = fix.ywrapstep; + display->line_length = fix.line_length; + display->can_soft_blank = 1; + display->inverse = pvr2fb_inverse; + switch (var->bits_per_pixel) { +#ifdef FBCON_HAS_CFB16 + case 16: + display->dispsw = &fbcon_cfb16; + display->dispsw_data = fbcon_cmap.cfb16; + break; +#endif +#ifdef FBCON_HAS_CFB24 + case 24: + display->dispsw = &fbcon_cfb24; + display->dispsw_data = fbcon_cmap.cfb24; + break; +#endif +#ifdef FBCON_HAS_CFB32 + case 32: + display->dispsw = &fbcon_cfb32; + display->dispsw_data = fbcon_cmap.cfb32; + break; +#endif + default: + display->dispsw = &fbcon_dummy; + break; + } + if (fb_info.changevar) + (*fb_info.changevar)(con); + } + if (oldbpp != var->bits_per_pixel) { + if ((err = fb_alloc_cmap(&display->cmap, 0, 0))) + return err; + do_install_cmap(con, info); + } + if (con == currcon) + pvr2_set_var(&display->var); + } + + return 0; +} + +/* + * Pan or wrap the display. + * This call looks only at xoffset, yoffset and the FB_VMODE_YRAP flag + */ + +static int pvr2fb_pan_display(struct fb_var_screeninfo *var, int con, + struct fb_info *info) +{ + if (var->vmode & FB_VMODE_YWRAP) { + if (var->yoffset<0 || var->yoffset >= + fb_display[con].var.yres_virtual || var->xoffset) + return -EINVAL; + } else { + if (var->xoffset+fb_display[con].var.xres > + fb_display[con].var.xres_virtual || + var->yoffset+fb_display[con].var.yres > + fb_display[con].var.yres_virtual) + return -EINVAL; + } + if (con == currcon) + pvr2_pan_var(var); + fb_display[con].var.xoffset = var->xoffset; + fb_display[con].var.yoffset = var->yoffset; + if (var->vmode & FB_VMODE_YWRAP) + fb_display[con].var.vmode |= FB_VMODE_YWRAP; + else + fb_display[con].var.vmode &= ~FB_VMODE_YWRAP; + + return 0; +} + +/* Get the colormap */ + +static int pvr2fb_get_cmap(struct fb_cmap *cmap, int kspc, int con, + struct fb_info *info) +{ + if (con == currcon) /* current console? */ + return fb_get_cmap(cmap, kspc, pvr2_getcolreg, info); + else if (fb_display[con].cmap.len) /* non default colormap? */ + fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2); + else + fb_copy_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel), + cmap, kspc ? 0 : 2); + return 0; +} + +/* Set the colormap */ + +static int pvr2fb_set_cmap(struct fb_cmap *cmap, int kspc, int con, + struct fb_info *info) +{ + int err; + + if (!fb_display[con].cmap.len) { /* no colormap allocated? */ + if ((err = fb_alloc_cmap(&fb_display[con].cmap, + 1<<fb_display[con].var.bits_per_pixel, + 0))) + return err; + } + if (con == currcon) /* current console? */ + return fb_set_cmap(cmap, kspc, pvr2_setcolreg, info); + else + fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1); + + return 0; +} + +static int pvr2fbcon_switch(int con, struct fb_info *info) +{ + /* Do we have to save the colormap? */ + if (fb_display[currcon].cmap.len) + fb_get_cmap(&fb_display[currcon].cmap, 1, pvr2_getcolreg, info); + + currcon = con; + pvr2_set_var(&fb_display[con].var); + /* Install new colormap */ + do_install_cmap(con, info); + return 0; +} + +static int pvr2fbcon_updatevar(int con, struct fb_info *info) +{ + pvr2_pan_var(&fb_display[con].var); + return 0; +} + +static void pvr2fbcon_blank(int blank, struct fb_info *info) +{ + do_blank = blank ? blank : -1; +} + +/* Setup the colormap */ + +static void do_install_cmap(int con, struct fb_info *info) +{ + if (con != currcon) + return; + if (fb_display[con].cmap.len) + fb_set_cmap(&fb_display[con].cmap, 1, pvr2_setcolreg, info); + else + fb_set_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel), + 1, pvr2_setcolreg, info); +} + +static inline u_long get_line_length(int xres_virtual, int bpp) +{ + return (u_long)((((xres_virtual*bpp)+31)&~31) >> 3); +} + +static void set_color_bitfields(struct fb_var_screeninfo *var) +{ + switch (var->bits_per_pixel) { + case 16: /* RGB 565 */ + var->red.offset = 11; var->red.length = 5; + var->green.offset = 5; var->green.length = 6; + var->blue.offset = 0; var->blue.length = 5; + var->transp.offset = 0; var->transp.length = 0; + break; + case 24: /* RGB 888 */ + var->red.offset = 16; var->red.length = 8; + var->green.offset = 8; var->green.length = 8; + var->blue.offset = 0; var->blue.length = 8; + var->transp.offset = 0; var->transp.length = 0; + break; + case 32: /* ARGB 8888 */ + var->red.offset = 16; var->red.length = 8; + var->green.offset = 8; var->green.length = 8; + var->blue.offset = 0; var->blue.length = 8; + var->transp.offset = 24; var->transp.length = 8; + break; + } +} + +static int pvr2_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue, + u_int *transp, struct fb_info *info) +{ + if (regno > 255) + return 1; + + *red = palette[regno].red; + *green = palette[regno].green; + *blue = palette[regno].blue; + *transp = 0; + return 0; +} + +static int pvr2_setcolreg(u_int regno, u_int red, u_int green, u_int blue, + u_int transp, struct fb_info *info) +{ + if (regno > 255) + return 1; + + palette[regno].red = red; + palette[regno].green = green; + palette[regno].blue = blue; + + if (regno < 16) { + switch (currbpp) { +#ifdef FBCON_HAS_CFB16 + case 16: /* RGB 565 */ + fbcon_cmap.cfb16[regno] = (red & 0xf800) | + ((green & 0xf800) >> 6) | + ((blue & 0xf800) >> 11); + break; +#endif +#ifdef FBCON_HAS_CFB24 + case 24: /* RGB 888 */ + red >>= 8; green >>= 8; blue >>= 8; + fbcon_cmap.cfb24[regno] = (red << 16) | (green << 8) | blue; + break; +#endif +#ifdef FBCON_HAS_CFB32 + case 32: /* ARGB 8888 */ + red >>= 8; green >>= 8; blue >>= 8; + fbcon_cmap.cfb32[regno] = (red << 16) | (green << 8) | blue; + break; +#endif + default: + DPRINTK("Invalid bit depth %d?!?\n", currbpp); + return 1; + } + } + + return 0; +} + + +static int pvr2_encode_fix(struct fb_fix_screeninfo *fix, + struct pvr2fb_par *par) +{ + memset(fix, 0, sizeof(struct fb_fix_screeninfo)); + strcpy(fix->id, pvr2fb_name); + fix->smem_start = videomemory; + fix->smem_len = videomemorysize; + fix->type = FB_TYPE_PACKED_PIXELS; + fix->type_aux = 0; + fix->visual = FB_VISUAL_TRUECOLOR; + + if (par->vmode & FB_VMODE_YWRAP) { + fix->ywrapstep = 1; + fix->xpanstep = fix->ypanstep = 0; + } else { + fix->ywrapstep = 0; + fix->xpanstep = 1; + fix->ypanstep = 1; + } + fix->line_length = par->next_line; + + return 0; +} + +/* + * Create a hardware video mode using the framebuffer values. If a value needs + * to be clipped or constrained it's done here. This routine needs a bit more + * work to make sure we're doing the right tests at the right time. + */ +static int pvr2_decode_var(struct fb_var_screeninfo *var, + struct pvr2fb_par *par) +{ + u_long line_length; + u_short vtotal; + + if (var->pixclock != TV_CLK && var->pixclock != VGA_CLK) { + DPRINTK("Invalid pixclock value %d\n", var->pixclock); + return -EINVAL; + } + par->pixclock = var->pixclock; + + if ((par->xres = var->xres) < 320) + par->xres = 320; + if ((par->yres = var->yres) < 240) + par->yres = 240; + if ((par->vxres = var->xres_virtual) < par->xres) + par->vxres = par->xres; + if ((par->vyres = var->yres_virtual) < par->yres) + par->vyres = par->yres; + + if ((par->bpp = var->bits_per_pixel) <= 16) + par->bpp = 16; + else if ((par->bpp = var->bits_per_pixel) <= 24) + par->bpp = 24; + else if ((par->bpp = var->bits_per_pixel) <= 32) + par->bpp = 32; + + currbpp = par->bpp; + + /* + * XXX: It's possible that a user could use a VGA box, change the cable + * type in hardware (i.e. switch from VGA<->composite), then change modes + * (i.e. switching to another VT). If that happens we should automagically + * change the output format to cope, but currently I don't have a VGA box + * to make sure this works properly. + */ + cable_type = pvr2_init_cable(); + if (cable_type == CT_VGA && video_output != VO_VGA) + video_output = VO_VGA; + + par->vmode = var->vmode & FB_VMODE_MASK; + if (par->vmode & FB_VMODE_INTERLACED && video_output != VO_VGA) + par->is_interlaced = 1; + /* + * XXX: Need to be more creative with this (i.e. allow doublecan for + * PAL/NTSC output). + */ + par->is_doublescan = (par->yres < 480 && video_output == VO_VGA); + + par->hsync_total = var->left_margin + var->xres + var->right_margin + + var->hsync_len; + par->vsync_total = var->upper_margin + var->yres + var->lower_margin + + var->vsync_len; + + if (var->sync & FB_SYNC_BROADCAST) { + vtotal = par->vsync_total; + if (par->is_interlaced) + vtotal /= 2; + if (vtotal > (PAL_VTOTAL + NTSC_VTOTAL)/2) { + /* PAL video output */ + /* XXX: Should be using a range here ... ? */ + if (par->hsync_total != PAL_HTOTAL) { + DPRINTK("invalid hsync total for PAL\n"); + return -EINVAL; + } + /* XXX: Check for start values here... */ + /* XXX: Check hardware for PAL-compatibility */ + par->borderstart_h = 116; + par->borderstart_v = 44; + } else { + /* NTSC video output */ + if (par->hsync_total != NTSC_HTOTAL) { + DPRINTK("invalid hsync total for NTSC\n"); + return -EINVAL; + } + par->borderstart_h = 126; + par->borderstart_v = 18; + } + } else { + /* VGA mode */ + /* XXX: What else needs to be checked? */ + /* + * XXX: We have a little freedom in VGA modes, what ranges should + * be here (i.e. hsync/vsync totals, etc.)? + */ + par->borderstart_h = 126; + par->borderstart_v = 40; + } + + /* Calculate the remainding offsets */ + par->borderstop_h = par->borderstart_h + par->hsync_total - + var->hsync_len; + par->borderstop_v = par->borderstart_v + par->vsync_total - + var->vsync_len; + par->diwstart_h = par->borderstart_h + var->left_margin; + par->diwstart_v = par->borderstart_v + var->upper_margin; + if (!par->is_interlaced) + par->borderstop_v /= 2; + + if (par->xres < 640) + par->is_lowres = 1; + + /* XXX: Needs testing. */ + if (!((par->vmode ^ var->vmode) & FB_VMODE_YWRAP)) { + par->xoffset = var->xoffset; + par->yoffset = var->yoffset; + if (par->vmode & FB_VMODE_YWRAP) { + if (par->xoffset || par->yoffset < 0 || par->yoffset >= + par->vyres) + par->xoffset = par->yoffset = 0; + } else { + if (par->xoffset < 0 || par->xoffset > par->vxres-par->xres || + par->yoffset < 0 || par->yoffset > par->vyres-par->yres) + par->xoffset = par->yoffset = 0; + } + } else + par->xoffset = par->yoffset = 0; + + /* Check memory sizes */ + line_length = get_line_length(var->xres_virtual, var->bits_per_pixel); + if (line_length * var->yres_virtual > videomemorysize) + return -ENOMEM; + par->disp_start = videomemory + (get_line_length(par->vxres, par->bpp) * + par->yoffset) * get_line_length(par->xoffset, par->bpp); + par->next_line = line_length; + + return 0; +} + +static int pvr2_encode_var(struct fb_var_screeninfo *var, + struct pvr2fb_par *par) +{ + memset(var, 0, sizeof(struct fb_var_screeninfo)); + + var->xres = par->xres; + var->yres = par->yres; + var->xres_virtual = par->vxres; + var->yres_virtual = par->vyres; + var->xoffset = par->xoffset; + var->yoffset = par->yoffset; + + var->bits_per_pixel = par->bpp; + set_color_bitfields(var); + + var->activate = FB_ACTIVATE_NOW; + var->height = -1; + var->width = -1; + + var->pixclock = par->pixclock; + + if (par->is_doublescan) + var->vmode = FB_VMODE_DOUBLE; + + if (par->is_interlaced) + var->vmode |= FB_VMODE_INTERLACED; + else + var->vmode |= FB_VMODE_NONINTERLACED; + + var->right_margin = par->borderstop_h - (par->diwstart_h + par->xres); + var->left_margin = par->diwstart_h - par->borderstart_h; + var->hsync_len = par->borderstart_h + (par->hsync_total - par->borderstop_h); + var->upper_margin = par->diwstart_v - par->borderstart_v; + var->lower_margin = par->borderstop_v - (par->diwstart_v + par->yres); + var->vsync_len = par->borderstart_v + (par->vsync_total - par->borderstop_v); + if (video_output != VO_VGA) + var->sync = FB_SYNC_BROADCAST; + + if (par->vmode & FB_VMODE_YWRAP) + var->vmode |= FB_VMODE_YWRAP; + + return 0; +} + +static void pvr2_get_par(struct pvr2fb_par *par) +{ + *par = currentpar; +} + +/* Setup the new videomode in hardware */ + +static void pvr2_set_var(struct fb_var_screeninfo *var) +{ + do_vmode_pan = 0; + do_vmode_full = 0; + pvr2_decode_var(var, ¤tpar); + + do_vmode_full = 1; +} + +/* + * Pan or wrap the display + * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag in `var'. + */ +static void pvr2_pan_var(struct fb_var_screeninfo *var) +{ + struct pvr2fb_par *par = ¤tpar; + + par->xoffset = var->xoffset; + par->yoffset = var->yoffset; + if (var->vmode & FB_VMODE_YWRAP) + par->vmode |= FB_VMODE_YWRAP; + else + par->vmode &= ~FB_VMODE_YWRAP; + + do_vmode_pan = 0; + pvr2_update_par(); + do_vmode_pan = 1; +} + +static int pvr2_update_par(void) +{ + struct pvr2fb_par *par = ¤tpar; + u_long move; + + move = get_line_length(par->xoffset, par->bpp); + if (par->yoffset) { + par->disp_start += (par->next_line * par->yoffset) + move; + } else + par->disp_start += move; + + return 0; +} + +static void pvr2_update_display(void) +{ + struct pvr2fb_par *par = ¤tpar; + + /* Update the start address of the display image */ + ctrl_outl(par->disp_start, DISP_DIWADDRL); + ctrl_outl(par->disp_start + + get_line_length(par->xoffset + par->xres, par->bpp), + DISP_DIWADDRS); +} + +/* + * Initialize the video mode. Currently, the 16bpp and 24bpp modes aren't + * very stable. It's probably due to the fact that a lot of the 2D video + * registers are still undocumented. + */ + +static void pvr2_init_display(void) +{ + struct pvr2fb_par *par = ¤tpar; + u_short diw_height, diw_width, diw_modulo = 1; + u_short bytesperpixel = par->bpp / 8; + + /* hsync and vsync totals */ + ctrl_outl((par->vsync_total << 16) | par->hsync_total, DISP_SYNCSIZE); + + /* column height, modulo, row width */ + /* since we're "panning" within vram, we need to offset things based + * on the offset from the virtual x start to our real gfx. */ + if (video_output != VO_VGA && par->is_interlaced) + diw_modulo += par->next_line / 4; + diw_height = (par->is_interlaced ? par->yres / 2 : par->yres); + diw_width = get_line_length(par->xres, par->bpp) / 4; + ctrl_outl((diw_modulo << 20) | (--diw_height << 10) | --diw_width, + DISP_DIWSIZE); + + /* display address, long and short fields */ + ctrl_outl(par->disp_start, DISP_DIWADDRL); + ctrl_outl(par->disp_start + + get_line_length(par->xoffset + par->xres, par->bpp), + DISP_DIWADDRS); + + /* border horizontal, border vertical, border color */ + ctrl_outl((par->borderstart_h << 16) | par->borderstop_h, DISP_BRDRHORZ); + ctrl_outl((par->borderstart_v << 16) | par->borderstop_v, DISP_BRDRVERT); + ctrl_outl(0, DISP_BRDRCOLR); + + /* display window start position */ + ctrl_outl(par->diwstart_h, DISP_DIWHSTRT); + ctrl_outl((par->diwstart_v << 16) | par->diwstart_v, DISP_DIWVSTRT); + + /* misc. settings */ + ctrl_outl((0x16 << 16) | par->is_lowres, DISP_DIWCONF); + + /* clock doubler (for VGA), scan doubler, display enable */ + ctrl_outl(((video_output == VO_VGA) << 23) | + (par->is_doublescan << 1) | 1, DISP_DIWMODE); + + /* bits per pixel */ + ctrl_outl(ctrl_inl(DISP_DIWMODE) | (--bytesperpixel << 2), DISP_DIWMODE); + + /* video enable, color sync, interlace, + * hsync and vsync polarity (currently unused) */ + ctrl_outl(0x100 | ((par->is_interlaced /*|4*/) << 4), DISP_SYNCCONF); + +} + +/* Simulate blanking by making the border cover the entire screen */ + +#define BLANK_BIT (1<<3) + +static void pvr2_do_blank(void) +{ + u_long diwconf; + + diwconf = ctrl_inl(DISP_DIWCONF); + if (do_blank > 0) + ctrl_outl(diwconf | BLANK_BIT, DISP_DIWCONF); + else + ctrl_outl(diwconf & ~BLANK_BIT, DISP_DIWCONF); + + is_blanked = do_blank > 0 ? do_blank : 0; +} + +static void pvr2fb_interrupt(int irq, void *dev_id, struct pt_regs *fp) +{ + if (do_vmode_pan || do_vmode_full) + pvr2_update_display(); + + if (do_vmode_full) + pvr2_init_display(); + + if (do_vmode_pan) + do_vmode_pan = 0; + + if (do_blank) { + pvr2_do_blank(); + do_blank = 0; + } + + if (do_vmode_full) { + do_vmode_full = 0; + } +} + +/* + * Determine the cable type and initialize the cable output format. Don't do + * anything if the cable type has been overidden (via "cable:XX"). + */ + +#define PCTRA 0xff80002c +#define PDTRA 0xff800030 +#define VOUTC 0xa0702c00 + +static int pvr2_init_cable(void) +{ + if (cable_type < 0) { + ctrl_outl((ctrl_inl(PCTRA) & 0xfff0ffff) | 0x000a0000, + PCTRA); + cable_type = (ctrl_inw(PDTRA) >> 8) & 3; + } + + /* Now select the output format (either composite or other) */ + /* XXX: Save the previous val first, as this reg is also AICA + related */ + if (cable_type == CT_COMPOSITE) + ctrl_outl(3 << 8, VOUTC); + else + ctrl_outl(0, VOUTC); + + return cable_type; +} + +int __init pvr2fb_init(void) +{ + struct fb_var_screeninfo var; + u_long modememused; + + if (!MACH_DREAMCAST) + return -ENXIO; + + /* Make a guess at the monitor based on the attached cable */ + if (pvr2_init_cable() == CT_VGA) { + fb_info.monspecs.hfmin = 30000; + fb_info.monspecs.hfmax = 70000; + fb_info.monspecs.vfmin = 60; + fb_info.monspecs.vfmax = 60; + } + else { /* Not VGA, using a TV (taken from acornfb) */ + fb_info.monspecs.hfmin = 15469; + fb_info.monspecs.hfmax = 15781; + fb_info.monspecs.vfmin = 49; + fb_info.monspecs.vfmax = 51; + } + + /* XXX: This needs to pull default video output via BIOS or other means */ + if (video_output < 0) { + if (cable_type == CT_VGA) + video_output = VO_VGA; + else + video_output = VO_NTSC; + } + + strcpy(fb_info.modename, pvr2fb_name); + fb_info.changevar = NULL; + fb_info.node = -1; + fb_info.fbops = &pvr2fb_ops; + fb_info.disp = &disp; + fb_info.switch_con = &pvr2fbcon_switch; + fb_info.updatevar = &pvr2fbcon_updatevar; + fb_info.blank = &pvr2fbcon_blank; + fb_info.flags = FBINFO_FLAG_DEFAULT; + memset(&var, 0, sizeof(var)); + + if (video_output == VO_VGA) + defmode = DEFMODE_VGA; + + if (!fb_find_mode(&var, &fb_info, mode_option, pvr2_modedb, + NUM_TOTAL_MODES, &pvr2_modedb[defmode], 16)) { + return -EINVAL; + } + + if (request_irq(HW_EVENT_VSYNC, pvr2fb_interrupt, 0, + "pvr2 VBL handler", ¤tpar)) { + DPRINTK("couldn't register VBL int\n"); + return -EBUSY; + } + +#ifdef CONFIG_MTRR + if (enable_mtrr) { + mtrr_handle = mtrr_add(videomemory, videomemorysize, MTRR_TYPE_WRCOMB, 1); + printk("pvr2fb: MTRR turned on\n"); + } +#endif + + pvr2fb_set_var(&var, -1, &fb_info); + + if (register_framebuffer(&fb_info) < 0) + return -EINVAL; + + modememused = get_line_length(var.xres_virtual, var.bits_per_pixel); + modememused *= var.yres_virtual; + printk("fb%d: %s frame buffer device, using %ldk/%ldk of video memory\n", + GET_FB_IDX(fb_info.node), fb_info.modename, modememused>>10, + videomemorysize>>10); + printk("fb%d: Mode %dx%d-%d pitch = %ld cable: %s video output: %s\n", + GET_FB_IDX(fb_info.node), var.xres, var.yres, var.bits_per_pixel, + get_line_length(var.xres, var.bits_per_pixel), + (char *)pvr2_get_param(cables, NULL, cable_type, 6), + (char *)pvr2_get_param(outputs, NULL, video_output, 6)); + + return 0; +} + +static void __exit pvr2fb_exit(void) +{ +#ifdef CONFIG_MTRR + if (enable_mtrr) { + mtrr_del(mtrr_handle, videomemory, videomemorysize); + printk("pvr2fb: MTRR turned off\n"); + } +#endif + unregister_framebuffer(&fb_info); +} + +static int __init pvr2_get_param(const struct pvr2_params *p, const char *s, + int val, int size) +{ + int i; + + for (i = 0 ; i < size ; i++ ) { + if (s != NULL) { + if (!strnicmp(p[i].name, s, strlen(s))) + return p[i].val; + } else { + if (p[i].val == val) + return (int)p[i].name; + } + } + return -1; +} + +/* + * Parse command arguments. Supported arguments are: + * inverse Use inverse color maps + * nomtrr Disable MTRR usage + * font:<fontname> Specify console font + * cable:composite|rgb|vga Override the video cable type + * output:NTSC|PAL|VGA Override the video output format + * + * <xres>x<yres>[-<bpp>][@<refresh>] or, + * <name>[-<bpp>][@<refresh>] Startup using this video mode + */ + +#ifndef MODULE +int __init pvr2fb_setup(char *options) +{ + char *this_opt; + char cable_arg[80]; + char output_arg[80]; + + fb_info.fontname[0] = '\0'; + + if (!options || !*options) + return 0; + + while ((this_opt = strsep(&options, ","))) { + if (!*this_opt) + continue; + if (!strcmp(this_opt, "inverse")) { + pvr2fb_inverse = 1; + fb_invert_cmaps(); + } else if (!strncmp(this_opt, "font:", 5)) + strcpy(fb_info.fontname, this_opt + 5); + else if (!strncmp(this_opt, "cable:", 6)) + strcpy(cable_arg, this_opt + 6); + else if (!strncmp(this_opt, "output:", 7)) + strcpy(output_arg, this_opt + 7); +#ifdef CONFIG_MTRR + else if (!strncmp(this_opt, "nomtrr", 6)) + enable_mtrr = 0; +#endif + else + mode_option = this_opt; + } + + if (*cable_arg) + cable_type = pvr2_get_param(cables, cable_arg, 0, 6); + + if (*output_arg) + video_output = pvr2_get_param(outputs, output_arg, 0, 6); + + return 0; +} +#endif + +#ifdef MODULE +module_init(pvr2fb_init); +#endif +module_exit(pvr2fb_exit); + diff -u --recursive --new-file v2.4.6/linux/drivers/video/riva/fbdev.c linux/drivers/video/riva/fbdev.c --- v2.4.6/linux/drivers/video/riva/fbdev.c Tue Feb 13 13:15:05 2001 +++ linux/drivers/video/riva/fbdev.c Wed Jul 18 16:36:37 2001 @@ -191,6 +191,8 @@ PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE2_GTS }, { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE2_GTS2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE2_GTS }, + { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE2_ULTRA, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE2_ULTRA }, { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO2_PRO, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_QUADRO2_PRO }, { 0, } /* terminate list */ diff -u --recursive --new-file v2.4.6/linux/drivers/video/tdfxfb.c linux/drivers/video/tdfxfb.c --- v2.4.6/linux/drivers/video/tdfxfb.c Wed Apr 18 11:49:12 2001 +++ linux/drivers/video/tdfxfb.c Wed Jul 4 11:50:39 2001 @@ -1207,7 +1207,7 @@ revc: tdfx_cfbX_revc, cursor: tdfx_cfbX_cursor, clear_margins: tdfx_cfbX_clear_margins, - fontwidthmask: FONTWIDTH(8) + fontwidthmask: FONTWIDTHRANGE(8, 12) }; #endif #ifdef FBCON_HAS_CFB16 @@ -1220,7 +1220,7 @@ revc: tdfx_cfbX_revc, cursor: tdfx_cfbX_cursor, clear_margins: tdfx_cfbX_clear_margins, - fontwidthmask: FONTWIDTH(8) + fontwidthmask: FONTWIDTHRANGE(8, 12) }; #endif #ifdef FBCON_HAS_CFB24 @@ -1233,7 +1233,7 @@ revc: tdfx_cfbX_revc, cursor: tdfx_cfbX_cursor, clear_margins: tdfx_cfbX_clear_margins, - fontwidthmask: FONTWIDTH(8) + fontwidthmask: FONTWIDTHRANGE(8, 12) }; #endif #ifdef FBCON_HAS_CFB32 @@ -1246,7 +1246,7 @@ revc: tdfx_cfbX_revc, cursor: tdfx_cfbX_cursor, clear_margins: tdfx_cfbX_clear_margins, - fontwidthmask: FONTWIDTH(8) + fontwidthmask: FONTWIDTHRANGE(8, 12) }; #endif @@ -1892,7 +1892,7 @@ ((pdev->device == PCI_DEVICE_ID_3DFX_BANSHEE) || (pdev->device == PCI_DEVICE_ID_3DFX_VOODOO3) || (pdev->device == PCI_DEVICE_ID_3DFX_VOODOO5))) { - char *name; + char *name = NULL; fb_info.dev = pdev->device; switch (pdev->device) { @@ -2314,7 +2314,12 @@ unsigned int h,to; tdfxfb_createcursorshape(p); - xline = (1 << fb_info.cursor.w)-1; + xline = ~((1 << (32 - fb_info.cursor.w)) - 1); + +#ifdef __LITTLE_ENDIAN + xline = swab32(xline); +#endif + cursorbase=(u8*)fb_info.bufbase_virt; h=fb_info.cursor.cursorimage; diff -u --recursive --new-file v2.4.6/linux/drivers/video/tgafb.c linux/drivers/video/tgafb.c --- v2.4.6/linux/drivers/video/tgafb.c Fri Feb 9 11:30:23 2001 +++ linux/drivers/video/tgafb.c Wed Jul 4 14:41:33 2001 @@ -60,7 +60,7 @@ static int current_par_valid = 0; static struct display disp; -static char default_fontname[40] = { 0 }; +static char default_fontname[40] __initdata = { 0 }; static struct fb_var_screeninfo default_var; static int default_var_valid = 0; @@ -281,9 +281,9 @@ static void tgafb_set_disp(const void *fb_par, struct display *disp, struct fb_info_gen *info); +#ifndef MODULE int tgafb_setup(char*); -int tgafb_init(void); -void tgafb_cleanup(struct fb_info *info); +#endif static void tgafb_set_pll(int f); #if 1 @@ -879,6 +879,7 @@ }; +#ifndef MODULE /* * Setup */ @@ -910,6 +911,7 @@ } return 0; } +#endif /* @@ -990,9 +992,9 @@ * Cleanup */ -void tgafb_cleanup(struct fb_info *info) +void __exit tgafb_cleanup(void) { - unregister_framebuffer(info); + unregister_framebuffer(&fb_info.gen.info); } @@ -1001,14 +1003,7 @@ */ #ifdef MODULE -int init_module(void) -{ - return tgafb_init(); -} - -void cleanup_module(void) -{ - tgafb_cleanup(void); -} -#endif /* MODULE */ +module_init(tgafb_init); +#endif +module_exit(tgafb_cleanup); diff -u --recursive --new-file v2.4.6/linux/fs/affs/Changes linux/fs/affs/Changes --- v2.4.6/linux/fs/affs/Changes Thu Apr 19 22:57:06 2001 +++ linux/fs/affs/Changes Sun Jul 15 16:34:14 2001 @@ -28,6 +28,18 @@ Please direct bug reports to: zippel@linux-m68k.org +Version 3.16 +------------ + +- use mark_buffer_dirty_inode instead of mark_buffer_dirty. +- introduce affs_lock_{link|dir|ext}. + +Version 3.15 +------------ + +- disable link to directories until we can properly support them. +- locking fixes for link creation/removal. + Version 3.14 ------------ diff -u --recursive --new-file v2.4.6/linux/fs/affs/amigaffs.c linux/fs/affs/amigaffs.c --- v2.4.6/linux/fs/affs/amigaffs.c Thu Apr 26 22:17:26 2001 +++ linux/fs/affs/amigaffs.c Thu Jul 19 17:47:14 2001 @@ -57,6 +57,7 @@ } AFFS_TAIL(sb, bh)->parent = cpu_to_be32(dir->i_ino); AFFS_TAIL(sb, bh)->hash_chain = 0; + affs_fix_checksum(sb, bh); if (dir->i_ino == dir_bh->b_blocknr) AFFS_HEAD(dir_bh)->table[offset] = cpu_to_be32(ino); @@ -64,7 +65,7 @@ AFFS_TAIL(sb, dir_bh)->hash_chain = cpu_to_be32(ino); affs_adjust_checksum(dir_bh, ino); - mark_buffer_dirty(dir_bh); + mark_buffer_dirty_inode(dir_bh, dir); affs_brelse(dir_bh); dir->i_mtime = dir->i_ctime = CURRENT_TIME; @@ -105,7 +106,8 @@ else AFFS_TAIL(sb, bh)->hash_chain = ino; affs_adjust_checksum(bh, be32_to_cpu(ino) - hash_ino); - mark_buffer_dirty(bh); + mark_buffer_dirty_inode(bh, dir); + AFFS_TAIL(sb, rem_bh)->parent = 0; retval = 0; break; } @@ -159,7 +161,6 @@ int retval; pr_debug("AFFS: remove_link(key=%ld)\n", inode->i_ino); - down(&AFFS_INODE->i_link_lock); retval = -EIO; bh = affs_bread(sb, inode->i_ino); if (!bh) @@ -179,18 +180,20 @@ if (!dir) goto done; - down(&AFFS_DIR->i_hash_lock); + affs_lock_dir(dir); affs_fix_dcache(dentry, link_ino); retval = affs_remove_hash(dir, link_bh); if (retval) goto done; + mark_buffer_dirty_inode(link_bh, inode); memcpy(AFFS_TAIL(sb, bh)->name, AFFS_TAIL(sb, link_bh)->name, 32); retval = affs_insert_hash(dir, bh); if (retval) goto done; + mark_buffer_dirty_inode(bh, inode); - up(&AFFS_DIR->i_hash_lock); + affs_unlock_dir(dir); iput(dir); } else { link_bh = affs_bread(sb, link_ino); @@ -203,7 +206,7 @@ ino = AFFS_TAIL(sb, link_bh)->link_chain; AFFS_TAIL(sb, bh)->link_chain = ino; affs_adjust_checksum(bh, be32_to_cpu(ino) - link_ino); - mark_buffer_dirty(bh); + mark_buffer_dirty_inode(bh, inode); retval = 0; /* Fix the link count, if bh is a normal header block without links */ switch (be32_to_cpu(AFFS_TAIL(sb, bh)->stype)) { @@ -226,7 +229,6 @@ done: affs_brelse(link_bh); affs_brelse(bh); - up(&AFFS_INODE->i_link_lock); return retval; } @@ -281,28 +283,41 @@ goto done; pr_debug("AFFS: remove_header(key=%ld)\n", inode->i_ino); - down(&AFFS_DIR->i_hash_lock); - if (S_ISDIR(inode->i_mode)) { + retval = -EIO; + bh = affs_bread(sb, (u32)(long)dentry->d_fsdata); + if (!bh) + goto done; + + affs_lock_link(inode); + affs_lock_dir(dir); + switch (be32_to_cpu(AFFS_TAIL(sb, bh)->stype)) { + case ST_USERDIR: + /* if we ever want to support links to dirs + * i_hash_lock of the inode must only be + * taken after some checks + */ + affs_lock_dir(inode); retval = affs_empty_dir(inode); + affs_unlock_dir(inode); if (retval) goto done_unlock; + break; + default: + break; } - retval = -EIO; - bh = affs_bread(sb, inode->i_ino); - if (!bh) - goto done; - retval = affs_remove_hash(dir, bh); if (retval) goto done_unlock; + mark_buffer_dirty_inode(bh, inode); - up(&AFFS_DIR->i_hash_lock); + affs_lock_dir(dir); if (inode->i_nlink > 1) retval = affs_remove_link(dentry); else inode->i_nlink = 0; + affs_unlock_link(inode); inode->i_ctime = CURRENT_TIME; mark_inode_dirty(inode); @@ -311,7 +326,8 @@ return retval; done_unlock: - up(&AFFS_DIR->i_hash_lock); + affs_unlock_dir(dir); + affs_unlock_link(inode); goto done; } diff -u --recursive --new-file v2.4.6/linux/fs/affs/dir.c linux/fs/affs/dir.c --- v2.4.6/linux/fs/affs/dir.c Thu Apr 26 22:17:26 2001 +++ linux/fs/affs/dir.c Sun Jul 15 16:34:14 2001 @@ -85,7 +85,7 @@ stored++; } - down(&AFFS_INODE->i_hash_lock); + affs_lock_dir(inode); chain_pos = (f_pos - 2) & 0xffff; hash_pos = (f_pos - 2) >> 16; if (chain_pos == 0xffff) { @@ -157,7 +157,7 @@ readdir_out: affs_brelse(dir_bh); affs_brelse(fh_bh); - up(&AFFS_INODE->i_hash_lock); + affs_unlock_dir(inode); pr_debug("AFFS: readdir()=%d\n", stored); return res; } diff -u --recursive --new-file v2.4.6/linux/fs/affs/file.c linux/fs/affs/file.c --- v2.4.6/linux/fs/affs/file.c Tue Jul 3 17:08:21 2001 +++ linux/fs/affs/file.c Sun Jul 15 16:34:14 2001 @@ -174,14 +174,14 @@ AFFS_TAIL(sb, new_bh)->parent = cpu_to_be32(inode->i_ino); affs_fix_checksum(sb, new_bh); - mark_buffer_dirty(new_bh); + mark_buffer_dirty_inode(new_bh, inode); tmp = be32_to_cpu(AFFS_TAIL(sb, bh)->extension); if (tmp) affs_warning(sb, "alloc_ext", "previous extension set (%x)", tmp); AFFS_TAIL(sb, bh)->extension = cpu_to_be32(blocknr); affs_adjust_checksum(bh, blocknr - tmp); - mark_buffer_dirty(bh); + mark_buffer_dirty_inode(bh, inode); AFFS_INODE->i_extcnt++; mark_inode_dirty(inode); @@ -349,7 +349,7 @@ create = 0; //lock cache - down(&AFFS_INODE->i_ext_lock); + affs_lock_ext(inode); ext = block / AFFS_SB->s_hashsize; block -= ext * AFFS_SB->s_hashsize; @@ -388,7 +388,7 @@ affs_brelse(ext_bh); //unlock cache - up(&AFFS_INODE->i_ext_lock); + affs_unlock_ext(inode); return 0; err_small: @@ -399,13 +399,13 @@ return -EIO; err_ext: // unlock cache - up(&AFFS_INODE->i_ext_lock); + affs_unlock_ext(inode); return PTR_ERR(ext_bh); err_alloc: brelse(ext_bh); bh_result->b_state &= ~(1UL << BH_Mapped); // unlock cache - up(&AFFS_INODE->i_ext_lock); + affs_unlock_ext(inode); return -ENOSPC; } @@ -561,7 +561,7 @@ memset(AFFS_DATA(bh) + boff, 0, tmp); AFFS_DATA_HEAD(bh)->size = cpu_to_be32(be32_to_cpu(AFFS_DATA_HEAD(bh)->size) + tmp); affs_fix_checksum(sb, bh); - mark_buffer_dirty(bh); + mark_buffer_dirty_inode(bh, inode); size += tmp; bidx++; } else if (bidx) { @@ -581,14 +581,14 @@ AFFS_DATA_HEAD(bh)->sequence = cpu_to_be32(bidx); AFFS_DATA_HEAD(bh)->size = cpu_to_be32(tmp); affs_fix_checksum(sb, bh); - mark_buffer_dirty(bh); + mark_buffer_dirty_inode(bh, inode); if (prev_bh) { u32 tmp = be32_to_cpu(AFFS_DATA_HEAD(prev_bh)->next); if (tmp) affs_warning(sb, "prepare_write_ofs", "next block already set for %d (%d)", bidx, tmp); AFFS_DATA_HEAD(prev_bh)->next = cpu_to_be32(bh->b_blocknr); affs_adjust_checksum(prev_bh, bidx - tmp); - mark_buffer_dirty(prev_bh); + mark_buffer_dirty_inode(prev_bh, inode); affs_brelse(prev_bh); } size += bsize; @@ -688,7 +688,7 @@ memcpy(AFFS_DATA(bh) + boff, data + from, tmp); AFFS_DATA_HEAD(bh)->size = cpu_to_be32(be32_to_cpu(AFFS_DATA_HEAD(bh)->size) + tmp); affs_fix_checksum(sb, bh); - mark_buffer_dirty(bh); + mark_buffer_dirty_inode(bh, inode); written += tmp; from += tmp; bidx++; @@ -715,12 +715,12 @@ affs_warning(sb, "prepare_write_ofs", "next block already set for %d (%d)", bidx, tmp); AFFS_DATA_HEAD(prev_bh)->next = cpu_to_be32(bh->b_blocknr); affs_adjust_checksum(prev_bh, bidx - tmp); - mark_buffer_dirty(prev_bh); + mark_buffer_dirty_inode(prev_bh, inode); } } affs_brelse(prev_bh); affs_fix_checksum(sb, bh); - mark_buffer_dirty(bh); + mark_buffer_dirty_inode(bh, inode); written += bsize; from += bsize; bidx++; @@ -744,13 +744,13 @@ affs_warning(sb, "prepare_write_ofs", "next block already set for %d (%d)", bidx, tmp); AFFS_DATA_HEAD(prev_bh)->next = cpu_to_be32(bh->b_blocknr); affs_adjust_checksum(prev_bh, bidx - tmp); - mark_buffer_dirty(prev_bh); + mark_buffer_dirty_inode(prev_bh, inode); } } else if (be32_to_cpu(AFFS_DATA_HEAD(bh)->size) < tmp) AFFS_DATA_HEAD(bh)->size = cpu_to_be32(tmp); affs_brelse(prev_bh); affs_fix_checksum(sb, bh); - mark_buffer_dirty(bh); + mark_buffer_dirty_inode(bh, inode); written += tmp; from += tmp; bidx++; @@ -866,7 +866,7 @@ } AFFS_TAIL(sb, ext_bh)->extension = 0; affs_fix_checksum(sb, ext_bh); - mark_buffer_dirty(ext_bh); + mark_buffer_dirty_inode(ext_bh, inode); affs_brelse(ext_bh); if (inode->i_size) { diff -u --recursive --new-file v2.4.6/linux/fs/affs/inode.c linux/fs/affs/inode.c --- v2.4.6/linux/fs/affs/inode.c Wed Apr 25 14:35:25 2001 +++ linux/fs/affs/inode.c Sun Jul 15 16:34:15 2001 @@ -120,8 +120,15 @@ inode->i_fop = &affs_dir_operations; break; case ST_LINKDIR: +#if 0 affs_warning(sb, "read_inode", "inode is LINKDIR"); goto bad_inode; +#else + inode->i_mode |= S_IFDIR; + inode->i_op = NULL; + inode->i_fop = NULL; + break; +#endif case ST_LINKFILE: affs_warning(sb, "read_inode", "inode is LINKFILE"); goto bad_inode; @@ -207,7 +214,7 @@ } } affs_fix_checksum(sb, bh); - mark_buffer_dirty(bh); + mark_buffer_dirty_inode(bh, inode); affs_brelse(bh); unlock_kernel(); } @@ -302,7 +309,7 @@ bh = affs_getzeroblk(sb, block); if (!bh) goto err_bh; - mark_buffer_dirty(bh); + mark_buffer_dirty_inode(bh, inode); affs_brelse(bh); inode->i_sb = sb; @@ -352,6 +359,7 @@ if (!bh) goto done; + affs_lock_link(inode); switch (type) { case ST_LINKFILE: case ST_LINKDIR: @@ -377,25 +385,25 @@ if (inode_bh) { u32 chain; - down(&AFFS_INODE->i_link_lock); chain = AFFS_TAIL(sb, inode_bh)->link_chain; AFFS_TAIL(sb, bh)->original = cpu_to_be32(inode->i_ino); AFFS_TAIL(sb, bh)->link_chain = chain; AFFS_TAIL(sb, inode_bh)->link_chain = cpu_to_be32(block); affs_adjust_checksum(inode_bh, block - be32_to_cpu(chain)); - mark_buffer_dirty(inode_bh); + mark_buffer_dirty_inode(inode_bh, inode); inode->i_nlink = 2; atomic_inc(&inode->i_count); - up(&AFFS_INODE->i_link_lock); } affs_fix_checksum(sb, bh); - mark_buffer_dirty(bh); + mark_buffer_dirty_inode(bh, inode); + dentry->d_fsdata = (void *)bh->b_blocknr; - down(&AFFS_DIR->i_hash_lock); + affs_lock_dir(dir); retval = affs_insert_hash(dir, bh); - up(&AFFS_DIR->i_hash_lock); + mark_buffer_dirty_inode(bh, inode); + affs_unlock_dir(dir); + affs_unlock_link(inode); - dentry->d_fsdata = (void *)bh->b_blocknr; d_instantiate(dentry, inode); done: affs_brelse(inode_bh); @@ -404,5 +412,6 @@ err: if (block) affs_free_block(sb, block); + affs_unlock_link(inode); goto done; } diff -u --recursive --new-file v2.4.6/linux/fs/affs/namei.c linux/fs/affs/namei.c --- v2.4.6/linux/fs/affs/namei.c Wed Apr 25 14:57:29 2001 +++ linux/fs/affs/namei.c Sun Jul 15 16:34:15 2001 @@ -217,9 +217,9 @@ pr_debug("AFFS: lookup(\"%.*s\")\n",(int)dentry->d_name.len,dentry->d_name.name); - down(&AFFS_DIR->i_hash_lock); + affs_lock_dir(dir); bh = affs_find_entry(dir, dentry); - up(&AFFS_DIR->i_hash_lock); + affs_unlock_dir(dir); if (IS_ERR(bh)) return ERR_PTR(PTR_ERR(bh)); if (bh) { @@ -228,7 +228,8 @@ /* store the real header ino in d_fsdata for faster lookups */ dentry->d_fsdata = (void *)(long)ino; switch (be32_to_cpu(AFFS_TAIL(sb, bh)->stype)) { - case ST_LINKDIR: + //link to dirs disabled + //case ST_LINKDIR: case ST_LINKFILE: ino = be32_to_cpu(AFFS_TAIL(sb, bh)->original); } @@ -381,7 +382,7 @@ symname++; } *p = 0; - mark_buffer_dirty(bh); + mark_buffer_dirty_inode(bh, inode); affs_brelse(bh); mark_inode_dirty(inode); @@ -407,6 +408,9 @@ pr_debug("AFFS: link(%u, %u, \"%.*s\")\n", (u32)inode->i_ino, (u32)dir->i_ino, (int)dentry->d_name.len,dentry->d_name.name); + if (S_ISDIR(inode->i_mode)) + return -EPERM; + error = affs_add_entry(dir, inode, dentry, S_ISDIR(inode->i_mode) ? ST_LINKDIR : ST_LINKFILE); if (error) { inode->i_nlink = 0; @@ -422,7 +426,6 @@ struct inode *new_dir, struct dentry *new_dentry) { struct super_block *sb = old_dir->i_sb; - struct inode *dir; struct buffer_head *bh = NULL; int retval; @@ -445,30 +448,28 @@ if (!bh) goto done; + affs_lock_dir(old_dir); + if (old_dir != new_dir) + affs_lock_dir(new_dir); + /* Remove header from its parent directory. */ - dir = old_dir; - down(&AFFS_DIR->i_hash_lock); - retval = affs_remove_hash(dir, bh); + retval = affs_remove_hash(old_dir, bh); if (retval) goto done_unlock; - up(&AFFS_DIR->i_hash_lock); - /* And insert it into the new directory with the new name. */ - dir = new_dir; affs_copy_name(AFFS_TAIL(sb, bh)->name, new_dentry); affs_fix_checksum(sb, bh); - down(&AFFS_DIR->i_hash_lock); retval = affs_insert_hash(new_dir, bh); - if (retval) - goto done_unlock; - up(&AFFS_DIR->i_hash_lock); + /* TODO: move it back to old_dir? */ + +done_unlock: + affs_unlock_dir(old_dir); + if (old_dir != new_dir) + affs_unlock_dir(new_dir); done: + mark_buffer_dirty_inode(bh, retval ? old_dir : new_dir); affs_brelse(bh); return retval; - -done_unlock: - up(&AFFS_DIR->i_hash_lock); - goto done; } diff -u --recursive --new-file v2.4.6/linux/fs/binfmt_aout.c linux/fs/binfmt_aout.c --- v2.4.6/linux/fs/binfmt_aout.c Mon Mar 19 12:34:56 2001 +++ linux/fs/binfmt_aout.c Thu Jul 19 20:33:38 2001 @@ -73,7 +73,7 @@ * Currently only a stub-function. * * Note that setuid/setgid files won't make a core-dump if the uid/gid - * changed due to the set[u|g]id. It's enforced by the "current->dumpable" + * changed due to the set[u|g]id. It's enforced by the "current->mm->dumpable" * field, which also makes sure the core-dumps won't be recursive if the * dumping of the process results in another error.. */ diff -u --recursive --new-file v2.4.6/linux/fs/binfmt_elf.c linux/fs/binfmt_elf.c --- v2.4.6/linux/fs/binfmt_elf.c Tue Jul 3 17:08:21 2001 +++ linux/fs/binfmt_elf.c Mon Jul 16 14:37:16 2001 @@ -888,11 +888,15 @@ */ static inline int maydump(struct vm_area_struct *vma) { - if (!(vma->vm_flags & (VM_READ|VM_WRITE|VM_EXEC))) + /* + * If we may not read the contents, don't allow us to dump + * them either. "dump_write()" can't handle it anyway. + */ + if (!(vma->vm_flags & VM_READ)) return 0; /* Do not dump I/O mapped devices! -DaveM */ - if(vma->vm_flags & VM_IO) + if (vma->vm_flags & VM_IO) return 0; #if 1 if (vma->vm_flags & (VM_WRITE|VM_GROWSUP|VM_GROWSDOWN)) @@ -1205,13 +1209,12 @@ pte_t *pte; pgd = pgd_offset(vma->vm_mm, addr); + if (pgd_none(*pgd)) + goto nextpage_coredump; pmd = pmd_offset(pgd, addr); - - if (!pmd) + if (pmd_none(*pmd)) goto nextpage_coredump; pte = pte_offset(pmd, addr); - if (!pte) - goto nextpage_coredump; if (pte_none(*pte)) { nextpage_coredump: DUMP_SEEK (file->f_pos + PAGE_SIZE); diff -u --recursive --new-file v2.4.6/linux/fs/buffer.c linux/fs/buffer.c --- v2.4.6/linux/fs/buffer.c Tue Jul 3 17:08:21 2001 +++ linux/fs/buffer.c Wed Jul 18 07:55:05 2001 @@ -45,6 +45,7 @@ #include <linux/quotaops.h> #include <linux/iobuf.h> #include <linux/highmem.h> +#include <linux/completion.h> #include <asm/uaccess.h> #include <asm/io.h> @@ -133,6 +134,14 @@ int bdflush_min[N_PARAM] = { 0, 10, 5, 25, 0, 1*HZ, 0, 0, 0}; int bdflush_max[N_PARAM] = {100,50000, 20000, 20000,600*HZ, 6000*HZ, 100, 0, 0}; +inline void unlock_buffer(struct buffer_head *bh) +{ + clear_bit(BH_Lock, &bh->b_state); + smp_mb__after_clear_bit(); + if (waitqueue_active(&bh->b_wait)) + wake_up(&bh->b_wait); +} + /* * Rewrote the wait-routines to use the "new" wait-queue functionality, * and getting rid of the cli-sti pairs. The wait-queue routines still @@ -147,7 +156,7 @@ struct task_struct *tsk = current; DECLARE_WAITQUEUE(wait, tsk); - atomic_inc(&bh->b_count); + get_bh(bh); add_wait_queue(&bh->b_wait, &wait); do { run_task_queue(&tq_disk); @@ -158,14 +167,18 @@ } while (buffer_locked(bh)); tsk->state = TASK_RUNNING; remove_wait_queue(&bh->b_wait, &wait); - atomic_dec(&bh->b_count); + put_bh(bh); } -/* End-of-write handler.. Just mark it up-to-date and unlock the buffer. */ -static void end_buffer_write(struct buffer_head *bh, int uptodate) +/* + * Default synchronous end-of-IO handler.. Just mark it up-to-date and + * unlock the buffer. This is what ll_rw_block uses too. + */ +void end_buffer_io_sync(struct buffer_head *bh, int uptodate) { mark_buffer_uptodate(bh, uptodate); unlock_buffer(bh); + put_bh(bh); } /* @@ -179,14 +192,14 @@ static void write_locked_buffers(struct buffer_head **array, unsigned int count) { struct buffer_head *wait = *array; - atomic_inc(&wait->b_count); + get_bh(wait); do { struct buffer_head * bh = *array++; - bh->b_end_io = end_buffer_write; + bh->b_end_io = end_buffer_io_sync; submit_bh(WRITE, bh); } while (--count); wait_on_buffer(wait); - atomic_dec(&wait->b_count); + put_bh(wait); } #define NRSYNC (32) @@ -210,6 +223,7 @@ continue; if (test_and_set_bit(BH_Lock, &bh->b_state)) continue; + get_bh(bh); if (atomic_set_buffer_clean(bh)) { __refile_buffer(bh); array[count++] = bh; @@ -221,6 +235,7 @@ goto repeat; } unlock_buffer(bh); + put_bh(bh); } spin_unlock(&lru_list_lock); @@ -249,10 +264,10 @@ if (dev && bh->b_dev != dev) continue; - atomic_inc(&bh->b_count); + get_bh(bh); spin_unlock(&lru_list_lock); wait_on_buffer (bh); - atomic_dec(&bh->b_count); + put_bh(bh); goto repeat; } spin_unlock(&lru_list_lock); @@ -552,7 +567,7 @@ bh->b_dev == dev) break; if (bh) - atomic_inc(&bh->b_count); + get_bh(bh); return bh; } @@ -646,12 +661,12 @@ if (!bh->b_pprev) continue; if (buffer_locked(bh)) { - atomic_inc(&bh->b_count); + get_bh(bh); spin_unlock(&lru_list_lock); wait_on_buffer(bh); slept = 1; spin_lock(&lru_list_lock); - atomic_dec(&bh->b_count); + put_bh(bh); } write_lock(&hash_table_lock); @@ -711,12 +726,12 @@ if (!bh->b_pprev) continue; if (buffer_locked(bh)) { - atomic_inc(&bh->b_count); + get_bh(bh); spin_unlock(&lru_list_lock); wait_on_buffer(bh); slept = 1; spin_lock(&lru_list_lock); - atomic_dec(&bh->b_count); + put_bh(bh); } write_lock(&hash_table_lock); @@ -803,7 +818,6 @@ */ spin_lock_irqsave(&page_uptodate_lock, flags); unlock_buffer(bh); - atomic_dec(&bh->b_count); tmp = bh->b_this_page; while (tmp != bh) { if (tmp->b_end_io == end_buffer_io_async && buffer_locked(tmp)) @@ -813,6 +827,7 @@ /* OK, the async IO on this page is complete. */ spin_unlock_irqrestore(&page_uptodate_lock, flags); + put_bh(bh); /* * if none of the buffers had errors then we can set the @@ -832,6 +847,7 @@ return; still_busy: + put_bh(bh); spin_unlock_irqrestore(&page_uptodate_lock, flags); return; } @@ -879,7 +895,7 @@ bh->b_inode = &tmp; list_add(&bh->b_inode_buffers, &tmp.i_dirty_buffers); if (buffer_dirty(bh)) { - atomic_inc(&bh->b_count); + get_bh(bh); spin_unlock(&lru_list_lock); ll_rw_block(WRITE, 1, &bh); brelse(bh); @@ -891,7 +907,7 @@ while (!list_empty(&tmp.i_dirty_buffers)) { bh = BH_ENTRY(tmp.i_dirty_buffers.prev); remove_inode_queue(bh); - atomic_inc(&bh->b_count); + get_bh(bh); spin_unlock(&lru_list_lock); wait_on_buffer(bh); if (!buffer_uptodate(bh)) @@ -935,7 +951,7 @@ bh = BH_ENTRY(list), list != &inode->i_dirty_buffers; list = bh->b_inode_buffers.prev) { if (buffer_locked(bh)) { - atomic_inc(&bh->b_count); + get_bh(bh); spin_unlock(&lru_list_lock); wait_on_buffer(bh); if (!buffer_uptodate(bh)) @@ -1130,10 +1146,10 @@ void __brelse(struct buffer_head * buf) { if (atomic_read(&buf->b_count)) { - atomic_dec(&buf->b_count); + put_bh(buf); return; } - printk("VFS: brelse: Trying to free free buffer\n"); + printk(KERN_ERR "VFS: brelse: Trying to free free buffer\n"); } /* @@ -1528,7 +1544,7 @@ do { lock_buffer(bh); bh->b_end_io = end_buffer_io_async; - atomic_inc(&bh->b_count); + get_bh(bh); set_bit(BH_Uptodate, &bh->b_state); clear_bit(BH_Dirty, &bh->b_state); bh = bh->b_this_page; @@ -1536,8 +1552,9 @@ /* Stage 3: submit the IO */ do { + struct buffer_head *next = bh->b_this_page; submit_bh(WRITE, bh); - bh = bh->b_this_page; + bh = next; } while (bh != head); /* Done - end_buffer_io_async will unlock */ @@ -1729,7 +1746,7 @@ struct buffer_head * bh = arr[i]; lock_buffer(bh); bh->b_end_io = end_buffer_io_async; - atomic_inc(&bh->b_count); + get_bh(bh); } /* Stage 3: start the IO */ @@ -2107,7 +2124,6 @@ offset += size; atomic_inc(&iobuf->io_count); - submit_bh(rw, tmp); /* * Wait for IO if we have got too much @@ -2175,14 +2191,15 @@ bh->b_blocknr = *(b++); set_bit(BH_Mapped, &bh->b_state); bh->b_end_io = end_buffer_io_async; - atomic_inc(&bh->b_count); + get_bh(bh); bh = bh->b_this_page; } while (bh != head); /* Stage 2: start the IO */ do { + struct buffer_head *next = bh->b_this_page; submit_bh(rw, bh); - bh = bh->b_this_page; + bh = next; } while (bh != head); return 0; } @@ -2235,7 +2252,7 @@ int isize; if ((size & 511) || (size > PAGE_SIZE)) { - printk("VFS: grow_buffers: size = %d\n",size); + printk(KERN_ERR "VFS: grow_buffers: size = %d\n",size); return 0; } @@ -2554,10 +2571,10 @@ } /* OK, now we are committed to write it out. */ - atomic_inc(&bh->b_count); + get_bh(bh); spin_unlock(&lru_list_lock); ll_rw_block(WRITE, 1, &bh); - atomic_dec(&bh->b_count); + put_bh(bh); if (current->need_resched) schedule(); @@ -2665,7 +2682,7 @@ * the syscall above, but now we launch it ourselves internally with * kernel_thread(...) directly after the first thread in init/main.c */ -int bdflush(void *sem) +int bdflush(void *startup) { struct task_struct *tsk = current; int flushed; @@ -2686,7 +2703,7 @@ recalc_sigpending(tsk); spin_unlock_irq(&tsk->sigmask_lock); - up((struct semaphore *)sem); + complete((struct completion *)startup); for (;;) { CHECK_EMERGENCY_SYNC @@ -2711,7 +2728,7 @@ * You don't need to change your userspace configuration since * the userspace `update` will do_exit(0) at the first sys_bdflush(). */ -int kupdate(void *sem) +int kupdate(void *startup) { struct task_struct * tsk = current; int interval; @@ -2727,7 +2744,7 @@ recalc_sigpending(tsk); spin_unlock_irq(&tsk->sigmask_lock); - up((struct semaphore *)sem); + complete((struct completion *)startup); for (;;) { /* update interval */ @@ -2754,7 +2771,7 @@ goto stop_kupdate; } #ifdef DEBUG - printk("kupdate() activated...\n"); + printk(KERN_DEBUG "kupdate() activated...\n"); #endif sync_old_buffers(); } @@ -2762,11 +2779,12 @@ static int __init bdflush_init(void) { - DECLARE_MUTEX_LOCKED(sem); - kernel_thread(bdflush, &sem, CLONE_FS | CLONE_FILES | CLONE_SIGNAL); - down(&sem); - kernel_thread(kupdate, &sem, CLONE_FS | CLONE_FILES | CLONE_SIGNAL); - down(&sem); + static struct completion startup __initdata = COMPLETION_INITIALIZER(startup); + + kernel_thread(bdflush, &startup, CLONE_FS | CLONE_FILES | CLONE_SIGNAL); + wait_for_completion(&startup); + kernel_thread(kupdate, &startup, CLONE_FS | CLONE_FILES | CLONE_SIGNAL); + wait_for_completion(&startup); return 0; } diff -u --recursive --new-file v2.4.6/linux/fs/cramfs/README linux/fs/cramfs/README --- v2.4.6/linux/fs/cramfs/README Tue Jan 11 10:24:58 2000 +++ linux/fs/cramfs/README Thu Jul 19 16:14:53 2001 @@ -14,11 +14,11 @@ <directory_structure> <data> -<superblock>: struct cramfs_super (see cramfs.h). +<superblock>: struct cramfs_super (see cramfs_fs.h). <directory_structure>: For each file: - struct cramfs_inode (see cramfs.h). + struct cramfs_inode (see cramfs_fs.h). Filename. Not generally null-terminated, but it is null-padded to a multiple of 4 bytes. diff -u --recursive --new-file v2.4.6/linux/fs/cramfs/cramfs.h linux/fs/cramfs/cramfs.h --- v2.4.6/linux/fs/cramfs/cramfs.h Tue Jan 11 10:24:58 2000 +++ linux/fs/cramfs/cramfs.h Wed Dec 31 16:00:00 1969 @@ -1,52 +0,0 @@ -#ifndef __CRAMFS_H -#define __CRAMFS_H - -#define CRAMFS_MAGIC 0x28cd3d45 /* some random number */ -#define CRAMFS_SIGNATURE "Compressed ROMFS" - -/* - * Reasonably terse representation of the inode data. - */ -struct cramfs_inode { - u32 mode:16, uid:16; - /* SIZE for device files is i_rdev */ - u32 size:24, gid:8; - /* NAMELEN is the length of the file name, divided by 4 and - rounded up. (cramfs doesn't support hard links.) */ - /* OFFSET: For symlinks and non-empty regular files, this - contains the offset (divided by 4) of the file data in - compressed form (starting with an array of block pointers; - see README). For non-empty directories it is the offset - (divided by 4) of the inode of the first file in that - directory. For anything else, offset is zero. */ - u32 namelen:6, offset:26; -}; - -/* - * Superblock information at the beginning of the FS. - */ -struct cramfs_super { - u32 magic; /* 0x28cd3d45 - random number */ - u32 size; /* Not used. mkcramfs currently - writes a constant 1<<16 here. */ - u32 flags; /* 0 */ - u32 future; /* 0 */ - u8 signature[16]; /* "Compressed ROMFS" */ - u8 fsid[16]; /* random number */ - u8 name[16]; /* user-defined name */ - struct cramfs_inode root; /* Root inode data */ -}; - -/* - * Valid values in super.flags. Currently we refuse to mount - * if (flags & ~CRAMFS_SUPPORTED_FLAGS). Maybe that should be - * changed to test super.future instead. - */ -#define CRAMFS_SUPPORTED_FLAGS (0xff) - -/* Uncompression interfaces to the underlying zlib */ -int cramfs_uncompress_block(void *dst, int dstlen, void *src, int srclen); -int cramfs_uncompress_init(void); -int cramfs_uncompress_exit(void); - -#endif diff -u --recursive --new-file v2.4.6/linux/fs/cramfs/inode.c linux/fs/cramfs/inode.c --- v2.4.6/linux/fs/cramfs/inode.c Tue Apr 17 23:16:38 2001 +++ linux/fs/cramfs/inode.c Thu Jul 19 16:14:53 2001 @@ -17,10 +17,16 @@ #include <linux/init.h> #include <linux/string.h> #include <linux/locks.h> +#include <linux/blkdev.h> +#include <linux/cramfs_fs.h> #include <asm/uaccess.h> -#include "cramfs.h" +#define CRAMFS_SB_MAGIC u.cramfs_sb.magic +#define CRAMFS_SB_SIZE u.cramfs_sb.size +#define CRAMFS_SB_BLOCKS u.cramfs_sb.blocks +#define CRAMFS_SB_FILES u.cramfs_sb.files +#define CRAMFS_SB_FLAGS u.cramfs_sb.flags static struct super_operations cramfs_ops; static struct inode_operations cramfs_dir_inode_operations; @@ -40,6 +46,8 @@ inode->i_mode = cramfs_inode->mode; inode->i_uid = cramfs_inode->uid; inode->i_size = cramfs_inode->size; + inode->i_blocks = (cramfs_inode->size - 1) / 512 + 1; + inode->i_blksize = PAGE_CACHE_SIZE; inode->i_gid = cramfs_inode->gid; inode->i_ino = CRAMINO(cramfs_inode); /* inode->i_nlink is left 1 - arguably wrong for directories, @@ -100,7 +108,11 @@ static void *cramfs_read(struct super_block *sb, unsigned int offset, unsigned int len) { struct buffer_head * bh_array[BLKS_PER_BUF]; - unsigned i, blocknr, buffer; + struct buffer_head * read_array[BLKS_PER_BUF]; + unsigned i, blocknr, buffer, unread; + unsigned long devsize; + int major, minor; + char *data; if (!len) @@ -123,9 +135,34 @@ return read_buffers[i] + blk_offset; } + devsize = ~0UL; + major = MAJOR(sb->s_dev); + minor = MINOR(sb->s_dev); + + if (blk_size[major]) + devsize = blk_size[major][minor] >> 2; + /* Ok, read in BLKS_PER_BUF pages completely first. */ - for (i = 0; i < BLKS_PER_BUF; i++) - bh_array[i] = bread(sb->s_dev, blocknr + i, PAGE_CACHE_SIZE); + unread = 0; + for (i = 0; i < BLKS_PER_BUF; i++) { + struct buffer_head *bh; + + bh = NULL; + if (blocknr + i < devsize) { + bh = getblk(sb->s_dev, blocknr + i, PAGE_CACHE_SIZE); + if (!buffer_uptodate(bh)) + read_array[unread++] = bh; + } + bh_array[i] = bh; + } + + if (unread) { + ll_rw_block(READ, unread, read_array); + do { + unread--; + wait_on_buffer(read_array[unread]); + } while (unread); + } /* Ok, copy them to the staging area without sleeping. */ buffer = next_buffer; @@ -167,34 +204,50 @@ /* Do sanity checks on the superblock */ if (super.magic != CRAMFS_MAGIC) { - printk("wrong magic\n"); - goto out; - } - if (memcmp(super.signature, CRAMFS_SIGNATURE, sizeof(super.signature))) { - printk("wrong signature\n"); - goto out; + /* check at 512 byte offset */ + memcpy(&super, cramfs_read(sb, 512, sizeof(super)), sizeof(super)); + if (super.magic != CRAMFS_MAGIC) { + printk(KERN_ERR "cramfs: wrong magic\n"); + goto out; + } } + + /* get feature flags first */ if (super.flags & ~CRAMFS_SUPPORTED_FLAGS) { - printk("unsupported filesystem features\n"); + printk(KERN_ERR "cramfs: unsupported filesystem features\n"); goto out; } /* Check that the root inode is in a sane state */ if (!S_ISDIR(super.root.mode)) { - printk("root is not a directory\n"); + printk(KERN_ERR "cramfs: root is not a directory\n"); goto out; } root_offset = super.root.offset << 2; + if (super.flags & CRAMFS_FLAG_FSID_VERSION_2) { + sb->CRAMFS_SB_SIZE=super.size; + sb->CRAMFS_SB_BLOCKS=super.fsid.blocks; + sb->CRAMFS_SB_FILES=super.fsid.files; + } else { + sb->CRAMFS_SB_SIZE=1<<28; + sb->CRAMFS_SB_BLOCKS=0; + sb->CRAMFS_SB_FILES=0; + } + sb->CRAMFS_SB_MAGIC=super.magic; + sb->CRAMFS_SB_FLAGS=super.flags; if (root_offset == 0) - printk(KERN_INFO "cramfs: note: empty filesystem"); - else if (root_offset != sizeof(struct cramfs_super)) { - printk("bad root offset %lu\n", root_offset); + printk(KERN_INFO "cramfs: empty filesystem"); + else if (!(super.flags & CRAMFS_FLAG_SHIFTED_ROOT_OFFSET) && + ((root_offset != sizeof(struct cramfs_super)) && + (root_offset != 512 + sizeof(struct cramfs_super)))) + { + printk(KERN_ERR "cramfs: bad root offset %lu\n", root_offset); goto out; } /* Set it all up.. */ - sb->s_op = &cramfs_ops; - sb->s_root = d_alloc_root(get_cramfs_inode(sb, &super.root)); + sb->s_op = &cramfs_ops; + sb->s_root = d_alloc_root(get_cramfs_inode(sb, &super.root)); retval = sb; out: return retval; @@ -204,8 +257,10 @@ { buf->f_type = CRAMFS_MAGIC; buf->f_bsize = PAGE_CACHE_SIZE; + buf->f_blocks = sb->CRAMFS_SB_BLOCKS; buf->f_bfree = 0; buf->f_bavail = 0; + buf->f_files = sb->CRAMFS_SB_FILES; buf->f_ffree = 0; buf->f_namelen = 255; return 0; @@ -270,14 +325,20 @@ static struct dentry * cramfs_lookup(struct inode *dir, struct dentry *dentry) { unsigned int offset = 0; + int sorted = dir->i_sb->CRAMFS_SB_FLAGS & CRAMFS_FLAG_SORTED_DIRS; while (offset < dir->i_size) { struct cramfs_inode *de; char *name; - int namelen; + int namelen, retval; de = cramfs_read(dir->i_sb, OFFSET(dir) + offset, sizeof(*de)+256); name = (char *)(de+1); + + /* Try to take advantage of sorted directories */ + if (sorted && (dentry->d_name.name[0] < name[0])) + break; + namelen = de->namelen << 2; offset += sizeof(*de) + namelen; @@ -294,10 +355,16 @@ } if (namelen != dentry->d_name.len) continue; - if (memcmp(dentry->d_name.name, name, namelen)) + retval = memcmp(dentry->d_name.name, name, namelen); + if (retval > 0) continue; - d_add(dentry, get_cramfs_inode(dir->i_sb, de)); - return NULL; + if (!retval) { + d_add(dentry, get_cramfs_inode(dir->i_sb, de)); + return NULL; + } + /* else (retval < 0) */ + if (sorted) + break; } d_add(dentry, NULL); return NULL; diff -u --recursive --new-file v2.4.6/linux/fs/dcache.c linux/fs/dcache.c --- v2.4.6/linux/fs/dcache.c Tue Jul 3 17:08:21 2001 +++ linux/fs/dcache.c Thu Jul 5 10:14:23 2001 @@ -562,7 +562,7 @@ * We should make sure we don't hold the superblock lock over * block allocations, but for now: */ - if (!(gfp_mask & __GFP_IO)) + if (!(gfp_mask & __GFP_FS)) return; if (priority) diff -u --recursive --new-file v2.4.6/linux/fs/devfs/base.c linux/fs/devfs/base.c --- v2.4.6/linux/fs/devfs/base.c Tue Jul 3 17:08:21 2001 +++ linux/fs/devfs/base.c Wed Jul 11 14:55:41 2001 @@ -507,6 +507,10 @@ Replaced <devfsd_read> stack usage with <devfsd_ioctl> kmalloc. Simplified locking in <devfsd_ioctl> and fixed memory leak. v0.106 + 20010709 Richard Gooch <rgooch@atnf.csiro.au> + Removed broken devnum allocation and use <devfs_alloc_devnum>. + Fixed old devnum leak by calling new <devfs_dealloc_devnum>. + v0.107 */ #include <linux/types.h> #include <linux/errno.h> @@ -524,8 +528,6 @@ #include <linux/mm.h> #include <linux/module.h> #include <linux/init.h> -#include <linux/locks.h> -#include <linux/kdev_t.h> #include <linux/devfs_fs.h> #include <linux/devfs_fs_kernel.h> #include <linux/smp_lock.h> @@ -541,7 +543,7 @@ #include <asm/bitops.h> #include <asm/atomic.h> -#define DEVFS_VERSION "0.106 (20010617)" +#define DEVFS_VERSION "0.107 (20010709)" #define DEVFS_NAME "devfs" @@ -550,9 +552,6 @@ #define STRING_LENGTH 256 -#define MIN_DEVNUM 36864 /* Use major numbers 144 */ -#define MAX_DEVNUM 61439 /* through 239, inclusive */ - #ifndef TRUE # define TRUE 1 # define FALSE 0 @@ -626,6 +625,7 @@ unsigned char aopen_notify:1; unsigned char removable:1; /* Belongs in device_type, but save space */ unsigned char open:1; /* Not entirely correct */ + unsigned char autogen:1; /* Belongs in device_type, but save space */ }; struct symlink_type @@ -712,8 +712,6 @@ }; static struct fs_info fs_info = {devfsd_buffer_lock: SPIN_LOCK_UNLOCKED}; -static unsigned int next_devnum_char = MIN_DEVNUM; -static unsigned int next_devnum_block = MIN_DEVNUM; static const int devfsd_buf_size = PAGE_SIZE / sizeof(struct devfsd_buf_entry); #ifdef CONFIG_DEVFS_DEBUG static unsigned int devfs_debug_init __initdata = DEBUG_NONE; @@ -873,6 +871,7 @@ static struct devfs_entry *get_root_entry (void) { + kdev_t devnum; struct devfs_entry *new; /* Always ensure the root is created */ @@ -885,9 +884,9 @@ /* And create the entry for ".devfsd" */ if ( ( new = create_entry (root_entry, ".devfsd", 0) ) == NULL ) return NULL; - new->u.fcb.u.device.major = next_devnum_char >> 8; - new->u.fcb.u.device.minor = next_devnum_char & 0xff; - ++next_devnum_char; + devnum = devfs_alloc_devnum (DEVFS_SPECIAL_CHR); + new->u.fcb.u.device.major = MAJOR (devnum); + new->u.fcb.u.device.minor = MINOR (devnum); new->mode = S_IFCHR | S_IRUSR | S_IWUSR; new->u.fcb.default_uid = 0; new->u.fcb.default_gid = 0; @@ -1264,7 +1263,9 @@ unsigned int major, unsigned int minor, umode_t mode, void *ops, void *info) { + char devtype = S_ISCHR (mode) ? DEVFS_SPECIAL_CHR : DEVFS_SPECIAL_BLK; int is_new; + kdev_t devnum = NODEV; struct devfs_entry *de; if (name == NULL) @@ -1296,29 +1297,17 @@ DEVFS_NAME, name); return NULL; } - if ( S_ISCHR (mode) && (flags & DEVFS_FL_AUTO_DEVNUM) ) - { - if (next_devnum_char >= MAX_DEVNUM) - { - printk ("%s: devfs_register(%s): exhausted char device numbers\n", - DEVFS_NAME, name); - return NULL; - } - major = next_devnum_char >> 8; - minor = next_devnum_char & 0xff; - ++next_devnum_char; - } - if ( S_ISBLK (mode) && (flags & DEVFS_FL_AUTO_DEVNUM) ) + if ( ( S_ISCHR (mode) || S_ISBLK (mode) ) && + (flags & DEVFS_FL_AUTO_DEVNUM) ) { - if (next_devnum_block >= MAX_DEVNUM) + if ( ( devnum = devfs_alloc_devnum (devtype) ) == NODEV ) { - printk ("%s: devfs_register(%s): exhausted block device numbers\n", - DEVFS_NAME, name); + printk ("%s: devfs_register(%s): exhausted %s device numbers\n", + DEVFS_NAME, name, S_ISCHR (mode) ? "char" : "block"); return NULL; } - major = next_devnum_block >> 8; - minor = next_devnum_block & 0xff; - ++next_devnum_block; + major = MAJOR (devnum); + minor = MINOR (devnum); } de = search_for_entry (dir, name, strlen (name), TRUE, TRUE, &is_new, FALSE); @@ -1326,6 +1315,7 @@ { printk ("%s: devfs_register(): could not create entry: \"%s\"\n", DEVFS_NAME, name); + if (devnum != NODEV) devfs_dealloc_devnum (devtype, devnum); return NULL; } #ifdef CONFIG_DEVFS_DEBUG @@ -1341,19 +1331,23 @@ { printk ("%s: devfs_register(): existing non-device/file entry: \"%s\"\n", DEVFS_NAME, name); + if (devnum != NODEV) devfs_dealloc_devnum (devtype, devnum); return NULL; } if (de->registered) { printk("%s: devfs_register(): device already registered: \"%s\"\n", DEVFS_NAME, name); + if (devnum != NODEV) devfs_dealloc_devnum (devtype, devnum); return NULL; } } + de->u.fcb.autogen = 0; if ( S_ISCHR (mode) || S_ISBLK (mode) ) { de->u.fcb.u.device.major = major; de->u.fcb.u.device.minor = minor; + de->u.fcb.autogen = (devnum == NODEV) ? 0 : 1; } else if ( S_ISREG (mode) ) de->u.fcb.u.file.size = 0; else @@ -1417,6 +1411,14 @@ { de->registered = FALSE; de->u.fcb.ops = NULL; + if (!S_ISREG (de->mode) && de->u.fcb.autogen) + { + devfs_dealloc_devnum ( S_ISCHR (de->mode) ? DEVFS_SPECIAL_CHR : + DEVFS_SPECIAL_BLK, + MKDEV (de->u.fcb.u.device.major, + de->u.fcb.u.device.minor) ); + } + de->u.fcb.autogen = 0; return; } if (S_ISLNK (de->mode) && de->registered) diff -u --recursive --new-file v2.4.6/linux/fs/devfs/util.c linux/fs/devfs/util.c --- v2.4.6/linux/fs/devfs/util.c Tue Jul 3 17:08:21 2001 +++ linux/fs/devfs/util.c Wed Jul 11 14:55:41 2001 @@ -35,12 +35,18 @@ Took account of interface change to <devfs_mk_dir>. 20010519 Richard Gooch <rgooch@atnf.csiro.au> Documentation cleanup. + 20010709 Richard Gooch <rgooch@atnf.csiro.au> + Created <devfs_*alloc_major> and <devfs_*alloc_devnum>. + 20010710 Richard Gooch <rgooch@atnf.csiro.au> + Created <devfs_*alloc_unique_number>. */ #include <linux/module.h> #include <linux/init.h> -#include <linux/locks.h> -#include <linux/kdev_t.h> #include <linux/devfs_fs_kernel.h> +#include <linux/malloc.h> +#include <linux/vmalloc.h> + +#include <asm/bitops.h> /* Private functions follow */ @@ -166,3 +172,297 @@ } } /* End Function devfs_register_series */ EXPORT_SYMBOL(devfs_register_series); + + +struct major_list +{ + spinlock_t lock; + __u32 bits[8]; +}; + +/* Block majors already assigned: + 0-3, 7-9, 11-12, 13-63, 65-93, 95-99, 101, 103-111, 120-127, 199, 201, + 240-255 +*/ +static struct major_list block_major_list = +{SPIN_LOCK_UNLOCKED, + {0xfffffb8f, /* Majors 0 to 31 */ + 0xffffffff, /* Majors 32 to 63 */ + 0xbffffffe, /* Majors 64 to 95 */ + 0xff00ffaf, /* Majors 96 to 127 */ + 0x00000000, /* Majors 128 to 159 */ + 0x00000000, /* Majors 160 to 191 */ + 0x00000280, /* Majors 192 to 223 */ + 0xffff0000} /* Majors 224 to 255 */ +}; + +/* Char majors already assigned: + 0-7, 9-151, 154-158, 160-195, 198-211, 216-221, 224-225, 240-255 +*/ +static struct major_list char_major_list = +{SPIN_LOCK_UNLOCKED, + {0xfffffeff, /* Majors 0 to 31 */ + 0xffffffff, /* Majors 32 to 63 */ + 0xffffffff, /* Majors 64 to 95 */ + 0xffffffff, /* Majors 96 to 127 */ + 0x7cffffff, /* Majors 128 to 159 */ + 0xffffffff, /* Majors 160 to 191 */ + 0x3f0fffcf, /* Majors 192 to 223 */ + 0xffff0003} /* Majors 224 to 255 */ +}; + + +/** + * devfs_alloc_major - Allocate a major number. + * @type: The type of the major (DEVFS_SPECIAL_CHR or DEVFS_SPECIAL_BLOCK) + + * Returns the allocated major, else -1 if none are available. + * This routine is thread safe and does not block. + */ + +int devfs_alloc_major (char type) +{ + int major; + struct major_list *list; + + list = (type == DEVFS_SPECIAL_CHR) ? &char_major_list : &block_major_list; + spin_lock (&list->lock); + major = find_first_zero_bit (list->bits, 256); + if (major < 256) __set_bit (major, list->bits); + else major = -1; + spin_unlock (&list->lock); + return major; +} /* End Function devfs_alloc_major */ +EXPORT_SYMBOL(devfs_alloc_major); + + +/** + * devfs_dealloc_major - Deallocate a major number. + * @type: The type of the major (DEVFS_SPECIAL_CHR or DEVFS_SPECIAL_BLOCK) + * @major: The major number. + * This routine is thread safe and does not block. + */ + +void devfs_dealloc_major (char type, int major) +{ + int was_set; + struct major_list *list; + + if (major < 0) return; + list = (type == DEVFS_SPECIAL_CHR) ? &char_major_list : &block_major_list; + spin_lock (&list->lock); + was_set = __test_and_clear_bit (major, list->bits); + spin_unlock (&list->lock); + if (!was_set) + printk (KERN_ERR __FUNCTION__ "(): major %d was already free\n", + major); +} /* End Function devfs_dealloc_major */ +EXPORT_SYMBOL(devfs_dealloc_major); + + +struct minor_list +{ + int major; + __u32 bits[8]; + struct minor_list *next; +}; + +struct device_list +{ + struct minor_list *first, *last; + int none_free; +}; + +DECLARE_MUTEX (block_semaphore); +static struct device_list block_list; + +DECLARE_MUTEX (char_semaphore); +static struct device_list char_list; + + +/** + * devfs_alloc_devnum - Allocate a device number. + * @type: The type (DEVFS_SPECIAL_CHR or DEVFS_SPECIAL_BLOCK). + * + * Returns the allocated device number, else NODEV if none are available. + * This routine is thread safe and may block. + */ + +kdev_t devfs_alloc_devnum (char type) +{ + int minor; + struct semaphore *semaphore; + struct device_list *list; + struct minor_list *entry; + + if (type == DEVFS_SPECIAL_CHR) + { + semaphore = &char_semaphore; + list = &char_list; + } + else + { + semaphore = &block_semaphore; + list = &block_list; + } + if (list->none_free) return NODEV; /* Fast test */ + down (semaphore); + if (list->none_free) + { + up (semaphore); + return NODEV; + } + for (entry = list->first; entry != NULL; entry = entry->next) + { + minor = find_first_zero_bit (entry->bits, 256); + if (minor >= 256) continue; + __set_bit (minor, entry->bits); + up (semaphore); + return MKDEV (entry->major, minor); + } + /* Need to allocate a new major */ + if ( ( entry = kmalloc (sizeof *entry, GFP_KERNEL) ) == NULL ) + { + list->none_free = 1; + up (semaphore); + return NODEV; + } + memset (entry, 0, sizeof *entry); + if ( ( entry->major = devfs_alloc_major (type) ) < 0 ) + { + list->none_free = 1; + up (semaphore); + kfree (entry); + return NODEV; + } + __set_bit (0, entry->bits); + if (list->first == NULL) list->first = entry; + else list->last->next = entry; + list->last = entry; + up (semaphore); + return MKDEV (entry->major, 0); +} /* End Function devfs_alloc_devnum */ +EXPORT_SYMBOL(devfs_alloc_devnum); + + +/** + * devfs_dealloc_devnum - Dellocate a device number. + * @type: The type (DEVFS_SPECIAL_CHR or DEVFS_SPECIAL_BLOCK). + * @devnum: The device number. + * + * This routine is thread safe and does not block. + */ + +void devfs_dealloc_devnum (char type, kdev_t devnum) +{ + int major, minor; + struct semaphore *semaphore; + struct device_list *list; + struct minor_list *entry; + + if (devnum == NODEV) return; + if (type == DEVFS_SPECIAL_CHR) + { + semaphore = &char_semaphore; + list = &char_list; + } + else + { + semaphore = &block_semaphore; + list = &block_list; + } + major = MAJOR (devnum); + minor = MINOR (devnum); + down (semaphore); + for (entry = list->first; entry != NULL; entry = entry->next) + { + int was_set; + + if (entry->major != major) continue; + was_set = __test_and_clear_bit (minor, entry->bits); + if (was_set) list->none_free = 0; + up (semaphore); + if (!was_set) + printk ( KERN_ERR __FUNCTION__ "(): device %s was already free\n", + kdevname (devnum) ); + return; + } + up (semaphore); + printk ( KERN_ERR __FUNCTION__ "(): major for %s not previously allocated\n", + kdevname (devnum) ); +} /* End Function devfs_dealloc_devnum */ +EXPORT_SYMBOL(devfs_dealloc_devnum); + + +/** + * devfs_alloc_unique_number - Allocate a unique (positive) number. + * @space: The number space to allocate from. + * + * Returns the allocated unique number, else a negative error code. + * This routine is thread safe and may block. + */ + +int devfs_alloc_unique_number (struct unique_numspace *space) +{ + int number; + unsigned int length; + __u32 *bits; + + /* Get around stupid lack of semaphore initialiser */ + spin_lock (&space->init_lock); + if (!space->sem_initialised) + { + sema_init (&space->semaphore, 1); + space->sem_initialised = 1; + } + spin_unlock (&space->init_lock); + down (&space->semaphore); + if (space->num_free < 1) + { + if (space->length < 16) length = 16; + else length = space->length << 1; + if ( ( bits = vmalloc (length) ) == NULL ) + { + up (&space->semaphore); + return -ENOMEM; + } + if (space->bits != NULL) + { + memcpy (bits, space->bits, space->length); + vfree (space->bits); + } + space->num_free = (length - space->length) << 3; + space->bits = bits; + memset (bits + space->length, 0, length - space->length); + space->length = length; + } + number = find_first_zero_bit (space->bits, space->length << 3); + __set_bit (number, space->bits); + up (&space->semaphore); + return number; +} /* End Function devfs_alloc_unique_number */ +EXPORT_SYMBOL(devfs_alloc_unique_number); + + +/** + * devfs_dealloc_unique_number - Deallocate a unique (positive) number. + * @space: The number space to deallocate from. + * @number: The number to deallocate. + * + * This routine is thread safe and may block. + */ + +void devfs_dealloc_unique_number (struct unique_numspace *space, int number) +{ + int was_set; + + if (number < 0) return; + down (&space->semaphore); + was_set = __test_and_clear_bit (number, space->bits); + if (was_set) ++space->num_free; + up (&space->semaphore); + if (!was_set) + printk (KERN_ERR __FUNCTION__ "(): number %d was already free\n", + number); +} /* End Function devfs_dealloc_unique_number */ +EXPORT_SYMBOL(devfs_dealloc_unique_number); diff -u --recursive --new-file v2.4.6/linux/fs/dquot.c linux/fs/dquot.c --- v2.4.6/linux/fs/dquot.c Tue Jul 3 17:08:21 2001 +++ linux/fs/dquot.c Wed Jul 11 14:50:47 2001 @@ -1467,7 +1467,7 @@ if (IS_ERR(f)) goto out_lock; error = -EIO; - if (!f->f_op || (!f->f_op->read && !f->f_op->write)) + if (!f->f_op || !f->f_op->read || !f->f_op->write) goto out_f; inode = f->f_dentry->d_inode; error = -EACCES; diff -u --recursive --new-file v2.4.6/linux/fs/exec.c linux/fs/exec.c --- v2.4.6/linux/fs/exec.c Thu Apr 26 14:11:29 2001 +++ linux/fs/exec.c Thu Jul 19 20:32:54 2001 @@ -548,7 +548,7 @@ current->sas_ss_sp = current->sas_ss_size = 0; if (current->euid == current->uid && current->egid == current->gid) - current->dumpable = 1; + current->mm->dumpable = 1; name = bprm->filename; for (i=0; (ch = *(name++)) != '\0';) { if (ch == '/') @@ -565,7 +565,7 @@ if (bprm->e_uid != current->euid || bprm->e_gid != current->egid || permission(bprm->file->f_dentry->d_inode,MAY_READ)) - current->dumpable = 0; + current->mm->dumpable = 0; /* An exec changes our domain. We are no longer part of the thread group */ @@ -683,7 +683,7 @@ if (bprm->e_uid != current->uid || bprm->e_gid != current->gid || !cap_issubset(new_permitted, current->cap_permitted)) { - current->dumpable = 0; + current->mm->dumpable = 0; lock_kernel(); if (must_not_trace_exec(current) @@ -927,14 +927,15 @@ char corename[6+sizeof(current->comm)]; struct file * file; struct inode * inode; + int retval = 0; lock_kernel(); binfmt = current->binfmt; if (!binfmt || !binfmt->core_dump) goto fail; - if (!current->dumpable || atomic_read(¤t->mm->mm_users) != 1) + if (!current->mm->dumpable) goto fail; - current->dumpable = 0; + current->mm->dumpable = 0; if (current->rlim[RLIMIT_CORE].rlim_cur < binfmt->min_coredump) goto fail; @@ -961,15 +962,14 @@ goto close_fail; if (do_truncate(file->f_dentry, 0) != 0) goto close_fail; - if (!binfmt->core_dump(signr, regs, file)) - goto close_fail; - unlock_kernel(); - filp_close(file, NULL); - return 1; + + down_read(¤t->mm->mmap_sem); + retval = binfmt->core_dump(signr, regs, file); + up_read(¤t->mm->mmap_sem); close_fail: filp_close(file, NULL); fail: unlock_kernel(); - return 0; + return retval; } diff -u --recursive --new-file v2.4.6/linux/fs/ext2/balloc.c linux/fs/ext2/balloc.c --- v2.4.6/linux/fs/ext2/balloc.c Fri Dec 29 14:36:44 2000 +++ linux/fs/ext2/balloc.c Wed Jul 11 15:44:45 2001 @@ -174,7 +174,7 @@ sb->u.ext2_sb.s_loaded_block_bitmaps++; else brelse (sb->u.ext2_sb.s_block_bitmap[EXT2_MAX_GROUP_LOADED - 1]); - for (j = sb->u.ext2_sb.s_loaded_block_bitmaps - 1; j > 0; j--) { + for (j = sb->u.ext2_sb.s_loaded_block_bitmaps - 1; j > 0; j--) { sb->u.ext2_sb.s_block_bitmap_number[j] = sb->u.ext2_sb.s_block_bitmap_number[j - 1]; sb->u.ext2_sb.s_block_bitmap[j] = @@ -276,7 +276,7 @@ goto error_return; } - ext2_debug ("freeing block %lu\n", block); + ext2_debug ("freeing block(s) %lu-%lu\n", block, block + count - 1); do_more: overflow = 0; @@ -315,8 +315,8 @@ for (i = 0; i < count; i++) { if (!ext2_clear_bit (bit + i, bh->b_data)) ext2_error (sb, "ext2_free_blocks", - "bit already cleared for block %lu", - block); + "bit already cleared for block %lu", + block + i); else { DQUOT_FREE_BLOCK(sb, inode, 1); gdp->bg_free_blocks_count = @@ -411,10 +411,7 @@ ext2_debug ("goal is at %d:%d.\n", i, j); if (!ext2_test_bit(j, bh->b_data)) { -#ifdef EXT2FS_DEBUG - goal_hits++; - ext2_debug ("goal bit allocated.\n"); -#endif + ext2_debug("goal bit allocated, %d hits\n",++goal_hits); goto got_block; } if (j) { @@ -471,10 +468,8 @@ if (i >= sb->u.ext2_sb.s_groups_count) i = 0; gdp = ext2_get_group_desc (sb, i, &bh2); - if (!gdp) { - *err = -EIO; - goto out; - } + if (!gdp) + goto io_error; if (le16_to_cpu(gdp->bg_free_blocks_count) > 0) break; } @@ -766,7 +761,7 @@ for (j = 0; j < sb->u.ext2_sb.s_itb_per_group; j++) if (!block_in_use (le32_to_cpu(gdp->bg_inode_table) + j, sb, bh->b_data)) ext2_error (sb, "ext2_check_blocks_bitmap", - "Block #%d of the inode table in " + "Block #%ld of the inode table in " "group %d is marked free", j, i); x = ext2_count_free (bh, sb->s_blocksize); diff -u --recursive --new-file v2.4.6/linux/fs/ext2/dir.c linux/fs/ext2/dir.c --- v2.4.6/linux/fs/ext2/dir.c Tue Jul 3 17:08:21 2001 +++ linux/fs/ext2/dir.c Mon Jul 16 16:36:36 2001 @@ -363,7 +363,7 @@ void ext2_set_link(struct inode *dir, struct ext2_dir_entry_2 *de, struct page *page, struct inode *inode) { - unsigned from = (char *)de-(char*)page_address(page); + unsigned from = (char *) de - (char *) page_address(page); unsigned to = from + le16_to_cpu(de->rec_len); int err; @@ -578,5 +578,6 @@ struct file_operations ext2_dir_operations = { read: generic_read_dir, readdir: ext2_readdir, + ioctl: ext2_ioctl, fsync: ext2_sync_file, }; diff -u --recursive --new-file v2.4.6/linux/fs/ext2/file.c linux/fs/ext2/file.c --- v2.4.6/linux/fs/ext2/file.c Wed Sep 27 13:41:33 2000 +++ linux/fs/ext2/file.c Wed Jul 11 15:44:45 2001 @@ -69,7 +69,7 @@ /* * Called when an inode is released. Note that this is different - * from ext2_file_open: open gets called at every open, but release + * from ext2_open_file: open gets called at every open, but release * gets called only when /all/ the files are closed. */ static int ext2_release_file (struct inode * inode, struct file * filp) diff -u --recursive --new-file v2.4.6/linux/fs/ext2/inode.c linux/fs/ext2/inode.c --- v2.4.6/linux/fs/ext2/inode.c Tue Jul 3 17:08:21 2001 +++ linux/fs/ext2/inode.c Wed Jul 11 15:44:45 2001 @@ -99,16 +99,12 @@ result = inode->u.ext2_i.i_prealloc_block++; inode->u.ext2_i.i_prealloc_count--; /* Writer: end */ -#ifdef EXT2FS_DEBUG ext2_debug ("preallocation hit (%lu/%lu).\n", ++alloc_hits, ++alloc_attempts); -#endif } else { ext2_discard_prealloc (inode); -#ifdef EXT2FS_DEBUG ext2_debug ("preallocation miss (%lu/%lu).\n", alloc_hits, ++alloc_attempts); -#endif if (S_ISREG(inode->i_mode)) result = ext2_new_block (inode, goal, &inode->u.ext2_i.i_prealloc_count, @@ -367,7 +363,7 @@ * be placed into *branch->p to fill that gap. * * If allocation fails we free all blocks we've allocated (and forget - * ther buffer_heads) and return the error value the from failed + * their buffer_heads) and return the error value the from failed * ext2_alloc_block() (normally -ENOSPC). Otherwise we set the chain * as described above and return 0. */ @@ -964,12 +960,10 @@ inode->u.ext2_i.i_frag_no = raw_inode->i_frag; inode->u.ext2_i.i_frag_size = raw_inode->i_fsize; inode->u.ext2_i.i_file_acl = le32_to_cpu(raw_inode->i_file_acl); - if (S_ISDIR(inode->i_mode)) - inode->u.ext2_i.i_dir_acl = le32_to_cpu(raw_inode->i_dir_acl); - else { - inode->u.ext2_i.i_high_size = le32_to_cpu(raw_inode->i_size_high); + if (S_ISREG(inode->i_mode)) inode->i_size |= ((__u64)le32_to_cpu(raw_inode->i_size_high)) << 32; - } + else + inode->u.ext2_i.i_dir_acl = le32_to_cpu(raw_inode->i_dir_acl); inode->i_generation = le32_to_cpu(raw_inode->i_generation); inode->u.ext2_i.i_prealloc_count = 0; inode->u.ext2_i.i_block_group = block_group; @@ -1114,7 +1108,7 @@ raw_inode->i_dir_acl = cpu_to_le32(inode->u.ext2_i.i_dir_acl); else { raw_inode->i_size_high = cpu_to_le32(inode->i_size >> 32); - if (raw_inode->i_size_high) { + if (inode->i_size > 0x7fffffffULL) { struct super_block *sb = inode->i_sb; if (!EXT2_HAS_RO_COMPAT_FEATURE(sb, EXT2_FEATURE_RO_COMPAT_LARGE_FILE) || diff -u --recursive --new-file v2.4.6/linux/fs/ext2/super.c linux/fs/ext2/super.c --- v2.4.6/linux/fs/ext2/super.c Wed May 16 10:31:27 2001 +++ linux/fs/ext2/super.c Wed Jul 11 15:45:10 2001 @@ -446,20 +446,17 @@ return NULL; } /* - * Note: s_es must be initialized s_es as soon as possible because - * some ext2 macro-instructions depend on its value + * Note: s_es must be initialized as soon as possible because + * some ext2 macro-instructions depend on its value */ es = (struct ext2_super_block *) (((char *)bh->b_data) + offset); sb->u.ext2_sb.s_es = es; sb->s_magic = le16_to_cpu(es->s_magic); if (sb->s_magic != EXT2_SUPER_MAGIC) { if (!silent) - printk ("VFS: Can't find an ext2 filesystem on dev " - "%s.\n", bdevname(dev)); - failed_mount: - if (bh) - brelse(bh); - return NULL; + printk ("VFS: Can't find ext2 filesystem on dev %s.\n", + bdevname(dev)); + goto failed_mount; } if (le32_to_cpu(es->s_rev_level) == EXT2_GOOD_OLD_REV && (EXT2_HAS_COMPAT_FEATURE(sb, ~0U) || @@ -622,11 +619,9 @@ } } if (!ext2_check_descriptors (sb)) { - for (j = 0; j < db_count; j++) - brelse (sb->u.ext2_sb.s_group_desc[j]); - kfree(sb->u.ext2_sb.s_group_desc); - printk ("EXT2-fs: group descriptors corrupted !\n"); - goto failed_mount; + printk ("EXT2-fs: group descriptors corrupted!\n"); + db_count = i; + goto failed_mount2; } for (i = 0; i < EXT2_MAX_GROUP_LOADED; i++) { sb->u.ext2_sb.s_inode_bitmap_number[i] = 0; @@ -642,17 +637,25 @@ */ sb->s_op = &ext2_sops; sb->s_root = d_alloc_root(iget(sb, EXT2_ROOT_INO)); - if (!sb->s_root) { - for (i = 0; i < db_count; i++) - if (sb->u.ext2_sb.s_group_desc[i]) - brelse (sb->u.ext2_sb.s_group_desc[i]); - kfree(sb->u.ext2_sb.s_group_desc); - brelse (bh); - printk ("EXT2-fs: get root inode failed\n"); - return NULL; + if (!sb->s_root || !S_ISDIR(sb->s_root->d_inode->i_mode) || + !sb->s_root->d_inode->i_blocks || !sb->s_root->d_inode->i_size) { + if (sb->s_root) { + dput(sb->s_root); + sb->s_root = NULL; + printk ("EXT2-fs: corrupt root inode, run e2fsck\n"); + } else + printk ("EXT2-fs: get root inode failed\n"); + goto failed_mount2; } ext2_setup_super (sb, es, sb->s_flags & MS_RDONLY); return sb; +failed_mount2: + for (i = 0; i < db_count; i++) + brelse(sb->u.ext2_sb.s_group_desc[i]); + kfree(sb->u.ext2_sb.s_group_desc); +failed_mount: + brelse(bh); + return NULL; } static void ext2_commit_super (struct super_block * sb, diff -u --recursive --new-file v2.4.6/linux/fs/inode.c linux/fs/inode.c --- v2.4.6/linux/fs/inode.c Tue Jul 3 17:08:21 2001 +++ linux/fs/inode.c Thu Jul 5 10:14:40 2001 @@ -692,7 +692,7 @@ * want to recurse into the FS that called us * in clear_inode() and friends.. */ - if (!(gfp_mask & __GFP_IO)) + if (!(gfp_mask & __GFP_FS)) return; if (priority) diff -u --recursive --new-file v2.4.6/linux/fs/jffs/jffs_fm.c linux/fs/jffs/jffs_fm.c --- v2.4.6/linux/fs/jffs/jffs_fm.c Fri Feb 9 11:29:44 2001 +++ linux/fs/jffs/jffs_fm.c Wed Jul 4 11:50:39 2001 @@ -47,7 +47,10 @@ mtd = get_mtd_device(NULL, MINOR(dev)); if (!mtd) + { + kfree(fmc); return NULL; + } /* Retrieve the size of the flash memory. */ fmc->flash_start = 0; diff -u --recursive --new-file v2.4.6/linux/fs/locks.c linux/fs/locks.c --- v2.4.6/linux/fs/locks.c Tue Jul 3 17:08:21 2001 +++ linux/fs/locks.c Wed Jul 4 15:39:28 2001 @@ -112,7 +112,7 @@ * * Leases and LOCK_MAND * Matthew Wilcox <willy@linuxcare.com>, June, 2000. - * Stephen Rothwell <sfr@linuxcare.com>, June, 2000. + * Stephen Rothwell <sfr@canb.auug.org.au>, June, 2000. */ #include <linux/slab.h> diff -u --recursive --new-file v2.4.6/linux/fs/namei.c linux/fs/namei.c --- v2.4.6/linux/fs/namei.c Tue Jul 3 17:08:21 2001 +++ linux/fs/namei.c Fri Jul 20 12:39:56 2001 @@ -886,7 +886,7 @@ { int error; - mode &= S_IALLUGO & ~current->fs->umask; + mode &= S_IALLUGO; mode |= S_IFREG; down(&dir->i_zombie); @@ -975,7 +975,8 @@ /* Negative dentry, just create the file */ if (!dentry->d_inode) { - error = vfs_create(dir->d_inode, dentry, mode); + error = vfs_create(dir->d_inode, dentry, + mode & ~current->fs->umask); up(&dir->d_inode->i_sem); dput(nd->dentry); nd->dentry = dentry; @@ -1164,8 +1165,6 @@ { int error = -EPERM; - mode &= ~current->fs->umask; - down(&dir->i_zombie); if ((S_ISCHR(mode) || S_ISBLK(mode)) && !capable(CAP_MKNOD)) goto exit_lock; @@ -1208,6 +1207,8 @@ goto out; dentry = lookup_create(&nd, 0); error = PTR_ERR(dentry); + + mode &= ~current->fs->umask; if (!IS_ERR(dentry)) { switch (mode & S_IFMT) { case 0: case S_IFREG: @@ -1246,7 +1247,7 @@ goto exit_lock; DQUOT_INIT(dir); - mode &= (S_IRWXUGO|S_ISVTX) & ~current->fs->umask; + mode &= (S_IRWXUGO|S_ISVTX); lock_kernel(); error = dir->i_op->mkdir(dir, dentry, mode); unlock_kernel(); @@ -1276,7 +1277,8 @@ dentry = lookup_create(&nd, 1); error = PTR_ERR(dentry); if (!IS_ERR(dentry)) { - error = vfs_mkdir(nd.dentry->d_inode, dentry, mode); + error = vfs_mkdir(nd.dentry->d_inode, dentry, + mode & ~current->fs->umask); dput(dentry); } up(&nd.dentry->d_inode->i_sem); @@ -1685,6 +1687,10 @@ down(&old_dir->i_sb->s_vfs_rename_sem); error = -EINVAL; if (is_subdir(new_dentry, old_dentry)) + goto out_unlock; + /* Don't eat your daddy, dear... */ + /* This also avoids locking issues */ + if (old_dentry->d_parent == new_dentry) goto out_unlock; target = new_dentry->d_inode; if (target) { /* Hastur! Hastur! Hastur! */ diff -u --recursive --new-file v2.4.6/linux/fs/nfs/nfsroot.c linux/fs/nfs/nfsroot.c --- v2.4.6/linux/fs/nfs/nfsroot.c Mon Sep 25 13:13:53 2000 +++ linux/fs/nfs/nfsroot.c Thu Jul 19 21:47:16 2001 @@ -418,7 +418,7 @@ "as nfsd port\n", port); } - if ((port = root_nfs_getport(NFS_MNT_PROGRAM, nfsd_ver, proto)) < 0) { + if ((port = root_nfs_getport(NFS_MNT_PROGRAM, mountd_ver, proto)) < 0) { printk(KERN_ERR "Root-NFS: Unable to get mountd port " "number from server, using default\n"); port = mountd_port; diff -u --recursive --new-file v2.4.6/linux/fs/nfsd/nfsfh.c linux/fs/nfsd/nfsfh.c --- v2.4.6/linux/fs/nfsd/nfsfh.c Tue Jul 3 17:08:21 2001 +++ linux/fs/nfsd/nfsfh.c Mon Jul 9 18:21:41 2001 @@ -837,11 +837,11 @@ dentry = fhp->fh_dentry; if (!dentry->d_inode) goto out_negative; - if (fhp->fh_handle.fh_fileid_type != 0) - goto out_uptodate; if (fhp->fh_handle.fh_version != 1) { _fh_update_old(dentry, fhp->fh_export, &fhp->fh_handle); } else { + if (fhp->fh_handle.fh_fileid_type != 0) + goto out_uptodate; datap = fhp->fh_handle.fh_auth+ fhp->fh_handle.fh_size/4 -1; fhp->fh_handle.fh_fileid_type = diff -u --recursive --new-file v2.4.6/linux/fs/ntfs/Makefile linux/fs/ntfs/Makefile --- v2.4.6/linux/fs/ntfs/Makefile Wed Apr 18 11:49:13 2001 +++ linux/fs/ntfs/Makefile Mon Jul 16 15:14:10 2001 @@ -2,10 +2,10 @@ O_TARGET := ntfs.o -obj-y := fs.o sysctl.o support.o util.o inode.o dir.o super.o attr.o +obj-y := fs.o sysctl.o support.o util.o inode.o dir.o super.o attr.o unistr.o obj-m := $(O_TARGET) -# Version format: YYMMDD -EXTRA_CFLAGS = -DNTFS_IN_LINUX_KERNEL -DNTFS_VERSION=\"010116\" +# New version format started 3 February 2001. +EXTRA_CFLAGS = -DNTFS_VERSION=\"1.1.15\" #-DDEBUG include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.4.6/linux/fs/ntfs/attr.c linux/fs/ntfs/attr.c --- v2.4.6/linux/fs/ntfs/attr.c Wed Apr 18 11:49:13 2001 +++ linux/fs/ntfs/attr.c Mon Jul 16 15:14:10 2001 @@ -1,10 +1,11 @@ -/* attr.c +/* + * attr.c * - * Copyright (C) 1996-1999 Martin von Löwis - * Copyright (C) 1996-1997 Régis Duchesne - * Copyright (C) 1998 Joseph Malicki - * Copyright (C) 1999 Steve Dodd - * Copyright (C) 2001 Anton Altaparmakov (AIA) + * Copyright (C) 1996-1999 Martin von Löwis + * Copyright (C) 1996-1997 Régis Duchesne + * Copyright (C) 1998 Joseph Malicki + * Copyright (C) 1999 Steve Dodd + * Copyright (C) 2001 Anton Altaparmakov (AIA) */ #include "ntfstypes.h" @@ -17,37 +18,156 @@ #include "util.h" #include "super.h" #include "inode.h" +#include "unistr.h" + +/** + * ntfs_find_attr_in_mft_rec - find attribute in mft record + * @vol: volume on which attr resides + * @m: mft record to search + * @type: attribute type to find + * @name: attribute name to find (optional, i.e. NULL means don't care) + * @name_len: attribute name length (only needed if @name present) + * @ic: ignore case if 1 or case sensitive if 0 (ignored if @name NULL) + * @instance: instance number to find + * + * Only search the specified mft record and it ignores the presence of an + * attribute list attribute (unless it is the one being searched for, + * obviously, in which case it is returned). + */ +ntfs_u8* ntfs_find_attr_in_mft_rec(ntfs_volume *vol, ntfs_u8 *m, __u32 type, + wchar_t *name, __u32 name_len, int ic, __u16 instance) +{ + ntfs_u8 *a; + + /* Iterate over attributes in mft record @m. */ + a = m + NTFS_GETU16(m + 20); /* attrs_offset */ + for (; a >= m && a <= m + vol->mft_record_size; + a += NTFS_GETU32(a + 4 /* length */)) { + /* We catch $END with this more general check, too... */ + if (NTFS_GETU32(a + 0 /* type */) > type) + return NULL; + if (!NTFS_GETU32(a + 4 /* length */)) + break; + if (NTFS_GETU32(a + 0 /* type */) != type) + continue; + /* If @name is present, compare the two names. */ + if (name && !ntfs_are_names_equal(name, name_len, (wchar_t*) + (a + NTFS_GETU16(a + 10 /* name_offset */)), + a[9] /* name_length */, ic, vol->upcase, + vol->upcase_length)) { + register int rc; + + rc = ntfs_collate_names(vol->upcase, vol->upcase_length, + name, name_len, (wchar_t*)(a + + NTFS_GETU16(a + 10 /* name_offset */)), + a[9] /* name_length */, 1, 1); + /* + * If @name collates before a->name, there is no + * matching attribute. + */ + if (rc == -1) + return NULL; + /* If the strings are not equal, continue search. */ + if (rc) + continue; + rc = ntfs_collate_names(vol->upcase, vol->upcase_length, + name, name_len, (wchar_t*)(a + + NTFS_GETU16(a + 10 /* name_offset */)), + a[9] /* name_length */, 0, 1); + if (rc == -1) + return NULL; + if (rc) + continue; + } + /* + * The names match or @name not present. Check instance number. + * and if it matches we have found the attribute and are done. + */ + if (instance != NTFS_GETU16(a + 14 /* instance */)) + continue; + ntfs_debug(DEBUG_FILE3, "ntfs_find_attr_in_mft_record: found: " + "attr type 0x%x, instance number = 0x%x.\n", + NTFS_GETU32(a + 0), instance); + return a; + } + ntfs_error("ntfs_find_attr_in_mft_record: mft record 0x%x is corrupt" + ". Run chkdsk.\n", m); + return NULL; +} /* Look if an attribute already exists in the inode, and if not, create it. */ -int ntfs_new_attr(ntfs_inode *ino, int type, void *name, int namelen, int *pos, - int *found, int do_search) +int ntfs_new_attr(ntfs_inode *ino, int type, void *name, int namelen, + void *value, int value_len, int *pos, int *found) { int do_insert = 0; - int i; + int i, m; + ntfs_attribute *a; for (i = 0; i < ino->attr_count; i++) { - int n = min(namelen, ino->attrs[i].namelen); - int s = ntfs_uni_strncmp(ino->attrs[i].name, name, n); - if (do_search) { - /* We assume that each attribute can be uniquely - * identified by inode number, attribute type and - * attribute name. */ - if (ino->attrs[i].type == type && - ino->attrs[i].namelen == namelen && !s) { - *found = 1; - *pos = i; - return 0; - } - } - /* Attributes are ordered by type, then by name. */ - if (ino->attrs[i].type > type || - (ino->attrs[i].type == type && s == 1)) { + a = ino->attrs + i; + if (a->type < type) + continue; + if (a->type > type) { do_insert = 1; break; } + /* If @name is present, compare the two names. */ + if (namelen && !ntfs_are_names_equal((wchar_t*)name, namelen, + a->name, a->namelen /* name_length */, + 1 /* ignore case*/, ino->vol->upcase, + ino->vol->upcase_length)) { + register int rc; + + rc = ntfs_collate_names(ino->vol->upcase, + ino->vol->upcase_length, a->name, + a->namelen, (wchar_t*)name, namelen, + 1 /* ignore case */, 1); + if (rc == -1) + continue; + if (rc == 1) { + do_insert = 1; + break; + } + rc = ntfs_collate_names(ino->vol->upcase, + ino->vol->upcase_length, a->name, + a->namelen, (wchar_t*)name, namelen, + 0 /* case sensitive */, 1); + if (rc == -1) + continue; + if (rc == 1) { + do_insert = 1; + break; + } + } + /* Names are equal or no name was asked for. */ + /* If a value was specified compare the values. */ + if (value_len && a->resident) { + if (!a->resident) { + ntfs_error("ntfs_new_attr: Value specified but " + "attribute non-resident. Bug!\n"); + return -EINVAL; + } + m = memcmp(value, a->d.data, min(value_len, a->size)); + if (m > 0) + continue; + if (m < 0) { + do_insert = 1; + break; + } + /* Values match until min of value lengths. */ + if (value_len > a->size) + continue; + if (value_len < a->size) { + do_insert = 1; + break; + } + } + /* Full match! */ + *found = 1; + *pos = i; + return 0; } - /* Re-allocate space. */ if (ino->attr_count % 8 == 0) { @@ -77,7 +197,7 @@ int ntfs_make_attr_resident(ntfs_inode *ino, ntfs_attribute *attr) { - int size = attr->size; + __s64 size = attr->size; if (size > 0) { /* FIXME: read data, free clusters */ return -EOPNOTSUPP; @@ -87,19 +207,35 @@ } /* Store in the inode readable information about a run. */ -void ntfs_insert_run(ntfs_attribute *attr, int cnum, ntfs_cluster_t cluster, +int ntfs_insert_run(ntfs_attribute *attr, int cnum, ntfs_cluster_t cluster, int len) { /* (re-)allocate space if necessary. */ - if (attr->d.r.len % 8 == 0) { + if ((attr->d.r.len * sizeof(ntfs_runlist)) % PAGE_SIZE == 0) { ntfs_runlist* new; - new = ntfs_malloc((attr->d.r.len + 8) * sizeof(ntfs_runlist)); - if (!new) - return; + unsigned long new_size; + + ntfs_debug(DEBUG_MALLOC, "ntfs_insert_run: re-allocating " + "space: old attr->d.r.len = 0x%x\n", + attr->d.r.len); + new_size = attr->d.r.len * sizeof(ntfs_runlist) + PAGE_SIZE; + if ((new_size >> PAGE_SHIFT) > num_physpages) { + ntfs_error("ntfs_insert_run: attempted to allocate " + "more pages than num_physpages." + "This might be a bug or a corrupt" + "file system.\n"); + return -1; + } + new = ntfs_vmalloc(new_size); + if (!new) { + ntfs_error("ntfs_insert_run: ntfs_vmalloc(new_size = " + "0x%x) failed\n", new_size); + return -1; + } if (attr->d.r.runlist) { ntfs_memcpy(new, attr->d.r.runlist, attr->d.r.len * sizeof(ntfs_runlist)); - ntfs_free(attr->d.r.runlist); + ntfs_vfree(attr->d.r.runlist); } attr->d.r.runlist = new; } @@ -110,6 +246,7 @@ attr->d.r.runlist[cnum].cluster = cluster; attr->d.r.runlist[cnum].len = len; attr->d.r.len++; + return 0; } /* Extends an attribute. Another run will be added if necessary, but we try to @@ -119,7 +256,7 @@ * * *len: the desired new length of the attr (_not_ the amount to extend by) */ -int ntfs_extend_attr(ntfs_inode *ino, ntfs_attribute *attr, int *len, int flags) +int ntfs_extend_attr(ntfs_inode *ino, ntfs_attribute *attr, __s64 *len, int flags) { int error = 0; ntfs_runlist *rl; @@ -145,8 +282,8 @@ cluster = 0; /* Calculate the extra space we need, and round up to multiple of * cluster size to get number of new clusters needed */ - clen = ((*len - attr->allocated) + ino->vol->clustersize - 1) / - ino->vol->clustersize; + clen = ((*len - attr->allocated) + ino->vol->cluster_size - 1) >> + ino->vol->cluster_size_bits; if (clen == 0) return 0; /* FIXME: try to allocate smaller pieces */ @@ -154,13 +291,17 @@ flags | ALLOC_REQUIRE_SIZE); if (error) return error; - attr->allocated += clen * ino->vol->clustersize; + attr->allocated += (__s64)clen << ino->vol->cluster_size_bits; *len = attr->allocated; /* Contiguous chunk. */ if (rlen >= 0 && cluster == rl[rlen].cluster + rl[rlen].len) { rl[rlen].len += clen; return 0; } + /* + * FIXME: if ntfs_insert_run fails we need to deallocate the cluster + * to revert to state before we were called... + */ ntfs_insert_run(attr, rlen + 1, cluster, clen); return 0; } @@ -168,13 +309,14 @@ int ntfs_make_attr_nonresident(ntfs_inode *ino, ntfs_attribute *attr) { void *data = attr->d.data; - int len = attr->size; - int error, alen; + __s64 len = attr->size; + int error; + __s64 alen; ntfs_io io; attr->d.r.len = 0; attr->d.r.runlist = 0; attr->resident = 0; - attr->allocated=attr->initialized = 0; + attr->allocated = attr->initialized = 0; alen = len; error = ntfs_extend_attr(ino, attr, &alen, ALLOC_REQUIRE_SIZE); if (error) @@ -203,13 +345,14 @@ } /* Resize the attribute to a newsize. */ -int ntfs_resize_attr(ntfs_inode *ino, ntfs_attribute *attr, int newsize) +int ntfs_resize_attr(ntfs_inode *ino, ntfs_attribute *attr, __s64 newsize) { int error = 0; - int oldsize = attr->size; - int clustersize = ino->vol->clustersize; - int i, count, newlen, newcount; + __s64 oldsize = attr->size; + int clustersizebits = ino->vol->cluster_size_bits; + int i, count, newcount; ntfs_runlist *rl; + __s64 newlen; if (newsize == oldsize) return 0; @@ -219,7 +362,7 @@ return -EOPNOTSUPP; if (attr->resident) { void *v; - if (newsize > ino->vol->mft_recordsize) { + if (newsize > ino->vol->mft_record_size) { error = ntfs_make_attr_nonresident(ino, attr); if (error) return error; @@ -247,16 +390,19 @@ rl = attr->d.r.runlist; if (newsize < oldsize) { for (i = 0, count = 0; i < attr->d.r.len; i++) { - if ((count + rl[i].len) * clustersize > newsize) + if ((__s64)(count + rl[i].len) << clustersizebits > + newsize) break; count += (int)rl[i].len; } newlen = i + 1; /* Free unused clusters in current run, unless sparse. */ newcount = count; - if (rl[i].cluster != MAX_CLUSTER_T) { - int rounded = newsize - count * clustersize; - rounded = (rounded + clustersize - 1) / clustersize; + if (rl[i].cluster != (ntfs_cluster_t)-1) { + int rounded = newsize - ((__s64)count << + clustersizebits); + rounded = (rounded + ino->vol->cluster_size - 1) >> + clustersizebits; error = ntfs_deallocate_clusters(ino->vol, rl[i].cluster + rounded, (int)rl[i].len - rounded); @@ -267,7 +413,7 @@ } /* Free all other runs. */ for (i++; i < attr->d.r.len; i++) - if (rl[i].cluster != MAX_CLUSTER_T) { + if (rl[i].cluster != (ntfs_cluster_t)-1) { error = ntfs_deallocate_clusters(ino->vol, rl[i].cluster, (int)rl[i].len); @@ -283,10 +429,10 @@ ALLOC_REQUIRE_SIZE); if (error) return error; /* FIXME: Incomplete operation. */ - newcount = newlen / clustersize; + newcount = newlen >> clustersizebits; } /* Fill in new sizes. */ - attr->allocated = newcount * clustersize; + attr->allocated = (__s64)newcount << clustersizebits; attr->size = newsize; /* attr->initialized does not change. */ if (!newsize) @@ -303,7 +449,7 @@ int error; ntfs_attribute *attr; - if (dsize > ino->vol->mft_recordsize) + if (dsize > ino->vol->mft_record_size) /* FIXME: Non-resident attributes. */ return -EOPNOTSUPP; if (aname) { @@ -316,14 +462,11 @@ name = 0; namelen = 0; } - error = ntfs_new_attr(ino, anum, name, namelen, &i, &found, 1); - if (error) { + error = ntfs_new_attr(ino, anum, name, namelen, data, dsize, &i, + &found); + if (error || found) { ntfs_free(name); - return error; - } - if (found) { - ntfs_free(name); - return -EEXIST; + return error ? error : -EEXIST; } *rattr = attr = ino->attrs + i; /* Allocate a new number. @@ -333,6 +476,10 @@ if (error) return error; attr->attrno = i; + if (attr->attrno + 1 != NTFS_GETU16(ino->attr + 0x28)) + ntfs_error("UH OH! attr->attrno (%i) != NTFS_GETU16(ino->attr " + "+ 0x28) (%i)\n", attr->attrno, + NTFS_GETU16(ino->attr + 0x28)); attr->resident = 1; attr->compressed = attr->cengine = 0; attr->size = attr->allocated = attr->initialized = dsize; @@ -340,9 +487,9 @@ /* FIXME: INDEXED information should come from $AttrDef * Currently, only file names are indexed. As of NTFS v3.0 (Win2k), * this is no longer true. Different attributes can be indexed now. */ - if (anum == ino->vol->at_file_name) { + if (anum == ino->vol->at_file_name) attr->indexed = 1; - } else + else attr->indexed = 0; attr->d.data = ntfs_malloc(dsize); if (!attr->d.data) @@ -354,7 +501,8 @@ /* Non-resident attributes are stored in runs (intervals of clusters). * * This function stores in the inode readable information about a non-resident - * attribute. */ + * attribute. + */ static int ntfs_process_runs(ntfs_inode *ino, ntfs_attribute* attr, unsigned char *data) { @@ -362,33 +510,71 @@ int vcn, cnum; ntfs_cluster_t cluster; int len, ctype; - startvcn = NTFS_GETU64(data + 0x10); - endvcn = NTFS_GETU64(data + 0x18); - - /* Check whether this chunk really belongs to the end. */ + int er = 0; + startvcn = NTFS_GETS64(data + 0x10); + endvcn = NTFS_GETS64(data + 0x18); + + /* Check whether this chunk really belongs to the end. Problem with + * this: this functions can get called on the last extent first, before + * it is called on the other extents in sequence. This happens when the + * base mft record contains the last extent instead of the first one + * and the first extent is stored, like any intermediate extents in + * extension mft records. This would be difficult to allow the way the + * run list is stored in memory. Thus we fix else where by causing the + * attribute list attribute to be processed immediately when found. The + * extents will then be processed starting with the first one. */ for (cnum = 0, vcn = 0; cnum < attr->d.r.len; cnum++) vcn += attr->d.r.runlist[cnum].len; if (vcn != startvcn) { - ntfs_error("Problem with runlist in extended record\n"); - return -1; + ntfs_debug(DEBUG_FILE3, "ntfs_process_runs: ino = 0x%x, " + "attr->type = 0x%x, startvcn = 0x%x, endvcn = 0x%x, " + "vcn = 0x%x, cnum = 0x%x\n", ino->i_number, attr->type, + startvcn, endvcn, vcn, cnum); + if (vcn < startvcn) { + ntfs_error("Problem with runlist in extended record\n"); + return -1; + } + /* Tried to insert an already inserted run list. */ + return 0; } if (!endvcn) { - endvcn = NTFS_GETU64(data + 0x28) - 1; /* Allocated length. */ - endvcn /= ino->vol->clustersize; + if (!startvcn) { + /* Allocated length. */ + endvcn = NTFS_GETS64(data + 0x28) - 1; + endvcn >>= ino->vol->cluster_size_bits; + } else { + /* This is an extent. Allocated length is not defined! + * Extents must have an endvcn though so this is an + * error. */ + ntfs_error("Corrupt attribute extent. (endvcn is " + "missing)\n"); + return -1; + } } data = data + NTFS_GETU16(data + 0x20); cnum = attr->d.r.len; cluster = 0; for (vcn = startvcn; vcn <= endvcn; vcn += len) { - if (ntfs_decompress_run(&data, &len, &cluster, &ctype)) + if (ntfs_decompress_run(&data, &len, &cluster, &ctype)) { + ntfs_debug(DEBUG_FILE3, "ntfs_process_runs: " + "ntfs_decompress_run failed. i_number = 0x%x\n", + ino->i_number); return -1; + } if (ctype) - ntfs_insert_run(attr, cnum, -1, len); + er = ntfs_insert_run(attr, cnum, -1, len); else - ntfs_insert_run(attr, cnum, cluster, len); + er = ntfs_insert_run(attr, cnum, cluster, len); + if (er) + break; cnum++; } - return 0; + if (er) + ntfs_error("ntfs_process_runs: ntfs_insert_run failed\n"); + ntfs_debug(DEBUG_FILE3, "ntfs_process_runs: startvcn = 0x%x, vcn = 0x%x" + ", endvcn = 0x%x, cnum = %i\n", startvcn, vcn, + endvcn, cnum); + return er; } /* Insert the attribute starting at attr in the inode ino. */ @@ -404,6 +590,8 @@ type = NTFS_GETU32(attrdata); namelen = NTFS_GETU8(attrdata + 9); + ntfs_debug(DEBUG_FILE3, "ntfs_insert_attribute: ino->i_number 0x%x, " + "attr type 0x%x\n", ino->i_number, type); /* Read the attribute's name if it has one. */ if (!namelen) name = 0; @@ -415,25 +603,30 @@ ntfs_memcpy(name, attrdata + NTFS_GETU16(attrdata + 10), 2 * namelen); } - error = ntfs_new_attr(ino, type, name, namelen, &i, &found, 1); + /* If resident look for value, too. */ + if (NTFS_GETU8(attrdata + 8) == 0) + error = ntfs_new_attr(ino, type, name, namelen, + attrdata + NTFS_GETU16(attrdata + 0x14), + NTFS_GETU16(attrdata + 0x10), &i, &found); + else + error = ntfs_new_attr(ino, type, name, namelen, NULL, 0, &i, + &found); if (error) { + ntfs_debug(DEBUG_FILE3, "ntfs_insert_attribute: ntfs_new_attr " + "failed.\n"); if (name) ntfs_free(name); return error; } - /* We can have in one inode two attributes with type 0x00000030 (File - * Name) and without name. FIXME: We can have a lot more than two! - * That is how hard links are implemented. (AIA) */ - if (found && /*FIXME*/ type != ino->vol->at_file_name) - { - ntfs_process_runs(ino, ino->attrs + i, attrdata); + if (found) { + /* It's already there, if not resident just process the runs. */ + if (!ino->attrs[i].resident) { + ntfs_debug(DEBUG_FILE3, "ntfs_insert_attribute:" + " processing runs 1.\n"); + /* FIXME: Check error code! (AIA) */ + ntfs_process_runs(ino, ino->attrs + i, attrdata); + } return 0; - } else if (found) { - /* Don't understand the above, but I know it leaks memory below - * as it overwrites a found entry without freeing it. So here - * we call ntfs_new_attr again but this time ask it to always - * allocate a new entry. */ - ntfs_new_attr(ino, type, name, namelen, &i, &found, 0); } attr = ino->attrs + i; attr->resident = NTFS_GETU8(attrdata + 8) == 0; @@ -449,14 +642,21 @@ ntfs_memcpy(attr->d.data, data, attr->size); attr->indexed = NTFS_GETU16(attrdata + 0x16); } else { - attr->allocated = NTFS_GETU32(attrdata + 0x28); - attr->size = NTFS_GETU32(attrdata + 0x30); - attr->initialized = NTFS_GETU32(attrdata + 0x38); + attr->allocated = NTFS_GETS64(attrdata + 0x28); + attr->size = NTFS_GETS64(attrdata + 0x30); + attr->initialized = NTFS_GETS64(attrdata + 0x38); attr->cengine = NTFS_GETU16(attrdata + 0x22); if (attr->compressed) - attr->compsize = NTFS_GETU32(attrdata + 0x40); + attr->compsize = NTFS_GETS64(attrdata + 0x40); + ntfs_debug(DEBUG_FILE3, "ntfs_insert_attribute: " + "attr->allocated = 0x%Lx, attr->size = 0x%Lx, " + "attr->initialized = 0x%Lx\n", attr->allocated, + attr->size, attr->initialized); ino->attrs[i].d.r.runlist = 0; ino->attrs[i].d.r.len = 0; + ntfs_debug(DEBUG_FILE3, "ntfs_insert_attribute: processing " + "runs 2.\n"); + /* FIXME: Check error code! (AIA) */ ntfs_process_runs(ino, attr, attrdata); } return 0; @@ -477,12 +677,13 @@ } /* Process compressed attributes. */ -int ntfs_read_compressed(ntfs_inode *ino, ntfs_attribute *attr, int offset, +int ntfs_read_compressed(ntfs_inode *ino, ntfs_attribute *attr, __s64 offset, ntfs_io *dest) { int error = 0; - int clustersize, l; - int s_vcn, rnum, vcn, len, chunk, got, l1, offs1, copied; + int clustersizebits; + int s_vcn, rnum, vcn, got, l1; + __s64 copied, len, chunk, offs1, l; ntfs_cluster_t cluster, cl1; char *comp = 0, *comp1; char *decomp = 0; @@ -490,13 +691,13 @@ ntfs_runlist *rl; l = dest->size; - clustersize = ino->vol->clustersize; + clustersizebits = ino->vol->cluster_size_bits; /* Starting cluster of potential chunk. There are three situations: a) In a large uncompressible or sparse chunk, s_vcn is in the middle of a run. b) s_vcn is right on a run border. c) When several runs make a chunk, s_vcn is before the chunks. */ - s_vcn = offset / clustersize; + s_vcn = offset >> clustersizebits; /* Round down to multiple of 16. */ s_vcn &= ~15; rl = attr->d.r.runlist; @@ -517,18 +718,19 @@ copied = 0; while (l) { chunk = 0; - if (cluster == MAX_CLUSTER_T) { + if (cluster == (ntfs_cluster_t)-1) { /* Sparse cluster. */ - int l1; + __s64 l1; if ((len - (s_vcn - vcn)) & 15) ntfs_error("Unexpected sparse chunk size."); - l1 = chunk = min((vcn + len) * clustersize - offset, l); + l1 = chunk = min(((__s64)(vcn + len) << clustersizebits) + - offset, l); error = ntfs_read_zero(dest, l1); if (error) goto out; } else if (dest->do_read) { if (!comp) { - comp = ntfs_malloc(16 * clustersize); + comp = ntfs_malloc(16 << clustersizebits); if (!comp) { error = -ENOMEM; goto out; @@ -541,7 +743,7 @@ do { io.param = comp1; l1 = min(len - max(s_vcn - vcn, 0), 16 - got); - io.size = l1 * clustersize; + io.size = (__s64)l1 << clustersizebits; error = ntfs_getput_clusters(ino->vol, cl1, 0, &io); if (error) @@ -554,16 +756,17 @@ len = rl->len; } got += l1; - comp1 += l1 * clustersize; - } while (cluster != MAX_CLUSTER_T && got < 16); + comp1 += (__s64)l1 << clustersizebits; + } while (cluster != (ntfs_cluster_t)-1 && got < 16); /* Until empty run. */ - chunk = 16 * clustersize; - if (cluster != MAX_CLUSTER_T || got == 16) + chunk = 16 << clustersizebits; + if (cluster != (ntfs_cluster_t)-1 || got == 16) /* Uncompressible */ comp1 = comp; else { if (!decomp) { - decomp = ntfs_malloc(16 * clustersize); + decomp = ntfs_malloc(16 << + clustersizebits); if (!decomp) { error = -ENOMEM; goto out; @@ -575,16 +778,16 @@ ntfs_decompress(decomp, comp, chunk); comp1 = decomp; } - offs1 = offset - s_vcn * clustersize; - chunk = min(16 * clustersize - offs1, chunk); + offs1 = offset - ((__s64)s_vcn << clustersizebits); + chunk = min((16 << clustersizebits) - offs1, chunk); chunk = min(l, chunk); dest->fn_put(dest, comp1 + offs1, chunk); } l -= chunk; copied += chunk; offset += chunk; - s_vcn = offset / clustersize & ~15; - if (l && offset >= ((vcn + len) * clustersize)) { + s_vcn = (offset >> clustersizebits) & ~15; + if (l && offset >= ((__s64)(vcn + len) << clustersizebits)) { rnum++; rl++; vcn += len; @@ -601,7 +804,7 @@ return error; } -int ntfs_write_compressed(ntfs_inode *ino, ntfs_attribute *attr, int offset, +int ntfs_write_compressed(ntfs_inode *ino, ntfs_attribute *attr, __s64 offset, ntfs_io *dest) { return -EOPNOTSUPP; diff -u --recursive --new-file v2.4.6/linux/fs/ntfs/attr.h linux/fs/ntfs/attr.h --- v2.4.6/linux/fs/ntfs/attr.h Wed Apr 18 11:49:13 2001 +++ linux/fs/ntfs/attr.h Mon Jul 16 15:14:10 2001 @@ -1,19 +1,25 @@ -/* attr.h - Header file for attr.c +/* + * attr.h - Header file for attr.c * - * Copyright (C) 1997 Régis Duchesne + * Copyright (C) 1997 Régis Duchesne + * Copyright (c) 2001 Anton Altaparmakov (AIA) */ +#include <linux/nls.h> -int ntfs_extend_attr(ntfs_inode *ino, ntfs_attribute *attr, int *len, +ntfs_u8* ntfs_find_attr_in_mft_rec(ntfs_volume *vol, ntfs_u8 *m, __u32 type, + wchar_t *name, __u32 name_len, int ic, __u16 instance); + +int ntfs_extend_attr(ntfs_inode *ino, ntfs_attribute *attr, __s64 *len, int flags); -int ntfs_resize_attr(ntfs_inode *ino, ntfs_attribute *attr, int newsize); +int ntfs_resize_attr(ntfs_inode *ino, ntfs_attribute *attr, __s64 newsize); int ntfs_insert_attribute(ntfs_inode *ino, unsigned char* attrdata); -int ntfs_read_compressed(ntfs_inode *ino, ntfs_attribute *attr, int offset, +int ntfs_read_compressed(ntfs_inode *ino, ntfs_attribute *attr, __s64 offset, ntfs_io *dest); -int ntfs_write_compressed(ntfs_inode *ino, ntfs_attribute *attr, int offset, +int ntfs_write_compressed(ntfs_inode *ino, ntfs_attribute *attr, __s64 offset, ntfs_io *dest); int ntfs_create_attr(ntfs_inode *ino, int anum, char *aname, void *data, @@ -26,8 +32,8 @@ int ntfs_attr_allnonresident(ntfs_inode *ino); int ntfs_new_attr(ntfs_inode *ino, int type, void *name, int namelen, - int *pos, int *found, int do_search ); + void *value, int value_len, int *pos, int *found); -void ntfs_insert_run(ntfs_attribute *attr, int cnum, ntfs_cluster_t cluster, +int ntfs_insert_run(ntfs_attribute *attr, int cnum, ntfs_cluster_t cluster, int len ); diff -u --recursive --new-file v2.4.6/linux/fs/ntfs/dir.c linux/fs/ntfs/dir.c --- v2.4.6/linux/fs/ntfs/dir.c Wed Apr 18 11:49:13 2001 +++ linux/fs/ntfs/dir.c Mon Jul 16 15:14:10 2001 @@ -1,9 +1,10 @@ -/* dir.c +/* + * dir.c * - * Copyright (C) 1995-1997, 1999 Martin von Löwis - * Copyright (C) 1999 Steve Dodd - * Copyright (C) 1999 Joseph Malicki - * Copyright (C) 2001 Anton Altaparmakov (AIA) + * Copyright (C) 1995-1997, 1999 Martin von Löwis + * Copyright (C) 1999 Steve Dodd + * Copyright (C) 1999 Joseph Malicki + * Copyright (C) 2001 Anton Altaparmakov (AIA) */ #include "ntfstypes.h" @@ -17,8 +18,9 @@ #include "attr.h" #include "support.h" #include "util.h" +#include <linux/smp_lock.h> -static char I30[]="$I30"; +static char I30[] = "$I30"; /* An index record should start with INDX, and the last word in each block * should contain the check value. If it passes, the original values need to @@ -104,9 +106,13 @@ return (int)(NTFS_GETU8(entry + 12) & 2) == 0; } +/* + * Removed RACE for allocating index blocks. But stil not too happy. + * There might be more races afterwards. (AIA) + */ static int ntfs_allocate_index_block(ntfs_iterate_s *walk) { - ntfs_attribute *allocation = 0, *bitmap = 0; + ntfs_attribute *allocation, *bitmap = 0; int error, size, i, bit; ntfs_u8 *bmap; ntfs_io io; @@ -120,68 +126,82 @@ error = ntfs_create_attr(walk->dir, vol->at_index_allocation, I30, 0, 0, &allocation); if (error) - return error; + goto err_ret; ntfs_bzero(bmp, sizeof(bmp)); error = ntfs_create_attr(walk->dir, vol->at_bitmap, I30, bmp, sizeof(bmp), &bitmap); if (error) - return error; + goto err_ret; } else bitmap = ntfs_find_attr(walk->dir, vol->at_bitmap, I30); if (!bitmap) { ntfs_error("Directory w/o bitmap\n"); - return -EINVAL; + error = -EINVAL; + goto err_ret; } size = bitmap->size; bmap = ntfs_malloc(size); - if (!bmap) - return -ENOMEM; + if (!bmap) { + error = -ENOMEM; + goto err_ret; + } io.fn_put = ntfs_put; io.fn_get = ntfs_get; +try_again: io.param = bmap; io.size = size; error = ntfs_read_attr(walk->dir, vol->at_bitmap, I30, 0, &io); - if (error) { - ntfs_free(bmap); - return error; - } - if (io.size != size) { - ntfs_free(bmap); - return -EIO; - } + if (error || (io.size != size && (error = -EIO, 1))) + goto err_fb_out; /* Allocate a bit. */ - for (i = bit = 0; i < size; i++) { + for (bit = i = 0; i < size; i++) { if (bmap[i] == 0xFF) continue; - for (bit = 0; bit < 8; bit++) - if (((bmap[i] >> bit) & 1) == 0) - break; - if (bit != 8) + bit = ffz(bmap[i]); + if (bit < 8) break; } - if (i == size) + if (i >= size) { /* FIXME: Extend bitmap. */ - return -EOPNOTSUPP; - walk->newblock = (i * 8 + bit) * walk->dir->u.index.clusters_per_record; - bmap[i] |= 1 << bit; + error = -EOPNOTSUPP; + goto err_fb_out; + } + /* Get the byte containing our bit again, now taking the BKL. */ io.param = bmap; - io.size = size; - error = ntfs_write_attr(walk->dir, vol->at_bitmap, I30, 0, &io); - if (error || io.size != size) { - ntfs_free(bmap); - return error ? error : -EIO; + io.size = 1; + lock_kernel(); + error = ntfs_read_attr(walk->dir, vol->at_bitmap, I30, i, &io); + if (error || (io.size != 1 && (error = -EIO, 1))) + goto err_unl_out; + if (ntfs_test_and_set_bit(bmap, bit)) { + unlock_kernel(); + /* Give other process(es) a chance to finish. */ + schedule(); + goto try_again; } + walk->newblock = (i * 8 + bit) * walk->dir->u.index.clusters_per_record; + io.param = bmap; + error = ntfs_write_attr(walk->dir, vol->at_bitmap, I30, i, &io); + if (error || (io.size != size && (error = -EIO, 1))) + goto err_unl_out; + /* Change inode on disk, required when bitmap is resident. */ + error = ntfs_update_inode(walk->dir); + if (error) + goto err_unl_out; + unlock_kernel(); ntfs_free(bmap); /* Check whether record is out of allocated range. */ size = allocation->size; - if (walk->newblock * vol->clustersize >= size) { + if (walk->newblock * vol->cluster_size >= size) { /* Build index record. */ - int s1 = walk->dir->u.index.recordsize; - int nr_fix = s1/vol->blocksize + 1; int hsize; + int s1 = walk->dir->u.index.recordsize; + int nr_fix = (s1 >> vol->sector_size) + 1; char *record = ntfs_malloc(s1); - if (!record) - return -ENOMEM; + if (!record) { + error = -ENOMEM; + goto err_ret; + } ntfs_bzero(record, s1); /* Magic */ ntfs_memcpy(record, "INDX", 4); @@ -205,13 +225,20 @@ io.size = s1; io.do_read = 0; error = ntfs_readwrite_attr(walk->dir, allocation, size, &io); - if (error || io.size != s1) { - ntfs_free(record); - return error ? error : -EIO; - } ntfs_free(record); + if (error || (io.size != s1 && (error = -EIO, 1))) + goto err_ret; + error = ntfs_update_inode(walk->dir); + if (error) + goto err_ret; } return 0; +err_unl_out: + unlock_kernel(); +err_fb_out: + ntfs_free(bmap); +err_ret: + return error; } /* Write an index block (root or allocation) back to storage. @@ -227,30 +254,27 @@ io.fn_put = 0; io.fn_get = ntfs_get; io.param = buf; - if (block == -1) { + if (block == -1) { /* Index root. */ NTFS_PUTU16(buf + 0x14, used - 0x10); /* 0x18 is a copy thereof. */ NTFS_PUTU16(buf + 0x18, used - 0x10); io.size = used; error = ntfs_write_attr(walk->dir, vol->at_index_root, I30, 0, &io); - if (error) + if (error || (io.size != used && (error = -EIO, 1))) return error; - if (io.size != used) - return -EIO; /* Shrink if necessary. */ a = ntfs_find_attr(walk->dir, vol->at_index_root, I30); ntfs_resize_attr(walk->dir, a, used); } else { NTFS_PUTU16(buf + 0x1C, used - 0x18); - ntfs_insert_fixups(buf, vol->blocksize); + ntfs_insert_fixups(buf, vol->sector_size); io.size = walk->dir->u.index.recordsize; error = ntfs_write_attr(walk->dir, vol->at_index_allocation, - I30, block*vol->clustersize, &io); - if (error) + I30, (__s64)block << vol->cluster_size_bits, &io); + if (error || (io.size != walk->dir->u.index.recordsize && + (error = -EIO, 1))) return error; - if (io.size != walk->dir->u.index.recordsize) - return -EIO; } return 0; } @@ -277,19 +301,19 @@ for (prev = entry; entry - start < usize / 2; entry += NTFS_GETU16(entry + 8)) prev = entry; - newbuf = ntfs_malloc(vol->index_recordsize); + newbuf = ntfs_malloc(vol->index_record_size); if (!newbuf) return -ENOMEM; io.fn_put = ntfs_put; io.fn_get = ntfs_get; io.param = newbuf; - io.size = vol->index_recordsize; + io.size = vol->index_record_size; /* Read in old header. FIXME: Reading everything is overkill. */ error = ntfs_read_attr(walk->dir, vol->at_index_allocation, I30, - walk->newblock * vol->clustersize, &io); + (__s64)walk->newblock << vol->cluster_size_bits, &io); if (error) goto out; - if (io.size != vol->index_recordsize) { + if (io.size != vol->index_record_size) { error = -EIO; goto out; } @@ -355,7 +379,7 @@ int do_split = 0; offset = entry - start; if (walk->block == -1) { /* index root */ - blocksize = walk->dir->vol->mft_recordsize; + blocksize = walk->dir->vol->mft_record_size; usedsize = NTFS_GETU16(start + 0x14) + 0x10; } else { blocksize = walk->dir->u.index.recordsize; @@ -399,7 +423,7 @@ ra = ntfs_find_attr(ino, ino->vol->at_index_root, I30); if (!ra) return -E2BIG; - bsize = ino->vol->mft_recordsize; + bsize = ino->vol->mft_record_size; root = ntfs_malloc(bsize); if (!root) return -E2BIG; @@ -418,7 +442,7 @@ error = -E2BIG; goto out; } - index = ntfs_malloc(ino->vol->index_recordsize); + index = ntfs_malloc(ino->vol->index_record_size); if (!index) { error = -ENOMEM; goto out; @@ -432,9 +456,9 @@ goto out; /* Write old root to new index block. */ io.param = index; - io.size = ino->vol->index_recordsize; + io.size = ino->vol->index_record_size; error = ntfs_read_attr(ino, ino->vol->at_index_allocation, I30, - walk.newblock * ino->vol->clustersize, &io); + (__s64)walk.newblock << ino->vol->cluster_size_bits, &io); if (error) goto out; isize = NTFS_GETU16(root + 0x18) - 0x10; @@ -460,10 +484,10 @@ } /* The entry has been found. Copy the result in the caller's buffer */ -static int ntfs_copyresult(char *dest,char *source) +static int ntfs_copyresult(char *dest, char *source) { - int length=NTFS_GETU16(source+8); - ntfs_memcpy(dest,source,length); + int length = NTFS_GETU16(source + 8); + ntfs_memcpy(dest, source, length); return 1; } @@ -521,7 +545,7 @@ io.size = length; /* Read the block from the index allocation attribute. */ error = ntfs_read_attr(walk->dir, walk->dir->vol->at_index_allocation, - I30, block * walk->dir->vol->clustersize, &io); + I30, (__s64)block << walk->dir->vol->cluster_size_bits, &io); if (error || io.size != length) { ntfs_error("read failed\n"); ntfs_free(record); @@ -546,7 +570,7 @@ static int ntfs_descend(ntfs_iterate_s *walk, ntfs_u8 *start, ntfs_u8 *entry) { int length = NTFS_GETU16(entry + 8); - int nextblock=NTFS_GETU32(entry+length-8); + int nextblock = NTFS_GETU32(entry + length - 8); int error; if (!ntfs_entry_has_subnodes(entry)) { @@ -649,23 +673,21 @@ switch (walk->type) { case BY_NAME: switch (cmp) { - case -1: - return ntfs_entry_has_subnodes(entry) ? - ntfs_descend(walk,start,entry) : - 0; - case 0: - return ntfs_copyresult(walk->result, - entry); - case 1: - break; + case -1: + return ntfs_entry_has_subnodes(entry) ? + ntfs_descend(walk, start, entry) : 0; + case 0: + return ntfs_copyresult(walk->result, entry); + case 1: + break; } break; case DIR_INSERT: switch (cmp) { case -1: return ntfs_entry_has_subnodes(entry) ? - ntfs_descend(walk, start, entry) : - ntfs_dir_insert(walk, start, entry); + ntfs_descend(walk, start, entry) : + ntfs_dir_insert(walk, start, entry); case 0: return -EEXIST; case 1: @@ -712,7 +734,7 @@ * entry to the result buffer. */ int ntfs_getdir(ntfs_iterate_s* walk) { - int length = walk->dir->vol->mft_recordsize; + int length = walk->dir->vol->mft_record_size; int retval, error; /* Start at the index root. */ char *root = ntfs_malloc(length); @@ -782,7 +804,7 @@ ntfs_debug(DEBUG_DIR3, "unsorted 1\n"); /* Are we still in the index root? */ if (*p_high == 0) { - buf = ntfs_malloc(length = vol->mft_recordsize); + buf = ntfs_malloc(length = vol->mft_record_size); if (!buf) return -ENOMEM; io.fn_put = ntfs_put; @@ -808,7 +830,7 @@ /* 0 is index root, index allocation starts with 4. */ block = *p_high - ino->u.index.clusters_per_record; error = ntfs_read_attr(ino, vol->at_index_allocation, I30, - block*vol->clustersize, &io); + (__s64)block << vol->cluster_size_bits, &io); if (!error && io.size != length) error = -EIO; if (error) { @@ -873,7 +895,7 @@ } attr = ntfs_find_attr(ino, vol->at_index_allocation, I30); while (1) { - if (*p_high * vol->clustersize > attr->size) { + if ((__s64)*p_high << vol->cluster_size_bits > attr->size) { /* No more index records. */ *p_high = 0xFFFFFFFF; ntfs_free(buf); @@ -882,7 +904,7 @@ } *p_high += ino->u.index.clusters_per_record; byte = *p_high / ino->u.index.clusters_per_record - 1; - bit = 1 << (byte & 7); + bit = 1 << (byte & 7); byte = byte >> 3; /* This record is allocated. */ if (buf[byte] & bit) @@ -907,16 +929,17 @@ ndata = name->d.data; walk.name = (ntfs_u16*)(ndata + 0x42); walk.namelen = NTFS_GETU8(ndata + 0x40); - walk.new_entry_size = esize = ((nsize + 0x18) / 8) * 8; + walk.new_entry_size = esize = (nsize + 0x10 + 7) & ~7; walk.new_entry = entry = ntfs_malloc(esize); if (!entry) return -ENOMEM; - ntfs_bzero(entry, esize); NTFS_PUTINUM(entry, new); NTFS_PUTU16(entry + 0x8, esize); /* Size of entry. */ NTFS_PUTU16(entry + 0xA, nsize); /* Size of original name attribute. */ - NTFS_PUTU32(entry + 0xC, 0); /* FIXME: D-F? */ + NTFS_PUTU16(entry + 0xC, 0); /* Flags. */ + NTFS_PUTU16(entry + 0xE, 0); /* Reserved. */ ntfs_memcpy(entry + 0x10, ndata, nsize); + ntfs_bzero(entry + 0x10 + nsize, esize - 0x10 - nsize); error = ntfs_getdir(&walk); if (walk.new_entry) ntfs_free(walk.new_entry); @@ -972,11 +995,11 @@ char name[10]; NTFS_PUTU32(data, type); - /* FIXME: ??? */ + /* Collation rule. 1 == COLLATION_FILENAME */ NTFS_PUTU32(data + 4, 1); - NTFS_PUTU32(data + 8, ino->vol->index_recordsize); + NTFS_PUTU32(data + 8, ino->vol->index_record_size); NTFS_PUTU32(data + 0xC, ino->vol->index_clusters_per_record); - /* FXIME: ??? */ + /* Byte offset to first INDEX_ENTRY. */ NTFS_PUTU32(data + 0x10, 0x10); /* Size of entries, including header. */ NTFS_PUTU32(data + 0x14, 0x20); @@ -1012,7 +1035,7 @@ error = ntfs_update_inode(dir); if (error) goto out; - error = ntfs_update_inode (result); + error = ntfs_update_inode(result); if (error) goto out; out: diff -u --recursive --new-file v2.4.6/linux/fs/ntfs/dir.h linux/fs/ntfs/dir.h --- v2.4.6/linux/fs/ntfs/dir.h Wed Apr 18 11:49:13 2001 +++ linux/fs/ntfs/dir.h Mon Jul 16 15:14:10 2001 @@ -1,8 +1,8 @@ -/* dir.h - Header file for dir.c +/* + * dir.h - Header file for dir.c * - * Copyright (C) 1997 Régis Duchesne + * Copyright (C) 1997 Régis Duchesne */ - #define ITERATE_SPLIT_DONE 1 enum ntfs_iterate_e { @@ -12,7 +12,7 @@ }; /* not all fields are used for all operations */ -typedef struct ntfs_iterate_s{ +typedef struct ntfs_iterate_s { enum ntfs_iterate_e type; ntfs_inode *dir; union{ diff -u --recursive --new-file v2.4.6/linux/fs/ntfs/fs.c linux/fs/ntfs/fs.c --- v2.4.6/linux/fs/ntfs/fs.c Wed Apr 18 11:49:13 2001 +++ linux/fs/ntfs/fs.c Mon Jul 16 15:14:10 2001 @@ -1,9 +1,13 @@ -/* fs.c - NTFS driver for Linux 2.4.x +/* + * fs.c - NTFS driver for Linux 2.4.x + * + * Development has as of recently (since June '01) been sponsored + * by Legato Systems, Inc. (http://www.legato.com) * - * Copyright (C) 1995-1997, 1999 Martin von Löwis - * Copyright (C) 1996 Richard Russon - * Copyright (C) 1996-1997 Régis Duchesne - * Copyright (C) 2000-2001, Anton Altaparmakov (AIA) + * Copyright (C) 1995-1997, 1999 Martin von Löwis + * Copyright (C) 1996 Richard Russon + * Copyright (C) 1996-1997 Régis Duchesne + * Copyright (C) 2000-2001, Anton Altaparmakov (AIA) */ #include <linux/config.h> @@ -19,12 +23,15 @@ #include "sysctl.h" #include <linux/module.h> #include <asm/uaccess.h> -#include <linux/nls.h> #include <linux/locks.h> #include <linux/init.h> #include <linux/smp_lock.h> #include <asm/page.h> +#ifndef NLS_MAX_CHARSET_SIZE +#include <linux/nls.h> +#endif + /* Forward declarations. */ static struct inode_operations ntfs_dir_inode_operations; static struct file_operations ntfs_dir_operations; @@ -55,6 +62,7 @@ } #endif +/* loff_t is 64 bit signed, so is cool. */ static ssize_t ntfs_read(struct file *filp, char *buf, size_t count,loff_t *off) { int error; @@ -64,20 +72,28 @@ /* Inode is not properly initialized. */ if (!ino) return -EINVAL; - ntfs_debug(DEBUG_OTHER, "ntfs_read %x,%x,%x ->", - (unsigned)ino->i_number, (unsigned)*off, (unsigned)count); + ntfs_debug(DEBUG_OTHER, "ntfs_read %x, %Lx, %x ->", + (unsigned)ino->i_number, (unsigned long long)*off, + (unsigned)count); /* Inode has no unnamed data attribute. */ - if(!ntfs_find_attr(ino, ino->vol->at_data, NULL)) + if(!ntfs_find_attr(ino, ino->vol->at_data, NULL)) { + ntfs_debug(DEBUG_OTHER, "ntfs_read: $DATA not found!\n"); return -EINVAL; + } /* Read the data. */ io.fn_put = ntfs_putuser; io.fn_get = 0; io.param = buf; io.size = count; error = ntfs_read_attr(ino, ino->vol->at_data, NULL, *off, &io); - if (error && !io.size) + if (error && !io.size) { + ntfs_debug(DEBUG_OTHER, "ntfs_read: read_attr failed with " + "error %i, io size %u.\n", error, io.size); return error; + } *off += io.size; + ntfs_debug(DEBUG_OTHER, "ntfs_read: finished. read %u bytes.\n", + io.size); return io.size; } @@ -326,6 +342,13 @@ if (!simple_getbool(value, &val)) goto needs_bool; vol->ngt = val ? ngt_posix : ngt_nt; + } else if (strcmp(opt, "show_sys_files") == 0) { + int val = 0; + if (!value || !*value) + val = 1; + else if (!simple_getbool(value, &val)) + goto needs_bool; + vol->ngt = val ? ngt_full : ngt_nt; } else if (strcmp(opt, "utf8") == 0) { int val = 0; if (!value || !*value) @@ -433,8 +456,13 @@ ino = NTFS_LINO2NINO(r); error = ntfs_alloc_file(NTFS_LINO2NINO(dir), ino, (char*)d->d_name.name, d->d_name.len); - if (error) + if (error) { + ntfs_error("ntfs_alloc_file FAILED: error = %i", error); goto fail; + } + /* Not doing this one was causing a huge amount of corruption! Now the + * bugger bytes the dust! (-8 (AIA) */ + r->i_ino = ino->i_number; error = ntfs_update_inode(ino); if (error) goto fail; @@ -491,6 +519,9 @@ ino); if (error) goto out; + /* Not doing this one was causing a huge amount of corruption! Now the + * bugger bytes the dust! (-8 (AIA) */ + r->i_ino = ino->i_number; r->i_uid = vol->uid; r->i_gid = vol->gid; si = ntfs_find_attr(ino, vol->at_standard_information, NULL); @@ -608,19 +639,75 @@ vol = NTFS_INO2VOL(inode); inode->i_mode = 0; - ntfs_debug(DEBUG_OTHER, "ntfs_read_inode %x\n", (unsigned)inode->i_ino); + ntfs_debug(DEBUG_OTHER, "ntfs_read_inode 0x%x\n", (unsigned)inode->i_ino); + /* + * This kills all accesses to system files (except $Extend directory). + * The driver can bypass this by calling ntfs_init_inode() directly. + * Only if ngt is ngt_full do we allow access to the system files. + */ switch (inode->i_ino) { /* Those are loaded special files. */ case FILE_$Mft: - ntfs_error("Trying to open MFT\n"); - return; + if (vol->ngt != ngt_full) { + ntfs_error("Trying to open $MFT!\n"); + return; + } + if (!vol->mft_ino || ((vol->ino_flags & 1) == 0)) + goto sys_file_error; + ntfs_memcpy(&inode->u.ntfs_i, vol->mft_ino, sizeof(ntfs_inode)); + ino = vol->mft_ino; + vol->mft_ino = &inode->u.ntfs_i; + vol->ino_flags &= ~1; + ntfs_free(ino); + ino = vol->mft_ino; + ntfs_debug(DEBUG_OTHER, "Opening $MFT!\n"); + break; + case FILE_$MftMirr: + if (vol->ngt != ngt_full) { + ntfs_error("Trying to open $MFTMirr!\n"); + return; + } + if (!vol->mftmirr || ((vol->ino_flags & 2) == 0)) + goto sys_file_error; + ntfs_memcpy(&inode->u.ntfs_i, vol->mftmirr, sizeof(ntfs_inode)); + ino = vol->mftmirr; + vol->mftmirr = &inode->u.ntfs_i; + vol->ino_flags &= ~2; + ntfs_free(ino); + ino = vol->mftmirr; + ntfs_debug(DEBUG_OTHER, "Opening $MFTMirr!\n"); + break; + case FILE_$BitMap: + if (vol->ngt != ngt_full) { + ntfs_error("Trying to open $Bitmap!\n"); + return; + } + if (!vol->bitmap || ((vol->ino_flags & 4) == 0)) + goto sys_file_error; + ntfs_memcpy(&inode->u.ntfs_i, vol->bitmap, sizeof(ntfs_inode)); + ino = vol->bitmap; + vol->bitmap = &inode->u.ntfs_i; + vol->ino_flags &= ~4; + ntfs_free(ino); + ino = vol->bitmap; + ntfs_debug(DEBUG_OTHER, "Opening $Bitmap!\n"); + break; + case FILE_$LogFile ... FILE_$AttrDef: + /* We need to allow reading the root directory. */ + case FILE_$Boot ... FILE_$UpCase: + if (vol->ngt != ngt_full) { + ntfs_error("Trying to open system file %i!\n", + inode->i_ino); + return; + } /* Do the default for ngt_full. */ + ntfs_debug(DEBUG_OTHER, "Opening system file %i!\n", inode->i_ino); default: ino = &inode->u.ntfs_i; if (!ino || ntfs_init_inode(ino, NTFS_INO2VOL(inode), inode->i_ino)) { - ntfs_debug(DEBUG_OTHER, "NTFS :Error loading inode " - "%x\n", (unsigned int)inode->i_ino); + ntfs_debug(DEBUG_OTHER, "NTFS: Error loading inode " + "0x%x\n", (unsigned int)inode->i_ino); return; } } @@ -641,7 +728,7 @@ can_mmap = 0; } /* Get the file modification times from the standard information. */ - si = ntfs_find_attr(ino,vol->at_standard_information, NULL); + si = ntfs_find_attr(ino, vol->at_standard_information, NULL); if (si) { char *attr = si->d.data; inode->i_atime = ntfs_ntutc2unixutc(NTFS_GETU64(attr + 0x18)); @@ -678,24 +765,85 @@ inode->i_mode |= S_IWUGO; #endif inode->i_mode &= ~vol->umask; + return; +sys_file_error: + ntfs_error("Critical error. Tried to call ntfs_read_inode() before we " + "have completed read_super() or VFS error.\n"); + // FIXME: Should we panic() at this stage? } #ifdef CONFIG_NTFS_RW static void ntfs_write_inode(struct inode *ino, int unused) { lock_kernel(); - ntfs_debug(DEBUG_LINUX, "ntfs_write_inode %x\n", ino->i_ino); + ntfs_debug(DEBUG_LINUX, "ntfs_write_inode 0x%x\n", ino->i_ino); ntfs_update_inode(NTFS_LINO2NINO(ino)); unlock_kernel(); } #endif -static void _ntfs_clear_inode(struct inode *ino) +static void _ntfs_clear_inode(struct inode *inode) { + ntfs_inode *ino; + ntfs_volume *vol; + lock_kernel(); - ntfs_debug(DEBUG_OTHER, "ntfs_clear_inode %lx\n", ino->i_ino); - if (ino->i_ino != FILE_$Mft) - ntfs_clear_inode(&ino->u.ntfs_i); + ntfs_debug(DEBUG_OTHER, "_ntfs_clear_inode 0x%x\n", inode->i_ino); + vol = NTFS_INO2VOL(inode); + if (!vol) + ntfs_error("_ntfs_clear_inode: vol = NTFS_INO2VOL(inode) is NULL.\n"); + switch (inode->i_ino) { + case FILE_$Mft: + if (vol->ngt != ngt_full) { + ntfs_error("Trying to _clear_inode of $MFT!\n"); + goto unl_out; + } + if (vol->mft_ino && ((vol->ino_flags & 1) == 0)) { + ino = (ntfs_inode*)ntfs_malloc(sizeof(ntfs_inode)); + ntfs_memcpy(ino, &inode->u.ntfs_i, sizeof(ntfs_inode)); + vol->mft_ino = ino; + vol->ino_flags |= 1; + goto unl_out; + } + break; + case FILE_$MftMirr: + if (vol->ngt != ngt_full) { + ntfs_error("Trying to _clear_inode of $MFTMirr!\n"); + goto unl_out; + } + if (vol->mftmirr && ((vol->ino_flags & 2) == 0)) { + ino = (ntfs_inode*)ntfs_malloc(sizeof(ntfs_inode)); + ntfs_memcpy(ino, &inode->u.ntfs_i, sizeof(ntfs_inode)); + vol->mftmirr = ino; + vol->ino_flags |= 2; + goto unl_out; + } + break; + case FILE_$BitMap: + if (vol->ngt != ngt_full) { + ntfs_error("Trying to _clear_inode of $Bitmap!\n"); + goto unl_out; + } + if (vol->bitmap && ((vol->ino_flags & 4) == 0)) { + ino = (ntfs_inode*)ntfs_malloc(sizeof(ntfs_inode)); + ntfs_memcpy(ino, &inode->u.ntfs_i, sizeof(ntfs_inode)); + vol->bitmap = ino; + vol->ino_flags |= 4; + goto unl_out; + } + break; + case FILE_$LogFile ... FILE_$AttrDef: + case FILE_$Boot ... FILE_$UpCase: + if (vol->ngt != ngt_full) { + ntfs_error("Trying to _clear_inode of system file %i! " + "Shouldn't happen.\n", inode->i_ino); + goto unl_out; + } /* Do the default for ngt_full. */ + default: + /* Nothing. Just clear the inode and exit. */ + } + ntfs_clear_inode(&inode->u.ntfs_i); +unl_out: unlock_kernel(); return; } @@ -718,25 +866,29 @@ { struct inode *mft; ntfs_volume *vol; - ntfs_u64 size; + __s64 size; int error; ntfs_debug(DEBUG_OTHER, "ntfs_statfs\n"); vol = NTFS_SB2VOL(sb); sf->f_type = NTFS_SUPER_MAGIC; - sf->f_bsize = vol->clustersize; + sf->f_bsize = vol->cluster_size; error = ntfs_get_volumesize(NTFS_SB2VOL(sb), &size); if (error) return error; sf->f_blocks = size; /* Volumesize is in clusters. */ - sf->f_bfree = ntfs_get_free_cluster_count(vol->bitmap); - sf->f_bavail = sf->f_bfree; + size = (__s64)ntfs_get_free_cluster_count(vol->bitmap); + /* Just say zero if the call failed. */ + if (size < 0LL) + size = 0; + sf->f_bfree = sf->f_bavail = size; + ntfs_debug(DEBUG_OTHER, "ntfs_statfs: calling mft = iget(sb, FILE_$Mft)\n"); mft = iget(sb, FILE_$Mft); + ntfs_debug(DEBUG_OTHER, "ntfs_statfs: iget(sb, FILE_$Mft) returned 0x%x\n", mft); if (!mft) return -EIO; - /* So ... we lie... thus this following cast of loff_t value is ok - * here.. */ - sf->f_files = (unsigned long)mft->i_size / vol->mft_recordsize; + sf->f_files = mft->i_size >> vol->mft_record_size_bits; + ntfs_debug(DEBUG_OTHER, "ntfs_statfs: calling iput(mft)\n"); iput(mft); /* Should be read from volume. */ sf->f_namelen = 255; @@ -763,6 +915,77 @@ clear_inode: _ntfs_clear_inode, }; +/** + * is_boot_sector_ntfs - check an NTFS boot sector for validity + * @b: buffer containing bootsector to check + * + * Check whether @b contains a valid NTFS boot sector. + * Return 1 if @b is a valid NTFS bootsector or 0 if not. + */ +static int is_boot_sector_ntfs(ntfs_u8 *b) +{ + ntfs_u32 i; + + /* FIXME: We don't use checksumming yet as NT4(SP6a) doesn't either... + * But we might as well have the code ready to do it. (AIA) */ +#if 0 + /* Calculate the checksum. */ + if (b < b + 0x50) { + ntfs_u32 *u; + ntfs_u32 *bi = (ntfs_u32 *)(b + 0x50); + + for (u = bi, i = 0; u < bi; ++u) + i += NTFS_GETU32(*u); + } +#endif + /* Check magic is "NTFS " */ + if (b[3] != 0x4e) goto not_ntfs; + if (b[4] != 0x54) goto not_ntfs; + if (b[5] != 0x46) goto not_ntfs; + if (b[6] != 0x53) goto not_ntfs; + for (i = 7; i < 0xb; ++i) + if (b[i] != 0x20) goto not_ntfs; + /* Check bytes per sector value is between 512 and 4096. */ + if (b[0xb] != 0) goto not_ntfs; + if (b[0xc] > 0x10) goto not_ntfs; + /* Check sectors per cluster value is valid. */ + switch (b[0xd]) { + case 1: case 2: case 4: case 8: case 16: + case 32: case 64: case 128: + break; + default: + goto not_ntfs; + } + /* Check reserved sectors value and four other fields are zero. */ + for (i = 0xe; i < 0x15; ++i) + if (b[i] != 0) goto not_ntfs; + if (b[0x16] != 0) goto not_ntfs; + if (b[0x17] != 0) goto not_ntfs; + for (i = 0x20; i < 0x24; ++i) + if (b[i] != 0) goto not_ntfs; + /* Check clusters per file record segment value is valid. */ + if (b[0x40] < 0xe1 || b[0x40] > 0xf7) { + switch (b[0x40]) { + case 1: case 2: case 4: case 8: case 16: case 32: case 64: + break; + default: + goto not_ntfs; + } + } + /* Check clusters per index block value is valid. */ + if (b[0x44] < 0xe1 || b[0x44] > 0xf7) { + switch (b[0x44]) { + case 1: case 2: case 4: case 8: case 16: case 32: case 64: + break; + default: + goto not_ntfs; + } + } + return 1; +not_ntfs: + return 0; +} + /* Called to mount a filesystem by read_super() in fs/super.c. * Return a super block, the main structure of a filesystem. * @@ -782,10 +1005,6 @@ vol = NTFS_SB2VOL(sb); if (!parse_options(vol, (char*)options)) goto ntfs_read_super_vol; -#if 0 - /* Set to read only, user option might reset it */ - sb->s_flags |= MS_RDONLY; -#endif /* Assume a 512 bytes block device for now. */ set_blocksize(sb->s_dev, 512); /* Read the super block (boot block). */ @@ -795,50 +1014,49 @@ } ntfs_debug(DEBUG_OTHER, "Done reading boot block\n"); /* Check for 'NTFS' magic number */ - if (!IS_NTFS_VOLUME(bh->b_data)) { + if (!is_boot_sector_ntfs(bh->b_data)) { ntfs_debug(DEBUG_OTHER, "Not a NTFS volume\n"); - brelse(bh); + bforget(bh); goto ntfs_read_super_unl; } ntfs_debug(DEBUG_OTHER, "Going to init volume\n"); if (ntfs_init_volume(vol, bh->b_data) < 0) { ntfs_debug(DEBUG_OTHER, "Init volume failed.\n"); - brelse(bh); + bforget(bh); goto ntfs_read_super_unl; } - ntfs_debug(DEBUG_OTHER, "$Mft at cluster 0x%Lx\n", vol->mft_cluster); - brelse(bh); + ntfs_debug(DEBUG_OTHER, "$Mft at cluster 0x%Lx\n", vol->mft_lcn); + bforget(bh); NTFS_SB(vol) = sb; - ntfs_debug(DEBUG_OTHER, "Done to init volume\n"); - /* Inform the kernel that a device block is a NTFS cluster. */ - sb->s_blocksize = vol->clustersize; - if (sb->s_blocksize > PAGE_SIZE) { - ntfs_error("Partition cluster size is not supported yet (too " - "large for kernel blocksize).\n"); + if (vol->cluster_size > PAGE_SIZE) { + ntfs_error("Partition cluster size is not supported yet (it " + "is > max kernel blocksize).\n"); goto ntfs_read_super_unl; } + ntfs_debug(DEBUG_OTHER, "Done to init volume\n"); + /* Inform the kernel that a device block is a NTFS cluster. */ + sb->s_blocksize = vol->cluster_size; for (i = sb->s_blocksize, sb->s_blocksize_bits = 0; i != 1; i >>= 1) sb->s_blocksize_bits++; set_blocksize(sb->s_dev, sb->s_blocksize); ntfs_debug(DEBUG_OTHER, "set_blocksize\n"); - - /* Allocate a MFT record (MFT record can be smaller than a cluster). */ - if (!(vol->mft = ntfs_malloc(max(vol->mft_recordsize, - vol->clustersize)))) + /* Allocate an MFT record (MFT record can be smaller than a cluster). */ + if (!(vol->mft = ntfs_malloc(max(vol->mft_record_size, + vol->cluster_size)))) goto ntfs_read_super_unl; /* Read at least the MFT record for $Mft. */ for (i = 0; i < max(vol->mft_clusters_per_record, 1); i++) { - if (!(bh = bread(sb->s_dev, vol->mft_cluster + i, - vol->clustersize))) { + if (!(bh = bread(sb->s_dev, vol->mft_lcn + i, + vol->cluster_size))) { ntfs_error("Could not read $Mft record 0\n"); goto ntfs_read_super_mft; } - ntfs_memcpy(vol->mft + i * vol->clustersize, bh->b_data, - vol->clustersize); + ntfs_memcpy(vol->mft + ((__s64)i << vol->cluster_size_bits), + bh->b_data, vol->cluster_size); brelse(bh); - ntfs_debug(DEBUG_OTHER, "Read cluster %x\n", - vol->mft_cluster + i); + ntfs_debug(DEBUG_OTHER, "Read cluster 0x%x\n", + vol->mft_lcn + i); } /* Check and fixup this MFT record */ if (!ntfs_check_mft_record(vol, vol->mft)){ @@ -848,7 +1066,7 @@ /* Inform the kernel about which super operations are available. */ sb->s_op = &ntfs_super_operations; sb->s_magic = NTFS_SUPER_MAGIC; - sb->s_maxbytes = ~0ULL; + sb->s_maxbytes = ~0ULL >> 1; ntfs_debug(DEBUG_OTHER, "Reading special files\n"); if (ntfs_load_special_files(vol)) { ntfs_error("Error loading special files\n"); @@ -860,14 +1078,15 @@ ntfs_error("Could not get root dir inode\n"); goto ntfs_read_super_mft; } +ntfs_read_super_ret: ntfs_debug(DEBUG_OTHER, "read_super: done\n"); return sb; ntfs_read_super_mft: ntfs_free(vol->mft); ntfs_read_super_unl: ntfs_read_super_vol: - ntfs_debug(DEBUG_OTHER, "read_super: done\n"); - return NULL; + sb = NULL; + goto ntfs_read_super_ret; } /* Define the filesystem */ @@ -894,7 +1113,11 @@ } EXPORT_NO_SYMBOLS; -MODULE_AUTHOR("Martin von Löwis"); +/* + * Not strictly true. The driver was written originally by Martin von Löwis. + * I am just maintaining and rewriting it. + */ +MODULE_AUTHOR("Anton Altaparmakov <aia21@cus.cam.ac.uk>"); MODULE_DESCRIPTION("NTFS driver"); #ifdef DEBUG MODULE_PARM(ntdebug, "i"); diff -u --recursive --new-file v2.4.6/linux/fs/ntfs/inode.c linux/fs/ntfs/inode.c --- v2.4.6/linux/fs/ntfs/inode.c Wed Apr 18 11:49:13 2001 +++ linux/fs/ntfs/inode.c Mon Jul 16 15:14:10 2001 @@ -1,11 +1,12 @@ -/* inode.c +/* + * inode.c * - * Copyright (C) 1995-1999 Martin von Löwis - * Copyright (C) 1996 Albert D. Cahalan - * Copyright (C) 1996-1997 Régis Duchesne - * Copyright (C) 1998 Joseph Malicki - * Copyright (C) 1999 Steve Dodd - * Copyright (C) 2000-2001 Anton Altaparmakov (AIA) + * Copyright (C) 1995-1999 Martin von Löwis + * Copyright (C) 1996 Albert D. Cahalan + * Copyright (C) 1996-1997 Régis Duchesne + * Copyright (C) 1998 Joseph Malicki + * Copyright (C) 1999 Steve Dodd + * Copyright (C) 2000-2001 Anton Altaparmakov (AIA) */ #include "ntfstypes.h" @@ -19,6 +20,7 @@ #include "dir.h" #include "support.h" #include "util.h" +#include <linux/smp_lock.h> typedef struct { int recno; @@ -86,27 +88,31 @@ /* Try to allocate at least 0.1% of the remaining disk space for * inodes. If the disk is almost full, make sure at least one inode is * requested. */ - int size, rcount, error, block; + int rcount, error, block, blockbits; + __s64 size; ntfs_attribute *mdata, *bmp; ntfs_u8 *buf; ntfs_io io; mdata = ntfs_find_attr(vol->mft_ino, vol->at_data, 0); /* First check whether there is uninitialized space. */ - if (mdata->allocated < mdata->size + vol->mft_recordsize) { - size = ntfs_get_free_cluster_count(vol->bitmap) * - vol->clustersize; - block = vol->mft_recordsize; - size = max(size / 1000, mdata->size + vol->mft_recordsize); - size = ((size + block - 1) / block) * block; + if (mdata->allocated < mdata->size + vol->mft_record_size) { + size = (__s64)ntfs_get_free_cluster_count(vol->bitmap) << + vol->cluster_size_bits; + /* On error, size will be negative. We can ignore this as we + * will fall back to the minimal size allocation below. (AIA) */ + block = vol->mft_record_size; + blockbits = vol->mft_record_size_bits; + size = max(size >> 10, mdata->size + vol->mft_record_size); + size = (__s64)((size + block - 1) >> blockbits) << blockbits; /* Require this to be a single chunk. */ error = ntfs_extend_attr(vol->mft_ino, mdata, &size, ALLOC_REQUIRE_SIZE); /* Try again, now we have the largest available fragment. */ if (error == -ENOSPC) { /* Round down to multiple of mft record size. */ - size = (size / vol->mft_recordsize) * - vol->mft_recordsize; + size = (__s64)(size >> vol->mft_record_size_bits) << + vol->mft_record_size_bits; if (!size) return -ENOSPC; error = ntfs_extend_attr(vol->mft_ino, mdata, &size, @@ -117,9 +123,9 @@ } /* Even though we might have allocated more than needed, we initialize * only one record. */ - mdata->size += vol->mft_recordsize; + mdata->size += vol->mft_record_size; /* Now extend the bitmap if necessary. */ - rcount = mdata->size / vol->mft_recordsize; + rcount = mdata->size >> vol->mft_record_size_bits; bmp = ntfs_find_attr(vol->mft_ino, vol->at_bitmap, 0); if (bmp->size * 8 < rcount) { /* Less bits than MFT records. */ ntfs_u8 buf[1]; @@ -141,20 +147,20 @@ return -EIO; } /* Now fill in the MFT header for the new block. */ - buf = ntfs_calloc(vol->mft_recordsize); + buf = ntfs_calloc(vol->mft_record_size); if (!buf) return -ENOMEM; - ntfs_fill_mft_header(buf, vol->mft_recordsize, vol->blocksize, 0); - ntfs_insert_fixups(buf, vol->blocksize); + ntfs_fill_mft_header(buf, vol->mft_record_size, vol->sector_size, 0); + ntfs_insert_fixups(buf, vol->sector_size); io.param = buf; - io.size = vol->mft_recordsize; + io.size = vol->mft_record_size; io.fn_put = ntfs_put; io.fn_get = ntfs_get; error = ntfs_write_attr(vol->mft_ino, vol->at_data, 0, - (rcount - 1) * vol->mft_recordsize, &io); + (__s64)(rcount - 1) << vol->mft_record_size_bits, &io); if (error) return error; - if (io.size != vol->mft_recordsize) + if (io.size != vol->mft_record_size) return -EIO; error = ntfs_update_inode(vol->mft_ino); if (error) @@ -162,35 +168,47 @@ return 0; } -/* Insert all attributes from the record mftno of the MFT in the inode ino. +/* + * Insert all attributes from the record mftno of the MFT in the inode ino. + * If mftno is a base mft record we abort as soon as we find the attribute + * list, but only on the first pass. We will get called later when the attribute + * list attribute is being parsed so we need to distinguish the two cases. * FIXME: We should be performing structural consistency checks. (AIA) - * Return 0 on success or -errno on error. */ + * Return 0 on success or -errno on error. + */ static int ntfs_insert_mft_attributes(ntfs_inode* ino, char *mft, int mftno) { - int i, error, type, len; + int i, error, type, len, present = 0; char *it; - - /* Check for duplicate. */ - for(i = 0; i < ino->record_count; i++) - if (ino->records[i] == mftno) - return 0; - /* (re-)allocate space if necessary. */ - if (ino->record_count % 8 == 0) { - int *new; - new = ntfs_malloc((ino->record_count + 8) * sizeof(int)); - if (!new) - return -ENOMEM; - if (ino->records) { - for (i = 0; i < ino->record_count; i++) - new[i] = ino->records[i]; - ntfs_free(ino->records); - } - ino->records = new; - } - ino->records[ino->record_count] = mftno; - ino->record_count++; - it = mft + NTFS_GETU16(mft + 0x14); + /* Check for duplicate extension record. */ + for(i = 0; i < ino->record_count; i++) + if (ino->records[i] == mftno) { + if (i) + return 0; + present = 1; + break; + } + if (!present) { + /* (re-)allocate space if necessary. */ + if (ino->record_count % 8 == 0) { + int *new; + + new = ntfs_malloc((ino->record_count + 8) * + sizeof(int)); + if (!new) + return -ENOMEM; + if (ino->records) { + for (i = 0; i < ino->record_count; i++) + new[i] = ino->records[i]; + ntfs_free(ino->records); + } + ino->records = new; + } + ino->records[ino->record_count] = mftno; + ino->record_count++; + } + it = mft + NTFS_GETU16(mft + 0x14); /* mft->attrs_offset */ do { type = NTFS_GETU32(it); len = NTFS_GETU32(it + 4); @@ -199,8 +217,66 @@ if (error) return error; } + /* If we have just processed the attribute list and this is + * the first time we are parsing this (base) mft record then we + * are done so that the attribute list gets parsed before the + * entries in the base mft record. Otherwise we run into + * problems with encountering attributes out of order and when + * this happens with different attribute extents we die. )-: + * This way we are ok as the attribute list is always sorted + * fully and correctly. (-: */ + if (type == 0x20 && !present) + return 0; it += len; - } while (type != -1); /* Attribute list ends with type -1. */ + } while (type != -1); /* Attribute listing ends with type -1. */ + return 0; +} + +/* + * Insert a single specific attribute from the record mftno of the MFT in the + * inode ino. We disregard the attribute list assuming we have already parsed + * it. + * FIXME: We should be performing structural consistency checks. (AIA) + * Return 0 on success or -errno on error. + */ +static int ntfs_insert_mft_attribute(ntfs_inode* ino, int mftno, + ntfs_u8 *attr) +{ + int i, error, present = 0; + + /* Check for duplicate extension record. */ + for(i = 0; i < ino->record_count; i++) + if (ino->records[i] == mftno) { + present = 1; + break; + } + if (!present) { + /* (re-)allocate space if necessary. */ + if (ino->record_count % 8 == 0) { + int *new; + + new = ntfs_malloc((ino->record_count + 8) * + sizeof(int)); + if (!new) + return -ENOMEM; + if (ino->records) { + for (i = 0; i < ino->record_count; i++) + new[i] = ino->records[i]; + ntfs_free(ino->records); + } + ino->records = new; + } + ino->records[ino->record_count] = mftno; + ino->record_count++; + } + if (NTFS_GETU32(attr) == -1) { + ntfs_debug(DEBUG_FILE3, "ntfs_insert_mft_attribute: attribute " + "type is -1.\n"); + return 0; + } + error = ntfs_insert_attribute(ino, attr); + if (error) + return error; return 0; } @@ -208,12 +284,17 @@ * Return the number of remaining bytes in *plen. */ static int parse_attributes(ntfs_inode *ino, ntfs_u8 *alist, int *plen) { - char *mft; + ntfs_u8 *mft, *attr; int mftno, l, error; int last_mft = -1; int len = *plen; - mft = ntfs_malloc(ino->vol->mft_recordsize); + if (!ino->attr) { + ntfs_error("parse_attributes: called on inode 0x%x without a " + "loaded base mft record.\n", ino->i_number); + return -EINVAL; + } + mft = ntfs_malloc(ino->vol->mft_record_size); if (!mft) return -ENOMEM; while (len > 8) { @@ -222,23 +303,49 @@ break; /* Process an attribute description. */ mftno = NTFS_GETU32(alist + 0x10); - /* FIXME: The mft reference (alist + 0x10) is __u64. + /* FIXME: The mft reference (alist + 0x10) is __s64. * - Not a problem unless we encounter a huge partition. * - Should be consistency checking the sequence numbers * though! This should maybe happen in * ntfs_read_mft_record() itself and a hotfix could * then occur there or the user notified to run * ntfsck. (AIA) */ - if (mftno != last_mft){ + if (mftno != ino->i_number && mftno != last_mft) { last_mft = mftno; - /* FIXME: Avoid loading record if it's already - * processed. */ error = ntfs_read_mft_record(ino->vol, mftno, mft); - if (error) - return error; - error = ntfs_insert_mft_attributes(ino, mft, mftno); - if (error) + if (error) { + ntfs_debug(DEBUG_FILE3, "parse_attributes: " + "ntfs_read_mft_record(mftno = 0x%x) " + "failed\n", mftno); + ntfs_free(mft); return error; + } + } + attr = ntfs_find_attr_in_mft_rec( + ino->vol, /* ntfs volume */ + mftno == ino->i_number ?/* mft record is: */ + ino->attr: /* base record */ + mft, /* extension record */ + NTFS_GETU32(alist + 0), /* type */ + (wchar_t*)(alist + alist[7]), /* name */ + alist[6], /* name length */ + 1, /* ignore case */ + NTFS_GETU16(alist + 24) /* instance number */ + ); + if (!attr) { + ntfs_error("parse_attributes: mft records 0x%x and/or " + "0x%x corrupt!\n", ino->i_number, mftno); + ntfs_free(mft); + return -EINVAL; /* FIXME: Better error code? (AIA) */ + } + error = ntfs_insert_mft_attribute(ino, mftno, attr); + if (error) { + ntfs_debug(DEBUG_FILE3, "parse_attributes: " + "ntfs_insert_mft_attribute(mftno 0x%x, " + "attribute type 0x%x) failed\n", mftno, + NTFS_GETU32(alist + 0)); + ntfs_free(mft); + return error; } len -= l; alist += l; @@ -266,10 +373,13 @@ return; ntfs_debug(DEBUG_FILE2, "load_attributes %x 4\n", ino->i_number); datasize = alist->size; + ntfs_debug(DEBUG_FILE2, "load_attributes %x: alist->size = 0x%x\n", + ino->i_number, alist->size); if (alist->resident) { parse_attributes(ino, alist->d.data, &datasize); return; } + ntfs_debug(DEBUG_FILE2, "load_attributes %x 5\n", ino->i_number); buf = ntfs_malloc(1024); if (!buf) /* FIXME: Should be passing error code to caller. (AIA) */ return; @@ -281,16 +391,24 @@ io.fn_get = 0; io.param = buf + delta; io.size = len = min(datasize, 1024 - delta); + ntfs_debug(DEBUG_FILE2, "load_attributes %x: len = %i\n", + ino->i_number, len); + ntfs_debug(DEBUG_FILE2, "load_attributes %x: delta = %i\n", + ino->i_number, delta); if (ntfs_read_attr(ino, vol->at_attribute_list, 0, offset, &io)) ntfs_error("error in load_attributes\n"); delta += len; + ntfs_debug(DEBUG_FILE2, "load_attributes %x: after += len, " + "delta = %i\n", ino->i_number, delta); parse_attributes(ino, buf, &delta); + ntfs_debug(DEBUG_FILE2, "load_attributes %x: after parse_attr, " + "delta = %i\n", ino->i_number, delta); if (delta) /* Move remaining bytes to buffer start. */ ntfs_memmove(buf, buf + len - delta, delta); } - ntfs_debug(DEBUG_FILE2, "load_attributes %x 5\n", ino->i_number); + ntfs_debug(DEBUG_FILE2, "load_attributes %x 6\n", ino->i_number); ntfs_free(buf); } @@ -300,11 +418,9 @@ int error; ntfs_debug(DEBUG_FILE1, "Initializing inode %x\n", inum); - if (!vol) - ntfs_error("NO VOLUME!\n"); ino->i_number = inum; ino->vol = vol; - ino->attr = buf = ntfs_malloc(vol->mft_recordsize); + ino->attr = buf = ntfs_malloc(vol->mft_record_size); if (!buf) return -ENOMEM; error = ntfs_read_mft_record(vol, inum, ino->attr); @@ -342,7 +458,7 @@ ntfs_free(ino->attrs[i].d.data); } else { if (ino->attrs[i].d.r.runlist) - ntfs_free(ino->attrs[i].d.r.runlist); + ntfs_vfree(ino->attrs[i].d.r.runlist); } } ntfs_free(ino->attrs); @@ -352,7 +468,7 @@ /* Check and fixup a MFT record. */ int ntfs_check_mft_record(ntfs_volume *vol, char *record) { - return ntfs_fixup_record(vol, record, "FILE", vol->mft_recordsize); + return ntfs_fixup_record(vol, record, "FILE", vol->mft_record_size); } /* Return (in result) the value indicating the next available attribute @@ -406,7 +522,7 @@ return it; } -int ntfs_get_attr_size(ntfs_inode *ino, int type, char *name) +__s64 ntfs_get_attr_size(ntfs_inode *ino, int type, char *name) { ntfs_attribute *attr = ntfs_find_attr(ino, type, name); if (!attr) @@ -462,6 +578,7 @@ ntfs_error("Can't decode run type field %x\n", type); return -1; } +// ntfs_debug(DEBUG_FILE3, "ntfs_decompress_run: length = 0x%x\n",*length); if (*length < 0) { ntfs_error("Negative run length decoded\n"); @@ -502,6 +619,8 @@ ntfs_error("Can't decode run type field %x\n", type); return -1; } +// ntfs_debug(DEBUG_FILE3, "ntfs_decompress_run: cluster = 0x%x\n", +// *cluster); *data += (type >> 4); return 0; } @@ -519,17 +638,18 @@ /* Reads l bytes of the attribute (attr, name) of ino starting at offset on * vol into buf. Returns the number of bytes read in the ntfs_io struct. * Returns 0 on success, errno on failure */ -int ntfs_readwrite_attr(ntfs_inode *ino, ntfs_attribute *attr, int offset, +int ntfs_readwrite_attr(ntfs_inode *ino, ntfs_attribute *attr, __s64 offset, ntfs_io *dest) { int rnum; ntfs_cluster_t cluster, s_cluster, vcn, len; - int l, chunk, copied; + __s64 l, chunk, copied; int s_vcn; - int clustersize; - int error; + int error, clustersizebits; - clustersize = ino->vol->clustersize; + ntfs_debug(DEBUG_FILE3, "ntfs_readwrite_attr 0: inode = 0x%x, attr->" + "type = 0x%x, offset = 0x%Lx, dest->size = 0x%x\n", + ino->i_number, attr->type, offset, dest->size); l = dest->size; if (l == 0) return 0; @@ -567,40 +687,49 @@ dest->size = l; return 0; } - /* Read uninitialized data. */ - if (offset >= attr->initialized && dest->do_read) - return ntfs_read_zero(dest, l); - if (offset + l > attr->initialized && dest->do_read) { - dest->size = chunk = offset + l - attr->initialized; - error = ntfs_readwrite_attr(ino, attr, offset, dest); - if (error) - return error; - return ntfs_read_zero(dest, l - chunk); - } - if (attr->compressed) { - if (dest->do_read) + if (dest->do_read) { + /* Read uninitialized data. */ + if (offset >= attr->initialized) + return ntfs_read_zero(dest, l); + if (offset + l > attr->initialized) { + dest->size = chunk = offset + l - attr->initialized; + error = ntfs_readwrite_attr(ino, attr, offset, dest); + if (error) + return error; + return ntfs_read_zero(dest, l - chunk); + } + if (attr->compressed) return ntfs_read_compressed(ino, attr, offset, dest); - else + } else { + if (attr->compressed) return ntfs_write_compressed(ino, attr, offset, dest); } vcn = 0; - s_vcn = offset / clustersize; + clustersizebits = ino->vol->cluster_size_bits; + s_vcn = offset >> clustersizebits; for (rnum = 0; rnum < attr->d.r.len && - vcn + attr->d.r.runlist[rnum].len <= s_vcn; rnum++) + vcn + attr->d.r.runlist[rnum].len <= s_vcn; rnum++) { vcn += attr->d.r.runlist[rnum].len; - if (rnum == attr->d.r.len) + } + if (rnum == attr->d.r.len) { + ntfs_debug(DEBUG_FILE3, "ntfs_readwrite_attr: EOPNOTSUPP: " + "inode = 0x%x, rnum = %i, offset = 0x%Lx, vcn = , 0x%x" + "s_vcn = 0x%x\n", ino->i_number, rnum, offset, vcn, + s_vcn); /*FIXME: Should extend runlist. */ return -EOPNOTSUPP; + } copied = 0; while (l) { - s_vcn = offset / clustersize; + s_vcn = offset >> clustersizebits; cluster = attr->d.r.runlist[rnum].cluster; len = attr->d.r.runlist[rnum].len; s_cluster = cluster + s_vcn - vcn; - chunk = min((vcn + len) * clustersize - offset, l); + chunk = min(((__s64)(vcn + len) << clustersizebits) - offset, + l); dest->size = chunk; - error = ntfs_getput_clusters(ino->vol, s_cluster, - offset - s_vcn * clustersize, dest); + error = ntfs_getput_clusters(ino->vol, s_cluster, offset - + ((__s64)s_vcn << clustersizebits), dest); if (error) { ntfs_error("Read/write error\n"); dest->size = copied; @@ -609,7 +738,7 @@ l -= chunk; copied += chunk; offset += chunk; - if (l && offset >= ((vcn + len) * clustersize)) { + if (l && offset >= ((__s64)(vcn + len) << clustersizebits)) { rnum++; vcn += len; cluster = attr->d.r.runlist[rnum].cluster; @@ -620,19 +749,22 @@ return 0; } -int ntfs_read_attr(ntfs_inode *ino, int type, char *name, int offset, +int ntfs_read_attr(ntfs_inode *ino, int type, char *name, __s64 offset, ntfs_io *buf) { ntfs_attribute *attr; buf->do_read = 1; attr = ntfs_find_attr(ino, type, name); - if (!attr) + if (!attr) { + ntfs_debug(DEBUG_FILE3, "ntfs_read_attr: attr 0x%x not found " + "in inode 0x%x\n", type, ino->i_number); return -EINVAL; + } return ntfs_readwrite_attr(ino, attr, offset, buf); } -int ntfs_write_attr(ntfs_inode *ino, int type, char *name, int offset, +int ntfs_write_attr(ntfs_inode *ino, int type, char *name, __s64 offset, ntfs_io *buf) { ntfs_attribute *attr; @@ -653,15 +785,19 @@ /* It's hard to give an error code. */ if (!data || data->resident || data->compressed) return -1; - if (data->size <= vcn*ino->vol->clustersize) + if (data->size <= (__s64)vcn << ino->vol->cluster_size_bits) return -1; - /* For Linux, block number 0 represents a hole. - * Hopefully, nobody will attempt to bmap $Boot. */ - if (data->initialized <= vcn * ino->vol->clustersize) + /* + * For Linux, block number 0 represents a hole. Hopefully, nobody will + * attempt to bmap $Boot. FIXME: Hopes are not good enough! We need to + * fix this properly before reenabling mmap-ed stuff. (AIA) + */ + if (data->initialized <= (__s64)vcn << ino->vol->cluster_size_bits) return 0; for (rnum = 0; rnum < data->d.r.len && - vcn >= data->d.r.runlist[rnum].len; rnum++) + vcn >= data->d.r.runlist[rnum].len; rnum++) vcn -= data->d.r.runlist[rnum].len; + /* We need to cope with sparse runs. (AIA) */ return data->d.r.runlist[rnum].cluster + vcn; } @@ -685,7 +821,7 @@ store->records = n; } for (i = store->count; i < count; i++) { - store->records[i].record = ntfs_malloc(vol->mft_recordsize); + store->records[i].record = ntfs_malloc(vol->mft_record_size); if (!store->records[i].record) return -ENOMEM; store->count++; @@ -717,79 +853,99 @@ * mapping pairs array. On exit, it contains the offset in @rec of the first * byte after the end of the mapping pairs array. */ -static int layout_runs(ntfs_attribute *attr, char* rec, int* offs, int size) +static int layout_runs(ntfs_attribute *attr, char *rec, int *offs, int size) { int i, len, offset, coffs; + /* ntfs_cluster_t MUST be signed! (AIA) */ ntfs_cluster_t cluster, rclus; ntfs_runlist *rl = attr->d.r.runlist; cluster = 0; offset = *offs; for (i = 0; i < attr->d.r.len; i++) { + /* + * We cheat with this check on the basis that cluster will never + * be less than -1 and the cluster delta will fit in signed + * 32-bits (ntfs_cluster_t). (AIA) + */ + if (rl[i].cluster < (ntfs_cluster_t)-1) { + ntfs_error("layout_runs() encountered an out of bounds " + "cluster delta!\n"); + return -ERANGE; + } rclus = rl[i].cluster - cluster; len = rl[i].len; rec[offset] = 0; if (offset + 9 > size) return -E2BIG; /* It might still fit, but this * simplifies testing. */ - /* Run length is stored as signed number. */ - if (len <= 0x7F) { - NTFS_PUTU8(rec + offset + 1, len); + /* + * Run length is stored as signed number, so deal with it + * properly, i.e. observe that a negative number will have all + * its most significant bits set to 1 but we don't store that + * in the mapping pairs array. We store the smallest type of + * negative number required, thus in the first if we check + * whether len fits inside a signed byte and if so we store it + * as such, the next ifs check for a signed short, then a signed + * 24-bit and finally the full blown signed 32-bit. Same goes + * for rlus below. (AIA) + */ + if (len >= -0x80 && len <= 0x7f) { + NTFS_PUTU8(rec + offset + 1, len & 0xff); coffs = 1; - } else if (len <= 0x7FFF) { - NTFS_PUTU16(rec + offset + 1, len); + } else if (len >= -0x8000 && len <= 0x7fff) { + NTFS_PUTU16(rec + offset + 1, len & 0xffff); coffs = 2; - } else if (len <= 0x7FFFFF) { - NTFS_PUTU24(rec + offset + 1, len); + } else if (len >= -0x800000 && len <= 0x7fffff) { + NTFS_PUTU24(rec + offset + 1, len & 0xffffff); coffs = 3; - } else { + } else /* if (len >= -0x80000000LL && len <= 0x7fffffff */ { NTFS_PUTU32(rec + offset + 1, len); coffs = 4; - } - *(rec + offset) |= coffs++; - if (rl[i].cluster == MAX_CLUSTER_T) /* Compressed run. */ + } /* else ... FIXME: When len becomes 64-bit we need to extend + * the else if () statements. (AIA) */ + *(rec + offset) |= coffs++; + if (rl[i].cluster == (ntfs_cluster_t)-1) /* Compressed run. */ /* Nothing */; - else if (rclus >= -0x80 && rclus <= 0x7F) { + else if (rclus >= -0x80 && rclus <= 0x7f) { *(rec + offset) |= 0x10; - NTFS_PUTS8(rec + offset + coffs, rclus); + NTFS_PUTS8(rec + offset + coffs, rclus & 0xff); coffs += 1; - } else if(rclus >= -0x8000 && rclus <= 0x7FFF) { + } else if (rclus >= -0x8000 && rclus <= 0x7fff) { *(rec + offset) |= 0x20; - NTFS_PUTS16(rec + offset + coffs, rclus); + NTFS_PUTS16(rec + offset + coffs, rclus & 0xffff); coffs += 2; - } else if(rclus >= -0x800000 && rclus <= 0x7FFFFF) { + } else if (rclus >= -0x800000 && rclus <= 0x7fffff) { *(rec + offset) |= 0x30; - NTFS_PUTS24(rec + offset + coffs, rclus); + NTFS_PUTS24(rec + offset + coffs, rclus & 0xffffff); coffs += 3; - } else -#if 0 /* In case ntfs_cluster_t ever becomes 64bit. */ - if (rclus >= -0x80000000LL && rclus <= 0x7FFFFFFF) -#endif - { + } else /* if (rclus >= -0x80000000LL && rclus <= 0x7fffffff)*/ { *(rec + offset) |= 0x40; - NTFS_PUTS32(rec + offset + coffs, rclus); + NTFS_PUTS32(rec + offset + coffs, rclus + /* & 0xffffffffLL */); coffs += 4; - } -#if 0 /* For 64-bit ntfs_cluster_t */ + } /* FIXME: When rclus becomes 64-bit. else if (rclus >= -0x8000000000 && rclus <= 0x7FFFFFFFFF) { *(rec + offset) |= 0x50; - NTFS_PUTS40(rec + offset + coffs, rclus); + NTFS_PUTS40(rec + offset + coffs, rclus & + 0xffffffffffLL); coffs += 5; } else if (rclus >= -0x800000000000 && rclus <= 0x7FFFFFFFFFFF) { *(rec + offset) |= 0x60; - NTFS_PUTS48(rec + offset + coffs, rclus); + NTFS_PUTS48(rec + offset + coffs, rclus & + 0xffffffffffffLL); coffs += 6; } else if (rclus >= -0x80000000000000 && rclus <= 0x7FFFFFFFFFFFFF) { *(rec + offset) |= 0x70; - NTFS_PUTS56(rec + offset + coffs, rclus); + NTFS_PUTS56(rec + offset + coffs, rclus & + 0xffffffffffffffLL); coffs += 7; } else { *(rec + offset) |= 0x80; NTFS_PUTS64(rec + offset + coffs, rclus); coffs += 8; - } -#endif + } */ offset += coffs; if (rl[i].cluster) cluster = rl[i].cluster; @@ -828,64 +984,59 @@ */ static int layout_attr(ntfs_attribute* attr, char *buf, int size, int *psize) { - int asize, error; - if (size < 10) - return -E2BIG; - NTFS_PUTU32(buf, attr->type); - /* Fill in length later. */ - NTFS_PUTU8(buf + 8, attr->resident ? 0 : 1); - NTFS_PUTU8(buf + 9, attr->namelen); - /* Fill in offset to name later. */ - NTFS_PUTU16(buf + 0xA, 0); - NTFS_PUTU16(buf + 0xC, attr->compressed); - /* Assign attribute instance. */ - NTFS_PUTU16(buf + 0xE, attr->attrno); + int nameoff, hdrsize, asize; + if (attr->resident) { - if (size < attr->size + 0x18 + attr->namelen) + nameoff = 0x18; + hdrsize = (nameoff + 2 * attr->namelen + 7) & ~7; + asize = (hdrsize + attr->size + 7) & ~7; + if (size < asize) return -E2BIG; - asize = 0x18; NTFS_PUTU32(buf + 0x10, attr->size); NTFS_PUTU16(buf + 0x16, attr->indexed); - if (attr->name) { - ntfs_memcpy(buf + asize, attr->name, 2 * attr->namelen); - NTFS_PUTU16(buf + 0xA, asize); - asize += 2 * attr->namelen; - asize = (asize + 7) & ~7; - } - NTFS_PUTU16(buf + 0x14, asize); - ntfs_memcpy(buf + asize, attr->d.data, attr->size); - asize += attr->size; + NTFS_PUTU16(buf + 0x14, hdrsize); + if (attr->size) + ntfs_memcpy(buf + hdrsize, attr->d.data, attr->size); } else { + int error; + + if (attr->compressed) + nameoff = 0x48; + else + nameoff = 0x40; + hdrsize = (nameoff + 2 * attr->namelen + 7) & ~7; + if (size < hdrsize) + return -E2BIG; + /* Make asize point at the end of the attribute record header, + i.e. at the beginning of the mapping pairs array. */ + asize = hdrsize; + error = layout_runs(attr, buf, &asize, size); + /* Now, asize points one byte beyond the end of the mapping + pairs array. */ + if (error) + return error; + /* The next attribute has to begin on 8-byte boundary. */ + asize = (asize + 7) & ~7; /* FIXME: fragments */ count_runs(attr, buf); - /* Offset to data is added later. */ + NTFS_PUTU16(buf + 0x20, hdrsize); NTFS_PUTU16(buf + 0x22, attr->cengine); NTFS_PUTU32(buf + 0x24, 0); - NTFS_PUTU64(buf + 0x28, attr->allocated); - NTFS_PUTU64(buf + 0x30, attr->size); - NTFS_PUTU64(buf + 0x38, attr->initialized); - if (attr->compressed) { - NTFS_PUTU64(buf + 0x40, attr->compsize); - asize = 0x48; - } else - asize = 0x40; - if (attr->name) { - NTFS_PUTU16(buf + 0xA, asize); - ntfs_memcpy(buf + asize, attr->name, 2 * attr->namelen); - asize += 2 * attr->namelen; - /* SRD: you whaaa? - AIA: Align to next 8 byte boundary - * as required by NTFS design and implementation. */ - asize = (asize + 7) & ~7; - } - /* asize points at the beginning of the data. */ - NTFS_PUTU16(buf + 0x20, asize); - error = layout_runs(attr, buf, &asize, size); - /* Now asize points at the end of the data. */ - if (error) - return error; + NTFS_PUTS64(buf + 0x28, attr->allocated); + NTFS_PUTS64(buf + 0x30, attr->size); + NTFS_PUTS64(buf + 0x38, attr->initialized); + if (attr->compressed) + NTFS_PUTS64(buf + 0x40, attr->compsize); } - asize = (asize + 7) & ~7; + NTFS_PUTU32(buf, attr->type); NTFS_PUTU32(buf + 4, asize); + NTFS_PUTU8(buf + 8, attr->resident ? 0 : 1); + NTFS_PUTU8(buf + 9, attr->namelen); + NTFS_PUTU16(buf + 0xa, nameoff); + NTFS_PUTU16(buf + 0xc, attr->compressed); + NTFS_PUTU16(buf + 0xe, attr->attrno); + if (attr->namelen) + ntfs_memcpy(buf + nameoff, attr->name, 2 * attr->namelen); *psize = asize; return 0; } @@ -905,42 +1056,56 @@ */ int layout_inode(ntfs_inode *ino, ntfs_disk_inode *store) { - int offset, i; + int offset, i, size, psize, error, count, recno; ntfs_attribute *attr; unsigned char *rec; - int size, psize; - int error; - if (ino->record_count > 1) { - ntfs_error("layout_inode: attribute lists not supported\n"); - return -EOPNOTSUPP; - } - error = allocate_store(ino->vol, store, 1); + error = allocate_store(ino->vol, store, ino->record_count); if (error) return error; - rec = store->records[0].record; - size = ino->vol->mft_recordsize; - store->records[0].recno = ino->records[0]; - /* Copy header. */ - offset = NTFS_GETU16(ino->attr + 0x14); - ntfs_memcpy(rec, ino->attr, offset); - for (i = 0; i < ino->attr_count; i++) { - attr = ino->attrs + i; - error = layout_attr(attr, rec + offset, size - offset, &psize); - if (error) - return error; - offset += psize; - } - /* Terminating attribute. */ - if (offset + 8 < size) { + size = ino->vol->mft_record_size; + count = i = 0; + do { + if (count < ino->record_count) { + recno = ino->records[count]; + } else { + error = allocate_store(ino->vol, store, count + 1); + if (error) + return error; + recno = -1; + } + /* + * FIXME: We need to support extension records properly. + * At the moment they wouldn't work. Probably would "just" get + * corrupted if we write to them... (AIA) + */ + store->records[count].recno = recno; + rec = store->records[count].record; + count++; + /* Copy header. */ + offset = NTFS_GETU16(ino->attr + 0x14); + ntfs_memcpy(rec, ino->attr, offset); + /* Copy attributes. */ + while (i < ino->attr_count) { + attr = ino->attrs + i; + error = layout_attr(attr, rec + offset, + size - offset - 8, &psize); + if (error == -E2BIG && offset != NTFS_GETU16(ino->attr + + 0x14)) + break; + if (error) + return error; + offset += psize; + i++; + } + /* Terminating attribute. */ NTFS_PUTU32(rec + offset, 0xFFFFFFFF); offset += 4; NTFS_PUTU32(rec + offset, 0); offset += 4; - } else - return -E2BIG; - NTFS_PUTU32(rec + 0x18, offset); - return 0; + NTFS_PUTU32(rec + 0x18, offset); + } while (i < ino->attr_count || count < ino->record_count); + return count - ino->record_count; } /* @@ -952,13 +1117,11 @@ */ int ntfs_update_inode(ntfs_inode *ino) { - int error; + int error, i; ntfs_disk_inode store; ntfs_io io; - int i; - store.count = store.size = 0; - store.records = 0; + ntfs_bzero(&store, sizeof(store)); error = layout_inode(ino, &store); if (error == -E2BIG) { error = ntfs_split_indexroot(ino); @@ -970,13 +1133,14 @@ if (!error) error = layout_inode(ino, &store); } - if (error == -E2BIG) { - /* FIXME: should try: introduce extension records */ - ntfs_error("cannot handle saving inode %x\n", ino->i_number); - deallocate_store(&store); - return -EOPNOTSUPP; + if (error > 0) { + /* FIXME: Introduce extension records. */ + error = -E2BIG; } if (error) { + if (error == -E2BIG) + ntfs_error("cannot handle saving inode %x\n", + ino->i_number); deallocate_store(&store); return error; } @@ -984,21 +1148,22 @@ io.fn_put = 0; for (i = 0; i < store.count; i++) { ntfs_insert_fixups(store.records[i].record, - ino->vol->blocksize); + ino->vol->sector_size); io.param = store.records[i].record; - io.size = ino->vol->mft_recordsize; + io.size = ino->vol->mft_record_size; /* FIXME: Is this the right way? */ error = ntfs_write_attr(ino->vol->mft_ino, ino->vol->at_data, - 0, store.records[i].recno * - ino->vol->mft_recordsize, &io); - if (error || io.size != ino->vol->mft_recordsize) { + 0, (__s64)store.records[i].recno << + ino->vol->mft_record_size_bits, &io); + if (error || io.size != ino->vol->mft_record_size) { /* Big trouble, partially written file. */ - ntfs_error("Please unmount: Write error in inode %x\n", - ino->i_number); + ntfs_error("Please unmount: Write error in inode " + "0x%x\n", ino->i_number); deallocate_store(&store); return error ? error : -EIO; } } + deallocate_store(&store); return 0; } @@ -1080,19 +1245,42 @@ } } -/* Caveat: No range checking in either ntfs_set_bit or ntfs_clear_bit. */ -void ntfs_set_bit(unsigned char *byte, int bit) +/* + * NOTE: Neither of the ntfs_*_bit functions are atomic! But we don't need + * them atomic at present as we never operate on shared/cached bitmaps. + */ +static __inline__ int ntfs_get_bit(unsigned char *byte, const int bit) +{ + return byte[bit >> 3] & (1 << (bit & 7)) ? 1 : 0; +} + +static __inline__ void ntfs_set_bit(unsigned char *byte, const int bit) +{ + byte[bit >> 3] |= 1 << (bit & 7); +} + +static __inline__ void ntfs_clear_bit(unsigned char *byte, const int bit) { - byte += (bit >> 3); - bit &= 7; - *byte |= (1 << bit); + byte[bit >> 3] &= ~(1 << (bit & 7)); } -void ntfs_clear_bit(unsigned char *byte, int bit) +__inline__ int ntfs_test_and_set_bit(unsigned char *byte, const int bit) { - byte += (bit >> 3); - bit &= 7; - *byte &= ~(1 << bit); + unsigned char *ptr = byte + (bit >> 3); + int b = 1 << (bit & 7); + int oldbit = *ptr & b ? 1 : 0; + *ptr |= b; + return oldbit; +} + +static __inline__ int ntfs_test_and_clear_bit(unsigned char *byte, + const int bit) +{ + unsigned char *ptr = byte + (bit >> 3); + int b = 1 << (bit & 7); + int oldbit = *ptr & b ? 1 : 0; + *ptr &= ~b; + return oldbit; } /** @@ -1104,50 +1292,87 @@ * and allocating it in the mft bitmap. * Return 0 on success or -ERRNO on error. * - * TODO(AIA): Implement mft bitmap caching. Replace function by race safe one. + * TODO(AIA): Implement mft bitmap caching. */ -static int ntfs_new_inode(ntfs_volume* vol, int* result) +static int ntfs_new_inode(ntfs_volume *vol, unsigned long *result) { - int byte, error; - int bit; - int size, length; + int byte, bit, error, size, length; unsigned char value; ntfs_u8 *buffer; ntfs_io io; ntfs_attribute *data; - buffer = ntfs_malloc(2048); + *result = 0; + /* Determine the number of mft records in the mft. */ + data = ntfs_find_attr(vol->mft_ino, vol->at_data, 0); + length = data->size >> vol->mft_record_size_bits; + /* Allocate sufficient space for the mft bitmap attribute value, + inferring it from the number of mft records. */ + buffer = ntfs_malloc((length + 7) >> 3); if (!buffer) return -ENOMEM; io.fn_put = ntfs_put; io.fn_get = ntfs_get; +try_again: io.param = buffer; - /* FIXME: Bitmaps larger than 2048 bytes. */ - io.size = 2048; + io.size = (length + 7) >> 3; error = ntfs_read_attr(vol->mft_ino, vol->at_bitmap, 0, 0, &io); - if (error) { - ntfs_free(buffer); - return error; - } + if (error) + goto err_out; size = io.size; - data = ntfs_find_attr(vol->mft_ino, vol->at_data, 0); - length = data->size / vol->mft_recordsize; - /* SRD: Start at byte 0: bits for system files _are_ already set in - * bitmap. AIA: This includes the reserved entries as well. */ - for (byte = 0; 8 * byte < length; byte++) { + /* Start at byte 0, as the bits for all 16 system files are already + set in the bitmap. */ + for (bit = byte = 0; (byte << 3) < length; byte++) { value = buffer[byte]; if (value == 0xFF) continue; - for (bit = 0; (bit < 8) && (8 * byte + bit < length); - bit++, value >>= 1) { - if (!(value & 1)) { - *result = byte * 8 + bit; - return 0; - } - } + bit = ffz(value); + if (bit < 8) + break; + } + if ((byte << 3) + bit >= length) { + /* No free space left. Need to extend the mft. */ + error = -ENOSPC; + goto err_out; + } + /* Get the byte containing our bit again, now taking the BKL. */ + io.param = buffer; + io.size = 1; + lock_kernel(); + error = ntfs_read_attr(vol->mft_ino, vol->at_bitmap, 0, byte, &io); + if (error || (io.size != 1 && (error = -EIO, 1))) + goto err_unl_out; + if (ntfs_test_and_set_bit(buffer, bit)) { + unlock_kernel(); + /* Give other process(es) a chance to finish. */ + schedule(); + goto try_again; } - /* There is no free space. We must first extend the MFT. */ - return -ENOSPC; + io.param = buffer; + error = ntfs_write_attr(vol->mft_ino, vol->at_bitmap, 0, byte, &io); + if (error || (io.size != 1 && (error = -EIO, 1))) + goto err_unl_out; + /* Change mft on disk, required when mft bitmap is resident. */ + error = ntfs_update_inode(vol->mft_ino); + if (!error) + *result = (byte << 3) + bit; +err_unl_out: + unlock_kernel(); +err_out: + ntfs_free(buffer); +#ifdef DEBUG + if (error) + printk(KERN_INFO "ntfs_new_inode() failed to allocate an " + "mft record. Error = %i\n", error); + else + printk(KERN_INFO "ntfs_new_inode() allocated mft record number " + "0x%lx\n", *result); +#endif + return error; + /* + * FIXME: Don't forget $MftMirr, though this probably belongs + * in ntfs_update_inode() (or even deeper). (AIA) + */ } static int add_mft_header(ntfs_inode *ino) @@ -1156,8 +1381,8 @@ ntfs_volume *vol = ino->vol; mft = ino->attr; - ntfs_bzero(mft, vol->mft_recordsize); - ntfs_fill_mft_header(mft, vol->mft_recordsize, vol->blocksize, + ntfs_bzero(mft, vol->mft_record_size); + ntfs_fill_mft_header(mft, vol->mft_record_size, vol->sector_size, ino->sequence_number); return 0; } @@ -1183,8 +1408,6 @@ return error; } -/* FIXME: Need to pass in the size of the file (Data size) as well as the - * allocated size for file data on disk (Allocated size). (AIA) */ static int add_filename(ntfs_inode* ino, ntfs_inode* dir, const unsigned char *filename, int length, ntfs_u32 flags) @@ -1201,7 +1424,6 @@ data = ntfs_malloc(size); if (!data) return -ENOMEM; - ntfs_bzero(data, size); /* Search for a position. */ position = data; NTFS_PUTINUM(position, dir); /* Inode num of dir */ @@ -1210,10 +1432,16 @@ NTFS_PUTU64(position + 0x10, now); /* Last modification */ NTFS_PUTU64(position + 0x18, now); /* Last mod for MFT */ NTFS_PUTU64(position + 0x20, now); /* Last access */ - /*NTFS_PUTU64(position + 0x28, 0);*/ /* Allocated size */ - /*NTFS_PUTU64(position + 0x30, 0);*/ /* Data size */ + /* FIXME: Get the following two sizes by finding the data attribute + * in ino->attr and copying the corresponding fields from there. + * If no data present then set to zero. In current implementation + * add_data is called after add_filename so zero is correct on + * creation. Need to change when we have hard links / support different + * filename namespaces. (AIA) */ + NTFS_PUTS64(position + 0x28, 0); /* Allocated size */ + NTFS_PUTS64(position + 0x30, 0); /* Data size */ NTFS_PUTU32(position + 0x38, flags); /* File flags */ - /*NTFS_PUTU32(position + 0x3c, 0);*/ /* We don't use these + NTFS_PUTU32(position + 0x3c, 0); /* We don't use these * features yet. */ NTFS_PUTU8(position + 0x40, length); /* Filename length */ NTFS_PUTU8(position + 0x41, 0); /* Only long name */ @@ -1281,11 +1509,10 @@ int ntfs_alloc_inode(ntfs_inode *dir, ntfs_inode *result, const char *filename, int namelen, ntfs_u32 flags) { - ntfs_io io; int error; - ntfs_u8 buffer[2]; ntfs_volume *vol = dir->vol; - int byte, bit; + ntfs_u8 buffer[2]; + ntfs_io io; error = ntfs_new_inode(vol, &(result->i_number)); if (error == -ENOSPC) { @@ -1295,50 +1522,26 @@ error = ntfs_new_inode(vol, &(result->i_number)); } if (error) { - ntfs_error("ntfs_get_empty_inode: no free inodes\n"); + if (error == -ENOSPC) + ntfs_error("ntfs_get_empty_inode: no free inodes\n"); return error; } - byte = result->i_number / 8; - bit = result->i_number & 7; + /* Get the sequence number. */ io.fn_put = ntfs_put; io.fn_get = ntfs_get; io.param = buffer; - io.size = 1; - /* Set a single bit. */ - error = ntfs_read_attr(vol->mft_ino, vol->at_bitmap, 0, byte, &io); - if (error) - return error; - if (io.size != 1) - return -EIO; - ntfs_set_bit(buffer, bit); - io.param = buffer; - io.size = 1; - error = ntfs_write_attr(vol->mft_ino, vol->at_bitmap, 0, byte, &io); - if (error) - return error; - if (io.size != 1) - return -EIO; - /* FIXME: Should change $Mft on disk. - * error = ntfs_update_inode(vol->mft_ino); - * if (error) - * return error; - * FIXME: And don't forget $MftMirr, though this probably belongs - * in ntfs_update_inode() (or even deeper). (AIA) */ - /* Get the sequence number. */ - io.param = buffer; io.size = 2; error = ntfs_read_attr(vol->mft_ino, vol->at_data, 0, - result->i_number * vol->mft_recordsize + 0x10, - &io); + ((__s64)result->i_number << vol->mft_record_size_bits) + + 0x10, &io); if (error) return error; /* Increment the sequence number skipping zero. */ - if (NTFS_GETU16(buffer) == 0xffff) - result->sequence_number = 1; - else - result->sequence_number = NTFS_GETU16(buffer) + 1; + result->sequence_number = (NTFS_GETU16(buffer) + 1) & 0xffff; + if (!result->sequence_number) + result->sequence_number++; result->vol = vol; - result->attr = ntfs_malloc(vol->mft_recordsize); + result->attr = ntfs_malloc(vol->mft_record_size); if (!result->attr) return -ENOMEM; result->attr_count = 0; diff -u --recursive --new-file v2.4.6/linux/fs/ntfs/inode.h linux/fs/ntfs/inode.h --- v2.4.6/linux/fs/ntfs/inode.h Wed Apr 18 11:49:13 2001 +++ linux/fs/ntfs/inode.h Mon Jul 16 15:14:10 2001 @@ -1,16 +1,18 @@ -/* inode.h - Header file for inode.c +/* + * inode.h - Header file for inode.c * - * Copyright (C) 1997 Régis Duchesne - * Copyright (C) 1998 Martin von Löwis + * Copyright (C) 1997 Régis Duchesne + * Copyright (C) 1998 Martin von Löwis + * Copyright (c) 2001 Anton Altparmakov (AIA) */ ntfs_attribute *ntfs_find_attr(ntfs_inode *ino, int type, char *name); -int ntfs_read_attr(ntfs_inode *ino, int type, char *name, int offset, - ntfs_io *buf); +int ntfs_read_attr(ntfs_inode *ino, int type, char *name, __s64 offset, + ntfs_io *buf); -int ntfs_write_attr(ntfs_inode *ino, int type, char *name, int offset, - ntfs_io *buf); +int ntfs_write_attr(ntfs_inode *ino, int type, char *name, __s64 offset, + ntfs_io *buf); int ntfs_init_inode(ntfs_inode *ino, ntfs_volume *vol, int inum); @@ -19,25 +21,28 @@ int ntfs_check_mft_record(ntfs_volume *vol, char *record); int ntfs_alloc_inode(ntfs_inode *dir, ntfs_inode *result, const char *filename, - int namelen, ntfs_u32); + int namelen, ntfs_u32); int ntfs_alloc_file(ntfs_inode *dir, ntfs_inode *result, char *filename, - int namelen); + int namelen); int ntfs_update_inode(ntfs_inode *ino); int ntfs_vcn_to_lcn(ntfs_inode *ino, int vcn); -int ntfs_readwrite_attr(ntfs_inode *ino, ntfs_attribute *attr, int offset, - ntfs_io *dest); +int ntfs_readwrite_attr(ntfs_inode *ino, ntfs_attribute *attr, __s64 offset, + ntfs_io *dest); int ntfs_allocate_attr_number(ntfs_inode *ino, int *result); int ntfs_decompress_run(unsigned char **data, int *length, - ntfs_cluster_t *cluster, int *ctype); + ntfs_cluster_t *cluster, int *ctype); void ntfs_decompress(unsigned char *dest, unsigned char *src, ntfs_size_t l); void ntfs_fill_mft_header(ntfs_u8 *mft, int recordsize, int blocksize, - int sequence_number); + int sequence_number); + +extern __inline__ int ntfs_test_and_set_bit(unsigned char *byte, + const int bit); diff -u --recursive --new-file v2.4.6/linux/fs/ntfs/macros.h linux/fs/ntfs/macros.h --- v2.4.6/linux/fs/ntfs/macros.h Wed Apr 18 11:49:13 2001 +++ linux/fs/ntfs/macros.h Mon Jul 16 15:14:10 2001 @@ -19,7 +19,6 @@ #define IS_MAGIC(a,b) (*(int*)(a) == *(int*)(b)) #define IS_MFT_RECORD(a) IS_MAGIC((a),"FILE") -#define IS_NTFS_VOLUME(a) IS_MAGIC((a) + 3,"NTFS") #define IS_INDEX_RECORD(a) IS_MAGIC((a),"INDX") /* 'NTFS' in little endian */ diff -u --recursive --new-file v2.4.6/linux/fs/ntfs/ntfsendian.h linux/fs/ntfs/ntfsendian.h --- v2.4.6/linux/fs/ntfs/ntfsendian.h Wed Apr 18 11:49:13 2001 +++ linux/fs/ntfs/ntfsendian.h Mon Jul 16 15:14:10 2001 @@ -1,11 +1,11 @@ -/* ntfsendian.h +/* + * ntfsendian.h * - * Copyright (C) 1998, 1999 Martin von Löwis - * Copyright (C) 1998 Joseph Malicki - * Copyright (C) 1999 Werner Seiler - * Copyright (C) 2001 Anton Altaparmakov (AIA) + * Copyright (C) 1998, 1999 Martin von Löwis + * Copyright (C) 1998 Joseph Malicki + * Copyright (C) 1999 Werner Seiler + * Copyright (C) 2001 Anton Altaparmakov (AIA) */ - #include <asm/byteorder.h> #define CPU_TO_LE16(a) __cpu_to_le16(a) @@ -56,4 +56,5 @@ #define NTFS_PUTS16(p,v) NTFS_PUTU16(p,v) #define NTFS_PUTS24(p,v) NTFS_PUTU24(p,v) #define NTFS_PUTS32(p,v) NTFS_PUTU32(p,v) +#define NTFS_PUTS64(p,v) NTFS_PUTU64(p,v) diff -u --recursive --new-file v2.4.6/linux/fs/ntfs/ntfstypes.h linux/fs/ntfs/ntfstypes.h --- v2.4.6/linux/fs/ntfs/ntfstypes.h Wed Apr 18 11:49:13 2001 +++ linux/fs/ntfs/ntfstypes.h Mon Jul 16 15:14:10 2001 @@ -1,17 +1,14 @@ -/* ntfstypes.h - This file defines four things: - * - Generic platform independent fixed-size types (e.g. ntfs_u32). - * - Specific fixed-size types (e.g. ntfs_offset_t). - * - Macros that read and write those types from and to byte arrays. - * - Types derived from OS specific ones. +/* + * ntfstypes.h - This file defines four things: + * - Generic platform independent fixed-size types (e.g. ntfs_u32). + * - Specific fixed-size types (e.g. ntfs_offset_t). + * - Macros that read and write those types from and to byte arrays. + * - Types derived from OS specific ones. * - * Copyright (C) 1996, 1998, 1999 Martin von Löwis - * Copyright (C) 2001 Anton Altaparmakov (AIA) + * Copyright (C) 1996, 1998, 1999 Martin von Löwis + * Copyright (C) 2001 Anton Altaparmakov (AIA) */ - #include <linux/fs.h> - -/* We don't need to define __LITTLE_ENDIAN, as we use - <asm/byteorder>. */ #include "ntfsendian.h" #include <asm/types.h> @@ -36,21 +33,24 @@ /* File offset */ #ifndef NTFS_OFFSET_T #define NTFS_OFFSET_T -typedef u64 ntfs_offset_t; +typedef s64 ntfs_offset_t; #endif /* UTC */ #ifndef NTFS_TIME64_T #define NTFS_TIME64_T typedef u64 ntfs_time64_t; #endif -/* This is really unsigned long long. So we support only volumes up to 2Tb. */ +/* + * This is really signed long long. So we support only volumes up to 2Tb. This + * is ok as Win2k also only uses 32-bits to store clusters. + * Whatever you do keep this a SIGNED value or a lot of NTFS users with + * corrupted filesystems will lynch you! It causes massive fs corruption when + * unsigned due to the nature of many checks relying on being performed on + * signed quantities. (AIA) + */ #ifndef NTFS_CLUSTER_T #define NTFS_CLUSTER_T -typedef u32 ntfs_cluster_t; -#endif - -#ifndef MAX_CLUSTER_T -#define MAX_CLUSTER_T (~((ntfs_cluster_t)0)) +typedef s32 ntfs_cluster_t; #endif /* Architecture independent macros. */ diff -u --recursive --new-file v2.4.6/linux/fs/ntfs/struct.h linux/fs/ntfs/struct.h --- v2.4.6/linux/fs/ntfs/struct.h Wed Apr 18 11:49:13 2001 +++ linux/fs/ntfs/struct.h Mon Jul 16 15:14:10 2001 @@ -1,7 +1,8 @@ -/* struct.h - Structure definitions +/* + * struct.h - Structure definitions * - * Copyright (C) 1997 Régis Duchesne - * Copyright (C) 2000-2001 Anton Altaparmakov (AIA) + * Copyright (C) 1997 Régis Duchesne + * Copyright (C) 2000-2001 Anton Altaparmakov (AIA) */ /* Necessary forward definition. */ @@ -14,7 +15,6 @@ #define ngt_posix 3 /* all names except hidden files */ #define ngt_full 4 /* all entries */ - typedef struct ntfs_sb_info ntfs_volume; typedef struct { @@ -27,31 +27,31 @@ ntfs_u16 *name; int namelen; int attrno; - int size, allocated, initialized, compsize; + __s64 size, allocated, initialized, compsize; int compressed, resident, indexed; int cengine; union { void *data; /* if resident */ struct { ntfs_runlist *runlist; - int len; + unsigned long len; } r; } d; } ntfs_attribute; +typedef struct ntfs_inode_info ntfs_inode; + /* Structure to define IO to user buffer. do_read means that the destination * has to be written using fn_put, do_write means that the destination has to * read using fn_get. So, do_read is from a user's point of view, while put and * get are from the driver's point of view. The first argument is always the * destination of the IO. */ -typedef struct ntfs_inode_info ntfs_inode; - typedef struct ntfs_io{ int do_read; void (*fn_put)(struct ntfs_io *dest, void *buf, ntfs_size_t); void (*fn_get)(void *buf, struct ntfs_io *src, ntfs_size_t len); void *param; - int size; + unsigned long size; } ntfs_io; #if 0 diff -u --recursive --new-file v2.4.6/linux/fs/ntfs/super.c linux/fs/ntfs/super.c --- v2.4.6/linux/fs/ntfs/super.c Wed Apr 18 11:49:13 2001 +++ linux/fs/ntfs/super.c Mon Jul 16 15:14:10 2001 @@ -1,9 +1,10 @@ -/* super.c +/* + * super.c * - * Copyright (C) 1995-1997, 1999 Martin von Löwis - * Copyright (C) 1996-1997 Régis Duchesne - * Copyright (C) 1999 Steve Dodd - * Copyright (C) 2000-2001 Anton Altparmakov (AIA) + * Copyright (C) 1995-1997, 1999 Martin von Löwis + * Copyright (C) 1996-1997 Régis Duchesne + * Copyright (C) 1999 Steve Dodd + * Copyright (C) 2000-2001 Anton Altparmakov (AIA) */ #include "ntfstypes.h" @@ -40,17 +41,17 @@ start = NTFS_GETU16(record + 4); count = NTFS_GETU16(record + 6); count--; - if(size && vol->blocksize * count != size) + if(size && vol->sector_size * count != size) return 0; fixup = NTFS_GETU16(record + start); start += 2; - offset = vol->blocksize - 2; + offset = vol->sector_size - 2; while (count--){ if (NTFS_GETU16(record + offset) != fixup) return 0; NTFS_PUTU16(record + offset, NTFS_GETU16(record + start)); start += 2; - offset += vol->blocksize; + offset += vol->sector_size; } return 1; } @@ -61,6 +62,8 @@ */ int ntfs_init_volume(ntfs_volume *vol, char *boot) { + int sectors_per_cluster_bits; + /* Historical default values, in case we don't load $AttrDef. */ vol->at_standard_information = 0x10; vol->at_attribute_list = 0x20; @@ -75,53 +78,71 @@ vol->at_bitmap = 0xB0; vol->at_symlink = 0xC0; /* Sector size */ - vol->blocksize = NTFS_GETU16(boot + 0xB); - vol->clusterfactorbits = ffs(NTFS_GETU8(boot + 0xD)) - 1; + vol->sector_size = NTFS_GETU16(boot + 0xB); + ntfs_debug(DEBUG_FILE3, "ntfs_init_volume: vol->sector_size = 0x%x\n", + vol->sector_size); + ntfs_debug(DEBUG_FILE3, "ntfs_init_volume: sectors_per_cluster = " + "0x%x\n", NTFS_GETU8(boot + 0xD)); + sectors_per_cluster_bits = ffs(NTFS_GETU8(boot + 0xD)) - 1; + ntfs_debug(DEBUG_FILE3, "ntfs_init_volume: sectors_per_cluster_bits " + "= 0x%x\n", sectors_per_cluster_bits); vol->mft_clusters_per_record = NTFS_GETS8(boot + 0x40); + ntfs_debug(DEBUG_FILE3, "ntfs_init_volume: vol->mft_clusters_per_record" + " = 0x%x\n", vol->mft_clusters_per_record); vol->index_clusters_per_record = NTFS_GETS8(boot + 0x44); - /* Just some consistency checks. */ - if (NTFS_GETU32(boot + 0x40) > 256) - ntfs_error("Unexpected data #1 in boot block\n"); - if (NTFS_GETU32(boot+ 0x44) > 256) - ntfs_error("Unexpected data #2 in boot block\n"); - vol->clustersize = vol->blocksize << vol->clusterfactorbits; + ntfs_debug(DEBUG_FILE3, "ntfs_init_volume: " + "vol->index_clusters_per_record = 0x%x\n", + vol->index_clusters_per_record); + vol->cluster_size = vol->sector_size << sectors_per_cluster_bits; + vol->cluster_size_bits = ffs(vol->cluster_size) - 1; + ntfs_debug(DEBUG_FILE3, "ntfs_init_volume: vol->cluster_size = 0x%x\n", + vol->cluster_size); + ntfs_debug(DEBUG_FILE3, "ntfs_init_volume: vol->cluster_size_bits = " + "0x%x\n", vol->cluster_size_bits); if (vol->mft_clusters_per_record > 0) - vol->mft_recordsize = - vol->clustersize * vol->mft_clusters_per_record; - else { - /* If mft_recordsize < clustersize then mft_clusters_per_record - = -log2(mft_recordsize) bytes. Mft_recordsize normaly equals - 1024 bytes, which is encoded as 0xF6. */ - if (vol->mft_clusters_per_record < -31 || - -9 < vol->mft_clusters_per_record) { - ntfs_error("Unexpected mft clusters per record value " - "in boot block.\n"); - return -1; - } - vol->mft_recordsize = 1 << (-vol->mft_clusters_per_record); - } + vol->mft_record_size = vol->cluster_size << + (ffs(vol->mft_clusters_per_record) - 1); + else + /* + * When mft_record_size < cluster_size, mft_clusters_per_record + * = -log2(mft_record_size) bytes. mft_record_size normaly is + * 1024 bytes, which is encoded as 0xF6 (-10 in decimal). + */ + vol->mft_record_size = 1 << -vol->mft_clusters_per_record; + vol->mft_record_size_bits = ffs(vol->mft_record_size) - 1; + ntfs_debug(DEBUG_FILE3, "ntfs_init_volume: vol->mft_record_size = 0x%x" + "\n", vol->mft_record_size); + ntfs_debug(DEBUG_FILE3, "ntfs_init_volume: vol->mft_record_size_bits = " + "0x%x\n", vol->mft_record_size_bits); if (vol->index_clusters_per_record > 0) - vol->index_recordsize = - vol->clustersize * vol->index_clusters_per_record; - else { - /* If index_recordsize < clustersize then - index_clusters_per_record = -log2(index_recordsize) bytes. - Index_recordsize normaly equals 1024 bytes, which is - encoded as 0xF6. */ - if (vol->index_clusters_per_record < -31 || - -9 < vol->index_clusters_per_record) { - ntfs_error("Unexpected index clusters per record " - "value in boot block.\n"); - return -1; - } - vol->index_recordsize = 1 << (-vol->index_clusters_per_record); - } - if (NTFS_GETU64(boot + 0x30) >= (1ULL << 32)) { - ntfs_error("Would require 64-bit inodes to mount partition."); + vol->index_record_size = vol->cluster_size << + (ffs(vol->index_clusters_per_record) - 1); + else + /* + * When index_record_size < cluster_size, + * index_clusters_per_record = -log2(index_record_size) bytes. + * index_record_size normaly equals 4096 bytes, which is + * encoded as 0xF4 (-12 in decimal). + */ + vol->index_record_size = 1 << -vol->index_clusters_per_record; + vol->index_record_size_bits = ffs(vol->index_record_size) - 1; + ntfs_debug(DEBUG_FILE3, "ntfs_init_volume: vol->index_record_size = " + "0x%x\n", vol->index_record_size); + ntfs_debug(DEBUG_FILE3, "ntfs_init_volume: vol->index_record_size_bits " + "= 0x%x\n", vol->index_record_size_bits); + /* + * Check mft and mftmirr locations for 64-bit-ness. NOTE: This is a + * crude check only as many other things could be out of bounds later + * on, but it will catch at least some of the cases, since the mftmirr + * is located in the middle of the volume so if the volume is very + * large the mftmirr probably will be out of 32-bit bounds. + */ + vol->mft_lcn = NTFS_GETS64(boot + 0x30); + if (vol->mft_lcn >= (__s64)1 << 31 || + NTFS_GETS64(boot + 0x38) >= (__s64)1 << 31) { + ntfs_error("Cannot handle 64-bit clusters yet.\n"); return -1; } - /* FIXME: long long value */ - vol->mft_cluster = NTFS_GETU64(boot + 0x30); /* This will be initialized later. */ vol->upcase = 0; vol->upcase_length = 0; @@ -151,6 +172,11 @@ ntfs_volume *vol = attrdef->vol; ntfs_u16* name = (ntfs_u16*)def; + if (!type) { + ntfs_debug(DEBUG_OTHER, "process_atrdef: finished processing " + "and returning 1\n"); + return 1; + } if (ntfs_ua_strncmp(name, "$STANDARD_INFORMATION", 64) == 0) { vol->at_standard_information = type; check_type = 0x10; @@ -190,9 +216,12 @@ check_type = 0xC0; } if (check_type && check_type != type) { - ntfs_error("Unexpected type %x for %x\n", type, check_type); + ntfs_error("process_attrdef: unexpected type 0x%x for 0x%x\n", + type, check_type); return -EINVAL; } + ntfs_debug(DEBUG_OTHER, "process_attrdef: found %s attribute of type " + "0x%x\n", check_type ? "known" : "unknown", type); return 0; } @@ -200,9 +229,12 @@ { ntfs_u8 *buf; ntfs_io io; - int offset, error,i; + __s64 offset; + unsigned i; + int error; ntfs_attribute *data; + ntfs_debug(DEBUG_BSD, "Entered ntfs_init_attrdef()\n"); buf = ntfs_malloc(4050); /* 90*45 */ if (!buf) return -ENOMEM; @@ -211,6 +243,8 @@ io.do_read = 1; offset = 0; data = ntfs_find_attr(attrdef, attrdef->vol->at_data, 0); + ntfs_debug(DEBUG_BSD, "In ntfs_init_attrdef() after call to " + "ntfs_find_attr.\n"); if (!data) { ntfs_free(buf); return -EINVAL; @@ -218,13 +252,23 @@ do { io.param = buf; io.size = 4050; + ntfs_debug(DEBUG_BSD, "In ntfs_init_attrdef() going to call " + "ntfs_readwrite_attr.\n"); error = ntfs_readwrite_attr(attrdef, data, offset, &io); - for (i = 0; !error && i < io.size - 0xA0; i += 0xA0) + ntfs_debug(DEBUG_BSD, "In ntfs_init_attrdef() after call to " + "ntfs_readwrite_attr.\n"); + for (i = 0; !error && i <= io.size - 0xA0; i += 0xA0) { + ntfs_debug(DEBUG_BSD, "In ntfs_init_attrdef() going " + "to call process_attrdef.\n"); error = process_attrdef(attrdef, buf + i); + ntfs_debug(DEBUG_BSD, "In ntfs_init_attrdef() after " + "call to process_attrdef.\n"); + } offset += 4096; } while (!error && io.size); + ntfs_debug(DEBUG_BSD, "Exiting ntfs_init_attrdef()\n"); ntfs_free(buf); - return error; + return error == 1 ? 0 : error; } /* ntfs_get_version will determine the NTFS version of the volume and will @@ -253,7 +297,10 @@ int error; ntfs_inode upcase, attrdef, volume; - vol->mft_ino = (ntfs_inode*)ntfs_calloc(3 * sizeof(ntfs_inode)); + vol->mft_ino = (ntfs_inode*)ntfs_calloc(sizeof(ntfs_inode)); + vol->mftmirr = (ntfs_inode*)ntfs_calloc(sizeof(ntfs_inode)); + vol->bitmap = (ntfs_inode*)ntfs_calloc(sizeof(ntfs_inode)); + vol->ino_flags = 4 | 2 | 1; error = -ENOMEM; ntfs_debug(DEBUG_BSD, "Going to load MFT\n"); if (!vol->mft_ino || (error = ntfs_init_inode(vol->mft_ino, vol, @@ -263,13 +310,11 @@ return error; } ntfs_debug(DEBUG_BSD, "Going to load MIRR\n"); - vol->mftmirr = vol->mft_ino + 1; if ((error = ntfs_init_inode(vol->mftmirr, vol, FILE_$MftMirr))) { ntfs_error("Problem %d loading MFTMirr\n", error); return error; } ntfs_debug(DEBUG_BSD, "Going to load BITMAP\n"); - vol->bitmap = vol->mft_ino + 2; if ((error = ntfs_init_inode(vol->bitmap, vol, FILE_$BitMap))) { ntfs_error("Problem loading Bitmap\n"); return error; @@ -311,36 +356,48 @@ int ntfs_release_volume(ntfs_volume *vol) { - if (vol->mft_ino) { + if (((vol->ino_flags & 1) == 1) && vol->mft_ino) { ntfs_clear_inode(vol->mft_ino); - ntfs_clear_inode(vol->mftmirr); - ntfs_clear_inode(vol->bitmap); ntfs_free(vol->mft_ino); vol->mft_ino = 0; } + if (((vol->ino_flags & 2) == 2) && vol->mftmirr) { + ntfs_clear_inode(vol->mftmirr); + ntfs_free(vol->mftmirr); + vol->mftmirr = 0; + } + if (((vol->ino_flags & 4) == 4) && vol->bitmap) { + ntfs_clear_inode(vol->bitmap); + ntfs_free(vol->bitmap); + vol->bitmap = 0; + } ntfs_free(vol->mft); ntfs_free(vol->upcase); return 0; } -/* Writes the volume size into vol_size. Returns 0 if successful or error. */ -int ntfs_get_volumesize(ntfs_volume *vol, ntfs_u64 *vol_size) +/* + * Writes the volume size (units of clusters) into vol_size. + * Returns 0 if successful or error. + */ +int ntfs_get_volumesize(ntfs_volume *vol, ntfs_s64 *vol_size) { ntfs_io io; char *cluster0; if (!vol_size) return -EFAULT; - cluster0 = ntfs_malloc(vol->clustersize); + cluster0 = ntfs_malloc(vol->cluster_size); if (!cluster0) return -ENOMEM; io.fn_put = ntfs_put; io.fn_get = ntfs_get; io.param = cluster0; io.do_read = 1; - io.size = vol->clustersize; + io.size = vol->cluster_size; ntfs_getput_clusters(vol, 0, 0, &io); - *vol_size = NTFS_GETU64(cluster0 + 0x28) >> vol->clusterfactorbits; + *vol_size = NTFS_GETU64(cluster0 + 0x28) >> + (ffs(NTFS_GETU8(cluster0 + 0xD)) - 1); ntfs_free(cluster0); return 0; } @@ -349,12 +406,12 @@ int ntfs_get_free_cluster_count(ntfs_inode *bitmap) { - unsigned char bits[2048]; - int offset, error; - int clusters = 0; ntfs_io io; - - offset = 0; + int offset, error, clusters; + unsigned char *bits = ntfs_malloc(2048); + if (!bits) + return -ENOMEM; + offset = clusters = 0; io.fn_put = ntfs_put; io.fn_get = ntfs_get; while (1) { @@ -382,6 +439,7 @@ } offset += io.size; } + ntfs_free(bits); return clusters; } diff -u --recursive --new-file v2.4.6/linux/fs/ntfs/super.h linux/fs/ntfs/super.h --- v2.4.6/linux/fs/ntfs/super.h Wed Apr 18 11:49:13 2001 +++ linux/fs/ntfs/super.h Mon Jul 16 15:14:10 2001 @@ -1,7 +1,8 @@ -/* super.h - Header file for super.c +/* + * super.h - Header file for super.c * - * Copyright (C) 1995-1997 Martin von Löwis - * Copyright (C) 1996-1997 Régis Duchesne + * Copyright (C) 1995-1997 Martin von Löwis + * Copyright (C) 1996-1997 Régis Duchesne */ #define ALLOC_REQUIRE_LOCATION 1 @@ -9,7 +10,7 @@ int ntfs_get_free_cluster_count(ntfs_inode *bitmap); -int ntfs_get_volumesize(ntfs_volume *vol, ntfs_u64 *vol_size ); +int ntfs_get_volumesize(ntfs_volume *vol, __s64 *vol_size); int ntfs_init_volume(ntfs_volume *vol, char *boot); diff -u --recursive --new-file v2.4.6/linux/fs/ntfs/support.c linux/fs/ntfs/support.c --- v2.4.6/linux/fs/ntfs/support.c Wed Apr 18 11:49:13 2001 +++ linux/fs/ntfs/support.c Mon Jul 16 15:14:10 2001 @@ -1,8 +1,9 @@ -/* support.c - Specific support functions +/* + * support.c - Specific support functions * - * Copyright (C) 1997 Martin von Löwis - * Copyright (C) 1997 Régis Duchesne - * Copyright (C) 2001 Anton Altaparmakov (AIA) + * Copyright (C) 1997 Martin von Löwis + * Copyright (C) 1997 Régis Duchesne + * Copyright (C) 2001 Anton Altaparmakov (AIA) */ #include "ntfstypes.h" @@ -12,11 +13,15 @@ #include <stdarg.h> #include <linux/slab.h> #include <linux/locks.h> -#include <linux/nls.h> +#include <linux/fs.h> #include "util.h" #include "inode.h" #include "macros.h" +#ifndef NLS_MAX_CHARSET_SIZE +#include <linux/nls.h> +#endif + static char print_buf[1024]; #ifdef DEBUG @@ -29,7 +34,7 @@ va_list ap; /* Filter it with the debugging level required */ - if(ntdebug & mask){ + if (ntdebug & mask) { va_start(ap,fmt); strcpy(print_buf, KERN_DEBUG); vsprintf(print_buf + 3, fmt, ap); @@ -114,13 +119,13 @@ int error; ntfs_io io; - ntfs_debug(DEBUG_OTHER, "read_mft_record %x\n",mftno); - if(mftno == FILE_$Mft) + ntfs_debug(DEBUG_OTHER, "read_mft_record 0x%x\n", mftno); + if (mftno == FILE_$Mft) { - ntfs_memcpy(buf, vol->mft, vol->mft_recordsize); + ntfs_memcpy(buf, vol->mft, vol->mft_record_size); return 0; } - if(!vol->mft_ino) + if (!vol->mft_ino) { printk(KERN_ERR "NTFS: mft_ino is NULL. Something is terribly " "wrong here!\n"); @@ -129,28 +134,31 @@ io.fn_put = ntfs_put; io.fn_get = 0; io.param = buf; - io.size = vol->mft_recordsize; + io.size = vol->mft_record_size; + ntfs_debug(DEBUG_OTHER, "read_mft_record: calling ntfs_read_attr with: " + "mftno = 0x%x, vol->mft_record_size_bits = 0x%x, " + "mftno << vol->mft_record_size_bits = 0x%Lx\n", mftno, + vol->mft_record_size_bits, + (__s64)mftno << vol->mft_record_size_bits); error = ntfs_read_attr(vol->mft_ino, vol->at_data, NULL, - mftno * vol->mft_recordsize, &io); - if (error || (io.size != vol->mft_recordsize)) - { - ntfs_debug(DEBUG_OTHER, "read_mft_record: read %x failed " + (__s64)mftno << vol->mft_record_size_bits, &io); + if (error || (io.size != vol->mft_record_size)) { + ntfs_debug(DEBUG_OTHER, "read_mft_record: read 0x%x failed " "(%d,%d,%d)\n", mftno, error, io.size, - vol->mft_recordsize); + vol->mft_record_size); return error ? error : -ENODATA; } - ntfs_debug(DEBUG_OTHER, "read_mft_record: finished read %x\n", mftno); - if(!ntfs_check_mft_record(vol, buf)) - { + ntfs_debug(DEBUG_OTHER, "read_mft_record: finished read 0x%x\n", mftno); + if (!ntfs_check_mft_record(vol, buf)) { /* FIXME: This is incomplete behaviour. We might be able to * recover at this stage. ntfs_check_mft_record() is too * conservative at aborting it's operations. It is OK for * now as we just can't handle some on disk structures * this way. (AIA) */ - printk(KERN_WARNING "NTFS: Invalid MFT record for %x\n", mftno); + printk(KERN_WARNING "NTFS: Invalid MFT record for 0x%x\n", mftno); return -EINVAL; } - ntfs_debug(DEBUG_OTHER, "read_mft_record: Done %x\n", mftno); + ntfs_debug(DEBUG_OTHER, "read_mft_record: Done 0x%x\n", mftno); return 0; } @@ -159,32 +167,57 @@ { struct super_block *sb = NTFS_SB(vol); struct buffer_head *bh; - ntfs_size_t to_copy; int length = buf->size; + int error = 0; + ntfs_size_t to_copy; ntfs_debug(DEBUG_OTHER, "%s_clusters %d %d %d\n", buf->do_read ? "get" : "put", cluster, start_offs, length); while (length) { - if (!(bh = bread(sb->s_dev, cluster, vol->clustersize))) { + if (!(bh = bread(sb->s_dev, cluster, vol->cluster_size))) { ntfs_debug(DEBUG_OTHER, "%s failed\n", buf->do_read ? "Reading" : "Writing"); - return -EIO; + error = -EIO; + goto error_ret; } - to_copy = min(vol->clustersize - start_offs, length); + to_copy = min(vol->cluster_size - start_offs, length); lock_buffer(bh); - if (buf->do_read) + if (buf->do_read) { buf->fn_put(buf, bh->b_data + start_offs, to_copy); - else { + unlock_buffer(bh); + } else { buf->fn_get(bh->b_data + start_offs, buf, to_copy); mark_buffer_dirty(bh); + unlock_buffer(bh); + /* + * Note: We treat synchronous IO on a per volume basis + * disregarding flags of individual inodes. This can + * lead to some strange write ordering effects upon a + * remount with a change in the sync flag but it should + * not break anything. [Except if the system crashes + * at that point in time but there would be more thigs + * to worry about than that in that case...]. (AIA) + */ + if (sb->s_flags & MS_SYNCHRONOUS) { + ll_rw_block(WRITE, 1, &bh); + wait_on_buffer(bh); + if (buffer_req(bh) && !buffer_uptodate(bh)) { + printk(KERN_ERR "IO error syncing NTFS " + "cluster [%s:%i]\n", + bdevname(sb->s_dev), cluster); + brelse(bh); + error = -EIO; + goto error_ret; + } + } } - unlock_buffer(bh); length -= to_copy; start_offs = 0; cluster++; brelse(bh); } - return 0; +error_ret: + return error; } ntfs_time64_t ntfs_now(void) @@ -241,6 +274,10 @@ /* adjust result buffer */ if (chl > 1) { buf = ntfs_malloc(*out_len + chl - 1); + if (!buf) { + ntfs_free(result); + return -ENOMEM; + } memcpy(buf, result, o); ntfs_free(result); result = buf; diff -u --recursive --new-file v2.4.6/linux/fs/ntfs/support.h linux/fs/ntfs/support.h --- v2.4.6/linux/fs/ntfs/support.h Wed Apr 18 11:49:13 2001 +++ linux/fs/ntfs/support.h Mon Jul 16 15:14:10 2001 @@ -1,6 +1,8 @@ -/* support.h - Header file for specific support.c +/* + * support.h - Header file for specific support.c * - * Copyright (C) 1997 Régis Duchesne + * Copyright (C) 1997 Régis Duchesne + * Copyright (c) 2001 Anton Altaparmakov (AIA) */ /* Debug levels */ @@ -20,10 +22,15 @@ void ntfs_debug(int mask, const char *fmt, ...); #include <linux/slab.h> +#include <linux/vmalloc.h> #define ntfs_malloc(size) kmalloc(size, GFP_KERNEL) #define ntfs_free(ptr) kfree(ptr) + +#define ntfs_vmalloc(size) vmalloc_32(size) + +#define ntfs_vfree(ptr) vfree(ptr) void ntfs_bzero(void *s, int n); diff -u --recursive --new-file v2.4.6/linux/fs/ntfs/sysctl.c linux/fs/ntfs/sysctl.c --- v2.4.6/linux/fs/ntfs/sysctl.c Fri Dec 19 15:24:21 1997 +++ linux/fs/ntfs/sysctl.c Mon Jul 16 15:14:10 2001 @@ -1,10 +1,8 @@ /* - * sysctl.c - * System control stuff - * - * Copyright (C) 1997 Martin von Löwis - * Copyright (C) 1997 Régis Duchesne + * sysctl.c - System control stuff * + * Copyright (C) 1997 Martin von Löwis + * Copyright (C) 1997 Régis Duchesne */ #include "sysctl.h" @@ -55,8 +53,3 @@ } #endif /* DEBUG */ -/* - * Local variables: - * c-file-style: "linux" - * End: - */ diff -u --recursive --new-file v2.4.6/linux/fs/ntfs/sysctl.h linux/fs/ntfs/sysctl.h --- v2.4.6/linux/fs/ntfs/sysctl.h Wed Apr 18 11:49:13 2001 +++ linux/fs/ntfs/sysctl.h Mon Jul 16 15:14:10 2001 @@ -1,8 +1,8 @@ -/* sysctl.h - Header file for sysctl.c - * - * Copyright (C) 1997 Martin von Löwis - * Copyright (C) 1997 Régis Duchesne +/* + * sysctl.h - Header file for sysctl.c * + * Copyright (C) 1997 Martin von Löwis + * Copyright (C) 1997 Régis Duchesne */ #ifdef DEBUG diff -u --recursive --new-file v2.4.6/linux/fs/ntfs/unistr.c linux/fs/ntfs/unistr.c --- v2.4.6/linux/fs/ntfs/unistr.c Wed Dec 31 16:00:00 1969 +++ linux/fs/ntfs/unistr.c Mon Jul 16 15:14:10 2001 @@ -0,0 +1,167 @@ +/* + * $Id: unistr.c,v 1.4 2001/04/08 03:02:55 antona Exp $ + * + * unistr.c - Unicode string handling. Part of the Linux-NTFS project. + * + * Copyright (c) 2000,2001 Anton Altaparmakov. + * + * This program/include file 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/include file 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 (in the main directory of the Linux-NTFS + * distribution in the file COPYING); if not, write to the Free Software + * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <linux/string.h> +#include <asm/byteorder.h> + +#include "unistr.h" +#include "macros.h" + +/* + * This is used by the name collation functions to quickly determine what + * characters are (in)valid. + */ +const __u8 legal_ansi_char_array[0x40] = { + 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + + 0x17, 0x07, 0x18, 0x17, 0x17, 0x17, 0x17, 0x17, + 0x17, 0x17, 0x18, 0x16, 0x16, 0x17, 0x07, 0x00, + + 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, + 0x17, 0x17, 0x04, 0x16, 0x18, 0x16, 0x18, 0x18, +}; + +/** + * ntfs_are_names_equal - compare two Unicode names for equality + * @s1: name to compare to @s2 + * @s1_len: length in Unicode characters of @s1 + * @s2: name to compare to @s1 + * @s2_len: length in Unicode characters of @s2 + * @ic: ignore case bool + * @upcase: upcase table (only if @ic == IGNORE_CASE) + * @upcase_size: length in Unicode characters of @upcase (if present) + * + * Compare the names @s1 and @s2 and return TRUE (1) if the names are + * identical, or FALSE (0) if they are not identical. If @ic is IGNORE_CASE, + * the @upcase table is used to performa a case insensitive comparison. + */ +int ntfs_are_names_equal(wchar_t *s1, size_t s1_len, + wchar_t *s2, size_t s2_len, int ic, + wchar_t *upcase, __u32 upcase_size) +{ + if (s1_len != s2_len) + return 0; + if (!ic) + return memcmp(s1, s2, s1_len << 1) ? 0: 1; + return ntfs_wcsncasecmp(s1, s2, s1_len, upcase, upcase_size) ? 0: 1; +} + +/** + * ntfs_collate_names - collate two Unicode names + * @upcase: upcase table (ignored if @ic is CASE_SENSITIVE) + * @upcase_len: upcase table size (ignored if @ic is CASE_SENSITIVE) + * @name1: first Unicode name to compare + * @name2: second Unicode name to compare + * @ic: either CASE_SENSITIVE or IGNORE_CASE + * @err_val: if @name1 contains an invalid character return this value + * + * ntfs_collate_names collates two Unicode names and returns: + * + * -1 if the first name collates before the second one, + * 0 if the names match, + * 1 if the second name collates before the first one, or + * @ec if an invalid character is encountered in @name1 during the comparison. + * + * The following characters are considered invalid: '"', '*', '<', '>' and '?'. + */ +int ntfs_collate_names(wchar_t *upcase, __u32 upcase_len, + wchar_t *name1, __u32 name1_len, + wchar_t *name2, __u32 name2_len, + int ic, int err_val) +{ + __u32 cnt; + wchar_t c1, c2; + + for (cnt = 0; cnt < min(name1_len, name2_len); ++cnt) + { + c1 = le16_to_cpu(*name1++); + c2 = le16_to_cpu(*name2++); + if (ic) { + if (c1 < upcase_len) + c1 = le16_to_cpu(upcase[c1]); + if (c2 < upcase_len) + c2 = le16_to_cpu(upcase[c2]); + } + if (c1 < 64 && legal_ansi_char_array[c1] & 8); + return err_val; + if (c1 < c2) + return -1; + if (c1 > c2) + return 1; + ++name1; + ++name2; + } + if (name1_len < name2_len) + return -1; + if (name1_len == name2_len) + return 0; + /* name1_len > name2_len */ + c1 = le16_to_cpu(*name1); + if (c1 < 64 && legal_ansi_char_array[c1] & 8) + return err_val; + return 1; +} + +/** + * ntfs_wcsncasecmp - compare two little endian Unicode strings, ignoring case + * @s1: first string + * @s2: second string + * @n: maximum unicode characters to compare + * @upcase: upcase table + * @upcase_size: upcase table size in Unicode characters + * + * Compare the first @n characters of the Unicode strings @s1 and @s2, + * ignoring case. The strings in little endian format and appropriate + * le16_to_cpu() conversion is performed on non-little endian machines. + * + * Each character is uppercased using the @upcase table before the comparison. + * + * The function returns an integer less than, equal to, or greater than zero + * if @s1 (or the first @n Unicode characters thereof) is found, respectively, + * to be less than, to match, or be greater than @s2. + */ +int ntfs_wcsncasecmp(wchar_t *s1, wchar_t *s2, size_t n, + wchar_t *upcase, __u32 upcase_size) +{ + wchar_t c1, c2; + size_t i; + + for (i = 0; i < n; ++i) { + if ((c1 = le16_to_cpu(s1[i])) < upcase_size) + c1 = le16_to_cpu(upcase[c1]); + if ((c2 = le16_to_cpu(s2[i])) < upcase_size) + c2 = le16_to_cpu(upcase[c2]); + if (c1 < c2) + return -1; + if (c1 > c2) + return 1; + if (!c1) + break; + } + return 0; +} + diff -u --recursive --new-file v2.4.6/linux/fs/ntfs/unistr.h linux/fs/ntfs/unistr.h --- v2.4.6/linux/fs/ntfs/unistr.h Wed Dec 31 16:00:00 1969 +++ linux/fs/ntfs/unistr.h Mon Jul 16 15:14:10 2001 @@ -0,0 +1,46 @@ +/* + * $Id: unistr.h,v 1.5 2001/04/11 11:49:16 antona Exp $ + * + * unistr.h - Exports for unicode string handling. Part of the Linux-NTFS + * project. + * + * Copyright (c) 2000,2001 Anton Altaparmakov. + * + * This program/include file 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/include file 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 (in the main directory of the Linux-NTFS + * distribution in the file COPYING); if not, write to the Free Software + * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _LINUX_NTFS_UNISTR_H +#define _LINUX_NTFS_UNISTR_H + +#include <linux/types.h> +#include <linux/nls.h> + +extern const __u8 legal_ansi_char_array[0x40]; + +int ntfs_are_names_equal(wchar_t *s1, size_t s1_len, + wchar_t *s2, size_t s2_len, int ic, + wchar_t *upcase, __u32 upcase_size); + +int ntfs_collate_names(wchar_t *upcase, __u32 upcase_len, + wchar_t *name1, __u32 name1_len, + wchar_t *name2, __u32 name2_len, + int ic, int err_val); + +int ntfs_wcsncasecmp(wchar_t *s1, wchar_t *s2, size_t n, + wchar_t *upcase, __u32 upcase_size); + +#endif /* defined _LINUX_NTFS_UNISTR_H */ + diff -u --recursive --new-file v2.4.6/linux/fs/ntfs/util.c linux/fs/ntfs/util.c --- v2.4.6/linux/fs/ntfs/util.c Wed Apr 18 11:49:13 2001 +++ linux/fs/ntfs/util.c Mon Jul 16 15:14:10 2001 @@ -1,16 +1,16 @@ -/* util.c - Miscellaneous support +/* + * util.c - Miscellaneous support * - * Copyright (C) 1997,1999 Martin von Löwis - * Copyright (C) 1997 Régis Duchesne - * Copyright (C) 2001 Anton Altaparmakov (AIA) + * Copyright (C) 1997,1999 Martin von Löwis + * Copyright (C) 1997 Régis Duchesne + * Copyright (C) 2001 Anton Altaparmakov (AIA) * - * The utf8 routines are copied from Python wstrop module. + * The utf8 routines are copied from Python wstrop module. */ #include "ntfstypes.h" #include "struct.h" #include "util.h" - #include <linux/string.h> #include <linux/errno.h> #include "support.h" @@ -258,7 +258,7 @@ if (NTFS_GETU16(b + i) < NTFS_GETU16(a + i)) return 1; if (NTFS_GETU16(a + i) == 0) - return 0; + break; } return 0; } diff -u --recursive --new-file v2.4.6/linux/fs/ntfs/util.h linux/fs/ntfs/util.h --- v2.4.6/linux/fs/ntfs/util.h Wed Apr 18 11:49:13 2001 +++ linux/fs/ntfs/util.h Mon Jul 16 15:14:10 2001 @@ -1,7 +1,8 @@ -/* util.h - Header file for util.c +/* + * util.h - Header file for util.c * - * Copyright (C) 1997 Régis Duchesne - * Copyright (C) 2001 Anton Altaparmakov + * Copyright (C) 1997 Régis Duchesne + * Copyright (C) 2001 Anton Altaparmakov (AIA) */ /* Which character set is used for file names. */ @@ -16,7 +17,7 @@ /* Use a mapping table to determine printables. */ #define nct_map 16 -/* The first 16 inodes correspond to NTFS special files */ +/* The first 16 inodes correspond to NTFS special files. */ typedef enum { FILE_$Mft = 0, FILE_$MftMirr = 1, diff -u --recursive --new-file v2.4.6/linux/fs/partitions/Config.in linux/fs/partitions/Config.in --- v2.4.6/linux/fs/partitions/Config.in Fri Feb 16 16:02:37 2001 +++ linux/fs/partitions/Config.in Mon Jul 16 10:44:20 2001 @@ -37,7 +37,7 @@ "$CONFIG_SGI_IP27" != "y" ]; then define_bool CONFIG_MSDOS_PARTITION y fi - if [ "$CONFIG_AMIGA" = "y" ]; then + if [ "$CONFIG_AMIGA" = "y" -o "CONFIG_AFFS_FS" = "y" ]; then define_bool CONFIG_AMIGA_PARTITION y fi if [ "$CONFIG_MAC" = "y" ]; then diff -u --recursive --new-file v2.4.6/linux/fs/partitions/check.c linux/fs/partitions/check.c --- v2.4.6/linux/fs/partitions/check.c Tue Jul 3 17:08:21 2001 +++ linux/fs/partitions/check.c Wed Jul 11 14:55:41 2001 @@ -328,6 +328,8 @@ dev->fops, NULL); } +static struct unique_numspace disc_numspace = UNIQUE_NUMBERSPACE_INITIALISER; + static void devfs_register_disc (struct gendisk *dev, int minor) { int pos = 0; @@ -335,7 +337,6 @@ devfs_handle_t dir, slave; unsigned int devfs_flags = DEVFS_FL_DEFAULT; char dirname[64], symlink[16]; - static unsigned int disc_counter; static devfs_handle_t devfs_handle; if (dev->part[minor].de) return; @@ -356,7 +357,8 @@ } if (!devfs_handle) devfs_handle = devfs_mk_dir (NULL, "discs", NULL); - sprintf (symlink, "disc%u", disc_counter++); + dev->part[minor].number = devfs_alloc_unique_number (&disc_numspace); + sprintf (symlink, "disc%d", dev->part[minor].number); devfs_mk_symlink (devfs_handle, symlink, DEVFS_FL_DEFAULT, dirname + pos, &slave, NULL); dev->part[minor].de = @@ -386,6 +388,8 @@ if (unregister) { devfs_unregister (dev->part[minor].de); dev->part[minor].de = NULL; + devfs_dealloc_unique_number (&disc_numspace, + dev->part[minor].number); } #endif /* CONFIG_DEVFS_FS */ } diff -u --recursive --new-file v2.4.6/linux/fs/proc/base.c linux/fs/proc/base.c --- v2.4.6/linux/fs/proc/base.c Tue Jul 3 17:08:21 2001 +++ linux/fs/proc/base.c Fri Jul 20 12:39:56 2001 @@ -645,6 +645,20 @@ /* building an inode */ +static int task_dumpable(struct task_struct *task) +{ + int dumpable = 0; + struct mm_struct *mm; + + task_lock(task); + mm = task->mm; + if (mm) + dumpable = mm->dumpable; + task_unlock(task); + return dumpable; +} + + static struct inode *proc_pid_make_inode(struct super_block * sb, struct task_struct *task, int ino) { struct inode * inode; @@ -670,7 +684,7 @@ inode->u.proc_i.task = task; inode->i_uid = 0; inode->i_gid = 0; - if (ino == PROC_PID_INO || task->dumpable) { + if (ino == PROC_PID_INO || task_dumpable(task)) { inode->i_uid = task->euid; inode->i_gid = task->egid; } diff -u --recursive --new-file v2.4.6/linux/fs/proc/proc_misc.c linux/fs/proc/proc_misc.c --- v2.4.6/linux/fs/proc/proc_misc.c Fri Apr 13 20:26:07 2001 +++ linux/fs/proc/proc_misc.c Sat Jul 7 11:43:24 2001 @@ -146,51 +146,53 @@ */ #define K(x) ((x) << (PAGE_SHIFT - 10)) #define B(x) ((x) << PAGE_SHIFT) - si_meminfo(&i); - si_swapinfo(&i); - len = sprintf(page, " total: used: free: shared: buffers: cached:\n" - "Mem: %8lu %8lu %8lu %8lu %8lu %8u\n" - "Swap: %8lu %8lu %8lu\n", - B(i.totalram), B(i.totalram-i.freeram), B(i.freeram), - B(i.sharedram), B(i.bufferram), - B(atomic_read(&page_cache_size)), B(i.totalswap), - B(i.totalswap-i.freeswap), B(i.freeswap)); - /* - * Tagged format, for easy grepping and expansion. - * The above will go away eventually, once the tools - * have been updated. - */ - len += sprintf(page+len, - "MemTotal: %8lu kB\n" - "MemFree: %8lu kB\n" - "MemShared: %8lu kB\n" - "Buffers: %8lu kB\n" - "Cached: %8u kB\n" + si_meminfo(&i); + si_swapinfo(&i); + len = sprintf(page, " total: used: free: shared: buffers: cached:\n" + "Mem: %8lu %8lu %8lu %8lu %8lu %8u\n" + "Swap: %8lu %8lu %8lu\n", + B(i.totalram), B(i.totalram-i.freeram), B(i.freeram), + B(i.sharedram), B(i.bufferram), + B(atomic_read(&page_cache_size)), B(i.totalswap), + B(i.totalswap-i.freeswap), B(i.freeswap)); + /* + * Tagged format, for easy grepping and expansion. + * The above will go away eventually, once the tools + * have been updated. + */ + len += sprintf(page+len, + "MemTotal: %8lu kB\n" + "MemFree: %8lu kB\n" + "MemShared: %8lu kB\n" + "Buffers: %8lu kB\n" + "Cached: %8lu kB\n" + "SwapCached: %8lu kB\n" "Active: %8u kB\n" "Inact_dirty: %8u kB\n" "Inact_clean: %8u kB\n" "Inact_target: %8lu kB\n" - "HighTotal: %8lu kB\n" - "HighFree: %8lu kB\n" - "LowTotal: %8lu kB\n" - "LowFree: %8lu kB\n" - "SwapTotal: %8lu kB\n" - "SwapFree: %8lu kB\n", - K(i.totalram), - K(i.freeram), - K(i.sharedram), - K(i.bufferram), - K(atomic_read(&page_cache_size)), + "HighTotal: %8lu kB\n" + "HighFree: %8lu kB\n" + "LowTotal: %8lu kB\n" + "LowFree: %8lu kB\n" + "SwapTotal: %8lu kB\n" + "SwapFree: %8lu kB\n", + K(i.totalram), + K(i.freeram), + K(i.sharedram), + K(i.bufferram), + K(atomic_read(&page_cache_size) - swapper_space.nrpages), + K(swapper_space.nrpages), K(nr_active_pages), K(nr_inactive_dirty_pages), K(nr_inactive_clean_pages()), K(inactive_target), - K(i.totalhigh), - K(i.freehigh), - K(i.totalram-i.totalhigh), - K(i.freeram-i.freehigh), - K(i.totalswap), - K(i.freeswap)); + K(i.totalhigh), + K(i.freehigh), + K(i.totalram-i.totalhigh), + K(i.freeram-i.freehigh), + K(i.totalswap), + K(i.freeswap)); return proc_calc_metrics(page, start, off, count, eof, len); #undef B @@ -289,11 +291,11 @@ kstat.per_cpu_nice[cpu_logical_map(i)], kstat.per_cpu_system[cpu_logical_map(i)], jif - ( kstat.per_cpu_user[cpu_logical_map(i)] \ - + kstat.per_cpu_nice[cpu_logical_map(i)] \ - + kstat.per_cpu_system[cpu_logical_map(i)])); + + kstat.per_cpu_nice[cpu_logical_map(i)] \ + + kstat.per_cpu_system[cpu_logical_map(i)])); len += sprintf(page + len, "page %u %u\n" - "swap %u %u\n" + "swap %u %u\n" "intr %u", kstat.pgpgin >> 1, kstat.pgpgout >> 1, diff -u --recursive --new-file v2.4.6/linux/fs/reiserfs/dir.c linux/fs/reiserfs/dir.c --- v2.4.6/linux/fs/reiserfs/dir.c Tue Jul 3 17:08:21 2001 +++ linux/fs/reiserfs/dir.c Wed Jul 18 07:46:02 2001 @@ -172,7 +172,7 @@ // user space buffer is swapped out. At that time // entry can move to somewhere else memcpy (local_buf, d_name, d_reclen); - if (filldir (dirent, d_name, d_reclen, d_off, d_ino, + if (filldir (dirent, local_buf, d_reclen, d_off, d_ino, DT_UNKNOWN) < 0) { if (local_buf != small_buf) { kfree(local_buf) ; @@ -187,8 +187,6 @@ next_pos = deh_offset (deh) + 1; if (item_moved (&tmp_ih, &path_to_entry)) { - reiserfs_warning ("vs-9020: reiserfs_readdir " - "things are moving under hands. Researching..\n"); goto research; } } /* for */ @@ -202,10 +200,6 @@ delimiting key check is it directory end */ rkey = get_rkey (&path_to_entry, inode->i_sb); if (! comp_le_keys (rkey, &MIN_KEY)) { -#ifdef CONFIG_REISERFS_CHECK - reiserfs_warning ("vs-9025: reiserfs_readdir:" - "get_rkey failed. Researching..\n"); -#endif /* set pos_key to key, that is the smallest and greater that key of the last entry in the item */ set_cpu_key_k_offset (&pos_key, next_pos); diff -u --recursive --new-file v2.4.6/linux/fs/reiserfs/do_balan.c linux/fs/reiserfs/do_balan.c --- v2.4.6/linux/fs/reiserfs/do_balan.c Mon Jan 15 15:31:19 2001 +++ linux/fs/reiserfs/do_balan.c Wed Jul 18 07:46:02 2001 @@ -1626,7 +1626,7 @@ for (i = 0; i < sizeof (tb->thrown)/sizeof (tb->thrown[0]); i ++) if (!tb->thrown[i]) { tb->thrown[i] = bh; - atomic_inc(&bh->b_count) ; /* decremented in free_thrown */ + get_bh(bh) ; /* free_thrown puts this */ return; } reiserfs_warning ("store_thrown: too many thrown buffers\n"); diff -u --recursive --new-file v2.4.6/linux/fs/reiserfs/fix_node.c linux/fs/reiserfs/fix_node.c --- v2.4.6/linux/fs/reiserfs/fix_node.c Tue Jul 3 17:08:21 2001 +++ linux/fs/reiserfs/fix_node.c Wed Jul 18 07:46:02 2001 @@ -1030,7 +1030,7 @@ left, left); } #endif - atomic_dec (&(left->b_count)); + put_bh(left) ; return 1; } @@ -1123,7 +1123,7 @@ n_first_last_position = B_NR_ITEMS (p_s_parent); if ( n_position != n_first_last_position ) { *pp_s_com_father = p_s_parent; - atomic_inc (&((*pp_s_com_father)->b_count)); + get_bh(*pp_s_com_father) ; /*(*pp_s_com_father = p_s_parent)->b_count++;*/ break; } @@ -1228,8 +1228,8 @@ /* Current node is not the first child of its parent. */ /*(p_s_curf = p_s_curcf = PATH_OFFSET_PBUFFER(p_s_path, n_path_offset - 1))->b_count += 2;*/ p_s_curf = p_s_curcf = PATH_OFFSET_PBUFFER(p_s_path, n_path_offset - 1); - atomic_inc (&(p_s_curf->b_count)); - atomic_inc (&(p_s_curf->b_count)); + get_bh(p_s_curf) ; + get_bh(p_s_curf) ; p_s_tb->lkey[n_h] = n_position - 1; } else { @@ -1267,8 +1267,8 @@ /* Current node is not the last child of its parent F[n_h]. */ /*(p_s_curf = p_s_curcf = PATH_OFFSET_PBUFFER(p_s_path, n_path_offset - 1))->b_count += 2;*/ p_s_curf = p_s_curcf = PATH_OFFSET_PBUFFER(p_s_path, n_path_offset - 1); - atomic_inc (&(p_s_curf->b_count)); - atomic_inc (&(p_s_curf->b_count)); + get_bh(p_s_curf) ; + get_bh(p_s_curf) ; p_s_tb->rkey[n_h] = n_position; } diff -u --recursive --new-file v2.4.6/linux/fs/reiserfs/inode.c linux/fs/reiserfs/inode.c --- v2.4.6/linux/fs/reiserfs/inode.c Tue Jul 3 17:08:21 2001 +++ linux/fs/reiserfs/inode.c Wed Jul 18 07:46:02 2001 @@ -44,7 +44,6 @@ windex = push_journal_writer("delete_inode") ; reiserfs_delete_object (&th, inode); - reiserfs_remove_page_from_flush_list(&th, inode) ; pop_journal_writer(windex) ; reiserfs_release_objectid (&th, inode->i_ino); @@ -103,6 +102,11 @@ ih->u.ih_entry_count = cpu_to_le16 (entry_count); } +static void add_to_flushlist(struct inode *inode, struct buffer_head *bh) { + struct inode *jinode = &(SB_JOURNAL(inode->i_sb)->j_dummy_inode) ; + + buffer_insert_inode_queue(bh, jinode) ; +} // // FIXME: we might cache recently accessed indirect item (or at least @@ -129,60 +133,6 @@ ** --chris */ -/* people who call journal_begin with a page locked must call this -** BEFORE calling journal_begin -*/ -static int prevent_flush_page_lock(struct page *page, - struct inode *inode) { - struct reiserfs_page_list *pl ; - struct super_block *s = inode->i_sb ; - /* we don't care if the inode has a stale pointer from an old - ** transaction - */ - if(!page || inode->u.reiserfs_i.i_conversion_trans_id != SB_JOURNAL(s)->j_trans_id) { - return 0 ; - } - pl = inode->u.reiserfs_i.i_converted_page ; - if (pl && pl->page == page) { - pl->do_not_lock = 1 ; - } - /* this last part is really important. The address space operations have - ** the page locked before they call the journal functions. So it is possible - ** for one process to be waiting in flush_pages_before_commit for a - ** page, then for the process with the page locked to call journal_begin. - ** - ** We'll deadlock because the process flushing pages will never notice - ** the process with the page locked has called prevent_flush_page_lock. - ** So, we wake up the page waiters, even though the page is still locked. - ** The process waiting in flush_pages_before_commit must check the - ** pl->do_not_lock flag, and stop trying to lock the page. - */ - wake_up(&page->wait) ; - return 0 ; - -} -/* people who call journal_end with a page locked must call this -** AFTER calling journal_end -*/ -static int allow_flush_page_lock(struct page *page, - struct inode *inode) { - - struct reiserfs_page_list *pl ; - struct super_block *s = inode->i_sb ; - /* we don't care if the inode has a stale pointer from an old - ** transaction - */ - if(!page || inode->u.reiserfs_i.i_conversion_trans_id != SB_JOURNAL(s)->j_trans_id) { - return 0 ; - } - pl = inode->u.reiserfs_i.i_converted_page ; - if (pl && pl->page == page) { - pl->do_not_lock = 0 ; - } - return 0 ; - -} - /* If this page has a file tail in it, and ** it was read in by get_block_create_0, the page data is valid, ** but tail is still sitting in a direct item, and we can't write to @@ -324,7 +274,7 @@ } // - bh = get_bh (&path); + bh = get_last_bh (&path); ih = get_ih (&path); if (is_indirect_le_ih (ih)) { __u32 * ind_item = (__u32 *)B_I_PITEM (bh, ih); @@ -419,7 +369,7 @@ if (search_for_position_by_key (inode->i_sb, &key, &path) != POSITION_FOUND) // we read something from tail, even if now we got IO_ERROR break; - bh = get_bh (&path); + bh = get_last_bh (&path); ih = get_ih (&path); } while (1); @@ -607,7 +557,6 @@ return -EIO; } - prevent_flush_page_lock(bh_result->b_page, inode) ; inode->u.reiserfs_i.i_pack_on_close = 1 ; windex = push_journal_writer("reiserfs_get_block") ; @@ -628,7 +577,7 @@ goto failure; } - bh = get_bh (&path); + bh = get_last_bh (&path); ih = get_ih (&path); item = get_item (&path); pos_in_item = path.pos_in_item; @@ -693,7 +642,6 @@ if (transaction_started) journal_end(&th, inode->i_sb, jbegin_count) ; - allow_flush_page_lock(bh_result->b_page, inode) ; unlock_kernel() ; /* the item was found, so new blocks were not added to the file @@ -794,8 +742,12 @@ /* we've converted the tail, so we must ** flush unbh before the transaction commits */ - reiserfs_add_page_to_flush_list(&th, inode, unbh) ; - mark_buffer_dirty(unbh) ; + add_to_flushlist(inode, unbh) ; + + /* mark it dirty now to prevent commit_write from adding + ** this buffer to the inode's dirty buffer list + */ + __mark_buffer_dirty(unbh) ; //inode->i_blocks += inode->i_sb->s_blocksize / 512; //mark_tail_converted (inode); @@ -871,7 +823,7 @@ pathrelse(&path) ; goto failure; } - bh = get_bh (&path); + bh = get_last_bh (&path); ih = get_ih (&path); item = get_item (&path); pos_in_item = path.pos_in_item; @@ -887,7 +839,6 @@ journal_end(&th, inode->i_sb, jbegin_count) ; } pop_journal_writer(windex) ; - allow_flush_page_lock(bh_result->b_page, inode) ; unlock_kernel() ; reiserfs_check_path(&path) ; return retval; @@ -914,7 +865,6 @@ copy_key (INODE_PKEY (inode), &(ih->ih_key)); - inode->i_generation = INODE_PKEY (inode)->k_dir_id; inode->i_blksize = PAGE_SIZE; INIT_LIST_HEAD(&inode->u.reiserfs_i.i_prealloc_list) ; @@ -934,6 +884,7 @@ inode->i_ctime = le32_to_cpu (sd->sd_ctime); inode->i_blocks = le32_to_cpu (sd->u.sd_blocks); + inode->i_generation = INODE_PKEY (inode)->k_dir_id; blocks = (inode->i_size + 511) >> 9; blocks = _ROUND_UP (blocks, inode->i_blksize >> 9); if (inode->i_blocks > blocks) { @@ -968,6 +919,10 @@ inode->i_ctime = le32_to_cpu (sd->sd_ctime); inode->i_blocks = le32_to_cpu (sd->sd_blocks); rdev = le32_to_cpu (sd->u.sd_rdev); + if( S_ISCHR( inode -> i_mode ) || S_ISBLK( inode -> i_mode ) ) + inode->i_generation = INODE_PKEY (inode)->k_dir_id; + else + inode->i_generation = le32_to_cpu( sd->u.sd_generation ); } /* nopack = 0, by default */ @@ -1005,8 +960,11 @@ sd_v2->sd_atime = cpu_to_le32 (inode->i_atime); sd_v2->sd_ctime = cpu_to_le32 (inode->i_ctime); sd_v2->sd_blocks = cpu_to_le32 (inode->i_blocks); - if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) + if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) { sd_v2->u.sd_rdev = cpu_to_le32 (inode->i_rdev); + } else { + sd_v2->u.sd_generation = cpu_to_le32( inode -> i_generation ); + } } @@ -1099,7 +1057,7 @@ ** FS might change. We have to detect that, and loop back to the ** search if the stat data item has moved */ - bh = get_bh(&path) ; + bh = get_last_bh(&path) ; ih = get_ih(&path) ; copy_item_head (&tmp_ih, ih); fs_gen = get_generation (inode->i_sb); @@ -1208,10 +1166,20 @@ key.on_disk_key.k_objectid = data[0] ; key.on_disk_key.k_dir_id = data[1] ; inode = reiserfs_iget(sb, &key) ; + if (inode && (fhtype == 3 || fhtype == 6) && + data[2] != inode->i_generation) { + iput(inode) ; + inode = NULL ; + } } else { - key.on_disk_key.k_objectid = data[2] ; - key.on_disk_key.k_dir_id = data[3] ; + key.on_disk_key.k_objectid = data[fhtype==6?3:2] ; + key.on_disk_key.k_dir_id = data[fhtype==6?4:3] ; inode = reiserfs_iget(sb, &key) ; + if (inode && fhtype == 6 && + data[5] != inode->i_generation) { + iput(inode) ; + inode = NULL ; + } } out: if (!inode) @@ -1246,21 +1214,23 @@ struct inode *inode = dentry->d_inode ; int maxlen = *lenp; - if (maxlen < 2) + if (maxlen < 3) return 255 ; data[0] = inode->i_ino ; data[1] = le32_to_cpu(INODE_PKEY (inode)->k_dir_id) ; - *lenp = 2; + data[2] = inode->i_generation ; + *lenp = 3; /* no room for directory info? return what we've stored so far */ - if (maxlen < 4 || ! need_parent) - return 2 ; + if (maxlen < 6 || ! need_parent) + return 3; inode = dentry->d_parent->d_inode ; - data[2] = inode->i_ino ; - data[3] = le32_to_cpu(INODE_PKEY (inode)->k_dir_id) ; - *lenp = 4; - return 4; + data[3] = inode->i_ino ; + data[4] = le32_to_cpu(INODE_PKEY (inode)->k_dir_id) ; + data[5] = inode->i_generation ; + *lenp = 6; + return 6; } @@ -1447,6 +1417,20 @@ return NULL; } if (old_format_only (sb)) + /* not a perfect generation count, as object ids can be reused, but this + ** is as good as reiserfs can do right now. + ** note that the private part of inode isn't filled in yet, we have + ** to use the directory. + */ + inode->i_generation = INODE_PKEY (dir)->k_objectid; + else +#if defined( USE_INODE_GENERATION_COUNTER ) + inode->i_generation = + le32_to_cpu( sb -> u.reiserfs_sb.s_rs -> s_inode_generation ); +#else + inode->i_generation = ++event; +#endif + if (old_format_only (sb)) make_le_item_head (&ih, 0, ITEM_VERSION_1, SD_OFFSET, TYPE_STAT_DATA, SD_V1_SIZE, MAX_US_INT); else make_le_item_head (&ih, 0, ITEM_VERSION_2, SD_OFFSET, TYPE_STAT_DATA, SD_SIZE, MAX_US_INT); @@ -1536,10 +1520,6 @@ return NULL; } - /* not a perfect generation count, as object ids can be reused, but this - ** is as good as reiserfs can do right now - */ - inode->i_generation = INODE_PKEY (inode)->k_dir_id; insert_inode_hash (inode); // we do not mark inode dirty: on disk content matches to the // in-core one @@ -1671,13 +1651,11 @@ ** because the truncate might pack the item anyway ** (it will unmap bh if it packs). */ - prevent_flush_page_lock(page, p_s_inode) ; journal_begin(&th, p_s_inode->i_sb, JOURNAL_PER_BALANCE_CNT * 2 ) ; windex = push_journal_writer("reiserfs_vfs_truncate_file") ; reiserfs_do_truncate (&th, p_s_inode, page, update_timestamps) ; pop_journal_writer(windex) ; journal_end(&th, p_s_inode->i_sb, JOURNAL_PER_BALANCE_CNT * 2 ) ; - allow_flush_page_lock(page, p_s_inode) ; if (page) { length = offset & (blocksize - 1) ; @@ -1719,7 +1697,6 @@ start_over: lock_kernel() ; - prevent_flush_page_lock(bh_result->b_page, inode) ; journal_begin(&th, inode->i_sb, jbegin_count) ; make_cpu_key(&key, inode, byte_offset, TYPE_ANY, 3) ; @@ -1731,7 +1708,7 @@ goto out ; } - bh = get_bh(&path) ; + bh = get_last_bh(&path) ; ih = get_ih(&path) ; item = get_item(&path) ; pos_in_item = path.pos_in_item ; @@ -1785,7 +1762,6 @@ out: pathrelse(&path) ; journal_end(&th, inode->i_sb, jbegin_count) ; - allow_flush_page_lock(bh_result->b_page, inode) ; unlock_kernel() ; /* this is where we fill in holes in the file. */ @@ -1814,7 +1790,7 @@ for(i = 0 ; i < nr ; i++) { bh = bhp[i] ; lock_buffer(bh) ; - atomic_inc(&bh->b_count) ; /* async end_io handler decs this */ + get_bh(bh) ; /* async end_io handler puts this */ set_buffer_async_io(bh) ; /* submit_bh doesn't care if the buffer is dirty, but nobody ** later on in the call chain will be cleaning it. So, we @@ -1950,29 +1926,27 @@ return generic_block_bmap(as, block, reiserfs_bmap) ; } +static int reiserfs_commit_write(struct file *f, struct page *page, + unsigned from, unsigned to) { + struct inode *inode = page->mapping->host; + int ret ; -static int reiserfs_commit_write(struct file *f, struct page *page, - unsigned from, unsigned to) { - struct inode *inode = page->mapping->host ; - int ret ; - struct reiserfs_transaction_handle th ; - reiserfs_wait_on_write_block(inode->i_sb) ; - lock_kernel(); - prevent_flush_page_lock(page, inode) ; ret = generic_commit_write(f, page, from, to) ; + /* we test for O_SYNC here so we can commit the transaction ** for any packed tails the file might have had */ if (f->f_flags & O_SYNC) { + struct reiserfs_transaction_handle th ; + lock_kernel() ; journal_begin(&th, inode->i_sb, 1) ; reiserfs_prepare_for_journal(inode->i_sb, SB_BUFFER_WITH_SB(inode->i_sb), 1) ; journal_mark_dirty(&th, inode->i_sb, SB_BUFFER_WITH_SB(inode->i_sb)) ; journal_end_sync(&th, inode->i_sb, 1) ; + unlock_kernel() ; } - allow_flush_page_lock(page, inode) ; - unlock_kernel(); return ret ; } diff -u --recursive --new-file v2.4.6/linux/fs/reiserfs/journal.c linux/fs/reiserfs/journal.c --- v2.4.6/linux/fs/reiserfs/journal.c Tue Jul 3 17:08:21 2001 +++ linux/fs/reiserfs/journal.c Wed Jul 18 07:46:02 2001 @@ -114,11 +114,7 @@ static int reiserfs_clean_and_file_buffer(struct buffer_head *bh) { if (bh) { clear_bit(BH_Dirty, &bh->b_state) ; -#if 0 - if (bh->b_list != BUF_CLEAN) { - reiserfs_file_buffer(bh, BUF_CLEAN) ; - } -#endif + refile_buffer(bh) ; } return 0 ; } @@ -711,7 +707,7 @@ } ll_rw_block(WRITE, 1, &tbh) ; count++ ; - atomic_dec(&(tbh->b_count)) ; /* once for our get_hash */ + put_bh(tbh) ; /* once for our get_hash */ } } @@ -726,7 +722,7 @@ if (!buffer_uptodate(tbh)) { reiserfs_panic(s, "journal-601, buffer write failed\n") ; } - atomic_dec(&(tbh->b_count)) ; /* once for our get_hash */ + put_bh(tbh) ; /* once for our get_hash */ bforget(tbh) ; /* once due to original getblk in do_journal_end */ atomic_dec(&(jl->j_commit_left)) ; } @@ -873,9 +869,11 @@ } mark_buffer_uptodate(bh, uptodate) ; unlock_buffer(bh) ; + put_bh(bh) ; } static void submit_logged_buffer(struct buffer_head *bh) { lock_buffer(bh) ; + get_bh(bh) ; bh->b_end_io = reiserfs_end_buffer_io_sync ; mark_buffer_notjournal_new(bh) ; clear_bit(BH_Dirty, &bh->b_state) ; @@ -971,13 +969,13 @@ /* we do this to make sure nobody releases the buffer while ** we are working with it */ - atomic_inc(&(saved_bh->b_count)) ; + get_bh(saved_bh) ; if (buffer_journal_dirty(saved_bh)) { was_jwait = 1 ; mark_buffer_notjournal_dirty(saved_bh) ; - /* brelse the inc from journal_mark_dirty */ - atomic_dec(&(saved_bh->b_count)) ; + /* undo the inc from journal_mark_dirty */ + put_bh(saved_bh) ; } if (can_dirty(cn)) { was_dirty = 1 ; @@ -1020,7 +1018,7 @@ } if (was_dirty) { /* we inc again because saved_bh gets decremented at free_cnode */ - atomic_inc(&(saved_bh->b_count)) ; + get_bh(saved_bh) ; set_bit(BLOCK_NEEDS_FLUSH, &cn->state) ; submit_logged_buffer(saved_bh) ; count++ ; @@ -1033,7 +1031,7 @@ cn = cn->next ; if (saved_bh) { /* we incremented this to keep others from taking the buffer head away */ - atomic_dec(&(saved_bh->b_count)); + put_bh(saved_bh) ; if (atomic_read(&(saved_bh->b_count)) < 0) { printk("journal-945: saved_bh->b_count < 0") ; } @@ -1889,6 +1887,7 @@ memset(journal_writers, 0, sizeof(char *) * 512) ; /* debug code */ INIT_LIST_HEAD(&SB_JOURNAL(p_s_sb)->j_bitmap_nodes) ; + INIT_LIST_HEAD(&(SB_JOURNAL(p_s_sb)->j_dummy_inode.i_dirty_buffers)) ; reiserfs_allocate_list_bitmaps(p_s_sb, SB_JOURNAL(p_s_sb)->j_list_bitmap, SB_BMAP_NR(p_s_sb)) ; allocate_bitmap_nodes(p_s_sb) ; @@ -2179,7 +2178,7 @@ cn->jlist = NULL ; insert_journal_hash(SB_JOURNAL(p_s_sb)->j_hash_table, cn) ; if (!count_already_incd) { - atomic_inc(&(bh->b_count)) ; + get_bh(bh) ; } } cn->next = NULL ; @@ -2251,7 +2250,7 @@ if (!already_cleaned) { mark_buffer_notjournal_dirty(bh) ; - atomic_dec(&(bh->b_count)) ; + put_bh(bh) ; if (atomic_read(&(bh->b_count)) < 0) { printk("journal-1752: remove from trans, b_count < 0\n") ; } @@ -2582,11 +2581,8 @@ ** in the current trans */ mark_buffer_notjournal_dirty(cn->bh) ; - if (!buffer_locked(cn->bh)) { - reiserfs_clean_and_file_buffer(cn->bh) ; - } cleaned = 1 ; - atomic_dec(&(cn->bh->b_count)) ; + put_bh(cn->bh) ; if (atomic_read(&(cn->bh->b_count)) < 0) { printk("journal-2138: cn->bh->b_count < 0\n") ; } @@ -2602,7 +2598,8 @@ } if (bh) { - atomic_dec(&(bh->b_count)) ; /* get_hash incs this */ + reiserfs_clean_and_file_buffer(bh) ; + put_bh(bh) ; /* get_hash grabs the buffer */ if (atomic_read(&(bh->b_count)) < 0) { printk("journal-2165: bh->b_count < 0\n") ; } @@ -2656,275 +2653,6 @@ } } -/* - * Wait for a page to get unlocked. - * - * This must be called with the caller "holding" the page, - * ie with increased "page->count" so that the page won't - * go away during the wait.. - */ -static void ___reiserfs_wait_on_page(struct reiserfs_page_list *pl) -{ - struct task_struct *tsk = current; - struct page *page = pl->page ; - DECLARE_WAITQUEUE(wait, tsk); - - add_wait_queue(&page->wait, &wait); - do { - block_sync_page(page); - set_task_state(tsk, TASK_UNINTERRUPTIBLE); - if (!PageLocked(page) || pl->do_not_lock) - break; - schedule(); - } while (PageLocked(page)); - tsk->state = TASK_RUNNING; - remove_wait_queue(&page->wait, &wait); -} - -/* - * Get an exclusive lock on the page.. - * but, every time you get woken up, check the page to make sure - * someone hasn't called a journal_begin with it locked. - * - * the page should always be locked when this returns - * - * returns 0 if you've got the page locked - * returns 1 if it returns because someone else has called journal_begin - * with the page locked - * this is only useful to the code that flushes pages before a - * commit. Do not export this hack. Ever. - */ -static int reiserfs_try_lock_page(struct reiserfs_page_list *pl) -{ - struct page *page = pl->page ; - while (TryLockPage(page)) { - if (pl->do_not_lock) { - /* the page is locked, but we cannot have it */ - return 1 ; - } - ___reiserfs_wait_on_page(pl); - } - /* we have the page locked */ - return 0 ; -} - - -/* -** This can only be called from do_journal_end. -** it runs through the list things that need flushing before the -** transaction can commit, and writes each of them to disk -** -*/ - -static void flush_pages_before_commit(struct reiserfs_transaction_handle *th, - struct super_block *p_s_sb) { - struct reiserfs_page_list *pl = SB_JOURNAL(p_s_sb)->j_flush_pages ; - struct reiserfs_page_list *pl_tmp ; - struct buffer_head *bh, *head ; - int count = 0 ; - - /* first write each dirty unlocked buffer in the list */ - - while(pl) { - /* ugly. journal_end can be called from get_block, which has a - ** page locked. So, we have to check to see if pl->page is the page - ** currently locked by the calling function, and if so, skip the - ** lock - */ - if (reiserfs_try_lock_page(pl)) { - goto setup_next ; - } - if (!PageLocked(pl->page)) { - BUG() ; - } - if (pl->page->buffers) { - head = pl->page->buffers ; - bh = head ; - do { - if (bh->b_blocknr == pl->blocknr && buffer_dirty(bh) && - !buffer_locked(bh) && buffer_uptodate(bh) ) { - ll_rw_block(WRITE, 1, &bh) ; - } - bh = bh->b_this_page ; - } while (bh != head) ; - } - if (!pl->do_not_lock) { - UnlockPage(pl->page) ; - } -setup_next: - pl = pl->next ; - } - - /* now wait on them */ - - pl = SB_JOURNAL(p_s_sb)->j_flush_pages ; - while(pl) { - if (reiserfs_try_lock_page(pl)) { - goto remove_page ; - } - if (!PageLocked(pl->page)) { - BUG() ; - } - if (pl->page->buffers) { - head = pl->page->buffers ; - bh = head ; - do { - if (bh->b_blocknr == pl->blocknr) { - count++ ; - wait_on_buffer(bh) ; - if (!buffer_uptodate(bh)) { - reiserfs_panic(p_s_sb, "journal-2443: flush_pages_before_commit, error writing block %lu\n", bh->b_blocknr) ; - } - } - bh = bh->b_this_page ; - } while (bh != head) ; - } - if (!pl->do_not_lock) { - UnlockPage(pl->page) ; - } -remove_page: - /* we've waited on the I/O, we can remove the page from the - ** list, and free our pointer struct to it. - */ - if (pl->prev) { - pl->prev->next = pl->next ; - } - if (pl->next) { - pl->next->prev = pl->prev ; - } - put_page(pl->page) ; - pl_tmp = pl ; - pl = pl->next ; - reiserfs_kfree(pl_tmp, sizeof(struct reiserfs_page_list), p_s_sb) ; - } - SB_JOURNAL(p_s_sb)->j_flush_pages = NULL ; -} - -/* -** called when a indirect item is converted back into a tail. -** -** The reiserfs part of the inode stores enough information to find -** our page_list struct in the flush list. We remove it from the list -** and free the struct. -** -** Note, it is possible for this to happen: -** -** reiserfs_add_page_to_flush_list(inode) -** transaction ends, list is flushed -** reiserfs_remove_page_from_flush_list(inode) -** -** This would be bad because the page_list pointer in the inode is not -** updated when the list is flushed, so we can't know if the pointer is -** valid. So, in the inode, we also store the transaction id when the -** page was added. If we are trying to remove something from an old -** transaction, we just clear out the pointer in the inode and return. -** -** Normal case is to use the reiserfs_page_list pointer in the inode to -** find and remove the page from the flush list. -*/ -int reiserfs_remove_page_from_flush_list(struct reiserfs_transaction_handle *th, - struct inode *inode) { - struct reiserfs_page_list *pl ; - - /* was this conversion done in a previous transaction? If so, return */ - if (inode->u.reiserfs_i.i_conversion_trans_id < th->t_trans_id) { - inode->u.reiserfs_i.i_converted_page = NULL ; - inode->u.reiserfs_i.i_conversion_trans_id = 0 ; - return 0 ; - } - - /* remove the page_list struct from the list, release our hold on the - ** page, and free the page_list struct - */ - pl = inode->u.reiserfs_i.i_converted_page ; - if (pl) { - if (pl->next) { - pl->next->prev = pl->prev ; - } - if (pl->prev) { - pl->prev->next = pl->next ; - } - if (SB_JOURNAL(inode->i_sb)->j_flush_pages == pl) { - SB_JOURNAL(inode->i_sb)->j_flush_pages = pl->next ; - } - put_page(pl->page) ; - reiserfs_kfree(pl, sizeof(struct reiserfs_page_list), inode->i_sb) ; - inode->u.reiserfs_i.i_converted_page = NULL ; - inode->u.reiserfs_i.i_conversion_trans_id = 0 ; - } - return 0 ; -} - -/* -** Called after a direct to indirect transaction. The unformatted node -** must be flushed to disk before the transaction commits, otherwise, we -** risk losing the data from the direct item. This adds the page -** containing the unformatted node to a list of pages that need flushing. -** -** it calls get_page(page), so the page won't disappear until we've -** flushed or removed it from our list. -** -** pointers to the reiserfs_page_list struct are stored in the inode, -** so this page can be quickly removed from the list after the tail is -** converted back into a direct item. -** -** If we fail to find the memory for the reiserfs_page_list struct, we -** just sync the page now. Not good, but safe. -** -** since this must be called with the page locked, we always set -** the do_not_lock field in the page_list struct we allocate -** -*/ -int reiserfs_add_page_to_flush_list(struct reiserfs_transaction_handle *th, - struct inode *inode, - struct buffer_head *bh) { - struct reiserfs_page_list *new_pl ; - -/* debugging use ONLY. Do not define this on data you care about. */ -#ifdef REISERFS_NO_FLUSH_AFTER_CONVERT - return 0 ; -#endif - - get_page(bh->b_page) ; - new_pl = reiserfs_kmalloc(sizeof(struct reiserfs_page_list), GFP_NOFS, - inode->i_sb) ; - if (!new_pl) { - put_page(bh->b_page) ; - reiserfs_warning("journal-2480: forced to flush page, out of memory\n") ; - ll_rw_block(WRITE, 1, &bh) ; - wait_on_buffer(bh) ; - if (!buffer_uptodate(bh)) { - reiserfs_panic(inode->i_sb, "journal-2484: error writing buffer %lu to disk\n", bh->b_blocknr) ; - } - inode->u.reiserfs_i.i_converted_page = NULL ; - return 0 ; - } - - new_pl->page = bh->b_page ; - new_pl->do_not_lock = 1 ; - new_pl->blocknr = bh->b_blocknr ; - new_pl->next = SB_JOURNAL(inode->i_sb)->j_flush_pages; - if (new_pl->next) { - new_pl->next->prev = new_pl ; - } - new_pl->prev = NULL ; - SB_JOURNAL(inode->i_sb)->j_flush_pages = new_pl ; - - /* if we have numbers from an old transaction, zero the converted - ** page, it has already been flushed and freed - */ - if (inode->u.reiserfs_i.i_conversion_trans_id && - inode->u.reiserfs_i.i_conversion_trans_id < th->t_trans_id) { - inode->u.reiserfs_i.i_converted_page = NULL ; - } - if (inode->u.reiserfs_i.i_converted_page) { - reiserfs_panic(inode->i_sb, "journal-2501: inode already had a converted page\n") ; - } - inode->u.reiserfs_i.i_converted_page = new_pl ; - inode->u.reiserfs_i.i_conversion_trans_id = th->t_trans_id ; - return 0 ; -} - /* ** long and ugly. If flush, will not return until all commit ** blocks and all real buffers in the trans are on disk. @@ -3137,11 +2865,8 @@ jindex = (SB_JOURNAL_LIST_INDEX(p_s_sb) + 1) % JOURNAL_LIST_COUNT ; SB_JOURNAL_LIST_INDEX(p_s_sb) = jindex ; - /* make sure to flush any data converted from direct items to - ** indirect items before allowing the commit blocks to reach the - ** disk - */ - flush_pages_before_commit(th, p_s_sb) ; + /* write any buffers that must hit disk before this commit is done */ + fsync_inode_buffers(&(SB_JOURNAL(p_s_sb)->j_dummy_inode)) ; /* honor the flush and async wishes from the caller */ if (flush) { diff -u --recursive --new-file v2.4.6/linux/fs/reiserfs/namei.c linux/fs/reiserfs/namei.c --- v2.4.6/linux/fs/reiserfs/namei.c Tue Jul 3 17:08:21 2001 +++ linux/fs/reiserfs/namei.c Wed Jul 18 07:46:02 2001 @@ -72,7 +72,7 @@ // comment? maybe something like set de to point to what the path points to? static inline void set_de_item_location (struct reiserfs_dir_entry * de, struct path * path) { - de->de_bh = get_bh (path); + de->de_bh = get_last_bh (path); de->de_ih = get_ih (path); de->de_deh = B_I_DEH (de->de_bh, de->de_ih); de->de_item_num = PATH_LAST_POSITION (path); diff -u --recursive --new-file v2.4.6/linux/fs/reiserfs/stree.c linux/fs/reiserfs/stree.c --- v2.4.6/linux/fs/reiserfs/stree.c Tue Jul 3 17:08:21 2001 +++ linux/fs/reiserfs/stree.c Wed Jul 18 07:46:02 2001 @@ -436,7 +436,7 @@ ) { if ( p_s_bh ) { if ( atomic_read (&(p_s_bh->b_count)) ) { - atomic_dec (&(p_s_bh->b_count)); + put_bh(p_s_bh) ; return; } reiserfs_panic(NULL, "PAP-5070: decrement_bcount: trying to free free buffer %b", p_s_bh); @@ -1032,7 +1032,7 @@ } /* Cut one record from the directory item. */ - *cut_size = -(DEH_SIZE + entry_length (get_bh (path), le_ih, pos_in_item (path))); + *cut_size = -(DEH_SIZE + entry_length (get_last_bh (path), le_ih, pos_in_item (path))); return M_CUT; } @@ -1192,13 +1192,21 @@ /* Search for the buffer in cache. */ p_s_un_bh = get_hash_table(p_s_sb->s_dev, *p_n_unfm_pointer, n_blk_size); - if (p_s_un_bh && buffer_locked(p_s_un_bh)) { - __wait_on_buffer(p_s_un_bh) ; - if ( item_moved (&s_ih, p_s_path) ) { - need_research = 1; - brelse(p_s_un_bh) ; - break ; - } + if (p_s_un_bh) { + mark_buffer_clean(p_s_un_bh) ; + if (buffer_locked(p_s_un_bh)) { + __wait_on_buffer(p_s_un_bh) ; + } + /* even if the item moves, the block number of the + ** unformatted node we want to cut won't. So, it was + ** safe to clean the buffer here, this block _will_ + ** get freed during this call to prepare_for_delete_or_cut + */ + if ( item_moved (&s_ih, p_s_path) ) { + need_research = 1; + brelse(p_s_un_bh) ; + break ; + } } if ( p_s_un_bh && block_in_use (p_s_un_bh)) { /* Block is locked or held more than by one holder and by @@ -1243,30 +1251,7 @@ if ( item_moved (&s_ih, p_s_path) ) { need_research = 1; break ; -#if 0 - reiserfs_prepare_for_journal(p_s_sb, - PATH_PLAST_BUFFER(p_s_path), - 1) ; - if ( comp_items(&s_ih, p_s_path) ) { - reiserfs_restore_prepared_buffer(p_s_sb, - PATH_PLAST_BUFFER(p_s_path)) ; - brelse(p_s_un_bh); - break; - } - *p_n_unfm_pointer = 0; - journal_mark_dirty (th,p_s_sb,PATH_PLAST_BUFFER(p_s_path)); - - reiserfs_free_block(th, p_s_sb, block_addr); - if (p_s_un_bh) { - mark_buffer_clean (p_s_un_bh); - brelse (p_s_un_bh); - } - if ( comp_items(&s_ih, p_s_path) ) { - break ; - } -#endif } - } /* a trick. If the buffer has been logged, this @@ -1560,6 +1545,17 @@ reiserfs_warning("clm-4001: deleting inode with link count==%d\n", inode->i_nlink) ; } #endif +#if defined( USE_INODE_GENERATION_COUNTER ) + if( !old_format_only ( th -> t_super ) ) + { + __u32 *inode_generation; + + inode_generation = + &th -> t_super -> u.reiserfs_sb.s_rs -> s_inode_generation; + *inode_generation = cpu_to_le32( le32_to_cpu( *inode_generation ) + 1 ); + } +/* USE_INODE_GENERATION_COUNTER */ +#endif reiserfs_delete_solid_item (th, INODE_PKEY (inode)); } @@ -1793,11 +1789,11 @@ do_balance(&s_cut_balance, NULL, NULL, c_mode); if ( n_is_inode_locked ) { - /* we've converted from indirect to direct, we must remove - ** ourselves from the list of pages that need flushing before - ** this transaction can commit + /* we've done an indirect->direct conversion. when the data block + ** was freed, it was removed from the list of blocks that must + ** be flushed before the transaction commits, so we don't need to + ** deal with it here. */ - reiserfs_remove_page_from_flush_list(th, p_s_inode) ; p_s_inode->u.reiserfs_i.i_pack_on_close = 0 ; } return n_ret_value; @@ -1960,15 +1956,15 @@ struct item_head * found_ih = get_ih (path); if (is_direct_le_ih (found_ih)) { - if (le_ih_k_offset (found_ih) + op_bytes_number (found_ih, get_bh (path)->b_size) != + if (le_ih_k_offset (found_ih) + op_bytes_number (found_ih, get_last_bh (path)->b_size) != cpu_key_k_offset (p_s_key) || - op_bytes_number (found_ih, get_bh (path)->b_size) != pos_in_item (path)) + op_bytes_number (found_ih, get_last_bh (path)->b_size) != pos_in_item (path)) reiserfs_panic (0, "PAP-5720: check_research_for_paste: " "found direct item %h or position (%d) does not match to key %K", found_ih, pos_in_item (path), p_s_key); } if (is_indirect_le_ih (found_ih)) { - if (le_ih_k_offset (found_ih) + op_bytes_number (found_ih, get_bh (path)->b_size) != cpu_key_k_offset (p_s_key) || + if (le_ih_k_offset (found_ih) + op_bytes_number (found_ih, get_last_bh (path)->b_size) != cpu_key_k_offset (p_s_key) || I_UNFM_NUM (found_ih) != pos_in_item (path) || get_ih_free_space (found_ih) != 0) reiserfs_panic (0, "PAP-5730: check_research_for_paste: " diff -u --recursive --new-file v2.4.6/linux/fs/sysv/dir.c linux/fs/sysv/dir.c --- v2.4.6/linux/fs/sysv/dir.c Tue Jul 3 17:08:21 2001 +++ linux/fs/sysv/dir.c Tue Jul 17 18:53:55 2001 @@ -40,6 +40,8 @@ { struct inode *dir = (struct inode *)page->mapping->host; int err = 0; + + dir->i_version = ++event; page->mapping->a_ops->commit_write(NULL, page, from, to); if (IS_SYNC(dir)) err = waitfor_one_page(page); @@ -109,6 +111,7 @@ done: filp->f_pos = (n << PAGE_CACHE_SHIFT) | offset; + filp->f_version = inode->i_version; UPDATE_ATIME(inode); return 0; } @@ -211,7 +214,7 @@ if (err) goto out_unlock; memcpy (de->name, name, namelen); - memset (de->name + namelen, 0, SYSV_DIRSIZE - namelen); + memset (de->name + namelen, 0, SYSV_DIRSIZE - namelen - 2); de->inode = cpu_to_fs16(inode->i_sb, inode->i_ino); err = dir_commit_chunk(page, from, to); dir->i_mtime = dir->i_ctime = CURRENT_TIME; diff -u --recursive --new-file v2.4.6/linux/fs/sysv/ialloc.c linux/fs/sysv/ialloc.c --- v2.4.6/linux/fs/sysv/ialloc.c Tue Jul 3 17:08:21 2001 +++ linux/fs/sysv/ialloc.c Tue Jul 17 18:53:55 2001 @@ -136,7 +136,8 @@ sb = dir->i_sb; inode = new_inode(sb); if (!inode) - return NULL; + return ERR_PTR(-ENOMEM); + lock_super(sb); count = fs16_to_cpu(sb, *sb->sv_sb_fic_count); if (count == 0 || (*sv_sb_fic_inode(sb,count-1) == 0)) { @@ -144,7 +145,7 @@ if (count == 0) { iput(inode); unlock_super(sb); - return NULL; + return ERR_PTR(-ENOSPC); } } /* Now count > 0. */ @@ -152,16 +153,23 @@ *sb->sv_sb_fic_count = cpu_to_fs16(sb, count); fs16_add(sb, sb->sv_sb_total_free_inodes, -1); dirty_sb(sb); + + if (dir->i_mode & S_ISGID) { + inode->i_gid = dir->i_gid; + if (S_ISDIR(mode)) + mode |= S_ISGID; + } else + inode->i_gid = current->fsgid; + inode->i_uid = current->fsuid; - inode->i_gid = (dir->i_mode & S_ISGID) ? dir->i_gid : current->fsgid; inode->i_ino = fs16_to_cpu(sb, ino); inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; inode->i_blocks = inode->i_blksize = 0; insert_inode_hash(inode); mark_inode_dirty(inode); + inode->i_mode = mode; /* for sysv_write_inode() */ sysv_write_inode(inode, 0); /* ensure inode not allocated again */ - /* FIXME: caller may call this too. */ mark_inode_dirty(inode); /* cleared by sysv_write_inode() */ /* That's it. */ unlock_super(sb); diff -u --recursive --new-file v2.4.6/linux/fs/sysv/inode.c linux/fs/sysv/inode.c --- v2.4.6/linux/fs/sysv/inode.c Tue Jul 3 17:08:21 2001 +++ linux/fs/sysv/inode.c Tue Jul 17 18:53:55 2001 @@ -28,11 +28,10 @@ #include <linux/highuid.h> #include <asm/byteorder.h> - /* This is only called on sync() and umount(), when s_dirt=1. */ static void sysv_write_super(struct super_block *sb) { - if (buffer_dirty(sb->sv_bh1) || buffer_dirty(sb->sv_bh2)) { + if (!(sb->s_flags & MS_RDONLY)) { /* If we are going to write out the super block, then attach current time stamp. But if the filesystem was marked clean, keep it clean. */ @@ -49,13 +48,16 @@ static void sysv_put_super(struct super_block *sb) { - /* we can assume sysv_write_super() has already been called, - and that the superblock is locked */ + if (!(sb->s_flags & MS_RDONLY)) { + /* XXX ext2 also updates the state here */ + mark_buffer_dirty(sb->sv_bh1); + if (sb->sv_bh1 != sb->sv_bh2) + mark_buffer_dirty(sb->sv_bh2); + } + brelse(sb->sv_bh1); - if (sb->sv_bh1 != sb->sv_bh2) brelse(sb->sv_bh2); - /* switch back to default block size */ - if (sb->s_blocksize != BLOCK_SIZE) - set_blocksize(sb->s_dev,BLOCK_SIZE); + if (sb->sv_bh1 != sb->sv_bh2) + brelse(sb->sv_bh2); } static int sysv_statfs(struct super_block *sb, struct statfs *buf) diff -u --recursive --new-file v2.4.6/linux/fs/sysv/namei.c linux/fs/sysv/namei.c --- v2.4.6/linux/fs/sysv/namei.c Tue Jul 3 17:08:21 2001 +++ linux/fs/sysv/namei.c Tue Jul 17 18:53:55 2001 @@ -86,11 +86,14 @@ static int sysv_mknod(struct inode * dir, struct dentry * dentry, int mode, int rdev) { struct inode * inode = sysv_new_inode(dir, mode); - if (!inode) - return -ENOSPC; - sysv_set_inode(inode, rdev); - mark_inode_dirty(inode); - return add_nondir(dentry, inode); + int err = PTR_ERR(inode); + + if (!IS_ERR(inode)) { + sysv_set_inode(inode, rdev); + mark_inode_dirty(inode); + err = add_nondir(dentry, inode); + } + return err; } static int sysv_create(struct inode * dir, struct dentry * dentry, int mode) @@ -108,16 +111,17 @@ if (l > dir->i_sb->s_blocksize) goto out; - err = -ENOSPC; inode = sysv_new_inode(dir, S_IFLNK|0777); - if (!inode) + err = PTR_ERR(inode); + if (IS_ERR(inode)) goto out; - + sysv_set_inode(inode, 0); err = block_symlink(inode, symname, l); if (err) goto out_fail; + mark_inode_dirty(inode); err = add_nondir(dentry, inode); out: return err; @@ -153,16 +157,13 @@ if (dir->i_nlink >= dir->i_sb->sv_link_max) goto out; - inc_count(dir); - if (dir->i_mode & S_ISGID) - mode |= S_ISGID; - - err = -ENOSPC; inode = sysv_new_inode(dir, S_IFDIR|mode); - if (!inode) + err = PTR_ERR(inode); + if (IS_ERR(inode)) goto out_dir; + sysv_set_inode(inode, 0); inc_count(inode); @@ -217,6 +218,7 @@ if (sysv_empty_dir(inode)) { err = sysv_unlink(dir, dentry); if (!err) { + inode->i_size = 0; dec_count(inode); dec_count(dir); } diff -u --recursive --new-file v2.4.6/linux/include/asm-alpha/atomic.h linux/include/asm-alpha/atomic.h --- v2.4.6/linux/include/asm-alpha/atomic.h Sun Nov 12 19:27:11 2000 +++ linux/include/asm-alpha/atomic.h Mon Jul 9 21:27:45 2001 @@ -106,4 +106,9 @@ #define atomic_inc(v) atomic_add(1,(v)) #define atomic_dec(v) atomic_sub(1,(v)) +#define smp_mb__before_atomic_dec() smp_mb() +#define smp_mb__after_atomic_dec() smp_mb() +#define smp_mb__before_atomic_inc() smp_mb() +#define smp_mb__after_atomic_inc() smp_mb() + #endif /* _ALPHA_ATOMIC_H */ diff -u --recursive --new-file v2.4.6/linux/include/asm-alpha/hardirq.h linux/include/asm-alpha/hardirq.h --- v2.4.6/linux/include/asm-alpha/hardirq.h Tue Jul 3 17:08:21 2001 +++ linux/include/asm-alpha/hardirq.h Mon Jul 9 14:47:39 2001 @@ -10,6 +10,7 @@ unsigned int __local_irq_count; unsigned int __local_bh_count; unsigned int __syscall_count; + struct task_struct * __ksoftirqd_task; } ____cacheline_aligned irq_cpustat_t; #include <linux/irq_cpustat.h> /* Standard mappings for irq_cpustat_t above */ diff -u --recursive --new-file v2.4.6/linux/include/asm-alpha/rwsem.h linux/include/asm-alpha/rwsem.h --- v2.4.6/linux/include/asm-alpha/rwsem.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-alpha/rwsem.h Tue Jul 10 20:08:51 2001 @@ -0,0 +1,208 @@ +#ifndef _ALPHA_RWSEM_H +#define _ALPHA_RWSEM_H + +/* + * Written by Ivan Kokshaysky <ink@jurassic.park.msu.ru>, 2001. + * Based on asm-alpha/semaphore.h and asm-i386/rwsem.h + */ + +#ifndef _LINUX_RWSEM_H +#error please dont include asm/rwsem.h directly, use linux/rwsem.h instead +#endif + +#ifdef __KERNEL__ + +#include <asm/compiler.h> +#include <linux/list.h> +#include <linux/spinlock.h> + +struct rwsem_waiter; + +extern struct rw_semaphore *rwsem_down_read_failed(struct rw_semaphore *sem); +extern struct rw_semaphore *rwsem_down_write_failed(struct rw_semaphore *sem); +extern struct rw_semaphore *rwsem_wake(struct rw_semaphore *); + +/* + * the semaphore definition + */ +struct rw_semaphore { + long count; +#define RWSEM_UNLOCKED_VALUE 0x0000000000000000L +#define RWSEM_ACTIVE_BIAS 0x0000000000000001L +#define RWSEM_ACTIVE_MASK 0x00000000ffffffffL +#define RWSEM_WAITING_BIAS (-0x0000000100000000L) +#define RWSEM_ACTIVE_READ_BIAS RWSEM_ACTIVE_BIAS +#define RWSEM_ACTIVE_WRITE_BIAS (RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS) + spinlock_t wait_lock; + struct list_head wait_list; +#if RWSEM_DEBUG + int debug; +#endif +}; + +#if RWSEM_DEBUG +#define __RWSEM_DEBUG_INIT , 0 +#else +#define __RWSEM_DEBUG_INIT /* */ +#endif + +#define __RWSEM_INITIALIZER(name) \ + { RWSEM_UNLOCKED_VALUE, SPIN_LOCK_UNLOCKED, \ + LIST_HEAD_INIT((name).wait_list) __RWSEM_DEBUG_INIT } + +#define DECLARE_RWSEM(name) \ + struct rw_semaphore name = __RWSEM_INITIALIZER(name) + +static inline void init_rwsem(struct rw_semaphore *sem) +{ + sem->count = RWSEM_UNLOCKED_VALUE; + spin_lock_init(&sem->wait_lock); + INIT_LIST_HEAD(&sem->wait_list); +#if RWSEM_DEBUG + sem->debug = 0; +#endif +} + +static inline void __down_read(struct rw_semaphore *sem) +{ + long oldcount; +#ifndef CONFIG_SMP + oldcount = sem->count; + sem->count += RWSEM_ACTIVE_READ_BIAS; +#else + long temp; + __asm__ __volatile__( + "1: ldq_l %0,%1\n" + " addq %0,%3,%2\n" + " stq_c %2,%1\n" + " beq %2,2f\n" + " mb\n" + ".subsection 2\n" + "2: br 1b\n" + ".previous" + :"=&r" (oldcount), "=m" (sem->count), "=&r" (temp) + :"Ir" (RWSEM_ACTIVE_READ_BIAS), "m" (sem->count) : "memory"); +#endif + if (__builtin_expect(oldcount < 0, 0)) + rwsem_down_read_failed(sem); +} + +static inline void __down_write(struct rw_semaphore *sem) +{ + long oldcount; +#ifndef CONFIG_SMP + oldcount = sem->count; + sem->count += RWSEM_ACTIVE_WRITE_BIAS; +#else + long temp; + __asm__ __volatile__( + "1: ldq_l %0,%1\n" + " addq %0,%3,%2\n" + " stq_c %2,%1\n" + " beq %2,2f\n" + " mb\n" + ".subsection 2\n" + "2: br 1b\n" + ".previous" + :"=&r" (oldcount), "=m" (sem->count), "=&r" (temp) + :"Ir" (RWSEM_ACTIVE_WRITE_BIAS), "m" (sem->count) : "memory"); +#endif + if (__builtin_expect(oldcount, 0)) + rwsem_down_write_failed(sem); +} + +static inline void __up_read(struct rw_semaphore *sem) +{ + long oldcount; +#ifndef CONFIG_SMP + oldcount = sem->count; + sem->count -= RWSEM_ACTIVE_READ_BIAS; +#else + long temp; + __asm__ __volatile__( + " mb\n" + "1: ldq_l %0,%1\n" + " subq %0,%3,%2\n" + " stq_c %2,%1\n" + " beq %2,2f\n" + ".subsection 2\n" + "2: br 1b\n" + ".previous" + :"=&r" (oldcount), "=m" (sem->count), "=&r" (temp) + :"Ir" (RWSEM_ACTIVE_READ_BIAS), "m" (sem->count) : "memory"); +#endif + if (__builtin_expect(oldcount < 0, 0)) + if ((int)oldcount - RWSEM_ACTIVE_READ_BIAS == 0) + rwsem_wake(sem); +} + +static inline void __up_write(struct rw_semaphore *sem) +{ + long count; +#ifndef CONFIG_SMP + sem->count -= RWSEM_ACTIVE_WRITE_BIAS; + count = sem->count; +#else + long temp; + __asm__ __volatile__( + " mb\n" + "1: ldq_l %0,%1\n" + " subq %0,%3,%2\n" + " stq_c %2,%1\n" + " beq %2,2f\n" + " subq %0,%3,%0\n" + ".subsection 2\n" + "2: br 1b\n" + ".previous" + :"=&r" (count), "=m" (sem->count), "=&r" (temp) + :"Ir" (RWSEM_ACTIVE_WRITE_BIAS), "m" (sem->count) : "memory"); +#endif + if (__builtin_expect(count, 0)) + if ((int)count == 0) + rwsem_wake(sem); +} + +static inline void rwsem_atomic_add(long val, struct rw_semaphore *sem) +{ +#ifndef CONFIG_SMP + sem->count += val; +#else + long temp; + __asm__ __volatile__( + "1: ldq_l %0,%1\n" + " addq %0,%2,%0\n" + " stq_c %0,%1\n" + " beq %0,2f\n" + ".subsection 2\n" + "2: br 1b\n" + ".previous" + :"=&r" (temp), "=m" (sem->count) + :"Ir" (val), "m" (sem->count)); +#endif +} + +static inline long rwsem_atomic_update(long val, struct rw_semaphore *sem) +{ +#ifndef CONFIG_SMP + sem->count += val; + return sem->count; +#else + long ret, temp; + __asm__ __volatile__( + "1: ldq_l %0,%1\n" + " addq %0,%3,%2\n" + " addq %0,%3,%0\n" + " stq_c %2,%1\n" + " beq %2,2f\n" + ".subsection 2\n" + "2: br 1b\n" + ".previous" + :"=&r" (ret), "=m" (sem->count), "=&r" (temp) + :"Ir" (val), "m" (sem->count)); + + return ret; +#endif +} + +#endif /* __KERNEL__ */ +#endif /* _ALPHA_RWSEM_H */ diff -u --recursive --new-file v2.4.6/linux/include/asm-alpha/softirq.h linux/include/asm-alpha/softirq.h --- v2.4.6/linux/include/asm-alpha/softirq.h Tue Jul 3 17:08:21 2001 +++ linux/include/asm-alpha/softirq.h Mon Jul 9 16:04:24 2001 @@ -8,21 +8,30 @@ extern inline void cpu_bh_disable(int cpu) { local_bh_count(cpu)++; - mb(); + barrier(); } -extern inline void cpu_bh_enable(int cpu) +extern inline void __cpu_bh_enable(int cpu) { - mb(); + barrier(); local_bh_count(cpu)--; } -#define local_bh_enable() cpu_bh_enable(smp_processor_id()) -#define __local_bh_enable local_bh_enable +#define __local_bh_enable() __cpu_bh_enable(smp_processor_id()) #define local_bh_disable() cpu_bh_disable(smp_processor_id()) +#define local_bh_enable() \ +do { \ + int cpu; \ + \ + barrier(); \ + cpu = smp_processor_id(); \ + if (!--local_bh_count(cpu) && softirq_pending(cpu)) \ + do_softirq(); \ +} while (0) + #define in_softirq() (local_bh_count(smp_processor_id()) != 0) -#define __cpu_raise_softirq(cpu,nr) set_bit((nr), &softirq_pending(cpu)) +#define __cpu_raise_softirq(cpu, nr) set_bit(nr, &softirq_pending(cpu)) #endif /* _ALPHA_SOFTIRQ_H */ diff -u --recursive --new-file v2.4.6/linux/include/asm-arm/arch-ebsa285/io.h linux/include/asm-arm/arch-ebsa285/io.h --- v2.4.6/linux/include/asm-arm/arch-ebsa285/io.h Thu Feb 8 16:32:44 2001 +++ linux/include/asm-arm/arch-ebsa285/io.h Wed Jul 4 20:11:17 2001 @@ -48,16 +48,7 @@ #define __arch_getw(a) (*(volatile unsigned short *)(a)) #define __arch_putw(v,a) (*(volatile unsigned short *)(a) = (v)) -#include <asm/hardware/dec21285.h> - -/* - * ioremap support - validate a PCI memory address, - * and convert a PCI memory address to a physical - * address for the page tables. - */ -#define iomem_valid_addr(iomem,sz) \ - ((iomem) < 0x80000000 && (iomem) + (sz) <= 0x80000000) - -#define iomem_to_phys(iomem) ((iomem) + DC21285_PCI_MEM) +#define iomem_valid_addr(iomem,sz) (1) +#define iomem_to_phys(iomem) (iomem) #endif diff -u --recursive --new-file v2.4.6/linux/include/asm-arm/arch-integrator/io.h linux/include/asm-arm/arch-integrator/io.h --- v2.4.6/linux/include/asm-arm/arch-integrator/io.h Fri Mar 2 18:38:39 2001 +++ linux/include/asm-arm/arch-integrator/io.h Wed Jul 4 20:11:17 2001 @@ -35,12 +35,11 @@ /* * Validate the pci memory address for ioremap. */ -#define iomem_valid_addr(iomem,size) \ - ((iomem) > 0 && (iomem) + (size) <= 0x20000000) +#define iomem_valid_addr(iomem,size) (1) /* * Convert PCI memory space to a CPU physical address */ -#define iomem_to_phys(iomem) ((iomem) + PHYS_PCI_MEM_BASE) +#define iomem_to_phys(iomem) (iomem) #endif diff -u --recursive --new-file v2.4.6/linux/include/asm-arm/hardirq.h linux/include/asm-arm/hardirq.h --- v2.4.6/linux/include/asm-arm/hardirq.h Fri Aug 4 16:15:37 2000 +++ linux/include/asm-arm/hardirq.h Wed Jul 4 14:56:44 2001 @@ -4,10 +4,9 @@ #include <linux/config.h> #include <linux/threads.h> -/* entry.S is sensitive to the offsets of these fields */ +/* softirq.h is sensitive to the offsets of these fields */ typedef struct { - unsigned int __softirq_active; - unsigned int __softirq_mask; + unsigned int __softirq_pending; unsigned int __local_irq_count; unsigned int __local_bh_count; unsigned int __syscall_count; diff -u --recursive --new-file v2.4.6/linux/include/asm-arm/mach/pci.h linux/include/asm-arm/mach/pci.h --- v2.4.6/linux/include/asm-arm/mach/pci.h Mon Sep 18 15:15:23 2000 +++ linux/include/asm-arm/mach/pci.h Wed Jul 4 15:43:05 2001 @@ -7,36 +7,26 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ -#define MAX_NR_BUS 2 +struct hw_pci { + /* Initialise the hardware */ + void (*init)(void *); + + /* Setup bus resources */ + void (*setup_resources)(struct resource **); -struct arm_bus_sysdata { - /* - * bitmask of features we can turn. - * See PCI command register for more info. - */ - u16 features; - /* - * Maximum devsel for this bus. - */ - u16 maxdevsel; /* - * The maximum latency that devices on this - * bus can withstand. + * This is the offset of PCI memory base registers + * to physical memory. */ - u8 max_lat; -}; - -struct arm_pci_sysdata { - struct arm_bus_sysdata bus[MAX_NR_BUS]; -}; + unsigned long mem_offset; -struct hw_pci { - void (*init)(struct arm_pci_sysdata *); + /* IRQ swizzle */ u8 (*swizzle)(struct pci_dev *dev, u8 *pin); + + /* IRQ mapping */ int (*map_irq)(struct pci_dev *dev, u8 slot, u8 pin); }; extern u8 no_swizzle(struct pci_dev *dev, u8 *pin); - -void __init dc21285_init(struct arm_pci_sysdata *); -void __init plx90x0_init(struct arm_pci_sysdata *); +extern void __init dc21285_setup_resources(struct resource **resource); +extern void __init dc21285_init(void *sysdata); diff -u --recursive --new-file v2.4.6/linux/include/asm-arm/softirq.h linux/include/asm-arm/softirq.h --- v2.4.6/linux/include/asm-arm/softirq.h Mon May 15 12:00:34 2000 +++ linux/include/asm-arm/softirq.h Mon Jul 9 16:04:24 2001 @@ -4,12 +4,22 @@ #include <asm/atomic.h> #include <asm/hardirq.h> -#define cpu_bh_disable(cpu) do { local_bh_count(cpu)++; barrier(); } while (0) -#define cpu_bh_enable(cpu) do { barrier(); local_bh_count(cpu)--; } while (0) +#define __cpu_bh_enable(cpu) \ + do { barrier(); local_bh_count(cpu)--; } while (0) +#define cpu_bh_disable(cpu) \ + do { local_bh_count(cpu)++; barrier(); } while (0) #define local_bh_disable() cpu_bh_disable(smp_processor_id()) -#define local_bh_enable() cpu_bh_enable(smp_processor_id()) +#define __local_bh_enable() __cpu_bh_enable(smp_processor_id()) +#define __cpu_raise_softirq(cpu,nr) set_bit((nr), &softirq_pending(cpu)) #define in_softirq() (local_bh_count(smp_processor_id()) != 0) + +#define local_bh_enable() \ +do { \ + unsigned int *ptr = &local_bh_count(smp_processor_id()); \ + if (!--*ptr && ptr[-2]) \ + __asm__("bl%? __do_softirq": : : "lr");/* out of line */\ +} while (0) #endif /* __ASM_SOFTIRQ_H */ diff -u --recursive --new-file v2.4.6/linux/include/asm-cris/axisflashmap.h linux/include/asm-cris/axisflashmap.h --- v2.4.6/linux/include/asm-cris/axisflashmap.h Tue May 1 16:05:00 2001 +++ linux/include/asm-cris/axisflashmap.h Wed Jul 4 11:50:39 2001 @@ -50,6 +50,7 @@ }; /* ended by an end marker: */ #define PARTITIONTABLE_END_MARKER 0xFFFFFFFF +#define PARTITIONTABLE_END_MARKER_SIZE 4 /*#define PARTITION_TYPE_RESCUE 0x0000?*/ /* Not used, maybe it should? */ #define PARTITION_TYPE_PARAM 0x0001 /* Hmm.. */ diff -u --recursive --new-file v2.4.6/linux/include/asm-cris/bitops.h linux/include/asm-cris/bitops.h --- v2.4.6/linux/include/asm-cris/bitops.h Fri Apr 6 10:51:19 2001 +++ linux/include/asm-cris/bitops.h Wed Jul 4 11:50:39 2001 @@ -1,5 +1,15 @@ -/* $Id: bitops.h,v 1.4 2001/02/28 04:26:11 hp Exp $ */ -/* all of these should probably be rewritten in assembler for speed. */ +/* asm/bitops.h for Linux/CRIS + * + * TODO: asm versions if speed is needed + * set_bit, clear_bit and change_bit wastes cycles being only + * macros into test_and_set_bit etc. + * kernel-doc things (**) for macros are disabled + * + * All bit operations return 0 if the bit was cleared before the + * operation and != 0 if it was not. + * + * bit 0 is the LSB of addr; bit 32 is the LSB of (addr+1). + */ #ifndef _CRIS_BITOPS_H #define _CRIS_BITOPS_H @@ -10,25 +20,72 @@ #include <asm/system.h> /* - * These have to be done with inline assembly: that way the bit-setting - * is guaranteed to be atomic. All bit operations return 0 if the bit - * was cleared before the operation and != 0 if it was not. - * - * bit 0 is the LSB of addr; bit 32 is the LSB of (addr+1). - */ - -/* * Some hacks to defeat gcc over-optimizations.. */ struct __dummy { unsigned long a[100]; }; #define ADDR (*(struct __dummy *) addr) #define CONST_ADDR (*(const struct __dummy *) addr) +/* + * set_bit - Atomically set a bit in memory + * @nr: the bit to set + * @addr: the address to start counting from + * + * This function is atomic and may not be reordered. See __set_bit() + * if you do not require the atomic guarantees. + * Note that @nr may be almost arbitrarily large; this function is not + * restricted to acting on a single-word quantity. + */ + #define set_bit(nr, addr) (void)test_and_set_bit(nr, addr) + +/* + * clear_bit - Clears a bit in memory + * @nr: Bit to clear + * @addr: Address to start counting from + * + * clear_bit() is atomic and may not be reordered. However, it does + * not contain a memory barrier, so if it is used for locking purposes, + * you should call smp_mb__before_clear_bit() and/or smp_mb__after_clear_bit() + * in order to ensure changes are visible on other processors. + */ + #define clear_bit(nr, addr) (void)test_and_clear_bit(nr, addr) + +/* + * change_bit - Toggle a bit in memory + * @nr: Bit to clear + * @addr: Address to start counting from + * + * change_bit() is atomic and may not be reordered. + * Note that @nr may be almost arbitrarily large; this function is not + * restricted to acting on a single-word quantity. + */ + #define change_bit(nr, addr) (void)test_and_change_bit(nr, addr) -extern __inline__ int test_and_set_bit(int nr, void *addr) +/* + * __change_bit - Toggle a bit in memory + * @nr: the bit to set + * @addr: the address to start counting from + * + * Unlike change_bit(), this function is non-atomic and may be reordered. + * If it's called on the same region of memory simultaneously, the effect + * may be that only one operation succeeds. + */ + +#define __change_bit(nr, addr) (void)__test_and_change_bit(nr, addr) + +/** + * test_and_set_bit - Set a bit and return its old value + * @nr: Bit to set + * @addr: Address to count from + * + * This operation is atomic and cannot be reordered. + * It also implies a memory barrier. + */ + +static __inline__ int test_and_set_bit(int nr, void *addr) { unsigned int mask, retval; unsigned long flags; @@ -50,7 +107,16 @@ #define smp_mb__before_clear_bit() barrier() #define smp_mb__after_clear_bit() barrier() -extern __inline__ int test_and_clear_bit(int nr, void *addr) +/** + * test_and_clear_bit - Clear a bit and return its old value + * @nr: Bit to set + * @addr: Address to count from + * + * This operation is atomic and cannot be reordered. + * It also implies a memory barrier. + */ + +static __inline__ int test_and_clear_bit(int nr, void *addr) { unsigned int mask, retval; unsigned long flags; @@ -66,7 +132,37 @@ return retval; } -extern __inline__ int test_and_change_bit(int nr, void *addr) +/** + * __test_and_clear_bit - Clear a bit and return its old value + * @nr: Bit to set + * @addr: Address to count from + * + * This operation is non-atomic and can be reordered. + * If two examples of this operation race, one can appear to succeed + * but actually fail. You must protect multiple accesses with a lock. + */ + +static __inline__ int __test_and_clear_bit(int nr, void *addr) +{ + unsigned int mask, retval; + unsigned int *adr = (unsigned int *)addr; + + adr += nr >> 5; + mask = 1 << (nr & 0x1f); + retval = (mask & *adr) != 0; + *adr &= ~mask; + return retval; +} +/** + * test_and_change_bit - Change a bit and return its new value + * @nr: Bit to set + * @addr: Address to count from + * + * This operation is atomic and cannot be reordered. + * It also implies a memory barrier. + */ + +static __inline__ int test_and_change_bit(int nr, void *addr) { unsigned int mask, retval; unsigned long flags; @@ -81,10 +177,30 @@ return retval; } -/* +/* WARNING: non atomic and it can be reordered! */ + +static __inline__ int __test_and_change_bit(int nr, void *addr) +{ + unsigned int mask, retval; + unsigned int *adr = (unsigned int *)addr; + + adr += nr >> 5; + mask = 1 << (nr & 0x1f); + retval = (mask & *adr) != 0; + *adr ^= mask; + + return retval; +} + +/** + * test_bit - Determine whether a bit is set + * @nr: bit number to test + * @addr: Address to start counting from + * * This routine doesn't need to be atomic. */ -extern __inline__ int test_bit(int nr, const void *addr) + +static __inline__ int test_bit(int nr, const void *addr) { unsigned int mask; unsigned int *adr = (unsigned int *)addr; @@ -102,7 +218,7 @@ * ffz = Find First Zero in word. Undefined if no zero exists, * so code should check against ~0UL first.. */ -extern __inline__ unsigned long ffz(unsigned long word) +static __inline__ unsigned long ffz(unsigned long word) { unsigned long result = 0; @@ -117,7 +233,7 @@ * Find first one in word. Undefined if no one exists, * so code should check against 0UL first.. */ -extern __inline__ unsigned long find_first_one(unsigned long word) +static __inline__ unsigned long find_first_one(unsigned long word) { unsigned long result = 0; @@ -128,7 +244,13 @@ return result; } -extern __inline__ int find_next_zero_bit (void * addr, int size, int offset) +/** + * find_next_zero_bit - find the first zero bit in a memory region + * @addr: The address to base the search on + * @offset: The bitnumber to start searching at + * @size: The maximum size to search + */ +static __inline__ int find_next_zero_bit (void * addr, int size, int offset) { unsigned long *p = ((unsigned long *) addr) + (offset >> 5); unsigned long result = offset & ~31UL; @@ -163,6 +285,15 @@ found_middle: return result + ffz(tmp); } + +/** + * find_first_zero_bit - find the first zero bit in a memory region + * @addr: The address to start the search at + * @size: The maximum size to search + * + * Returns the bit-number of the first zero bit, not the number of the byte + * containing a bit. + */ #define find_first_zero_bit(addr, size) \ find_next_zero_bit((addr), (size), 0) diff -u --recursive --new-file v2.4.6/linux/include/asm-cris/delay.h linux/include/asm-cris/delay.h --- v2.4.6/linux/include/asm-cris/delay.h Fri Apr 6 10:51:19 2001 +++ linux/include/asm-cris/delay.h Wed Jul 4 11:50:39 2001 @@ -1,4 +1,4 @@ -/* $Id: delay.h,v 1.3 2001/02/23 13:47:33 bjornw Exp $ */ +/* $Id: delay.h,v 1.4 2001/05/31 06:40:53 markusl Exp $ */ #ifndef _CRIS_DELAY_H #define _CRIS_DELAY_H @@ -20,23 +20,17 @@ extern __inline__ void __delay(int loops) { - /* need to be a great deal of nops, because Etrax shuts off IRQ's during a branch - and we depend on the irq's to measure the time! */ - __asm__ __volatile__ ( - "move.d %0,r0\n" + "move.d %0,r0\n\t" "1:\n\t" - "nop\n\t" - "nop\n\t" - "nop\n\t" - "nop\n\t" - "nop\n\t" - "nop\n\t" + "cmpq 0,r0\n\t" + "beq 2f\n\t" "nop\n\t" "subq 1,r0\n\t" - "bne 1b\n\t" + "ba 1b\n\t" "nop\n\t" - : : "r" (loops) : "r0", "cc"); + "2:\n\t" + : : "r" (loops) : "r0"); } @@ -55,13 +49,7 @@ __delay(usecs * loops_per_usec); } -extern __inline__ unsigned long muldiv(unsigned long a, unsigned long b, unsigned long c) -{ - printk("muldiv called!\n"); - return 0; -} - -#endif /* defined(_ETRAX_DELAY_H) */ +#endif /* defined(_CRIS_DELAY_H) */ diff -u --recursive --new-file v2.4.6/linux/include/asm-cris/dma.h linux/include/asm-cris/dma.h --- v2.4.6/linux/include/asm-cris/dma.h Thu Feb 8 16:32:44 2001 +++ linux/include/asm-cris/dma.h Wed Jul 4 11:50:39 2001 @@ -1,4 +1,4 @@ -/* $Id: dma.h,v 1.1 2000/07/10 16:32:31 bjornw Exp $ +/* $Id: dma.h,v 1.2 2001/05/09 12:17:42 johana Exp $ * linux/include/asm/dma.h: Defines for using and allocating dma channels. */ @@ -13,6 +13,44 @@ /* TODO: check nbr of channels on Etrax-100LX */ #define MAX_DMA_CHANNELS 10 + +/* dma0 and dma1 used for network (ethernet) */ +#define NETWORK_TX_DMA_NBR 0 +#define NETWORK_RX_DMA_NBR 1 + +/* dma2 and dma3 shared by par0, scsi0, ser2 and ata */ +#define PAR0_TX_DMA_NBR 2 +#define PAR0_RX_DMA_NBR 3 +#define SCSI0_TX_DMA_NBR 2 +#define SCSI0_RX_DMA_NBR 3 +#define SER2_TX_DMA_NBR 2 +#define SER2_RX_DMA_NBR 3 +#define ATA_TX_DMA_NBR 2 +#define ATA_RX_DMA_NBR 3 + +/* dma4 and dma5 shared by par1, scsi1, ser3 and extdma0 */ +#define PAR1_TX_DMA_NBR 4 +#define PAR1_RX_DMA_NBR 5 +#define SCSI1_TX_DMA_NBR 4 +#define SCSI1_RX_DMA_NBR 5 +#define SER3_TX_DMA_NBR 4 +#define SER3_RX_DMA_NBR 5 +#define EXTDMA0_TX_DMA_NBR 4 +#define EXTDMA0_RX_DMA_NBR 5 + +/* dma6 and dma7 shared by ser0, extdma1 and mem2mem */ +#define SER0_TX_DMA_NBR 6 +#define SER0_RX_DMA_NBR 7 +#define EXTDMA1_TX_DMA_NBR 6 +#define EXTDMA1_RX_DMA_NBR 7 +#define MEM2MEM_TX_DMA_NBR 6 +#define MEM2MEM_RX_DMA_NBR 7 + +/* dma8 and dma9 shared by ser1 and usb */ +#define SER1_TX_DMA_NBR 8 +#define SER1_RX_DMA_NBR 9 +#define USB_TX_DMA_NBR 8 +#define USB_RX_DMA_NBR 9 /* These are in kernel/dma.c: */ extern int request_dma(unsigned int dmanr, const char * device_id); /* reserve a DMA channel */ diff -u --recursive --new-file v2.4.6/linux/include/asm-cris/etraxgpio.h linux/include/asm-cris/etraxgpio.h --- v2.4.6/linux/include/asm-cris/etraxgpio.h Tue May 1 16:05:00 2001 +++ linux/include/asm-cris/etraxgpio.h Wed Jul 4 11:50:39 2001 @@ -31,4 +31,8 @@ /* LED ioctl extended */ #define IO_LED_SETBIT 0xB #define IO_LED_CLRBIT 0xC + +/* SHUTDOWN ioctl */ +#define IO_SHUTDOWN 0xD +#define IO_GET_PWR_BT 0xE #endif diff -u --recursive --new-file v2.4.6/linux/include/asm-cris/io.h linux/include/asm-cris/io.h --- v2.4.6/linux/include/asm-cris/io.h Tue May 1 16:05:00 2001 +++ linux/include/asm-cris/io.h Wed Jul 4 11:50:39 2001 @@ -128,12 +128,24 @@ #define LED_ACTIVE_SET_R(x) \ REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, CONFIG_ETRAX_LED2R, !(x)) #define LED_DISK_WRITE(x) \ - REG_SHADOW_SET(R_PORT_PB_DATA, port_pa_data_shadow, CONFIG_ETRAX_LED3R, !(x)) + REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, CONFIG_ETRAX_LED3R, !(x)) #define LED_DISK_READ(x) \ - REG_SHADOW_SET(R_PORT_PB_DATA, port_pa_data_shadow, CONFIG_ETRAX_LED3G, !(x)) + REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, CONFIG_ETRAX_LED3G, !(x)) #endif #ifdef CONFIG_ETRAX_CSP0_LEDS +#define CONFIGURABLE_LEDS\ + ((1 << CONFIG_ETRAX_LED1G ) | (1 << CONFIG_ETRAX_LED1R ) |\ + (1 << CONFIG_ETRAX_LED2G ) | (1 << CONFIG_ETRAX_LED2R ) |\ + (1 << CONFIG_ETRAX_LED3G ) | (1 << CONFIG_ETRAX_LED3R ) |\ + (1 << CONFIG_ETRAX_LED4G ) | (1 << CONFIG_ETRAX_LED4R ) |\ + (1 << CONFIG_ETRAX_LED5G ) | (1 << CONFIG_ETRAX_LED5R ) |\ + (1 << CONFIG_ETRAX_LED6G ) | (1 << CONFIG_ETRAX_LED6R ) |\ + (1 << CONFIG_ETRAX_LED7G ) | (1 << CONFIG_ETRAX_LED7R ) |\ + (1 << CONFIG_ETRAX_LED8Y ) | (1 << CONFIG_ETRAX_LED9Y ) |\ + (1 << CONFIG_ETRAX_LED10Y ) |(1 << CONFIG_ETRAX_LED11Y )|\ + (1 << CONFIG_ETRAX_LED12R )) + #define LED_NETWORK_SET_G(x) \ REG_SHADOW_SET(port_csp0_addr, port_csp0_shadow, CONFIG_ETRAX_LED1G, !(x)) #define LED_NETWORK_SET_R(x) \ @@ -146,10 +158,24 @@ REG_SHADOW_SET(port_csp0_addr, port_csp0_shadow, CONFIG_ETRAX_LED3R, !(x)) #define LED_DISK_READ(x) \ REG_SHADOW_SET(port_csp0_addr, port_csp0_shadow, CONFIG_ETRAX_LED3G, !(x)) -#define LED_BIT_SET(x) \ - REG_SHADOW_SET(port_csp0_addr, port_csp0_shadow, x, 1) -#define LED_BIT_CLR(x) \ - REG_SHADOW_SET(port_csp0_addr, port_csp0_shadow, x, 0) +#define LED_BIT_SET(x)\ + do{\ + if((( 1 << x) & CONFIGURABLE_LEDS) != 0)\ + REG_SHADOW_SET(port_csp0_addr, port_csp0_shadow, x, 1);\ + }while(0) +#define LED_BIT_CLR(x)\ + do{\ + if((( 1 << x) & CONFIGURABLE_LEDS) != 0)\ + REG_SHADOW_SET(port_csp0_addr, port_csp0_shadow, x, 0);\ + }while(0) +#endif + +# +#ifdef CONFIG_ETRAX_SOFT_SHUTDOWN +#define SOFT_SHUTDOWN() \ + REG_SHADOW_SET(port_csp0_addr, port_csp0_shadow, CONFIG_ETRAX_SHUTDOWN_BIT, 1) +#else +#define SOFT_SHUTDOWN() #endif /* diff -u --recursive --new-file v2.4.6/linux/include/asm-cris/irq.h linux/include/asm-cris/irq.h --- v2.4.6/linux/include/asm-cris/irq.h Tue May 1 16:05:00 2001 +++ linux/include/asm-cris/irq.h Wed Jul 4 11:50:39 2001 @@ -1,10 +1,11 @@ /* - * Interrupt handling assembler for Linux/CRIS + * Interrupt handling assembler and defines for Linux/CRIS * * Copyright (c) 2000 Axis Communications AB * * Authors: Bjorn Wesen (bjornw@axis.com) * + * $Id: irq.h,v 1.11 2001/06/01 14:57:17 starvik Exp $ */ #ifndef _ASM_IRQ_H @@ -20,6 +21,61 @@ #include <asm/sv_addr_ag.h> #define NR_IRQS 32 +#define SOME_IRQ_NBR IO_BITNR(R_VECT_MASK_RD, some) /* 0 ? */ +#define NMI_IRQ_NBR IO_BITNR(R_VECT_MASK_RD, nmi) /* 1 */ +#define TIMER0_IRQ_NBR IO_BITNR(R_VECT_MASK_RD, timer0) /* 2 */ +#define TIMER1_IRQ_NBR IO_BITNR(R_VECT_MASK_RD, timer1) /* 3 */ +/* mio, ata, par0, scsi0 on 4 */ +/* par1, scsi1 on 5 */ +#define NETWORK_STATUS_IRQ_NBR IO_BITNR(R_VECT_MASK_RD, network) /* 6 */ + +#define SERIAL_IRQ_NBR IO_BITNR(R_VECT_MASK_RD, network) /* 8 */ +#define PA_IRQ_NBR IO_BITNR(R_VECT_MASK_RD, pa) /* 11 */ +/* extdma0 and extdma1 is at irq 12 and 13 and/or same as dma5 and dma6 ? */ +#define EXTDMA0_IRQ_NBR IO_BITNR(R_VECT_MASK_RD, ext_dma0) +#define EXTDMA1_IRQ_NBR IO_BITNR(R_VECT_MASK_RD, ext_dma1) + +/* dma0-9 is irq 16..25 */ +/* 16,17: network */ +#define DMA0_TX_IRQ_NBR IO_BITNR(R_VECT_MASK_RD, dma0) +#define DMA1_RX_IRQ_NBR IO_BITNR(R_VECT_MASK_RD, dma1) +#define NETWORK_DMA_TX_IRQ_NBR DMA0_TX_IRQ_NBR +#define NETWORK_DMA_RX_IRQ_NBR DMA1_RX_IRQ_NBR + +/* 18,19: dma2 and dma3 shared by par0, scsi0, ser2 and ata */ +#define DMA2_TX_IRQ_NBR IO_BITNR(R_VECT_MASK_RD, dma2) +#define DMA3_RX_IRQ_NBR IO_BITNR(R_VECT_MASK_RD, dma3) +#define SER2_DMA_TX_IRQ_NBR DMA2_TX_IRQ_NBR +#define SER2_DMA_RX_IRQ_NBR DMA3_RX_IRQ_NBR + +/* 20,21: dma4 and dma5 shared by par1, scsi1, ser3 and extdma0 */ +#define DMA4_TX_IRQ_NBR IO_BITNR(R_VECT_MASK_RD, dma4) +#define DMA5_RX_IRQ_NBR IO_BITNR(R_VECT_MASK_RD, dma5) +#define SER3_DMA_TX_IRQ_NBR DMA4_TX_IRQ_NBR +#define SER3_DMA_RX_IRQ_NBR DMA5_RX_IRQ_NBR + +/* 22,23: dma6 and dma7 shared by ser0, extdma1 and mem2mem */ +#define DMA6_TX_IRQ_NBR IO_BITNR(R_VECT_MASK_RD, dma6) +#define DMA7_RX_IRQ_NBR IO_BITNR(R_VECT_MASK_RD, dma7) +#define SER0_DMA_TX_IRQ_NBR DMA6_TX_IRQ_NBR +#define SER0_DMA_RX_IRQ_NBR DMA7_RX_IRQ_NBR +#define MEM2MEM_DMA_TX_IRQ_NBR DMA6_TX_IRQ_NBR +#define MEM2MEM_DMA_RX_IRQ_NBR DMA7_RX_IRQ_NBR + +/* 24,25: dma8 and dma9 shared by ser1 and usb */ +#define DMA8_TX_IRQ_NBR IO_BITNR(R_VECT_MASK_RD, dma8) +#define DMA9_RX_IRQ_NBR IO_BITNR(R_VECT_MASK_RD, dma9) +#define SER1_DMA_TX_IRQ_NBR DMA8_TX_IRQ_NBR +#define SER1_DMA_RX_IRQ_NBR DMA9_RX_IRQ_NBR +#define USB_DMA_TX_IRQ_NBR DMA8_TX_IRQ_NBR +#define USB_DMA_RX_IRQ_NBR DMA9_RX_IRQ_NBR + +/* usb: controller at irq 31 + uses DMA8 and DMA9 */ +#define USB_HC_IRQ_NBR IO_BITNR(R_VECT_MASK_RD, usb) + + + + extern void disable_irq(unsigned int); extern void enable_irq(unsigned int); diff -u --recursive --new-file v2.4.6/linux/include/asm-cris/mmu_context.h linux/include/asm-cris/mmu_context.h --- v2.4.6/linux/include/asm-cris/mmu_context.h Thu Feb 8 16:32:44 2001 +++ linux/include/asm-cris/mmu_context.h Wed Jul 4 11:50:39 2001 @@ -9,6 +9,12 @@ #define activate_mm(prev,next) switch_mm((prev),(next),NULL,smp_processor_id()) +/* current active pgd - this is similar to other processors pgd + * registers like cr3 on the i386 + */ + +extern volatile pgd_t *current_pgd; /* defined in arch/cris/mm/fault.c */ + static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk, unsigned cpu) { } diff -u --recursive --new-file v2.4.6/linux/include/asm-cris/ptrace.h linux/include/asm-cris/ptrace.h --- v2.4.6/linux/include/asm-cris/ptrace.h Tue May 1 16:05:00 2001 +++ linux/include/asm-cris/ptrace.h Wed Jul 4 11:50:39 2001 @@ -22,8 +22,9 @@ #define PT_MOF 16 #define PT_DCCR 17 #define PT_SRP 18 -#define PT_IRP 19 -#define PT_CSRINSTR 20 /* CPU Status record remnants - valid if frametype == busfault */ +#define PT_IRP 19 /* This is actually the debugged process' PC */ +#define PT_CSRINSTR 20 /* CPU Status record remnants - + valid if frametype == busfault */ #define PT_CSRADDR 21 #define PT_CSRDATA 22 #define PT_USP 23 /* special case - USP is not in the pt_regs */ @@ -31,12 +32,9 @@ /* Frame types */ -#define CRIS_FRAME_NORMAL 0 /* normal frame without SBFS stacking */ -#define CRIS_FRAME_BUSFAULT 1 /* frame stacked using SBFS, need RBF return path */ - -/* Arbitrarily choose the same ptrace numbers as used by the Sparc code. */ -#define PTRACE_GETREGS 12 -#define PTRACE_SETREGS 13 +#define CRIS_FRAME_NORMAL 0 /* normal frame without SBFS stacking */ +#define CRIS_FRAME_BUSFAULT 1 /* frame stacked using SBFS, need RBF return + path */ /* pt_regs not only specifices the format in the user-struct during * ptrace but is also the frame format used in the kernel prologue/epilogues @@ -47,10 +45,10 @@ unsigned long frametype; /* type of stackframe */ unsigned long orig_r10; /* pushed by movem r13, [sp] in SAVE_ALL, movem pushes backwards */ - unsigned long r13; /* 8 */ - unsigned long r12; /* 12 */ - unsigned long r11; /* 16 */ - unsigned long r10; /* 20 */ + unsigned long r13; + unsigned long r12; + unsigned long r11; + unsigned long r10; unsigned long r9; unsigned long r8; unsigned long r7; @@ -64,20 +62,21 @@ unsigned long mof; unsigned long dccr; unsigned long srp; - unsigned long irp; + unsigned long irp; /* This is actually the debugged process' PC */ unsigned long csrinstr; unsigned long csraddr; unsigned long csrdata; }; -/* switch_stack is the extra stuff pushed onto the stack in _resume (entry.S) when - doing a context-switch. it is used (apart from in resume) when a new thread is made - and we need to make _resume (which is starting it for the first time) realise what - is going on. - - actually, the use is very close to the thread struct (TSS) in that both the switch_stack - and the TSS are used to keep thread stuff when switching in _resume. -*/ +/* switch_stack is the extra stuff pushed onto the stack in _resume (entry.S) + * when doing a context-switch. it is used (apart from in resume) when a new + * thread is made and we need to make _resume (which is starting it for the + * first time) realise what is going on. + * + * Actually, the use is very close to the thread struct (TSS) in that both the + * switch_stack and the TSS are used to keep thread stuff when switching in + * _resume. + */ struct switch_stack { unsigned long r9; @@ -94,6 +93,10 @@ }; #ifdef __KERNEL__ +/* Arbitrarily choose the same ptrace numbers as used by the Sparc code. */ +#define PTRACE_GETREGS 12 +#define PTRACE_SETREGS 13 + /* bit 8 is user-mode flag */ #define user_mode(regs) ((regs)->dccr & 0x100) #define instruction_pointer(regs) ((regs)->irp) diff -u --recursive --new-file v2.4.6/linux/include/asm-cris/semaphore.h linux/include/asm-cris/semaphore.h --- v2.4.6/linux/include/asm-cris/semaphore.h Tue Apr 17 17:19:30 2001 +++ linux/include/asm-cris/semaphore.h Wed Jul 4 11:50:39 2001 @@ -1,4 +1,4 @@ -/* $Id: semaphore.h,v 1.2 2000/07/13 16:52:46 bjornw Exp $ */ +/* $Id: semaphore.h,v 1.3 2001/05/08 13:54:09 bjornw Exp $ */ /* On the i386 these are coded in asm, perhaps we should as well. Later.. */ diff -u --recursive --new-file v2.4.6/linux/include/asm-cris/svinto.h linux/include/asm-cris/svinto.h --- v2.4.6/linux/include/asm-cris/svinto.h Thu Feb 8 16:32:44 2001 +++ linux/include/asm-cris/svinto.h Wed Jul 4 11:50:39 2001 @@ -33,14 +33,29 @@ unsigned long next; /* 4-7 */ unsigned long buf; /* 8-11 */ unsigned short hw_len; /* 12-13 */ - unsigned short status; /* 14-15 */ + unsigned char status; /* 14 */ + unsigned char fifo_len; /* 15 */ } etrax_dma_descr; -#define RESET_DMA( n ) \ + +/* Use this for constant numbers only */ +#define RESET_DMA_NUM( n ) \ *R_DMA_CH##n##_CMD = IO_STATE( R_DMA_CH0_CMD, cmd, reset ) -#define WAIT_DMA( n ) \ +/* Use this for constant numbers or symbols, + * having two macros makes it possible to use constant expressions. + */ +#define RESET_DMA( n ) RESET_DMA_NUM( n ) + + +/* Use this for constant numbers only */ +#define WAIT_DMA_NUM( n ) \ while( (*R_DMA_CH##n##_CMD & IO_MASK( R_DMA_CH0_CMD, cmd )) != \ IO_STATE( R_DMA_CH0_CMD, cmd, hold ) ) + +/* Use this for constant numbers or symbols + * having two macros makes it possible to use constant expressions. + */ +#define WAIT_DMA( n ) WAIT_DMA_NUM( n ) #endif diff -u --recursive --new-file v2.4.6/linux/include/asm-i386/atomic.h linux/include/asm-i386/atomic.h --- v2.4.6/linux/include/asm-i386/atomic.h Fri May 25 18:01:26 2001 +++ linux/include/asm-i386/atomic.h Fri Jul 20 12:52:18 2001 @@ -195,4 +195,10 @@ __asm__ __volatile__(LOCK "orl %0,%1" \ : : "r" (mask),"m" (*addr) : "memory") +/* Atomic operations are already serializing on x86 */ +#define smp_mb__before_atomic_dec() barrier() +#define smp_mb__after_atomic_dec() barrier() +#define smp_mb__before_atomic_inc() barrier() +#define smp_mb__after_atomic_inc() barrier() + #endif diff -u --recursive --new-file v2.4.6/linux/include/asm-i386/hardirq.h linux/include/asm-i386/hardirq.h --- v2.4.6/linux/include/asm-i386/hardirq.h Tue Jul 3 17:08:21 2001 +++ linux/include/asm-i386/hardirq.h Fri Jul 20 12:52:18 2001 @@ -11,6 +11,7 @@ unsigned int __local_irq_count; unsigned int __local_bh_count; unsigned int __syscall_count; + struct task_struct * __ksoftirqd_task; /* waitqueue is too large */ unsigned int __nmi_count; /* arch dependent */ } ____cacheline_aligned irq_cpustat_t; diff -u --recursive --new-file v2.4.6/linux/include/asm-i386/processor.h linux/include/asm-i386/processor.h --- v2.4.6/linux/include/asm-i386/processor.h Fri May 25 18:01:26 2001 +++ linux/include/asm-i386/processor.h Fri Jul 20 12:52:18 2001 @@ -126,7 +126,7 @@ "=b" (*ebx), "=c" (*ecx), "=d" (*edx) - : "a" (op)); + : "0" (op)); } /* @@ -134,38 +134,42 @@ */ extern inline unsigned int cpuid_eax(unsigned int op) { - unsigned int eax, ebx, ecx, edx; + unsigned int eax; __asm__("cpuid" - : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx) - : "a" (op)); + : "=a" (eax) + : "0" (op) + : "bx", "cx", "dx"); return eax; } extern inline unsigned int cpuid_ebx(unsigned int op) { - unsigned int eax, ebx, ecx, edx; + unsigned int eax, ebx; __asm__("cpuid" - : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx) - : "a" (op)); + : "=a" (eax), "=b" (ebx) + : "0" (op) + : "cx", "dx" ); return ebx; } extern inline unsigned int cpuid_ecx(unsigned int op) { - unsigned int eax, ebx, ecx, edx; + unsigned int eax, ecx; __asm__("cpuid" - : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx) - : "a" (op)); + : "=a" (eax), "=c" (ecx) + : "0" (op) + : "bx", "dx" ); return ecx; } extern inline unsigned int cpuid_edx(unsigned int op) { - unsigned int eax, ebx, ecx, edx; + unsigned int eax, edx; __asm__("cpuid" - : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx) - : "a" (op)); + : "=a" (eax), "=d" (edx) + : "0" (op) + : "bx", "cx"); return edx; } @@ -222,6 +226,7 @@ #define CX86_CCR4 0xe8 #define CX86_CCR5 0xe9 #define CX86_CCR6 0xea +#define CX86_CCR7 0xeb #define CX86_DIR0 0xfe #define CX86_DIR1 0xff #define CX86_ARR_BASE 0xc4 diff -u --recursive --new-file v2.4.6/linux/include/asm-i386/softirq.h linux/include/asm-i386/softirq.h --- v2.4.6/linux/include/asm-i386/softirq.h Tue Jul 3 17:08:21 2001 +++ linux/include/asm-i386/softirq.h Fri Jul 20 12:52:18 2001 @@ -11,8 +11,6 @@ #define local_bh_disable() cpu_bh_disable(smp_processor_id()) #define __local_bh_enable() __cpu_bh_enable(smp_processor_id()) -#define __cpu_raise_softirq(cpu,nr) set_bit((nr), &softirq_pending(cpu)); -#define raise_softirq(nr) __cpu_raise_softirq(smp_processor_id(), (nr)) #define in_softirq() (local_bh_count(smp_processor_id()) != 0) @@ -28,6 +26,7 @@ do { \ unsigned int *ptr = &local_bh_count(smp_processor_id()); \ \ + barrier(); \ if (!--*ptr) \ __asm__ __volatile__ ( \ "cmpl $0, -8(%0);" \ @@ -45,5 +44,7 @@ : "r" (ptr), "i" (do_softirq) \ /* no registers clobbered */ ); \ } while (0) + +#define __cpu_raise_softirq(cpu, nr) __set_bit(nr, &softirq_pending(cpu)) #endif /* __ASM_SOFTIRQ_H */ diff -u --recursive --new-file v2.4.6/linux/include/asm-ia64/atomic.h linux/include/asm-ia64/atomic.h --- v2.4.6/linux/include/asm-ia64/atomic.h Mon Oct 9 17:54:57 2000 +++ linux/include/asm-ia64/atomic.h Mon Jul 9 21:30:19 2001 @@ -91,4 +91,10 @@ #define atomic_inc(v) atomic_add(1, (v)) #define atomic_dec(v) atomic_sub(1, (v)) +/* Atomic operations are already serializing */ +#define smp_mb__before_atomic_dec() barrier() +#define smp_mb__after_atomic_dec() barrier() +#define smp_mb__before_atomic_inc() barrier() +#define smp_mb__after_atomic_inc() barrier() + #endif /* _ASM_IA64_ATOMIC_H */ diff -u --recursive --new-file v2.4.6/linux/include/asm-ia64/processor.h linux/include/asm-ia64/processor.h --- v2.4.6/linux/include/asm-ia64/processor.h Thu Apr 12 12:10:25 2001 +++ linux/include/asm-ia64/processor.h Thu Jul 19 20:38:52 2001 @@ -379,9 +379,9 @@ regs->ar_bspstore = IA64_RBS_BOT; \ regs->ar_fpsr = FPSR_DEFAULT; \ regs->loadrs = 0; \ - regs->r8 = current->dumpable; /* set "don't zap registers" flag */ \ + regs->r8 = current->mm->dumpable; /* set "don't zap registers" flag */ \ regs->r12 = new_sp - 16; /* allocate 16 byte scratch area */ \ - if (!__builtin_expect (current->dumpable, 1)) { \ + if (!__builtin_expect (current->mm->dumpable, 1)) { \ /* \ * Zap scratch regs to avoid leaking bits between processes with different \ * uid/privileges. \ diff -u --recursive --new-file v2.4.6/linux/include/asm-m68k/atomic.h linux/include/asm-m68k/atomic.h --- v2.4.6/linux/include/asm-m68k/atomic.h Fri Nov 20 11:43:55 1998 +++ linux/include/asm-m68k/atomic.h Mon Jul 9 21:30:19 2001 @@ -49,4 +49,10 @@ #define atomic_set_mask(mask, v) \ __asm__ __volatile__("orl %1,%0" : "=m" (*v) : "id" (mask),"0"(*v)) +/* Atomic operations are already serializing */ +#define smp_mb__before_atomic_dec() barrier() +#define smp_mb__after_atomic_dec() barrier() +#define smp_mb__before_atomic_inc() barrier() +#define smp_mb__after_atomic_inc() barrier() + #endif /* __ARCH_M68K_ATOMIC __ */ diff -u --recursive --new-file v2.4.6/linux/include/asm-mips/atomic.h linux/include/asm-mips/atomic.h --- v2.4.6/linux/include/asm-mips/atomic.h Tue Jul 3 17:08:21 2001 +++ linux/include/asm-mips/atomic.h Mon Jul 9 21:30:19 2001 @@ -272,6 +272,12 @@ * Currently not implemented for MIPS. */ +/* Atomic operations are already serializing */ +#define smp_mb__before_atomic_dec() barrier() +#define smp_mb__after_atomic_dec() barrier() +#define smp_mb__before_atomic_inc() barrier() +#define smp_mb__after_atomic_inc() barrier() + #endif /* defined(__KERNEL__) */ #endif /* __ASM_ATOMIC_H */ diff -u --recursive --new-file v2.4.6/linux/include/asm-mips64/atomic.h linux/include/asm-mips64/atomic.h --- v2.4.6/linux/include/asm-mips64/atomic.h Tue Nov 28 21:42:04 2000 +++ linux/include/asm-mips64/atomic.h Mon Jul 9 21:30:19 2001 @@ -21,7 +21,23 @@ #ifdef __KERNEL__ #define ATOMIC_INIT(i) { (i) } +/* + * atomic_read - read atomic variable + * @v: pointer of type atomic_t + * + * Atomically reads the value of @v. Note that the guaranteed + * useful range of an atomic_t is only 24 bits. + */ #define atomic_read(v) ((v)->counter) + +/* + * atomic_set - set atomic variable + * @v: pointer of type atomic_t + * @i: required value + * + * Atomically sets the value of @v to @i. Note that the guaranteed + * useful range of an atomic_t is only 24 bits. + */ #define atomic_set(v,i) ((v)->counter = (i)) extern __inline__ void atomic_add(int i, volatile atomic_t * v) @@ -37,6 +53,14 @@ : "Ir" (i), "m" (v->counter)); } +/* + * atomic_sub - subtract the atomic variable + * @i: integer value to subtract + * @v: pointer of type atomic_t + * + * Atomically subtracts @i from @v. Note that the guaranteed + * useful range of an atomic_t is only 24 bits. + */ extern __inline__ void atomic_sub(int i, volatile atomic_t * v) { unsigned long temp; @@ -94,11 +118,77 @@ #define atomic_dec_return(v) atomic_sub_return(1,(v)) #define atomic_inc_return(v) atomic_add_return(1,(v)) +/* + * atomic_sub_and_test - subtract value from variable and test result + * @i: integer value to subtract + * @v: pointer of type atomic_t + * + * Atomically subtracts @i from @v and returns + * true if the result is zero, or false for all + * other cases. Note that the guaranteed + * useful range of an atomic_t is only 24 bits. + */ #define atomic_sub_and_test(i,v) (atomic_sub_return((i), (v)) == 0) + +/* + * atomic_inc_and_test - increment and test + * @v: pointer of type atomic_t + * + * Atomically increments @v by 1 + * and returns true if the result is zero, or false for all + * other cases. Note that the guaranteed + * useful range of an atomic_t is only 24 bits. + * atomic_inc_and_test is currently not implemented for mips64. + */ + +/* + * atomic_dec_and_test - decrement by 1 and test + * @v: pointer of type atomic_t + * + * Atomically decrements @v by 1 and + * returns true if the result is 0, or false for all other + * cases. Note that the guaranteed + * useful range of an atomic_t is only 24 bits. + */ #define atomic_dec_and_test(v) (atomic_sub_return(1, (v)) == 0) +/* + * atomic_inc - increment atomic variable + * @v: pointer of type atomic_t + * + * Atomically increments @v by 1. Note that the guaranteed + * useful range of an atomic_t is only 24 bits. + */ #define atomic_inc(v) atomic_add(1,(v)) + +/* + * atomic_dec - decrement and test + * @v: pointer of type atomic_t + * + * Atomically decrements @v by 1. Note that the guaranteed + * useful range of an atomic_t is only 24 bits. + */ #define atomic_dec(v) atomic_sub(1,(v)) + +/* + * atomic_add_negative - add and test if negative + * @v: pointer of type atomic_t + * @i: integer value to add + * + * Atomically adds @i to @v and returns true + * if the result is negative, or false when + * result is greater than or equal to zero. Note that the guaranteed + * useful range of an atomic_t is only 24 bits. + * + * atomic_add_negative is currently not implemented for mips64. + */ + +/* Atomic operations are already serializing */ +#define smp_mb__before_atomic_dec() barrier() +#define smp_mb__after_atomic_dec() barrier() +#define smp_mb__before_atomic_inc() barrier() +#define smp_mb__after_atomic_inc() barrier() + #endif /* defined(__KERNEL__) */ #endif /* _ASM_ATOMIC_H */ diff -u --recursive --new-file v2.4.6/linux/include/asm-mips64/bitops.h linux/include/asm-mips64/bitops.h --- v2.4.6/linux/include/asm-mips64/bitops.h Tue Nov 28 21:42:04 2000 +++ linux/include/asm-mips64/bitops.h Wed Jul 4 11:50:39 2001 @@ -21,16 +21,15 @@ #include <asm/mipsregs.h> /* - * clear_bit() doesn't provide any barrier for the compiler. + * set_bit - Atomically set a bit in memory + * @nr: the bit to set + * @addr: the address to start counting from + * + * This function is atomic and may not be reordered. See __set_bit() + * if you do not require the atomic guarantees. + * Note that @nr may be almost arbitrarily large; this function is not + * restricted to acting on a single-word quantity. */ -#define smp_mb__before_clear_bit() barrier() -#define smp_mb__after_clear_bit() barrier() - -/* - * These functions for MIPS ISA > 1 are interrupt and SMP proof and - * interrupt friendly - */ - extern __inline__ void set_bit(unsigned long nr, volatile void *addr) { @@ -47,7 +46,15 @@ : "memory"); } -/* WARNING: non atomic and it can be reordered! */ +/* + * __set_bit - Set a bit in memory + * @nr: the bit to set + * @addr: the address to start counting from + * + * Unlike set_bit(), this function is non-atomic and may be reordered. + * If it's called on the same region of memory simultaneously, the effect + * may be that only one operation succeeds. + */ extern __inline__ void __set_bit(int nr, volatile void * addr) { unsigned long * m = ((unsigned long *) addr) + (nr >> 6); @@ -55,6 +62,16 @@ *m |= 1UL << (nr & 0x3f); } +/* + * clear_bit - Clears a bit in memory + * @nr: Bit to clear + * @addr: Address to start counting from + * + * clear_bit() is atomic and may not be reordered. However, it does + * not contain a memory barrier, so if it is used for locking purposes, + * you should call smp_mb__before_clear_bit() and/or smp_mb__after_clear_bit() + * in order to ensure changes are visible on other processors. + */ extern __inline__ void clear_bit(unsigned long nr, volatile void *addr) { @@ -70,7 +87,18 @@ : "ir" (~(1UL << (nr & 0x3f))), "m" (*m)); } +#define smp_mb__before_clear_bit() barrier() +#define smp_mb__after_clear_bit() barrier() +/* + * change_bit - Toggle a bit in memory + * @nr: Bit to clear + * @addr: Address to start counting from + * + * change_bit() is atomic and may not be reordered. + * Note that @nr may be almost arbitrarily large; this function is not + * restricted to acting on a single-word quantity. + */ extern __inline__ void change_bit(unsigned long nr, volatile void *addr) { @@ -86,6 +114,30 @@ :"ir" (1UL << (nr & 0x3f)), "m" (*m)); } +/* + * __change_bit - Toggle a bit in memory + * @nr: the bit to set + * @addr: the address to start counting from + * + * Unlike change_bit(), this function is non-atomic and may be reordered. + * If it's called on the same region of memory simultaneously, the effect + * may be that only one operation succeeds. + */ +extern __inline__ void __change_bit(int nr, volatile void * addr) +{ + unsigned long * m = ((unsigned long *) addr) + (nr >> 6); + + *m ^= 1UL << (nr & 0x3f); +} + +/* + * test_and_set_bit - Set a bit and return its old value + * @nr: Bit to set + * @addr: Address to count from + * + * This operation is atomic and cannot be reordered. + * It also implies a memory barrier. + */ extern __inline__ unsigned long test_and_set_bit(unsigned long nr, volatile void *addr) { @@ -107,19 +159,37 @@ return res != 0; } -extern __inline__ int __test_and_set_bit(int nr, volatile void * addr) +/* + * __test_and_set_bit - Set a bit and return its old value + * @nr: Bit to set + * @addr: Address to count from + * + * This operation is non-atomic and can be reordered. + * If two examples of this operation race, one can appear to succeed + * but actually fail. You must protect multiple accesses with a lock. + */ +extern __inline__ int +__test_and_set_bit(int nr, volatile void * addr) { - int mask, retval; - volatile long *a = addr; + unsigned long mask, retval; + long *a = (unsigned long *) addr; - a += nr >> 6; - mask = 1 << (nr & 0x3f); - retval = (mask & *a) != 0; + a += (nr >> 6); + mask = 1UL << (nr & 0x3f); + retval = ((mask & *a) != 0); *a |= mask; return retval; } +/* + * test_and_clear_bit - Clear a bit and return its old value + * @nr: Bit to set + * @addr: Address to count from + * + * This operation is atomic and cannot be reordered. + * It also implies a memory barrier. + */ extern __inline__ unsigned long test_and_clear_bit(unsigned long nr, volatile void *addr) { @@ -142,19 +212,37 @@ return res != 0; } -extern __inline__ int __test_and_clear_bit(int nr, volatile void * addr) +/* + * __test_and_clear_bit - Clear a bit and return its old value + * @nr: Bit to set + * @addr: Address to count from + * + * This operation is non-atomic and can be reordered. + * If two examples of this operation race, one can appear to succeed + * but actually fail. You must protect multiple accesses with a lock. + */ +extern __inline__ int +__test_and_clear_bit(int nr, volatile void * addr) { - int mask, retval; - volatile long *a = addr; + unsigned long mask, retval; + unsigned long *a = (unsigned long *) addr; - a += nr >> 6; - mask = 1 << (nr & 0x3f); - retval = (mask & *a) != 0; + a += (nr >> 6); + mask = 1UL << (nr & 0x3f); + retval = ((mask & *a) != 0); *a &= ~mask; return retval; } +/* + * test_and_change_bit - Change a bit and return its new value + * @nr: Bit to set + * @addr: Address to count from + * + * This operation is atomic and cannot be reordered. + * It also implies a memory barrier. + */ extern __inline__ unsigned long test_and_change_bit(unsigned long nr, volatile void *addr) { @@ -176,16 +264,51 @@ return res != 0; } +/* + * __test_and_change_bit - Change a bit and return its old value + * @nr: Bit to set + * @addr: Address to count from + * + * This operation is non-atomic and can be reordered. + * If two examples of this operation race, one can appear to succeed + * but actually fail. You must protect multiple accesses with a lock. + */ +extern __inline__ int +__test_and_change_bit(int nr, volatile void * addr) +{ + unsigned long mask, retval; + unsigned long *a = (unsigned long *) addr; + + a += (nr >> 6); + mask = 1UL << (nr & 0x3f); + retval = ((mask & *a) != 0); + *a ^= mask; + + return retval; +} +/* + * test_bit - Determine whether a bit is set + * @nr: bit number to test + * @addr: Address to start counting from + */ extern __inline__ unsigned long test_bit(int nr, volatile void * addr) { - return 1UL & (((const long *) addr)[nr >> 6] >> (nr & 0x3f)); + return 1UL & (((volatile unsigned long *) addr)[nr >> 6] >> (nr & 0x3f)); } #ifndef __MIPSEB__ /* Little endian versions. */ +/* + * find_first_zero_bit - find the first zero bit in a memory region + * @addr: The address to start the search at + * @size: The maximum size to search + * + * Returns the bit-number of the first zero bit, not the number of the byte + * containing a bit. + */ extern __inline__ int find_first_zero_bit (void *addr, unsigned size) { @@ -228,6 +351,12 @@ return res; } +/* + * find_next_zero_bit - find the first zero bit in a memory region + * @addr: The address to base the search on + * @offset: The bitnumber to start searching at + * @size: The maximum size to search + */ extern __inline__ int find_next_zero_bit (void * addr, int size, int offset) { @@ -267,8 +396,10 @@ #endif /* !(__MIPSEB__) */ /* - * ffz = Find First Zero in word. Undefined if no zero exists, - * so code should check against ~0UL first.. + * ffz - find first zero in word. + * @word: The word to search + * + * Undefined if no zero exists, so code should check against ~0UL first. */ extern __inline__ unsigned long ffz(unsigned long word) { @@ -288,8 +419,12 @@ #ifdef __KERNEL__ + /* - * ffs: find first bit set. This is defined the same way as + * ffs - find first bit set + * @x: the word to search + * + * This is defined the same way as * the libc and compiler builtin ffs routines, therefore * differs in spirit from the above ffz (man ffs). */ @@ -297,8 +432,10 @@ #define ffs(x) generic_ffs(x) /* - * hweightN: returns the hamming weight (i.e. the number - * of bits set) of a N-bit word + * hweightN - returns the hamming weight of a N-bit word + * @x: the word to weigh + * + * The Hamming Weight of a number is the total number of bits set in it. */ #define hweight32(x) generic_hweight32(x) @@ -310,11 +447,11 @@ #ifdef __MIPSEB__ /* - * find_next_zero_bit() finds the first zero bit in a bit string of length - * 'size' bits, starting the search at bit 'offset'. This is largely based - * on Linus's ALPHA routines, which are pretty portable BTW. + * find_next_zero_bit - find the first zero bit in a memory region + * @addr: The address to base the search on + * @offset: The bitnumber to start searching at + * @size: The maximum size to search */ - extern __inline__ unsigned long find_next_zero_bit(void *addr, unsigned long size, unsigned long offset) { diff -u --recursive --new-file v2.4.6/linux/include/asm-mips64/bootinfo.h linux/include/asm-mips64/bootinfo.h --- v2.4.6/linux/include/asm-mips64/bootinfo.h Tue Nov 28 21:42:04 2000 +++ linux/include/asm-mips64/bootinfo.h Wed Jul 4 11:50:39 2001 @@ -88,7 +88,7 @@ /* * Valid machtype for group SGI */ -#define MACH_SGI_INDY 0 /* R4?K and R5K Indy workstaions */ +#define MACH_SGI_INDY 0 /* R4?K and R5K Indy workstations */ #define MACH_SGI_CHALLENGE_S 1 /* The Challenge S server */ #define MACH_SGI_INDIGO2 2 /* The Indigo2 system */ #define MACH_SGI_IP27 3 /* Origin 200, Origin 2000, Onyx 2 */ @@ -144,6 +144,11 @@ #define CL_SIZE (80) +#define BOOT_MEM_MAP_MAX 32 +#define BOOT_MEM_RAM 1 +#define BOOT_MEM_ROM_DATA 2 +#define BOOT_MEM_RESERVED 3 + #ifndef _LANGUAGE_ASSEMBLY /* @@ -159,6 +164,24 @@ extern unsigned long mips_machtype; extern unsigned long mips_machgroup; extern unsigned long mips_tlb_entries; + +/* + * A memory map that's built upon what was determined + * or specified on the command line. + */ +struct boot_mem_map { + int nr_map; + struct { + unsigned long addr; /* start of memory segment */ + unsigned long size; /* size of memory segment */ + long type; /* type of memory segment */ + } map[BOOT_MEM_MAP_MAX]; +}; + +extern struct boot_mem_map boot_mem_map; + +extern void add_memory_region(unsigned long start, unsigned long size, + long type); #endif /* _LANGUAGE_ASSEMBLY */ diff -u --recursive --new-file v2.4.6/linux/include/asm-mips64/cache.h linux/include/asm-mips64/cache.h --- v2.4.6/linux/include/asm-mips64/cache.h Sat May 13 08:31:25 2000 +++ linux/include/asm-mips64/cache.h Wed Jul 4 11:50:39 2001 @@ -1,5 +1,4 @@ -/* $Id: cache.h,v 1.3 2000/02/04 07:40:53 ralf Exp $ - * +/* * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. @@ -11,7 +10,6 @@ #define _ASM_CACHE_H /* bytes per L1 cache line */ -#define L1_CACHE_BYTES 32 /* A guess */ -#define SMP_CACHE_BYTES L1_CACHE_BYTES +#define L1_CACHE_BYTES (1 << CONFIG_L1_CACHE_SHIFT) #endif /* _ASM_CACHE_H */ diff -u --recursive --new-file v2.4.6/linux/include/asm-mips64/checksum.h linux/include/asm-mips64/checksum.h --- v2.4.6/linux/include/asm-mips64/checksum.h Sat May 13 08:31:25 2000 +++ linux/include/asm-mips64/checksum.h Wed Jul 4 11:50:39 2001 @@ -1,15 +1,17 @@ -/* $Id: checksum.h,v 1.6 2000/02/18 22:06:19 ralf Exp $ - * +/* * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. * * Copyright (C) 1995, 1996, 1997, 1998, 1999 by Ralf Baechle * Copyright (C) 1999 Silicon Graphics, Inc. + * Copyright (C) 2001 Thiemo Seufer. */ #ifndef _ASM_CHECKSUM_H #define _ASM_CHECKSUM_H +#include <asm/uaccess.h> + /* * computes the checksum of a memory block at buff, length len, * and adds in "sum" (32-bit) @@ -22,7 +24,7 @@ * * it's best to have buff aligned on a 32-bit boundary */ -unsigned int csum_partial(const unsigned char * buff, int len, unsigned int sum); +unsigned int csum_partial(const unsigned char *buff, int len, unsigned int sum); /* * this is a new version of the above that records errors it finds in *errp, @@ -41,9 +43,9 @@ * Copy and checksum to user */ #define HAVE_CSUM_COPY_USER -extern inline unsigned int -csum_and_copy_to_user (const char *src, char *dst, - int len, int sum, int *err_ptr) +extern inline unsigned int csum_and_copy_to_user (const char *src, char *dst, + int len, int sum, + int *err_ptr) { sum = csum_partial(src, len, sum); @@ -62,23 +64,23 @@ * this is obsolete and will go away. */ #define csum_partial_copy_fromuser csum_partial_copy -unsigned int csum_partial_copy(const char *src, char *dst, int len, unsigned int sum); - +unsigned int csum_partial_copy(const char *src, char *dst, int len, + unsigned int sum); + /* * Fold a partial checksum without adding pseudo headers */ -static inline unsigned short int -csum_fold(unsigned int sum) +static inline unsigned short int csum_fold(unsigned int sum) { - __asm__(" - .set noat - sll $1, %0, 16 - addu %0, $1 - sltu $1, %0, $1 - srl %0, %0, 16 - addu %0, $1 - xori %0, 0xffff - .set at" + __asm__( + ".set\tnoat\t\t\t# csum_fold\n\t" + "sll\t$1,%0,16\n\t" + "addu\t%0,$1\n\t" + "sltu\t$1,%0,$1\n\t" + "srl\t%0,%0,16\n\t" + "addu\t%0,$1\n\t" + "xori\t%0,0xffff\n\t" + ".set\tat" : "=r" (sum) : "0" (sum) : "$1"); @@ -93,8 +95,8 @@ * By Jorge Cwik <jorge@laser.satlink.net>, adapted for linux by * Arnt Gulbrandsen. */ -static inline unsigned short -ip_fast_csum(unsigned char * iph, unsigned int ihl) +static inline unsigned short ip_fast_csum(unsigned char *iph, + unsigned int ihl) { unsigned int sum; unsigned long dummy; @@ -103,36 +105,35 @@ * This is for 32-bit processors ... but works just fine for 64-bit * processors for now ... XXX */ - __asm__ __volatile__(" - .set noreorder - .set noat - lw %0, (%1) - subu %2, 4 - dsll %2, 2 - - lw %3, 4(%1) - daddu %2, %1 - addu %0, %3 - sltu $1, %0, %3 - lw %3, 8(%1) - addu %0, $1 - addu %0, %3 - sltu $1, %0, %3 - lw %3, 12(%1) - addu %0, $1 - addu %0, %3 - sltu $1, %0, %3 - addu %0, $1 - -1: lw %3, 16(%1) - daddiu %1, 4 - addu %0, %3 - sltu $1, %0, %3 - bne %2, %1, 1b - addu %0, $1 + __asm__ __volatile__( + ".set\tnoreorder\t\t\t# ip_fast_csum\n\t" + ".set\tnoat\n\t" + "lw\t%0, (%1)\n\t" + "subu\t%2, 4\n\t" + "dsll\t%2, 2\n\t" + "lw\t%3, 4(%1)\n\t" + "daddu\t%2, %1\n\t" + "addu\t%0, %3\n\t" + "sltu\t$1, %0, %3\n\t" + "lw\t%3, 8(%1)\n\t" + "addu\t%0, $1\n\t" + "addu\t%0, %3\n\t" + "sltu\t$1, %0, %3\n\t" + "lw\t%3, 12(%1)\n\t" + "addu\t%0, $1\n\t" + "addu\t%0, %3\n\t" + "sltu\t$1, %0, %3\n\t" + "addu\t%0, $1\n" + + "1:\tlw\t%3, 16(%1)\n\t" + "daddiu\t%1, 4\n" + "addu\t%0, %3\n\t" + "sltu\t$1, %0, %3\n\t" + "bne\t%2, %1, 1b\n\t" + " addu\t%0, $1\n" -2: .set at - .set reorder" + "2:\t.set\tat\n\t" + ".set\treorder" : "=&r" (sum), "=&r" (iph), "=&r" (ihl), "=&r" (dummy) : "1" (iph), "2" (ihl) : "$1"); @@ -144,26 +145,29 @@ * computes the checksum of the TCP/UDP pseudo-header * returns a 16-bit checksum, already complemented */ -static inline unsigned long -csum_tcpudp_nofold(unsigned long saddr, unsigned long daddr, - unsigned short len, unsigned short proto, unsigned int sum) -{ - __asm__(" - .set noat - daddu %0, %2 - daddu %0, %3 - daddu %0, %4 - dsll32 $1, %0, 0 - daddu %0, $1 # never results in an overflow - dsrl32 %0, %0, 0 - .set at" +static inline unsigned long csum_tcpudp_nofold(unsigned long saddr, + unsigned long daddr, + unsigned short len, + unsigned short proto, + unsigned int sum) +{ + __asm__( + ".set\tnoat\t\t\t# csum_tcpudp_nofold\n\t" + "daddu\t%0, %2\n\t" + "daddu\t%0, %3\n\t" + "daddu\t%0, %4\n\t" + "dsll32\t$1, %0, 0\n\t" + "daddu\t%0, $1\n\t" + "dsrl32\t%0, %0, 0\n\t" + ".set\tat" : "=r" (sum) - : "0" (sum), "r"(saddr), "r" (daddr), + : "0" (daddr), "r"(saddr), #ifdef __MIPSEL__ - "r" ((ntohs(len)<<16)+proto*256) + "r" ((ntohs(len)<<16)+proto*256), #else - "r" (((proto)<<16)+len) + "r" (((proto)<<16)+len), #endif + "r" (sum) : "$1"); return sum; @@ -173,82 +177,85 @@ * computes the checksum of the TCP/UDP pseudo-header * returns a 16-bit checksum, already complemented */ -static inline unsigned short int -csum_tcpudp_magic(unsigned long saddr, unsigned long daddr, unsigned short len, - unsigned short proto, unsigned int sum) +static inline unsigned short int csum_tcpudp_magic(unsigned long saddr, + unsigned long daddr, + unsigned short len, + unsigned short proto, + unsigned int sum) { - return csum_fold(csum_tcpudp_nofold(saddr,daddr,len,proto,sum)); + return csum_fold(csum_tcpudp_nofold(saddr, daddr, len, proto, sum)); } /* * this routine is used for miscellaneous IP-like checksums, mainly * in icmp.c */ -static inline unsigned short -ip_compute_csum(unsigned char * buff, int len) +static inline unsigned short ip_compute_csum(unsigned char * buff, int len) { return csum_fold(csum_partial(buff, len, 0)); } #define _HAVE_ARCH_IPV6_CSUM -static inline unsigned short int -csum_ipv6_magic(struct in6_addr *saddr, struct in6_addr *daddr, __u32 len, - unsigned short proto, unsigned int sum) -{ - __asm__(" - .set noreorder - .set noat - addu %0, %5 # proto (long in network byte order) - sltu $1, %0, %5 - addu %0, $1 - - addu %0, %6 # csum - sltu $1, %0, %6 - lw %1, 0(%2) # four words source address - addu %0, $1 - addu %0, %1 - sltu $1, %0, $1 - - lw %1, 4(%2) - addu %0, $1 - addu %0, %1 - sltu $1, %0, $1 - - lw %1, 8(%2) - addu %0, $1 - addu %0, %1 - sltu $1, %0, $1 - - lw %1, 12(%2) - addu %0, $1 - addu %0, %1 - sltu $1, %0, $1 - - lw %1, 0(%3) - addu %0, $1 - addu %0, %1 - sltu $1, %0, $1 - - lw %1, 4(%3) - addu %0, $1 - addu %0, %1 - sltu $1, %0, $1 - - lw %1, 8(%3) - addu %0, $1 - addu %0, %1 - sltu $1, %0, $1 - - lw %1, 12(%3) - addu %0, $1 - addu %0, %1 - sltu $1, %0, $1 - .set noat - .set noreorder" - : "=r" (sum), "=r" (proto) - : "r" (saddr), "r" (daddr), - "0" (htonl(len)), "1" (htonl(proto)), "r"(sum) - : "$1"); +static inline unsigned short int csum_ipv6_magic(struct in6_addr *saddr, + struct in6_addr *daddr, + __u32 len, + unsigned short proto, + unsigned int sum) +{ + __asm__( + ".set\tnoreorder\t\t\t# csum_ipv6_magic\n\t" + ".set\tnoat\n\t" + "addu\t%0, %5\t\t\t# proto (long in network byte order)\n\t" + "sltu\t$1, %0, %5\n\t" + "addu\t%0, $1\n\t" + + "addu\t%0, %6\t\t\t# csum\n\t" + "sltu\t$1, %0, %6\n\t" + "lw\t%1, 0(%2)\t\t\t# four words source address\n\t" + "addu\t%0, $1\n\t" + "addu\t%0, %1\n\t" + "sltu\t$1, %0, $1\n\t" + + "lw\t%1, 4(%2)\n\t" + "addu\t%0, $1\n\t" + "addu\t%0, %1\n\t" + "sltu\t$1, %0, $1\n\t" + + "lw\t%1, 8(%2)\n\t" + "addu\t%0, $1\n\t" + "addu\t%0, %1\n\t" + "sltu\t$1, %0, $1\n\t" + + "lw\t%1, 12(%2)\n\t" + "addu\t%0, $1\n\t" + "addu\t%0, %1\n\t" + "sltu\t$1, %0, $1\n\t" + + "lw\t%1, 0(%3)\n\t" + "addu\t%0, $1\n\t" + "addu\t%0, %1\n\t" + "sltu\t$1, %0, $1\n\t" + + "lw\t%1, 4(%3)\n\t" + "addu\t%0, $1\n\t" + "addu\t%0, %1\n\t" + "sltu\t$1, %0, $1\n\t" + + "lw\t%1, 8(%3)\n\t" + "addu\t%0, $1\n\t" + "addu\t%0, %1\n\t" + "sltu\t$1, %0, $1\n\t" + + "lw\t%1, 12(%3)\n\t" + "addu\t%0, $1\n\t" + "addu\t%0, %1\n\t" + "sltu\t$1, %0, $1\n\t" + ".set\tnoat\n\t" + ".set\tnoreorder" + : "=r" (sum), "=r" (proto) + : "r" (saddr), "r" (daddr), + "0" (htonl(len)), "1" (htonl(proto)), "r" (sum) + : "$1"); return csum_fold(sum); } diff -u --recursive --new-file v2.4.6/linux/include/asm-mips64/cpu.h linux/include/asm-mips64/cpu.h --- v2.4.6/linux/include/asm-mips64/cpu.h Sat May 13 08:31:25 2000 +++ linux/include/asm-mips64/cpu.h Wed Jul 4 11:50:39 2001 @@ -1,5 +1,4 @@ -/* $Id: cpu.h,v 1.1 1999/10/19 20:51:53 ralf Exp $ - * +/* * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. @@ -18,17 +17,18 @@ * be examined. */ #define PRID_IMP_R2000 0x0100 -#define PRID_IMP_R3000 0x0200 -#define PRID_IMP_R6000 0x0300 +#define PRID_IMP_R3000 0x0200 /* Same as R2000A */ +#define PRID_IMP_R6000 0x0300 /* Same as R3000A */ #define PRID_IMP_R4000 0x0400 #define PRID_IMP_R6000A 0x0600 #define PRID_IMP_R10000 0x0900 #define PRID_IMP_R4300 0x0b00 +#define PRID_IMP_R12000 0x0e00 #define PRID_IMP_R8000 0x1000 #define PRID_IMP_R4600 0x2000 #define PRID_IMP_R4700 0x2100 #define PRID_IMP_R4640 0x2200 -#define PRID_IMP_R4650 0x2200 /* Same as R4640 */ +#define PRID_IMP_R4650 0x2200 /* Same as R4640 */ #define PRID_IMP_R5000 0x2300 #define PRID_IMP_SONIC 0x2400 #define PRID_IMP_MAGIC 0x2500 diff -u --recursive --new-file v2.4.6/linux/include/asm-mips64/delay.h linux/include/asm-mips64/delay.h --- v2.4.6/linux/include/asm-mips64/delay.h Sun Feb 4 21:48:46 2001 +++ linux/include/asm-mips64/delay.h Wed Jul 4 11:50:39 2001 @@ -12,7 +12,7 @@ #include <linux/config.h> -extern unsigned long loops_per_sec; +extern unsigned long loops_per_jiffy; extern __inline__ void __delay(unsigned long loops) @@ -36,21 +36,21 @@ * first constant multiplications gets optimized away if the delay is * a constant) */ -extern __inline__ void __udelay(unsigned long usecs, unsigned long lps) +extern __inline__ void __udelay(unsigned long usecs, unsigned long lpj) { unsigned long lo; - usecs *= 0x000010c6f7a0b5edUL; /* 2**64 / 1000000 */ + usecs *= 0x00068db8bac710cbUL; /* 2**64 / (1000000 / HZ) */ __asm__("dmultu\t%2,%3" :"=h" (usecs), "=l" (lo) - :"r" (usecs),"r" (lps)); + :"r" (usecs),"r" (lpj)); __delay(usecs); } #ifdef CONFIG_SMP #define __udelay_val cpu_data[smp_processor_id()].udelay_val #else -#define __udelay_val loops_per_sec +#define __udelay_val loops_per_jiffy #endif #define udelay(usecs) __udelay((usecs),__udelay_val) diff -u --recursive --new-file v2.4.6/linux/include/asm-mips64/elf.h linux/include/asm-mips64/elf.h --- v2.4.6/linux/include/asm-mips64/elf.h Thu Jul 27 18:36:54 2000 +++ linux/include/asm-mips64/elf.h Wed Jul 4 11:50:39 2001 @@ -29,8 +29,7 @@ int __res = 1; \ struct elfhdr *__h = (hdr); \ \ - if ((__h->e_machine != EM_MIPS) && \ - (__h->e_machine != EM_MIPS_RS4_BE)) \ + if (__h->e_machine != EM_MIPS) \ __res = 0; \ if (sizeof(elf_caddr_t) == 8 && \ __h->e_ident[EI_CLASS] == ELFCLASS32) \ diff -u --recursive --new-file v2.4.6/linux/include/asm-mips64/gcc/sgidefs.h linux/include/asm-mips64/gcc/sgidefs.h --- v2.4.6/linux/include/asm-mips64/gcc/sgidefs.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-mips64/gcc/sgidefs.h Wed Jul 4 11:50:39 2001 @@ -0,0 +1,17 @@ +/* + * include/sgidefs.h + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1996 by Ralf Baechle + * + * This file is here to satisfy GCC's expectations. + */ +#ifndef __SGIDEFS_H +#define __SGIDEFS_H + +#include <asm/sgidefs.h> + +#endif /* __SGIDEFS_H */ diff -u --recursive --new-file v2.4.6/linux/include/asm-mips64/hdreg.h linux/include/asm-mips64/hdreg.h --- v2.4.6/linux/include/asm-mips64/hdreg.h Sat May 13 08:31:25 2000 +++ linux/include/asm-mips64/hdreg.h Wed Jul 4 11:50:39 2001 @@ -1,5 +1,4 @@ -/* $Id$ - * +/* * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. @@ -7,12 +6,13 @@ * This file contains the MIPS architecture specific IDE code. * * Copyright (C) 1994-1996 Linus Torvalds & authors + * Copyright (C) 2001 Ralf Baechle */ #ifndef _ASM_HDREG_H #define _ASM_HDREG_H -typedef unsigned short ide_ioreg_t; +typedef unsigned long ide_ioreg_t; #endif /* _ASM_HDREG_H */ diff -u --recursive --new-file v2.4.6/linux/include/asm-mips64/ide.h linux/include/asm-mips64/ide.h --- v2.4.6/linux/include/asm-mips64/ide.h Sun Jul 9 22:18:15 2000 +++ linux/include/asm-mips64/ide.h Wed Jul 4 11:50:39 2001 @@ -8,10 +8,6 @@ * Copyright (C) 1994-1996 Linus Torvalds & authors */ -/* - * This file contains the MIPS architecture specific IDE code. - */ - #ifndef __ASM_IDE_H #define __ASM_IDE_H @@ -128,6 +124,52 @@ { ide_ops->ide_release_region(from, extent); } + + +#if defined(CONFIG_SWAP_IO_SPACE) && defined(__MIPSEB__) + +#ifdef insl +#undef insl +#endif +#ifdef outsl +#undef outsl +#endif +#ifdef insw +#undef insw +#endif +#ifdef outsw +#undef outsw +#endif + +#define insw(p,a,c) \ +do { \ + unsigned short *ptr = (unsigned short *)(a); \ + unsigned int i = (c); \ + while (i--) \ + *ptr++ = inw(p); \ +} while (0) +#define insl(p,a,c) \ +do { \ + unsigned long *ptr = (unsigned long *)(a); \ + unsigned int i = (c); \ + while (i--) \ + *ptr++ = inl(p); \ +} while (0) +#define outsw(p,a,c) \ +do { \ + unsigned short *ptr = (unsigned short *)(a); \ + unsigned int i = (c); \ + while (i--) \ + outw(*ptr++, (p)); \ +} while (0) +#define outsl(p,a,c) { \ + unsigned long *ptr = (unsigned long *)(a); \ + unsigned int i = (c); \ + while (i--) \ + outl(*ptr++, (p)); \ +} while (0) + +#endif /* defined(CONFIG_SWAP_IO_SPACE) && defined(__MIPSEB__) */ /* * The following are not needed for the non-m68k ports diff -u --recursive --new-file v2.4.6/linux/include/asm-mips64/io.h linux/include/asm-mips64/io.h --- v2.4.6/linux/include/asm-mips64/io.h Tue Nov 28 21:42:04 2000 +++ linux/include/asm-mips64/io.h Wed Jul 4 11:50:39 2001 @@ -185,7 +185,7 @@ ".set\tnoreorder\n\t" \ ".set\tnoat\n" \ "1:\tl" #m "\t$1, %4(%5)\n\t" \ - "dsubiu\t%1, 1\n\t" \ + "dsubu\t%1, 1\n\t" \ "s" #m "\t$1,(%0)\n\t" \ "bnez\t%1, 1b\n\t" \ "daddiu\t%0, %6\n\t" \ diff -u --recursive --new-file v2.4.6/linux/include/asm-mips64/ioctl.h linux/include/asm-mips64/ioctl.h --- v2.4.6/linux/include/asm-mips64/ioctl.h Sat May 13 08:31:25 2000 +++ linux/include/asm-mips64/ioctl.h Wed Jul 4 11:50:39 2001 @@ -1,10 +1,9 @@ -/* $Id$ - * +/* * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1995, 1996, 1999 by Ralf Baechle + * Copyright (C) 1995, 1996, 1999, 2001 by Ralf Baechle */ #ifndef _ASM_IOCTL_H #define _ASM_IOCTL_H @@ -39,11 +38,6 @@ #define _IOC_DIRSHIFT (_IOC_SIZESHIFT+_IOC_SIZEBITS) /* - * We to additionally limit parameters to a maximum 255 bytes. - */ -#define _IOC_SLMASK 0xff - -/* * Direction bits _IOC_NONE could be 0, but OSF/1 gives it a bit. * And this turns out useful to catch old ioctl numbers in header * files for us. @@ -64,7 +58,7 @@ (((dir) << _IOC_DIRSHIFT) | \ ((type) << _IOC_TYPESHIFT) | \ ((nr) << _IOC_NRSHIFT) | \ - (((size) & _IOC_SLMASK) << _IOC_SIZESHIFT)) + ((size) << _IOC_SIZESHIFT)) /* used to create numbers */ #define _IO(type,nr) _IOC(_IOC_NONE,(type),(nr),0) diff -u --recursive --new-file v2.4.6/linux/include/asm-mips64/irq.h linux/include/asm-mips64/irq.h --- v2.4.6/linux/include/asm-mips64/irq.h Tue Nov 28 21:42:04 2000 +++ linux/include/asm-mips64/irq.h Wed Jul 4 11:50:39 2001 @@ -6,15 +6,32 @@ * Copyright (C) 1994 by Waldorf GMBH, written by Ralf Baechle * Copyright (C) 1995, 96, 97, 98, 1999, 2000 by Ralf Baechle * Copyright (C) 1999, 2000 Silicon Graphics, Inc. + * Copyright (C) 2001 Kanoj Sarcar */ #ifndef _ASM_IRQ_H #define _ASM_IRQ_H #include <linux/config.h> +#include <asm/sn/arch.h> #define NR_IRQS 256 -#define TIMER_IRQ 0 +/* + * Number of levels in INT_PEND0. Can be set to 128 if we also + * consider INT_PEND1. + */ +#define PERNODE_LEVELS 64 + +extern int node_level_to_irq[MAX_COMPACT_NODES][PERNODE_LEVELS]; + +/* + * we need to map irq's up to at least bit 7 of the INT_MASK0_A register + * since bits 0-6 are pre-allocated for other purposes. + */ +#define LEAST_LEVEL 7 +#define FAST_IRQ_TO_LEVEL(i) ((i) + LEAST_LEVEL) +#define LEVEL_TO_IRQ(c, l) \ + (node_level_to_irq[CPUID_TO_COMPACT_NODEID(c)][(l)]) #ifdef CONFIG_I8259 static inline int irq_cannonicalize(int irq) diff -u --recursive --new-file v2.4.6/linux/include/asm-mips64/mipsregs.h linux/include/asm-mips64/mipsregs.h --- v2.4.6/linux/include/asm-mips64/mipsregs.h Fri Apr 13 20:26:07 2001 +++ linux/include/asm-mips64/mipsregs.h Wed Jul 4 11:50:39 2001 @@ -246,7 +246,7 @@ #define CAUSEF_BD (1 << 31) /* - * Bits in the coprozessor 0 config register. + * Bits in the coprocessor 0 config register. */ #define CONF_CM_CACHABLE_NO_WA 0 #define CONF_CM_CACHABLE_WA 1 @@ -265,7 +265,7 @@ * R10000 performance counter definitions. * * FIXME: The R10000 performance counter opens a nice way to implement CPU - * time accounting with a precission of one cycle. I don't have + * time accounting with a precision of one cycle. I don't have * R10000 silicon but just a manual, so ... */ diff -u --recursive --new-file v2.4.6/linux/include/asm-mips64/pci.h linux/include/asm-mips64/pci.h --- v2.4.6/linux/include/asm-mips64/pci.h Wed May 16 10:31:27 2001 +++ linux/include/asm-mips64/pci.h Wed Jul 4 11:50:39 2001 @@ -1,5 +1,4 @@ -/* $Id: pci.h,v 1.4 2000/02/24 00:13:20 ralf Exp $ - * +/* * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. @@ -196,8 +195,21 @@ #endif } -/* Return the index of the PCI controller for device PDEV. */ -#define pci_controller_num(PDEV) (0) +extern inline int pci_dma_supported(struct pci_dev *hwdev, dma_addr_t mask) +{ + /* + * we fall back to GFP_DMA when the mask isn't all 1s, + * so we can't guarantee allocations that must be + * within a tighter range than GFP_DMA.. + */ + if (mask < 0x00ffffff) + return 0; + + return 1; +} + +/* Return the index of the PCI controller for device. */ +#define pci_controller_num(pdev) (0) /* * These macros should be used after a pci_map_sg call has been done diff -u --recursive --new-file v2.4.6/linux/include/asm-mips64/pgalloc.h linux/include/asm-mips64/pgalloc.h --- v2.4.6/linux/include/asm-mips64/pgalloc.h Mon Apr 23 15:28:07 2001 +++ linux/include/asm-mips64/pgalloc.h Wed Jul 4 11:50:39 2001 @@ -3,8 +3,8 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1994 - 2000 by Ralf Baechle at alii - * Copyright (C) 1999, 2000 Silicon Graphics, Inc. + * Copyright (C) 1994 - 2001 by Ralf Baechle at alii + * Copyright (C) 1999, 2000, 2001 Silicon Graphics, Inc. */ #ifndef _ASM_PGALLOC_H #define _ASM_PGALLOC_H @@ -49,9 +49,7 @@ /* - * Allocate and free page tables. The xxx_kernel() versions are - * used to allocate a kernel page table - this turns on ASN bits - * if any. + * Allocate and free page tables. */ #define pgd_quicklist (current_cpu_data.pgd_quick) @@ -59,6 +57,9 @@ #define pte_quicklist (current_cpu_data.pte_quick) #define pgtable_cache_size (current_cpu_data.pgtable_cache_sz) +#define pmd_populate(mm, pmd, pte) pmd_set(pmd, pte) +#define pgd_populate(mm, pgd, pmd) pgd_set(pgd, pmd) + extern pgd_t *get_pgd_slow(void); extern inline pgd_t *get_pgd_fast(void) @@ -88,8 +89,29 @@ free_pages((unsigned long)pgd, 1); } +static inline pte_t *pte_alloc_one(struct mm_struct *mm, unsigned long address) +{ + pte_t *pte; + + pte = (pte_t *) __get_free_page(GFP_KERNEL); + if (pte) + clear_page(pte); + return pte; +} + +static inline pte_t *pte_alloc_one_fast(struct mm_struct *mm, unsigned long address) +{ + unsigned long *ret; + + if ((ret = (unsigned long *)pte_quicklist) != NULL) { + pte_quicklist = (unsigned long *)(*ret); + ret[0] = ret[1]; + pgtable_cache_size--; + } + return (pte_t *)ret; +} + extern pte_t *get_pte_slow(pmd_t *pmd, unsigned long address_preadjusted); -extern pte_t *get_pte_kernel_slow(pmd_t *pmd, unsigned long address_preadjusted); extern inline pte_t *get_pte_fast(void) { @@ -115,8 +137,29 @@ free_pages((unsigned long)pte, 0); } +static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long address) +{ + pmd_t *pmd; + + pmd = (pmd_t *) __get_free_pages(GFP_KERNEL, 1); + if (pmd) + pmd_init((unsigned long)pmd, (unsigned long)invalid_pte_table); + return pmd; +} + +static inline pmd_t *pmd_alloc_one_fast(struct mm_struct *mm, unsigned long address) +{ + unsigned long *ret; + + if ((ret = (unsigned long *)pmd_quicklist) != NULL) { + pmd_quicklist = (unsigned long *)(*ret); + ret[0] = ret[1]; + pgtable_cache_size--; + } + return (pmd_t *)ret; +} + extern pmd_t *get_pmd_slow(pgd_t *pgd, unsigned long address_preadjusted); -extern pmd_t *get_pmd_kernel_slow(pgd_t *pgd, unsigned long address_preadjusted); extern inline pmd_t *get_pmd_fast(void) { @@ -144,61 +187,13 @@ free_pages((unsigned long)pmd, 1); } -extern void __bad_pte(pmd_t *pmd); -extern void __bad_pte_kernel(pmd_t *pmd); -extern void __bad_pmd(pgd_t *pgd); - #define pte_free(pte) free_pte_fast(pte) #define pmd_free(pte) free_pmd_fast(pte) #define pgd_free(pgd) free_pgd_fast(pgd) #define pgd_alloc(mm) get_pgd_fast() -extern inline pte_t * pte_alloc(pmd_t * pmd, unsigned long address) -{ - address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1); - - if (pmd_none(*pmd)) { - pte_t *page = get_pte_fast(); - if (page) { - pmd_val(*pmd) = (unsigned long) page; - return page + address; - } - return get_pte_slow(pmd, address); - } - if (pmd_bad(*pmd)) { - __bad_pte(pmd); - return NULL; - } - return (pte_t *) pmd_page(*pmd) + address; -} - -extern inline pmd_t *pmd_alloc(pgd_t * pgd, unsigned long address) -{ - address = (address >> PMD_SHIFT) & (PTRS_PER_PMD - 1); - if (pgd_none(*pgd)) { - pmd_t *page = get_pmd_fast(); - - if (!page) - return get_pmd_slow(pgd, address); - pgd_set(pgd, page); - return page + address; - } - if (pgd_bad(*pgd)) { - __bad_pmd(pgd); - return NULL; - } - return (pmd_t *) pgd_page(*pgd) + address; -} - extern pte_t kptbl[(PAGE_SIZE<<KPTBL_PAGE_ORDER)/sizeof(pte_t)]; extern pmd_t kpmdtbl[PTRS_PER_PMD]; - -#define pmd_alloc_kernel(d,a) (pmd_t *)kpmdtbl - -extern inline pte_t * pte_alloc_kernel(pmd_t * pmd, unsigned long address) -{ - return (kptbl + (address >> PAGE_SHIFT)); -} extern int do_check_pgt_cache(int, int); diff -u --recursive --new-file v2.4.6/linux/include/asm-mips64/pgtable.h linux/include/asm-mips64/pgtable.h --- v2.4.6/linux/include/asm-mips64/pgtable.h Tue Nov 28 21:42:04 2000 +++ linux/include/asm-mips64/pgtable.h Wed Jul 4 11:50:39 2001 @@ -3,8 +3,8 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1994 - 2000 by Ralf Baechle at alii - * Copyright (C) 1999, 2000 Silicon Graphics, Inc. + * Copyright (C) 1994 - 2001 by Ralf Baechle at alii + * Copyright (C) 1999, 2000, 2001 Silicon Graphics, Inc. */ #ifndef _ASM_PGTABLE_H #define _ASM_PGTABLE_H @@ -177,15 +177,25 @@ #define _PAGE_CHG_MASK (PAGE_MASK | _PAGE_ACCESSED | _PAGE_MODIFIED | _CACHE_MASK) -#define PAGE_NONE __pgprot(_PAGE_PRESENT | _CACHE_CACHABLE_COW) +#ifdef CONFIG_MIPS_UNCACHED +#define PAGE_CACHABLE_DEFAULT _CACHE_UNCACHED +#else /* ! UNCACHED */ +#ifdef CONFIG_SGI_IP22 +#define PAGE_CACHABLE_DEFAULT _CACHE_CACHABLE_NONCOHERENT +#else /* ! IP22 */ +#define PAGE_CACHABLE_DEFAULT _CACHE_CACHABLE_COW +#endif /* IP22 */ +#endif /* UNCACHED */ + +#define PAGE_NONE __pgprot(_PAGE_PRESENT | PAGE_CACHABLE_DEFAULT) #define PAGE_SHARED __pgprot(_PAGE_PRESENT | _PAGE_READ | _PAGE_WRITE | \ - _CACHE_CACHABLE_COW) + PAGE_CACHABLE_DEFAULT) #define PAGE_COPY __pgprot(_PAGE_PRESENT | _PAGE_READ | \ - _CACHE_CACHABLE_COW) + PAGE_CACHABLE_DEFAULT) #define PAGE_READONLY __pgprot(_PAGE_PRESENT | _PAGE_READ | \ - _CACHE_CACHABLE_COW) + PAGE_CACHABLE_DEFAULT) #define PAGE_KERNEL __pgprot(_PAGE_PRESENT | __READABLE | __WRITEABLE | \ - _CACHE_CACHABLE_COW) + PAGE_CACHABLE_DEFAULT) #define PAGE_USERIO __pgprot(_PAGE_PRESENT | _PAGE_READ | _PAGE_WRITE | \ _CACHE_UNCACHED) #define PAGE_KERNEL_UNCACHED __pgprot(_PAGE_PRESENT | __READABLE | __WRITEABLE | \ @@ -224,22 +234,13 @@ printk("%s:%d: bad pgd %016lx.\n", __FILE__, __LINE__, pgd_val(e)) /* - * BAD_PAGETABLE is used when we need a bogus page-table, while - * BAD_PAGE is used for a bogus page. - * * ZERO_PAGE is a global shared page that is always zero: used * for zero-mapped memory areas etc.. */ -extern pte_t __bad_page(void); -extern pte_t *__bad_pagetable(void); -extern pmd_t *__bad_pmd_table(void); extern unsigned long empty_zero_page; extern unsigned long zero_page_mask; -#define BAD_PAGETABLE __bad_pagetable() -#define BAD_PMDTABLE __bad_pmd_table() -#define BAD_PAGE __bad_page() #define ZERO_PAGE(vaddr) \ (virt_to_page(empty_zero_page + (((unsigned long)(vaddr)) & zero_page_mask))) @@ -297,7 +298,8 @@ return pte_val(pte) & _PAGE_PRESENT; } -/* Certain architectures need to do special things when pte's +/* + * Certain architectures need to do special things when pte's * within a page table are directly modified. Thus, the following * hook is made available. */ @@ -312,6 +314,13 @@ } /* + * (pmds are folded into pgds so this doesnt get actually called, + * but the define is needed for a generic inline function.) + */ +#define set_pmd(pmdptr, pmdval) (*(pmdptr) = pmdval) +#define set_pgd(pgdptr, pgdval) (*(pgdptr) = pgdval) + +/* * Empty pmd entries point to the invalid_pte_table. */ extern inline int pmd_none(pmd_t pmd) @@ -321,7 +330,12 @@ extern inline int pmd_bad(pmd_t pmd) { - return pmd_val(pmd) == (unsigned long) empty_bad_page_table; + return pmd_val(pmd) &~ PAGE_MASK; +} + +extern inline int pmd_present(pmd_t pmd) +{ + return pmd_val(pmd) != (unsigned long) invalid_pte_table; } extern inline void pmd_clear(pmd_t *pmdp) @@ -339,7 +353,12 @@ extern inline int pgd_bad(pgd_t pgd) { - return pgd_val(pgd) == (unsigned long) empty_bad_pmd_table; + return pgd_val(pgd) &~ PAGE_MASK; +} + +extern inline int pgd_present(pgd_t pgd) +{ + return pgd_val(pgd) != (unsigned long) invalid_pmd_table; } extern inline void pgd_clear(pgd_t *pgdp) @@ -350,7 +369,6 @@ /* * Permanent address of a page. On MIPS64 we never have highmem, so this * is simple. - * called on a highmem page. */ #define page_address(page) ((page)->virtual) #ifndef CONFIG_DISCONTIGMEM @@ -761,7 +779,7 @@ __asm__ __volatile__( ".set noreorder\n\t" - "mfc0 %0, $4\n\t" + "dmfc0 %0, $4\n\t" ".set reorder" : "=r" (val)); @@ -772,7 +790,7 @@ { __asm__ __volatile__( ".set noreorder\n\t" - "mtc0 %0, $4\n\t" + "dmtc0 %0, $4\n\t" ".set reorder" : : "r" (val)); } diff -u --recursive --new-file v2.4.6/linux/include/asm-mips64/processor.h linux/include/asm-mips64/processor.h --- v2.4.6/linux/include/asm-mips64/processor.h Sat Dec 30 09:35:40 2000 +++ linux/include/asm-mips64/processor.h Wed Jul 4 11:50:39 2001 @@ -26,7 +26,7 @@ ({ \ void *_a; \ \ - __asm__ ("jal\t1f, 1f\n\t" \ + __asm__ ("jal\t1f, %0\n\t" \ "1:" \ : "=r" (_a)); \ \ diff -u --recursive --new-file v2.4.6/linux/include/asm-mips64/rrm.h linux/include/asm-mips64/rrm.h --- v2.4.6/linux/include/asm-mips64/rrm.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-mips64/rrm.h Wed Jul 4 11:50:39 2001 @@ -0,0 +1,88 @@ +/* + * SGI Rendering Resource Manager API (?). + * + * written by Miguel de Icaza (miguel@nuclecu.unam.mx) + * + * Ok, even if SGI choosed to do mmap trough ioctls, their + * kernel support for virtualizing the graphics card is nice. + * + * We should be able to make graphic applications on Linux + * fly. + * + * This header file should be included from GNU libc as well. + */ + + +/* Why like this you say? Well, gdb can print enums */ +#define RRM_BASE 1000 +#define RRM_CMD_LIMIT (RRM_BASE + 100) + +enum { + RRM_OPENRN = RRM_BASE, /* open rendering node */ + RRM_CLOSERN, + RRM_BINDPROCTORN, /* set current rendering region for node */ + RRM_BINDRNTOCLIP, + RRM_UNBINDRNFROMCLIP, + RRM_SWAPBUF, + RRM_SETSWAPINTERVAL, + RRM_WAITFORRETRACE, + RRM_SETDISPLAYMODE, + RRM_MESSAGE, + RRM_INVALIDATERN, + RRM_VALIDATECLIP, + RRM_VALIDATESWAPBUF, + RRM_SWAPGROUP, + RRM_SWAPUNGROUP, + RRM_VALIDATEMESSAGE, + RRM_GETDISPLAYMODES, + RRM_LOADDISPLAYMODE, + RRM_CUSHIONBUFFER, + RRM_SWAPREADY, + RRM_MGR_SWAPBUF, + RRM_SETVSYNC, + RRM_GETVSYNC, + RRM_WAITVSYNC, + RRM_BINDRNTOREADANDCLIP, + RRM_MAPCLIPTOSWPBUFID +}; + +/* Parameters for the above ioctls + * + * All of the ioctls take as their first argument the rendering node id. + * + */ + +/* + * RRM_OPENRN: + * + * This is called by the IRIX X server with: + * rnid = 0xffffffff rmask = 0 + * + * Returns a number like this: 0x10001. + * If you run the X server over and over, you get a value + * that is of the form (n * 0x10000) + 1. + * + * The return value seems to be the RNID. + */ +struct RRM_OpenRN { + int rnid; + unsigned int rmask; +}; + +struct RRM_CloseRN { + int rnid; +}; + +/* + * RRM_BINDPROCTORN: + * + * Return value when the X server calls it: 0 + */ +struct RRM_BindProcToRN { + int rnid; +}; + +#ifdef __KERNEL__ +int rrm_command (unsigned int cmd, void *arg); +int rrm_close (struct inode *inode, struct file *file); +#endif diff -u --recursive --new-file v2.4.6/linux/include/asm-mips64/semaphore-helper.h linux/include/asm-mips64/semaphore-helper.h --- v2.4.6/linux/include/asm-mips64/semaphore-helper.h Tue Nov 28 21:42:04 2000 +++ linux/include/asm-mips64/semaphore-helper.h Wed Jul 4 11:50:39 2001 @@ -3,8 +3,8 @@ * * (C) Copyright 1996 Linus Torvalds * (C) Copyright 1999 Andrea Arcangeli - * (C) Copyright 1999 Ralf Baechle - * (C) Copyright 1999 Silicon Graphics, Inc. + * (C) Copyright 1999, 2001 Ralf Baechle + * (C) Copyright 1999, 2001 Silicon Graphics, Inc. */ #ifndef _ASM_SEMAPHORE_HELPER_H #define _ASM_SEMAPHORE_HELPER_H @@ -68,63 +68,56 @@ #ifdef __MIPSEB__ - __asm__ __volatile__(" - .set push - .set noat -0: lld %1, %2 - li %0, 0 - sll $1, %1, 0 - blez $1, 1f - daddiu %1, %1, -1 - li %0, 1 - b 2f -1: - beqz %3, 2f - li %0, %4 - dli $1, 0x0000000100000000 - daddu %1, %1, $1 -2: - scd %1, %2 - beqz %1, 0b - .set pop" + __asm__ __volatile__( + ".set\tpush\t\t\t# waking_non_zero_interruptible\n\t" + ".set\tnoat\n\t" + "0:\tlld\t%1, %2\n\t" + "li\t%0, 0\n\t" + "sll\t$1, %1, 0\n\t" + "blez\t$1, 1f\n\t" + "daddiu\t%1, %1, -1\n\t" + "li\t%0, 1\n\t" + "b\t2f\n\t" + "1:\tbeqz\t%3, 2f\n\t" + "li\t%0, %4\n\t" + "dli\t$1, 0x0000000100000000\n\t" + "daddu\t%1, %1, $1\n\t" + "2:\tscd\t%1, %2\n\t" + "beqz\t%1, 0b\n\t" + ".set\tpop" : "=&r" (ret), "=&r" (tmp), "=m" (*sem) : "r" (signal_pending(tsk)), "i" (-EINTR)); #elif defined(__MIPSEL__) - __asm__ __volatile__(" - .set push - .set noat -0: - lld %1, %2 - li %0, 0 - blez %1, 1f - dli $1, 0x0000000100000000 - dsubu %1, %1, $1 - li %0, 1 - b 2f -1: - beqz %3, 2f - li %0, %4 + __asm__ __volatile__( + ".set\tpush\t\t\t# waking_non_zero_interruptible\n\t" + ".set\t noat\n" + "0:\tlld\t%1, %2\n\t" + "li\t%0, 0\n\t" + "blez\t%1, 1f\n\t" + "dli\t$1, 0x0000000100000000\n\t" + "dsubu\t%1, %1, $1\n\t" + "li\t%0, 1\n\t" + "b\t2f\n" + "1:\tbeqz\t%3, 2f\n\t" + "li\t%0, %4\n\t" /* * It would be nice to assume that sem->count * is != -1, but we will guard against that case */ - daddiu $1, %1, 1 - dsll32 $1, $1, 0 - dsrl32 $1, $1, 0 - dsrl32 %1, %1, 0 - dsll32 %1, %1, 0 - or %1, %1, $1 -2: - scd %1, %2 - beqz %1, 0b - .set pop" + "daddiu\t$1, %1, 1\n\t" + "dsll32\t$1, $1, 0\n\t" + "dsrl32\t$1, $1, 0\n\t" + "dsrl32\t%1, %1, 0\n\t" + "dsll32\t%1, %1, 0\n\t" + "or\t%1, %1, $1\n" + "2:\tscd\t%1, %2\n\t" + "beqz\t %1, 0b\n\t" + ".set\tpop" : "=&r" (ret), "=&r" (tmp), "=m" (*sem) : "r" (signal_pending(tsk)), "i" (-EINTR)); -#else -#error "MIPS but neither __MIPSEL__ nor __MIPSEB__?" #endif return ret; diff -u --recursive --new-file v2.4.6/linux/include/asm-mips64/semaphore.h linux/include/asm-mips64/semaphore.h --- v2.4.6/linux/include/asm-mips64/semaphore.h Tue Apr 17 17:19:31 2001 +++ linux/include/asm-mips64/semaphore.h Wed Jul 4 11:50:39 2001 @@ -3,8 +3,8 @@ * for more details. * * Copyright (C) 1996 Linus Torvalds - * Copyright (C) 1998, 1999, 2000 Ralf Baechle - * Copyright (C) 1999, 2000 Silicon Graphics, Inc. + * Copyright (C) 1998, 1999, 2000, 2001 Ralf Baechle + * Copyright (C) 1999, 2000, 2001 Silicon Graphics, Inc. */ #ifndef _ASM_SEMAPHORE_H #define _ASM_SEMAPHORE_H @@ -130,29 +130,25 @@ CHECK_MAGIC(sem->__magic); #endif - __asm__ __volatile__(" - .set mips3 - - 0: lld %1, %4 - dli %3, 0x0000000100000000 - dsubu %1, %3 - li %0, 0 - bgez %1, 2f - sll %2, %1, 0 - blez %2, 1f - daddiu %1, %1, -1 - b 2f - 1: - daddu %1, %1, %3 - li %0, 1 - 2: - scd %1, %4 - beqz %1, 0b - - .set mips0" - : "=&r"(ret), "=&r"(tmp), "=&r"(tmp2), "=&r"(sub) - : "m"(*sem) - : "memory"); + __asm__ __volatile__( + ".set\tmips3\t\t\t# down_trylock\n" + "0:\tlld\t%1, %4\n\t" + "\tdli\t%3, 0x0000000100000000\n\t" + "\tdsubu\t%1, %3\n\t" + "\tli\t%0, 0\n\t" + "\tbgez\t%1, 2f\n\t" + "\tsll\t%2, %1, 0\n\t" + "\tblez\t%2, 1f\n\t" + "\tdaddiu\t%1, %1, -1\n\t" + "\tb\t2f\n" + "1:\tdaddu\t%1, %1, %3\n\t" + "\tli\t%0, 1\n" + "2:\tscd\t%1, %4\n\t" + "\tbeqz\t%1, 0b\n\t" + "\t.set\tmips0" + : "=&r"(ret), "=&r"(tmp), "=&r"(tmp2), "=&r"(sub) + : "m"(*sem) + : "memory"); return ret; } diff -u --recursive --new-file v2.4.6/linux/include/asm-mips64/sgi/sgint23.h linux/include/asm-mips64/sgi/sgint23.h --- v2.4.6/linux/include/asm-mips64/sgi/sgint23.h Tue Nov 28 21:42:04 2000 +++ linux/include/asm-mips64/sgi/sgint23.h Wed Jul 4 11:50:39 2001 @@ -170,7 +170,7 @@ #endif #define INT2_TCLEAR_T0CLR 0x1 /* Clear timer0 IRQ */ #define INT2_TCLEAR_T1CLR 0x2 /* Clear timer1 IRQ */ -/* I am guesing there are only two unused registers here +/* I am guessing there are only two unused registers here * but I could be wrong... - andrewb */ /* u32 _unused[3]; */ diff -u --recursive --new-file v2.4.6/linux/include/asm-mips64/sgialib.h linux/include/asm-mips64/sgialib.h --- v2.4.6/linux/include/asm-mips64/sgialib.h Sat May 13 08:31:25 2000 +++ linux/include/asm-mips64/sgialib.h Wed Jul 4 11:50:39 2001 @@ -1,5 +1,4 @@ -/* $Id: sgialib.h,v 1.3 1999/12/04 03:59:12 ralf Exp $ - * +/* * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. @@ -7,6 +6,7 @@ * SGI ARCS firmware interface library for the Linux kernel. * * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) + * Copyright (C) 2001 Ralf Baechle (ralf@gnu.org) */ #ifndef _ASM_SGIALIB_H #define _ASM_SGIALIB_H @@ -90,9 +90,9 @@ */ extern void prom_identify_arch(void); -/* Environemt variable routines. */ +/* Environment variable routines. */ extern PCHAR ArcGetEnvironmentVariable(PCHAR name); -extern LONG SetEnvironmentVariable(PCHAR name, PCHAR value); +extern LONG ArcSetEnvironmentVariable(PCHAR name, PCHAR value); /* ARCS command line acquisition and parsing. */ extern char *prom_getcmdline(void); @@ -120,11 +120,11 @@ extern long prom_exec(char *name, long argc, char **argv, char **envp); /* Misc. routines. */ -extern void prom_halt(VOID) __attribute__((noreturn)); -extern void prom_powerdown(VOID) __attribute__((noreturn)); -extern void prom_restart(VOID) __attribute__((noreturn)); +extern VOID prom_halt(VOID) __attribute__((noreturn)); +extern VOID prom_powerdown(VOID) __attribute__((noreturn)); +extern VOID prom_restart(VOID) __attribute__((noreturn)); extern VOID ArcReboot(VOID) __attribute__((noreturn)); -extern VOID ArcEnterInteractiveMode(void) __attribute__((noreturn)); +extern VOID ArcEnterInteractiveMode(VOID) __attribute__((noreturn)); extern long prom_cfgsave(VOID); extern struct linux_sysid *prom_getsysid(VOID); extern VOID ArcFlushAllCaches(VOID); diff -u --recursive --new-file v2.4.6/linux/include/asm-mips64/sgiarcs.h linux/include/asm-mips64/sgiarcs.h --- v2.4.6/linux/include/asm-mips64/sgiarcs.h Sat May 13 08:31:25 2000 +++ linux/include/asm-mips64/sgiarcs.h Wed Jul 4 11:50:39 2001 @@ -143,7 +143,7 @@ /* ARCS virtual dirents. */ struct linux_vdirent { - unsigned long namelen; + ULONG namelen; unsigned char attr; char fname[32]; /* XXX imperical, should be a define */ }; @@ -177,38 +177,38 @@ struct linux_bigint begin; struct linux_bigint end; struct linux_bigint cur; - enum linux_devtypes dtype; + enum linux_devtypes dtype; unsigned long namelen; unsigned char attr; char name[32]; /* XXX imperical, should be define */ }; -/* This describes the vector containing fuction pointers to the ARC +/* This describes the vector containing function pointers to the ARC firmware functions. */ struct linux_romvec { - LONG load; /* Load an executable image. */ - LONG invoke; /* Invoke a standalong image. */ - LONG exec; /* Load and begin execution of a + LONG load; /* Load an executable image. */ + LONG invoke; /* Invoke a standalong image. */ + LONG exec; /* Load and begin execution of a standalone image. */ - LONG halt; /* Halt the machine. */ - LONG pdown; /* Power down the machine. */ - LONG restart; /* XXX soft reset??? */ - LONG reboot; /* Reboot the machine. */ - LONG imode; /* Enter PROM interactive mode. */ - LONG _unused1; /* Was ReturnFromMain(). */ + LONG halt; /* Halt the machine. */ + LONG pdown; /* Power down the machine. */ + LONG restart; /* XXX soft reset??? */ + LONG reboot; /* Reboot the machine. */ + LONG imode; /* Enter PROM interactive mode. */ + LONG _unused1; /* Was ReturnFromMain(). */ /* PROM device tree interface. */ - LONG next_component; - LONG child_component; - LONG parent_component; - LONG component_data; - LONG child_add; - LONG comp_del; - LONG component_by_path; + LONG next_component; + LONG child_component; + LONG parent_component; + LONG component_data; + LONG child_add; + LONG comp_del; + LONG component_by_path; /* Misc. stuff. */ - LONG cfg_save; - LONG get_sysid; + LONG cfg_save; + LONG get_sysid; /* Probing for memory. */ LONG get_mdesc; diff -u --recursive --new-file v2.4.6/linux/include/asm-mips64/siginfo.h linux/include/asm-mips64/siginfo.h --- v2.4.6/linux/include/asm-mips64/siginfo.h Wed May 24 18:38:26 2000 +++ linux/include/asm-mips64/siginfo.h Wed Jul 4 11:50:39 2001 @@ -1,10 +1,10 @@ -/* $Id: siginfo.h,v 1.2 2000/01/27 01:05:37 ralf Exp $ - * +/* * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1998, 1999 by Ralf Baechle + * Copyright (C) 1998, 1999, 2001 Ralf Baechle + * Copyright (C) 2000, 2001 Silicon Graphics, Inc. */ #ifndef _ASM_SIGINFO_H #define _ASM_SIGINFO_H @@ -62,7 +62,7 @@ /* SIGPOLL, SIGXFSZ (To do ...) */ struct { - int _band; /* POLL_IN, POLL_OUT, POLL_MSG */ + long _band; /* POLL_IN, POLL_OUT, POLL_MSG */ int _fd; } _sigpoll; diff -u --recursive --new-file v2.4.6/linux/include/asm-mips64/smp.h linux/include/asm-mips64/smp.h --- v2.4.6/linux/include/asm-mips64/smp.h Fri Mar 2 11:30:15 2001 +++ linux/include/asm-mips64/smp.h Wed Jul 4 11:50:39 2001 @@ -1,3 +1,12 @@ +/* + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file "COPYING" in the main directory of this + * archive for more details. + * + * Copyright (C) 2000 - 2001 by Kanoj Sarcar (kanoj@sgi.com) + * Copyright (C) 2000 - 2001 by Silicon Graphics, Inc. + */ + #ifndef __ASM_SMP_H #define __ASM_SMP_H @@ -38,12 +47,42 @@ extern int __cpu_logical_map[NR_CPUS]; #define cpu_logical_map(cpu) __cpu_logical_map[cpu] -/* Good enough for toy^Wupto 64 CPU Origins. */ -extern unsigned long cpu_present_mask; -#define cpu_online_map cpu_present_mask - #endif #define NO_PROC_ID (-1) -#endif __ASM_SMP_H +#if (NR_CPUS <= _MIPS_SZLONG) + +typedef unsigned long cpumask_t; + +#define CPUMASK_CLRALL(p) (p) = 0 +#define CPUMASK_SETB(p, bit) (p) |= 1 << (bit) +#define CPUMASK_CLRB(p, bit) (p) &= ~(1ULL << (bit)) +#define CPUMASK_TSTB(p, bit) ((p) & (1ULL << (bit))) + +#elif (NR_CPUS <= 128) + +/* + * The foll should work till 128 cpus. + */ +#define CPUMASK_SIZE (NR_CPUS/_MIPS_SZLONG) +#define CPUMASK_INDEX(bit) ((bit) >> 6) +#define CPUMASK_SHFT(bit) ((bit) & 0x3f) + +typedef struct { + unsigned long _bits[CPUMASK_SIZE]; +} cpumask_t; + +#define CPUMASK_CLRALL(p) (p)._bits[0] = 0, (p)._bits[1] = 0 +#define CPUMASK_SETB(p, bit) (p)._bits[CPUMASK_INDEX(bit)] |= \ + (1ULL << CPUMASK_SHFT(bit)) +#define CPUMASK_CLRB(p, bit) (p)._bits[CPUMASK_INDEX(bit)] &= \ + ~(1ULL << CPUMASK_SHFT(bit)) +#define CPUMASK_TSTB(p, bit) ((p)._bits[CPUMASK_INDEX(bit)] & \ + (1ULL << CPUMASK_SHFT(bit))) + +#else +#error cpumask macros only defined for 128p kernels +#endif + +#endif /* __ASM_SMP_H */ diff -u --recursive --new-file v2.4.6/linux/include/asm-mips64/sn/types.h linux/include/asm-mips64/sn/types.h --- v2.4.6/linux/include/asm-mips64/sn/types.h Sun Jul 9 22:18:15 2000 +++ linux/include/asm-mips64/sn/types.h Wed Jul 4 11:50:39 2001 @@ -13,7 +13,6 @@ #include <linux/types.h> typedef unsigned long cpuid_t; -typedef unsigned long cpumask_t; typedef unsigned long cnodemask_t; typedef signed short nasid_t; /* node id in numa-as-id space */ typedef signed short cnodeid_t; /* node id in compact-id space */ diff -u --recursive --new-file v2.4.6/linux/include/asm-mips64/socket.h linux/include/asm-mips64/socket.h --- v2.4.6/linux/include/asm-mips64/socket.h Tue Jul 3 17:08:21 2001 +++ linux/include/asm-mips64/socket.h Wed Jul 4 11:50:39 2001 @@ -3,8 +3,8 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1997, 1999, 2000 Ralf Baechle - * Copyright (C) 2000 Silicon Graphics, Inc. + * Copyright (C) 1997, 1999, 2000, 2001 Ralf Baechle + * Copyright (C) 2000, 2001 Silicon Graphics, Inc. */ #ifndef _ASM_SOCKET_H #define _ASM_SOCKET_H @@ -41,7 +41,7 @@ #define SO_RCVLOWAT 0x1004 /* receive low-water mark */ #define SO_SNDTIMEO 0x1005 /* send timeout */ #define SO_RCVTIMEO 0x1006 /* receive timeout */ -#define SO_ACCEPTCONN 0x1007 +#define SO_ACCEPTCONN 0x1009 /* linux-specific, might as well be the same as on i386 */ #define SO_NO_CHECK 11 diff -u --recursive --new-file v2.4.6/linux/include/asm-mips64/system.h linux/include/asm-mips64/system.h --- v2.4.6/linux/include/asm-mips64/system.h Tue Nov 28 21:42:04 2000 +++ linux/include/asm-mips64/system.h Wed Jul 4 11:50:39 2001 @@ -33,7 +33,7 @@ } /* - * For cli() we have to insert nops to make shure that the new value + * For cli() we have to insert nops to make sure that the new value * has actually arrived in the status register before the end of this * macro. * R4000/R4400 need three nops, the R4600 two nops and the R10000 needs diff -u --recursive --new-file v2.4.6/linux/include/asm-mips64/termios.h linux/include/asm-mips64/termios.h --- v2.4.6/linux/include/asm-mips64/termios.h Tue Jul 3 17:08:21 2001 +++ linux/include/asm-mips64/termios.h Wed Jul 4 11:50:39 2001 @@ -1,10 +1,10 @@ -/* $Id: termios.h,v 1.2 2000/01/27 23:45:30 ralf Exp $ - * +/* * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1995, 1996 by Ralf Baechle + * Copyright (C) 1995, 1996, 2000, 2001 by Ralf Baechle + * Copyright (C) 2000, 2001 Silicon Graphics, Inc. */ #ifndef _ASM_TERMIOS_H #define _ASM_TERMIOS_H diff -u --recursive --new-file v2.4.6/linux/include/asm-mips64/unaligned.h linux/include/asm-mips64/unaligned.h --- v2.4.6/linux/include/asm-mips64/unaligned.h Tue Nov 28 21:42:04 2000 +++ linux/include/asm-mips64/unaligned.h Wed Jul 4 11:50:39 2001 @@ -3,8 +3,8 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1996, 1999, 2000 by Ralf Baechle - * Copyright (C) 1999, 2000 Silicon Graphics, Inc. + * Copyright (C) 1996, 1999, 2000, 2001 by Ralf Baechle + * Copyright (C) 1999, 2000, 2001 Silicon Graphics, Inc. */ #ifndef _ASM_UNALIGNED_H #define _ASM_UNALIGNED_H @@ -84,8 +84,15 @@ : "r" (__val)); } -/* - * The main single-value unaligned transfer routines. +/* + * get_unaligned - get value from possibly mis-aligned location + * @ptr: pointer to value + * + * This macro should be used for accessing values larger in size than + * single bytes at locations that are expected to be improperly aligned, + * e.g. retrieving a u16 value from a location not u16-aligned. + * + * Note that unaligned accesses can be very expensive on some architectures. */ #define get_unaligned(ptr) \ ({ \ @@ -102,7 +109,7 @@ __val = __ldl_u((const unsigned int *)(ptr)); \ break; \ case 8: \ - __val = __ldq_u((const unsigned long long *)(ptr)); \ + __val = __ldq_u((const unsigned long *)(ptr)); \ break; \ default: \ __get_unaligned_bad_length(); \ @@ -112,6 +119,17 @@ __val; \ }) +/* + * put_unaligned - put value to a possibly mis-aligned location + * @val: value to place + * @ptr: pointer to location + * + * This macro should be used for placing values larger in size than + * single bytes at locations that are expected to be improperly aligned, + * e.g. writing a u16 value to a location not u16-aligned. + * + * Note that unaligned accesses can be very expensive on some architectures. + */ #define put_unaligned(val,ptr) \ do { \ switch (sizeof(*(ptr))) { \ diff -u --recursive --new-file v2.4.6/linux/include/asm-ppc/atomic.h linux/include/asm-ppc/atomic.h --- v2.4.6/linux/include/asm-ppc/atomic.h Mon May 21 15:02:06 2001 +++ linux/include/asm-ppc/atomic.h Mon Jul 9 21:27:13 2001 @@ -111,4 +111,9 @@ return t; } +#define smp_mb__before_atomic_dec() smp_mb() +#define smp_mb__after_atomic_dec() smp_mb() +#define smp_mb__before_atomic_inc() smp_mb() +#define smp_mb__after_atomic_inc() smp_mb() + #endif /* _ASM_PPC_ATOMIC_H_ */ diff -u --recursive --new-file v2.4.6/linux/include/asm-ppc/hardirq.h linux/include/asm-ppc/hardirq.h --- v2.4.6/linux/include/asm-ppc/hardirq.h Tue Jul 3 17:08:21 2001 +++ linux/include/asm-ppc/hardirq.h Wed Jul 18 07:14:01 2001 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.hardirq.h 1.10 06/09/01 22:16:38 paulus + * BK Id: SCCS/s.hardirq.h 1.12 07/10/01 11:26:58 trini */ #ifdef __KERNEL__ #ifndef __ASM_HARDIRQ_H @@ -19,6 +19,7 @@ unsigned int __local_irq_count; unsigned int __local_bh_count; unsigned int __syscall_count; + struct task_struct * __ksoftirqd_task; unsigned int __last_jiffy_stamp; } ____cacheline_aligned irq_cpustat_t; diff -u --recursive --new-file v2.4.6/linux/include/asm-ppc/immap_8260.h linux/include/asm-ppc/immap_8260.h --- v2.4.6/linux/include/asm-ppc/immap_8260.h Mon May 21 15:02:06 2001 +++ linux/include/asm-ppc/immap_8260.h Wed Jul 18 18:01:03 2001 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.immap_8260.h 1.5 05/17/01 18:14:24 cort + * BK Id: SCCS/s.immap_8260.h 1.8 07/18/01 15:46:50 trini */ /* @@ -431,10 +431,7 @@ char res11[4096]; } immap_t; -/* The 8260 relies heavily on the IMMR, so we keep it around as a - * kernel global symbol now. Should have done this for the 8xx...... - */ -immap_t *immr; +extern immap_t *immr; #endif /* __IMMAP_82XX__ */ #endif /* __KERNEL__ */ diff -u --recursive --new-file v2.4.6/linux/include/asm-ppc/softirq.h linux/include/asm-ppc/softirq.h --- v2.4.6/linux/include/asm-ppc/softirq.h Tue Jul 3 17:08:21 2001 +++ linux/include/asm-ppc/softirq.h Wed Jul 18 07:14:01 2001 @@ -1,5 +1,5 @@ /* - * BK Id: SCCS/s.softirq.h 1.10 06/09/01 22:16:38 paulus + * BK Id: SCCS/s.softirq.h 1.13 07/12/01 20:02:34 paulus */ #ifdef __KERNEL__ #ifndef __ASM_SOFTIRQ_H @@ -25,12 +25,10 @@ if (!--local_bh_count(smp_processor_id()) \ && softirq_pending(smp_processor_id())) { \ do_softirq(); \ - __sti(); \ } \ } while (0) #define __cpu_raise_softirq(cpu, nr) set_bit((nr), &softirq_pending(cpu)); -#define raise_softirq(nr) __cpu_raise_softirq(smp_processor_id(), (nr)) #define in_softirq() (local_bh_count(smp_processor_id()) != 0) diff -u --recursive --new-file v2.4.6/linux/include/asm-s390/atomic.h linux/include/asm-s390/atomic.h --- v2.4.6/linux/include/asm-s390/atomic.h Wed Apr 11 19:02:28 2001 +++ linux/include/asm-s390/atomic.h Mon Jul 9 21:27:45 2001 @@ -170,5 +170,10 @@ atomic_set(where,(to));\ } +#define smp_mb__before_atomic_dec() smp_mb() +#define smp_mb__after_atomic_dec() smp_mb() +#define smp_mb__before_atomic_inc() smp_mb() +#define smp_mb__after_atomic_inc() smp_mb() + #endif /* __ARCH_S390_ATOMIC __ */ diff -u --recursive --new-file v2.4.6/linux/include/asm-s390/bitops.h linux/include/asm-s390/bitops.h --- v2.4.6/linux/include/asm-s390/bitops.h Wed Apr 11 19:02:28 2001 +++ linux/include/asm-s390/bitops.h Wed Jul 4 11:50:39 2001 @@ -34,7 +34,14 @@ * align the address to 4 byte boundary. It seems to work * without the alignment. */ +#ifdef __KERNEL__ #define ALIGN_CS 0 +#else +#define ALIGN_CS 1 +#ifndef CONFIG_SMP +#error "bitops won't work without CONFIG_SMP" +#endif +#endif /* bitmap tables from arch/S390/kernel/bitmap.S */ extern const char _oi_bitmap[]; @@ -487,6 +494,7 @@ : "cc", "memory", "1", "2" ); return oldbit; } +#define __test_and_set_bit(X,Y) test_and_set_bit_simple(X,Y) /* * fast, non-SMP test_and_clear_bit routine @@ -513,6 +521,7 @@ : "cc", "memory", "1", "2" ); return oldbit; } +#define __test_and_clear_bit(X,Y) test_and_clear_bit_simple(X,Y) /* * fast, non-SMP test_and_change_bit routine @@ -539,6 +548,7 @@ : "cc", "memory", "1", "2" ); return oldbit; } +#define __test_and_change_bit(X,Y) test_and_change_bit_simple(X,Y) #ifdef CONFIG_SMP #define set_bit set_bit_cs diff -u --recursive --new-file v2.4.6/linux/include/asm-s390/ebcdic.h linux/include/asm-s390/ebcdic.h --- v2.4.6/linux/include/asm-s390/ebcdic.h Wed Apr 11 19:02:28 2001 +++ linux/include/asm-s390/ebcdic.h Wed Jul 4 11:50:39 2001 @@ -29,8 +29,8 @@ __asm__ __volatile__( " bras 1,1f\n" " tr 0(1,%0),0(%2)\n" - "0: la %0,256(%0)\n" - " tr 0(256,%0),0(%2)\n" + "0: tr 0(256,%0),0(%2)\n" + " la %0,256(%0)\n" "1: ahi %1,-256\n" " jp 0b\n" " ex %1,0(1)" diff -u --recursive --new-file v2.4.6/linux/include/asm-s390/pci.h linux/include/asm-s390/pci.h --- v2.4.6/linux/include/asm-s390/pci.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-s390/pci.h Wed Jul 4 11:50:39 2001 @@ -0,0 +1,9 @@ +#ifndef __ASM_S390_PCI_H +#define __ASM_S390_PCI_H + +/* S/390 systems don't have a PCI bus. This file is just here because some stupid .c code + * includes it even if CONFIG_PCI is not set. + */ + +#endif /* __ASM_S390_PCI_H */ + diff -u --recursive --new-file v2.4.6/linux/include/asm-s390x/atomic.h linux/include/asm-s390x/atomic.h --- v2.4.6/linux/include/asm-s390x/atomic.h Wed Apr 11 19:02:29 2001 +++ linux/include/asm-s390x/atomic.h Mon Jul 9 21:27:45 2001 @@ -170,5 +170,9 @@ atomic_set(where,(to));\ } -#endif /* __ARCH_S390_ATOMIC __ */ +#define smp_mb__before_atomic_dec() smp_mb() +#define smp_mb__after_atomic_dec() smp_mb() +#define smp_mb__before_atomic_inc() smp_mb() +#define smp_mb__after_atomic_inc() smp_mb() +#endif /* __ARCH_S390_ATOMIC __ */ diff -u --recursive --new-file v2.4.6/linux/include/asm-s390x/bitops.h linux/include/asm-s390x/bitops.h --- v2.4.6/linux/include/asm-s390x/bitops.h Tue Feb 13 14:13:44 2001 +++ linux/include/asm-s390x/bitops.h Wed Jul 4 11:50:39 2001 @@ -38,7 +38,14 @@ * align the address to 4 byte boundary. It seems to work * without the alignment. */ +#ifdef __KERNEL__ #define ALIGN_CS 0 +#else +#define ALIGN_CS 1 +#ifndef CONFIG_SMP +#error "bitops won't work without CONFIG_SMP" +#endif +#endif /* bitmap tables from arch/S390/kernel/bitmap.S */ extern const char _oi_bitmap[]; @@ -54,7 +61,7 @@ unsigned long bits, mask; __asm__ __volatile__( #if ALIGN_CS == 1 - " lghi %2,3\n" /* CS must be aligned on 4 byte b. */ + " lghi %2,7\n" /* CS must be aligned on 4 byte b. */ " ngr %2,%1\n" /* isolate last 2 bits of address */ " xgr %1,%2\n" /* make addr % 4 == 0 */ " sllg %2,%2,3\n" @@ -84,7 +91,7 @@ unsigned long bits, mask; __asm__ __volatile__( #if ALIGN_CS == 1 - " lghi %2,3\n" /* CS must be aligned on 4 byte b. */ + " lghi %2,7\n" /* CS must be aligned on 4 byte b. */ " ngr %2,%1\n" /* isolate last 2 bits of address */ " xgr %1,%2\n" /* make addr % 4 == 0 */ " sllg %2,%2,3\n" @@ -115,7 +122,7 @@ unsigned long bits, mask; __asm__ __volatile__( #if ALIGN_CS == 1 - " lghi %2,3\n" /* CS must be aligned on 4 byte b. */ + " lghi %2,7\n" /* CS must be aligned on 4 byte b. */ " ngr %2,%1\n" /* isolate last 2 bits of address */ " xgr %1,%2\n" /* make addr % 4 == 0 */ " sllg %2,%2,3\n" @@ -146,7 +153,7 @@ unsigned long bits, mask; __asm__ __volatile__( #if ALIGN_CS == 1 - " lghi %2,3\n" /* CS must be aligned on 4 byte b. */ + " lghi %2,7\n" /* CS must be aligned on 4 byte b. */ " ngr %2,%1\n" /* isolate last 2 bits of address */ " xgr %1,%2\n" /* make addr % 4 == 0 */ " sllg %2,%2,3\n" @@ -179,7 +186,7 @@ unsigned long bits, mask; __asm__ __volatile__( #if ALIGN_CS == 1 - " lghi %2,3\n" /* CS must be aligned on 4 byte b. */ + " lghi %2,7\n" /* CS must be aligned on 4 byte b. */ " ngr %2,%1\n" /* isolate last 2 bits of address */ " xgr %1,%2\n" /* make addr % 4 == 0 */ " sllg %2,%2,3\n" @@ -212,7 +219,7 @@ unsigned long bits, mask; __asm__ __volatile__( #if ALIGN_CS == 1 - " lghi %2,3\n" /* CS must be aligned on 4 byte b. */ + " lghi %2,7\n" /* CS must be aligned on 4 byte b. */ " ngr %2,%1\n" /* isolate last 2 bits of address */ " xgr %1,%2\n" /* make addr % 4 == 0 */ " sllg %2,%2,3\n" @@ -494,6 +501,7 @@ : "cc", "memory", "1", "2" ); return oldbit & 1; } +#define __test_and_set_bit(X,Y) test_and_set_bit_simple(X,Y) /* * fast, non-SMP test_and_clear_bit routine @@ -518,6 +526,7 @@ : "cc", "memory", "1", "2" ); return oldbit & 1; } +#define __test_and_clear_bit(X,Y) test_and_clear_bit_simple(X,Y) /* * fast, non-SMP test_and_change_bit routine @@ -542,6 +551,7 @@ : "cc", "memory", "1", "2" ); return oldbit & 1; } +#define __test_and_change_bit(X,Y) test_and_change_bit_simple(X,Y) #ifdef CONFIG_SMP #define set_bit set_bit_cs diff -u --recursive --new-file v2.4.6/linux/include/asm-s390x/byteorder.h linux/include/asm-s390x/byteorder.h --- v2.4.6/linux/include/asm-s390x/byteorder.h Tue Feb 13 14:13:44 2001 +++ linux/include/asm-s390x/byteorder.h Wed Jul 4 11:50:39 2001 @@ -36,9 +36,9 @@ static __inline__ void ___arch__swab64s(__u64 *x) { __asm__ __volatile__ ( - " lrvg %0,%1\n" - " stg %0,%1" - : : "m" (*x) : "memory"); + " lrvg 0,%0\n" + " stg 0,%0" + : "+m" (*x) : : "0"); } static __inline__ __const__ __u32 ___arch__swab32(__u32 x) @@ -64,9 +64,9 @@ static __inline__ void ___arch__swab32s(__u32 *x) { __asm__ __volatile__ ( - " lrv %0,%1\n" - " st %0,%1" - : : "m" (*x) : "memory"); + " lrv 0,%0\n" + " st 0,%0" + : "+m" (*x) : : "0" ); } static __inline__ __const__ __u16 ___arch__swab16(__u16 x) @@ -92,15 +92,18 @@ static __inline__ void ___arch__swab16s(__u16 *x) { __asm__ __volatile__ ( - " lrvh %0,%1\n" - " sth %0,%1" - : : "m" (*x) : "memory"); + " lrvh 0,%0\n" + " sth 0,%0" + : "+m" (*x) : : "0" ); } +#define __arch__swab64(x) ___arch__swab64(x) #define __arch__swab32(x) ___arch__swab32(x) #define __arch__swab16(x) ___arch__swab16(x) +#define __arch__swab64p(x) ___arch__swab64p(x) #define __arch__swab32p(x) ___arch__swab32p(x) #define __arch__swab16p(x) ___arch__swab16p(x) +#define __arch__swab64s(x) ___arch__swab64s(x) #define __arch__swab32s(x) ___arch__swab32s(x) #define __arch__swab16s(x) ___arch__swab16s(x) diff -u --recursive --new-file v2.4.6/linux/include/asm-s390x/ebcdic.h linux/include/asm-s390x/ebcdic.h --- v2.4.6/linux/include/asm-s390x/ebcdic.h Wed Apr 11 19:02:29 2001 +++ linux/include/asm-s390x/ebcdic.h Wed Jul 4 11:50:39 2001 @@ -29,8 +29,8 @@ __asm__ __volatile__( " bras 1,1f\n" " tr 0(1,%0),0(%2)\n" - "0: la %0,256(%0)\n" - " tr 0(256,%0),0(%2)\n" + "0: tr 0(256,%0),0(%2)\n" + " la %0,256(%0)\n" "1: ahi %1,-256\n" " jp 0b\n" " ex %1,0(1)" diff -u --recursive --new-file v2.4.6/linux/include/asm-s390x/irq.h linux/include/asm-s390x/irq.h --- v2.4.6/linux/include/asm-s390x/irq.h Wed Apr 11 19:02:29 2001 +++ linux/include/asm-s390x/irq.h Wed Jul 4 11:50:39 2001 @@ -889,9 +889,9 @@ spin_lock_irqsave(&(ioinfo[irq]->irq_lock), flags) #define s390irq_spin_unlock_irqrestore(irq,flags) \ spin_unlock_irqrestore(&(ioinfo[irq]->irq_lock), flags) -#endif /* __KERNEL__ */ #define touch_nmi_watchdog() do { } while(0) +#endif /* __KERNEL__ */ #endif diff -u --recursive --new-file v2.4.6/linux/include/asm-s390x/string.h linux/include/asm-s390x/string.h --- v2.4.6/linux/include/asm-s390x/string.h Tue Feb 13 14:13:44 2001 +++ linux/include/asm-s390x/string.h Wed Jul 4 11:50:39 2001 @@ -45,8 +45,6 @@ extern char *strncpy(char *, const char *, size_t); extern int strcmp(const char *,const char *); -#undef __HAVE_ARCH_MEMCHR -#if 0 static inline void * memchr(const void * cs,int c,size_t count) { void *ptr; @@ -63,7 +61,6 @@ : "cc", "0", "1" ); return ptr; } -#endif static __inline__ char *strcpy(char *dest, const char *src) { @@ -77,8 +74,6 @@ return tmp; } -#undef __HAVE_ARCH_STRLEN -#if 0 static __inline__ size_t strlen(const char *s) { size_t len; @@ -93,10 +88,7 @@ : "cc", "0" ); return len; } -#endif -#undef __HAVE_ARCH_STRCAT -#if 0 static __inline__ char *strcat(char *dest, const char *src) { char *tmp = dest; @@ -112,7 +104,6 @@ : "cc", "memory", "0" ); return tmp; } -#endif extern void *alloca(size_t); #endif /* __KERNEL__ */ diff -u --recursive --new-file v2.4.6/linux/include/asm-sh/softirq.h linux/include/asm-sh/softirq.h --- v2.4.6/linux/include/asm-sh/softirq.h Tue Jul 3 17:08:21 2001 +++ linux/include/asm-sh/softirq.h Mon Jul 9 16:04:24 2001 @@ -26,7 +26,6 @@ } while (0) #define __cpu_raise_softirq(cpu, nr) set_bit((nr), &softirq_pending(cpu)); -#define raise_softirq(nr) __cpu_raise_softirq(smp_processor_id(), (nr)) #define in_softirq() (local_bh_count(smp_processor_id()) != 0) diff -u --recursive --new-file v2.4.6/linux/include/asm-sparc/atomic.h linux/include/asm-sparc/atomic.h --- v2.4.6/linux/include/asm-sparc/atomic.h Sun Mar 25 18:14:21 2001 +++ linux/include/asm-sparc/atomic.h Mon Jul 9 21:32:02 2001 @@ -100,6 +100,12 @@ #define atomic_add_negative(i, v) (__atomic_add((i), (v)) < 0) +/* Atomic operations are already serializing */ +#define smp_mb__before_atomic_dec() barrier() +#define smp_mb__after_atomic_dec() barrier() +#define smp_mb__before_atomic_inc() barrier() +#define smp_mb__after_atomic_inc() barrier() + #endif /* !(__KERNEL__) */ #endif /* !(__ARCH_SPARC_ATOMIC__) */ diff -u --recursive --new-file v2.4.6/linux/include/asm-sparc/bitops.h linux/include/asm-sparc/bitops.h --- v2.4.6/linux/include/asm-sparc/bitops.h Tue Oct 3 09:24:41 2000 +++ linux/include/asm-sparc/bitops.h Thu Jul 19 18:11:13 2001 @@ -1,8 +1,9 @@ -/* $Id: bitops.h,v 1.61 2000/09/23 02:11:22 davem Exp $ +/* $Id: bitops.h,v 1.63 2001/07/17 16:17:33 anton Exp $ * bitops.h: Bit string operations on the Sparc. * * Copyright 1995 David S. Miller (davem@caip.rutgers.edu) * Copyright 1996 Eddie C. Dost (ecd@skynet.be) + * Copyright 2001 Anton Blanchard (anton@samba.org) */ #ifndef _SPARC_BITOPS_H @@ -10,83 +11,17 @@ #include <linux/kernel.h> #include <asm/byteorder.h> - -#ifndef __KERNEL__ - -/* User mode bitops, defined here for convenience. Note: these are not - * atomic, so packages like nthreads should do some locking around these - * themself. - */ - -extern __inline__ unsigned long set_bit(unsigned long nr, void *addr) -{ - int mask; - unsigned long *ADDR = (unsigned long *) addr; - - ADDR += nr >> 5; - mask = 1 << (nr & 31); - __asm__ __volatile__(" - ld [%0], %%g3 - or %%g3, %2, %%g2 - st %%g2, [%0] - and %%g3, %2, %0 - " - : "=&r" (ADDR) - : "0" (ADDR), "r" (mask) - : "g2", "g3"); - - return (unsigned long) ADDR; -} - -extern __inline__ unsigned long clear_bit(unsigned long nr, void *addr) -{ - int mask; - unsigned long *ADDR = (unsigned long *) addr; - - ADDR += nr >> 5; - mask = 1 << (nr & 31); - __asm__ __volatile__(" - ld [%0], %%g3 - andn %%g3, %2, %%g2 - st %%g2, [%0] - and %%g3, %2, %0 - " - : "=&r" (ADDR) - : "0" (ADDR), "r" (mask) - : "g2", "g3"); - - return (unsigned long) ADDR; -} - -extern __inline__ void change_bit(unsigned long nr, void *addr) -{ - int mask; - unsigned long *ADDR = (unsigned long *) addr; - - ADDR += nr >> 5; - mask = 1 << (nr & 31); - __asm__ __volatile__(" - ld [%0], %%g3 - xor %%g3, %2, %%g2 - st %%g2, [%0] - and %%g3, %2, %0 - " - : "=&r" (ADDR) - : "0" (ADDR), "r" (mask) - : "g2", "g3"); -} - -#else /* __KERNEL__ */ - #include <asm/system.h> -/* Set bit 'nr' in 32-bit quantity at address 'addr' where bit '0' +#ifdef __KERNEL__ + +/* + * Set bit 'nr' in 32-bit quantity at address 'addr' where bit '0' * is in the highest of the four bytes and bit '31' is the high bit * within the first byte. Sparc is BIG-Endian. Unless noted otherwise * all bit-ops return 0 if bit was previously clear and != 0 otherwise. */ - -extern __inline__ int test_and_set_bit(unsigned long nr, volatile void *addr) +static __inline__ int test_and_set_bit(unsigned long nr, volatile void *addr) { register unsigned long mask asm("g2"); register unsigned long *ADDR asm("g1"); @@ -103,12 +38,12 @@ return mask != 0; } -extern __inline__ void set_bit(unsigned long nr, volatile void *addr) +static __inline__ void set_bit(unsigned long nr, volatile void *addr) { (void) test_and_set_bit(nr, addr); } -extern __inline__ int test_and_clear_bit(unsigned long nr, volatile void *addr) +static __inline__ int test_and_clear_bit(unsigned long nr, volatile void *addr) { register unsigned long mask asm("g2"); register unsigned long *ADDR asm("g1"); @@ -126,12 +61,12 @@ return mask != 0; } -extern __inline__ void clear_bit(unsigned long nr, volatile void *addr) +static __inline__ void clear_bit(unsigned long nr, volatile void *addr) { (void) test_and_clear_bit(nr, addr); } -extern __inline__ int test_and_change_bit(unsigned long nr, volatile void *addr) +static __inline__ int test_and_change_bit(unsigned long nr, volatile void *addr) { register unsigned long mask asm("g2"); register unsigned long *ADDR asm("g1"); @@ -149,24 +84,79 @@ return mask != 0; } -extern __inline__ void change_bit(unsigned long nr, volatile void *addr) +static __inline__ void change_bit(unsigned long nr, volatile void *addr) { (void) test_and_change_bit(nr, addr); } -#endif /* __KERNEL__ */ +/* + * non-atomic versions + */ +static __inline__ void __set_bit(int nr, volatile void *addr) +{ + unsigned long mask = 1UL << (nr & 0x1f); + unsigned long *p = ((unsigned long *)addr) + (nr >> 5); + + *p |= mask; +} + +static __inline__ void __clear_bit(int nr, volatile void *addr) +{ + unsigned long mask = 1UL << (nr & 0x1f); + unsigned long *p = ((unsigned long *)addr) + (nr >> 5); + + *p &= ~mask; +} + +static __inline__ void __change_bit(int nr, volatile void *addr) +{ + unsigned long mask = 1UL << (nr & 0x1f); + unsigned long *p = ((unsigned long *)addr) + (nr >> 5); + + *p ^= mask; +} + +static __inline__ int __test_and_set_bit(int nr, volatile void *addr) +{ + unsigned long mask = 1UL << (nr & 0x1f); + unsigned long *p = ((unsigned long *)addr) + (nr >> 5); + unsigned long old = *p; + + *p = old | mask; + return (old & mask) != 0; +} + +static __inline__ int __test_and_clear_bit(int nr, volatile void *addr) +{ + unsigned long mask = 1UL << (nr & 0x1f); + unsigned long *p = ((unsigned long *)addr) + (nr >> 5); + unsigned long old = *p; + + *p = old & ~mask; + return (old & mask) != 0; +} + +static __inline__ int __test_and_change_bit(int nr, volatile void *addr) +{ + unsigned long mask = 1UL << (nr & 0x1f); + unsigned long *p = ((unsigned long *)addr) + (nr >> 5); + unsigned long old = *p; + + *p = old ^ mask; + return (old & mask) != 0; +} #define smp_mb__before_clear_bit() do { } while(0) #define smp_mb__after_clear_bit() do { } while(0) /* The following routine need not be atomic. */ -extern __inline__ int test_bit(int nr, __const__ void *addr) +static __inline__ int test_bit(int nr, __const__ void *addr) { return (1 & (((__const__ unsigned int *) addr)[nr >> 5] >> (nr & 31))) != 0; } /* The easy/cheese version for now. */ -extern __inline__ unsigned long ffz(unsigned long word) +static __inline__ unsigned long ffz(unsigned long word) { unsigned long result = 0; @@ -177,33 +167,27 @@ return result; } -#ifdef __KERNEL__ - /* * ffs: find first bit set. This is defined the same way as * the libc and compiler builtin ffs routines, therefore * differs in spirit from the above ffz (man ffs). */ - #define ffs(x) generic_ffs(x) /* * hweightN: returns the hamming weight (i.e. the number * of bits set) of a N-bit word */ - #define hweight32(x) generic_hweight32(x) #define hweight16(x) generic_hweight16(x) #define hweight8(x) generic_hweight8(x) -#endif /* __KERNEL__ */ - -/* find_next_zero_bit() finds the first zero bit in a bit string of length +/* + * find_next_zero_bit() finds the first zero bit in a bit string of length * 'size' bits, starting the search at bit 'offset'. This is largely based * on Linus's ALPHA routines, which are pretty portable BTW. */ - -extern __inline__ unsigned long find_next_zero_bit(void *addr, unsigned long size, unsigned long offset) +static __inline__ unsigned long find_next_zero_bit(void *addr, unsigned long size, unsigned long offset) { unsigned long *p = ((unsigned long *) addr) + (offset >> 5); unsigned long result = offset & ~31UL; @@ -241,119 +225,63 @@ return result + ffz(tmp); } -/* Linus sez that gcc can optimize the following correctly, we'll see if this +/* + * Linus sez that gcc can optimize the following correctly, we'll see if this * holds on the Sparc as it does for the ALPHA. */ - #define find_first_zero_bit(addr, size) \ find_next_zero_bit((addr), (size), 0) -#ifndef __KERNEL__ - -extern __inline__ int set_le_bit(int nr, void *addr) +static __inline__ int test_le_bit(int nr, __const__ void * addr) { - int mask; - unsigned char *ADDR = (unsigned char *) addr; - - ADDR += nr >> 3; - mask = 1 << (nr & 0x07); - __asm__ __volatile__(" - ldub [%0], %%g3 - or %%g3, %2, %%g2 - stb %%g2, [%0] - and %%g3, %2, %0 - " - : "=&r" (ADDR) - : "0" (ADDR), "r" (mask) - : "g2", "g3"); - - return (int) ADDR; + __const__ unsigned char *ADDR = (__const__ unsigned char *) addr; + return (ADDR[nr >> 3] >> (nr & 7)) & 1; } -extern __inline__ int clear_le_bit(int nr, void *addr) +/* + * non-atomic versions + */ +static __inline__ void __set_le_bit(int nr, void *addr) { - int mask; - unsigned char *ADDR = (unsigned char *) addr; + unsigned char *ADDR = (unsigned char *)addr; ADDR += nr >> 3; - mask = 1 << (nr & 0x07); - __asm__ __volatile__(" - ldub [%0], %%g3 - andn %%g3, %2, %%g2 - stb %%g2, [%0] - and %%g3, %2, %0 - " - : "=&r" (ADDR) - : "0" (ADDR), "r" (mask) - : "g2", "g3"); - - return (int) ADDR; + *ADDR |= 1 << (nr & 0x07); } -#else /* __KERNEL__ */ - -/* Now for the ext2 filesystem bit operations and helper routines. */ - -extern __inline__ int set_le_bit(int nr, volatile void * addr) +static __inline__ void __clear_le_bit(int nr, void *addr) { - register int mask asm("g2"); - register unsigned char *ADDR asm("g1"); - - ADDR = ((unsigned char *) addr) + (nr >> 3); - mask = 1 << (nr & 0x07); - __asm__ __volatile__(" - mov %%o7, %%g4 - call ___set_le_bit - add %%o7, 8, %%o7 -" : "=&r" (mask) - : "0" (mask), "r" (ADDR) - : "g3", "g4", "g5", "g7", "cc"); + unsigned char *ADDR = (unsigned char *)addr; - return mask; + ADDR += nr >> 3; + *ADDR &= ~(1 << (nr & 0x07)); } -extern __inline__ int clear_le_bit(int nr, volatile void * addr) +static __inline__ int __test_and_set_le_bit(int nr, void *addr) { - register int mask asm("g2"); - register unsigned char *ADDR asm("g1"); + int mask, retval; + unsigned char *ADDR = (unsigned char *)addr; - ADDR = ((unsigned char *) addr) + (nr >> 3); + ADDR += nr >> 3; mask = 1 << (nr & 0x07); - __asm__ __volatile__(" - mov %%o7, %%g4 - call ___clear_le_bit - add %%o7, 8, %%o7 -" : "=&r" (mask) - : "0" (mask), "r" (ADDR) - : "g3", "g4", "g5", "g7", "cc"); - - return mask; + retval = (mask & *ADDR) != 0; + *ADDR |= mask; + return retval; } -#endif /* __KERNEL__ */ - -extern __inline__ int test_le_bit(int nr, __const__ void * addr) +static __inline__ int __test_and_clear_le_bit(int nr, void *addr) { - int mask; - __const__ unsigned char *ADDR = (__const__ unsigned char *) addr; + int mask, retval; + unsigned char *ADDR = (unsigned char *)addr; ADDR += nr >> 3; mask = 1 << (nr & 0x07); - return ((mask & *ADDR) != 0); + retval = (mask & *ADDR) != 0; + *ADDR &= ~mask; + return retval; } -#ifdef __KERNEL__ - -#define ext2_set_bit set_le_bit -#define ext2_clear_bit clear_le_bit -#define ext2_test_bit test_le_bit - -#endif /* __KERNEL__ */ - -#define find_first_zero_le_bit(addr, size) \ - find_next_zero_le_bit((addr), (size), 0) - -extern __inline__ unsigned long find_next_zero_le_bit(void *addr, unsigned long size, unsigned long offset) +static __inline__ unsigned long find_next_zero_le_bit(void *addr, unsigned long size, unsigned long offset) { unsigned long *p = ((unsigned long *) addr) + (offset >> 5); unsigned long result = offset & ~31UL; @@ -393,17 +321,21 @@ return result + ffz(__swab32(tmp)); } -#ifdef __KERNEL__ +#define find_first_zero_le_bit(addr, size) \ + find_next_zero_le_bit((addr), (size), 0) -#define ext2_find_first_zero_bit find_first_zero_le_bit -#define ext2_find_next_zero_bit find_next_zero_le_bit +#define ext2_set_bit __test_and_set_le_bit +#define ext2_clear_bit __test_and_clear_le_bit +#define ext2_test_bit test_le_bit +#define ext2_find_first_zero_bit find_first_zero_le_bit +#define ext2_find_next_zero_bit find_next_zero_le_bit /* Bitmap functions for the minix filesystem. */ -#define minix_test_and_set_bit(nr,addr) test_and_set_bit(nr,addr) -#define minix_set_bit(nr,addr) set_bit(nr,addr) -#define minix_test_and_clear_bit(nr,addr) test_and_clear_bit(nr,addr) -#define minix_test_bit(nr,addr) test_bit(nr,addr) -#define minix_find_first_zero_bit(addr,size) find_first_zero_bit(addr,size) +#define minix_test_and_set_bit(nr,addr) test_and_set_bit(nr,addr) +#define minix_set_bit(nr,addr) set_bit(nr,addr) +#define minix_test_and_clear_bit(nr,addr) test_and_clear_bit(nr,addr) +#define minix_test_bit(nr,addr) test_bit(nr,addr) +#define minix_find_first_zero_bit(addr,size) find_first_zero_bit(addr,size) #endif /* __KERNEL__ */ diff -u --recursive --new-file v2.4.6/linux/include/asm-sparc/hardirq.h linux/include/asm-sparc/hardirq.h --- v2.4.6/linux/include/asm-sparc/hardirq.h Tue Jul 3 17:08:21 2001 +++ linux/include/asm-sparc/hardirq.h Mon Jul 9 14:47:39 2001 @@ -23,6 +23,7 @@ #endif unsigned int __local_bh_count; unsigned int __syscall_count; + struct task_struct * __ksoftirqd_task; } ____cacheline_aligned irq_cpustat_t; #include <linux/irq_cpustat.h> /* Standard mappings for irq_cpustat_t above */ diff -u --recursive --new-file v2.4.6/linux/include/asm-sparc/pgalloc.h linux/include/asm-sparc/pgalloc.h --- v2.4.6/linux/include/asm-sparc/pgalloc.h Thu Apr 26 22:17:26 2001 +++ linux/include/asm-sparc/pgalloc.h Thu Jul 19 18:11:13 2001 @@ -1,4 +1,4 @@ -/* $Id: pgalloc.h,v 1.12 2001/04/26 02:36:35 davem Exp $ */ +/* $Id: pgalloc.h,v 1.13 2001/07/17 16:17:33 anton Exp $ */ #ifndef _SPARC_PGALLOC_H #define _SPARC_PGALLOC_H @@ -104,39 +104,42 @@ BTFIXUPDEF_CALL(int, do_check_pgt_cache, int, int) #define do_check_pgt_cache(low,high) BTFIXUP_CALL(do_check_pgt_cache)(low,high) -/* - * Allocate and free page tables. The xxx_kernel() versions are - * used to allocate a kernel page table - this turns on ASN bits - * if any, and marks the page tables reserved. - */ -BTFIXUPDEF_CALL(void, pte_free_kernel, pte_t *) -BTFIXUPDEF_CALL(pte_t *, pte_alloc_kernel, pmd_t *, unsigned long) +BTFIXUPDEF_CALL(pgd_t *, get_pgd_fast, void) +#define get_pgd_fast() BTFIXUP_CALL(get_pgd_fast)() -#define pte_free_kernel(pte) BTFIXUP_CALL(pte_free_kernel)(pte) -#define pte_alloc_kernel(pmd,addr) BTFIXUP_CALL(pte_alloc_kernel)(pmd,addr) +BTFIXUPDEF_CALL(void, free_pgd_fast, pgd_t *) +#define free_pgd_fast(pgd) BTFIXUP_CALL(free_pgd_fast)(pgd) -BTFIXUPDEF_CALL(void, pmd_free_kernel, pmd_t *) -BTFIXUPDEF_CALL(pmd_t *, pmd_alloc_kernel, pgd_t *, unsigned long) +#define pgd_free(pgd) free_pgd_fast(pgd) +#define pgd_alloc(mm) get_pgd_fast() -#define pmd_free_kernel(pmd) BTFIXUP_CALL(pmd_free_kernel)(pmd) -#define pmd_alloc_kernel(pgd,addr) BTFIXUP_CALL(pmd_alloc_kernel)(pgd,addr) +#define pgd_populate(MM, PGD, PMD) pgd_set(PGD, PMD) -BTFIXUPDEF_CALL(void, pte_free, pte_t *) -BTFIXUPDEF_CALL(pte_t *, pte_alloc, pmd_t *, unsigned long) +static __inline__ pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long address) +{ + BUG(); + return 0; +} + +BTFIXUPDEF_CALL(pmd_t *, pmd_alloc_one_fast, struct mm_struct *, unsigned long) +#define pmd_alloc_one_fast(mm, address) BTFIXUP_CALL(pmd_alloc_one_fast)(mm, address) + +BTFIXUPDEF_CALL(void, free_pmd_fast, pmd_t *) +#define free_pmd_fast(pmd) BTFIXUP_CALL(free_pmd_fast)(pmd) + +#define pmd_free(pmd) free_pmd_fast(pmd) -#define pte_free(pte) BTFIXUP_CALL(pte_free)(pte) -#define pte_alloc(pmd,addr) BTFIXUP_CALL(pte_alloc)(pmd,addr) +#define pmd_populate(MM, PMD, PTE) pmd_set(PMD, PTE) -BTFIXUPDEF_CALL(void, pmd_free, pmd_t *) -BTFIXUPDEF_CALL(pmd_t *, pmd_alloc, pgd_t *, unsigned long) +BTFIXUPDEF_CALL(pte_t *, pte_alloc_one, struct mm_struct *, unsigned long) +#define pte_alloc_one(mm, address) BTFIXUP_CALL(pte_alloc_one)(mm, address) -#define pmd_free(pmd) BTFIXUP_CALL(pmd_free)(pmd) -#define pmd_alloc(pgd,addr) BTFIXUP_CALL(pmd_alloc)(pgd,addr) +BTFIXUPDEF_CALL(pte_t *, pte_alloc_one_fast, struct mm_struct *, unsigned long) +#define pte_alloc_one_fast(mm, address) BTFIXUP_CALL(pte_alloc_one_fast)(mm, address) -BTFIXUPDEF_CALL(void, pgd_free, pgd_t *) -BTFIXUPDEF_CALL(pgd_t *, pgd_alloc, void) +BTFIXUPDEF_CALL(void, free_pte_fast, pte_t *) +#define free_pte_fast(pte) BTFIXUP_CALL(free_pte_fast)(pte) -#define pgd_free(pgd) BTFIXUP_CALL(pgd_free)(pgd) -#define pgd_alloc(mm) BTFIXUP_CALL(pgd_alloc)() +#define pte_free(pte) free_pte_fast(pte) -#endif /* _SPARC64_PGALLOC_H */ +#endif /* _SPARC_PGALLOC_H */ diff -u --recursive --new-file v2.4.6/linux/include/asm-sparc/softirq.h linux/include/asm-sparc/softirq.h --- v2.4.6/linux/include/asm-sparc/softirq.h Tue Jul 3 17:08:21 2001 +++ linux/include/asm-sparc/softirq.h Mon Jul 9 16:31:14 2001 @@ -22,11 +22,11 @@ __sti(); \ } \ } while (0) -#define __cpu_raise_softirq(cpu, nr) (softirq_pending(cpu) |= (1<<nr)) -#define raise_softirq(nr) \ +#define __do_cpu_raise_softirq(cpu, nr) (softirq_pending(cpu) |= (1<<nr)) +#define __cpu_raise_softirq(cpu, nr) \ do { unsigned long flags; \ local_irq_save(flags); \ - __cpu_raise_softirq(smp_processor_id(), nr); \ + __do_cpu_raise_softirq(cpu, nr); \ local_irq_restore(flags); \ } while (0) #define in_softirq() (local_bh_count(smp_processor_id()) != 0) diff -u --recursive --new-file v2.4.6/linux/include/asm-sparc/vaddrs.h linux/include/asm-sparc/vaddrs.h --- v2.4.6/linux/include/asm-sparc/vaddrs.h Tue Jul 3 17:08:21 2001 +++ linux/include/asm-sparc/vaddrs.h Fri Jul 6 16:46:22 2001 @@ -1,4 +1,4 @@ -/* $Id: vaddrs.h,v 1.26 2000/08/01 04:53:58 anton Exp $ */ +/* $Id: vaddrs.h,v 1.27 2001/07/04 00:18:18 davem Exp $ */ #ifndef _SPARC_VADDRS_H #define _SPARC_VADDRS_H diff -u --recursive --new-file v2.4.6/linux/include/asm-sparc64/atomic.h linux/include/asm-sparc64/atomic.h --- v2.4.6/linux/include/asm-sparc64/atomic.h Tue Oct 10 10:33:52 2000 +++ linux/include/asm-sparc64/atomic.h Thu Jul 19 18:11:13 2001 @@ -1,4 +1,4 @@ -/* $Id: atomic.h,v 1.21 2000/10/03 07:28:56 anton Exp $ +/* $Id: atomic.h,v 1.22 2001/07/11 23:56:07 davem Exp $ * atomic.h: Thankfully the V9 is at least reasonable for this * stuff. * @@ -28,5 +28,11 @@ #define atomic_inc(v) ((void)__atomic_add(1, v)) #define atomic_dec(v) ((void)__atomic_sub(1, v)) + +/* Atomic operations are already serializing */ +#define smp_mb__before_atomic_dec() barrier() +#define smp_mb__after_atomic_dec() barrier() +#define smp_mb__before_atomic_inc() barrier() +#define smp_mb__after_atomic_inc() barrier() #endif /* !(__ARCH_SPARC64_ATOMIC__) */ diff -u --recursive --new-file v2.4.6/linux/include/asm-sparc64/hardirq.h linux/include/asm-sparc64/hardirq.h --- v2.4.6/linux/include/asm-sparc64/hardirq.h Tue Jul 3 17:08:21 2001 +++ linux/include/asm-sparc64/hardirq.h Mon Jul 9 14:47:39 2001 @@ -22,6 +22,7 @@ #endif unsigned int __local_bh_count; unsigned int __syscall_count; + struct task_struct * __ksoftirqd_task; } ____cacheline_aligned irq_cpustat_t; #include <linux/irq_cpustat.h> /* Standard mappings for irq_cpustat_t above */ diff -u --recursive --new-file v2.4.6/linux/include/asm-sparc64/softirq.h linux/include/asm-sparc64/softirq.h --- v2.4.6/linux/include/asm-sparc64/softirq.h Tue Jul 3 17:08:21 2001 +++ linux/include/asm-sparc64/softirq.h Mon Jul 9 16:31:27 2001 @@ -19,11 +19,12 @@ __sti(); \ } \ } while (0) -#define __cpu_raise_softirq(cpu, nr) (softirq_pending(cpu) |= (1<<nr)) -#define raise_softirq(nr) \ + +#define __do_cpu_raise_softirq(cpu, nr) (softirq_pending(cpu) |= (1<<nr)) +#define __cpu_raise_softirq(cpu,nr) \ do { unsigned long flags; \ local_irq_save(flags); \ - __cpu_raise_softirq(smp_processor_id(), nr); \ + __do_cpu_raise_softirq(cpu, nr); \ local_irq_restore(flags); \ } while (0) #define in_softirq() (local_bh_count(smp_processor_id()) != 0) diff -u --recursive --new-file v2.4.6/linux/include/asm-sparc64/starfire.h linux/include/asm-sparc64/starfire.h --- v2.4.6/linux/include/asm-sparc64/starfire.h Tue Jul 3 17:08:21 2001 +++ linux/include/asm-sparc64/starfire.h Fri Jul 6 16:46:22 2001 @@ -1,4 +1,4 @@ -/* $Id: starfire.h,v 1.1 2000/09/21 06:18:53 anton Exp $ +/* $Id: starfire.h,v 1.2 2001/07/04 00:18:18 davem Exp $ * starfire.h: Group all starfire specific code together. * * Copyright (C) 2000 Anton Blanchard (anton@samba.org) diff -u --recursive --new-file v2.4.6/linux/include/linux/amigaffs.h linux/include/linux/amigaffs.h --- v2.4.6/linux/include/linux/amigaffs.h Thu Apr 19 22:57:06 2001 +++ linux/include/linux/amigaffs.h Sun Jul 15 16:34:15 2001 @@ -90,6 +90,38 @@ ((u32 *)bh->b_data)[0] = cpu_to_be32(tmp - val); } +static inline void +affs_lock_link(struct inode *inode) +{ + down(&AFFS_INODE->i_link_lock); +} +static inline void +affs_unlock_link(struct inode *inode) +{ + up(&AFFS_INODE->i_link_lock); +} +static inline void +affs_lock_dir(struct inode *inode) +{ + down(&AFFS_INODE->i_hash_lock); +} +static inline void +affs_unlock_dir(struct inode *inode) +{ + up(&AFFS_INODE->i_hash_lock); +} +static inline void +affs_lock_ext(struct inode *inode) +{ + down(&AFFS_INODE->i_ext_lock); +} +static inline void +affs_unlock_ext(struct inode *inode) +{ + up(&AFFS_INODE->i_ext_lock); +} + + #define MIN(a, b) ({ \ typeof(a) _a = (a); \ typeof(b) _b = (b); \ diff -u --recursive --new-file v2.4.6/linux/include/linux/apm_bios.h linux/include/linux/apm_bios.h --- v2.4.6/linux/include/linux/apm_bios.h Fri Apr 6 10:51:19 2001 +++ linux/include/linux/apm_bios.h Wed Jul 4 11:50:39 2001 @@ -52,6 +52,9 @@ struct apm_bios_info bios; unsigned short connection_version; int get_power_status_broken; + int allow_ints; + int realmode_power_off; + int disabled; }; /* diff -u --recursive --new-file v2.4.6/linux/include/linux/blkdev.h linux/include/linux/blkdev.h --- v2.4.6/linux/include/linux/blkdev.h Fri May 25 18:01:40 2001 +++ linux/include/linux/blkdev.h Fri Jul 20 12:53:09 2001 @@ -15,8 +15,8 @@ /* * Ok, this is an expanded form so that we can use the same * request for paging requests when that is implemented. In - * paging, 'bh' is NULL, and the semaphore is used to wait - * for read/write completion. + * paging, 'bh' is NULL, and the completion is used to wait + * for the IO to be ready. */ struct request { struct list_head queue; @@ -41,7 +41,7 @@ unsigned long current_nr_sectors; void * special; char * buffer; - struct semaphore * sem; + struct completion * waiting; struct buffer_head * bh; struct buffer_head * bhtail; request_queue_t *q; diff -u --recursive --new-file v2.4.6/linux/include/linux/cdrom.h linux/include/linux/cdrom.h --- v2.4.6/linux/include/linux/cdrom.h Fri May 25 18:01:28 2001 +++ linux/include/linux/cdrom.h Fri Jul 20 12:53:03 2001 @@ -729,7 +729,8 @@ struct cdrom_device_ops *ops; /* link to device_ops */ struct cdrom_device_info *next; /* next device_info for this major */ void *handle; /* driver-dependent data */ - devfs_handle_t de; /* real driver creates this */ + devfs_handle_t de; /* real driver should create this */ + int number; /* generic driver updates this */ /* specifications */ kdev_t dev; /* device number */ int mask; /* mask of capability: disables them */ diff -u --recursive --new-file v2.4.6/linux/include/linux/completion.h linux/include/linux/completion.h --- v2.4.6/linux/include/linux/completion.h Wed Dec 31 16:00:00 1969 +++ linux/include/linux/completion.h Fri Jul 20 12:52:18 2001 @@ -0,0 +1,35 @@ +#ifndef __LINUX_COMPLETION_H +#define __LINUX_COMPLETION_H + +/* + * (C) Copyright 2001 Linus Torvalds + * + * Atomic wait-for-completion handler data structures. + * See kernel/sched.c for details. + */ + +#include <linux/wait.h> + +struct completion { + unsigned int done; + wait_queue_head_t wait; +}; + +#define COMPLETION_INITIALIZER(work) \ + { 0, __WAIT_QUEUE_HEAD_INITIALIZER((work).wait) } + +#define DECLARE_COMPLETION(work) \ + struct completion work = COMPLETION_INITIALIZER(work) + +static inline void init_completion(struct completion *x) +{ + x->done = 0; + init_waitqueue_head(&x->wait); +} + +extern void FASTCALL(wait_for_completion(struct completion *)); +extern void FASTCALL(complete(struct completion *)); + +#define INIT_COMPLETION(x) ((x).done = 0) + +#endif diff -u --recursive --new-file v2.4.6/linux/include/linux/cramfs_fs.h linux/include/linux/cramfs_fs.h --- v2.4.6/linux/include/linux/cramfs_fs.h Wed Dec 31 16:00:00 1969 +++ linux/include/linux/cramfs_fs.h Thu Jul 19 16:14:53 2001 @@ -0,0 +1,89 @@ +#ifndef __CRAMFS_H +#define __CRAMFS_H + +#ifndef __KERNEL__ + +typedef unsigned char u8; +typedef unsigned short u16; +typedef unsigned int u32; + +#endif + +#define CRAMFS_MAGIC 0x28cd3d45 /* some random number */ +#define CRAMFS_SIGNATURE "Compressed ROMFS" + +/* + * Width of various bitfields in struct cramfs_inode. + * Primarily used to generate warnings in mkcramfs. + */ +#define CRAMFS_MODE_WIDTH 16 +#define CRAMFS_UID_WIDTH 16 +#define CRAMFS_SIZE_WIDTH 24 +#define CRAMFS_GID_WIDTH 8 +#define CRAMFS_NAMELEN_WIDTH 6 +#define CRAMFS_OFFSET_WIDTH 26 + +/* + * Reasonably terse representation of the inode data. + */ +struct cramfs_inode { + u32 mode:CRAMFS_MODE_WIDTH, uid:CRAMFS_UID_WIDTH; + /* SIZE for device files is i_rdev */ + u32 size:CRAMFS_SIZE_WIDTH, gid:CRAMFS_GID_WIDTH; + /* NAMELEN is the length of the file name, divided by 4 and + rounded up. (cramfs doesn't support hard links.) */ + /* OFFSET: For symlinks and non-empty regular files, this + contains the offset (divided by 4) of the file data in + compressed form (starting with an array of block pointers; + see README). For non-empty directories it is the offset + (divided by 4) of the inode of the first file in that + directory. For anything else, offset is zero. */ + u32 namelen:CRAMFS_NAMELEN_WIDTH, offset:CRAMFS_OFFSET_WIDTH; +}; + +struct cramfs_info { + u32 crc; + u32 edition; + u32 blocks; + u32 files; +}; + +/* + * Superblock information at the beginning of the FS. + */ +struct cramfs_super { + u32 magic; /* 0x28cd3d45 - random number */ + u32 size; /* length in bytes */ + u32 flags; /* 0 */ + u32 future; /* 0 */ + u8 signature[16]; /* "Compressed ROMFS" */ + struct cramfs_info fsid; /* unique filesystem info */ + u8 name[16]; /* user-defined name */ + struct cramfs_inode root; /* Root inode data */ +}; + +/* + * Feature flags + * + * 0x00000000 - 0x000000ff: features that work for all past kernels + * 0x00000100 - 0xffffffff: features that don't work for past kernels + */ +#define CRAMFS_FLAG_FSID_VERSION_2 0x00000001 /* fsid version #2 */ +#define CRAMFS_FLAG_SORTED_DIRS 0x00000002 /* sorted dirs */ +#define CRAMFS_FLAG_HOLES 0x00000100 /* support for holes */ +#define CRAMFS_FLAG_WRONG_SIGNATURE 0x00000200 /* reserved */ +#define CRAMFS_FLAG_SHIFTED_ROOT_OFFSET 0x00000400 /* shifted root fs */ + +/* + * Valid values in super.flags. Currently we refuse to mount + * if (flags & ~CRAMFS_SUPPORTED_FLAGS). Maybe that should be + * changed to test super.future instead. + */ +#define CRAMFS_SUPPORTED_FLAGS (0x7ff) + +/* Uncompression interfaces to the underlying zlib */ +int cramfs_uncompress_block(void *dst, int dstlen, void *src, int srclen); +int cramfs_uncompress_init(void); +int cramfs_uncompress_exit(void); + +#endif diff -u --recursive --new-file v2.4.6/linux/include/linux/cramfs_fs_sb.h linux/include/linux/cramfs_fs_sb.h --- v2.4.6/linux/include/linux/cramfs_fs_sb.h Wed Dec 31 16:00:00 1969 +++ linux/include/linux/cramfs_fs_sb.h Thu Jul 19 16:14:53 2001 @@ -0,0 +1,15 @@ +#ifndef _CRAMFS_FS_SB +#define _CRAMFS_FS_SB + +/* + * cramfs super-block data in memory + */ +struct cramfs_sb_info { + unsigned long magic; + unsigned long size; + unsigned long blocks; + unsigned long files; + unsigned long flags; +}; + +#endif diff -u --recursive --new-file v2.4.6/linux/include/linux/devfs_fs_kernel.h linux/include/linux/devfs_fs_kernel.h --- v2.4.6/linux/include/linux/devfs_fs_kernel.h Tue Jul 3 17:08:21 2001 +++ linux/include/linux/devfs_fs_kernel.h Fri Jul 20 12:52:57 2001 @@ -3,6 +3,11 @@ #include <linux/fs.h> #include <linux/config.h> +#include <linux/locks.h> +#include <linux/kdev_t.h> +#include <linux/types.h> + +#include <asm/semaphore.h> #define DEVFS_SUPER_MAGIC 0x1373 @@ -53,6 +58,19 @@ #ifdef CONFIG_DEVFS_FS + +struct unique_numspace +{ + spinlock_t init_lock; + unsigned char sem_initialised; + unsigned int num_free; /* Num free in bits */ + unsigned int length; /* Array length in bytes */ + __u32 *bits; + struct semaphore semaphore; +}; + +#define UNIQUE_NUMBERSPACE_INITIALISER {SPIN_LOCK_UNLOCKED, 0, 0, 0, NULL} + extern devfs_handle_t devfs_register (devfs_handle_t dir, const char *name, unsigned int flags, unsigned int major, unsigned int minor, @@ -95,10 +113,26 @@ unsigned int flags, unsigned int major, unsigned int minor_start, umode_t mode, void *ops, void *info); +extern int devfs_alloc_major (char type); +extern void devfs_dealloc_major (char type, int major); +extern kdev_t devfs_alloc_devnum (char type); +extern void devfs_dealloc_devnum (char type, kdev_t devnum); +extern int devfs_alloc_unique_number (struct unique_numspace *space); +extern void devfs_dealloc_unique_number (struct unique_numspace *space, + int number); extern void mount_devfs_fs (void); extern void devfs_make_root (const char *name); + #else /* CONFIG_DEVFS_FS */ + +struct unique_numspace +{ + char dummy; +}; + +#define UNIQUE_NUMBERSPACE_INITIALISER {0} + static inline devfs_handle_t devfs_register (devfs_handle_t dir, const char *name, unsigned int flags, @@ -228,6 +262,37 @@ unsigned int major, unsigned int minor_start, umode_t mode, void *ops, void *info) +{ + return; +} + +static inline int devfs_alloc_major (char type) +{ + return -1; +} + +static inline void devfs_dealloc_major (char type, int major) +{ + return; +} + +static inline kdev_t devfs_alloc_devnum (char type) +{ + return NODEV; +} + +static inline void devfs_dealloc_devnum (char type, kdev_t devnum) +{ + return; +} + +static inline int devfs_alloc_unique_number (struct unique_numspace *space) +{ + return -1; +} + +static inline void devfs_dealloc_unique_number (struct unique_numspace *space, + int number) { return; } diff -u --recursive --new-file v2.4.6/linux/include/linux/ethtool.h linux/include/linux/ethtool.h --- v2.4.6/linux/include/linux/ethtool.h Thu Apr 19 09:35:46 2001 +++ linux/include/linux/ethtool.h Thu Jul 19 17:47:14 2001 @@ -1,4 +1,4 @@ -/* $Id: ethtool.h,v 1.2 2000/11/12 10:05:57 davem Exp $ +/* * ethtool.h: Defines for Linux ethtool. * * Copyright (C) 1998 David S. Miller (davem@redhat.com) @@ -34,13 +34,15 @@ char bus_info[32]; /* Bus info for this interface. For PCI * devices, use pci_dev->slot_name. */ char reserved1[32]; - char reserved2[32]; + char reserved2[28]; + u32 regdump_len; /* Amount of data from ETHTOOL_GREGS */ }; /* CMDs currently supported */ #define ETHTOOL_GSET 0x00000001 /* Get settings. */ #define ETHTOOL_SSET 0x00000002 /* Set settings, privileged. */ #define ETHTOOL_GDRVINFO 0x00000003 /* Get driver info. */ +#define ETHTOOL_GREGS 0x00000004 /* Get NIC registers, privileged. */ /* compatibility with older code */ #define SPARC_ETH_GSET ETHTOOL_GSET diff -u --recursive --new-file v2.4.6/linux/include/linux/ext2_fs.h linux/include/linux/ext2_fs.h --- v2.4.6/linux/include/linux/ext2_fs.h Tue Jul 3 17:08:21 2001 +++ linux/include/linux/ext2_fs.h Fri Jul 20 12:52:44 2001 @@ -53,7 +53,7 @@ #endif /* - * Special inodes numbers + * Special inode numbers */ #define EXT2_BAD_INO 1 /* Bad blocks inode */ #define EXT2_ROOT_INO 2 /* Root inode */ @@ -448,19 +448,31 @@ EXT2_SB(sb)->s_es->s_feature_incompat &= ~cpu_to_le32(mask) #define EXT2_FEATURE_COMPAT_DIR_PREALLOC 0x0001 +#define EXT2_FEATURE_COMPAT_IMAGIC_INODES 0x0002 +#define EXT3_FEATURE_COMPAT_HAS_JOURNAL 0x0004 +#define EXT2_FEATURE_COMPAT_EXT_ATTR 0x0008 +#define EXT2_FEATURE_COMPAT_RESIZE_INO 0x0010 +#define EXT2_FEATURE_COMPAT_DIR_INDEX 0x0020 +#define EXT2_FEATURE_COMPAT_ANY 0xffffffff #define EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER 0x0001 #define EXT2_FEATURE_RO_COMPAT_LARGE_FILE 0x0002 #define EXT2_FEATURE_RO_COMPAT_BTREE_DIR 0x0004 +#define EXT2_FEATURE_RO_COMPAT_ANY 0xffffffff #define EXT2_FEATURE_INCOMPAT_COMPRESSION 0x0001 #define EXT2_FEATURE_INCOMPAT_FILETYPE 0x0002 +#define EXT3_FEATURE_INCOMPAT_RECOVER 0x0004 +#define EXT3_FEATURE_INCOMPAT_JOURNAL_DEV 0x0008 +#define EXT2_FEATURE_INCOMPAT_ANY 0xffffffff #define EXT2_FEATURE_COMPAT_SUPP 0 #define EXT2_FEATURE_INCOMPAT_SUPP EXT2_FEATURE_INCOMPAT_FILETYPE #define EXT2_FEATURE_RO_COMPAT_SUPP (EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER| \ EXT2_FEATURE_RO_COMPAT_LARGE_FILE| \ EXT2_FEATURE_RO_COMPAT_BTREE_DIR) +#define EXT2_FEATURE_RO_COMPAT_UNSUPPORTED ~EXT2_FEATURE_RO_COMPAT_SUPP +#define EXT2_FEATURE_INCOMPAT_UNSUPPORTED ~EXT2_FEATURE_INCOMPAT_SUPP /* * Default values for user and/or group using reserved blocks diff -u --recursive --new-file v2.4.6/linux/include/linux/ext2_fs_i.h linux/include/linux/ext2_fs_i.h --- v2.4.6/linux/include/linux/ext2_fs_i.h Tue May 11 14:37:47 1999 +++ linux/include/linux/ext2_fs_i.h Wed Jul 11 15:44:45 2001 @@ -29,13 +29,11 @@ __u32 i_file_acl; __u32 i_dir_acl; __u32 i_dtime; - __u32 not_used_1; /* FIX: not used/ 2.2 placeholder */ __u32 i_block_group; __u32 i_next_alloc_block; __u32 i_next_alloc_goal; __u32 i_prealloc_block; __u32 i_prealloc_count; - __u32 i_high_size; int i_new_inode:1; /* Is a freshly allocated inode */ }; diff -u --recursive --new-file v2.4.6/linux/include/linux/fs.h linux/include/linux/fs.h --- v2.4.6/linux/include/linux/fs.h Tue Jul 3 17:08:21 2001 +++ linux/include/linux/fs.h Fri Jul 20 12:52:18 2001 @@ -660,6 +660,7 @@ #include <linux/udf_fs_sb.h> #include <linux/ncp_fs_sb.h> #include <linux/usbdev_fs_sb.h> +#include <linux/cramfs_fs_sb.h> extern struct list_head super_blocks; @@ -711,6 +712,7 @@ struct udf_sb_info udf_sb; struct ncp_sb_info ncpfs_sb; struct usbdev_sb_info usbdevfs_sb; + struct cramfs_sb_info cramfs_sb; void *generic_sbp; } u; /* @@ -1058,6 +1060,7 @@ extern int try_to_free_buffers(struct page *, unsigned int); extern void refile_buffer(struct buffer_head * buf); +extern void end_buffer_io_sync(struct buffer_head *bh, int uptodate); /* reiserfs_writepage needs this */ extern void set_buffer_async_io(struct buffer_head *bh) ; @@ -1067,6 +1070,17 @@ #define BUF_DIRTY 2 /* Dirty buffers, not yet scheduled for write */ #define BUF_PROTECTED 3 /* Ramdisk persistent storage */ #define NR_LIST 4 + +static inline void get_bh(struct buffer_head * bh) +{ + atomic_inc(&(bh)->b_count); +} + +static inline void put_bh(struct buffer_head *bh) +{ + smp_mb__before_atomic_dec(); + atomic_dec(&bh->b_count); +} /* * This is called by bh->b_end_io() handlers when I/O has completed. diff -u --recursive --new-file v2.4.6/linux/include/linux/fs_struct.h linux/include/linux/fs_struct.h --- v2.4.6/linux/include/linux/fs_struct.h Thu Mar 15 09:56:07 2001 +++ linux/include/linux/fs_struct.h Fri Jul 13 15:10:44 2001 @@ -13,7 +13,7 @@ #define INIT_FS { \ ATOMIC_INIT(1), \ RW_LOCK_UNLOCKED, \ - 0000, \ + 0022, \ NULL, NULL, NULL, NULL, NULL, NULL \ } diff -u --recursive --new-file v2.4.6/linux/include/linux/genhd.h linux/include/linux/genhd.h --- v2.4.6/linux/include/linux/genhd.h Fri May 25 18:01:28 2001 +++ linux/include/linux/genhd.h Fri Jul 20 12:53:03 2001 @@ -51,6 +51,7 @@ long start_sect; long nr_sects; devfs_handle_t de; /* primary (master) devfs entry */ + int number; /* stupid old code wastes space */ }; #define GENHD_FL_REMOVABLE 1 diff -u --recursive --new-file v2.4.6/linux/include/linux/hdreg.h linux/include/linux/hdreg.h --- v2.4.6/linux/include/linux/hdreg.h Fri May 25 18:01:27 2001 +++ linux/include/linux/hdreg.h Fri Jul 20 12:52:18 2001 @@ -98,6 +98,7 @@ #define SMART_IMMEDIATE_OFFLINE 0xd4 #define SMART_READ_LOG_SECTOR 0xd5 #define SMART_WRITE_LOG_SECTOR 0xd6 +#define SMART_WRITE_THRESHOLDS 0xd7 #define SMART_ENABLE 0xd8 #define SMART_DISABLE 0xd9 #define SMART_STATUS 0xda @@ -159,6 +160,7 @@ #define ABRT_ERR 0x04 /* Command aborted */ #define MCR_ERR 0x08 /* media change request */ #define ID_ERR 0x10 /* ID field not found */ +#define MC_ERR 0x20 /* media changed */ #define ECC_ERR 0x40 /* Uncorrectable ECC error */ #define BBD_ERR 0x80 /* pre-EIDE meaning: block marked bad */ #define ICRC_ERR 0x80 /* new meaning: CRC error during transfer */ @@ -174,6 +176,7 @@ #define HDIO_GETGEO 0x0301 /* get device geometry */ #define HDIO_GET_UNMASKINTR 0x0302 /* get current unmask setting */ #define HDIO_GET_MULTCOUNT 0x0304 /* get current IDE blockmode setting */ +#define HDIO_GET_QDMA 0x0305 /* get use-qdma flag */ #define HDIO_OBSOLETE_IDENTITY 0x0307 /* OBSOLETE, DO NOT USE: returns 142 bytes */ #define HDIO_GET_KEEPSETTINGS 0x0308 /* get keep-settings-on-reset flag */ #define HDIO_GET_32BIT 0x0309 /* get current io_32bit setting */ @@ -181,9 +184,13 @@ #define HDIO_GET_DMA 0x030b /* get use-dma flag */ #define HDIO_GET_NICE 0x030c /* get nice flags */ #define HDIO_GET_IDENTITY 0x030d /* get IDE identification info */ +#define HDIO_GET_WCACHE 0x030e /* get write cache mode on|off */ +#define HDIO_GET_ACOUSTIC 0x030f /* get acoustic value */ +#define HDIO_GET_BUSSTATE 0x031a /* get the bus state of the hwif */ +#define HDIO_TRISTATE_HWIF 0x031b /* OBSOLETE - use SET_BUSSTATE */ #define HDIO_DRIVE_RESET 0x031c /* execute a device reset */ -#define HDIO_TRISTATE_HWIF 0x031d /* execute a channel tristate */ +#define HDIO_DRIVE_TASKFILE 0x031d /* execute raw taskfile */ #define HDIO_DRIVE_TASK 0x031e /* execute task and special drive command */ #define HDIO_DRIVE_CMD 0x031f /* execute a special drive command */ @@ -200,6 +207,17 @@ #define HDIO_SCAN_HWIF 0x0328 /* register and (re)scan interface */ #define HDIO_SET_NICE 0x0329 /* set nice flags */ #define HDIO_UNREGISTER_HWIF 0x032a /* unregister interface */ +#define HDIO_SET_WCACHE 0x032b /* change write cache enable-disable */ +#define HDIO_SET_ACOUSTIC 0x032c /* change acoustic behavior */ +#define HDIO_SET_BUSSTATE 0x032d /* set the bus state of the hwif */ +#define HDIO_SET_QDMA 0x032e /* change use-qdma flag */ + +/* bus states */ +enum { + BUSSTATE_OFF = 0, + BUSSTATE_ON, + BUSSTATE_TRISTATE +}; /* BIG GEOMETRY */ struct hd_big_geometry { diff -u --recursive --new-file v2.4.6/linux/include/linux/ibmtr.h linux/include/linux/ibmtr.h --- v2.4.6/linux/include/linux/ibmtr.h Tue Jul 3 17:08:21 2001 +++ linux/include/linux/ibmtr.h Wed Jul 4 11:50:39 2001 @@ -6,26 +6,22 @@ /* ported to the Alpha architecture 02/20/96 (just used the HZ macro) */ -#define TR_RETRY_INTERVAL (5*HZ) /* 500 on PC = 5 s */ -#define TR_RESET_INTERVAL (HZ/20) /* 5 on PC = 50 ms */ -#define TR_BUSY_INTERVAL (HZ/5) /* 5 on PC = 200 ms */ -#define TR_SPIN_INTERVAL (3*HZ) /* 3 seconds before init timeout */ -#define TR_RETRIES 6 /* number of open retries */ +#define TR_RETRY_INTERVAL (30*HZ) /* 500 on PC = 5 s */ +#define TR_RST_TIME (HZ/20) /* 5 on PC = 50 ms */ +#define TR_BUSY_INTERVAL (HZ/5) /* 5 on PC = 200 ms */ +#define TR_SPIN_INTERVAL (3*HZ) /* 3 seconds before init timeout */ #define TR_ISA 1 #define TR_MCA 2 #define TR_ISAPNP 3 #define NOTOK 0 -#define TOKDEBUG 1 #define IBMTR_SHARED_RAM_SIZE 0x10000 #define IBMTR_IO_EXTENT 4 -#define IBMTR_MAX_ADAPTERS 2 +#define IBMTR_MAX_ADAPTERS 4 #define CHANNEL_ID 0X1F30 #define AIP 0X1F00 -#define AIPCHKSUM1 0X1F60 -#define AIPCHKSUM2 0X1FF0 #define AIPADAPTYPE 0X1FA0 #define AIPDATARATE 0X1FA2 #define AIPEARLYTOKEN 0X1FA4 @@ -35,22 +31,17 @@ #define AIP16MBDHB 0X1FAC #define AIPFID 0X1FBA -/* Note, 0xA20 == 0x220 since motherboard decodes 10 bits. I left everything - the way my documentation had it, ie: 0x0A20. */ -#define ADAPTINTCNTRL 0x02f0 /* Adapter interrupt control */ #define ADAPTRESET 0x1 /* Control Adapter reset (add to base) */ #define ADAPTRESETREL 0x2 /* Release Adapter from reset ( """) */ #define ADAPTINTREL 0x3 /* Adapter interrupt release */ -#define MMIOStartLocP 0x0a20 /* Primary adapter's starting MMIO area */ -#define MMIOStartLocA 0x0a24 /* Alternate adapter's starting MMIO area */ - #define GLOBAL_INT_ENABLE 0x02f0 /* MMIO bits 0-4 select register */ -#define RRR_EVEN 0x00 /* Shared RAM relocation registers - even and odd */ +#define RRR_EVEN 0x00 /* Shared RAM relocation registers - even and odd */ /* Used to set the starting address of shared RAM */ -/* Bits 1 through 7 of this register map to bits 13 through 19 of the shared RAM address.*/ +/* Bits 1 through 7 of this register map to bits 13 through 19 of the shared + RAM address.*/ /* ie: 0x02 sets RAM address to ...ato! issy su wazzoo !! GODZILLA!!! */ #define RRR_ODD 0x01 /* Bits 2 and 3 of this register can be read to determine shared RAM size */ @@ -59,28 +50,26 @@ #define WRBR_ODD 0x03 #define WWOR_EVEN 0x04 /* Write window open registers - even and odd */ #define WWOR_ODD 0x05 -#define WWCR_EVEN 0x06 /* Write window close registers - even and odd */ +#define WWCR_EVEN 0x06 /* Write window close registers - even and odd */ #define WWCR_ODD 0x07 /* Interrupt status registers - PC system - even and odd */ #define ISRP_EVEN 0x08 -#define TCR_INT 0x10 /* Bit 4 - Timer interrupt. The TVR_EVEN timer has +#define TCR_INT 0x10 /* Bit 4 - Timer interrupt. The TVR_EVEN timer has expired. */ -#define ERR_INT 0x08 /* Bit 3 - Error interrupt. The adapter has had an - internal error. */ +#define ERR_INT 0x08 /* Bit 3 - Error interrupt. The adapter has had an + internal error. */ #define ACCESS_INT 0x04 /* Bit 2 - Access interrupt. You have attempted to - write to an invalid area of shared RAM or an invalid - register within the MMIO. */ -/* In addition, the following bits within ISRP_EVEN can be turned on or off by you */ -/* to control the interrupt processing: */ -#define INT_IRQ 0x80 /* Bit 7 - If 0 the adapter will issue a CHCK, if 1 and - IRQ. This should normally be set (by you) to 1. */ + write to an invalid area of shared RAM + or an invalid register within the MMIO. */ +/* In addition, the following bits within ISRP_EVEN can be turned on or off */ +/* by you to control the interrupt processing: */ #define INT_ENABLE 0x40 /* Bit 6 - Interrupt enable. If 0, no interrupts will - occur. If 1, interrupts will occur normally. - Normally set to 1. */ -/* Bit 0 - Primary or alternate adapter. Set to zero if this adapter is the primary adapter,*/ -/* 1 if this adapter is the alternate adapter. */ + occur. If 1, interrupts will occur normally. + Normally set to 1. */ +/* Bit 0 - Primary or alternate adapter. Set to zero if this adapter is the + primary adapter, 1 if this adapter is the alternate adapter. */ #define ISRP_ODD 0x09 @@ -92,21 +81,21 @@ an SRB request and set the return code within the SRB. */ #define ASB_FREE_INT 0x10 /* Bit 4 - ASB free. The adapter has read the ASB - and this area can be safely reused. This interrupt - is only used if your application has set the ASB - free request bit in ISRA_ODD or if an error was - detected in your response. */ + and this area can be safely reused. This interrupt + is only used if your application has set the ASB + free request bit in ISRA_ODD or if an error was + detected in your response. */ #define ARB_CMD_INT 0x08 /* Bit 3 - ARB command. The adapter has given you a - command for action. The command is located in the - ARB area of shared memory. */ + command for action. The command is located in the + ARB area of shared memory. */ #define SSB_RESP_INT 0x04 /* Bit 2 - SSB response. The adapter has posted a - response to your SRB (the response is located in - the SSB area of shared memory). */ + response to your SRB (the response is located in + the SSB area of shared memory). */ /* Bit 1 - Bridge frame forward complete. */ -#define ISRA_EVEN 0x0A /* Interrupt status registers - adapter - even and odd */ +#define ISRA_EVEN 0x0A /*Interrupt status registers - adapter - even and odd */ /* Bit 7 - Internal parity error (on adapter's internal bus) */ /* Bit 6 - Timer interrupt pending */ /* Bit 5 - Access interrupt (attempt by adapter to access illegal address) */ @@ -114,21 +103,21 @@ /* Bit 3 - Adapter processor check status */ /* Bit 2 - Reserved */ /* Bit 1 - Adapter hardware interrupt mask (prevents internal interrupts) */ -/* Bit 0 - Adapter software interrupt mask (prevents internal software interrupts) */ +/* Bit 0 - Adapter software interrupt mask (prevents internal software ints) */ #define ISRA_ODD 0x0B -#define CMD_IN_SRB 0x20 /* Bit 5 - Indicates that you have placed a new +#define CMD_IN_SRB 0x20 /* Bit 5 - Indicates that you have placed a new command in the SRB and are ready for the adapter to process the command. */ #define RESP_IN_ASB 0x10 /* Bit 4 - Indicates that you have placed a response - (an ASB) in the shared RAM which is available for - the adapter's use. */ -/* Bit 3 - Indicates that you are ready to put an SRB in the shared RAM, but that a previous */ -/* command is still pending. The adapter will then interrupt you when the previous */ -/* command is completed */ -/* Bit 2 - Indicates that you are ready to put an ASB in the shared RAM, but that a previous */ -/* ASB is still pending. The adapter will then interrupt you when the previous ASB */ -/* is copied. */ + (an ASB) in the shared RAM which is available for + the adapter's use. */ +/* Bit 3 - Indicates that you are ready to put an SRB in the shared RAM, but + that a previous command is still pending. The adapter will then + interrupt you when the previous command is completed */ +/* Bit 2 - Indicates that you are ready to put an ASB in the shared RAM, but + that a previous ASB is still pending. The adapter will then interrupt + you when the previous ASB is copied. */ #define ARB_FREE 0x2 #define SSB_FREE 0x1 @@ -138,7 +127,7 @@ #define TVR_ODD 0x0F #define SRPR_EVEN 0x18 /* Shared RAM paging registers - even and odd */ #define SRPR_ENABLE_PAGING 0xc0 -#define SRPR_ODD 0x19 /* Not used. */ +#define SRPR_ODD 0x19 /* Not used. */ #define TOKREAD 0x60 #define TOKOR 0x40 #define TOKAND 0x20 @@ -153,7 +142,8 @@ /* MMIO bits 7-8 select area of interest.. see below */ /* 00 selects attachment control area. */ /* 01 is reserved. */ -/* 10 selects adapter identification area A containing the adapter encoded address. */ +/* 10 selects adapter identification area A containing the adapter encoded + address. */ /* 11 selects the adapter identification area B containing test patterns. */ #define PCCHANNELID 5049434F3631313039393020 @@ -165,18 +155,18 @@ #define ACA_RW 0x00 #ifdef ENABLE_PAGING -#define SET_PAGE(x) (isa_writeb((x), \ - ti->mmio + ACA_OFFSET + ACA_RW + SRPR_EVEN)) +#define SET_PAGE(x) (writeb((x), ti->mmio + ACA_OFFSET+ ACA_RW + SRPR_EVEN)) #else #define SET_PAGE(x) #endif -typedef enum { IN_PROGRESS, SUCCESS, FAILURE, CLOSED } open_state; - /* do_tok_int possible values */ #define FIRST_INT 1 #define NOT_FIRST 2 +typedef enum { CLOSED, OPEN } open_state; +//staic const char *printstate[] = { "CLOSED","OPEN"}; + struct tok_info { unsigned char irq; __u32 mmio; @@ -186,6 +176,7 @@ unsigned char token_release; unsigned char avail_shared_ram; unsigned char shared_ram_paging; + unsigned char turbo; unsigned short dhb_size4mb; unsigned short rbuf_len4; unsigned short rbuf_cnt4; @@ -196,14 +187,13 @@ unsigned short maxmtu16; /* Additions by David Morris */ unsigned char do_tok_int; - wait_queue_head_t wait_for_tok_int; wait_queue_head_t wait_for_reset; unsigned char sram_base; /* Additions by Peter De Schrijver */ unsigned char page_mask; /* mask to select RAM page to Map*/ unsigned char mapped_ram_size; /* size of RAM page */ - __u32 sram; /* Shared memory base address */ - __u32 init_srb; /* Initial System Request Block address */ + __u32 sram_virt; /* Shared memory base address */ + __u32 init_srb; /* Initial System Request Block address */ __u32 srb; /* System Request Block address */ __u32 ssb; /* System Status Block address */ __u32 arb; /* Adapter Request Block address */ @@ -217,14 +207,15 @@ unsigned short global_int_enable; struct sk_buff *current_skb; struct net_device_stats tr_stats; - unsigned char auto_ringspeedsave; - open_state open_status; + unsigned char auto_speedsave; + open_state open_status, sap_status; + enum {MANUAL, AUTOMATIC} open_mode; + enum {FAIL, RESTART, REOPEN} open_action; + enum {NO, YES} open_failure; unsigned char readlog_pending; unsigned short adapter_int_enable; /* Adapter-specific int enable */ struct timer_list tr_timer; unsigned char ring_speed; - __u32 func_addr; - unsigned int retry_count; spinlock_t lock; /* SMP protection */ }; @@ -311,18 +302,6 @@ unsigned char product_id[18]; }; -struct srb_open_response { - unsigned char command; - unsigned char reserved1; - unsigned char ret_code; - unsigned char reserved2[3]; - __u16 error_code; - __u16 asb_addr; - __u16 srb_addr; - __u16 arb_addr; - __u16 ssb_addr; -}; - struct dlc_open_sap { unsigned char command; unsigned char reserved1; @@ -353,49 +332,6 @@ __u16 station_id; }; -struct srb_interrupt { - unsigned char command; - unsigned char cmd_corr; - unsigned char ret_code; -}; - -struct srb_read_log { - unsigned char command; - unsigned char reserved1; - unsigned char ret_code; - unsigned char reserved2; - unsigned char line_errors; - unsigned char internal_errors; - unsigned char burst_errors; - unsigned char A_C_errors; - unsigned char abort_delimiters; - unsigned char reserved3; - unsigned char lost_frames; - unsigned char recv_congest_count; - unsigned char frame_copied_errors; - unsigned char frequency_errors; - unsigned char token_errors; -}; - -struct asb_xmit_resp { - unsigned char command; - unsigned char cmd_corr; - unsigned char ret_code; - unsigned char reserved; - __u16 station_id; - __u16 frame_length; - unsigned char hdr_length; - unsigned char rsap_value; -}; - -struct arb_xmit_req { - unsigned char command; - unsigned char cmd_corr; - unsigned char reserved1[2]; - __u16 station_id; - __u16 dhb_address; -}; - struct arb_rec_req { unsigned char command; unsigned char reserved1[3]; @@ -417,36 +353,14 @@ }; struct rec_buf { - /* unsigned char reserved1[2]; */ + unsigned char reserved1[2]; __u16 buf_ptr; unsigned char reserved2; + unsigned char receive_fs; __u16 buf_len; unsigned char data[0]; }; -struct arb_dlc_status { - unsigned char command; - unsigned char reserved1[3]; - __u16 station_id; - __u16 status; - unsigned char frmr_data[5]; - unsigned char access_prio; - unsigned char rem_addr[TR_ALEN]; - unsigned char rsap_value; -}; - -struct arb_ring_stat_change { - unsigned char command; - unsigned char reserved1[5]; - __u16 ring_status; -}; - -struct srb_close_adapter { - unsigned char command; - unsigned char reserved1; - unsigned char ret_code; -}; - struct srb_set_funct_addr { unsigned char command; unsigned char reserved1; @@ -455,4 +369,4 @@ unsigned char funct_address[4]; }; -#endif /* __LINUX_IBMTR_H__ */ +#endif diff -u --recursive --new-file v2.4.6/linux/include/linux/if_arp.h linux/include/linux/if_arp.h --- v2.4.6/linux/include/linux/if_arp.h Tue Jul 3 17:08:21 2001 +++ linux/include/linux/if_arp.h Fri Jul 20 12:53:03 2001 @@ -38,6 +38,7 @@ #define ARPHRD_DLCI 15 /* Frame Relay DLCI */ #define ARPHRD_ATM 19 /* ATM */ #define ARPHRD_METRICOM 23 /* Metricom STRIP (new IANA id) */ +#define ARPHRD_IEEE1394 24 /* IEEE 1394 IPv4 - RFC 2734 */ /* Dummy types for non ARP hardware */ #define ARPHRD_SLIP 256 diff -u --recursive --new-file v2.4.6/linux/include/linux/if_pppox.h linux/include/linux/if_pppox.h --- v2.4.6/linux/include/linux/if_pppox.h Fri May 25 18:02:48 2001 +++ linux/include/linux/if_pppox.h Fri Jul 20 12:53:06 2001 @@ -97,8 +97,15 @@ #define PTT_GEN_ERR __constant_htons(0x0203) struct pppoe_hdr { +#if defined(__LITTLE_ENDIAN_BITFIELD) __u8 ver : 4; __u8 type : 4; +#elif defined(__BIG_ENDIAN_BITFIELD) + __u8 type : 4; + __u8 ver : 4; +#else +#error "Please fix <asm/byteorder.h>" +#endif __u8 code; __u16 sid; __u16 length; diff -u --recursive --new-file v2.4.6/linux/include/linux/interrupt.h linux/include/linux/interrupt.h --- v2.4.6/linux/include/linux/interrupt.h Tue Jul 3 17:08:21 2001 +++ linux/include/linux/interrupt.h Fri Jul 20 12:52:18 2001 @@ -73,8 +73,9 @@ asmlinkage void do_softirq(void); extern void open_softirq(int nr, void (*action)(struct softirq_action*), void *data); - extern void softirq_init(void); +extern void FASTCALL(cpu_raise_softirq(unsigned int cpu, unsigned int nr)); +extern void FASTCALL(raise_softirq(unsigned int nr)); @@ -129,7 +130,7 @@ extern struct tasklet_head tasklet_hi_vec[NR_CPUS]; #define tasklet_trylock(t) (!test_and_set_bit(TASKLET_STATE_RUN, &(t)->state)) -#define tasklet_unlock(t) clear_bit(TASKLET_STATE_RUN, &(t)->state) +#define tasklet_unlock(t) do { smp_mb__before_clear_bit(); clear_bit(TASKLET_STATE_RUN, &(t)->state); } while(0) #define tasklet_unlock_wait(t) while (test_bit(TASKLET_STATE_RUN, &(t)->state)) { barrier(); } extern void tasklet_schedule(struct tasklet_struct *t); diff -u --recursive --new-file v2.4.6/linux/include/linux/irq_cpustat.h linux/include/linux/irq_cpustat.h --- v2.4.6/linux/include/linux/irq_cpustat.h Tue Jul 3 17:08:21 2001 +++ linux/include/linux/irq_cpustat.h Fri Jul 20 12:52:18 2001 @@ -30,6 +30,7 @@ #define local_irq_count(cpu) __IRQ_STAT((cpu), __local_irq_count) #define local_bh_count(cpu) __IRQ_STAT((cpu), __local_bh_count) #define syscall_count(cpu) __IRQ_STAT((cpu), __syscall_count) +#define ksoftirqd_task(cpu) __IRQ_STAT((cpu), __ksoftirqd_task) /* arch dependent irq_stat fields */ #define nmi_count(cpu) __IRQ_STAT((cpu), __nmi_count) /* i386, ia64 */ diff -u --recursive --new-file v2.4.6/linux/include/linux/isdnif.h linux/include/linux/isdnif.h --- v2.4.6/linux/include/linux/isdnif.h Tue Jul 3 17:08:22 2001 +++ linux/include/linux/isdnif.h Fri Jul 6 17:01:06 2001 @@ -1,4 +1,4 @@ -/* $Id: isdnif.h,v 1.37.6.4 2001/06/09 15:14:19 kai Exp $ +/* $Id: isdnif.h,v 1.37.6.5 2001/06/11 22:08:38 kai Exp $ * Linux ISDN subsystem * diff -u --recursive --new-file v2.4.6/linux/include/linux/locks.h linux/include/linux/locks.h --- v2.4.6/linux/include/linux/locks.h Fri May 25 18:02:03 2001 +++ linux/include/linux/locks.h Fri Jul 20 12:52:24 2001 @@ -26,13 +26,7 @@ __wait_on_buffer(bh); } -extern inline void unlock_buffer(struct buffer_head *bh) -{ - clear_bit(BH_Lock, &bh->b_state); - smp_mb__after_clear_bit(); - if (waitqueue_active(&bh->b_wait)) - wake_up(&bh->b_wait); -} +extern void unlock_buffer(struct buffer_head *bh); /* * super-block locking. Again, interrupts may only unlock diff -u --recursive --new-file v2.4.6/linux/include/linux/lvm.h linux/include/linux/lvm.h --- v2.4.6/linux/include/linux/lvm.h Fri Feb 16 16:06:17 2001 +++ linux/include/linux/lvm.h Wed Jul 11 16:35:37 2001 @@ -299,7 +299,7 @@ #define LVM_SNAPSHOT_MAX_CHUNK 1024 /* 1024 KB */ #define LVM_SNAPSHOT_DEF_CHUNK 64 /* 64 KB */ -#define LVM_SNAPSHOT_MIN_CHUNK 1 /* 1 KB */ +#define LVM_SNAPSHOT_MIN_CHUNK (PAGE_SIZE/1024) /* 4 or 8 KB */ #define UNDEF -1 #define FALSE 0 @@ -585,7 +585,7 @@ } le_remap_req_t; typedef struct lv_bmap { - ulong lv_block; + uint32_t lv_block; dev_t lv_dev; } lv_bmap_t; diff -u --recursive --new-file v2.4.6/linux/include/linux/meye.h linux/include/linux/meye.h --- v2.4.6/linux/include/linux/meye.h Wed Dec 31 16:00:00 1969 +++ linux/include/linux/meye.h Wed Jul 4 14:41:33 2001 @@ -0,0 +1,57 @@ +/* + * Motion Eye video4linux driver for Sony Vaio PictureBook + * + * Copyright (C) 2001 Stelian Pop <stelian.pop@fr.alcove.com>, Alcôve + * + * Copyright (C) 2000 Andrew Tridgell <tridge@valinux.com> + * + * Earlier work by Werner Almesberger, Paul `Rusty' Russell and Paul Mackerras. + * + * Some parts borrowed from various video4linux drivers, especially + * bttv-driver.c and zoran.c, see original files for credits. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef _MEYE_H_ +#define _MEYE_H_ + +/****************************************************************************/ +/* Private API for handling mjpeg capture / playback. */ +/****************************************************************************/ + +struct meye_params { + unsigned char subsample; + unsigned char quality; + unsigned char sharpness; + unsigned char agc; + unsigned char picture; + unsigned char framerate; +}; + +/* query the extended parameters */ +#define MEYEIOC_G_PARAMS _IOR ('v', BASE_VIDIOCPRIVATE+0, struct meye_params) +/* set the extended parameters */ +#define MEYEIOC_S_PARAMS _IOW ('v', BASE_VIDIOCPRIVATE+1, struct meye_params) +/* queue a buffer for mjpeg capture */ +#define MEYEIOC_QBUF_CAPT _IOW ('v', BASE_VIDIOCPRIVATE+2, int) +/* sync a previously queued mjpeg buffer */ +#define MEYEIOC_SYNC _IOWR('v', BASE_VIDIOCPRIVATE+3, int) +/* get a still uncompressed snapshot */ +#define MEYEIOC_STILLCAPT _IO ('v', BASE_VIDIOCPRIVATE+4) +/* get a jpeg compressed snapshot */ +#define MEYEIOC_STILLJCAPT _IOR ('v', BASE_VIDIOCPRIVATE+5, int) + +#endif diff -u --recursive --new-file v2.4.6/linux/include/linux/mm.h linux/include/linux/mm.h --- v2.4.6/linux/include/linux/mm.h Tue Jul 3 17:08:22 2001 +++ linux/include/linux/mm.h Fri Jul 20 12:52:18 2001 @@ -442,6 +442,7 @@ extern int access_process_vm(struct task_struct *tsk, unsigned long addr, void *buf, int len, int write); extern int ptrace_readdata(struct task_struct *tsk, unsigned long src, char *dst, int len); extern int ptrace_writedata(struct task_struct *tsk, char * src, unsigned long dst, int len); +extern int ptrace_attach(struct task_struct *tsk); /* * On a two-level page table, this ends up being trivial. Thus the diff -u --recursive --new-file v2.4.6/linux/include/linux/mtd/cfi.h linux/include/linux/mtd/cfi.h --- v2.4.6/linux/include/linux/mtd/cfi.h Tue Jul 3 17:08:22 2001 +++ linux/include/linux/mtd/cfi.h Fri Jul 20 12:50:24 2001 @@ -1,7 +1,7 @@ /* Common Flash Interface structures * See http://support.intel.com/design/flash/technote/index.htm - * $Id: cfi.h,v 1.21 2001/06/03 01:32:57 nico Exp $ + * $Id: cfi.h,v 1.22 2001/07/06 09:29:07 dwmw2 Exp $ */ #ifndef __MTD_CFI_H__ @@ -10,6 +10,7 @@ #include <linux/config.h> #include <linux/delay.h> #include <linux/types.h> +#include <linux/interrupt.h> #include <linux/mtd/flashchip.h> #include <linux/mtd/cfi_endian.h> diff -u --recursive --new-file v2.4.6/linux/include/linux/netdevice.h linux/include/linux/netdevice.h --- v2.4.6/linux/include/linux/netdevice.h Fri May 25 18:02:01 2001 +++ linux/include/linux/netdevice.h Fri Jul 20 12:53:00 2001 @@ -64,7 +64,7 @@ #endif -#define MAX_ADDR_LEN 7 /* Largest hardware address length */ +#define MAX_ADDR_LEN 8 /* Largest hardware address length */ /* * Compute the worst case header length according to the protocols @@ -487,7 +487,7 @@ local_irq_save(flags); dev->next_sched = softnet_data[cpu].output_queue; softnet_data[cpu].output_queue = dev; - __cpu_raise_softirq(cpu, NET_TX_SOFTIRQ); + cpu_raise_softirq(cpu, NET_TX_SOFTIRQ); local_irq_restore(flags); } } @@ -536,7 +536,7 @@ local_irq_save(flags); skb->next = softnet_data[cpu].completion_queue; softnet_data[cpu].completion_queue = skb; - __cpu_raise_softirq(cpu, NET_TX_SOFTIRQ); + cpu_raise_softirq(cpu, NET_TX_SOFTIRQ); local_irq_restore(flags); } } diff -u --recursive --new-file v2.4.6/linux/include/linux/netlink.h linux/include/linux/netlink.h --- v2.4.6/linux/include/linux/netlink.h Sun Nov 12 20:37:17 2000 +++ linux/include/linux/netlink.h Tue Jul 10 16:11:43 2001 @@ -34,7 +34,7 @@ #define NLM_F_REQUEST 1 /* It is request message. */ #define NLM_F_MULTI 2 /* Multipart message, terminated by NLMSG_DONE */ -#define NLM_F_ACK 4 /* If succeed, reply with ack */ +#define NLM_F_ACK 4 /* Reply with ack, with zero or error code */ #define NLM_F_ECHO 8 /* Echo this request */ /* Modifiers to GET request */ diff -u --recursive --new-file v2.4.6/linux/include/linux/nls.h linux/include/linux/nls.h --- v2.4.6/linux/include/linux/nls.h Fri May 25 18:01:58 2001 +++ linux/include/linux/nls.h Fri Jul 20 12:53:03 2001 @@ -1,3 +1,6 @@ +#ifndef _LINUX_NLS_H +#define _LINUX_NLS_H + #include <linux/init.h> /* unicode character */ @@ -28,3 +31,6 @@ extern int utf8_mbstowcs(wchar_t *, const __u8 *, int); extern int utf8_wctomb(__u8 *, wchar_t, int); extern int utf8_wcstombs(__u8 *, const wchar_t *, int); + +#endif /* _LINUX_NLS_H */ + diff -u --recursive --new-file v2.4.6/linux/include/linux/ntfs_fs_i.h linux/include/linux/ntfs_fs_i.h --- v2.4.6/linux/include/linux/ntfs_fs_i.h Wed Apr 18 11:49:12 2001 +++ linux/include/linux/ntfs_fs_i.h Mon Jul 16 15:14:10 2001 @@ -42,34 +42,41 @@ /* unicode character type */ #ifndef NTFS_WCHAR_T #define NTFS_WCHAR_T -typedef unsigned short ntfs_wchar_t; +typedef u16 ntfs_wchar_t; #endif /* file offset */ #ifndef NTFS_OFFSET_T #define NTFS_OFFSET_T -typedef unsigned long long ntfs_offset_t; +typedef s64 ntfs_offset_t; #endif /* UTC */ #ifndef NTFS_TIME64_T #define NTFS_TIME64_T -typedef unsigned long long ntfs_time64_t; +typedef u64 ntfs_time64_t; #endif -/* This is really unsigned long long. So we support only volumes up to 2 TB */ +/* + * This is really signed long long. So we support only volumes up to 2Tb. This + * is ok as Win2k also only uses 32-bits to store clusters. + * Whatever you do keep this a SIGNED value or a lot of NTFS users with + * corrupted filesystems will lynch you! It causes massive fs corruption when + * unsigned due to the nature of many checks relying on being performed on + * signed quantities. (AIA) + */ #ifndef NTFS_CLUSTER_T #define NTFS_CLUSTER_T -typedef unsigned int ntfs_cluster_t; +typedef s32 ntfs_cluster_t; #endif /* Definition of the NTFS in-memory inode structure. */ struct ntfs_inode_info{ unsigned long mmu_private; struct ntfs_sb_info *vol; - int i_number; /* Should be really 48 bits. */ - __u16 sequence_number; /* The current sequence number. */ - unsigned char* attr; /* Array of the attributes. */ - int attr_count; /* Size of attrs[]. */ + unsigned long i_number; /* Should be really 48 bits. */ + __u16 sequence_number; /* The current sequence number. */ + unsigned char *attr; /* Array of the attributes. */ + int attr_count; /* Size of attrs[]. */ struct ntfs_attribute *attrs; - int record_count; /* Size of records[]. */ + int record_count; /* Size of records[]. */ int *records; /* Array of the record numbers of the $Mft whose * attributes have been inserted in the inode. */ union { diff -u --recursive --new-file v2.4.6/linux/include/linux/ntfs_fs_sb.h linux/include/linux/ntfs_fs_sb.h --- v2.4.6/linux/include/linux/ntfs_fs_sb.h Wed Apr 18 11:49:12 2001 +++ linux/include/linux/ntfs_fs_sb.h Mon Jul 16 15:14:10 2001 @@ -1,6 +1,8 @@ #ifndef _LINUX_NTFS_FS_SB_H #define _LINUX_NTFS_FS_SB_H +typedef __s64 LCN; + struct ntfs_sb_info{ /* Configuration provided by user at mount time. */ ntfs_uid_t uid; @@ -26,14 +28,16 @@ ntfs_u32 at_bitmap; ntfs_u32 at_symlink; /* aka SYMBOLIC_LINK or REPARSE_POINT */ /* Data read / calculated from the boot file. */ - int blocksize; - int clusterfactorbits; - int clustersize; - int mft_recordsize; + int sector_size; + int cluster_size; + int cluster_size_bits; int mft_clusters_per_record; - int index_recordsize; + int mft_record_size; + int mft_record_size_bits; int index_clusters_per_record; - int mft_cluster; + int index_record_size; + int index_record_size_bits; + LCN mft_lcn; /* Data read from special files. */ unsigned char *mft; unsigned short *upcase; @@ -43,6 +47,7 @@ struct ntfs_inode_info *mftmirr; struct ntfs_inode_info *bitmap; struct super_block *sb; + unsigned char ino_flags; }; #endif diff -u --recursive --new-file v2.4.6/linux/include/linux/parport.h linux/include/linux/parport.h --- v2.4.6/linux/include/linux/parport.h Sat May 19 18:07:04 2001 +++ linux/include/linux/parport.h Tue Jul 10 16:07:46 2001 @@ -22,6 +22,7 @@ #define PARPORT_DMA_NOFIFO -3 #define PARPORT_DISABLE -2 #define PARPORT_IRQ_PROBEONLY -3 +#define PARPORT_IOHI_AUTO -1 #define PARPORT_CONTROL_STROBE 0x1 #define PARPORT_CONTROL_AUTOFD 0x2 diff -u --recursive --new-file v2.4.6/linux/include/linux/pci.h linux/include/linux/pci.h --- v2.4.6/linux/include/linux/pci.h Tue Jul 3 17:08:22 2001 +++ linux/include/linux/pci.h Fri Jul 20 12:52:38 2001 @@ -680,13 +680,16 @@ #if defined(CONFIG_HOTPLUG) && !defined(MODULE) if (rc == 0) return 0; +#else + if (rc == 0) + rc = -ENODEV; #endif /* if we get here, we need to clean up pci driver instance * and return some sort of error */ pci_unregister_driver (drv); - return -ENODEV; + return rc; } #endif /* !CONFIG_PCI */ diff -u --recursive --new-file v2.4.6/linux/include/linux/prctl.h linux/include/linux/prctl.h --- v2.4.6/linux/include/linux/prctl.h Sun Mar 19 11:15:32 2000 +++ linux/include/linux/prctl.h Thu Jul 19 20:39:57 2001 @@ -6,7 +6,7 @@ #define PR_SET_PDEATHSIG 1 /* Second arg is a signal */ #define PR_GET_PDEATHSIG 2 /* Second arg is a ptr to return the signal */ -/* Get/set current->dumpable */ +/* Get/set current->mm->dumpable */ #define PR_GET_DUMPABLE 3 #define PR_SET_DUMPABLE 4 diff -u --recursive --new-file v2.4.6/linux/include/linux/proc_fs.h linux/include/linux/proc_fs.h --- v2.4.6/linux/include/linux/proc_fs.h Fri May 25 18:01:31 2001 +++ linux/include/linux/proc_fs.h Fri Jul 20 12:52:20 2001 @@ -171,6 +171,8 @@ #else +#define proc_root_driver NULL + static inline struct proc_dir_entry *proc_net_create(const char *name, mode_t mode, get_info_t *get_info) {return NULL;} static inline void proc_net_remove(const char *name) {} diff -u --recursive --new-file v2.4.6/linux/include/linux/reiserfs_fs.h linux/include/linux/reiserfs_fs.h --- v2.4.6/linux/include/linux/reiserfs_fs.h Tue Jul 3 17:08:22 2001 +++ linux/include/linux/reiserfs_fs.h Wed Jul 18 07:46:02 2001 @@ -65,6 +65,9 @@ /* enable journalling */ #define ENABLE_JOURNAL +#define USE_INODE_GENERATION_COUNTER + + #ifdef __KERNEL__ /* #define REISERFS_CHECK */ @@ -708,6 +711,7 @@ __u32 sd_blocks; union { __u32 sd_rdev; + __u32 sd_generation; //__u32 sd_first_direct_byte; /* first byte of file which is stored in a direct item: except that if it equals 1 @@ -1102,7 +1106,7 @@ #define PATH_H_PATH_OFFSET(p_s_path, n_h) ((p_s_path)->path_length - (n_h)) -#define get_bh(path) PATH_PLAST_BUFFER(path) +#define get_last_bh(path) PATH_PLAST_BUFFER(path) #define get_ih(path) PATH_PITEM_HEAD(path) #define get_item_pos(path) PATH_LAST_POSITION(path) #define get_item(path) ((void *)B_N_PITEM(PATH_PLAST_BUFFER(path), PATH_LAST_POSITION (path))) @@ -1539,29 +1543,6 @@ __u32 j_last_flush_trans_id ; /* id of last fully flushed transaction */ __u32 j_first_unflushed_offset ; /* offset in the log of where to start replay after a crash */ __u32 j_mount_id ; -} ; - -/* these are used to keep flush pages that contain converted direct items. -** if the page is not flushed before the transaction that converted it -** is committed, we risk losing data -** -** note, while a page is in this list, its counter is incremented. -*/ -struct reiserfs_page_list { - struct reiserfs_page_list *next ; - struct reiserfs_page_list *prev ; - struct page *page ; - unsigned long blocknr ; /* block number holding converted data */ - - /* if a transaction writer has the page locked the flush_page_list - ** function doesn't need to (and can't) get the lock while flushing - ** the page. do_not_lock needs to be set by anyone who calls journal_end - ** with a page lock held. They have to look in the inode and see - ** if the inode has the page they have locked in the flush list. - ** - ** this sucks. - */ - int do_not_lock ; } ; extern task_queue reiserfs_commit_thread_tq ; diff -u --recursive --new-file v2.4.6/linux/include/linux/reiserfs_fs_i.h linux/include/linux/reiserfs_fs_i.h --- v2.4.6/linux/include/linux/reiserfs_fs_i.h Fri Apr 27 14:18:08 2001 +++ linux/include/linux/reiserfs_fs_i.h Wed Jul 18 07:46:02 2001 @@ -3,11 +3,6 @@ #include <linux/list.h> -/* these are used to keep track of the pages that need -** flushing before the current transaction can commit -*/ -struct reiserfs_page_list ; - struct reiserfs_inode_info { __u32 i_key [4];/* key is still 4 32 bit integers */ @@ -21,21 +16,6 @@ int i_pack_on_close ; // file might need tail packing on close __u32 i_first_direct_byte; // offset of first byte stored in direct item. - - /* pointer to the page that must be flushed before - ** the current transaction can commit. - ** - ** this pointer is only used when the tail is converted back into - ** a direct item, or the file is deleted - */ - struct reiserfs_page_list *i_converted_page ; - - /* we save the id of the transaction when we did the direct->indirect - ** conversion. That allows us to flush the buffers to disk - ** without having to update this inode to zero out the converted - ** page variable - */ - int i_conversion_trans_id ; /* My guess is this contains the first unused block of a sequence of diff -u --recursive --new-file v2.4.6/linux/include/linux/reiserfs_fs_sb.h linux/include/linux/reiserfs_fs_sb.h --- v2.4.6/linux/include/linux/reiserfs_fs_sb.h Fri May 25 18:01:28 2001 +++ linux/include/linux/reiserfs_fs_sb.h Fri Jul 20 12:52:18 2001 @@ -60,7 +60,8 @@ don't need to save bytes in the superblock. -Hans */ __u16 s_reserved; - char s_unused[128] ; /* zero filled by mkreiserfs */ + __u32 s_inode_generation; + char s_unused[124] ; /* zero filled by mkreiserfs */ } __attribute__ ((__packed__)); #define SB_SIZE (sizeof(struct reiserfs_super_block)) @@ -249,6 +250,7 @@ int j_free_bitmap_nodes ; int j_used_bitmap_nodes ; struct list_head j_bitmap_nodes ; + struct inode j_dummy_inode ; struct reiserfs_list_bitmap j_list_bitmap[JOURNAL_NUM_BITMAPS] ; /* array of bitmaps to record the deleted blocks */ struct reiserfs_journal_list j_journal_list[JOURNAL_LIST_COUNT] ; /* array of all the journal lists */ struct reiserfs_journal_cnode *j_hash_table[JOURNAL_HASH_SIZE] ; /* hash table for real buffer heads in current trans */ diff -u --recursive --new-file v2.4.6/linux/include/linux/sched.h linux/include/linux/sched.h --- v2.4.6/linux/include/linux/sched.h Fri May 25 18:01:28 2001 +++ linux/include/linux/sched.h Fri Jul 20 12:52:18 2001 @@ -124,6 +124,8 @@ int sched_priority; }; +struct completion; + #ifdef __KERNEL__ #include <linux/spinlock.h> @@ -224,6 +226,8 @@ unsigned long cpu_vm_mask; unsigned long swap_address; + unsigned dumpable:1; + /* Architecture-specific MM context */ mm_context_t context; }; @@ -322,7 +326,6 @@ int pdeath_signal; /* The signal sent when the parent dies */ /* ??? */ unsigned long personality; - int dumpable:1; int did_exec:1; pid_t pid; pid_t pgrp; @@ -344,7 +347,7 @@ struct task_struct **pidhash_pprev; wait_queue_head_t wait_chldexit; /* for wait4() */ - struct semaphore *vfork_sem; /* for vfork() */ + struct completion *vfork_done; /* for vfork() */ unsigned long rt_priority; unsigned long it_real_value, it_prof_value, it_virt_value; unsigned long it_real_incr, it_prof_incr, it_virt_incr; @@ -412,7 +415,6 @@ #define PF_DUMPCORE 0x00000200 /* dumped core */ #define PF_SIGNALED 0x00000400 /* killed by a signal */ #define PF_MEMALLOC 0x00000800 /* Allocating memory */ -#define PF_VFORK 0x00001000 /* Wake up parent in mm_release */ #define PF_USEDFPU 0x00100000 /* task used FPU this quantum (SMP) */ diff -u --recursive --new-file v2.4.6/linux/include/linux/serialP.h linux/include/linux/serialP.h --- v2.4.6/linux/include/linux/serialP.h Fri May 25 18:02:51 2001 +++ linux/include/linux/serialP.h Fri Jul 20 12:53:55 2001 @@ -142,10 +142,6 @@ */ struct pci_dev; struct pci_board { - unsigned short vendor; - unsigned short device; - unsigned short subvendor; - unsigned short subdevice; int flags; int num_ports; int base_baud; diff -u --recursive --new-file v2.4.6/linux/include/linux/skbuff.h linux/include/linux/skbuff.h --- v2.4.6/linux/include/linux/skbuff.h Fri May 25 18:01:43 2001 +++ linux/include/linux/skbuff.h Fri Jul 20 12:52:24 2001 @@ -1124,6 +1124,7 @@ extern unsigned int skb_checksum(const struct sk_buff *skb, int offset, int len, unsigned int csum); extern int skb_copy_bits(const struct sk_buff *skb, int offset, void *to, int len); extern unsigned int skb_copy_and_csum_bits(const struct sk_buff *skb, int offset, u8 *to, int len, unsigned int csum); +extern void skb_copy_and_csum_dev(const struct sk_buff *skb, u8 *to); extern void skb_init(void); extern void skb_add_mtu(int mtu); diff -u --recursive --new-file v2.4.6/linux/include/linux/sonypi.h linux/include/linux/sonypi.h --- v2.4.6/linux/include/linux/sonypi.h Wed Dec 31 16:00:00 1969 +++ linux/include/linux/sonypi.h Wed Jul 4 14:41:33 2001 @@ -0,0 +1,103 @@ +/* + * Sony Programmable I/O Control Device driver for VAIO + * + * Copyright (C) 2001 Stelian Pop <stelian.pop@fr.alcove.com>, Alcôve + * + * Copyright (C) 2001 Michael Ashley <m.ashley@unsw.edu.au> + * + * Copyright (C) 2001 Junichi Morita <jun1m@mars.dti.ne.jp> + * + * Copyright (C) 2000 Takaya Kinjo <t-kinjo@tc4.so-net.ne.jp> + * + * Copyright (C) 2000 Andrew Tridgell <tridge@valinux.com> + * + * Earlier work by Werner Almesberger, Paul `Rusty' Russell and Paul Mackerras. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef _SONYPI_H_ +#define _SONYPI_H_ + +#include <linux/types.h> + +/* events the user application reading /dev/sonypi can use */ + +#define SONYPI_EVENT_JOGDIAL_DOWN 1 +#define SONYPI_EVENT_JOGDIAL_UP 2 +#define SONYPI_EVENT_JOGDIAL_DOWN_PRESSED 3 +#define SONYPI_EVENT_JOGDIAL_UP_PRESSED 4 +#define SONYPI_EVENT_JOGDIAL_PRESSED 5 +#define SONYPI_EVENT_JOGDIAL_RELEASED 6 +#define SONYPI_EVENT_CAPTURE_PRESSED 7 +#define SONYPI_EVENT_CAPTURE_RELEASED 8 +#define SONYPI_EVENT_CAPTURE_PARTIALPRESSED 9 +#define SONYPI_EVENT_CAPTURE_PARTIALRELEASED 10 +#define SONYPI_EVENT_FNKEY_ESC 11 +#define SONYPI_EVENT_FNKEY_F1 12 +#define SONYPI_EVENT_FNKEY_F2 13 +#define SONYPI_EVENT_FNKEY_F3 14 +#define SONYPI_EVENT_FNKEY_F4 15 +#define SONYPI_EVENT_FNKEY_F5 16 +#define SONYPI_EVENT_FNKEY_F6 17 +#define SONYPI_EVENT_FNKEY_F7 18 +#define SONYPI_EVENT_FNKEY_F8 19 +#define SONYPI_EVENT_FNKEY_F9 20 +#define SONYPI_EVENT_FNKEY_F10 21 +#define SONYPI_EVENT_FNKEY_F11 22 +#define SONYPI_EVENT_FNKEY_F12 23 +#define SONYPI_EVENT_FNKEY_1 24 +#define SONYPI_EVENT_FNKEY_2 25 +#define SONYPI_EVENT_FNKEY_D 26 +#define SONYPI_EVENT_FNKEY_E 27 +#define SONYPI_EVENT_FNKEY_F 28 +#define SONYPI_EVENT_FNKEY_S 29 +#define SONYPI_EVENT_FNKEY_B 30 +#define SONYPI_EVENT_BLUETOOTH_PRESSED 31 + +/* brightness etc. ioctls */ +#define SONYPI_IOCGBRT _IOR('v', 0, __u8) +#define SONYPI_IOCSBRT _IOW('v', 0, __u8) + +#ifdef __KERNEL__ + +/* used only for communication between v4l and sonypi */ + +#define SONYPI_COMMAND_GETCAMERA 1 +#define SONYPI_COMMAND_SETCAMERA 2 +#define SONYPI_COMMAND_GETCAMERABRIGHTNESS 3 +#define SONYPI_COMMAND_SETCAMERABRIGHTNESS 4 +#define SONYPI_COMMAND_GETCAMERACONTRAST 5 +#define SONYPI_COMMAND_SETCAMERACONTRAST 6 +#define SONYPI_COMMAND_GETCAMERAHUE 7 +#define SONYPI_COMMAND_SETCAMERAHUE 8 +#define SONYPI_COMMAND_GETCAMERACOLOR 9 +#define SONYPI_COMMAND_SETCAMERACOLOR 10 +#define SONYPI_COMMAND_GETCAMERASHARPNESS 11 +#define SONYPI_COMMAND_SETCAMERASHARPNESS 12 +#define SONYPI_COMMAND_GETCAMERAPICTURE 13 +#define SONYPI_COMMAND_SETCAMERAPICTURE 14 +#define SONYPI_COMMAND_GETCAMERAAGC 15 +#define SONYPI_COMMAND_SETCAMERAAGC 16 +#define SONYPI_COMMAND_GETCAMERADIRECTION 17 +#define SONYPI_COMMAND_GETCAMERAROMVERSION 18 +#define SONYPI_COMMAND_GETCAMERAREVISION 19 + +u8 sonypi_camera_command(int command, u8 value); + +#endif /* __KERNEL__ */ + +#endif /* _SONYPI_H_ */ diff -u --recursive --new-file v2.4.6/linux/include/linux/spinlock.h linux/include/linux/spinlock.h --- v2.4.6/linux/include/linux/spinlock.h Fri May 25 18:01:27 2001 +++ linux/include/linux/spinlock.h Fri Jul 20 12:52:18 2001 @@ -34,7 +34,8 @@ #ifdef CONFIG_SMP #include <asm/spinlock.h> -#else /* !SMP */ +#elif !defined(spin_lock_init) /* !SMP and spin_lock_init not previously + defined (e.g. by including asm/spinlock.h */ #define DEBUG_SPINLOCKS 0 /* 0 == no debugging, 1 == maintain lock state, 2 == full debug */ diff -u --recursive --new-file v2.4.6/linux/include/linux/swap.h linux/include/linux/swap.h --- v2.4.6/linux/include/linux/swap.h Tue Jul 3 17:08:22 2001 +++ linux/include/linux/swap.h Fri Jul 20 12:52:18 2001 @@ -10,11 +10,23 @@ #define MAX_SWAPFILES 8 +/* + * Magic header for a swap area. The first part of the union is + * what the swap magic looks like for the old (limited to 128MB) + * swap area format, the second part of the union adds - in the + * old reserved area - some extra information. Note that the first + * kilobyte is reserved for boot loader or disk label stuff... + * + * Having the magic at the end of the PAGE_SIZE makes detecting swap + * areas somewhat tricky on machines that support multiple page sizes. + * For 2.5 we'll probably want to move the magic to just beyond the + * bootbits... + */ union swap_header { struct { char reserved[PAGE_SIZE - 10]; - char magic[10]; + char magic[10]; /* SWAP-SPACE or SWAPSPACE2 */ } magic; struct { @@ -46,6 +58,9 @@ #define SWAP_MAP_MAX 0x7fff #define SWAP_MAP_BAD 0x8000 +/* + * The in-memory structure used to track swap areas. + */ struct swap_info_struct { unsigned int flags; kdev_t swap_device; diff -u --recursive --new-file v2.4.6/linux/include/linux/timex.h linux/include/linux/timex.h --- v2.4.6/linux/include/linux/timex.h Fri May 25 18:01:26 2001 +++ linux/include/linux/timex.h Fri Jul 20 12:52:18 2001 @@ -60,7 +60,9 @@ * OSF/1 kernel. The SHIFT_HZ define expresses the same value as the * nearest power of two in order to avoid hardware multiply operations. */ -#if HZ >= 24 && HZ < 48 +#if HZ >= 12 && HZ < 24 +# define SHIFT_HZ 4 +#elif HZ >= 24 && HZ < 48 # define SHIFT_HZ 5 #elif HZ >= 48 && HZ < 96 # define SHIFT_HZ 6 diff -u --recursive --new-file v2.4.6/linux/include/linux/tty.h linux/include/linux/tty.h --- v2.4.6/linux/include/linux/tty.h Fri May 25 18:01:28 2001 +++ linux/include/linux/tty.h Fri Jul 20 12:52:18 2001 @@ -366,6 +366,7 @@ extern int specialix_init(void); extern int espserial_init(void); extern int macserial_init(void); +extern int a2232board_init(void); extern int tty_paranoia_check(struct tty_struct *tty, kdev_t device, const char *routine); diff -u --recursive --new-file v2.4.6/linux/include/linux/usb.h linux/include/linux/usb.h --- v2.4.6/linux/include/linux/usb.h Fri May 25 18:02:43 2001 +++ linux/include/linux/usb.h Fri Jul 20 12:55:50 2001 @@ -21,6 +21,7 @@ /* * USB types */ +#define USB_TYPE_MASK (0x03 << 5) #define USB_TYPE_STANDARD (0x00 << 5) #define USB_TYPE_CLASS (0x01 << 5) #define USB_TYPE_VENDOR (0x02 << 5) @@ -595,6 +596,7 @@ int slow; /* Slow device? */ atomic_t refcnt; /* Reference count */ + struct semaphore serialize; unsigned int toggle[2]; /* one bit for each endpoint ([0] = IN, [1] = OUT) */ unsigned int halted[2]; /* endpoint halts; one bit per endpoint # & direction; */ @@ -838,6 +840,7 @@ extern struct list_head usb_driver_list; extern struct list_head usb_bus_list; +extern rwlock_t usb_bus_list_lock; /* * USB device fs stuff diff -u --recursive --new-file v2.4.6/linux/include/linux/usbdevice_fs.h linux/include/linux/usbdevice_fs.h --- v2.4.6/linux/include/linux/usbdevice_fs.h Fri May 25 18:03:10 2001 +++ linux/include/linux/usbdevice_fs.h Fri Jul 20 12:56:04 2001 @@ -162,18 +162,6 @@ #define IROOT 1 -/* - * sigh. rwsemaphores do not (yet) work from modules - */ - -#define rw_semaphore semaphore -#define init_rwsem init_MUTEX -#define down_read down -#define down_write down -#define up_read up -#define up_write up - - struct dev_state { struct list_head list; /* state list */ struct rw_semaphore devsem; /* protects modifications to dev (dev == NULL indicating disconnect) */ diff -u --recursive --new-file v2.4.6/linux/include/linux/videodev.h linux/include/linux/videodev.h --- v2.4.6/linux/include/linux/videodev.h Tue May 22 10:25:36 2001 +++ linux/include/linux/videodev.h Wed Jul 4 14:41:33 2001 @@ -375,6 +375,7 @@ #define VID_HARDWARE_W9966 29 #define VID_HARDWARE_SE401 30 /* SE401 USB webcams */ #define VID_HARDWARE_PWC 31 /* Philips webcams */ +#define VID_HARDWARE_MEYE 32 /* Sony Vaio MotionEye cameras */ /* * Initialiser list diff -u --recursive --new-file v2.4.6/linux/include/net/irda/ali-ircc.h linux/include/net/irda/ali-ircc.h --- v2.4.6/linux/include/net/irda/ali-ircc.h Wed Dec 31 16:00:00 1969 +++ linux/include/net/irda/ali-ircc.h Wed Jul 4 11:50:38 2001 @@ -0,0 +1,229 @@ +/********************************************************************* + * + * Filename: ali-ircc.h + * Version: 0.5 + * Description: Driver for the ALI M1535D and M1543C FIR Controller + * Status: Experimental. + * Author: Benjamin Kong <benjamin_kong@ali.com.tw> + * Created at: 2000/10/16 03:46PM + * Modified at: 2001/1/3 02:56PM + * Modified by: Benjamin Kong <benjamin_kong@ali.com.tw> + * + * Copyright (c) 2000 Benjamin Kong <benjamin_kong@ali.com.tw> + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + ********************************************************************/ + +#ifndef ALI_IRCC_H +#define ALI_IRCC_H + +#include <linux/time.h> + +#include <linux/spinlock.h> +#include <linux/pm.h> +#include <asm/io.h> + +/* SIR Register */ +/* Usr definition of linux/serial_reg.h */ + +/* FIR Register */ +#define BANK0 0x20 +#define BANK1 0x21 +#define BANK2 0x22 +#define BANK3 0x23 + +#define FIR_MCR 0x07 /* Master Control Register */ + +/* Bank 0 */ +#define FIR_DR 0x00 /* Alias 0, FIR Data Register (R/W) */ +#define FIR_IER 0x01 /* Alias 1, FIR Interrupt Enable Register (R/W) */ +#define FIR_IIR 0x02 /* Alias 2, FIR Interrupt Identification Register (Read only) */ +#define FIR_LCR_A 0x03 /* Alias 3, FIR Line Control Register A (R/W) */ +#define FIR_LCR_B 0x04 /* Alias 4, FIR Line Control Register B (R/W) */ +#define FIR_LSR 0x05 /* Alias 5, FIR Line Status Register (R/W) */ +#define FIR_BSR 0x06 /* Alias 6, FIR Bus Status Register (Read only) */ + + + /* Alias 1 */ + #define IER_FIFO 0x10 /* FIR FIFO Interrupt Enable */ + #define IER_TIMER 0x20 /* Timer Interrupt Enable */ + #define IER_EOM 0x40 /* End of Message Interrupt Enable */ + #define IER_ACT 0x80 /* Active Frame Interrupt Enable */ + + /* Alias 2 */ + #define IIR_FIFO 0x10 /* FIR FIFO Interrupt */ + #define IIR_TIMER 0x20 /* Timer Interrupt */ + #define IIR_EOM 0x40 /* End of Message Interrupt */ + #define IIR_ACT 0x80 /* Active Frame Interrupt */ + + /* Alias 3 */ + #define LCR_A_FIFO_RESET 0x80 /* FIFO Reset */ + + /* Alias 4 */ + #define LCR_B_BW 0x10 /* Brick Wall */ + #define LCR_B_SIP 0x20 /* SIP Enable */ + #define LCR_B_TX_MODE 0x40 /* Transmit Mode */ + #define LCR_B_RX_MODE 0x80 /* Receive Mode */ + + /* Alias 5 */ + #define LSR_FIR_LSA 0x00 /* FIR Line Status Address */ + #define LSR_FRAME_ABORT 0x08 /* Frame Abort */ + #define LSR_CRC_ERROR 0x10 /* CRC Error */ + #define LSR_SIZE_ERROR 0x20 /* Size Error */ + #define LSR_FRAME_ERROR 0x40 /* Frame Error */ + #define LSR_FIFO_UR 0x80 /* FIFO Underrun */ + #define LSR_FIFO_OR 0x80 /* FIFO Overrun */ + + /* Alias 6 */ + #define BSR_FIFO_NOT_EMPTY 0x80 /* FIFO Not Empty */ + +/* Bank 1 */ +#define FIR_CR 0x00 /* Alias 0, FIR Configuration Register (R/W) */ +#define FIR_FIFO_TR 0x01 /* Alias 1, FIR FIFO Threshold Register (R/W) */ +#define FIR_DMA_TR 0x02 /* Alias 2, FIR DMA Threshold Register (R/W) */ +#define FIR_TIMER_IIR 0x03 /* Alias 3, FIR Timer interrupt interval register (W/O) */ +#define FIR_FIFO_FR 0x03 /* Alias 3, FIR FIFO Flag register (R/O) */ +#define FIR_FIFO_RAR 0x04 /* Alias 4, FIR FIFO Read Address register (R/O) */ +#define FIR_FIFO_WAR 0x05 /* Alias 5, FIR FIFO Write Address register (R/O) */ +#define FIR_TR 0x06 /* Alias 6, Test REgister (W/O) */ + + /* Alias 0 */ + #define CR_DMA_EN 0x01 /* DMA Enable */ + #define CR_DMA_BURST 0x02 /* DMA Burst Mode */ + #define CR_TIMER_EN 0x08 /* Timer Enable */ + + /* Alias 3 */ + #define TIMER_IIR_500 0x00 /* 500 us */ + #define TIMER_IIR_1ms 0x01 /* 1 ms */ + #define TIMER_IIR_2ms 0x02 /* 2 ms */ + #define TIMER_IIR_4ms 0x03 /* 4 ms */ + +/* Bank 2 */ +#define FIR_IRDA_CR 0x00 /* Alias 0, IrDA Control Register (R/W) */ +#define FIR_BOF_CR 0x01 /* Alias 1, BOF Count Register (R/W) */ +#define FIR_BW_CR 0x02 /* Alias 2, Brick Wall Count Register (R/W) */ +#define FIR_TX_DSR_HI 0x03 /* Alias 3, TX Data Size Register (high) (R/W) */ +#define FIR_TX_DSR_LO 0x04 /* Alias 4, TX Data Size Register (low) (R/W) */ +#define FIR_RX_DSR_HI 0x05 /* Alias 5, RX Data Size Register (high) (R/W) */ +#define FIR_RX_DSR_LO 0x06 /* Alias 6, RX Data Size Register (low) (R/W) */ + + /* Alias 0 */ + #define IRDA_CR_HDLC1152 0x80 /* 1.152Mbps HDLC Select */ + #define IRDA_CR_CRC 0X40 /* CRC Select. */ + #define IRDA_CR_HDLC 0x20 /* HDLC select. */ + #define IRDA_CR_HP_MODE 0x10 /* HP mode (read only) */ + #define IRDA_CR_SD_ST 0x08 /* SD/MODE State. */ + #define IRDA_CR_FIR_SIN 0x04 /* FIR SIN Select. */ + #define IRDA_CR_ITTX_0 0x02 /* SOUT State. IRTX force to 0 */ + #define IRDA_CR_ITTX_1 0x03 /* SOUT State. IRTX force to 1 */ + +/* Bank 3 */ +#define FIR_ID_VR 0x00 /* Alias 0, FIR ID Version Register (R/O) */ +#define FIR_MODULE_CR 0x01 /* Alias 1, FIR Module Control Register (R/W) */ +#define FIR_IO_BASE_HI 0x02 /* Alias 2, FIR Higher I/O Base Address Register (R/O) */ +#define FIR_IO_BASE_LO 0x03 /* Alias 3, FIR Lower I/O Base Address Register (R/O) */ +#define FIR_IRQ_CR 0x04 /* Alias 4, FIR IRQ Channel Register (R/O) */ +#define FIR_DMA_CR 0x05 /* Alias 5, FIR DMA Channel Register (R/O) */ + +struct ali_chip { + char *name; + int cfg[2]; + unsigned char entr1; + unsigned char entr2; + unsigned char cid_index; + unsigned char cid_value; + int (*probe)(struct ali_chip *chip, chipio_t *info); + int (*init)(struct ali_chip *chip, chipio_t *info); +}; +typedef struct ali_chip ali_chip_t; + + +/* DMA modes needed */ +#define DMA_TX_MODE 0x08 /* Mem to I/O, ++, demand. */ +#define DMA_RX_MODE 0x04 /* I/O to mem, ++, demand. */ + +#define MAX_TX_WINDOW 7 +#define MAX_RX_WINDOW 7 + +#define TX_FIFO_Threshold 8 +#define RX_FIFO_Threshold 1 +#define TX_DMA_Threshold 1 +#define RX_DMA_Threshold 1 + +/* For storing entries in the status FIFO */ + +struct st_fifo_entry { + int status; + int len; +}; + +struct st_fifo { + struct st_fifo_entry entries[MAX_RX_WINDOW]; + int pending_bytes; + int head; + int tail; + int len; +}; + +struct frame_cb { + void *start; /* Start of frame in DMA mem */ + int len; /* Lenght of frame in DMA mem */ +}; + +struct tx_fifo { + struct frame_cb queue[MAX_TX_WINDOW]; /* Info about frames in queue */ + int ptr; /* Currently being sent */ + int len; /* Lenght of queue */ + int free; /* Next free slot */ + void *tail; /* Next free start in DMA mem */ +}; + +/* Private data for each instance */ +struct ali_ircc_cb { + + struct st_fifo st_fifo; /* Info about received frames */ + struct tx_fifo tx_fifo; /* Info about frames to be transmitted */ + + struct net_device *netdev; /* Yes! we are some kind of netdevice */ + struct net_device_stats stats; + + struct irlap_cb *irlap; /* The link layer we are binded to */ + struct qos_info qos; /* QoS capabilities for this device */ + + chipio_t io; /* IrDA controller information */ + iobuff_t tx_buff; /* Transmit buffer */ + iobuff_t rx_buff; /* Receive buffer */ + + __u8 ier; /* Interrupt enable register */ + + __u8 InterruptID; /* Interrupt ID */ + __u8 BusStatus; /* Bus Status */ + __u8 LineStatus; /* Line Status */ + + unsigned char rcvFramesOverflow; + + struct timeval stamp; + struct timeval now; + + spinlock_t lock; /* For serializing operations */ + + __u32 flags; /* Interface flags */ + __u32 new_speed; + int index; /* Instance index */ + + unsigned char fifo_opti_buf; + + struct pm_dev *dev; +}; + +static inline void switch_bank(int iobase, int bank) +{ + outb(bank, iobase+FIR_MCR); +} + +#endif /* ALI_IRCC_H */ diff -u --recursive --new-file v2.4.6/linux/include/net/irda/irlap.h linux/include/net/irda/irlap.h --- v2.4.6/linux/include/net/irda/irlap.h Fri May 25 17:07:20 2001 +++ linux/include/net/irda/irlap.h Wed Jul 4 11:50:38 2001 @@ -43,15 +43,8 @@ #define LAP_ADDR_HEADER 1 /* IrLAP Address Header */ #define LAP_CTRL_HEADER 1 /* IrLAP Control Header */ -#define LAP_COMP_HEADER 1 /* IrLAP Compression Header */ -#ifdef CONFIG_IRDA_COMPRESSION -# define LAP_MAX_HEADER (LAP_ADDR_HEADER + LAP_CTRL_HEADER + LAP_COMP_HEADER) -# define IRDA_COMPRESSED 1 -# define IRDA_NORMAL 0 -#else #define LAP_MAX_HEADER (LAP_ADDR_HEADER + LAP_CTRL_HEADER) -#endif #define BROADCAST 0xffffffff /* Broadcast device address */ #define CBROADCAST 0xfe /* Connection broadcast address */ @@ -68,26 +61,6 @@ #define NS_UNEXPECTED 0 #define NS_INVALID -1 -#ifdef CONFIG_IRDA_COMPRESSION - -/* - * Just some shortcuts (may give you strange compiler errors if you change - * them :-) - */ -#define irda_compress (*self->compessor.cp->compress) -#define irda_comp_free (*self->compressor.cp->comp_free) -#define irda_decompress (*self->decompressor.cp->decompress) -#define irda_decomp_free (*self->decompressor.cp->decomp_free) -#define irda_incomp (*self->decompressor.cp->incomp) - -struct irda_compressor { - irda_queue_t q; - - struct compressor *cp; - void *state; /* Not used by IrDA */ -}; -#endif - /* Main structure of IrLAP */ struct irlap_cb { irda_queue_t q; /* Must be first */ @@ -180,11 +153,6 @@ int xbofs_delay; /* Nr of XBOF's used to MTT */ int bofs_count; /* Negotiated extra BOFs */ int next_bofs; /* Negotiated extra BOFs after next frame */ - -#ifdef CONFIG_IRDA_COMPRESSION - struct irda_compressor compressor; - struct irda_compressor decompressor; -#endif /* CONFIG_IRDA_COMPRESSION */ }; extern hashbin_t *irlap; diff -u --recursive --new-file v2.4.6/linux/include/net/irda/irlap_comp.h linux/include/net/irda/irlap_comp.h --- v2.4.6/linux/include/net/irda/irlap_comp.h Mon Dec 11 13:33:20 2000 +++ linux/include/net/irda/irlap_comp.h Wed Dec 31 16:00:00 1969 @@ -1,47 +0,0 @@ -/********************************************************************* - * - * Filename: irlap_comp.h - * Version: - * Description: - * Status: Experimental. - * Author: Dag Brattli <dagb@cs.uit.no> - * Created at: Fri Oct 9 09:21:12 1998 - * Modified at: Sat Dec 12 12:23:16 1998 - * Modified by: Dag Brattli <dagb@cs.uit.no> - * - * Copyright (c) 1998 Dag Brattli, All Rights Reserved. - * - * 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. - * - * Neither Dag Brattli nor University of Tromsø admit liability nor - * provide warranty for any of this software. This material is - * provided "AS-IS" and at no charge. - * - ********************************************************************/ - -#ifndef IRLAP_COMP_H -#define IRLAP_COMP_H - -#include <linux/ppp-comp.h> - -#define CI_BZIP2 27 /* Random pick */ - -extern hashbin_t *irlap_compressors; - -int irda_register_compressor( struct compressor *cp); -void irda_unregister_compressor( struct compressor *cp); - -int irda_set_compression( struct irlap_cb *self, int proto); -void irlap_compressor_init( struct irlap_cb *self, int compress); -void irda_free_compression( struct irlap_cb *self); - -struct sk_buff *irlap_compress_frame( struct irlap_cb *self, - struct sk_buff *skb); -struct sk_buff *irlap_decompress_frame( struct irlap_cb *self, - struct sk_buff *skb); - -#endif - diff -u --recursive --new-file v2.4.6/linux/include/net/irda/qos.h linux/include/net/irda/qos.h --- v2.4.6/linux/include/net/irda/qos.h Fri May 25 18:02:38 2001 +++ linux/include/net/irda/qos.h Fri Jul 20 12:53:03 2001 @@ -43,8 +43,6 @@ #define PI_ADD_BOFS 0x85 #define PI_MIN_TURN_TIME 0x86 #define PI_LINK_DISC 0x08 -#define PI_COMPRESSION 0x07 /* Just a random pick */ - #define IR_115200_MAX 0x3f @@ -80,10 +78,6 @@ qos_value_t link_disc_time; qos_value_t power; -#ifdef CONFIG_IRDA_COMPRESSION - /* An experimental non IrDA field */ - qos_value_t compression; -#endif }; extern int sysctl_max_baud_rate; diff -u --recursive --new-file v2.4.6/linux/include/net/route.h linux/include/net/route.h --- v2.4.6/linux/include/net/route.h Fri May 25 18:02:42 2001 +++ linux/include/net/route.h Fri Jul 20 12:53:07 2001 @@ -14,6 +14,7 @@ * Alan Cox : Support for TCP parameters. * Alexey Kuznetsov: Major changes for new routing code. * Mike McLagan : Routing by source + * Robert Olsson : Added rt_cache statistics * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -90,6 +91,20 @@ __u32 o_packets; __u32 i_bytes; __u32 i_packets; +}; + +struct rt_cache_stat +{ + unsigned int in_hit; + unsigned int in_slow_tot; + unsigned int in_slow_mc; + unsigned int in_no_route; + unsigned int in_brd; + unsigned int in_martian_dst; + unsigned int in_martian_src; + unsigned int out_hit; + unsigned int out_slow_tot; + unsigned int out_slow_mc; }; extern struct ip_rt_acct *ip_rt_acct; diff -u --recursive --new-file v2.4.6/linux/include/scsi/sg.h linux/include/scsi/sg.h --- v2.4.6/linux/include/scsi/sg.h Thu Sep 21 20:48:05 2000 +++ linux/include/scsi/sg.h Wed Jul 4 15:39:28 2001 @@ -9,89 +9,43 @@ Original driver (sg.h): * Copyright (C) 1992 Lawrence Foard Version 2 and 3 extensions to driver: -* Copyright (C) 1998 - 2000 Douglas Gilbert +* Copyright (C) 1998 - 2001 Douglas Gilbert - Version: 3.1.17 (20000921) + Version: 3.1.19 (20010623) This version is for 2.4 series kernels. - Changes since 3.1.16 (20000716) - - changes for new scsi subsystem initialization - - change Scsi_Cmnd usage to Scsi_Request - - cleanup for no procfs - Changes since 3.1.15 (20000528) - - further (scatter gather) buffer length changes - Changes since 3.1.14 (20000503) - - fix aha1542 odd length buffer problem - - make multiple readers on same fd safe - Changes since 3.1.13 (20000324) - - revert change so sg_header interface doesn't send _UNKNOWN - - "discon" and "tq" in /proc/scsi/sg/devices replaced with - "bopens" and "busy"; correct duration output in procfs - - provision for SG_RESET - - lock file descriptor and request lists - Changes since 3.1.12 (20000222) - - make sg_header interface use SCSI_DATA_UNKNOWN - - add SG_DXFER_UNKNOWN define to sg interface - - stop allocating data buffers to non data transfer commands - Changes since 3.1.10 (20000123) - - make device allocation dynamic (get rid of SG_EXTRA_DEVS) - - move to sg0,sg1,sg2 rather than sga,sgb,sgc - - make sg_io_hdr_t safer across architectures - Changes since 2.1.34 (990603) and 2.3.35 (990708) - - add new interface structure: sg_io_hdr_t - - supports larger sense buffer, DMA residual count + direct IO - - add SG_IO ioctl (combines function of write() + read() ) - - remove SG_SET_MERGE_FD, UNDERRUN_FLAG + _GET_ ioctls + logic - - add proc_fs support in /proc/scsi/sg/ directory - - add queuing info into struct sg_scsi_id - - def_reserved_size can be given at driver or module load time - Changes since 2.1.33 (990521) - - implement SG_SET_RESERVED_SIZE and associated memory re-org. - - add SG_NEXT_CMD_LEN to override SCSI command lengths - - add SG_GET_VERSION_NUM to get version expressed as an integer - Changes since 2.1.32 (990501) - - fix race condition in sg_read() and sg_open() - Changes since 2.1.31 (990327) - - add ioctls SG_GET_UNDERRUN_FLAG and _SET_. Change the default - to _not_ flag underruns (affects aic7xxx driver) - - clean up logging of pointers to use %p (for 64 bit architectures) - - rework usage of get_user/copy_to_user family of kernel calls - - "disown" scsi_command blocks before releasing them + Changes since 3.1.18 (20010505) + - fix bug that caused long wait when large buffer requested + - fix leak in error case of sg_new_read() [report: Eric Barton] + - add 'online' column to /proc/scsi/sg/devices + Changes since 3.1.17 (20000921) + - add CAP_SYS_RAWIO capability for sensitive stuff + - compile in dio stuff, procfs 'allow_dio' defaulted off (0) + - make premature close and detach more robust + - lun masked into commands <= SCSI_2 + - poll() and async notification now yield POLL_HUP on detach + - various 3rd party tweaks tracking lk 2.4 internal changes Map of SG verions to the Linux kernels in which they appear: ---------- ---------------------------------- original all kernels < 2.2.6 - 2.1.31 2.2.6 and 2.2.7 - 2.1.32 2.2.8 and 2.2.9 - 2.1.34 2.2.10 to 2.2.13 - 2.1.36 2.2.14 and 2.2.15 + 2.1.38 2.2.16 + 2.1.39 2.2.17 - 2.2.19 3.0.x optional version 3 sg driver for 2.2 series - 3.1.x first appeared in lk 2.3.43 + 3.1.17 2.4.0 ++ Major new features in SG 3.x driver (cf SG 2.x drivers) - SG_IO ioctl() combines function if write() and read() - new interface (sg_io_hdr_t) but still supports old interface - scatter/gather in user space and direct IO supported -Major features in SG 2.x driver (cf original SG driver) - - per file descriptor (fd) write-read sequencing - - command queuing supported - - scatter-gather supported at kernel level allowing potentially - large transfers - - more SCSI status information returned - - asynchronous notification support added (SIGPOLL, SIGIO) - - read() can fetch by given pack_id - - uses kernel memory as appropriate for SCSI adapter being used - - single SG_BIG_BUFF replaced by per file descriptor "reserve - buffer" whose size can be manipulated by ioctls() - The term "indirect IO" refers a method by which data is DMAed into kernel buffers from the hardware and afterwards is transferred into the user space (or vice versa if you are writing). Transfer speeds of up to 20 to 30MBytes/sec have been measured using indirect IO. For faster throughputs "direct IO" which cuts out the double handling of data is required. - Direct IO is supported by the SG 3.x drivers on 2.3 series Linux kernels - (or later) and requires the use of the new interface. + Direct IO is supported by the SG 3.x drivers on 2.4 series Linux kernels + and requires the use of the new interface. Requests for direct IO with the new interface will automatically fall back to indirect IO mode if they cannot be fulfilled. An example of such a case @@ -107,6 +61,9 @@ kernel memory that is suitable for DMA may be constrained by the architecture of the SCSI adapter (e.g. ISA adapters). + ** N.B. To use direct IO 'echo 1 > /proc/scsi/sg/allow_dio' may be + needed. That pseudo file's content is defaulted to 0. ** + Documentation ============= A web site for SG device drivers can be found at: @@ -116,9 +73,10 @@ http://www.torque.net/sg/p/scsi-generic_long.txt Documentation on the changes and additions in 3.x version of the sg driver can be found at: http://www.torque.net/sg/p/scsi-generic_v3.txt - This document can also be found in the kernel source tree, probably at: + A version of this document (potentially out of date) may also be found in + the kernel source tree, probably at: /usr/src/linux/Documentation/scsi-generic.txt . - Utility and test programs are also available at that web site. + Utility and test programs are available at the sg web site. */ /* New interface introduced in the 3.x SG drivers follows */ diff -u --recursive --new-file v2.4.6/linux/init/main.c linux/init/main.c --- v2.4.6/linux/init/main.c Tue Jul 3 17:08:22 2001 +++ linux/init/main.c Thu Jul 5 11:31:58 2001 @@ -503,6 +503,21 @@ #endif /* + * We need to finalize in a non-__init function or else race conditions + * between the root thread and the init thread may cause start_kernel to + * be reaped by free_initmem before the root thread has proceeded to + * cpu_idle. + */ + +static void rest_init(void) +{ + kernel_thread(init, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGNAL); + unlock_kernel(); + current->need_resched = 1; + cpu_idle(); +} + +/* * Activate the first processor. */ @@ -523,8 +538,8 @@ trap_init(); init_IRQ(); sched_init(); - time_init(); softirq_init(); + time_init(); /* * HACK ALERT! This is early. We're enabling the console before @@ -584,10 +599,7 @@ * make syscalls (and thus be locked). */ smp_init(); - kernel_thread(init, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGNAL); - unlock_kernel(); - current->need_resched = 1; - cpu_idle(); + rest_init(); } #ifdef CONFIG_BLK_DEV_INITRD diff -u --recursive --new-file v2.4.6/linux/kernel/fork.c linux/kernel/fork.c --- v2.4.6/linux/kernel/fork.c Mon Apr 30 22:23:29 2001 +++ linux/kernel/fork.c Tue Jul 17 18:23:28 2001 @@ -18,6 +18,7 @@ #include <linux/smp_lock.h> #include <linux/module.h> #include <linux/vmalloc.h> +#include <linux/completion.h> #include <asm/pgtable.h> #include <asm/pgalloc.h> @@ -269,11 +270,12 @@ void mm_release(void) { struct task_struct *tsk = current; + struct completion *vfork_done = tsk->vfork_done; /* notify parent sleeping on vfork() */ - if (tsk->flags & PF_VFORK) { - tsk->flags &= ~PF_VFORK; - up(tsk->p_opptr->vfork_sem); + if (vfork_done) { + tsk->vfork_done = NULL; + complete(vfork_done); } } @@ -536,12 +538,10 @@ { unsigned long new_flags = p->flags; - new_flags &= ~(PF_SUPERPRIV | PF_USEDFPU | PF_VFORK); + new_flags &= ~(PF_SUPERPRIV | PF_USEDFPU); new_flags |= PF_FORKNOEXEC; if (!(clone_flags & CLONE_PTRACE)) p->ptrace = 0; - if (clone_flags & CLONE_VFORK) - new_flags |= PF_VFORK; p->flags = new_flags; } @@ -557,18 +557,22 @@ int do_fork(unsigned long clone_flags, unsigned long stack_start, struct pt_regs *regs, unsigned long stack_size) { - int retval = -ENOMEM; + int retval; struct task_struct *p; - DECLARE_MUTEX_LOCKED(sem); + struct completion vfork; + + retval = -EPERM; + /* + * CLONE_PID is only allowed for the initial SMP swapper + * calls + */ if (clone_flags & CLONE_PID) { - /* This is only allowed from the boot up thread */ if (current->pid) - return -EPERM; + goto fork_out; } - - current->vfork_sem = &sem; + retval = -ENOMEM; p = alloc_task_struct(); if (!p) goto fork_out; @@ -578,6 +582,7 @@ retval = -EAGAIN; if (atomic_read(&p->user->processes) >= p->rlim[RLIMIT_NPROC].rlim_cur) goto bad_fork_free; + atomic_inc(&p->user->__count); atomic_inc(&p->user->processes); @@ -604,14 +609,13 @@ p->run_list.next = NULL; p->run_list.prev = NULL; - if ((clone_flags & CLONE_VFORK) || !(clone_flags & CLONE_PARENT)) { - p->p_opptr = current; - if (!(p->ptrace & PT_PTRACED)) - p->p_pptr = current; - } p->p_cptr = NULL; init_waitqueue_head(&p->wait_chldexit); - p->vfork_sem = NULL; + p->vfork_done = NULL; + if (clone_flags & CLONE_VFORK) { + p->vfork_done = &vfork; + init_completion(&vfork); + } spin_lock_init(&p->alloc_lock); p->sigpending = 0; @@ -685,11 +689,24 @@ retval = p->pid; p->tgid = retval; INIT_LIST_HEAD(&p->thread_group); + + /* Need tasklist lock for parent etc handling! */ write_lock_irq(&tasklist_lock); + + /* CLONE_PARENT and CLONE_THREAD re-use the old parent */ + p->p_opptr = current->p_opptr; + p->p_pptr = current->p_pptr; + if (!(clone_flags & (CLONE_PARENT | CLONE_THREAD))) { + p->p_opptr = current; + if (!(p->ptrace & PT_PTRACED)) + p->p_pptr = current; + } + if (clone_flags & CLONE_THREAD) { p->tgid = current->tgid; list_add(&p->thread_group, ¤t->thread_group); } + SET_LINKS(p); hash_pid(p); nr_threads++; @@ -700,10 +717,10 @@ wake_up_process(p); /* do this last */ ++total_forks; + if (clone_flags & CLONE_VFORK) + wait_for_completion(&vfork); fork_out: - if ((clone_flags & CLONE_VFORK) && (retval > 0)) - down(&sem); return retval; bad_fork_cleanup_mm: diff -u --recursive --new-file v2.4.6/linux/kernel/kmod.c linux/kernel/kmod.c --- v2.4.6/linux/kernel/kmod.c Tue May 1 16:05:00 2001 +++ linux/kernel/kmod.c Tue Jul 17 18:23:50 2001 @@ -24,6 +24,7 @@ #include <linux/unistd.h> #include <linux/kmod.h> #include <linux/smp_lock.h> +#include <linux/completion.h> #include <asm/uaccess.h> @@ -263,7 +264,7 @@ #endif /* CONFIG_HOTPLUG */ struct subprocess_info { - struct semaphore *sem; + struct completion *complete; char *path; char **argv; char **envp; @@ -302,7 +303,7 @@ pid = kernel_thread(____call_usermodehelper, sub_info, CLONE_VFORK | SIGCHLD); if (pid < 0) sub_info->retval = pid; - up(sub_info->sem); + complete(sub_info->complete); } /** @@ -320,9 +321,9 @@ */ int call_usermodehelper(char *path, char **argv, char **envp) { - DECLARE_MUTEX_LOCKED(sem); + DECLARE_COMPLETION(work); struct subprocess_info sub_info = { - sem: &sem, + complete: &work, path: path, argv: argv, envp: envp, @@ -341,7 +342,7 @@ __call_usermodehelper(&sub_info); } else { schedule_task(&tqs); - down(&sem); /* Wait until keventd has started the subprocess */ + wait_for_completion(&work); } out: return sub_info.retval; diff -u --recursive --new-file v2.4.6/linux/kernel/ksyms.c linux/kernel/ksyms.c --- v2.4.6/linux/kernel/ksyms.c Tue Jul 3 17:08:22 2001 +++ linux/kernel/ksyms.c Fri Jul 20 12:41:02 2001 @@ -23,8 +23,6 @@ #include <linux/serial.h> #include <linux/locks.h> #include <linux/delay.h> -#include <linux/minix_fs.h> -#include <linux/ext2_fs.h> #include <linux/random.h> #include <linux/reboot.h> #include <linux/pagemap.h> @@ -47,6 +45,7 @@ #include <linux/fs.h> #include <linux/tty.h> #include <linux/in6.h> +#include <linux/completion.h> #include <asm/checksum.h> #if defined(CONFIG_PROC_FS) @@ -194,6 +193,7 @@ EXPORT_SYMBOL(__bforget); EXPORT_SYMBOL(ll_rw_block); EXPORT_SYMBOL(submit_bh); +EXPORT_SYMBOL(unlock_buffer); EXPORT_SYMBOL(__wait_on_buffer); EXPORT_SYMBOL(___wait_on_page); EXPORT_SYMBOL(block_write_full_page); @@ -363,6 +363,10 @@ EXPORT_SYMBOL(add_wait_queue_exclusive); EXPORT_SYMBOL(remove_wait_queue); +/* completion handling */ +EXPORT_SYMBOL(wait_for_completion); +EXPORT_SYMBOL(complete); + /* The notion of irq probe/assignment is foreign to S/390 */ #if !defined(CONFIG_ARCH_S390) @@ -537,6 +541,8 @@ EXPORT_SYMBOL(tasklet_kill); EXPORT_SYMBOL(__run_task_queue); EXPORT_SYMBOL(do_softirq); +EXPORT_SYMBOL(raise_softirq); +EXPORT_SYMBOL(cpu_raise_softirq); EXPORT_SYMBOL(tasklet_schedule); EXPORT_SYMBOL(tasklet_hi_schedule); diff -u --recursive --new-file v2.4.6/linux/kernel/ptrace.c linux/kernel/ptrace.c --- v2.4.6/linux/kernel/ptrace.c Mon Mar 19 12:35:08 2001 +++ linux/kernel/ptrace.c Fri Jul 20 12:39:56 2001 @@ -16,6 +16,51 @@ #include <asm/pgtable.h> #include <asm/uaccess.h> +int ptrace_attach(struct task_struct *task) +{ + task_lock(task); + if (task->pid <= 1) + goto bad; + if (task == current) + goto bad; + if (!task->mm) + goto bad; + if(((current->uid != task->euid) || + (current->uid != task->suid) || + (current->uid != task->uid) || + (current->gid != task->egid) || + (current->gid != task->sgid) || + (!cap_issubset(task->cap_permitted, current->cap_permitted)) || + (current->gid != task->gid)) && !capable(CAP_SYS_PTRACE)) + goto bad; + rmb(); + if (!task->mm->dumpable && !capable(CAP_SYS_PTRACE)) + goto bad; + /* the same process cannot be attached many times */ + if (task->ptrace & PT_PTRACED) + goto bad; + + /* Go */ + task->ptrace |= PT_PTRACED; + task_unlock(task); + + write_lock_irq(&tasklist_lock); + if (task->p_pptr != current) { + REMOVE_LINKS(task); + task->p_pptr = current; + SET_LINKS(task); + } + write_unlock_irq(&tasklist_lock); + + send_sig(SIGSTOP, task, 1); + return 0; + +bad: + task_unlock(task); + return -EPERM; +} + + /* * Access another process' address space, one page at a time. */ diff -u --recursive --new-file v2.4.6/linux/kernel/sched.c linux/kernel/sched.c --- v2.4.6/linux/kernel/sched.c Tue Jul 3 17:08:22 2001 +++ linux/kernel/sched.c Tue Jul 17 18:30:50 2001 @@ -25,6 +25,7 @@ #include <linux/smp_lock.h> #include <linux/interrupt.h> #include <linux/kernel_stat.h> +#include <linux/completion.h> #include <asm/uaccess.h> #include <asm/mmu_context.h> @@ -543,11 +544,6 @@ release_kernel_lock(prev, this_cpu); - /* Do "administrative" work here while we don't hold any locks */ - if (softirq_pending(this_cpu)) - goto handle_softirq; -handle_softirq_back: - /* * 'sched_data' is protected by the fact that we can run * only one process per CPU. @@ -611,8 +607,11 @@ #endif spin_unlock_irq(&runqueue_lock); - if (prev == next) + if (prev == next) { + /* We won't go through the normal tail, so do this by hand */ + prev->policy &= ~SCHED_YIELD; goto same_process; + } #ifdef CONFIG_SMP /* @@ -689,14 +688,12 @@ goto repeat_schedule; still_running: + if (!(prev->cpus_allowed & (1UL << this_cpu))) + goto still_running_back; c = goodness(prev, this_cpu, prev->active_mm); next = prev; goto still_running_back; -handle_softirq: - do_softirq(); - goto handle_softirq_back; - move_rr_last: if (!prev->counter) { prev->counter = NICE_TO_TICKS(prev->nice); @@ -763,6 +760,36 @@ __wake_up_common(q, mode, nr, 1); wq_read_unlock_irqrestore(&q->lock, flags); } +} + +void complete(struct completion *x) +{ + unsigned long flags; + + spin_lock_irqsave(&x->wait.lock, flags); + x->done++; + __wake_up_common(&x->wait, TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE, 1, 0); + spin_unlock_irqrestore(&x->wait.lock, flags); +} + +void wait_for_completion(struct completion *x) +{ + spin_lock_irq(&x->wait.lock); + if (!x->done) { + DECLARE_WAITQUEUE(wait, current); + + wait.flags |= WQ_FLAG_EXCLUSIVE; + __add_wait_queue_tail(&x->wait, &wait); + do { + __set_current_state(TASK_UNINTERRUPTIBLE); + spin_unlock_irq(&x->wait.lock); + schedule(); + spin_lock_irq(&x->wait.lock); + } while (!x->done); + __remove_wait_queue(&x->wait, &wait); + } + x->done--; + spin_unlock_irq(&x->wait.lock); } #define SLEEP_ON_VAR \ diff -u --recursive --new-file v2.4.6/linux/kernel/softirq.c linux/kernel/softirq.c --- v2.4.6/linux/kernel/softirq.c Tue Jul 3 17:08:22 2001 +++ linux/kernel/softirq.c Mon Jul 9 16:32:45 2001 @@ -47,21 +47,38 @@ static struct softirq_action softirq_vec[32] __cacheline_aligned; +/* + * we cannot loop indefinitely here to avoid userspace starvation, + * but we also don't want to introduce a worst case 1/HZ latency + * to the pending events, so lets the scheduler to balance + * the softirq load for us. + */ +static inline void wakeup_softirqd(unsigned cpu) +{ + struct task_struct * tsk = ksoftirqd_task(cpu); + + if (tsk && tsk->state != TASK_RUNNING) + wake_up_process(tsk); +} + asmlinkage void do_softirq() { int cpu = smp_processor_id(); __u32 pending; + long flags; + __u32 mask; if (in_interrupt()) return; - local_irq_disable(); + local_irq_save(flags); pending = softirq_pending(cpu); if (pending) { struct softirq_action *h; + mask = ~pending; local_bh_disable(); restart: /* Reset the pending bitmask before enabling irqs */ @@ -81,14 +98,40 @@ local_irq_disable(); pending = softirq_pending(cpu); - if (pending) + if (pending & mask) { + mask &= ~pending; goto restart; + } __local_bh_enable(); + + if (pending) + wakeup_softirqd(cpu); } - local_irq_enable(); + local_irq_restore(flags); } +inline void cpu_raise_softirq(unsigned int cpu, unsigned int nr) +{ + __cpu_raise_softirq(cpu, nr); + + /* + * If we're in an interrupt or bh, we're done + * (this also catches bh-disabled code). We will + * actually run the softirq once we return from + * the irq or bh. + * + * Otherwise we wake up ksoftirqd to make sure we + * schedule the softirq soon. + */ + if (!(local_irq_count(cpu) | local_bh_count(cpu))) + wakeup_softirqd(cpu); +} + +void raise_softirq(unsigned int nr) +{ + cpu_raise_softirq(smp_processor_id(), nr); +} void open_softirq(int nr, void (*action)(struct softirq_action*), void *data) { @@ -112,11 +155,10 @@ * If nobody is running it then add it to this CPU's * tasklet queue. */ - if (!test_and_set_bit(TASKLET_STATE_SCHED, &t->state) && - tasklet_trylock(t)) { + if (!test_and_set_bit(TASKLET_STATE_SCHED, &t->state)) { t->next = tasklet_vec[cpu].list; tasklet_vec[cpu].list = t; - __cpu_raise_softirq(cpu, TASKLET_SOFTIRQ); + cpu_raise_softirq(cpu, TASKLET_SOFTIRQ); tasklet_unlock(t); } local_irq_restore(flags); @@ -130,11 +172,10 @@ cpu = smp_processor_id(); local_irq_save(flags); - if (!test_and_set_bit(TASKLET_STATE_SCHED, &t->state) && - tasklet_trylock(t)) { + if (!test_and_set_bit(TASKLET_STATE_SCHED, &t->state)) { t->next = tasklet_hi_vec[cpu].list; tasklet_hi_vec[cpu].list = t; - __cpu_raise_softirq(cpu, HI_SOFTIRQ); + cpu_raise_softirq(cpu, HI_SOFTIRQ); tasklet_unlock(t); } local_irq_restore(flags); @@ -148,37 +189,30 @@ local_irq_disable(); list = tasklet_vec[cpu].list; tasklet_vec[cpu].list = NULL; + local_irq_enable(); while (list) { struct tasklet_struct *t = list; list = list->next; - /* - * A tasklet is only added to the queue while it's - * locked, so no other CPU can have this tasklet - * pending: - */ if (!tasklet_trylock(t)) BUG(); -repeat: - if (!test_and_clear_bit(TASKLET_STATE_SCHED, &t->state)) - BUG(); if (!atomic_read(&t->count)) { - local_irq_enable(); + if (!test_and_clear_bit(TASKLET_STATE_SCHED, &t->state)) + BUG(); t->func(t->data); - local_irq_disable(); - /* - * One more run if the tasklet got reactivated: - */ - if (test_bit(TASKLET_STATE_SCHED, &t->state)) - goto repeat; + tasklet_unlock(t); + continue; } tasklet_unlock(t); - if (test_bit(TASKLET_STATE_SCHED, &t->state)) - tasklet_schedule(t); + + local_irq_disable(); + t->next = tasklet_vec[cpu].list; + tasklet_vec[cpu].list = t; + cpu_raise_softirq(cpu, TASKLET_SOFTIRQ); + local_irq_enable(); } - local_irq_enable(); } @@ -193,6 +227,7 @@ local_irq_disable(); list = tasklet_hi_vec[cpu].list; tasklet_hi_vec[cpu].list = NULL; + local_irq_enable(); while (list) { struct tasklet_struct *t = list; @@ -201,21 +236,21 @@ if (!tasklet_trylock(t)) BUG(); -repeat: - if (!test_and_clear_bit(TASKLET_STATE_SCHED, &t->state)) - BUG(); if (!atomic_read(&t->count)) { - local_irq_enable(); + if (!test_and_clear_bit(TASKLET_STATE_SCHED, &t->state)) + BUG(); t->func(t->data); - local_irq_disable(); - if (test_bit(TASKLET_STATE_SCHED, &t->state)) - goto repeat; + tasklet_unlock(t); + continue; } tasklet_unlock(t); - if (test_bit(TASKLET_STATE_SCHED, &t->state)) - tasklet_hi_schedule(t); + + local_irq_disable(); + t->next = tasklet_hi_vec[cpu].list; + tasklet_hi_vec[cpu].list = t; + cpu_raise_softirq(cpu, HI_SOFTIRQ); + local_irq_enable(); } - local_irq_enable(); } @@ -335,3 +370,61 @@ f(data); } } + +static int ksoftirqd(void * __bind_cpu) +{ + int bind_cpu = *(int *) __bind_cpu; + int cpu = cpu_logical_map(bind_cpu); + + daemonize(); + current->nice = 19; + sigfillset(¤t->blocked); + + /* Migrate to the right CPU */ + current->cpus_allowed = 1UL << cpu; + while (smp_processor_id() != cpu) + schedule(); + + sprintf(current->comm, "ksoftirqd_CPU%d", bind_cpu); + + __set_current_state(TASK_INTERRUPTIBLE); + mb(); + + ksoftirqd_task(cpu) = current; + + for (;;) { + if (!softirq_pending(cpu)) + schedule(); + + __set_current_state(TASK_RUNNING); + + while (softirq_pending(cpu)) { + do_softirq(); + if (current->need_resched) + schedule(); + } + + __set_current_state(TASK_INTERRUPTIBLE); + } +} + +static __init int spawn_ksoftirqd(void) +{ + int cpu; + + for (cpu = 0; cpu < smp_num_cpus; cpu++) { + if (kernel_thread(ksoftirqd, (void *) &cpu, + CLONE_FS | CLONE_FILES | CLONE_SIGNAL) < 0) + printk("spawn_ksoftirqd() failed for cpu %d\n", cpu); + else { + while (!ksoftirqd_task(cpu_logical_map(cpu))) { + current->policy |= SCHED_YIELD; + schedule(); + } + } + } + + return 0; +} + +__initcall(spawn_ksoftirqd); diff -u --recursive --new-file v2.4.6/linux/kernel/sys.c linux/kernel/sys.c --- v2.4.6/linux/kernel/sys.c Thu Apr 12 12:20:31 2001 +++ linux/kernel/sys.c Thu Jul 19 20:34:31 2001 @@ -399,7 +399,7 @@ } if (new_egid != old_egid) { - current->dumpable = 0; + current->mm->dumpable = 0; wmb(); } if (rgid != (gid_t) -1 || @@ -424,7 +424,7 @@ { if(old_egid != gid) { - current->dumpable=0; + current->mm->dumpable=0; wmb(); } current->gid = current->egid = current->sgid = current->fsgid = gid; @@ -433,7 +433,7 @@ { if(old_egid != gid) { - current->dumpable=0; + current->mm->dumpable=0; wmb(); } current->egid = current->fsgid = gid; @@ -507,7 +507,7 @@ if(dumpclear) { - current->dumpable = 0; + current->mm->dumpable = 0; wmb(); } current->uid = new_ruid; @@ -561,7 +561,7 @@ if (new_euid != old_euid) { - current->dumpable=0; + current->mm->dumpable=0; wmb(); } current->fsuid = current->euid = new_euid; @@ -608,7 +608,7 @@ if (old_euid != uid) { - current->dumpable = 0; + current->mm->dumpable = 0; wmb(); } current->fsuid = current->euid = uid; @@ -650,7 +650,7 @@ if (euid != (uid_t) -1) { if (euid != current->euid) { - current->dumpable = 0; + current->mm->dumpable = 0; wmb(); } current->euid = euid; @@ -696,7 +696,7 @@ if (egid != (gid_t) -1) { if (egid != current->egid) { - current->dumpable = 0; + current->mm->dumpable = 0; wmb(); } current->egid = egid; @@ -738,7 +738,7 @@ { if (uid != old_fsuid) { - current->dumpable = 0; + current->mm->dumpable = 0; wmb(); } current->fsuid = uid; @@ -780,7 +780,7 @@ { if (gid != old_fsgid) { - current->dumpable = 0; + current->mm->dumpable = 0; wmb(); } current->fsgid = gid; @@ -1119,8 +1119,6 @@ return -EINVAL; if(copy_from_user(&new_rlim, rlim, sizeof(*rlim))) return -EFAULT; - if (new_rlim.rlim_cur < 0 || new_rlim.rlim_max < 0) - return -EINVAL; old_rlim = current->rlim + resource; if (((new_rlim.rlim_cur > old_rlim->rlim_max) || (new_rlim.rlim_max > old_rlim->rlim_max)) && @@ -1220,7 +1218,7 @@ error = put_user(current->pdeath_signal, (int *)arg2); break; case PR_GET_DUMPABLE: - if (current->dumpable) + if (current->mm->dumpable) error = 1; break; case PR_SET_DUMPABLE: @@ -1228,7 +1226,7 @@ error = -EINVAL; break; } - current->dumpable = arg2; + current->mm->dumpable = arg2; break; case PR_SET_UNALIGN: #ifdef SET_UNALIGN_CTL diff -u --recursive --new-file v2.4.6/linux/lib/rwsem.c linux/lib/rwsem.c --- v2.4.6/linux/lib/rwsem.c Fri Apr 27 13:58:28 2001 +++ linux/lib/rwsem.c Tue Jul 10 20:08:51 2001 @@ -112,7 +112,7 @@ */ static inline struct rw_semaphore *rwsem_down_failed_common(struct rw_semaphore *sem, struct rwsem_waiter *waiter, - __s32 adjustment) + signed long adjustment) { struct task_struct *tsk = current; signed long count; diff -u --recursive --new-file v2.4.6/linux/mm/Makefile linux/mm/Makefile --- v2.4.6/linux/mm/Makefile Fri Dec 29 14:07:24 2000 +++ linux/mm/Makefile Wed Jul 11 15:46:28 2001 @@ -9,6 +9,8 @@ O_TARGET := mm.o +export-objs := shmem.o + obj-y := memory.o mmap.o filemap.o mprotect.o mlock.o mremap.o \ vmalloc.o slab.o bootmem.o swap.o vmscan.o page_io.o \ page_alloc.o swap_state.o swapfile.o numa.o oom_kill.o \ diff -u --recursive --new-file v2.4.6/linux/mm/filemap.c linux/mm/filemap.c --- v2.4.6/linux/mm/filemap.c Tue Jul 3 17:08:22 2001 +++ linux/mm/filemap.c Wed Jul 11 14:52:58 2001 @@ -760,7 +760,7 @@ lock_page(page); /* Is the page still hashed? Ok, good.. */ - if (page->mapping) + if (page->mapping == mapping && page->index == offset) return page; /* Nope: we raced. Release and try again.. */ @@ -1649,10 +1649,13 @@ { pte_t pte = *ptep; - if (pte_present(pte) && ptep_test_and_clear_dirty(ptep)) { + if (pte_present(pte)) { struct page *page = pte_page(pte); - flush_tlb_page(vma, address); - set_page_dirty(page); + if (VALID_PAGE(page) && !PageReserved(page) && ptep_test_and_clear_dirty(ptep)) { + flush_tlb_page(vma, address); + if (page->mapping) + set_page_dirty(page); + } } return 0; } diff -u --recursive --new-file v2.4.6/linux/mm/memory.c linux/mm/memory.c --- v2.4.6/linux/mm/memory.c Tue Jul 3 17:08:22 2001 +++ linux/mm/memory.c Thu Jul 12 09:05:22 2001 @@ -888,8 +888,7 @@ * change only once the write actually happens. This avoids a few races, * and potentially makes it more efficient. * - * We enter with the page table read-lock held, and need to exit without - * it. + * We hold the mm semaphore and the page_table_lock on entry and exit. */ static int do_wp_page(struct mm_struct *mm, struct vm_area_struct * vma, unsigned long address, pte_t *page_table, pte_t pte) @@ -1108,9 +1107,6 @@ spin_lock(&mm->page_table_lock); return -1; } - wait_on_page(page); - flush_page_to_ram(page); - flush_icache_page(vma, page); } /* @@ -1140,6 +1136,8 @@ pte = pte_mkwrite(pte_mkdirty(pte)); UnlockPage(page); + flush_page_to_ram(page); + flush_icache_page(vma, page); set_pte(page_table, pte); /* No need to invalidate - it was non-present before */ diff -u --recursive --new-file v2.4.6/linux/mm/oom_kill.c linux/mm/oom_kill.c --- v2.4.6/linux/mm/oom_kill.c Tue May 15 00:25:41 2001 +++ linux/mm/oom_kill.c Fri Jul 6 17:02:23 2001 @@ -191,11 +191,28 @@ */ int out_of_memory(void) { + long cache_mem, limit; + /* Enough free memory? Not OOM. */ if (nr_free_pages() > freepages.min) return 0; if (nr_free_pages() + nr_inactive_clean_pages() > freepages.low) + return 0; + + /* + * If the buffer and page cache (excluding swap cache) are over + * their (/proc tunable) minimum, we're still not OOM. We test + * this to make sure we don't return OOM when the system simply + * has a hard time with the cache. + */ + cache_mem = atomic_read(&page_cache_size); + cache_mem += atomic_read(&buffermem_pages); + cache_mem -= swapper_space.nrpages; + limit = (page_cache.min_percent + buffer_mem.min_percent); + limit *= num_physpages / 100; + + if (cache_mem > limit) return 0; /* Enough swap space left? Not OOM. */ diff -u --recursive --new-file v2.4.6/linux/mm/shmem.c linux/mm/shmem.c --- v2.4.6/linux/mm/shmem.c Tue May 22 09:31:25 2001 +++ linux/mm/shmem.c Wed Jul 11 14:52:58 2001 @@ -3,7 +3,8 @@ * * Copyright (C) 2000 Linus Torvalds. * 2000 Transmeta Corp. - * 2000 Christoph Rohland + * 2000-2001 Christoph Rohland + * 2000-2001 SAP AG * * This file is released under the GPL. */ @@ -33,7 +34,7 @@ #define TMPFS_MAGIC 0x01021994 #define ENTRIES_PER_PAGE (PAGE_SIZE/sizeof(unsigned long)) -#define NR_SINGLE (ENTRIES_PER_PAGE + SHMEM_NR_DIRECT) +#define SHMEM_MAX_BLOCKS (SHMEM_NR_DIRECT + ENTRIES_PER_PAGE*ENTRIES_PER_PAGE) static struct super_operations shmem_ops; static struct address_space_operations shmem_aops; @@ -193,7 +194,14 @@ } out: - info->max_index = index; + /* + * We have no chance to give an error, so we limit it to max + * size here and the application will fail later + */ + if (index > SHMEM_MAX_BLOCKS) + info->max_index = SHMEM_MAX_BLOCKS; + else + info->max_index = index; info->swapped -= freed; shmem_recalc_inode(inode); spin_unlock (&info->lock); @@ -223,7 +231,7 @@ */ static int shmem_writepage(struct page * page) { - int error = 0; + int error; struct shmem_inode_info *info; swp_entry_t *entry, swap; struct inode *inode; @@ -231,17 +239,14 @@ if (!PageLocked(page)) BUG(); - /* Only move to the swap cache if there are no other users of - * the page. */ - if (atomic_read(&page->count) > 2) - goto out; - inode = page->mapping->host; info = &inode->u.shmem_i; swap = __get_swap_page(2); error = -ENOMEM; - if (!swap.val) + if (!swap.val) { + activate_page(page); goto out; + } spin_lock(&info->lock); entry = shmem_swp_entry(info, page->index); @@ -314,6 +319,7 @@ return page; } + shmem_recalc_inode(inode); if (entry->val) { unsigned long flags; @@ -393,22 +399,9 @@ static int shmem_getpage(struct inode * inode, unsigned long idx, struct page **ptr) { - struct address_space * mapping = inode->i_mapping; int error; - *ptr = NOPAGE_SIGBUS; - if (inode->i_size <= (loff_t) idx * PAGE_CACHE_SIZE) - return -EFAULT; - - *ptr = __find_get_page(mapping, idx, page_hash(mapping, idx)); - if (*ptr) { - if (Page_Uptodate(*ptr)) - return 0; - page_cache_release(*ptr); - } - down (&inode->i_sem); - /* retest we may have slept */ if (inode->i_size < (loff_t) idx * PAGE_CACHE_SIZE) goto sigbus; *ptr = shmem_getpage_locked(inode, idx); @@ -1027,6 +1020,8 @@ unsigned long max_inodes, inodes; struct shmem_sb_info *info = &sb->u.shmem_sb; + max_blocks = info->max_blocks; + max_inodes = info->max_inodes; if (shmem_parse_options (data, NULL, &max_blocks, &max_inodes)) return -EINVAL; @@ -1074,7 +1069,7 @@ sb->u.shmem_sb.free_blocks = blocks; sb->u.shmem_sb.max_inodes = inodes; sb->u.shmem_sb.free_inodes = inodes; - sb->s_maxbytes = (unsigned long long)(SHMEM_NR_DIRECT + (ENTRIES_PER_PAGE*ENTRIES_PER_PAGE)) << PAGE_CACHE_SHIFT; + sb->s_maxbytes = (unsigned long long)SHMEM_MAX_BLOCKS << PAGE_CACHE_SHIFT; sb->s_blocksize = PAGE_CACHE_SIZE; sb->s_blocksize_bits = PAGE_CACHE_SHIFT; sb->s_magic = TMPFS_MAGIC; @@ -1282,9 +1277,11 @@ struct qstr this; int vm_enough_memory(long pages); - error = -ENOMEM; + if (size > (unsigned long long) SHMEM_MAX_BLOCKS << PAGE_CACHE_SHIFT) + return ERR_PTR(-EINVAL); + if (!vm_enough_memory((size) >> PAGE_SHIFT)) - goto out; + return ERR_PTR(-ENOMEM); this.name = name; this.len = strlen(name); @@ -1292,7 +1289,7 @@ root = tmpfs_fs_type.kern_mnt->mnt_root; dentry = d_alloc(root, &this); if (!dentry) - goto out; + return ERR_PTR(-ENOMEM); error = -ENFILE; file = get_empty_filp(); @@ -1318,7 +1315,6 @@ put_filp(file); put_dentry: dput (dentry); -out: return ERR_PTR(error); } /* diff -u --recursive --new-file v2.4.6/linux/mm/swap_state.c linux/mm/swap_state.c --- v2.4.6/linux/mm/swap_state.c Tue Jul 3 17:08:22 2001 +++ linux/mm/swap_state.c Wed Jul 18 15:18:15 2001 @@ -81,6 +81,7 @@ BUG(); flags = page->flags & ~((1 << PG_error) | (1 << PG_arch_1)); page->flags = flags | (1 << PG_uptodate); + page->age = PAGE_AGE_START; add_to_page_cache_locked(page, &swapper_space, entry.val); } @@ -226,7 +227,7 @@ if (found_page) goto out_free_swap; - new_page = alloc_page(GFP_USER); + new_page = alloc_page(GFP_HIGHUSER); if (!new_page) goto out_free_swap; /* Out of memory */ diff -u --recursive --new-file v2.4.6/linux/mm/swapfile.c linux/mm/swapfile.c --- v2.4.6/linux/mm/swapfile.c Tue Jul 3 17:08:22 2001 +++ linux/mm/swapfile.c Wed Jul 4 11:50:38 2001 @@ -513,7 +513,7 @@ len += sprintf(buf, "Filename\t\t\tType\t\tSize\tUsed\tPriority\n"); for (i = 0 ; i < nr_swapfiles ; i++, ptr++) { - if (ptr->flags & SWP_USED) { + if ((ptr->flags & SWP_USED) && ptr->swap_map) { char * path = d_path(ptr->swap_file, ptr->swap_vfsmnt, page, PAGE_SIZE); diff -u --recursive --new-file v2.4.6/linux/mm/vmscan.c linux/mm/vmscan.c --- v2.4.6/linux/mm/vmscan.c Tue Jul 3 17:08:22 2001 +++ linux/mm/vmscan.c Mon Jul 9 10:18:50 2001 @@ -613,7 +613,7 @@ * loads, flush out the dirty pages before we have to wait on * IO. */ - if ((CAN_DO_IO || CAN_DO_FS) && !launder_loop && free_shortage()) { + if (CAN_DO_IO && !launder_loop && free_shortage()) { launder_loop = 1; /* If we cleaned pages, never do synchronous IO. */ if (cleaned_pages) diff -u --recursive --new-file v2.4.6/linux/net/atm/mpoa_proc.c linux/net/atm/mpoa_proc.c --- v2.4.6/linux/net/atm/mpoa_proc.c Tue May 15 01:29:35 2001 +++ linux/net/atm/mpoa_proc.c Wed Jul 4 11:50:38 2001 @@ -109,8 +109,6 @@ eg_cache_entry *eg_entry; struct timeval now; unsigned char ip_string[16]; - if(count < 0) - return -EINVAL; if(count == 0) return 0; page = get_free_page(GFP_KERNEL); @@ -173,7 +171,6 @@ char *page, c; const char *tmp; - if (nbytes < 0) return -EINVAL; if (nbytes == 0) return 0; if (nbytes >= PAGE_SIZE) nbytes = PAGE_SIZE-1; diff -u --recursive --new-file v2.4.6/linux/net/atm/proc.c linux/net/atm/proc.c --- v2.4.6/linux/net/atm/proc.c Sun Mar 25 18:14:25 2001 +++ linux/net/atm/proc.c Wed Jul 4 11:50:38 2001 @@ -495,7 +495,7 @@ unsigned long page; int length; - if (count < 0) return -EINVAL; + if (count == 0) return 0; page = get_free_page(GFP_KERNEL); if (!page) return -ENOMEM; dev = ((struct proc_dir_entry *) file->f_dentry->d_inode->u.generic_ip) @@ -524,7 +524,7 @@ info = ((struct proc_dir_entry *) file->f_dentry->d_inode->u.generic_ip) ->data; - if (count < 0) return -EINVAL; + if (count == 0) return 0; page = get_free_page(GFP_KERNEL); if (!page) return -ENOMEM; length = (*info)(*pos,(char *) page); diff -u --recursive --new-file v2.4.6/linux/net/core/dev.c linux/net/core/dev.c --- v2.4.6/linux/net/core/dev.c Tue Jul 3 17:08:22 2001 +++ linux/net/core/dev.c Sun Jul 15 16:29:40 2001 @@ -1217,6 +1217,8 @@ enqueue: dev_hold(skb->dev); __skb_queue_tail(&queue->input_pkt_queue,skb); + + /* Runs from irqs or BH's, no need to wake BH */ __cpu_raise_softirq(this_cpu, NET_RX_SOFTIRQ); local_irq_restore(flags); #ifndef OFFLINE_SAMPLE @@ -1527,6 +1529,8 @@ local_irq_disable(); netdev_rx_stat[this_cpu].time_squeeze++; + + /* This already runs in BH context, no need to wake up BH's */ __cpu_raise_softirq(this_cpu, NET_RX_SOFTIRQ); local_irq_enable(); @@ -2650,10 +2654,6 @@ if (!dev_boot_phase) return 0; -#ifdef CONFIG_NET_SCHED - pktsched_init(); -#endif - #ifdef CONFIG_NET_DIVERT dv_init(); #endif /* CONFIG_NET_DIVERT */ @@ -2767,6 +2767,10 @@ dst_init(); dev_mcast_init(); + +#ifdef CONFIG_NET_SCHED + pktsched_init(); +#endif /* * Initialise network devices diff -u --recursive --new-file v2.4.6/linux/net/core/dv.c linux/net/core/dv.c --- v2.4.6/linux/net/core/dv.c Sun Mar 25 18:14:25 2001 +++ linux/net/core/dv.c Tue Jul 10 16:11:43 2001 @@ -66,6 +66,7 @@ } else { memset(dev->divert, 0, sizeof(struct divert_blk)); } + dev_hold(dev); } else { printk(KERN_DEBUG "divert: not allocating divert_blk for non-ethernet device %s\n", dev->name); @@ -84,6 +85,7 @@ if (dev->divert) { kfree(dev->divert); dev->divert=NULL; + dev_put(dev); printk(KERN_DEBUG "divert: freeing divert_blk for %s\n", dev->name); } else { @@ -151,7 +153,8 @@ int check_args(struct divert_cf *div_cf, struct net_device **dev) { char devname[32]; - + int ret; + if (dev == NULL) return -EFAULT; @@ -170,16 +173,21 @@ /* dev should NOT be null */ if (*dev == NULL) return -EINVAL; - + + ret = 0; + /* user issuing the ioctl must be a super one :) */ - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; + if (!capable(CAP_SYS_ADMIN)) { + ret = -EPERM; + goto out; + } /* Device must have a divert_blk member NOT null */ if ((*dev)->divert == NULL) - return -EFAULT; - - return 0; + ret = -EINVAL; +out: + dev_put(*dev); + return ret; } /* diff -u --recursive --new-file v2.4.6/linux/net/core/skbuff.c linux/net/core/skbuff.c --- v2.4.6/linux/net/core/skbuff.c Thu Apr 12 12:11:39 2001 +++ linux/net/core/skbuff.c Tue Jul 10 16:11:43 2001 @@ -4,7 +4,7 @@ * Authors: Alan Cox <iiitac@pyr.swan.ac.uk> * Florian La Roche <rzsfl@rz.uni-sb.de> * - * Version: $Id: skbuff.c,v 1.87 2001/03/06 22:09:50 davem Exp $ + * Version: $Id: skbuff.c,v 1.88 2001/07/09 23:19:14 davem Exp $ * * Fixes: * Alan Cox : Fixed the worst of the load balancer bugs. @@ -1149,6 +1149,32 @@ return csum; } +void skb_copy_and_csum_dev(const struct sk_buff *skb, u8 *to) +{ + unsigned int csum; + long csstart; + + if (skb->ip_summed == CHECKSUM_HW) + csstart = skb->h.raw - skb->data; + else + csstart = skb->len - skb->data_len; + + if (csstart > skb->len - skb->data_len) + BUG(); + + memcpy(to, skb->data, csstart); + + csum = 0; + if (csstart != skb->len) + csum = skb_copy_and_csum_bits(skb, csstart, to+csstart, + skb->len-csstart, 0); + + if (skb->ip_summed == CHECKSUM_HW) { + long csstuff = csstart + skb->csum; + + *((unsigned short *)(to + csstuff)) = csum_fold(csum); + } +} #if 0 /* diff -u --recursive --new-file v2.4.6/linux/net/decnet/dn_dev.c linux/net/decnet/dn_dev.c --- v2.4.6/linux/net/decnet/dn_dev.c Mon Jan 22 13:32:10 2001 +++ linux/net/decnet/dn_dev.c Fri Jul 6 16:46:22 2001 @@ -68,106 +68,77 @@ static struct dn_dev_parms dn_dev_list[] = { { - ARPHRD_ETHER, /* Ethernet */ - DN_DEV_BCAST, - DN_DEV_S_RU, - 0, - 1498, - 1, - 10, - 0, - "ethernet", - NET_DECNET_CONF_ETHER, - dn_eth_up, - NULL, - dn_send_brd_hello, - NULL + type: ARPHRD_ETHER, /* Ethernet */ + mode: DN_DEV_BCAST, + state: DN_DEV_S_RU, + blksize: 1498, + t2: 1, + t3: 10, + name: "ethernet", + ctl_name: NET_DECNET_CONF_ETHER, + up: dn_eth_up, + timer3: dn_send_brd_hello, }, { - ARPHRD_IPGRE, /* DECnet tunneled over GRE in IP */ - DN_DEV_BCAST, - DN_DEV_S_RU, - 0, - 1400, - 1, - 10, - 0, - "ipgre", - NET_DECNET_CONF_GRE, - NULL, - NULL, - dn_send_brd_hello, - NULL + type: ARPHRD_IPGRE, /* DECnet tunneled over GRE in IP */ + mode: DN_DEV_BCAST, + state: DN_DEV_S_RU, + blksize: 1400, + t2: 1, + t3: 10, + name: "ipgre", + ctl_name: NET_DECNET_CONF_GRE, + timer3: dn_send_brd_hello, }, #if 0 { - ARPHRD_X25, /* Bog standard X.25 */ - DN_DEV_UCAST, - DN_DEV_S_DS, - 0, - 230, - 1, - 120, - 0, - "x25", - NET_DECNET_CONF_X25, - NULL, - NULL, - dn_send_ptp_hello, - NULL + type: ARPHRD_X25, /* Bog standard X.25 */ + mode: DN_DEV_UCAST, + state: DN_DEV_S_DS, + blksize: 230, + t2: 1, + t3: 120, + name: "x25", + ctl_name: NET_DECNET_CONF_X25, + timer3: dn_send_ptp_hello, }, #endif #if 0 { - ARPHRD_PPP, /* DECnet over PPP */ - DN_DEV_BCAST, - DN_DEV_S_RU, - 0, - 230, - 1, - 10, - 0, - "ppp", - NET_DECNET_CONF_PPP, - NULL, - NULL, - dn_send_brd_hello, - NULL + type: ARPHRD_PPP, /* DECnet over PPP */ + mode: DN_DEV_BCAST, + state: DN_DEV_S_RU, + blksize: 230, + t2: 1, + t3: 10, + name: "ppp", + ctl_name: NET_DECNET_CONF_PPP, + timer3: dn_send_brd_hello, }, #endif #if 0 { - ARPHRD_DDCMP, /* DECnet over DDCMP */ - DN_DEV_UCAST, - DN_DEV_S_DS, - 0, - 230, - 1, - 120, - 0, - "ddcmp", - NET_DECNET_CONF_DDCMP, - NULL, - NULL, - dn_send_ptp_hello, - NULL + type: ARPHRD_DDCMP, /* DECnet over DDCMP */ + mode: DN_DEV_UCAST, + state: DN_DEV_S_DS, + blksize: 230, + t2: 1, + t3: 120, + name: "ddcmp", + ctl_name: NET_DECNET_CONF_DDCMP, + timer3: dn_send_ptp_hello, }, #endif { - ARPHRD_LOOPBACK, /* Loopback interface - always last */ - DN_DEV_BCAST, - DN_DEV_S_RU, - 0, - 1498, - 1, - 10, - 0, - "loopback", - NET_DECNET_CONF_LOOPBACK, - NULL, - NULL, - dn_send_brd_hello, - NULL + type: ARPHRD_LOOPBACK, /* Loopback interface - always last */ + mode: DN_DEV_BCAST, + state: DN_DEV_S_RU, + blksize: 1498, + t2: 1, + t3: 10, + name: "loopback", + ctl_name: NET_DECNET_CONF_LOOPBACK, + timer3: dn_send_brd_hello, } }; @@ -182,7 +153,7 @@ static int min_t3[] = { 1 }; static int max_t3[] = { 8191 }; /* Must fit in 16 bits when multiplied by BCT3MULT or T3MULT */ -static int min_priority[] = { 0 }; +static int min_priority[1]; static int max_priority[] = { 127 }; /* From DECnet spec */ static int dn_forwarding_proc(ctl_table *, int, struct file *, @@ -344,7 +315,8 @@ if (newlen != sizeof(int)) return -EINVAL; - get_user(value, (int *)newval); + if (get_user(value, (int *)newval)) + return -EFAULT; if (value < 0) return -EINVAL; if (value > 2) diff -u --recursive --new-file v2.4.6/linux/net/decnet/sysctl_net_decnet.c linux/net/decnet/sysctl_net_decnet.c --- v2.4.6/linux/net/decnet/sysctl_net_decnet.c Fri Feb 9 11:34:13 2001 +++ linux/net/decnet/sysctl_net_decnet.c Wed Jul 4 11:50:38 2001 @@ -27,7 +27,7 @@ #include <net/dn_route.h> -int decnet_debug_level = 0; +int decnet_debug_level; int decnet_time_wait = 30; int decnet_dn_count = 1; int decnet_di_count = 3; diff -u --recursive --new-file v2.4.6/linux/net/ipv4/ip_output.c linux/net/ipv4/ip_output.c --- v2.4.6/linux/net/ipv4/ip_output.c Tue Jul 3 17:08:22 2001 +++ linux/net/ipv4/ip_output.c Tue Jul 10 16:11:43 2001 @@ -5,7 +5,7 @@ * * The Internet Protocol (IP) output module. * - * Version: $Id: ip_output.c,v 1.93 2001/06/01 14:59:31 davem Exp $ + * Version: $Id: ip_output.c,v 1.94 2001/07/10 00:40:13 davem Exp $ * * Authors: Ross Biro, <bir7@leland.Stanford.Edu> * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> @@ -847,6 +847,9 @@ ptr += len; offset += len; +#ifdef CONFIG_NET_SCHED + skb2->tc_index = skb->tc_index; +#endif #ifdef CONFIG_NETFILTER skb2->nfmark = skb->nfmark; /* Connection association is same as pre-frag packet */ diff -u --recursive --new-file v2.4.6/linux/net/ipv4/netfilter/ip_queue.c linux/net/ipv4/netfilter/ip_queue.c --- v2.4.6/linux/net/ipv4/netfilter/ip_queue.c Mon Dec 11 12:37:04 2000 +++ linux/net/ipv4/netfilter/ip_queue.c Fri Jul 6 17:07:55 2001 @@ -24,19 +24,28 @@ #include <linux/sysctl.h> #include <linux/proc_fs.h> #include <net/sock.h> +#include <net/route.h> #include <linux/netfilter_ipv4/ip_queue.h> +#include <linux/netfilter_ipv4/ip_tables.h> #define IPQ_QMAX_DEFAULT 1024 #define IPQ_PROC_FS_NAME "ip_queue" #define NET_IPQ_QMAX 2088 #define NET_IPQ_QMAX_NAME "ip_queue_maxlen" +typedef struct ipq_rt_info { + __u8 tos; + __u32 daddr; + __u32 saddr; +} ipq_rt_info_t; + typedef struct ipq_queue_element { struct list_head list; /* Links element into queue */ int verdict; /* Current verdict */ struct nf_info *info; /* Extra info from netfilter */ struct sk_buff *skb; /* Packet inside */ + ipq_rt_info_t rt_info; /* May need post-mangle routing */ } ipq_queue_element_t; typedef int (*ipq_send_cb_t)(ipq_queue_element_t *e); @@ -64,7 +73,6 @@ * Packet queue * ****************************************************************************/ - /* Dequeue a packet if matched by cmp, or the next available if cmp is NULL */ static ipq_queue_element_t * ipq_dequeue(ipq_queue_t *q, @@ -150,9 +158,19 @@ printk(KERN_ERR "ip_queue: OOM in enqueue\n"); return -ENOMEM; } + e->verdict = NF_DROP; e->info = info; e->skb = skb; + + if (e->info->hook == NF_IP_LOCAL_OUT) { + struct iphdr *iph = skb->nh.iph; + + e->rt_info.tos = iph->tos; + e->rt_info.daddr = iph->daddr; + e->rt_info.saddr = iph->saddr; + } + spin_lock_bh(&q->lock); if (q->len >= *q->maxlen) { spin_unlock_bh(&q->lock); @@ -198,6 +216,32 @@ kfree(q); } +/* With a chainsaw... */ +static int route_me_harder(struct sk_buff *skb) +{ + struct iphdr *iph = skb->nh.iph; + struct rtable *rt; + + struct rt_key key = { + dst:iph->daddr, src:iph->saddr, + oif:skb->sk ? skb->sk->bound_dev_if : 0, + tos:RT_TOS(iph->tos)|RTO_CONN, +#ifdef CONFIG_IP_ROUTE_FWMARK + fwmark:skb->nfmark +#endif + }; + + if (ip_route_output_key(&rt, &key) != 0) { + printk("route_me_harder: No more route.\n"); + return -EINVAL; + } + + /* Drop old route. */ + dst_release(skb->dst); + skb->dst = &rt->u.dst; + return 0; +} + static int ipq_mangle_ipv4(ipq_verdict_msg_t *v, ipq_queue_element_t *e) { int diff; @@ -223,6 +267,8 @@ "in mangle, dropping packet\n"); return -ENOMEM; } + if (e->skb->sk) + skb_set_owner_w(newskb, e->skb->sk); kfree_skb(e->skb); e->skb = newskb; } @@ -230,6 +276,19 @@ } memcpy(e->skb->data, v->payload, v->data_len); e->skb->nfcache |= NFC_ALTERED; + + /* + * Extra routing may needed on local out, as the QUEUE target never + * returns control to the table. + */ + if (e->info->hook == NF_IP_LOCAL_OUT) { + struct iphdr *iph = e->skb->nh.iph; + + if (!(iph->tos == e->rt_info.tos + && iph->daddr == e->rt_info.daddr + && iph->saddr == e->rt_info.saddr)) + return route_me_harder(e->skb); + } return 0; } @@ -400,6 +459,13 @@ if (e->info->outdev) strcpy(pm->outdev_name, e->info->outdev->name); else pm->outdev_name[0] = '\0'; pm->hw_protocol = e->skb->protocol; + if (e->info->indev && e->skb->dev) { + pm->hw_type = e->skb->dev->type; + if (e->skb->dev->hard_header_parse) + pm->hw_addrlen = + e->skb->dev->hard_header_parse(e->skb, + pm->hw_addr); + } if (data_len) memcpy(pm->payload, e->skb->data, data_len); nlh->nlmsg_len = skb->tail - old_tail; @@ -431,10 +497,15 @@ int status, type; struct nlmsghdr *nlh; + if (skb->len < sizeof(struct nlmsghdr)) + return; + nlh = (struct nlmsghdr *)skb->data; - if (nlh->nlmsg_len < sizeof(*nlh) - || skb->len < nlh->nlmsg_len - || nlh->nlmsg_pid <= 0 + if (nlh->nlmsg_len < sizeof(struct nlmsghdr) + || skb->len < nlh->nlmsg_len) + return; + + if(nlh->nlmsg_pid <= 0 || !(nlh->nlmsg_flags & NLM_F_REQUEST) || nlh->nlmsg_flags & NLM_F_MULTI) RCV_SKB_FAIL(-EINVAL); diff -u --recursive --new-file v2.4.6/linux/net/ipv4/netfilter/ipt_unclean.c linux/net/ipv4/netfilter/ipt_unclean.c --- v2.4.6/linux/net/ipv4/netfilter/ipt_unclean.c Tue Jul 3 17:08:22 2001 +++ linux/net/ipv4/netfilter/ipt_unclean.c Fri Jul 6 17:07:55 2001 @@ -268,6 +268,7 @@ int embedded) { u_int8_t *opt = (u_int8_t *)tcph; + u_int8_t *endhdr = (u_int8_t *)tcph + tcph->doff * 4; u_int8_t tcpflags; int end_of_options = 0; size_t i; @@ -373,7 +374,7 @@ return 0; } /* CHECK: oversize options. */ - else if (opt[i+1] + i >= tcph->doff * 4) { + else if (&opt[i] + opt[i+1] > endhdr) { limpk("TCP option %u at %Zu too long\n", (unsigned int) opt[i], i); return 0; @@ -392,6 +393,7 @@ check_ip(struct iphdr *iph, size_t length, int embedded) { u_int8_t *opt = (u_int8_t *)iph; + u_int8_t *endhdr = (u_int8_t *)iph + iph->ihl * 4; int end_of_options = 0; void *protoh; size_t datalen; @@ -444,7 +446,7 @@ return 0; } /* CHECK: oversize options. */ - else if (opt[i+1] + i > iph->ihl * 4) { + else if (&opt[i] + opt[i+1] > endhdr) { limpk("IP option %u at %u too long\n", opt[i], i); return 0; diff -u --recursive --new-file v2.4.6/linux/net/ipv4/netfilter/iptable_mangle.c linux/net/ipv4/netfilter/iptable_mangle.c --- v2.4.6/linux/net/ipv4/netfilter/iptable_mangle.c Mon Jan 29 08:07:30 2001 +++ linux/net/ipv4/netfilter/iptable_mangle.c Fri Jul 6 17:07:55 2001 @@ -148,7 +148,7 @@ ret = ipt_do_table(pskb, hook, in, out, &packet_mangler, NULL); /* Reroute for ANY change. */ - if (ret != NF_DROP && ret != NF_STOLEN + if (ret != NF_DROP && ret != NF_STOLEN && ret != NF_QUEUE && ((*pskb)->nh.iph->saddr != saddr || (*pskb)->nh.iph->daddr != daddr || (*pskb)->nfmark != nfmark diff -u --recursive --new-file v2.4.6/linux/net/ipv4/raw.c linux/net/ipv4/raw.c --- v2.4.6/linux/net/ipv4/raw.c Tue Jul 3 17:08:22 2001 +++ linux/net/ipv4/raw.c Tue Jul 10 16:11:43 2001 @@ -5,7 +5,7 @@ * * RAW - implementation of IP "raw" sockets. * - * Version: $Id: raw.c,v 1.62 2001/06/05 10:52:15 davem Exp $ + * Version: $Id: raw.c,v 1.63 2001/07/10 04:29:01 davem Exp $ * * Authors: Ross Biro, <bir7@leland.Stanford.Edu> * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> @@ -520,6 +520,7 @@ if (sin) { sin->sin_family = AF_INET; sin->sin_addr.s_addr = skb->nh.iph->saddr; + memset(&sin->sin_zero, 0, sizeof(sin->sin_zero)); } if (sk->protinfo.af_inet.cmsg_flags) ip_cmsg_recv(msg, skb); diff -u --recursive --new-file v2.4.6/linux/net/ipv4/route.c linux/net/ipv4/route.c --- v2.4.6/linux/net/ipv4/route.c Wed May 16 10:31:27 2001 +++ linux/net/ipv4/route.c Thu Jul 19 18:11:13 2001 @@ -5,7 +5,7 @@ * * ROUTE - implementation of the IP router. * - * Version: $Id: route.c,v 1.94 2001/05/05 01:01:02 davem Exp $ + * Version: $Id: route.c,v 1.95 2001/07/10 22:32:51 davem Exp $ * * Authors: Ross Biro, <bir7@leland.Stanford.Edu> * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> @@ -52,6 +52,7 @@ * Tobias Ringstrom : Uninitialized res.type in ip_route_output_slow. * Vladimir V. Ivanov : IP rule info (flowid) is really useful. * Marc Boucher : routing by fwmark + * Robert Olsson : Added rt_cache statistics * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -198,6 +199,8 @@ static unsigned rt_hash_mask; static int rt_hash_log; +struct rt_cache_stat rt_cache_stat[NR_CPUS]; + static int rt_intern_hash(unsigned hash, struct rtable *rth, struct rtable **res); @@ -277,6 +280,41 @@ len = length; return len; } + +static int rt_cache_stat_get_info(char *buffer, char **start, off_t offset, int length) +{ + unsigned int dst_entries = atomic_read(&ipv4_dst_ops.entries); + int i, lcpu; + int len = 0; + + for (lcpu = 0; lcpu < smp_num_cpus; lcpu++) { + i = cpu_logical_map(lcpu); + + len += sprintf(buffer+len, "%08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x\n", + dst_entries, + rt_cache_stat[i].in_hit, + rt_cache_stat[i].in_slow_tot, + rt_cache_stat[i].in_slow_mc, + rt_cache_stat[i].in_no_route, + rt_cache_stat[i].in_brd, + rt_cache_stat[i].in_martian_dst, + rt_cache_stat[i].in_martian_src, + + rt_cache_stat[i].out_hit, + rt_cache_stat[i].out_slow_tot, + rt_cache_stat[i].out_slow_mc + ); + } + len -= offset; + + if (len > length) + len = length; + if (len < 0) + len = 0; + + *start = buffer + offset; + return len; +} static __inline__ void rt_free(struct rtable *rt) { @@ -1250,6 +1288,7 @@ if (!LOCAL_MCAST(daddr) && IN_DEV_MFORWARD(in_dev)) rth->u.dst.input = ip_mr_input; #endif + rt_cache_stat[smp_processor_id()].in_slow_mc++; in_dev_put(in_dev); hash = rt_hash_code(daddr, saddr ^ (dev->ifindex << 5), tos); @@ -1335,6 +1374,8 @@ } free_res = 1; + rt_cache_stat[smp_processor_id()].in_slow_tot++; + #ifdef CONFIG_IP_ROUTE_NAT /* Policy is applied before mapping destination, but rerouting after map should be made with old source. @@ -1486,6 +1527,7 @@ } flags |= RTCF_BROADCAST; res.type = RTN_BROADCAST; + rt_cache_stat[smp_processor_id()].in_brd++; local_input: rth = dst_alloc(&ipv4_dst_ops); @@ -1529,6 +1571,7 @@ goto intern; no_route: + rt_cache_stat[smp_processor_id()].in_no_route++; spec_dst = inet_select_addr(dev, 0, RT_SCOPE_UNIVERSE); res.type = RTN_UNREACHABLE; goto local_input; @@ -1537,6 +1580,7 @@ * Do not cache martian addresses: they should be logged (RFC1812) */ martian_destination: + rt_cache_stat[smp_processor_id()].in_martian_dst++; #ifdef CONFIG_IP_ROUTE_VERBOSE if (IN_DEV_LOG_MARTIANS(in_dev) && net_ratelimit()) printk(KERN_WARNING "martian destination %u.%u.%u.%u from " @@ -1552,6 +1596,8 @@ goto done; martian_source: + + rt_cache_stat[smp_processor_id()].in_martian_src++; #ifdef CONFIG_IP_ROUTE_VERBOSE if (IN_DEV_LOG_MARTIANS(in_dev) && net_ratelimit()) { /* @@ -1600,6 +1646,7 @@ rth->u.dst.lastuse = jiffies; dst_hold(&rth->u.dst); rth->u.dst.__use++; + rt_cache_stat[smp_processor_id()].in_hit++; read_unlock(&rt_hash_table[hash].lock); skb->dst = (struct dst_entry*)rth; return 0; @@ -1890,14 +1937,18 @@ rth->u.dst.output=ip_output; + rt_cache_stat[smp_processor_id()].out_slow_tot++; + if (flags & RTCF_LOCAL) { rth->u.dst.input = ip_local_deliver; rth->rt_spec_dst = key.dst; } if (flags & (RTCF_BROADCAST | RTCF_MULTICAST)) { rth->rt_spec_dst = key.src; - if (flags & RTCF_LOCAL && !(dev_out->flags & IFF_LOOPBACK)) + if (flags & RTCF_LOCAL && !(dev_out->flags & IFF_LOOPBACK)) { rth->u.dst.output = ip_mc_output; + rt_cache_stat[smp_processor_id()].out_slow_mc++; + } #ifdef CONFIG_IP_MROUTE if (res.type == RTN_MULTICAST) { struct in_device *in_dev = in_dev_get(dev_out); @@ -1957,6 +2008,7 @@ rth->u.dst.lastuse = jiffies; dst_hold(&rth->u.dst); rth->u.dst.__use++; + rt_cache_stat[smp_processor_id()].out_hit++; read_unlock_bh(&rt_hash_table[hash].lock); *rp = rth; return 0; @@ -2474,6 +2526,7 @@ add_timer(&rt_periodic_timer); proc_net_create ("rt_cache", 0, rt_cache_get_info); + proc_net_create ("rt_cache_stat", 0, rt_cache_stat_get_info); #ifdef CONFIG_NET_CLS_ROUTE create_proc_read_entry("net/rt_acct", 0, 0, ip_rt_acct_read, NULL); #endif diff -u --recursive --new-file v2.4.6/linux/net/ipv4/tcp_output.c linux/net/ipv4/tcp_output.c --- v2.4.6/linux/net/ipv4/tcp_output.c Tue Jul 3 17:08:22 2001 +++ linux/net/ipv4/tcp_output.c Tue Jul 10 16:11:43 2001 @@ -5,7 +5,7 @@ * * Implementation of the Transmission Control Protocol(TCP). * - * Version: $Id: tcp_output.c,v 1.136 2001/03/06 22:42:56 davem Exp $ + * Version: $Id: tcp_output.c,v 1.137 2001/06/29 21:11:28 davem Exp $ * * Authors: Ross Biro, <bir7@leland.Stanford.Edu> * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> diff -u --recursive --new-file v2.4.6/linux/net/irda/Makefile linux/net/irda/Makefile --- v2.4.6/linux/net/irda/Makefile Fri Dec 29 14:07:24 2000 +++ linux/net/irda/Makefile Wed Jul 4 11:50:38 2001 @@ -20,7 +20,6 @@ obj-m := $(O_TARGET) endif -obj-$(CONFIG_IRDA_COMPRESSION) += irlap_comp.o obj-$(CONFIG_PROC_FS) += irproc.o obj-$(CONFIG_SYSCTL) += irsysctl.o obj-$(CONFIG_IRLAN) += irlan/irlan.o @@ -28,7 +27,6 @@ subdir-$(CONFIG_IRLAN) += irlan subdir-$(CONFIG_IRNET) += irnet subdir-$(CONFIG_IRCOMM) += ircomm -subdir-$(CONFIG_IRDA_COMPRESSION) += compressors ifeq ($(CONFIG_IRLAN),y) obj-y += irlan/irlan.o @@ -36,14 +34,6 @@ ifeq ($(CONFIG_IRNET),y) obj-y += irnet/irnet.o -endif - -ifeq ($(CONFIG_IRDA_DEFLATE),y) -obj-y += compressors/irda_deflate.o -else - ifeq ($(CONFIG_IRDA_DEFLATE),m) - MOD_TO_LIST += irda_deflate.o - endif endif ifeq ($(CONFIG_IRCOMM),y) diff -u --recursive --new-file v2.4.6/linux/net/irda/af_irda.c linux/net/irda/af_irda.c --- v2.4.6/linux/net/irda/af_irda.c Sat May 19 17:47:55 2001 +++ linux/net/irda/af_irda.c Wed Jul 4 11:50:38 2001 @@ -218,8 +218,7 @@ self->max_data_size); memcpy(&self->qos_tx, qos, sizeof(struct qos_info)); - - skb_queue_tail(&sk->receive_queue, skb); + kfree_skb(skb); /* We are now connected! */ sk->state = TCP_ESTABLISHED; @@ -439,7 +438,7 @@ * We were waiting for a node to be discovered, but nothing has come up * so far. Wake up the user and tell him that we failed... */ -static void irda_discovery_timeout(u_long priv) +static void irda_discovery_timeout(u_long priv) { struct irda_sock *self; @@ -776,7 +775,6 @@ struct sock *sk = sock->sk; struct sockaddr_irda *addr = (struct sockaddr_irda *) uaddr; struct irda_sock *self; - __u16 hints = 0; int err; IRDA_DEBUG(2, __FUNCTION__ "()\n"); @@ -821,15 +819,6 @@ self->stsap_sel, IAS_KERNEL_ATTR); irias_insert_object(self->ias_obj); -#if 1 /* Will be removed in near future */ - - /* Fill in some default hint bits values */ - if (strncmp(addr->sir_name, "OBEX", 4) == 0) - hints = irlmp_service_to_hint(S_OBEX); - - if (hints) - self->skey = irlmp_register_service(hints); -#endif return 0; } @@ -1079,8 +1068,10 @@ return -ENOMEM; self = kmalloc(sizeof(struct irda_sock), GFP_ATOMIC); - if (self == NULL) + if (self == NULL) { + kfree (sk); return -ENOMEM; + } memset(self, 0, sizeof(struct irda_sock)); init_waitqueue_head(&self->query_wait); @@ -1633,34 +1624,58 @@ { struct sock *sk = sock->sk; unsigned int mask; + struct irda_sock *self; IRDA_DEBUG(4, __FUNCTION__ "()\n"); + self = sk->protinfo.irda; poll_wait(file, sk->sleep, wait); mask = 0; - /* exceptional events? */ + /* Exceptional events? */ if (sk->err) mask |= POLLERR; - if (sk->shutdown & RCV_SHUTDOWN) + if (sk->shutdown & RCV_SHUTDOWN) { + IRDA_DEBUG(0, __FUNCTION__ "(), POLLHUP\n"); mask |= POLLHUP; + } - /* readable? */ + /* Readable? */ if (!skb_queue_empty(&sk->receive_queue)) { IRDA_DEBUG(4, "Socket is readable\n"); mask |= POLLIN | POLLRDNORM; } + /* Connection-based need to check for termination and startup */ - if (sk->type == SOCK_STREAM && sk->state==TCP_CLOSE) - mask |= POLLHUP; + switch (sk->type) { + case SOCK_STREAM: + if (sk->state == TCP_CLOSE) { + IRDA_DEBUG(0, __FUNCTION__ "(), POLLHUP\n"); + mask |= POLLHUP; + } - /* - * we set writable also when the other side has shut down the - * connection. This prevents stuck sockets. - */ - if (sk->sndbuf - (int)atomic_read(&sk->wmem_alloc) >= SOCK_MIN_WRITE_SPACE) + if (sk->state == TCP_ESTABLISHED) { + if ((self->tx_flow == FLOW_START) && + (sk->sndbuf - (int)atomic_read(&sk->wmem_alloc) >= SOCK_MIN_WRITE_SPACE)) + { + mask |= POLLOUT | POLLWRNORM | POLLWRBAND; + } + } + break; + case SOCK_SEQPACKET: + if ((self->tx_flow == FLOW_START) && + (sk->sndbuf - (int)atomic_read(&sk->wmem_alloc) >= SOCK_MIN_WRITE_SPACE)) + { mask |= POLLOUT | POLLWRNORM | POLLWRBAND; - + } + break; + case SOCK_DGRAM: + if (sk->sndbuf - (int)atomic_read(&sk->wmem_alloc) >= SOCK_MIN_WRITE_SPACE) + mask |= POLLOUT | POLLWRNORM | POLLWRBAND; + break; + default: + break; + } return mask; } @@ -1740,7 +1755,7 @@ { struct sock *sk = sock->sk; struct irda_sock *self; - struct irda_ias_set ias_opt; + struct irda_ias_set *ias_opt; struct ias_object *ias_obj; struct ias_attrib * ias_attr; /* Attribute in IAS object */ int opt; @@ -1763,64 +1778,78 @@ if (optlen != sizeof(struct irda_ias_set)) return -EINVAL; + ias_opt = kmalloc(sizeof(struct irda_ias_set), GFP_ATOMIC); + if (ias_opt == NULL) + return -ENOMEM; + /* Copy query to the driver. */ - if (copy_from_user(&ias_opt, (char *)optval, optlen)) + if (copy_from_user(ias_opt, (char *)optval, optlen)) { + kfree(ias_opt); return -EFAULT; + } /* Find the object we target */ - ias_obj = irias_find_object(ias_opt.irda_class_name); + ias_obj = irias_find_object(ias_opt->irda_class_name); if(ias_obj == (struct ias_object *) NULL) { /* Create a new object */ - ias_obj = irias_new_object(ias_opt.irda_class_name, + ias_obj = irias_new_object(ias_opt->irda_class_name, jiffies); } /* Do we have it already ? */ - if(irias_find_attrib(ias_obj, ias_opt.irda_attrib_name)) + if(irias_find_attrib(ias_obj, ias_opt->irda_attrib_name)) { + kfree(ias_opt); return -EINVAL; + } /* Look at the type */ - switch(ias_opt.irda_attrib_type) { + switch(ias_opt->irda_attrib_type) { case IAS_INTEGER: /* Add an integer attribute */ irias_add_integer_attrib( ias_obj, - ias_opt.irda_attrib_name, - ias_opt.attribute.irda_attrib_int, + ias_opt->irda_attrib_name, + ias_opt->attribute.irda_attrib_int, IAS_USER_ATTR); break; case IAS_OCT_SEQ: /* Check length */ - if(ias_opt.attribute.irda_attrib_octet_seq.len > - IAS_MAX_OCTET_STRING) + if(ias_opt->attribute.irda_attrib_octet_seq.len > + IAS_MAX_OCTET_STRING) { + kfree(ias_opt); return -EINVAL; + } /* Add an octet sequence attribute */ irias_add_octseq_attrib( ias_obj, - ias_opt.irda_attrib_name, - ias_opt.attribute.irda_attrib_octet_seq.octet_seq, - ias_opt.attribute.irda_attrib_octet_seq.len, + ias_opt->irda_attrib_name, + ias_opt->attribute.irda_attrib_octet_seq.octet_seq, + ias_opt->attribute.irda_attrib_octet_seq.len, IAS_USER_ATTR); break; case IAS_STRING: /* Should check charset & co */ /* Check length */ - if(ias_opt.attribute.irda_attrib_string.len > - IAS_MAX_STRING) + if(ias_opt->attribute.irda_attrib_string.len > + IAS_MAX_STRING) { + kfree(ias_opt); return -EINVAL; + } /* NULL terminate the string (avoid troubles) */ - ias_opt.attribute.irda_attrib_string.string[ias_opt.attribute.irda_attrib_string.len] = '\0'; + ias_opt->attribute.irda_attrib_string.string[ias_opt->attribute.irda_attrib_string.len] = '\0'; /* Add a string attribute */ irias_add_string_attrib( ias_obj, - ias_opt.irda_attrib_name, - ias_opt.attribute.irda_attrib_string.string, + ias_opt->irda_attrib_name, + ias_opt->attribute.irda_attrib_string.string, IAS_USER_ATTR); break; default : + kfree(ias_opt); return -EINVAL; } irias_insert_object(ias_obj); + kfree(ias_opt); break; case IRLMP_IAS_DEL: /* The user want to delete an object from our local IAS @@ -1831,31 +1860,42 @@ if (optlen != sizeof(struct irda_ias_set)) return -EINVAL; + ias_opt = kmalloc(sizeof(struct irda_ias_set), GFP_ATOMIC); + if (ias_opt == NULL) + return -ENOMEM; + /* Copy query to the driver. */ - if (copy_from_user(&ias_opt, (char *)optval, optlen)) + if (copy_from_user(ias_opt, (char *)optval, optlen)) { + kfree(ias_opt); return -EFAULT; + } /* Find the object we target */ - ias_obj = irias_find_object(ias_opt.irda_class_name); - if(ias_obj == (struct ias_object *) NULL) + ias_obj = irias_find_object(ias_opt->irda_class_name); + if(ias_obj == (struct ias_object *) NULL) { + kfree(ias_opt); return -EINVAL; + } /* Find the attribute (in the object) we target */ ias_attr = irias_find_attrib(ias_obj, - ias_opt.irda_attrib_name); - if(ias_attr == (struct ias_attrib *) NULL) + ias_opt->irda_attrib_name); + if(ias_attr == (struct ias_attrib *) NULL) { + kfree(ias_opt); return -EINVAL; + } /* Check is the user space own the object */ if(ias_attr->value->owner != IAS_USER_ATTR) { IRDA_DEBUG(1, __FUNCTION__ "(), attempting to delete a kernel attribute\n"); + kfree(ias_opt); return -EPERM; } /* Remove the attribute (and maybe the object) */ irias_delete_attrib(ias_obj, ias_attr); - + kfree(ias_opt); break; case IRLMP_MAX_SDU_SIZE: if (optlen < sizeof(int)) @@ -1978,7 +2018,7 @@ struct irda_sock *self; struct irda_device_list list; struct irda_device_info *discoveries; - struct irda_ias_set ias_opt; /* IAS get/query params */ + struct irda_ias_set * ias_opt; /* IAS get/query params */ struct ias_object * ias_obj; /* Object in IAS */ struct ias_attrib * ias_attr; /* Attribute in IAS object */ int daddr = DEV_ADDR_ANY; /* Dest address for IAS queries */ @@ -2048,34 +2088,49 @@ * that we found */ /* Check that the user has allocated the right space for us */ - if (len != sizeof(ias_opt)) + if (len != sizeof(struct irda_ias_set)) return -EINVAL; + ias_opt = kmalloc(sizeof(struct irda_ias_set), GFP_ATOMIC); + if (ias_opt == NULL) + return -ENOMEM; + /* Copy query to the driver. */ - if (copy_from_user((char *) &ias_opt, (char *)optval, len)) + if (copy_from_user((char *) ias_opt, (char *)optval, len)) { + kfree(ias_opt); return -EFAULT; + } /* Find the object we target */ - ias_obj = irias_find_object(ias_opt.irda_class_name); - if(ias_obj == (struct ias_object *) NULL) + ias_obj = irias_find_object(ias_opt->irda_class_name); + if(ias_obj == (struct ias_object *) NULL) { + kfree(ias_opt); return -EINVAL; + } /* Find the attribute (in the object) we target */ ias_attr = irias_find_attrib(ias_obj, - ias_opt.irda_attrib_name); - if(ias_attr == (struct ias_attrib *) NULL) + ias_opt->irda_attrib_name); + if(ias_attr == (struct ias_attrib *) NULL) { + kfree(ias_opt); return -EINVAL; + } /* Translate from internal to user structure */ - err = irda_extract_ias_value(&ias_opt, ias_attr->value); - if(err) + err = irda_extract_ias_value(ias_opt, ias_attr->value); + if(err) { + kfree(ias_opt); return err; + } /* Copy reply to the user */ - if (copy_to_user((char *)optval, (char *) &ias_opt, - sizeof(ias_opt))) + if (copy_to_user((char *)optval, (char *) ias_opt, + sizeof(struct irda_ias_set))) { + kfree(ias_opt); return -EFAULT; + } /* Note : don't need to put optlen, we checked it */ + kfree(ias_opt); break; case IRLMP_IAS_QUERY: /* The user want an object from a remote IAS database. @@ -2083,12 +2138,18 @@ * then wait for the answer to come back. */ /* Check that the user has allocated the right space for us */ - if (len != sizeof(ias_opt)) + if (len != sizeof(struct irda_ias_set)) return -EINVAL; + ias_opt = kmalloc(sizeof(struct irda_ias_set), GFP_ATOMIC); + if (ias_opt == NULL) + return -ENOMEM; + /* Copy query to the driver. */ - if (copy_from_user((char *) &ias_opt, (char *)optval, len)) + if (copy_from_user((char *) ias_opt, (char *)optval, len)) { + kfree(ias_opt); return -EFAULT; + } /* At this point, there are two cases... * 1) the socket is connected - that's the easy case, we @@ -2105,15 +2166,18 @@ } else { /* We are not connected, we must specify a valid * destination address */ - daddr = ias_opt.daddr; - if((!daddr) || (daddr == DEV_ADDR_ANY)) + daddr = ias_opt->daddr; + if((!daddr) || (daddr == DEV_ADDR_ANY)) { + kfree(ias_opt); return -EINVAL; + } } /* Check that we can proceed with IAP */ if (self->iriap) { WARNING(__FUNCTION__ "(), busy with a previous query\n"); + kfree(ias_opt); return -EBUSY; } @@ -2126,14 +2190,15 @@ /* Query remote LM-IAS */ iriap_getvaluebyclass_request(self->iriap, self->saddr, daddr, - ias_opt.irda_class_name, - ias_opt.irda_attrib_name); + ias_opt->irda_class_name, + ias_opt->irda_attrib_name); /* Wait for answer (if not already failed) */ if(self->iriap != NULL) interruptible_sleep_on(&self->query_wait); /* Check what happened */ if (self->errno) { + kfree(ias_opt); /* Requested object/attribute doesn't exist */ if((self->errno == IAS_CLASS_UNKNOWN) || (self->errno == IAS_ATTRIB_UNKNOWN)) @@ -2143,17 +2208,22 @@ } /* Translate from internal to user structure */ - err = irda_extract_ias_value(&ias_opt, self->ias_result); + err = irda_extract_ias_value(ias_opt, self->ias_result); if (self->ias_result) irias_delete_value(self->ias_result); - if (err) + if (err) { + kfree(ias_opt); return err; + } /* Copy reply to the user */ - if (copy_to_user((char *)optval, (char *) &ias_opt, - sizeof(ias_opt))) + if (copy_to_user((char *)optval, (char *) ias_opt, + sizeof(struct irda_ias_set))) { + kfree(ias_opt); return -EFAULT; + } /* Note : don't need to put optlen, we checked it */ + kfree(ias_opt); break; case IRLMP_WAITDEVICE: /* This function is just another way of seeing life ;-) @@ -2328,6 +2398,9 @@ SOCKOPS_WRAP(irda_stream, PF_IRDA); SOCKOPS_WRAP(irda_seqpacket, PF_IRDA); SOCKOPS_WRAP(irda_dgram, PF_IRDA); +#ifdef CONFIG_IRDA_ULTRA +SOCKOPS_WRAP(irda_ultra, PF_IRDA); +#endif /* CONFIG_IRDA_ULTRA */ /* * Function irda_device_event (this, event, ptr) @@ -2416,7 +2489,9 @@ #endif return 0; } -module_init(irda_proto_init); +#ifdef MODULE +module_init(irda_proto_init); /* If non-module, called from init/main.c */ +#endif /* * Function irda_proto_cleanup (void) diff -u --recursive --new-file v2.4.6/linux/net/irda/compressors/Config.in linux/net/irda/compressors/Config.in --- v2.4.6/linux/net/irda/compressors/Config.in Wed Sep 29 15:32:14 1999 +++ linux/net/irda/compressors/Config.in Wed Dec 31 16:00:00 1969 @@ -1,11 +0,0 @@ - -bool ' IrLAP compression' CONFIG_IRDA_COMPRESSION - -if [ "$CONFIG_IRDA_COMPRESSION" != "n" ]; then - comment ' IrDA compressors' - if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - dep_tristate ' Deflate compression (EXPERIMENTAL)' CONFIG_IRDA_DEFLATE $CONFIG_IRDA - fi -# tristate ' BZIP2 compression' CONFIG_IRDA_BZIP2 -# tristate ' BSD compression' CONFIG_IRDA_BSD -fi diff -u --recursive --new-file v2.4.6/linux/net/irda/compressors/Makefile linux/net/irda/compressors/Makefile --- v2.4.6/linux/net/irda/compressors/Makefile Fri Dec 29 14:07:24 2000 +++ linux/net/irda/compressors/Makefile Wed Dec 31 16:00:00 1969 @@ -1,20 +0,0 @@ -# -# Makefile for the Linux IRDA compression protocols -# -# Note! Dependencies are done automagically by 'make dep', which also -# removes any old dependencies. DON'T put your own dependencies here -# unless it's something special (ie not a .c file). -# -# Note 2! The CFLAGS definition is now in the main makefile... - -O_TARGET := - -obj-y := -obj-m := - -obj-$(CONFIG_IRDA_DEFLATE) += irda_deflate.o - -include $(TOPDIR)/Rules.make - -tar: - tar -cvf /dev/f1 . diff -u --recursive --new-file v2.4.6/linux/net/irda/compressors/irda_deflate.c linux/net/irda/compressors/irda_deflate.c --- v2.4.6/linux/net/irda/compressors/irda_deflate.c Fri Feb 9 11:29:44 2001 +++ linux/net/irda/compressors/irda_deflate.c Wed Dec 31 16:00:00 1969 @@ -1,634 +0,0 @@ -/********************************************************************* - * - * Filename: irda_deflate.c - * Version: - * Description: - * Status: Experimental. - * Author: Dag Brattli <dagb@cs.uit.no> - * Created at: Fri Oct 9 02:52:08 1998 - * Modified at: Mon Dec 14 19:48:54 1998 - * Modified by: Dag Brattli <dagb@cs.uit.no> - * - * ==FILEVERSION 980319== - * - * irda_deflate.c - interface the zlib procedures for Deflate compression - * and decompression (as used by gzip) to the IrDA code. - * This version is for use with Linux kernel 2.1.X. - * - * Copyright (c) 1994 The Australian National University. - * All rights reserved. - * - * Permission to use, copy, modify, and distribute this software and its - * documentation is hereby granted, provided that the above copyright - * notice appears in all copies. This software is provided without any - * warranty, express or implied. The Australian National University - * makes no representations about the suitability of this software for - * any purpose. - * - * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY - * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES - * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF - * THE AUSTRALIAN NATIONAL UNIVERSITY HAS BEEN ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY - * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS - * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO - * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, - * OR MODIFICATIONS. - * - * From: deflate.c,v 1.1 1996/01/18 03:17:48 paulus Exp - */ - -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/init.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/slab.h> -#include <linux/vmalloc.h> -#include <linux/errno.h> -#include <linux/string.h> /* used in new tty drivers */ -#include <linux/signal.h> /* used in new tty drivers */ - -#include <asm/system.h> - -#include <linux/netdevice.h> -#include <linux/skbuff.h> -#include <linux/inet.h> -#include <linux/ioctl.h> - -#include <linux/ppp_defs.h> -#include <linux/ppp-comp.h> - -/* - * This is not that nice, but what can we do when the code has been placed - * elsewhere - */ - -#include "../../../drivers/net/zlib.c" - -/* - * State for a Deflate (de)compressor. - */ -struct irda_deflate_state { - int seqno; - int w_size; - int unit; - int mru; - int debug; - z_stream strm; - struct compstat stats; -}; - -#define DEFLATE_OVHD 2 /* Deflate overhead/packet */ - -static void *zalloc __P((void *, unsigned int items, unsigned int size)); -static void *zalloc_init __P((void *, unsigned int items, - unsigned int size)); -static void zfree __P((void *, void *ptr)); -static void *z_comp_alloc __P((unsigned char *options, int opt_len)); -static void *z_decomp_alloc __P((unsigned char *options, int opt_len)); -static void z_comp_free __P((void *state)); -static void z_decomp_free __P((void *state)); -static int z_comp_init __P((void *state, unsigned char *options, - int opt_len, - int unit, int hdrlen, int debug)); -static int z_decomp_init __P((void *state, unsigned char *options, - int opt_len, - int unit, int hdrlen, int mru, int debug)); -static int z_compress __P((void *state, unsigned char *rptr, - unsigned char *obuf, - int isize, int osize)); -static void z_incomp __P((void *state, unsigned char *ibuf, int icnt)); -static int z_decompress __P((void *state, unsigned char *ibuf, - int isize, unsigned char *obuf, int osize)); -static void z_comp_reset __P((void *state)); -static void z_decomp_reset __P((void *state)); -static void z_comp_stats __P((void *state, struct compstat *stats)); - -struct chunk_header { - int valloced; /* allocated with valloc, not kmalloc */ - int guard; /* check for overwritten header */ -}; - -#define GUARD_MAGIC 0x77a8011a -#define MIN_VMALLOC 2048 /* use kmalloc for blocks < this */ - -/* - * Space allocation and freeing routines for use by zlib routines. - */ -void zfree(void *arg, void *ptr) -{ - struct chunk_header *hdr = ((struct chunk_header *)ptr) - 1; - - if (hdr->guard != GUARD_MAGIC) { - printk(KERN_WARNING "zfree: header corrupted (%x %x) at %p\n", - hdr->valloced, hdr->guard, hdr); - return; - } - if (hdr->valloced) - vfree(hdr); - else - kfree(hdr); -} - -void * -zalloc(arg, items, size) - void *arg; - unsigned int items, size; -{ - struct chunk_header *hdr; - unsigned nbytes; - - nbytes = items * size + sizeof(*hdr); - hdr = kmalloc(nbytes, GFP_ATOMIC); - if (hdr == 0) - return 0; - hdr->valloced = 0; - hdr->guard = GUARD_MAGIC; - return (void *) (hdr + 1); -} - -void * zalloc_init(void *arg, unsigned int items, unsigned int size) -{ - struct chunk_header *hdr; - unsigned nbytes; - - nbytes = items * size + sizeof(*hdr); - if (nbytes >= MIN_VMALLOC) - hdr = vmalloc(nbytes); - else - hdr = kmalloc(nbytes, GFP_KERNEL); - if (hdr == 0) - return 0; - hdr->valloced = nbytes >= MIN_VMALLOC; - hdr->guard = GUARD_MAGIC; - return (void *) (hdr + 1); -} - -static void -z_comp_free(arg) - void *arg; -{ - struct irda_deflate_state *state = (struct irda_deflate_state *) arg; - - if (state) { - deflateEnd(&state->strm); - kfree(state); - MOD_DEC_USE_COUNT; - } -} - -/* - * Allocate space for a compressor. - */ -static void * -z_comp_alloc(options, opt_len) - unsigned char *options; - int opt_len; -{ - struct irda_deflate_state *state; - int w_size; - - if (opt_len != CILEN_DEFLATE - || (options[0] != CI_DEFLATE && options[0] != CI_DEFLATE_DRAFT) - || options[1] != CILEN_DEFLATE - || DEFLATE_METHOD(options[2]) != DEFLATE_METHOD_VAL - || options[3] != DEFLATE_CHK_SEQUENCE) - return NULL; - w_size = DEFLATE_SIZE(options[2]); - w_size = MAX_WBITS; - if (w_size < DEFLATE_MIN_SIZE || w_size > DEFLATE_MAX_SIZE) - return NULL; - - state = (struct irda_deflate_state *) kmalloc(sizeof(*state), GFP_KERNEL); - if (state == NULL) - return NULL; - - MOD_INC_USE_COUNT; - memset (state, 0, sizeof (struct irda_deflate_state)); - state->strm.next_in = NULL; - state->strm.zalloc = zalloc_init; - state->strm.zfree = zfree; - state->w_size = w_size; - - if (deflateInit2(&state->strm, Z_DEFAULT_COMPRESSION, - DEFLATE_METHOD_VAL, -w_size, 8, Z_DEFAULT_STRATEGY) - != Z_OK) - goto out_free; - state->strm.zalloc = zalloc; - return (void *) state; - -out_free: - z_comp_free(state); - MOD_DEC_USE_COUNT; - return NULL; -} - -static int -z_comp_init(arg, options, opt_len, unit, hdrlen, debug) - void *arg; - unsigned char *options; - int opt_len, unit, hdrlen, debug; -{ - struct irda_deflate_state *state = (struct irda_deflate_state *) arg; - - if (opt_len < CILEN_DEFLATE - || (options[0] != CI_DEFLATE && options[0] != CI_DEFLATE_DRAFT) - || options[1] != CILEN_DEFLATE - || DEFLATE_METHOD(options[2]) != DEFLATE_METHOD_VAL - || DEFLATE_SIZE(options[2]) != state->w_size - || options[3] != DEFLATE_CHK_SEQUENCE) - return 0; - - state->seqno = 0; - state->unit = unit; - state->debug = debug; - - deflateReset(&state->strm); - - return 1; -} - -static void z_comp_reset(void *arg) -{ - struct irda_deflate_state *state = (struct irda_deflate_state *) arg; - - state->seqno = 0; - deflateReset(&state->strm); -} - -int -z_compress(arg, rptr, obuf, isize, osize) - void *arg; - unsigned char *rptr; /* uncompressed packet (in) */ - unsigned char *obuf; /* compressed packet (out) */ - int isize, osize; -{ - struct irda_deflate_state *state = (struct irda_deflate_state *) arg; - int r, olen, oavail; - - olen = 0; - - /* Don't generate compressed packets which are larger than - the uncompressed packet. */ - if (osize > isize) - osize = isize; - - state->strm.next_out = obuf; - state->strm.avail_out = oavail = osize; - - state->strm.next_in = rptr; - state->strm.avail_in = isize; - - for (;;) { - r = deflate(&state->strm, Z_PACKET_FLUSH); - if (r != Z_OK) { - if (state->debug) - printk(KERN_ERR - "z_compress: deflate returned %d\n", r); - break; - } - if (state->strm.avail_out == 0) { - olen += oavail; - state->strm.next_out = NULL; - state->strm.avail_out = oavail = 1000000; - } else { - break; /* all done */ - } - } - olen += oavail - state->strm.avail_out; - - /* - * See if we managed to reduce the size of the packet. - */ - if (olen < isize) { - state->stats.comp_bytes += olen; - state->stats.comp_packets++; - } else { - state->stats.inc_bytes += isize; - state->stats.inc_packets++; - olen = 0; - } - state->stats.unc_bytes += isize; - state->stats.unc_packets++; - - return olen; -} - -static void -z_comp_stats(arg, stats) - void *arg; - struct compstat *stats; -{ - struct irda_deflate_state *state = (struct irda_deflate_state *) arg; - - *stats = state->stats; -} - -static void z_decomp_free(void *arg) -{ - struct irda_deflate_state *state = (struct irda_deflate_state *) arg; - - if (state) { - inflateEnd(&state->strm); - kfree(state); - MOD_DEC_USE_COUNT; - } -} - -/* - * Allocate space for a decompressor. - */ -static void * -z_decomp_alloc(options, opt_len) - unsigned char *options; - int opt_len; -{ - struct irda_deflate_state *state; - int w_size; - - if (opt_len != CILEN_DEFLATE - || (options[0] != CI_DEFLATE && options[0] != CI_DEFLATE_DRAFT) - || options[1] != CILEN_DEFLATE - || DEFLATE_METHOD(options[2]) != DEFLATE_METHOD_VAL - || options[3] != DEFLATE_CHK_SEQUENCE) - return NULL; - w_size = DEFLATE_SIZE(options[2]); - w_size = MAX_WBITS; - if (w_size < DEFLATE_MIN_SIZE || w_size > DEFLATE_MAX_SIZE) - return NULL; - - state = (struct irda_deflate_state *) kmalloc(sizeof(*state), GFP_KERNEL); - if (state == NULL) - return NULL; - - MOD_INC_USE_COUNT; - memset (state, 0, sizeof (struct irda_deflate_state)); - state->w_size = w_size; - state->strm.next_out = NULL; - state->strm.zalloc = zalloc_init; - state->strm.zfree = zfree; - - if (inflateInit2(&state->strm, -w_size) != Z_OK) - goto out_free; - state->strm.zalloc = zalloc; - return (void *) state; - -out_free: - z_decomp_free(state); - MOD_DEC_USE_COUNT; - return NULL; -} - -static int -z_decomp_init(arg, options, opt_len, unit, hdrlen, mru, debug) - void *arg; - unsigned char *options; - int opt_len, unit, hdrlen, mru, debug; -{ - struct irda_deflate_state *state = (struct irda_deflate_state *) arg; - - if (opt_len < CILEN_DEFLATE - || (options[0] != CI_DEFLATE && options[0] != CI_DEFLATE_DRAFT) - || options[1] != CILEN_DEFLATE - || DEFLATE_METHOD(options[2]) != DEFLATE_METHOD_VAL - || DEFLATE_SIZE(options[2]) != state->w_size - || options[3] != DEFLATE_CHK_SEQUENCE) - return 0; - - state->seqno = 0; - state->unit = unit; - state->debug = debug; - state->mru = mru; - - inflateReset(&state->strm); - - return 1; -} - -static void z_decomp_reset(void *arg) -{ - struct irda_deflate_state *state = (struct irda_deflate_state *) arg; - - state->seqno = 0; - inflateReset(&state->strm); -} - -/* - * Decompress a Deflate-compressed packet. - * - * Because of patent problems, we return DECOMP_ERROR for errors - * found by inspecting the input data and for system problems, but - * DECOMP_FATALERROR for any errors which could possibly be said to - * be being detected "after" decompression. For DECOMP_ERROR, - * we can issue a CCP reset-request; for DECOMP_FATALERROR, we may be - * infringing a patent of Motorola's if we do, so we take CCP down - * instead. - * - * Given that the frame has the correct sequence number and a good FCS, - * errors such as invalid codes in the input most likely indicate a - * bug, so we return DECOMP_FATALERROR for them in order to turn off - * compression, even though they are detected by inspecting the input. - */ -int -z_decompress(arg, ibuf, isize, obuf, osize) - void *arg; - unsigned char *ibuf; - int isize; - unsigned char *obuf; - int osize; -{ - struct irda_deflate_state *state = (struct irda_deflate_state *) arg; - int olen, r; - int overflow; - unsigned char overflow_buf[1]; - - if (isize <= DEFLATE_OVHD) { - if (state->debug) - printk(KERN_DEBUG "z_decompress%d: short pkt (%d)\n", - state->unit, isize); - return DECOMP_ERROR; - } - - /* - * Set up to call inflate. - */ - state->strm.next_in = ibuf; - state->strm.avail_in = isize; - state->strm.next_out = obuf; - state->strm.avail_out = osize; - overflow = 0; - - /* - * Call inflate, supplying more input or output as needed. - */ - for (;;) { - r = inflate(&state->strm, Z_PACKET_FLUSH); - if (r != Z_OK) { - if (state->debug) - printk(KERN_DEBUG "z_decompress%d: inflate returned %d (%s)\n", - state->unit, r, (state->strm.msg? state->strm.msg: "")); - return DECOMP_FATALERROR; - } - if (state->strm.avail_out != 0) - break; /* all done */ - - if (!overflow) { - /* - * We've filled up the output buffer; the only way to - * find out whether inflate has any more characters - * left is to give it another byte of output space. - */ - state->strm.next_out = overflow_buf; - state->strm.avail_out = 1; - overflow = 1; - } else { - if (state->debug) - printk(KERN_DEBUG "z_decompress%d: ran out of mru\n", - state->unit); - return DECOMP_FATALERROR; - } - } - - olen = osize + overflow - state->strm.avail_out; - state->stats.unc_bytes += olen; - state->stats.unc_packets++; - state->stats.comp_bytes += isize; - state->stats.comp_packets++; - - return olen; -} - -/* - * Incompressible data has arrived - add it to the history. - */ -static void -z_incomp(arg, ibuf, icnt) - void *arg; - unsigned char *ibuf; - int icnt; -{ - struct irda_deflate_state *state = (struct irda_deflate_state *) arg; - int r; - - /* - * Check that the protocol is one we handle. - */ - - /* - * We start at the either the 1st or 2nd byte of the protocol field, - * depending on whether the protocol value is compressible. - */ - state->strm.next_in = ibuf; - state->strm.avail_in = icnt; - - r = inflateIncomp(&state->strm); - if (r != Z_OK) { - /* gak! */ - if (state->debug) { - printk(KERN_DEBUG "z_incomp%d: inflateIncomp returned %d (%s)\n", - state->unit, r, (state->strm.msg? state->strm.msg: "")); - } - return; - } - - /* - * Update stats. - */ - state->stats.inc_bytes += icnt; - state->stats.inc_packets++; - state->stats.unc_bytes += icnt; - state->stats.unc_packets++; -} - -/************************************************************* - * Module interface table - *************************************************************/ - -/* These are in ppp.c */ -extern int irda_register_compressor (struct compressor *cp); -extern void irda_unregister_compressor (struct compressor *cp); - -/* - * Procedures exported to if_ppp.c. - */ -static struct compressor irda_deflate = { -compress_proto: CI_DEFLATE, -comp_alloc: z_comp_alloc, -comp_free: z_comp_free, -comp_init: z_comp_init, -comp_reset: z_comp_reset, -compress: z_compress, -comp_stat: z_comp_stats, -decomp_alloc: z_decomp_alloc, -decomp_free: z_decomp_free, -decomp_init: z_decomp_init, -decomp_reset: z_decomp_reset, -decompress: z_decompress, -incomp: z_incomp, -decomp_stat: z_comp_stats -}; - -static struct compressor irda_deflate_draft = { -compress_proto: CI_DEFLATE_DRAFT, -comp_alloc: z_comp_alloc, -comp_free: z_comp_free, -comp_init: z_comp_init, -comp_reset: z_comp_reset, -compress: z_compress, -comp_stat: z_comp_stats, -decomp_alloc: z_decomp_alloc, -decomp_free: z_decomp_free, -decomp_init: z_decomp_init, -decomp_reset: z_decomp_reset, -decompress: z_decompress, -incomp: z_incomp, -decomp_stat: z_comp_stats -}; - -int __init irda_deflate_init(void) -{ - int answer = irda_register_compressor ( &irda_deflate); - if (answer == 0) - printk (KERN_INFO - "IrDA Deflate Compression module registered\n"); - irda_register_compressor( &irda_deflate_draft); - return answer; -} - -void irda_deflate_cleanup(void) -{ - - irda_unregister_compressor (&irda_deflate); - irda_unregister_compressor (&irda_deflate_draft); -} - -#ifdef MODULE -/************************************************************* - * Module support routines - *************************************************************/ - -int init_module(void) -{ - return irda_deflate_init(); -} - -void -cleanup_module(void) -{ - if (MOD_IN_USE) - printk (KERN_INFO - "Deflate Compression module busy, remove delayed\n"); - else { - irda_deflate_cleanup(); - } -} -#endif diff -u --recursive --new-file v2.4.6/linux/net/irda/ircomm/ircomm_tty_ioctl.c linux/net/irda/ircomm/ircomm_tty_ioctl.c --- v2.4.6/linux/net/irda/ircomm/ircomm_tty_ioctl.c Thu Jan 6 14:46:18 2000 +++ linux/net/irda/ircomm/ircomm_tty_ioctl.c Wed Jul 4 11:50:38 2001 @@ -221,16 +221,14 @@ { unsigned int arg; __u8 old_rts, old_dtr; - int error; IRDA_DEBUG(2, __FUNCTION__ "()\n"); ASSERT(self != NULL, return -1;); ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;); - error = get_user(arg, value); - if (error) - return error; + if (get_user(arg, value)) + return -EFAULT; old_rts = self->settings.dte & IRCOMM_RTS; old_dtr = self->settings.dte & IRCOMM_DTR; @@ -431,28 +429,18 @@ cnow = driver->icount; restore_flags(flags); p_cuser = (struct serial_icounter_struct *) arg; - error = put_user(cnow.cts, &p_cuser->cts); - if (error) return error; - error = put_user(cnow.dsr, &p_cuser->dsr); - if (error) return error; - error = put_user(cnow.rng, &p_cuser->rng); - if (error) return error; - error = put_user(cnow.dcd, &p_cuser->dcd); - if (error) return error; - error = put_user(cnow.rx, &p_cuser->rx); - if (error) return error; - error = put_user(cnow.tx, &p_cuser->tx); - if (error) return error; - error = put_user(cnow.frame, &p_cuser->frame); - if (error) return error; - error = put_user(cnow.overrun, &p_cuser->overrun); - if (error) return error; - error = put_user(cnow.parity, &p_cuser->parity); - if (error) return error; - error = put_user(cnow.brk, &p_cuser->brk); - if (error) return error; - error = put_user(cnow.buf_overrun, &p_cuser->buf_overrun); - if (error) return error; + if (put_user(cnow.cts, &p_cuser->cts) || + put_user(cnow.dsr, &p_cuser->dsr) || + put_user(cnow.rng, &p_cuser->rng) || + put_user(cnow.dcd, &p_cuser->dcd) || + put_user(cnow.rx, &p_cuser->rx) || + put_user(cnow.tx, &p_cuser->tx) || + put_user(cnow.frame, &p_cuser->frame) || + put_user(cnow.overrun, &p_cuser->overrun) || + put_user(cnow.parity, &p_cuser->parity) || + put_user(cnow.brk, &p_cuser->brk) || + put_user(cnow.buf_overrun, &p_cuser->buf_overrun)) + return -EFAULT; #endif return 0; default: diff -u --recursive --new-file v2.4.6/linux/net/irda/irias_object.c linux/net/irda/irias_object.c --- v2.4.6/linux/net/irda/irias_object.c Sat May 19 17:47:55 2001 +++ linux/net/irda/irias_object.c Wed Jul 4 11:50:38 2001 @@ -34,7 +34,7 @@ /* * Used when a missing value needs to be returned */ -struct ias_value missing = { IAS_MISSING, 0, 0, 0}; +struct ias_value missing = { IAS_MISSING, 0, 0, 0, {0}}; /* * Function strdup (str) diff -u --recursive --new-file v2.4.6/linux/net/irda/irlan/irlan_common.c linux/net/irda/irlan/irlan_common.c --- v2.4.6/linux/net/irda/irlan/irlan_common.c Sat Nov 11 18:11:23 2000 +++ linux/net/irda/irlan/irlan_common.c Wed Jul 4 11:50:38 2001 @@ -209,6 +209,7 @@ struct irlan_cb *self; IRDA_DEBUG(2, __FUNCTION__ "()\n"); + ASSERT(irlan != NULL, return NULL;); /* * Initialize the irlan structure. @@ -224,8 +225,6 @@ */ self->magic = IRLAN_MAGIC; - ASSERT(irlan != NULL, return NULL;); - sprintf(self->dev.name, "%s", "unknown"); self->dev.priv = (void *) self; @@ -1074,19 +1073,18 @@ { struct irlan_cb *self; unsigned long flags; + ASSERT(irlan != NULL, return 0;); save_flags(flags); cli(); - ASSERT(irlan != NULL, return 0;); - len = 0; len += sprintf(buf+len, "IrLAN instances:\n"); self = (struct irlan_cb *) hashbin_get_first(irlan); while (self != NULL) { - ASSERT(self->magic == IRLAN_MAGIC, return len;); + ASSERT(self->magic == IRLAN_MAGIC, break;); len += sprintf(buf+len, "ifname: %s,\n", self->dev.name); diff -u --recursive --new-file v2.4.6/linux/net/irda/irlap.c linux/net/irda/irlap.c --- v2.4.6/linux/net/irda/irlap.c Sat May 19 17:47:55 2001 +++ linux/net/irda/irlap.c Wed Jul 4 11:50:38 2001 @@ -46,7 +46,6 @@ #include <net/irda/irlap.h> #include <net/irda/timer.h> #include <net/irda/qos.h> -#include <net/irda/irlap_comp.h> hashbin_t *irlap = NULL; int sysctl_slot_timeout = SLOT_TIMEOUT * 1000 / HZ; @@ -79,15 +78,6 @@ return -ENOMEM; } -#ifdef CONFIG_IRDA_COMPRESSION - irlap_compressors = hashbin_new(HB_LOCAL); - if (irlap_compressors == NULL) { - WARNING(__FUNCTION__ - "(), can't allocate compressors hashbin!\n"); - return -ENOMEM; - } -#endif - return 0; } @@ -96,10 +86,6 @@ ASSERT(irlap != NULL, return;); hashbin_delete(irlap, (FREE_FUNC) __irlap_close); - -#ifdef CONFIG_IRDA_COMPRESSION - hashbin_delete(irlap_compressors, (FREE_FUNC) kfree); -#endif } /* @@ -312,16 +298,6 @@ /* Hide LAP header from IrLMP layer */ skb_pull(skb, LAP_ADDR_HEADER+LAP_CTRL_HEADER); -#ifdef CONFIG_IRDA_COMPRESSION - if (self->qos_tx.compression.value) { - skb_get(skb); /*LEVEL4*/ - skb = irlap_decompress_frame(self, skb); - if (!skb) { - IRDA_DEBUG(1, __FUNCTION__ "(), Decompress error!\n"); - return; - } - } -#endif skb_get(skb); /*LEVEL4*/ irlmp_link_data_indication(self->notify.instance, skb, unreliable); } @@ -341,15 +317,6 @@ IRDA_DEBUG(3, __FUNCTION__ "()\n"); -#ifdef CONFIG_IRDA_COMPRESSION - if (self->qos_tx.compression.value) { - skb = irlap_compress_frame(self, skb); - if (!skb) { - IRDA_DEBUG(1, __FUNCTION__ "(), Compress error!\n"); - return; - } - } -#endif ASSERT(skb_headroom(skb) >= (LAP_ADDR_HEADER+LAP_CTRL_HEADER), return;); skb_push(skb, LAP_ADDR_HEADER+LAP_CTRL_HEADER); @@ -482,9 +449,6 @@ ASSERT(self != NULL, return;); ASSERT(self->magic == LAP_MAGIC, return;); -#ifdef CONFIG_IRDA_COMPRESSION - irda_free_compression(self); -#endif /* Flush queues */ irlap_flush_all_queues(self); @@ -860,13 +824,6 @@ /* Free sliding window buffered packets */ while ((skb = skb_dequeue(&self->wx_list)) != NULL) dev_kfree_skb(skb); - -#ifdef CONFIG_IRDA_RECYCLE_RR - if (self->recycle_rr_skb) { - dev_kfree_skb(self->recycle_rr_skb); - self->recycle_rr_skb = NULL; - } -#endif } /* @@ -894,50 +851,6 @@ } } -#ifdef CONFIG_IRDA_COMPRESSION -void irlap_init_comp_qos_capabilities(struct irlap_cb *self) -{ - struct irda_compressor *comp; - __u8 mask; /* Current bit tested */ - int i; - - ASSERT(self != NULL, return;); - ASSERT(self->magic == LAP_MAGIC, return;); - - /* - * Find out which compressors we support. We do this be checking that - * the corresponding compressor for each bit set in the QoS bits has - * actually been loaded. Ths is sort of hairy code but that is what - * you get when you do a little bit flicking :-) - */ - IRDA_DEBUG(4, __FUNCTION__ "(), comp bits 0x%02x\n", - self->qos_rx.compression.bits); - mask = 0x80; /* Start with testing MSB */ - for (i=0;i<8;i++) { - IRDA_DEBUG(4, __FUNCTION__ "(), testing bit %d\n", 8-i); - if (self->qos_rx.compression.bits & mask) { - IRDA_DEBUG(4, __FUNCTION__ - "(), bit %d is set by defalt\n", 8-i); - comp = hashbin_find(irlap_compressors, - compressions[msb_index(mask)], - NULL); - if (!comp) { - /* Protocol not supported, so clear the bit */ - IRDA_DEBUG(4, __FUNCTION__ "(), Compression " - "protocol %d has not been loaded!\n", - compressions[msb_index(mask)]); - self->qos_rx.compression.bits &= ~mask; - IRDA_DEBUG(4, __FUNCTION__ - "(), comp bits 0x%02x\n", - self->qos_rx.compression.bits); - } - } - /* Try the next bit */ - mask >>= 1; - } -} -#endif - /* * Function irlap_init_qos_capabilities (self, qos) * @@ -956,10 +869,6 @@ /* Start out with the maximum QoS support possible */ irda_init_max_qos_capabilies(&self->qos_rx); -#ifdef CONFIG_IRDA_COMPRESSION - irlap_init_comp_qos_capabilities(self); -#endif - /* Apply drivers QoS capabilities */ irda_qos_compute_intersection(&self->qos_rx, self->qos_dev); @@ -981,9 +890,6 @@ if (qos_user->link_disc_time.bits) self->qos_rx.link_disc_time.bits &= qos_user->link_disc_time.bits; -#ifdef CONFIG_IRDA_COMPRESSION - self->qos_rx.compression.bits &= qos_user->compression.bits; -#endif } /* Use 500ms in IrLAP for now */ @@ -1076,7 +982,7 @@ /* Set the negociated xbofs value */ self->next_bofs = self->qos_tx.additional_bofs.value; - if(now) + if (now) self->bofs_count = self->next_bofs; /* Set the negociated link speed (may need the new xbofs value) */ @@ -1092,51 +998,62 @@ self->line_capacity = irlap_max_line_capacity(self->qos_tx.baud_rate.value, self->qos_tx.max_turn_time.value); + + + /* + * Initialize timeout values, some of the rules are listed on + * page 92 in IrLAP. + */ + ASSERT(self->qos_tx.max_turn_time.value != 0, return;); + ASSERT(self->qos_rx.max_turn_time.value != 0, return;); + /* The poll timeout applies only to the primary station. + * It defines the maximum time the primary stay in XMIT mode + * before timeout and turning the link around (sending a RR). + * Or, this is how much we can keep the pf bit in primary mode. + * Therefore, it must be lower or equal than our *OWN* max turn around. + * Jean II */ + self->poll_timeout = self->qos_tx.max_turn_time.value * HZ / 1000; + /* The Final timeout applies only to the primary station. + * It defines the maximum time the primary wait (mostly in RECV mode) + * for an answer from the secondary station before polling it again. + * Therefore, it must be greater or equal than our *PARTNER* + * max turn around time - Jean II */ + self->final_timeout = self->qos_rx.max_turn_time.value * HZ / 1000; + /* The Watchdog Bit timeout applies only to the secondary station. + * It defines the maximum time the secondary wait (mostly in RECV mode) + * for poll from the primary station before getting annoyed. + * Therefore, it must be greater or equal than our *PARTNER* + * max turn around time - Jean II */ + self->wd_timeout = self->final_timeout * 2; + + /* + * N1 and N2 are maximum retry count for *both* the final timer + * and the wd timer (with a factor 2) as defined above. + * After N1 retry of a timer, we give a warning to the user. + * After N2 retry, we consider the link dead and disconnect it. + * Jean II + */ + /* * Set N1 to 0 if Link Disconnect/Threshold Time = 3 and set it to * 3 seconds otherwise. See page 71 in IrLAP for more details. - * TODO: these values should be calculated from the final timer - * as well */ - ASSERT(self->qos_tx.max_turn_time.value != 0, return;); if (self->qos_tx.link_disc_time.value == 3) /* * If we set N1 to 0, it will trigger immediately, which is * not what we want. What we really want is to disable it, * Jean II */ - self->N1 = -1; /* Disable */ + self->N1 = -2; /* Disable - Need to be multiple of 2*/ else - self->N1 = 3000 / self->qos_tx.max_turn_time.value; + self->N1 = 3000 / self->qos_rx.max_turn_time.value; IRDA_DEBUG(4, "Setting N1 = %d\n", self->N1); - + /* Set N2 to match our own disconnect time */ self->N2 = self->qos_tx.link_disc_time.value * 1000 / - self->qos_tx.max_turn_time.value; + self->qos_rx.max_turn_time.value; IRDA_DEBUG(4, "Setting N2 = %d\n", self->N2); - - /* - * Initialize timeout values, some of the rules are listed on - * page 92 in IrLAP. - */ - self->poll_timeout = self->qos_tx.max_turn_time.value * HZ / 1000; - self->wd_timeout = self->poll_timeout * 2; - - /* - * Be careful to keep our promises to the peer device about how long - * time it can keep the pf bit. So here we must use the rx_qos value - */ - self->final_timeout = self->qos_rx.max_turn_time.value * HZ / 1000; - -#ifdef CONFIG_IRDA_COMPRESSION - if (self->qos_tx.compression.value) { - IRDA_DEBUG(1, __FUNCTION__ "(), Initializing compression\n"); - irda_set_compression(self, self->qos_tx.compression.value); - - irlap_compressor_init(self, 0); - } -#endif } /* @@ -1226,10 +1143,6 @@ self->qos_tx.min_turn_time.value); len += sprintf(buf+len, "%d\t", self->qos_tx.link_disc_time.value); -#ifdef CONFIG_IRDA_COMPRESSION - len += sprintf(buf+len, "%d", - self->qos_tx.compression.value); -#endif len += sprintf(buf+len, "\n"); len += sprintf(buf+len, " rx\t%d\t", @@ -1246,10 +1159,6 @@ self->qos_rx.min_turn_time.value); len += sprintf(buf+len, "%d\t", self->qos_rx.link_disc_time.value); -#ifdef CONFIG_IRDA_COMPRESSION - len += sprintf(buf+len, "%d", - self->qos_rx.compression.value); -#endif len += sprintf(buf+len, "\n"); self = (struct irlap_cb *) hashbin_get_next(irlap); diff -u --recursive --new-file v2.4.6/linux/net/irda/irlap_comp.c linux/net/irda/irlap_comp.c --- v2.4.6/linux/net/irda/irlap_comp.c Fri Mar 2 11:12:12 2001 +++ linux/net/irda/irlap_comp.c Wed Dec 31 16:00:00 1969 @@ -1,354 +0,0 @@ -/********************************************************************* - * - * Filename: irlap_comp.c - * Version: - * Description: - * Status: Experimental. - * Author: Dag Brattli <dagb@cs.uit.no> - * Created at: Fri Oct 9 09:18:07 1998 - * Modified at: Tue Oct 5 11:34:52 1999 - * Modified by: Dag Brattli <dagb@cs.uit.no> - * Modified at: Fri May 28 3:11 CST 1999 - * Modified by: Horst von Brand <vonbrand@sleipnir.valparaiso.cl> - * Sources: ppp.c, isdn_ppp.c - * - * Copyright (c) 1998-1999 Dag Brattli, All Rights Reserved. - * - * 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. - * - * Neither Dag Brattli nor University of Tromsø admit liability nor - * provide warranty for any of this software. This material is - * provided "AS-IS" and at no charge. - * - ********************************************************************/ - -#include <linux/string.h> - -#include <net/irda/irda.h> -#include <net/irda/irqueue.h> -#include <net/irda/irlap.h> -#include <net/irda/irlap_comp.h> -#include "../../drivers/net/zlib.h" - -hashbin_t *irlap_compressors = NULL; - -/* - * Function irda_register_compressor (cp) - * - * Register new compressor with the IrLAP - * - */ -int irda_register_compressor( struct compressor *cp) -{ - struct irda_compressor *new; - - IRDA_DEBUG( 4, __FUNCTION__ "()\n"); - - /* Check if this compressor has been registred before */ - if ( hashbin_find ( irlap_compressors, cp->compress_proto, NULL)) { - IRDA_DEBUG( 0, __FUNCTION__ "(), Compressor already registered\n"); - return 0; - } - - /* Make new IrDA compressor */ - new = (struct irda_compressor *) - kmalloc( sizeof( struct irda_compressor), GFP_KERNEL); - if (new == NULL) - return 1; - - memset( new, 0, sizeof( struct irda_compressor)); - new->cp = cp; - - /* Insert IrDA compressor into hashbin */ - hashbin_insert( irlap_compressors, (irda_queue_t *) new, cp->compress_proto, - NULL); - - return 0; -} - -/* - * Function irda_unregister_compressor (cp) - * - * Unregister compressor - * - */ -void irda_unregister_compressor ( struct compressor *cp) -{ - struct irda_compressor *node; - - IRDA_DEBUG( 4, __FUNCTION__ "()\n"); - - node = hashbin_remove( irlap_compressors, cp->compress_proto, NULL); - if ( !node) { - IRDA_DEBUG( 0, __FUNCTION__ "(), compressor not found!\n"); - return; - } - kfree( node); -} - -/* - * Function irda_set_compression (self, proto) - * - * The compression protocol to be used by this session - * - */ -int irda_set_compression( struct irlap_cb *self, int proto) -{ - struct compressor *cp; - struct irda_compressor *comp; - - __u8 options[CILEN_DEFLATE]; - - IRDA_DEBUG( 4, __FUNCTION__ "()\n"); - - ASSERT( self != NULL, return -ENODEV;); - ASSERT( self->magic == LAP_MAGIC, return -EBADR;); - - /* Initialize options */ - options[0] = CI_DEFLATE; - options[1] = CILEN_DEFLATE; - options[2] = DEFLATE_METHOD( DEFLATE_METHOD_VAL); - options[3] = DEFLATE_CHK_SEQUENCE; - - comp = hashbin_find( irlap_compressors, proto, NULL); - if ( !comp) { - IRDA_DEBUG( 0, __FUNCTION__ "(), Unable to find compressor\n"); - return -1; - } - - cp = comp->cp; - /* - * Compressor part - */ - if ( self->compressor.state != NULL) - (*self->compressor.cp->comp_free)( self->compressor.state); - self->compressor.state = NULL; - - self->compressor.cp = cp; - self->compressor.state = cp->comp_alloc( options, sizeof( options)); - if ( self->compressor.state == NULL) { - IRDA_DEBUG( 0, __FUNCTION__ "(), Failed!\n"); - return -ENOBUFS; - } - - /* - * Decompress part - */ - - if ( self->decompressor.state != NULL) - irda_decomp_free( self->decompressor.state); - self->decompressor.state = NULL; - - self->decompressor.cp = cp; - self->decompressor.state = cp->decomp_alloc( options, sizeof( options)); - if ( self->decompressor.state == NULL) { - IRDA_DEBUG( 0, __FUNCTION__ "(), Failed!\n"); - return -ENOBUFS; - } - return 0; -} - -/* - * Function irda_free_compression (self) - * - * - * - */ -void irda_free_compression( struct irlap_cb *self) -{ - IRDA_DEBUG( 4, __FUNCTION__ "()\n"); - - if ( self->compressor.state) { - irda_comp_free( self->compressor.state); - self->compressor.state = NULL; - } - - if ( self->decompressor.state) { - irda_decomp_free( self->decompressor.state); - self->decompressor.state = NULL; - } -} - -/* - * Function irlap_compress_init (self) - * - * - * - */ -void irlap_compressor_init( struct irlap_cb *self, int compress) -{ - int debug = TRUE; - __u8 options[CILEN_DEFLATE]; - - IRDA_DEBUG(4, __FUNCTION__ "()\n"); - - ASSERT( self != NULL, return;); - ASSERT( self->magic == LAP_MAGIC, return;); - - /* Initialize options */ - options[0] = CI_DEFLATE; - options[1] = CILEN_DEFLATE; - options[2] = DEFLATE_METHOD_VAL; - options[3] = DEFLATE_CHK_SEQUENCE; - - /* - * We're agreeing to send compressed packets. - */ - if ( self->compressor.state == NULL) { - IRDA_DEBUG( 0, __FUNCTION__ "(), state == NULL\n"); - return; - } - - if ((*self->compressor.cp->comp_init)( self->compressor.state, - options, sizeof( options), - 0, 0, debug)) - { - IRDA_DEBUG( 0, __FUNCTION__ "(), Compressor running!\n"); - /* ppp->flags |= SC_COMP_RUN; */ - } - - /* - * Initialize decompressor - */ - if ( self->decompressor.state == NULL) { - IRDA_DEBUG( 0, __FUNCTION__ "(), state == NULL\n"); - return; - } - - if (( self->decompressor.cp->decomp_init)( self->decompressor.state, - options, sizeof( options), - 0, 0, 0, debug)) - { - IRDA_DEBUG( 0, __FUNCTION__ "(), Decompressor running!\n"); - - /* ppp->flags |= SC_DECOMP_RUN; */ - /* ppp->flags &= ~(SC_DC_ERROR | SC_DC_FERROR); */ - } -} - -/* - * Function irlap_compress_frame (self, skb) - * - * - * - */ -struct sk_buff *irlap_compress_frame( struct irlap_cb *self, - struct sk_buff *skb) -{ - struct sk_buff *new_skb; - int count; - - ASSERT( skb != NULL, return NULL;); - - IRDA_DEBUG(4, __FUNCTION__ "() skb->len=%d, jiffies=%ld\n", (int) skb->len, - jiffies); - - ASSERT( self != NULL, return NULL;); - ASSERT( self->magic == LAP_MAGIC, return NULL;); - - /* Check if compressor got initialized */ - if ( self->compressor.state == NULL) { - /* Tell peer that this frame is not compressed */ - skb_push( skb, LAP_COMP_HEADER); - skb->data[0] = IRDA_NORMAL; - - return skb; - } - - /* FIXME: Find out what is the max overhead (not 10) */ - new_skb = dev_alloc_skb( skb->len+LAP_MAX_HEADER+10); - if(!new_skb) - return skb; - - skb_reserve( new_skb, LAP_MAX_HEADER); - skb_put( new_skb, skb->len+10); - - count = (self->compressor.cp->compress)( self->compressor.state, - skb->data, new_skb->data, - skb->len, new_skb->len); - if( count <= 0) { - IRDA_DEBUG(4, __FUNCTION__ "(), Unable to compress frame!\n"); - dev_kfree_skb( new_skb); - - /* Tell peer that this frame is not compressed */ - skb_push( skb, 1); - skb->data[0] = IRDA_NORMAL; - - return skb; - } - skb_trim( new_skb, count); - - /* Tell peer that this frame is compressed */ - skb_push( new_skb, 1); - new_skb->data[0] = IRDA_COMPRESSED; - - dev_kfree_skb( skb); - - IRDA_DEBUG(4, __FUNCTION__ "() new_skb->len=%d\n, jiffies=%ld", - (int) new_skb->len, jiffies); - - return new_skb; -} - -/* - * Function irlap_decompress_frame (self, skb) - * - * - * - */ -struct sk_buff *irlap_decompress_frame( struct irlap_cb *self, - struct sk_buff *skb) -{ - struct sk_buff *new_skb; - int count; - - IRDA_DEBUG( 4, __FUNCTION__ "() skb->len=%d\n", (int) skb->len); - - ASSERT( self != NULL, return NULL;); - ASSERT( self->magic == LAP_MAGIC, return NULL;); - - ASSERT( self->compressor.state != NULL, return NULL;); - - /* Check if frame is compressed */ - if ( skb->data[0] == IRDA_NORMAL) { - - /* Remove compression header */ - skb_pull( skb, LAP_COMP_HEADER); - - /* - * The frame is not compressed. Pass it to the - * decompression code so it can update its - * dictionary if necessary. - */ - irda_incomp( self->decompressor.state, skb->data, skb->len); - - return skb; - } - - /* Remove compression header */ - skb_pull( skb, LAP_COMP_HEADER); - - new_skb = dev_alloc_skb( 2048); /* FIXME: find the right size */ - if(!new_skb) - return skb; - skb_put( new_skb, 2048); - - count = irda_decompress( self->decompressor.state, skb->data, - skb->len, new_skb->data, new_skb->len); - if ( count <= 0) { - IRDA_DEBUG( 4, __FUNCTION__ "(), Unable to decompress frame!\n"); - - dev_kfree_skb( new_skb); - return skb; - } - - skb_trim( new_skb, count); - - IRDA_DEBUG( 4, __FUNCTION__ "() new_skb->len=%d\n", (int) new_skb->len); - - return new_skb; -} - diff -u --recursive --new-file v2.4.6/linux/net/irda/irlap_event.c linux/net/irda/irlap_event.c --- v2.4.6/linux/net/irda/irlap_event.c Fri Mar 2 11:12:12 2001 +++ linux/net/irda/irlap_event.c Wed Jul 4 11:50:38 2001 @@ -1870,11 +1870,24 @@ /* Update Nr received */ irlap_update_nr_received(self, info->nr); irlap_wait_min_turn_around(self, &self->qos_tx); + irlap_start_wd_timer(self, self->wd_timeout); - irlap_send_rr_frame(self, RSP_FRAME); + /* Note : if the link is idle (this case), + * we never go in XMIT_S, so we never get a + * chance to process any DISCONNECT_REQUEST. + * Do it now ! - Jean II */ + if (self->disconnect_pending) { + /* Disconnect */ + irlap_send_rd_frame(self); + irlap_flush_all_queues(self); + + irlap_next_state(self, LAP_SCLOSE); + } else { + /* Just send back pf bit */ + irlap_send_rr_frame(self, RSP_FRAME); - irlap_start_wd_timer(self, self->wd_timeout); - irlap_next_state(self, LAP_NRM_S); + irlap_next_state(self, LAP_NRM_S); + } } } else if (nr_status == NR_UNEXPECTED) { self->remote_busy = FALSE; @@ -1927,24 +1940,23 @@ * Wait until retry_count * n matches negotiated threshold/ * disconnect time (note 2 in IrLAP p. 82) * - * Note : self->wd_timeout = (self->poll_timeout * 2), - * and self->final_timeout == self->poll_timeout, - * which explain why we use (self->retry_count * 2) here !!! + * Note : self->wd_timeout = (self->final_timeout * 2), + * which explain why we use (self->N2 / 2) here !!! * Jean II */ IRDA_DEBUG(1, __FUNCTION__ "(), retry_count = %d\n", self->retry_count); - if (((self->retry_count * 2) < self->N2) && - ((self->retry_count * 2) != self->N1)) { + if ((self->retry_count < (self->N2 / 2)) && + (self->retry_count != (self->N1 / 2))) { irlap_start_wd_timer(self, self->wd_timeout); self->retry_count++; - } else if ((self->retry_count * 2) == self->N1) { + } else if (self->retry_count == (self->N1 / 2)) { irlap_status_indication(self, STATUS_NO_ACTIVITY); irlap_start_wd_timer(self, self->wd_timeout); self->retry_count++; - } else if ((self->retry_count * 2) >= self->N2) { + } else if (self->retry_count >= (self->N2 / 2)) { irlap_apply_default_connection_parameters(self); /* Always switch state before calling upper layers */ diff -u --recursive --new-file v2.4.6/linux/net/irda/irlap_frame.c linux/net/irda/irlap_frame.c --- v2.4.6/linux/net/irda/irlap_frame.c Sat May 19 17:47:55 2001 +++ linux/net/irda/irlap_frame.c Wed Jul 4 11:50:38 2001 @@ -742,12 +742,6 @@ return; } - /* - * make sure the skb->sk accounting of memory usage is sane - */ - if (skb->sk != NULL) - skb_set_owner_w(tx_skb, skb->sk); - /* * Insert frame in store, in case of retransmissions */ @@ -788,12 +782,6 @@ return; } - /* - * make sure the skb->sk accounting of memory usage is sane - */ - if (skb->sk != NULL) - skb_set_owner_w(tx_skb, skb->sk); - /* * Insert frame in store, in case of retransmissions */ @@ -863,9 +851,6 @@ return; } - if (skb->sk != NULL) - skb_set_owner_w(tx_skb, skb->sk); - /* Insert frame in store */ skb_queue_tail(&self->wx_list, skb_get(skb)); @@ -917,9 +902,6 @@ return; } - if (skb->sk != NULL) - skb_set_owner_w(tx_skb, skb->sk); - /* Insert frame in store */ skb_queue_tail(&self->wx_list, skb_get(skb)); @@ -973,12 +955,6 @@ tx_skb->next = tx_skb->prev = NULL; tx_skb->list = NULL; - /* - * make sure the skb->sk accounting of memory usage is sane - */ - if (skb->sk != NULL) - skb_set_owner_w(tx_skb, skb->sk); - /* Clear old Nr field + poll bit */ tx_skb->data[1] &= 0x0f; @@ -1058,12 +1034,6 @@ /* Unlink tx_skb from list */ tx_skb->next = tx_skb->prev = NULL; tx_skb->list = NULL; - - /* - * make sure the skb->sk accounting of memory usage is sane - */ - if (skb->sk != NULL) - skb_set_owner_w(tx_skb, skb->sk); /* Clear old Nr field + poll bit */ tx_skb->data[1] &= 0x0f; diff -u --recursive --new-file v2.4.6/linux/net/irda/irlmp.c linux/net/irda/irlmp.c --- v2.4.6/linux/net/irda/irlmp.c Sat May 19 17:47:55 2001 +++ linux/net/irda/irlmp.c Wed Jul 4 11:50:38 2001 @@ -376,7 +376,7 @@ * discovery log and check if any of the links has discovered a * device with the given daddr */ - if (!saddr) { + if ((!saddr) || (saddr == DEV_ADDR_ANY)) { if (daddr != DEV_ADDR_ANY) discovery = hashbin_find(irlmp->cachelog, daddr, NULL); else { diff -u --recursive --new-file v2.4.6/linux/net/irda/irlmp_event.c linux/net/irda/irlmp_event.c --- v2.4.6/linux/net/irda/irlmp_event.c Sat May 19 17:47:55 2001 +++ linux/net/irda/irlmp_event.c Wed Jul 4 11:50:38 2001 @@ -379,13 +379,23 @@ irlmp_start_idle_timer(self, LM_IDLE_TIMEOUT); else { /* No more connections, so close IrLAP */ - irlmp_next_lap_state(self, LAP_STANDBY); + + /* We don't want to change state just yet, because + * we want to reflect accurately the real state of + * the LAP, not the the state we whish it was in, + * so that we don't loose LM_LAP_CONNECT_REQUEST. + * In some cases, IrLAP won't close the LAP + * immediately. For example, it might still be + * retrying packets or waiting for the pf bit. + * As the LAP always send a DISCONNECT_INDICATION + * in PCLOSE or SCLOSE, just change state on that. + * Jean II */ irlap_disconnect_request(self->irlap); } break; case LM_LAP_IDLE_TIMEOUT: if (HASHBIN_GET_SIZE(self->lsaps) == 0) { - irlmp_next_lap_state(self, LAP_STANDBY); + /* Same reasoning as above - keep state */ irlap_disconnect_request(self->irlap); } break; @@ -472,8 +482,6 @@ irlmp_start_watchdog_timer(self, 5*HZ); break; case LM_CONNECT_INDICATION: - irlmp_next_lsap_state(self, LSAP_CONNECT_PEND); - if (self->conn_skb) { WARNING(__FUNCTION__ "(), busy with another request!\n"); @@ -481,7 +489,20 @@ } self->conn_skb = skb; + irlmp_next_lsap_state(self, LSAP_CONNECT_PEND); + irlmp_do_lap_event(self->lap, LM_LAP_CONNECT_REQUEST, NULL); + + /* Start watchdog timer + * This is not mentionned in the spec, but there is a rare + * race condition that can get the socket stuck. + * If we receive this event while our LAP is closing down, + * the LM_LAP_CONNECT_REQUEST get lost and we get stuck in + * CONNECT_PEND state forever. + * Anyway, it make sense to make sure that we always have + * a backup plan. 1 second is plenty (should be immediate). + * Jean II */ + irlmp_start_watchdog_timer(self, 1*HZ); break; default: IRDA_DEBUG(2, __FUNCTION__ "(), Unknown event %s\n", @@ -533,6 +554,16 @@ irlmp_next_lsap_state(self, LSAP_DATA_TRANSFER_READY); break; + case LM_WATCHDOG_TIMEOUT: + /* May happen, who knows... + * Jean II */ + IRDA_DEBUG(0, __FUNCTION__ "() WATCHDOG_TIMEOUT!\n"); + + /* Here, we should probably disconnect proper */ + self->dlsap_sel = LSAP_ANY; + self->conn_skb = NULL; + irlmp_next_lsap_state(self, LSAP_DISCONNECTED); + break; default: IRDA_DEBUG(0, __FUNCTION__ "(), Unknown event %s\n", irlmp_event[event]); @@ -563,6 +594,15 @@ case LM_CONNECT_REQUEST: /* Keep state */ break; + case LM_CONNECT_INDICATION: + /* Will happen in some rare cases when the socket get stuck, + * the other side retries the connect request. + * We just unstuck the socket - Jean II */ + IRDA_DEBUG(0, __FUNCTION__ "(), LM_CONNECT_INDICATION, " + "LSAP stuck in CONNECT_PEND state...\n"); + /* Keep state */ + irlmp_do_lap_event(self->lap, LM_LAP_CONNECT_REQUEST, NULL); + break; case LM_CONNECT_RESPONSE: IRDA_DEBUG(0, __FUNCTION__ "(), LM_CONNECT_RESPONSE, " "no indication issued yet\n"); @@ -581,6 +621,17 @@ self->conn_skb = NULL; irlmp_connect_indication(self, skb); + break; + case LM_WATCHDOG_TIMEOUT: + /* Will happen in some rare cases because of a race condition. + * Just make sure we don't stay there forever... + * Jean II */ + IRDA_DEBUG(0, __FUNCTION__ "() WATCHDOG_TIMEOUT!\n"); + + /* Go back to disconnected mode, keep the socket waiting */ + self->dlsap_sel = LSAP_ANY; + self->conn_skb = NULL; + irlmp_next_lsap_state(self, LSAP_DISCONNECTED); break; default: IRDA_DEBUG(0, __FUNCTION__ "Unknown event %s\n", diff -u --recursive --new-file v2.4.6/linux/net/irda/irproc.c linux/net/irda/irproc.c --- v2.4.6/linux/net/irda/irproc.c Sat Nov 27 15:27:49 1999 +++ linux/net/irda/irproc.c Wed Jul 4 11:50:38 2001 @@ -67,6 +67,8 @@ int i; proc_irda = proc_mkdir("net/irda", NULL); + if (proc_irda == NULL) + return; proc_irda->owner = THIS_MODULE; for (i=0;i<IRDA_ENTRIES_NUM;i++) @@ -83,10 +85,13 @@ { int i; - for (i=0;i<IRDA_ENTRIES_NUM;i++) - remove_proc_entry(dir[i].name, proc_irda); + if (proc_irda) { + for (i=0;i<IRDA_ENTRIES_NUM;i++) + remove_proc_entry(dir[i].name, proc_irda); - remove_proc_entry("net/irda", NULL); + remove_proc_entry("net/irda", NULL); + proc_irda = NULL; + } } diff -u --recursive --new-file v2.4.6/linux/net/irda/irqueue.c linux/net/irda/irqueue.c --- v2.4.6/linux/net/irda/irqueue.c Thu Jan 4 13:00:55 2001 +++ linux/net/irda/irqueue.c Wed Jul 4 11:50:38 2001 @@ -739,7 +739,7 @@ /* * Queue was empty. */ - } if ( (*queue)->q_next == *queue ) { + } else if ( (*queue)->q_next == *queue ) { /* * Queue only contained a single element. It will now be * empty. diff -u --recursive --new-file v2.4.6/linux/net/irda/irsyms.c linux/net/irda/irsyms.c --- v2.4.6/linux/net/irda/irsyms.c Sun Nov 12 20:43:11 2000 +++ linux/net/irda/irsyms.c Wed Jul 4 11:50:38 2001 @@ -35,9 +35,6 @@ #include <net/irda/irda.h> #include <net/irda/irmod.h> #include <net/irda/irlap.h> -#ifdef CONFIG_IRDA_COMPRESSION -#include <net/irda/irlap_comp.h> -#endif /* CONFIG_IRDA_COMPRESSION */ #include <net/irda/irlmp.h> #include <net/irda/iriap.h> #include <net/irda/irias_object.h> @@ -66,12 +63,6 @@ extern int irlpt_client_init(void); extern int irlpt_server_init(void); -#ifdef CONFIG_IRDA_COMPRESSION -#ifdef CONFIG_IRDA_DEFLATE -extern irda_deflate_init(); -#endif /* CONFIG_IRDA_DEFLATE */ -#endif /* CONFIG_IRDA_COMPRESSION */ - /* IrTTP */ EXPORT_SYMBOL(irttp_open_tsap); EXPORT_SYMBOL(irttp_close_tsap); @@ -150,10 +141,6 @@ /* IrLAP */ EXPORT_SYMBOL(irlap_open); EXPORT_SYMBOL(irlap_close); -#ifdef CONFIG_IRDA_COMPRESSION -EXPORT_SYMBOL(irda_unregister_compressor); -EXPORT_SYMBOL(irda_register_compressor); -#endif /* CONFIG_IRDA_COMPRESSION */ EXPORT_SYMBOL(irda_init_max_qos_capabilies); EXPORT_SYMBOL(irda_qos_bits_to_value); EXPORT_SYMBOL(irda_device_setup); @@ -208,13 +195,6 @@ ircomm_init(); ircomm_tty_init(); #endif - -#ifdef CONFIG_IRDA_COMPRESSION -#ifdef CONFIG_IRDA_DEFLATE - irda_deflate_init(); -#endif /* CONFIG_IRDA_DEFLATE */ -#endif /* CONFIG_IRDA_COMPRESSION */ - return 0; } diff -u --recursive --new-file v2.4.6/linux/net/irda/irsysctl.c linux/net/irda/irsysctl.c --- v2.4.6/linux/net/irda/irsysctl.c Sat Nov 11 18:11:23 2000 +++ linux/net/irda/irsysctl.c Wed Jul 4 11:50:38 2001 @@ -32,7 +32,7 @@ #include <net/irda/irias_object.h> #define NET_IRDA 412 /* Random number */ -enum { DISCOVERY=1, DEVNAME, COMPRESSION, DEBUG, SLOTS, DISCOVERY_TIMEOUT, +enum { DISCOVERY=1, DEVNAME, DEBUG, SLOTS, DISCOVERY_TIMEOUT, SLOT_TIMEOUT, MAX_BAUD_RATE, MAX_INACTIVE_TIME }; extern int sysctl_discovery; @@ -71,8 +71,6 @@ sizeof(int), 0644, NULL, &proc_dointvec }, { DEVNAME, "devname", sysctl_devname, 65, 0644, NULL, &do_devname, &sysctl_string}, - { COMPRESSION, "compression", &sysctl_compression, - sizeof(int), 0644, NULL, &proc_dointvec }, #ifdef CONFIG_IRDA_DEBUG { DEBUG, "debug", &irda_debug, sizeof(int), 0644, NULL, &proc_dointvec }, diff -u --recursive --new-file v2.4.6/linux/net/irda/irttp.c linux/net/irda/irttp.c --- v2.4.6/linux/net/irda/irttp.c Tue May 1 16:05:00 2001 +++ linux/net/irda/irttp.c Wed Jul 4 11:50:38 2001 @@ -1598,7 +1598,7 @@ self = (struct tsap_cb *) hashbin_get_first(irttp->tsaps); while (self != NULL) { if (!self || self->magic != TTP_TSAP_MAGIC) - return len; + break; len += sprintf(buf+len, "TSAP %d, ", i++); len += sprintf(buf+len, "stsap_sel: %02x, ", diff -u --recursive --new-file v2.4.6/linux/net/irda/qos.c linux/net/irda/qos.c --- v2.4.6/linux/net/irda/qos.c Mon Apr 30 16:26:09 2001 +++ linux/net/irda/qos.c Wed Jul 4 11:50:38 2001 @@ -36,12 +36,6 @@ #include <net/irda/parameters.h> #include <net/irda/qos.h> #include <net/irda/irlap.h> -#ifdef CONFIG_IRDA_COMPRESSION -#include <net/irda/irlap_comp.h> -#include "../../drivers/net/zlib.h" - -#define CI_BZIP2 27 /* Random pick */ -#endif /* * Maximum values of the baud rate we negociate with the other end. @@ -79,10 +73,6 @@ __u32 max_turn_times[] = { 500, 250, 100, 50 }; /* ms */ __u32 link_disc_times[] = { 3, 8, 12, 16, 20, 25, 30, 40 }; /* secs */ -#ifdef CONFIG_IRDA_COMPRESSION -__u32 compressions[] = { CI_BZIP2, CI_DEFLATE, CI_DEFLATE_DRAFT }; -#endif - __u32 max_line_capacities[10][4] = { /* 500 ms 250 ms 100 ms 50 ms (max turn time) */ { 100, 0, 0, 0 }, /* 2400 bps */ @@ -238,10 +228,6 @@ qos->link_disc_time.bits &= new->link_disc_time.bits; qos->additional_bofs.bits &= new->additional_bofs.bits; -#ifdef CONFIG_IRDA_COMPRESSION - qos->compression.bits &= new->compression.bits; -#endif - irda_qos_bits_to_value(qos); } @@ -280,10 +266,6 @@ qos->data_size.bits = 0x3f; qos->link_disc_time.bits &= 0xff; qos->additional_bofs.bits = 0xff; - -#ifdef CONFIG_IRDA_COMPRESSION - qos->compression.bits = 0x03; -#endif } /* @@ -359,20 +341,10 @@ int irlap_qos_negotiate(struct irlap_cb *self, struct sk_buff *skb) { int ret; -#ifdef CONFIG_IRDA_COMPRESSION - int comp_seen = FALSE; -#endif + ret = irda_param_extract_all(self, skb->data, skb->len, &irlap_param_info); -#ifdef CONFIG_IRDA_COMPRESSION - if (!comp_seen) { - IRDA_DEBUG( 4, __FUNCTION__ "(), Compression not seen!\n"); - self->qos_tx.compression.bits = 0x00; - self->qos_rx.compression.bits = 0x00; - } -#endif - /* Convert the negotiated bits to values */ irda_qos_bits_to_value(&self->qos_tx); irda_qos_bits_to_value(&self->qos_rx); @@ -393,10 +365,6 @@ self->qos_tx.min_turn_time.value); IRDA_DEBUG(2, "Setting LINK_DISC to %d secs.\n", self->qos_tx.link_disc_time.value); -#ifdef CONFIG_IRDA_COMPRESSION - IRDA_DEBUG(2, "Setting COMPRESSION to %d\n", - self->qos_tx.compression.value); -#endif return ret; } @@ -710,12 +678,4 @@ index = msb_index(qos->additional_bofs.bits); qos->additional_bofs.value = add_bofs[index]; - -#ifdef CONFIG_IRDA_COMPRESSION - index = msb_index(qos->compression.bits); - if (index >= 0) - qos->compression.value = compressions[index]; - else - qos->compression.value = 0; -#endif } diff -u --recursive --new-file v2.4.6/linux/net/netsyms.c linux/net/netsyms.c --- v2.4.6/linux/net/netsyms.c Tue Jul 3 17:08:22 2001 +++ linux/net/netsyms.c Wed Jul 11 15:44:45 2001 @@ -145,6 +145,7 @@ EXPORT_SYMBOL(skb_copy_and_csum_datagram_iovec); EXPORT_SYMBOL(skb_copy_bits); EXPORT_SYMBOL(skb_copy_and_csum_bits); +EXPORT_SYMBOL(skb_copy_and_csum_dev); EXPORT_SYMBOL(skb_copy_expand); EXPORT_SYMBOL(___pskb_trim); EXPORT_SYMBOL(__pskb_pull_tail); @@ -251,6 +252,7 @@ EXPORT_SYMBOL(ip_mc_inc_group); EXPORT_SYMBOL(ip_mc_dec_group); EXPORT_SYMBOL(ip_finish_output); +EXPORT_SYMBOL(inet_stream_ops); EXPORT_SYMBOL(inet_dgram_ops); EXPORT_SYMBOL(ip_cmsg_recv); EXPORT_SYMBOL(inet_addr_type); @@ -281,7 +283,6 @@ #endif #if defined (CONFIG_IPV6_MODULE) || defined (CONFIG_KHTTPD) || defined (CONFIG_KHTTPD_MODULE) /* inet functions common to v4 and v6 */ -EXPORT_SYMBOL(inet_stream_ops); EXPORT_SYMBOL(inet_release); EXPORT_SYMBOL(inet_stream_connect); EXPORT_SYMBOL(inet_dgram_connect); diff -u --recursive --new-file v2.4.6/linux/net/socket.c linux/net/socket.c --- v2.4.6/linux/net/socket.c Tue Jul 3 17:08:22 2001 +++ linux/net/socket.c Thu Jul 19 18:11:13 2001 @@ -841,8 +841,10 @@ /* * Check protocol is in range */ - if(family<0 || family>=NPROTO) + if (family < 0 || family >= NPROTO) return -EAFNOSUPPORT; + if (type < 0 || type >= SOCK_MAX) + return -EINVAL; /* Compatibility. diff -u --recursive --new-file v2.4.6/linux/net/sunrpc/svcsock.c linux/net/sunrpc/svcsock.c --- v2.4.6/linux/net/sunrpc/svcsock.c Fri Apr 27 14:15:01 2001 +++ linux/net/sunrpc/svcsock.c Wed Jul 4 11:50:38 2001 @@ -383,7 +383,7 @@ /* Sorry. */ if (skb_is_nonlinear(skb)) { - if (skb_linearize(skb, GFP_ATOMIC) != 0) { + if (skb_linearize(skb, GFP_KERNEL) != 0) { kfree_skb(skb); svc_sock_received(svsk, 0); return 0; diff -u --recursive --new-file v2.4.6/linux/net/unix/af_unix.c linux/net/unix/af_unix.c --- v2.4.6/linux/net/unix/af_unix.c Tue Jul 3 17:08:22 2001 +++ linux/net/unix/af_unix.c Sat Jul 14 10:13:09 2001 @@ -8,7 +8,7 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * - * Version: $Id: af_unix.c,v 1.116 2001/03/03 01:20:11 davem Exp $ + * Version: $Id: af_unix.c,v 1.117 2001/07/01 06:59:10 davem Exp $ * * Fixes: * Linus Torvalds : Assorted bug cures. @@ -674,6 +674,7 @@ atomic_set(&addr->refcnt, 1); if (sunaddr->sun_path[0]) { + unsigned int mode; err = 0; /* * Get the parent directory, calculate the hash for last @@ -713,8 +714,8 @@ /* * All right, let's create it. */ - err = vfs_mknod(nd.dentry->d_inode, dentry, - S_IFSOCK|sock->inode->i_mode, 0); + mode = S_IFSOCK | (sock->inode->i_mode & ~current->fs->umask); + err = vfs_mknod(nd.dentry->d_inode, dentry, mode, 0); if (err) goto out_mknod_dput; up(&nd.dentry->d_inode->i_sem); diff -u --recursive --new-file v2.4.6/linux/scripts/cramfs/GNUmakefile linux/scripts/cramfs/GNUmakefile --- v2.4.6/linux/scripts/cramfs/GNUmakefile Tue Jan 11 10:24:58 2000 +++ linux/scripts/cramfs/GNUmakefile Thu Jul 19 16:14:53 2001 @@ -1,7 +1,8 @@ -CFLAGS = -Wall -O2 -CPPFLAGS = -I../../fs/cramfs +CC = gcc +CFLAGS = -W -Wall -O2 -g +CPPFLAGS = -I../../include LDLIBS = -lz -PROGS = mkcramfs +PROGS = mkcramfs cramfsck all: $(PROGS) diff -u --recursive --new-file v2.4.6/linux/scripts/cramfs/cramfsck.c linux/scripts/cramfs/cramfsck.c --- v2.4.6/linux/scripts/cramfs/cramfsck.c Wed Dec 31 16:00:00 1969 +++ linux/scripts/cramfs/cramfsck.c Thu Jul 19 16:14:53 2001 @@ -0,0 +1,588 @@ +/* + * cramfsck - check a cramfs file system + * + * Copyright (C) 2000-2001 Transmeta 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 + * + * 1999/12/03: Linus Torvalds (cramfs tester and unarchive program) + * 2000/06/03: Daniel Quinlan (CRC and length checking program) + * 2000/06/04: Daniel Quinlan (merged programs, added options, support + * for special files, preserve permissions and + * ownership, cramfs superblock v2, bogus mode + * test, pathname length test, etc.) + * 2000/06/06: Daniel Quinlan (support for holes, pretty-printing, + * symlink size test) + * 2000/07/11: Daniel Quinlan (file length tests, start at offset 0 or 512, + * fsck-compatible exit codes) + * 2000/07/15: Daniel Quinlan (initial support for block devices) + */ + +/* compile-time options */ +#define INCLUDE_FS_TESTS /* include cramfs checking and extraction */ + +#include <sys/types.h> +#include <stdio.h> +#include <sys/stat.h> +#include <unistd.h> +#include <sys/mman.h> +#include <sys/fcntl.h> +#include <dirent.h> +#include <stdlib.h> +#include <errno.h> +#include <string.h> +#include <assert.h> +#include <getopt.h> +#include <sys/sysmacros.h> +#include <utime.h> +#include <sys/ioctl.h> +#define _LINUX_STRING_H_ +#include <linux/fs.h> +#include <linux/cramfs_fs.h> +#include <zlib.h> + +static const char *progname = "cramfsck"; + +static int fd; /* ROM image file descriptor */ +static char *filename; /* ROM image filename */ +struct cramfs_super *super; /* just find the cramfs superblock once */ +static int opt_verbose = 0; /* 1 = verbose (-v), 2+ = very verbose (-vv) */ +#ifdef INCLUDE_FS_TESTS +static int opt_extract = 0; /* extract cramfs (-x) */ +char *extract_dir = NULL; /* extraction directory (-x) */ + +unsigned long start_inode = 1 << 28; /* start of first non-root inode */ +unsigned long end_inode = 0; /* end of the directory structure */ +unsigned long start_data = 1 << 28; /* start of the data (256 MB = max) */ +unsigned long end_data = 0; /* end of the data */ +/* true? cramfs_super < start_inode < end_inode <= start_data <= end_data */ +static uid_t euid; /* effective UID */ + +#define PAD_SIZE 512 +#define PAGE_CACHE_SIZE (4096) + +/* Guarantee access to at least 8kB at a time */ +#define ROMBUFFER_BITS 13 +#define ROMBUFFERSIZE (1 << ROMBUFFER_BITS) +#define ROMBUFFERMASK (ROMBUFFERSIZE-1) +static char read_buffer[ROMBUFFERSIZE * 2]; +static unsigned long read_buffer_block = ~0UL; + +/* Uncompressing data structures... */ +static char outbuffer[PAGE_CACHE_SIZE*2]; +z_stream stream; + +#endif /* INCLUDE_FS_TESTS */ + +/* Input status of 0 to print help and exit without an error. */ +static void usage(int status) +{ + FILE *stream = status ? stderr : stdout; + + fprintf(stream, "usage: %s [-hv] [-x dir] file\n" + " -h print this help\n" + " -x dir extract into dir\n" + " -v be more verbose\n" + " file file to test\n", progname); + + exit(status); +} + +#ifdef INCLUDE_FS_TESTS +void print_node(char type, struct cramfs_inode *i, char *name) +{ + char info[10]; + + if (S_ISCHR(i->mode) || (S_ISBLK(i->mode))) { + /* major/minor numbers can be as high as 2^12 or 4096 */ + snprintf(info, 10, "%4d,%4d", major(i->size), minor(i->size)); + } + else { + /* size be as high as 2^24 or 16777216 */ + snprintf(info, 10, "%9d", i->size); + } + + printf("%c %04o %s %5d:%-3d %s\n", + type, i->mode & ~S_IFMT, info, i->uid, i->gid, name); +} + +/* + * Create a fake "blocked" access + */ +static void *romfs_read(unsigned long offset) +{ + unsigned int block = offset >> ROMBUFFER_BITS; + if (block != read_buffer_block) { + read_buffer_block = block; + lseek(fd, block << ROMBUFFER_BITS, SEEK_SET); + read(fd, read_buffer, ROMBUFFERSIZE * 2); + } + return read_buffer + (offset & ROMBUFFERMASK); +} + +static struct cramfs_inode *cramfs_iget(struct cramfs_inode * i) +{ + struct cramfs_inode *inode = malloc(sizeof(struct cramfs_inode)); + *inode = *i; + return inode; +} + +static struct cramfs_inode *iget(unsigned int ino) +{ + return cramfs_iget(romfs_read(ino)); +} + +void iput(struct cramfs_inode *inode) +{ + free(inode); +} + +/* + * Return the offset of the root directory, + * or 0 if none. + */ +static struct cramfs_inode *read_super(void) +{ + unsigned long offset; + + offset = super->root.offset << 2; + if (super->magic != CRAMFS_MAGIC) + return NULL; + if (memcmp(super->signature, CRAMFS_SIGNATURE, sizeof(super->signature)) != 0) + return NULL; + if (offset < sizeof(super)) + return NULL; + return cramfs_iget(&super->root); +} + +static int uncompress_block(void *src, int len) +{ + int err; + + stream.next_in = src; + stream.avail_in = len; + + stream.next_out = (unsigned char *) outbuffer; + stream.avail_out = PAGE_CACHE_SIZE*2; + + inflateReset(&stream); + + err = inflate(&stream, Z_FINISH); + if (err != Z_STREAM_END) { + fprintf(stderr, "%s: error %d while decompressing! %p(%d)\n", + filename, err, src, len); + exit(4); + } + return stream.total_out; +} + +static void change_file_status(char *path, struct cramfs_inode *i) +{ + struct utimbuf epoch = { 0, 0 }; + + if (euid == 0) { + if (lchown(path, i->uid, i->gid) < 0) { + perror(path); + exit(8); + } + if (S_ISLNK(i->mode)) + return; + if ((S_ISUID | S_ISGID) & i->mode) { + if (chmod(path, i->mode) < 0) { + perror(path); + exit(8); + } + } + } + if (S_ISLNK(i->mode)) + return; + if (utime(path, &epoch) < 0) { + perror(path); + exit(8); + } +} + +static void do_symlink(char *path, struct cramfs_inode *i) +{ + unsigned long offset = i->offset << 2; + unsigned long curr = offset + 4; + unsigned long next = *(u32 *) romfs_read(offset); + unsigned long size; + + if (next > end_data) { + end_data = next; + } + + size = uncompress_block(romfs_read(curr), next - curr); + if (size != i->size) { + fprintf(stderr, "%s: size error in symlink `%s'\n", + filename, path); + exit(4); + } + outbuffer[size] = 0; + if (opt_verbose) { + char *str; + + str = malloc(strlen(outbuffer) + strlen(path) + 5); + strcpy(str, path); + strncat(str, " -> ", 4); + strncat(str, outbuffer, size); + + print_node('l', i, str); + if (opt_verbose > 1) { + printf(" uncompressing block at %ld to %ld (%ld)\n", curr, next, next - curr); + } + } + if (opt_extract) { + symlink(outbuffer, path); + change_file_status(path, i); + } +} + +static void do_special_inode(char *path, struct cramfs_inode *i) +{ + dev_t devtype = 0; + char type; + + if (S_ISCHR(i->mode)) { + devtype = i->size; + type = 'c'; + } + else if (S_ISBLK(i->mode)) { + devtype = i->size; + type = 'b'; + } + else if (S_ISFIFO(i->mode)) + type = 'p'; + else if (S_ISSOCK(i->mode)) + type = 's'; + else { + fprintf(stderr, "%s: bogus mode on `%s' (%o)\n", filename, path, i->mode); + exit(4); + } + + if (opt_verbose) { + print_node(type, i, path); + } + + if (opt_extract) { + if (mknod(path, i->mode, devtype) < 0) { + perror(path); + exit(8); + } + change_file_status(path, i); + } +} + +static void do_uncompress(int fd, unsigned long offset, unsigned long size) +{ + unsigned long curr = offset + 4 * ((size + PAGE_CACHE_SIZE - 1) / PAGE_CACHE_SIZE); + + do { + unsigned long out = PAGE_CACHE_SIZE; + unsigned long next = *(u32 *) romfs_read(offset); + + if (next > end_data) { + end_data = next; + } + + offset += 4; + if (curr == next) { + if (opt_verbose > 1) { + printf(" hole at %ld (%d)\n", curr, PAGE_CACHE_SIZE); + } + if (size < PAGE_CACHE_SIZE) + out = size; + memset(outbuffer, 0x00, out); + } + else { + if (opt_verbose > 1) { + printf(" uncompressing block at %ld to %ld (%ld)\n", curr, next, next - curr); + } + out = uncompress_block(romfs_read(curr), next - curr); + } + if (size >= PAGE_CACHE_SIZE) { + if (out != PAGE_CACHE_SIZE) { + fprintf(stderr, "%s: Non-block (%ld) bytes\n", filename, out); + exit(4); + } + } else { + if (out != size) { + fprintf(stderr, "%s: Non-size (%ld vs %ld) bytes\n", filename, out, size); + exit(4); + } + } + size -= out; + if (opt_extract) { + write(fd, outbuffer, out); + } + curr = next; + } while (size); +} + +static void expand_fs(int pathlen, char *path, struct cramfs_inode *inode) +{ + if (S_ISDIR(inode->mode)) { + int count = inode->size; + unsigned long offset = inode->offset << 2; + char *newpath = malloc(pathlen + 256); + + if (count > 0 && offset < start_inode) { + start_inode = offset; + } + /* XXX - need to check end_inode for empty case? */ + memcpy(newpath, path, pathlen); + newpath[pathlen] = '/'; + pathlen++; + if (opt_verbose) { + print_node('d', inode, path); + } + if (opt_extract) { + mkdir(path, inode->mode); + change_file_status(path, inode); + } + while (count > 0) { + struct cramfs_inode *child = iget(offset); + int size; + int newlen = child->namelen << 2; + + size = sizeof(struct cramfs_inode) + newlen; + count -= size; + + offset += sizeof(struct cramfs_inode); + + memcpy(newpath + pathlen, romfs_read(offset), newlen); + newpath[pathlen + newlen] = 0; + if ((pathlen + newlen) - strlen(newpath) > 3) { + fprintf(stderr, "%s: invalid cramfs--bad path length\n", filename); + exit(4); + } + expand_fs(strlen(newpath), newpath, child); + + offset += newlen; + + if (offset > end_inode) { + end_inode = offset; + } + } + return; + } + if (S_ISREG(inode->mode)) { + int fd = 0; + unsigned long offset = inode->offset << 2; + + if (offset > 0 && offset < start_data) { + start_data = offset; + } + if (opt_verbose) { + print_node('f', inode, path); + } + if (opt_extract) { + fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, inode->mode); + } + if (inode->size) { + do_uncompress(fd, offset, inode->size); + } + if (opt_extract) { + close(fd); + change_file_status(path, inode); + } + return; + } + if (S_ISLNK(inode->mode)) { + unsigned long offset = inode->offset << 2; + + if (offset < start_data) { + start_data = offset; + } + do_symlink(path, inode); + return; + } + else { + do_special_inode(path, inode); + return; + } +} +#endif /* INCLUDE_FS_TESTS */ + +int main(int argc, char **argv) +{ + void *buf; + size_t length; + struct stat st; + u32 crc_old, crc_new; +#ifdef INCLUDE_FS_TESTS + struct cramfs_inode *root; +#endif /* INCLUDE_FS_TESTS */ + int c; /* for getopt */ + int start = 0; + + if (argc) + progname = argv[0]; + + /* command line options */ + while ((c = getopt(argc, argv, "hx:v")) != EOF) { + switch (c) { + case 'h': + usage(0); + case 'x': +#ifdef INCLUDE_FS_TESTS + opt_extract = 1; + extract_dir = malloc(strlen(optarg) + 1); + strcpy(extract_dir, optarg); + break; +#else /* not INCLUDE_FS_TESTS */ + fprintf(stderr, "%s: compiled without -x support\n", + progname); + exit(16); +#endif /* not INCLUDE_FS_TESTS */ + case 'v': + opt_verbose++; + break; + } + } + + if ((argc - optind) != 1) + usage(16); + filename = argv[optind]; + + /* find the physical size of the file or block device */ + if (lstat(filename, &st) < 0) { + perror(filename); + exit(8); + } + fd = open(filename, O_RDONLY); + if (fd < 0) { + perror(filename); + exit(8); + } + if (S_ISBLK(st.st_mode)) { + if (ioctl(fd, BLKGETSIZE, &length) < 0) { + fprintf(stderr, "%s: warning--unable to determine filesystem size \n", filename); + exit(4); + } + length = length * 512; + } + else if (S_ISREG(st.st_mode)) { + length = st.st_size; + } + else { + fprintf(stderr, "%s is not a block device or file\n", filename); + exit(8); + } + + if (length < sizeof(struct cramfs_super)) { + fprintf(stderr, "%s: invalid cramfs--file length too short\n", filename); + exit(4); + } + + if (S_ISBLK(st.st_mode)) { + /* nasty because mmap of block devices fails */ + buf = mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + read(fd, buf, length); + } + else { + /* nice and easy */ + buf = mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); + } + + /* XXX - this could be cleaner... */ + if (((struct cramfs_super *) buf)->magic == CRAMFS_MAGIC) { + start = 0; + super = (struct cramfs_super *) buf; + } + else if (length >= (PAD_SIZE + sizeof(struct cramfs_super)) && + ((((struct cramfs_super *) (buf + PAD_SIZE))->magic == CRAMFS_MAGIC))) + { + start = PAD_SIZE; + super = (struct cramfs_super *) (buf + PAD_SIZE); + } + else { + fprintf(stderr, "%s: invalid cramfs--wrong magic\n", filename); + exit(4); + } + + if (super->flags & CRAMFS_FLAG_FSID_VERSION_2) { + /* length test */ + if (length < super->size) { + fprintf(stderr, "%s: invalid cramfs--file length too short\n", filename); + exit(4); + } + else if (length > super->size) { + fprintf(stderr, "%s: warning--file length too long, padded image?\n", filename); + } + + /* CRC test */ + crc_old = super->fsid.crc; + super->fsid.crc = crc32(0L, Z_NULL, 0); + crc_new = crc32(0L, Z_NULL, 0); + crc_new = crc32(crc_new, (unsigned char *) buf+start, super->size - start); + if (crc_new != crc_old) { + fprintf(stderr, "%s: invalid cramfs--crc error\n", filename); + exit(4); + } + } + else { + fprintf(stderr, "%s: warning--old cramfs image, no CRC\n", + filename); + } + +#ifdef INCLUDE_FS_TESTS + super = (struct cramfs_super *) malloc(sizeof(struct cramfs_super)); + if (((struct cramfs_super *) buf)->magic == CRAMFS_MAGIC) { + memcpy(super, buf, sizeof(struct cramfs_super)); + } + else if (length >= (PAD_SIZE + sizeof(struct cramfs_super)) && + ((((struct cramfs_super *) (buf + PAD_SIZE))->magic == CRAMFS_MAGIC))) + { + memcpy(super, (buf + PAD_SIZE), sizeof(struct cramfs_super)); + } + + munmap(buf, length); + + /* file format test, uses fake "blocked" accesses */ + root = read_super(); + umask(0); + euid = geteuid(); + if (!root) { + fprintf(stderr, "%s: invalid cramfs--bad superblock\n", + filename); + exit(4); + } + stream.next_in = NULL; + stream.avail_in = 0; + inflateInit(&stream); + + if (!extract_dir) { + extract_dir = "root"; + } + + expand_fs(strlen(extract_dir), extract_dir, root); + inflateEnd(&stream); + + if (start_data != 1 << 28 && end_inode != start_data) { + fprintf(stderr, "%s: invalid cramfs--directory data end (%ld) != file data start (%ld)\n", filename, end_inode, start_data); + exit(4); + } + if (super->flags & CRAMFS_FLAG_FSID_VERSION_2) { + if (end_data > super->size) { + fprintf(stderr, "%s: invalid cramfs--invalid file data offset\n", filename); + exit(4); + } + } +#endif /* INCLUDE_FS_TESTS */ + + exit(0); +} diff -u --recursive --new-file v2.4.6/linux/scripts/cramfs/mkcramfs.c linux/scripts/cramfs/mkcramfs.c --- v2.4.6/linux/scripts/cramfs/mkcramfs.c Mon Jun 19 13:45:52 2000 +++ linux/scripts/cramfs/mkcramfs.c Thu Jul 19 16:14:53 2001 @@ -1,3 +1,23 @@ +/* + * mkcramfs - make a cramfs file system + * + * Copyright (C) 1999-2001 Transmeta 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 + */ + #include <sys/types.h> #include <stdio.h> #include <sys/stat.h> @@ -9,43 +29,58 @@ #include <errno.h> #include <string.h> #include <assert.h> - -/* zlib required.. */ +#include <getopt.h> +#include <linux/cramfs_fs.h> #include <zlib.h> -typedef unsigned char u8; -typedef unsigned short u16; -typedef unsigned int u32; - -#include "cramfs.h" +#define PAD_SIZE 512 /* only 0 and 512 supported by kernel */ static const char *progname = "mkcramfs"; /* N.B. If you change the disk format of cramfs, please update fs/cramfs/README. */ -static void usage(void) +/* Input status of 0 to print help and exit without an error. */ +static void usage(int status) { - fprintf(stderr, "Usage: '%s dirname outfile'\n" - " where <dirname> is the root of the\n" - " filesystem to be compressed.\n", progname); - exit(1); -} + FILE *stream = status ? stderr : stdout; -/* - * If DO_HOLES is defined, then mkcramfs can create explicit holes in the - * data, which saves 26 bytes per hole (which is a lot smaller a saving than - * most filesystems). - * - * Note that kernels up to at least 2.3.39 don't support cramfs holes, which - * is why this defaults to undefined at the moment. - */ -/* #define DO_HOLES 1 */ + fprintf(stream, "usage: %s [-h] [-e edition] [-i file] [-n name] dirname outfile\n" + " -h print this help\n" + " -E make all warnings errors (non-zero exit status)\n" + " -e edition set edition number (part of fsid)\n" + " -i file insert a file image into the filesystem (requires >= 2.4.0)\n" + " -n name set name of cramfs filesystem\n" + " -p pad by %d bytes for boot code\n" + " -s sort directory entries (old option, ignored)\n" + " -z make explicit holes (requires >= 2.3.39)\n" + " dirname root of the filesystem to be compressed\n" + " outfile output file\n", progname, PAD_SIZE); + + exit(status); +} #define PAGE_CACHE_SIZE (4096) /* The kernel assumes PAGE_CACHE_SIZE as block size. */ static unsigned int blksize = PAGE_CACHE_SIZE; +static long total_blocks = 0, total_nodes = 1; /* pre-count the root node */ +static int image_length = 0; + +/* + * If opt_holes is set, then mkcramfs can create explicit holes in the + * data, which saves 26 bytes per hole (which is a lot smaller a + * saving than most most filesystems). + * + * Note that kernels up to at least 2.3.39 don't support cramfs holes, + * which is why this is turned off by default. + */ +static int opt_edition = 0; +static int opt_errors = 0; +static int opt_holes = 0; +static int opt_pad = 0; +static char *opt_image = NULL; +static char *opt_name = NULL; -static int warn_dev, warn_gid, warn_namelen, warn_size, warn_uid; +static int warn_dev, warn_gid, warn_namelen, warn_skip, warn_size, warn_uid; #ifndef MIN # define MIN(_a,_b) ((_a) < (_b) ? (_a) : (_b)) @@ -70,15 +105,6 @@ }; /* - * Width of various bitfields in struct cramfs_inode. - * Used only to generate warnings. - */ -#define SIZE_WIDTH 24 -#define UID_WIDTH 16 -#define GID_WIDTH 8 -#define OFFSET_WIDTH 26 - -/* * The longest file name component to allow for in the input directory tree. * Ext2fs (and many others) allow up to 255 bytes. A couple of filesystems * allow longer (e.g. smbfs 1024), but there isn't much use in supporting @@ -101,45 +127,60 @@ static void eliminate_doubles(struct entry *root,struct entry *orig) { if(orig) { - if(orig->size && orig->uncompressed) + if(orig->size && orig->uncompressed) find_identical_file(root,orig); eliminate_doubles(root,orig->child); eliminate_doubles(root,orig->next); } } +/* + * We define our own sorting function instead of using alphasort which + * uses strcoll and changes ordering based on locale information. + */ +static int cramsort (const void *a, const void *b) +{ + return strcmp ((*(const struct dirent **) a)->d_name, + (*(const struct dirent **) b)->d_name); +} + static unsigned int parse_directory(struct entry *root_entry, const char *name, struct entry **prev, loff_t *fslen_ub) { - DIR *dir; - int count = 0, totalsize = 0; - struct dirent *dirent; + struct dirent **dirlist; + int totalsize = 0, dircount, dirindex; char *path, *endpath; size_t len = strlen(name); - dir = opendir(name); - if (!dir) { - perror(name); - exit(2); - } - /* Set up the path. */ /* TODO: Reuse the parent's buffer to save memcpy'ing and duplication. */ path = malloc(len + 1 + MAX_INPUT_NAMELEN + 1); if (!path) { perror(NULL); - exit(1); + exit(8); } memcpy(path, name, len); endpath = path + len; *endpath = '/'; endpath++; - while ((dirent = readdir(dir)) != NULL) { + /* read in the directory and sort */ + dircount = scandir(name, &dirlist, 0, cramsort); + + if (dircount < 0) { + perror(name); + exit(8); + } + + /* process directory */ + for (dirindex = 0; dirindex < dircount; dirindex++) { + struct dirent *dirent; struct entry *entry; struct stat st; int size; size_t namelen; + dirent = dirlist[dirindex]; + /* Ignore "." and ".." - we won't be adding them to the archive */ if (dirent->d_name[0] == '.') { if (dirent->d_name[1] == '\0') @@ -155,23 +196,24 @@ "Very long (%u bytes) filename `%s' found.\n" " Please increase MAX_INPUT_NAMELEN in mkcramfs.c and recompile. Exiting.\n", namelen, dirent->d_name); - exit(1); + exit(8); } memcpy(endpath, dirent->d_name, namelen + 1); if (lstat(path, &st) < 0) { perror(endpath); + warn_skip = 1; continue; } entry = calloc(1, sizeof(struct entry)); if (!entry) { perror(NULL); - exit(5); + exit(8); } entry->name = strdup(dirent->d_name); if (!entry->name) { perror(NULL); - exit(1); + exit(8); } if (namelen > 255) { /* Can't happen when reading from ext2fs. */ @@ -184,10 +226,10 @@ entry->mode = st.st_mode; entry->size = st.st_size; entry->uid = st.st_uid; - if (entry->uid >= 1 << UID_WIDTH) + if (entry->uid >= 1 << CRAMFS_UID_WIDTH) warn_uid = 1; entry->gid = st.st_gid; - if (entry->gid >= 1 << GID_WIDTH) + if (entry->gid >= 1 << CRAMFS_GID_WIDTH) /* TODO: We ought to replace with a default gid instead of truncating; otherwise there are security problems. Maybe mode should @@ -211,18 +253,19 @@ int fd = open(path, O_RDONLY); if (fd < 0) { perror(path); + warn_skip = 1; continue; } if (entry->size) { - if ((entry->size >= 1 << SIZE_WIDTH)) { + if ((entry->size >= 1 << CRAMFS_SIZE_WIDTH)) { warn_size = 1; - entry->size = (1 << SIZE_WIDTH) - 1; + entry->size = (1 << CRAMFS_SIZE_WIDTH) - 1; } entry->uncompressed = mmap(NULL, entry->size, PROT_READ, MAP_PRIVATE, fd, 0); if (-1 == (int) (long) entry->uncompressed) { perror("mmap"); - exit(5); + exit(8); } } close(fd); @@ -230,63 +273,69 @@ entry->uncompressed = malloc(entry->size); if (!entry->uncompressed) { perror(NULL); - exit(5); + exit(8); } if (readlink(path, entry->uncompressed, entry->size) < 0) { perror(path); + warn_skip = 1; continue; } + } else if (S_ISFIFO(st.st_mode) || S_ISSOCK(st.st_mode)) { + /* maybe we should skip sockets */ + entry->size = 0; } else { entry->size = st.st_rdev; - if (entry->size & -(1<<SIZE_WIDTH)) + if (entry->size & -(1<<CRAMFS_SIZE_WIDTH)) warn_dev = 1; } if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)) { + int blocks = ((entry->size - 1) / blksize + 1); + /* block pointers & data expansion allowance + data */ - if(entry->size) - *fslen_ub += ((4+26)*((entry->size - 1) / blksize + 1) - + MIN(entry->size + 3, st.st_blocks << 9)); - else - *fslen_ub += MIN(entry->size + 3, st.st_blocks << 9); + if(entry->size) + *fslen_ub += (4+26)*blocks + entry->size + 3; } /* Link it into the list */ *prev = entry; prev = &entry->next; - count++; totalsize += size; } - closedir(dir); free(path); + free(dirlist); /* allocated by scandir() with malloc() */ return totalsize; } -static void set_random(void *area, size_t size) -{ - int fd = open("/dev/random", O_RDONLY); - - if (fd >= 0) { - if (read(fd, area, size) == size) - return; - } - memset(area, 0x00, size); -} - /* Returns sizeof(struct cramfs_super), which includes the root inode. */ -static unsigned int write_superblock(struct entry *root, char *base) +static unsigned int write_superblock(struct entry *root, char *base, int size) { struct cramfs_super *super = (struct cramfs_super *) base; - unsigned int offset = sizeof(struct cramfs_super); + unsigned int offset = sizeof(struct cramfs_super) + image_length; + + if (opt_pad) { + offset += opt_pad; + } super->magic = CRAMFS_MAGIC; - super->flags = 0; - /* Note: 0x10000 is meaningless, which is a bug; but - super->size is never used anyway. */ - super->size = 0x10000; + super->flags = CRAMFS_FLAG_FSID_VERSION_2 | CRAMFS_FLAG_SORTED_DIRS; + if (opt_holes) + super->flags |= CRAMFS_FLAG_HOLES; + if (image_length > 0) + super->flags |= CRAMFS_FLAG_SHIFTED_ROOT_OFFSET; + super->size = size; memcpy(super->signature, CRAMFS_SIGNATURE, sizeof(super->signature)); - set_random(super->fsid, sizeof(super->fsid)); - strncpy(super->name, "Compressed", sizeof(super->name)); + + super->fsid.crc = crc32(0L, Z_NULL, 0); + super->fsid.edition = opt_edition; + super->fsid.blocks = total_blocks; + super->fsid.files = total_nodes; + + memset(super->name, 0x00, sizeof(super->name)); + if (opt_name) + strncpy(super->name, opt_name, sizeof(super->name)); + else + strncpy(super->name, "Compressed", sizeof(super->name)); super->root.mode = root->mode; super->root.uid = root->uid; @@ -300,10 +349,12 @@ static void set_data_offset(struct entry *entry, char *base, unsigned long offset) { struct cramfs_inode *inode = (struct cramfs_inode *) (base + entry->dir_offset); +#ifdef DEBUG assert ((offset & 3) == 0); - if (offset >= (1 << (2 + OFFSET_WIDTH))) { +#endif /* DEBUG */ + if (offset >= (1 << (2 + CRAMFS_OFFSET_WIDTH))) { fprintf(stderr, "filesystem too big. Exiting.\n"); - exit(1); + exit(8); } inode->offset = (offset >> 2); } @@ -337,6 +388,7 @@ write over inode->offset later. */ offset += sizeof(struct cramfs_inode); + total_nodes++; /* another node */ memcpy(base + offset, entry->name, len); /* Pad up the name to a 4-byte boundary */ while (len & 3) { @@ -354,7 +406,7 @@ if (entry->child) { if (stack_entries >= MAXENTRIES) { fprintf(stderr, "Exceeded MAXENTRIES. Raise this value in mkcramfs.c and recompile. Exiting.\n"); - exit(1); + exit(8); } entry_stack[stack_entries] = entry; stack_entries++; @@ -393,26 +445,24 @@ return offset; } -#ifdef DO_HOLES -/* - * Returns non-zero iff the first LEN bytes from BEGIN are all NULs. - */ -static int -is_zero(char const *begin, unsigned len) +static int is_zero(char const *begin, unsigned len) { - return (len-- == 0 || - (begin[0] == '\0' && - (len-- == 0 || - (begin[1] == '\0' && - (len-- == 0 || - (begin[2] == '\0' && - (len-- == 0 || - (begin[3] == '\0' && - memcmp(begin, begin + 4, len) == 0)))))))); -} -#else /* !DO_HOLES */ -# define is_zero(_begin,_len) (0) /* Never create holes. */ -#endif /* !DO_HOLES */ + if (opt_holes) + /* Returns non-zero iff the first LEN bytes from BEGIN are + all NULs. */ + return (len-- == 0 || + (begin[0] == '\0' && + (len-- == 0 || + (begin[1] == '\0' && + (len-- == 0 || + (begin[2] == '\0' && + (len-- == 0 || + (begin[3] == '\0' && + memcmp(begin, begin + 4, len) == 0)))))))); + else + /* Never create holes. */ + return 0; +} /* * One 4-byte pointer per block and then the actual blocked @@ -433,6 +483,8 @@ unsigned long curr = offset + 4 * blocks; int change; + total_blocks += blocks; + do { unsigned long len = 2 * blksize; unsigned int input = size; @@ -448,7 +500,7 @@ if (len > blksize*2) { /* (I don't think this can happen with zlib.) */ printf("AIEEE: block \"compressed\" to > 2*blocklength (%ld)\n", len); - exit(1); + exit(8); } *(u32 *) (base + offset) = curr; @@ -493,6 +545,27 @@ return offset; } +static unsigned int write_file(char *file, char *base, unsigned int offset) +{ + int fd; + char *buf; + + fd = open(file, O_RDONLY); + if (fd < 0) { + perror(file); + exit(8); + } + buf = mmap(NULL, image_length, PROT_READ, MAP_PRIVATE, fd, 0); + memcpy(base + offset, buf, image_length); + munmap(buf, image_length); + close (fd); + /* Pad up the image_length to a 4-byte boundary */ + while (image_length & 3) { + *(base + offset + image_length) = '\0'; + image_length++; + } + return (offset + image_length); +} /* * Maximum size fs you can create is roughly 256MB. (The last file's @@ -501,9 +574,9 @@ * Note that if you want it to fit in a ROM then you're limited to what the * hardware and kernel can support (64MB?). */ -#define MAXFSLEN ((((1 << OFFSET_WIDTH) - 1) << 2) /* offset */ \ - + (1 << SIZE_WIDTH) - 1 /* filesize */ \ - + (1 << SIZE_WIDTH) * 4 / PAGE_CACHE_SIZE /* block pointers */ ) +#define MAXFSLEN ((((1 << CRAMFS_OFFSET_WIDTH) - 1) << 2) /* offset */ \ + + (1 << CRAMFS_SIZE_WIDTH) - 1 /* filesize */ \ + + (1 << CRAMFS_SIZE_WIDTH) * 4 / PAGE_CACHE_SIZE /* block pointers */ ) /* @@ -517,41 +590,88 @@ */ int main(int argc, char **argv) { - struct stat st; + struct stat st; /* used twice... */ struct entry *root_entry; char *rom_image; - unsigned int offset; - ssize_t written; + ssize_t offset, written; int fd; - loff_t fslen_ub = 0; /* initial guess (upper-bound) of - required filesystem size */ - char const *dirname; + /* initial guess (upper-bound) of required filesystem size */ + loff_t fslen_ub = sizeof(struct cramfs_super); + char const *dirname, *outfile; + u32 crc = crc32(0L, Z_NULL, 0); + int c; /* for getopt */ + + total_blocks = 0; if (argc) progname = argv[0]; - if (argc != 3) - usage(); - if (stat(dirname = argv[1], &st) < 0) { - perror(argv[1]); - exit(1); + /* command line options */ + while ((c = getopt(argc, argv, "hEe:i:n:psz")) != EOF) { + switch (c) { + case 'h': + usage(0); + case 'E': + opt_errors = 1; + break; + case 'e': + opt_edition = atoi(optarg); + break; + case 'i': + opt_image = optarg; + if (lstat(opt_image, &st) < 0) { + perror(opt_image); + exit(16); + } + image_length = st.st_size; /* may be padded later */ + fslen_ub += (image_length + 3); /* 3 is for padding */ + break; + case 'n': + opt_name = optarg; + break; + case 'p': + opt_pad = PAD_SIZE; + fslen_ub += PAD_SIZE; + break; + case 's': + /* old option, ignored */ + break; + case 'z': + opt_holes = 1; + break; + } + } + + if ((argc - optind) != 2) + usage(16); + dirname = argv[optind]; + outfile = argv[optind + 1]; + + if (stat(dirname, &st) < 0) { + perror(dirname); + exit(16); } - fd = open(argv[2], O_WRONLY | O_CREAT | O_TRUNC, 0666); + fd = open(outfile, O_WRONLY | O_CREAT | O_TRUNC, 0666); root_entry = calloc(1, sizeof(struct entry)); if (!root_entry) { perror(NULL); - exit(5); + exit(8); } root_entry->mode = st.st_mode; root_entry->uid = st.st_uid; root_entry->gid = st.st_gid; - root_entry->size = parse_directory(root_entry, argv[1], &root_entry->child, &fslen_ub); + root_entry->size = parse_directory(root_entry, dirname, &root_entry->child, &fslen_ub); + + /* always allocate a multiple of blksize bytes because that's + what we're going to write later on */ + fslen_ub = ((fslen_ub - 1) | (blksize - 1)) + 1; + if (fslen_ub > MAXFSLEN) { fprintf(stderr, - "warning: guestimate of required size (upper bound) is %luMB, but maximum image size is %uMB. We might die prematurely.\n", - (unsigned long) (fslen_ub >> 20), + "warning: guestimate of required size (upper bound) is %LdMB, but maximum image size is %uMB. We might die prematurely.\n", + fslen_ub >> 20, MAXFSLEN >> 20); fslen_ub = MAXFSLEN; } @@ -560,7 +680,6 @@ possible. */ eliminate_doubles(root_entry,root_entry); - /* TODO: Why do we use a private/anonymous mapping here followed by a write below, instead of just a shared mapping and a couple of ftruncate calls? Is it just to save us @@ -570,13 +689,25 @@ RAM free. If the reason is to be able to write to un-mmappable block devices, then we could try shared mmap and revert to anonymous mmap if the shared mmap fails. */ - rom_image = mmap(NULL, fslen_ub, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + rom_image = mmap(NULL, fslen_ub?fslen_ub:1, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (-1 == (int) (long) rom_image) { perror("ROM image map"); - exit(1); + exit(8); + } + + /* Skip the first opt_pad bytes for boot loader code */ + offset = opt_pad; + memset(rom_image, 0x00, opt_pad); + + /* Skip the superblock and come back to write it later. */ + offset += sizeof(struct cramfs_super); + + /* Insert a file image. */ + if (opt_image) { + printf("Including: %s\n", opt_image); + offset = write_file(opt_image, rom_image, offset); } - offset = write_superblock(root_entry, rom_image); - printf("Super block: %d bytes\n", offset); offset = write_directory_structure(root_entry->child, rom_image, offset); printf("Directory data: %d bytes\n", offset); @@ -588,14 +719,30 @@ offset = ((offset - 1) | (blksize - 1)) + 1; printf("Everything: %d kilobytes\n", offset >> 10); + /* Write the superblock now that we can fill in all of the fields. */ + write_superblock(root_entry, rom_image+opt_pad, offset); + printf("Super block: %d bytes\n", sizeof(struct cramfs_super)); + + /* Put the checksum in. */ + crc = crc32(crc, (rom_image+opt_pad), (offset-opt_pad)); + ((struct cramfs_super *) (rom_image+opt_pad))->fsid.crc = crc; + printf("CRC: %x\n", crc); + + /* Check to make sure we allocated enough space. */ + if (fslen_ub < offset) { + fprintf(stderr, "not enough space allocated for ROM image (%Ld allocated, %d used)\n", + fslen_ub, offset); + exit(8); + } + written = write(fd, rom_image, offset); if (written < 0) { - perror("rom image"); - exit(1); + perror("ROM image"); + exit(8); } if (offset != written) { fprintf(stderr, "ROM image write failed (%d %d)\n", written, offset); - exit(1); + exit(8); } /* (These warnings used to come at the start, but they scroll off the @@ -603,22 +750,27 @@ if (warn_namelen) /* (can't happen when reading from ext2fs) */ fprintf(stderr, /* bytes, not chars: think UTF8. */ "warning: filenames truncated to 255 bytes.\n"); + if (warn_skip) + fprintf(stderr, "warning: files were skipped due to errors.\n"); if (warn_size) fprintf(stderr, "warning: file sizes truncated to %luMB (minus 1 byte).\n", - 1L << (SIZE_WIDTH - 20)); + 1L << (CRAMFS_SIZE_WIDTH - 20)); if (warn_uid) /* (not possible with current Linux versions) */ fprintf(stderr, "warning: uids truncated to %u bits. (This may be a security concern.)\n", - UID_WIDTH); + CRAMFS_UID_WIDTH); if (warn_gid) fprintf(stderr, "warning: gids truncated to %u bits. (This may be a security concern.)\n", - GID_WIDTH); + CRAMFS_GID_WIDTH); if (warn_dev) fprintf(stderr, "WARNING: device numbers truncated to %u bits. This almost certainly means\n" "that some device files will be wrong.\n", - OFFSET_WIDTH); + CRAMFS_OFFSET_WIDTH); + if (opt_errors && + (warn_namelen||warn_skip||warn_size||warn_uid||warn_gid||warn_dev)) + exit(8); return 0; }